Version v0.3.40 - -m Add directory encryption (TAR+GZIP+OTP), integrate ranger for directory selection, add microtar/miniz libraries, remove binary state file backward compatibility - enforce text format only

This commit is contained in:
2025-12-27 11:45:31 -05:00
parent 89aa3baff6
commit 6fe12e0c1c
8 changed files with 730 additions and 30 deletions

131
src/ui.c
View File

@@ -99,6 +99,9 @@ int interactive_mode(void) {
case 'F':
handle_file_encrypt();
break;
case 'R':
handle_directory_encrypt();
break;
case 'D':
handle_decrypt_menu();
break;
@@ -125,11 +128,12 @@ void show_main_menu(void) {
print_centered_header(header, 0);
printf("\n");
printf(" \033[4mT\033[0mext encrypt\n"); //TEXT ENCRYPT
printf(" \033[4mF\033[0mile encrypt\n"); //FILE ENCRYPT
printf(" \033[4mD\033[0mecrypt\n"); //DECRYPT
printf(" \033[4mP\033[0mads\n"); //PADS
printf(" E\033[4mx\033[0mit\n"); //EXIT
printf(" \033[4mT\033[0mext encrypt\n"); //TEXT ENCRYPT
printf(" \033[4mF\033[0mile encrypt\n"); //FILE ENCRYPT
printf(" Di\033[4mr\033[0mectory encrypt\n"); //DIRECTORY ENCRYPT
printf(" \033[4mD\033[0mecrypt\n"); //DECRYPT
printf(" \033[4mP\033[0mads\n"); //PADS
printf(" E\033[4mx\033[0mit\n"); //EXIT
printf("\nSelect option: ");
}
@@ -352,7 +356,23 @@ int handle_decrypt_menu(void) {
return 1;
}
return decrypt_file(selected_file, output_file);
// Check if it's a directory archive
if (strstr(selected_file, ".tar.gz.otp") || strstr(selected_file, ".tar.otp")) {
// It's a directory archive - extract to directory
char extract_dir[512];
strncpy(extract_dir, output_file, sizeof(extract_dir) - 1);
extract_dir[sizeof(extract_dir) - 1] = '\0';
// Remove .tar.gz.otp or .tar.otp extension to get directory name
char* ext = strstr(extract_dir, ".tar.gz.otp");
if (!ext) ext = strstr(extract_dir, ".tar.otp");
if (ext) *ext = '\0';
printf("Extracting directory archive to: %s/\n", extract_dir);
return decrypt_and_extract_directory(selected_file, extract_dir);
} else {
return decrypt_file(selected_file, output_file);
}
}
else if (strncmp(input_line, "-----BEGIN OTP MESSAGE-----", 27) == 0) {
// Looks like ASCII armor - collect the full message
@@ -404,7 +424,23 @@ int handle_decrypt_menu(void) {
return 1;
}
return decrypt_file(input_line, output_file);
// Check if it's a directory archive
if (strstr(input_line, ".tar.gz.otp") || strstr(input_line, ".tar.otp")) {
// It's a directory archive - extract to directory
char extract_dir[512];
strncpy(extract_dir, output_file, sizeof(extract_dir) - 1);
extract_dir[sizeof(extract_dir) - 1] = '\0';
// Remove .tar.gz.otp or .tar.otp extension to get directory name
char* ext = strstr(extract_dir, ".tar.gz.otp");
if (!ext) ext = strstr(extract_dir, ".tar.otp");
if (ext) *ext = '\0';
printf("Extracting directory archive to: %s/\n", extract_dir);
return decrypt_and_extract_directory(input_line, extract_dir);
} else {
return decrypt_file(input_line, output_file);
}
} else {
printf("Input not recognized as ASCII armor or valid file path.\n");
return 1;
@@ -501,5 +537,86 @@ int handle_file_encrypt(void) {
int result = encrypt_file(selected_pad, input_file, output_filename, ascii_armor);
free(selected_pad);
return result;
}
int handle_directory_encrypt(void) {
printf("\n");
print_centered_header("Directory Encrypt", 0);
// Directory selection options
printf("\nDirectory selection options:\n");
printf(" 1. Type directory path directly\n");
printf(" 2. Use file manager (navigate to directory)\n");
printf("Enter choice (1-2): ");
char choice_input[10];
char dir_path[512];
if (!fgets(choice_input, sizeof(choice_input), stdin)) {
printf("Error: Failed to read input\n");
return 1;
}
if (atoi(choice_input) == 2) {
// Use directory manager
if (launch_directory_manager(".", dir_path, sizeof(dir_path)) != 0) {
printf("Falling back to manual directory path entry.\n");
printf("Enter directory path to encrypt: ");
if (!fgets(dir_path, sizeof(dir_path), stdin)) {
printf("Error: Failed to read input\n");
return 1;
}
dir_path[strcspn(dir_path, "\n")] = 0;
}
} else {
// Direct directory path input
printf("Enter directory path to encrypt: ");
if (!fgets(dir_path, sizeof(dir_path), stdin)) {
printf("Error: Failed to read input\n");
return 1;
}
dir_path[strcspn(dir_path, "\n")] = 0;
}
// Check if directory exists
struct stat st;
if (stat(dir_path, &st) != 0 || !S_ISDIR(st.st_mode)) {
printf("Error: '%s' is not a valid directory\n", dir_path);
return 1;
}
// Select pad
char* selected_pad = select_pad_interactive("Select Pad for Directory Encryption",
"Select pad (by prefix)",
PAD_FILTER_ALL, 1);
if (!selected_pad) {
printf("Directory encryption cancelled.\n");
return 1;
}
// Generate default output filename
char default_output[1024];
const char* dir_name = strrchr(dir_path, '/');
if (dir_name) {
dir_name++; // Skip the '/'
} else {
dir_name = dir_path;
}
snprintf(default_output, sizeof(default_output), "%s.tar.gz.otp", dir_name);
// Get output filename
char output_file[512];
if (get_filename_with_default("Output filename:", default_output, output_file, sizeof(output_file)) != 0) {
printf("Error: Failed to read input\n");
free(selected_pad);
return 1;
}
// Encrypt directory
int result = encrypt_directory(dir_path, selected_pad, output_file);
free(selected_pad);
return result;
}