Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 592d54728b | |||
| 21b3c4de52 | |||
| 3a854c3ccf | |||
| 877add0dbf | |||
| 482687cb68 | |||
| e35d94243e | |||
| e88e1b5d3d | |||
| 41ef97c43e | |||
| 7810e66114 | |||
| b4be05c34d | |||
| 1cb0ba935d | |||
| 8c8c873e73 | |||
| 692f65b7f0 | |||
| 1c4200a73a | |||
| 1c9e2ee527 | |||
| 8401e14ae0 | |||
| 0dbd81d1cc |
@@ -1,7 +1,29 @@
|
|||||||
|
|
||||||
When building, use build.sh, not make.
|
When building, use build.sh, not make.
|
||||||
|
|
||||||
Use it as follows: build.sh -m "useful comment on changes being made"
|
Use it as follows: build.sh -m "useful comment on changes being made"
|
||||||
|
|
||||||
When making TUI menus, try to use the first leter of the command and the key to press to execute that command. For example, if the command is "Open file" try to use a keypress of "o" upper or lower case to signal to open the file. Use this instead of number keyed menus when possible. In the command, the letter should be underlined that signifies the command.
|
When making TUI menus, try to use the first leter of the command and the key to press to execute that command. For example, if the command is "Open file" try to use a keypress of "o" upper or lower case to signal to open the file. Use this instead of number keyed menus when possible. In the command, the letter should be underlined that signifies the command.
|
||||||
|
|
||||||
|
## Buffer Size Guidelines
|
||||||
|
|
||||||
|
### Path Handling
|
||||||
|
- Always use buffers of size 1024 or PATH_MAX (4096) for file paths
|
||||||
|
- When concatenating paths with snprintf, ensure buffer is at least 2x the expected maximum input
|
||||||
|
- Use safer path construction patterns that check lengths before concatenation
|
||||||
|
|
||||||
|
### String Formatting Safety
|
||||||
|
- Before using snprintf with dynamic strings, validate that buffer size >= sum of all input string lengths + format characters + 1
|
||||||
|
- Use strnlen() to check actual string lengths before formatting
|
||||||
|
- Consider using asprintf() for dynamic allocation when exact size is unknown
|
||||||
|
- Add length validation before snprintf calls
|
||||||
|
|
||||||
|
### Compiler Warning Prevention
|
||||||
|
- Always size string buffers generously (minimum 1024 for paths, 512 for general strings)
|
||||||
|
- Use buffer size calculations: `size >= strlen(str1) + strlen(str2) + format_overhead + 1`
|
||||||
|
- Add runtime length checks before snprintf operations
|
||||||
|
- Consider using safer alternatives like strlcpy/strlcat if available
|
||||||
|
|
||||||
|
### Code Patterns to Avoid
|
||||||
|
- Fixed-size buffers (512 bytes) for path operations where inputs could be 255+ bytes each
|
||||||
|
- Concatenating unchecked strings with snprintf
|
||||||
|
- Assuming maximum path component sizes without validation
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
Test file content for decryption
|
|
||||||
551
otp.c
551
otp.c
@@ -46,10 +46,26 @@ static const int base64_decode_table[256] = {
|
|||||||
// Global variable for current pads directory (can be local or OTP thumb drive)
|
// Global variable for current pads directory (can be local or OTP thumb drive)
|
||||||
static char current_pads_dir[512] = DEFAULT_PADS_DIR;
|
static char current_pads_dir[512] = DEFAULT_PADS_DIR;
|
||||||
|
|
||||||
|
// Global variable for default pad path from preferences
|
||||||
|
static char default_pad_path[1024] = "";
|
||||||
|
|
||||||
// Function prototypes
|
// Function prototypes
|
||||||
int main(int argc, char* argv[]);
|
int main(int argc, char* argv[]);
|
||||||
int interactive_mode(void);
|
int interactive_mode(void);
|
||||||
int command_line_mode(int argc, char* argv[]);
|
int command_line_mode(int argc, char* argv[]);
|
||||||
|
int pipe_mode(int argc, char* argv[], const char* piped_text);
|
||||||
|
|
||||||
|
// Stdin detection functions
|
||||||
|
int has_stdin_data(void);
|
||||||
|
char* read_stdin_text(void);
|
||||||
|
|
||||||
|
// Preferences management functions
|
||||||
|
int load_preferences(void);
|
||||||
|
int save_preferences(void);
|
||||||
|
char* get_preference(const char* key);
|
||||||
|
int set_preference(const char* key, const char* value);
|
||||||
|
char* get_default_pad_path(void);
|
||||||
|
int set_default_pad_path(const char* pad_path);
|
||||||
|
|
||||||
// OTP thumb drive detection function
|
// OTP thumb drive detection function
|
||||||
int detect_otp_thumb_drive(char* otp_drive_path, size_t path_size);
|
int detect_otp_thumb_drive(char* otp_drive_path, size_t path_size);
|
||||||
@@ -65,6 +81,7 @@ int generate_pad(uint64_t size_bytes, int show_progress);
|
|||||||
int generate_pad_with_entropy(uint64_t size_bytes, int show_progress, int use_keyboard_entropy);
|
int generate_pad_with_entropy(uint64_t size_bytes, int show_progress, int use_keyboard_entropy);
|
||||||
int encrypt_text(const char* pad_identifier, const char* input_text);
|
int encrypt_text(const char* pad_identifier, const char* input_text);
|
||||||
int decrypt_text(const char* pad_identifier, const char* encrypted_message);
|
int decrypt_text(const char* pad_identifier, const char* encrypted_message);
|
||||||
|
int decrypt_text_silent(const char* pad_identifier, const char* encrypted_message);
|
||||||
int encrypt_file(const char* pad_identifier, const char* input_file, const char* output_file, int ascii_armor);
|
int encrypt_file(const char* pad_identifier, const char* input_file, const char* output_file, int ascii_armor);
|
||||||
int decrypt_file(const char* input_file, const char* output_file);
|
int decrypt_file(const char* input_file, const char* output_file);
|
||||||
int decrypt_binary_file(FILE* input_fp, const char* output_file);
|
int decrypt_binary_file(FILE* input_fp, const char* output_file);
|
||||||
@@ -115,16 +132,40 @@ void get_directory_display(const char* file_path, char* result, size_t result_si
|
|||||||
void print_usage(const char* program_name);
|
void print_usage(const char* program_name);
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
|
// Load preferences first
|
||||||
|
load_preferences();
|
||||||
|
|
||||||
|
// Check for piped input first (before any output)
|
||||||
|
int is_pipe_mode = (argc == 1 && has_stdin_data());
|
||||||
|
|
||||||
|
// Check for decrypt command with piped input
|
||||||
|
int is_decrypt_pipe = (argc == 2 &&
|
||||||
|
(strcmp(argv[1], "decrypt") == 0 || strcmp(argv[1], "-d") == 0) &&
|
||||||
|
has_stdin_data());
|
||||||
|
|
||||||
// Check for OTP thumb drive on startup
|
// Check for OTP thumb drive on startup
|
||||||
char otp_drive_path[512];
|
char otp_drive_path[512];
|
||||||
if (detect_otp_thumb_drive(otp_drive_path, sizeof(otp_drive_path))) {
|
if (detect_otp_thumb_drive(otp_drive_path, sizeof(otp_drive_path))) {
|
||||||
printf("Detected OTP thumb drive: %s\n", otp_drive_path);
|
// Only show messages in interactive/command mode, not pipe mode
|
||||||
printf("Using as default pads directory for this session.\n\n");
|
if (!is_pipe_mode && !is_decrypt_pipe) {
|
||||||
|
printf("Detected OTP thumb drive: %s\n", otp_drive_path);
|
||||||
|
printf("Using as default pads directory for this session.\n\n");
|
||||||
|
}
|
||||||
strncpy(current_pads_dir, otp_drive_path, sizeof(current_pads_dir) - 1);
|
strncpy(current_pads_dir, otp_drive_path, sizeof(current_pads_dir) - 1);
|
||||||
current_pads_dir[sizeof(current_pads_dir) - 1] = '\0';
|
current_pads_dir[sizeof(current_pads_dir) - 1] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argc == 1) {
|
if (is_pipe_mode) {
|
||||||
|
// No arguments but has piped data - enter pipe mode
|
||||||
|
char* piped_text = read_stdin_text();
|
||||||
|
if (piped_text) {
|
||||||
|
int result = pipe_mode(argc, argv, piped_text);
|
||||||
|
free(piped_text);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
// If reading stdin failed, fall back to interactive mode
|
||||||
|
return interactive_mode();
|
||||||
|
} else if (argc == 1) {
|
||||||
return interactive_mode();
|
return interactive_mode();
|
||||||
} else {
|
} else {
|
||||||
return command_line_mode(argc, argv);
|
return command_line_mode(argc, argv);
|
||||||
@@ -158,6 +199,7 @@ int interactive_mode(void) {
|
|||||||
handle_pads_menu();
|
handle_pads_menu();
|
||||||
break;
|
break;
|
||||||
case 'X':
|
case 'X':
|
||||||
|
case 'Q':
|
||||||
printf("Goodbye!\n");
|
printf("Goodbye!\n");
|
||||||
return 0;
|
return 0;
|
||||||
default:
|
default:
|
||||||
@@ -202,6 +244,16 @@ int command_line_mode(int argc, char* argv[]) {
|
|||||||
}
|
}
|
||||||
else if (strcmp(argv[1], "decrypt") == 0 || strcmp(argv[1], "-d") == 0) {
|
else if (strcmp(argv[1], "decrypt") == 0 || strcmp(argv[1], "-d") == 0) {
|
||||||
if (argc == 2) {
|
if (argc == 2) {
|
||||||
|
// Check for piped input first
|
||||||
|
if (has_stdin_data()) {
|
||||||
|
// Piped decrypt mode - read stdin and decrypt silently
|
||||||
|
char* piped_message = read_stdin_text();
|
||||||
|
if (piped_message) {
|
||||||
|
int result = decrypt_text_silent(NULL, piped_message);
|
||||||
|
free(piped_message);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
// Interactive mode - no arguments needed
|
// Interactive mode - no arguments needed
|
||||||
return decrypt_text(NULL, NULL);
|
return decrypt_text(NULL, NULL);
|
||||||
}
|
}
|
||||||
@@ -1127,10 +1179,39 @@ int generate_pad_with_entropy(uint64_t size_bytes, int display_progress, int use
|
|||||||
// Get final paths in pads directory
|
// Get final paths in pads directory
|
||||||
get_pad_path(chksum_hex, pad_path, state_path);
|
get_pad_path(chksum_hex, pad_path, state_path);
|
||||||
|
|
||||||
|
// Try rename first (works for same filesystem)
|
||||||
if (rename(temp_filename, pad_path) != 0) {
|
if (rename(temp_filename, pad_path) != 0) {
|
||||||
printf("Error: Cannot move pad file to pads directory\n");
|
// If rename fails, try copy and delete (works across filesystems)
|
||||||
|
FILE* temp_file = fopen(temp_filename, "rb");
|
||||||
|
FILE* dest_file = fopen(pad_path, "wb");
|
||||||
|
|
||||||
|
if (!temp_file || !dest_file) {
|
||||||
|
printf("Error: Cannot copy pad file to pads directory\n");
|
||||||
|
if (temp_file) fclose(temp_file);
|
||||||
|
if (dest_file) fclose(dest_file);
|
||||||
|
unlink(temp_filename);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy file in chunks
|
||||||
|
unsigned char copy_buffer[64 * 1024];
|
||||||
|
size_t bytes_read;
|
||||||
|
while ((bytes_read = fread(copy_buffer, 1, sizeof(copy_buffer), temp_file)) > 0) {
|
||||||
|
if (fwrite(copy_buffer, 1, bytes_read, dest_file) != bytes_read) {
|
||||||
|
printf("Error: Failed to copy pad file to pads directory\n");
|
||||||
|
fclose(temp_file);
|
||||||
|
fclose(dest_file);
|
||||||
|
unlink(temp_filename);
|
||||||
|
unlink(pad_path);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(temp_file);
|
||||||
|
fclose(dest_file);
|
||||||
|
|
||||||
|
// Remove temporary file after successful copy
|
||||||
unlink(temp_filename);
|
unlink(temp_filename);
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set pad file to read-only
|
// Set pad file to read-only
|
||||||
@@ -1325,8 +1406,15 @@ int encrypt_text(const char* pad_identifier, const char* input_text) {
|
|||||||
printf("Warning: Failed to update state file\n");
|
printf("Warning: Failed to update state file\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output in ASCII armor format
|
// Output in ASCII armor format - clean format for piping, spaced format for interactive
|
||||||
printf("\n\n-----BEGIN OTP MESSAGE-----\n");
|
int is_interactive = (input_text == NULL); // Interactive if no input_text provided
|
||||||
|
|
||||||
|
if (is_interactive) {
|
||||||
|
printf("\n\n-----BEGIN OTP MESSAGE-----\n");
|
||||||
|
} else {
|
||||||
|
printf("-----BEGIN OTP MESSAGE-----\n");
|
||||||
|
}
|
||||||
|
|
||||||
printf("Version: %s\n", get_version());
|
printf("Version: %s\n", get_version());
|
||||||
printf("Pad-ChkSum: %s\n", chksum_hex);
|
printf("Pad-ChkSum: %s\n", chksum_hex);
|
||||||
printf("Pad-Offset: %lu\n", current_offset);
|
printf("Pad-Offset: %lu\n", current_offset);
|
||||||
@@ -1338,7 +1426,11 @@ int encrypt_text(const char* pad_identifier, const char* input_text) {
|
|||||||
printf("%.64s\n", base64_cipher + i);
|
printf("%.64s\n", base64_cipher + i);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("-----END OTP MESSAGE-----\n\n\n");
|
if (is_interactive) {
|
||||||
|
printf("-----END OTP MESSAGE-----\n\n\n");
|
||||||
|
} else {
|
||||||
|
printf("-----END OTP MESSAGE-----\n");
|
||||||
|
}
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
free(pad_data);
|
free(pad_data);
|
||||||
@@ -1523,6 +1615,135 @@ int decrypt_text(const char* pad_identifier, const char* encrypted_message) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int decrypt_text_silent(const char* pad_identifier, const char* encrypted_message) {
|
||||||
|
// For piped decrypt mode - silent operation with minimal output
|
||||||
|
(void)pad_identifier; // Suppress unused parameter warning
|
||||||
|
|
||||||
|
char stored_chksum[MAX_HASH_LENGTH];
|
||||||
|
char current_chksum[MAX_HASH_LENGTH];
|
||||||
|
uint64_t pad_offset;
|
||||||
|
char base64_data[MAX_INPUT_SIZE * 2] = {0};
|
||||||
|
int in_data_section = 0;
|
||||||
|
|
||||||
|
if (encrypted_message != NULL) {
|
||||||
|
// Parse provided encrypted message
|
||||||
|
char *message_copy = strdup(encrypted_message);
|
||||||
|
char *line_ptr = strtok(message_copy, "\n");
|
||||||
|
|
||||||
|
int found_begin = 0;
|
||||||
|
while (line_ptr != NULL) {
|
||||||
|
if (strcmp(line_ptr, "-----BEGIN OTP MESSAGE-----") == 0) {
|
||||||
|
found_begin = 1;
|
||||||
|
}
|
||||||
|
else if (strcmp(line_ptr, "-----END OTP MESSAGE-----") == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (found_begin) {
|
||||||
|
if (strncmp(line_ptr, "Pad-ChkSum: ", 12) == 0) {
|
||||||
|
strncpy(stored_chksum, line_ptr + 12, 64);
|
||||||
|
stored_chksum[64] = '\0';
|
||||||
|
}
|
||||||
|
else if (strncmp(line_ptr, "Pad-Offset: ", 12) == 0) {
|
||||||
|
pad_offset = strtoull(line_ptr + 12, NULL, 10);
|
||||||
|
}
|
||||||
|
else if (strlen(line_ptr) == 0) {
|
||||||
|
in_data_section = 1;
|
||||||
|
}
|
||||||
|
else if (in_data_section) {
|
||||||
|
strncat(base64_data, line_ptr, sizeof(base64_data) - strlen(base64_data) - 1);
|
||||||
|
}
|
||||||
|
else if (strncmp(line_ptr, "Version:", 8) != 0 && strncmp(line_ptr, "Pad-", 4) != 0) {
|
||||||
|
// This might be base64 data without a blank line separator
|
||||||
|
strncat(base64_data, line_ptr, sizeof(base64_data) - strlen(base64_data) - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
line_ptr = strtok(NULL, "\n");
|
||||||
|
}
|
||||||
|
free(message_copy);
|
||||||
|
|
||||||
|
if (!found_begin) {
|
||||||
|
fprintf(stderr, "Error: Invalid message format - missing BEGIN header\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Error: No encrypted message provided\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we have the pad chksum from the message, construct filename
|
||||||
|
char pad_path[MAX_HASH_LENGTH + 20];
|
||||||
|
char state_path[MAX_HASH_LENGTH + 20];
|
||||||
|
get_pad_path(stored_chksum, pad_path, state_path);
|
||||||
|
|
||||||
|
// Check if we have this pad
|
||||||
|
if (access(pad_path, R_OK) != 0) {
|
||||||
|
fprintf(stderr, "Error: Required pad not found: %s\n", stored_chksum);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify pad integrity (silent check)
|
||||||
|
if (calculate_checksum(pad_path, current_chksum) != 0) {
|
||||||
|
fprintf(stderr, "Error: Cannot calculate current pad checksum\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(stored_chksum, current_chksum) != 0) {
|
||||||
|
fprintf(stderr, "Error: Pad integrity check failed!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode base64
|
||||||
|
int ciphertext_len;
|
||||||
|
unsigned char* ciphertext = custom_base64_decode(base64_data, &ciphertext_len);
|
||||||
|
if (!ciphertext) {
|
||||||
|
fprintf(stderr, "Error: Invalid base64 data\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read pad data at specified offset
|
||||||
|
FILE* pad_file = fopen(pad_path, "rb");
|
||||||
|
if (!pad_file) {
|
||||||
|
fprintf(stderr, "Error: Cannot open pad file %s\n", pad_path);
|
||||||
|
free(ciphertext);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fseek(pad_file, pad_offset, SEEK_SET) != 0) {
|
||||||
|
fprintf(stderr, "Error: Cannot seek to offset %lu in pad file\n", pad_offset);
|
||||||
|
free(ciphertext);
|
||||||
|
fclose(pad_file);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char* pad_data = malloc(ciphertext_len);
|
||||||
|
if (fread(pad_data, 1, ciphertext_len, pad_file) != (size_t)ciphertext_len) {
|
||||||
|
fprintf(stderr, "Error: Cannot read pad data\n");
|
||||||
|
free(ciphertext);
|
||||||
|
free(pad_data);
|
||||||
|
fclose(pad_file);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
fclose(pad_file);
|
||||||
|
|
||||||
|
// XOR decrypt
|
||||||
|
char* plaintext = malloc(ciphertext_len + 1);
|
||||||
|
for (int i = 0; i < ciphertext_len; i++) {
|
||||||
|
plaintext[i] = ciphertext[i] ^ pad_data[i];
|
||||||
|
}
|
||||||
|
plaintext[ciphertext_len] = '\0';
|
||||||
|
|
||||||
|
// Output only the decrypted text with newline and flush
|
||||||
|
printf("%s\n", plaintext);
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
free(ciphertext);
|
||||||
|
free(pad_data);
|
||||||
|
free(plaintext);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int encrypt_file(const char* pad_identifier, const char* input_file, const char* output_file, int ascii_armor) {
|
int encrypt_file(const char* pad_identifier, const char* input_file, const char* output_file, int ascii_armor) {
|
||||||
char* pad_chksum = find_pad_by_prefix(pad_identifier);
|
char* pad_chksum = find_pad_by_prefix(pad_identifier);
|
||||||
if (!pad_chksum) {
|
if (!pad_chksum) {
|
||||||
@@ -2293,6 +2514,212 @@ void get_pad_path(const char* chksum, char* pad_path, char* state_path) {
|
|||||||
snprintf(state_path, 1024, "%s/%s.state", current_pads_dir, chksum);
|
snprintf(state_path, 1024, "%s/%s.state", current_pads_dir, chksum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stdin detection functions implementation
|
||||||
|
int has_stdin_data(void) {
|
||||||
|
// Check if stdin is a pipe/redirect (not a terminal)
|
||||||
|
if (!isatty(STDIN_FILENO)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* read_stdin_text(void) {
|
||||||
|
size_t capacity = 4096;
|
||||||
|
size_t length = 0;
|
||||||
|
char* buffer = malloc(capacity);
|
||||||
|
|
||||||
|
if (!buffer) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char chunk[1024];
|
||||||
|
while (fgets(chunk, sizeof(chunk), stdin)) {
|
||||||
|
size_t chunk_len = strlen(chunk);
|
||||||
|
|
||||||
|
// Ensure we have enough capacity
|
||||||
|
while (length + chunk_len >= capacity) {
|
||||||
|
capacity *= 2;
|
||||||
|
char* new_buffer = realloc(buffer, capacity);
|
||||||
|
if (!new_buffer) {
|
||||||
|
free(buffer);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
buffer = new_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(buffer + length, chunk);
|
||||||
|
length += chunk_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove trailing newline if present
|
||||||
|
if (length > 0 && buffer[length - 1] == '\n') {
|
||||||
|
buffer[length - 1] = '\0';
|
||||||
|
length--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If empty, free and return NULL
|
||||||
|
if (length == 0) {
|
||||||
|
free(buffer);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pipe_mode(int argc, char* argv[], const char* piped_text) {
|
||||||
|
(void)argc; // Suppress unused parameter warning
|
||||||
|
(void)argv; // Suppress unused parameter warning
|
||||||
|
|
||||||
|
// Check if we have a default pad configured
|
||||||
|
char* default_pad = get_default_pad_path();
|
||||||
|
if (default_pad) {
|
||||||
|
// Verify the default pad exists and extract checksum
|
||||||
|
if (access(default_pad, R_OK) == 0) {
|
||||||
|
// Extract checksum from pad filename
|
||||||
|
char* filename = strrchr(default_pad, '/');
|
||||||
|
if (!filename) filename = default_pad;
|
||||||
|
else filename++; // Skip the '/'
|
||||||
|
|
||||||
|
// Extract checksum (remove .pad extension)
|
||||||
|
if (strlen(filename) >= 68 && strstr(filename, ".pad")) {
|
||||||
|
char pad_checksum[65];
|
||||||
|
strncpy(pad_checksum, filename, 64);
|
||||||
|
pad_checksum[64] = '\0';
|
||||||
|
|
||||||
|
free(default_pad);
|
||||||
|
|
||||||
|
// Encrypt using the default pad (silent mode)
|
||||||
|
return encrypt_text(pad_checksum, piped_text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "Error: Default pad not found or invalid: %s\n", default_pad);
|
||||||
|
free(default_pad);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "Error: No default pad configured for pipe mode\n");
|
||||||
|
fprintf(stderr, "Configure a default pad in ~/.otp/otp.conf\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Preferences management functions implementation
|
||||||
|
int load_preferences(void) {
|
||||||
|
char* home_dir = getenv("HOME");
|
||||||
|
if (!home_dir) {
|
||||||
|
return 1; // No home directory
|
||||||
|
}
|
||||||
|
|
||||||
|
char preferences_dir[1024];
|
||||||
|
char preferences_file[1024];
|
||||||
|
snprintf(preferences_dir, sizeof(preferences_dir), "%s/.otp", home_dir);
|
||||||
|
snprintf(preferences_file, sizeof(preferences_file), "%s/otp.conf", preferences_dir);
|
||||||
|
|
||||||
|
FILE* file = fopen(preferences_file, "r");
|
||||||
|
if (!file) {
|
||||||
|
return 0; // No preferences file, use defaults
|
||||||
|
}
|
||||||
|
|
||||||
|
char line[1024];
|
||||||
|
while (fgets(line, sizeof(line), file)) {
|
||||||
|
// Remove newline
|
||||||
|
line[strcspn(line, "\n")] = 0;
|
||||||
|
|
||||||
|
// Skip empty lines and comments
|
||||||
|
if (strlen(line) == 0 || line[0] == '#') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse key=value pairs
|
||||||
|
char* equals = strchr(line, '=');
|
||||||
|
if (equals) {
|
||||||
|
*equals = '\0';
|
||||||
|
char* key = line;
|
||||||
|
char* value = equals + 1;
|
||||||
|
|
||||||
|
// Trim whitespace
|
||||||
|
while (*key == ' ' || *key == '\t') key++;
|
||||||
|
while (*value == ' ' || *value == '\t') value++;
|
||||||
|
|
||||||
|
if (strcmp(key, "default_pad") == 0) {
|
||||||
|
strncpy(default_pad_path, value, sizeof(default_pad_path) - 1);
|
||||||
|
default_pad_path[sizeof(default_pad_path) - 1] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int save_preferences(void) {
|
||||||
|
char* home_dir = getenv("HOME");
|
||||||
|
if (!home_dir) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char preferences_dir[1024];
|
||||||
|
char preferences_file[1024];
|
||||||
|
snprintf(preferences_dir, sizeof(preferences_dir), "%s/.otp", home_dir);
|
||||||
|
snprintf(preferences_file, sizeof(preferences_file), "%s/otp.conf", preferences_dir);
|
||||||
|
|
||||||
|
// Create .otp directory if it doesn't exist
|
||||||
|
struct stat st = {0};
|
||||||
|
if (stat(preferences_dir, &st) == -1) {
|
||||||
|
if (mkdir(preferences_dir, 0755) != 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE* file = fopen(preferences_file, "w");
|
||||||
|
if (!file) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(file, "# OTP Preferences File\n");
|
||||||
|
fprintf(file, "# This file is automatically generated and updated by the OTP program\n\n");
|
||||||
|
|
||||||
|
if (strlen(default_pad_path) > 0) {
|
||||||
|
fprintf(file, "default_pad=%s\n", default_pad_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* get_preference(const char* key) {
|
||||||
|
if (strcmp(key, "default_pad") == 0) {
|
||||||
|
if (strlen(default_pad_path) > 0) {
|
||||||
|
return strdup(default_pad_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int set_preference(const char* key, const char* value) {
|
||||||
|
if (strcmp(key, "default_pad") == 0) {
|
||||||
|
if (value) {
|
||||||
|
strncpy(default_pad_path, value, sizeof(default_pad_path) - 1);
|
||||||
|
default_pad_path[sizeof(default_pad_path) - 1] = '\0';
|
||||||
|
} else {
|
||||||
|
default_pad_path[0] = '\0';
|
||||||
|
}
|
||||||
|
return save_preferences();
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* get_default_pad_path(void) {
|
||||||
|
if (strlen(default_pad_path) > 0) {
|
||||||
|
return strdup(default_pad_path);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int set_default_pad_path(const char* pad_path) {
|
||||||
|
return set_preference("default_pad", pad_path);
|
||||||
|
}
|
||||||
|
|
||||||
// OTP thumb drive detection function implementation
|
// OTP thumb drive detection function implementation
|
||||||
int detect_otp_thumb_drive(char* otp_drive_path, size_t path_size) {
|
int detect_otp_thumb_drive(char* otp_drive_path, size_t path_size) {
|
||||||
const char* mount_dirs[] = {"/media", "/run/media", "/mnt", NULL};
|
const char* mount_dirs[] = {"/media", "/run/media", "/mnt", NULL};
|
||||||
@@ -2305,14 +2732,44 @@ int detect_otp_thumb_drive(char* otp_drive_path, size_t path_size) {
|
|||||||
while ((mount_entry = readdir(mount_dir)) != NULL) {
|
while ((mount_entry = readdir(mount_dir)) != NULL) {
|
||||||
if (mount_entry->d_name[0] == '.') continue;
|
if (mount_entry->d_name[0] == '.') continue;
|
||||||
|
|
||||||
// Check if drive name starts with "OTP"
|
char mount_path[1024]; // Increased buffer size
|
||||||
if (strncmp(mount_entry->d_name, "OTP", 3) != 0) continue;
|
|
||||||
|
|
||||||
char mount_path[512];
|
|
||||||
snprintf(mount_path, sizeof(mount_path), "%s/%s", mount_dirs[mount_idx], mount_entry->d_name);
|
snprintf(mount_path, sizeof(mount_path), "%s/%s", mount_dirs[mount_idx], mount_entry->d_name);
|
||||||
|
|
||||||
// For /run/media, we need to go one level deeper (skip username)
|
// For /media, we need to go one level deeper (user directories)
|
||||||
if (strcmp(mount_dirs[mount_idx], "/run/media") == 0) {
|
if (strcmp(mount_dirs[mount_idx], "/media") == 0) {
|
||||||
|
// This is /media/[username] - look inside for drives
|
||||||
|
DIR* user_dir = opendir(mount_path);
|
||||||
|
if (!user_dir) continue;
|
||||||
|
|
||||||
|
struct dirent* user_entry;
|
||||||
|
while ((user_entry = readdir(user_dir)) != NULL) {
|
||||||
|
if (user_entry->d_name[0] == '.') continue;
|
||||||
|
|
||||||
|
// Check if drive name starts with "OTP"
|
||||||
|
if (strncmp(user_entry->d_name, "OTP", 3) != 0) continue;
|
||||||
|
|
||||||
|
char user_mount_path[1024]; // Increased buffer size
|
||||||
|
// Verify buffer has enough space before concatenation
|
||||||
|
size_t mount_len = strlen(mount_path);
|
||||||
|
size_t entry_len = strlen(user_entry->d_name);
|
||||||
|
if (mount_len + entry_len + 2 < sizeof(user_mount_path)) {
|
||||||
|
snprintf(user_mount_path, sizeof(user_mount_path), "%s/%s", mount_path, user_entry->d_name);
|
||||||
|
|
||||||
|
// Check if this is a readable directory
|
||||||
|
DIR* drive_dir = opendir(user_mount_path);
|
||||||
|
if (drive_dir) {
|
||||||
|
closedir(drive_dir);
|
||||||
|
strncpy(otp_drive_path, user_mount_path, path_size - 1);
|
||||||
|
otp_drive_path[path_size - 1] = '\0';
|
||||||
|
closedir(user_dir);
|
||||||
|
closedir(mount_dir);
|
||||||
|
return 1; // Found OTP drive
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closedir(user_dir);
|
||||||
|
} else if (strcmp(mount_dirs[mount_idx], "/run/media") == 0) {
|
||||||
|
// For /run/media, we need to go one level deeper (skip username)
|
||||||
DIR* user_dir = opendir(mount_path);
|
DIR* user_dir = opendir(mount_path);
|
||||||
if (!user_dir) continue;
|
if (!user_dir) continue;
|
||||||
|
|
||||||
@@ -2339,14 +2796,17 @@ int detect_otp_thumb_drive(char* otp_drive_path, size_t path_size) {
|
|||||||
}
|
}
|
||||||
closedir(user_dir);
|
closedir(user_dir);
|
||||||
} else {
|
} else {
|
||||||
// Direct mount point (like /media/OTP_DRIVE or /mnt/OTP_DRIVE)
|
// Direct mount point (like /mnt/OTP_DRIVE)
|
||||||
DIR* drive_dir = opendir(mount_path);
|
// Check if drive name starts with "OTP"
|
||||||
if (drive_dir) {
|
if (strncmp(mount_entry->d_name, "OTP", 3) == 0) {
|
||||||
closedir(drive_dir);
|
DIR* drive_dir = opendir(mount_path);
|
||||||
strncpy(otp_drive_path, mount_path, path_size - 1);
|
if (drive_dir) {
|
||||||
otp_drive_path[path_size - 1] = '\0';
|
closedir(drive_dir);
|
||||||
closedir(mount_dir);
|
strncpy(otp_drive_path, mount_path, path_size - 1);
|
||||||
return 1; // Found OTP drive
|
otp_drive_path[path_size - 1] = '\0';
|
||||||
|
closedir(mount_dir);
|
||||||
|
return 1; // Found OTP drive
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2937,7 +3397,7 @@ int handle_pads_menu(void) {
|
|||||||
pads[pad_count].chksum[64] = '\0';
|
pads[pad_count].chksum[64] = '\0';
|
||||||
|
|
||||||
// Get pad file size and usage info
|
// Get pad file size and usage info
|
||||||
char full_path[512];
|
char full_path[1024]; // Increased buffer size
|
||||||
snprintf(full_path, sizeof(full_path), "%s/%s", current_pads_dir, entry->d_name);
|
snprintf(full_path, sizeof(full_path), "%s/%s", current_pads_dir, entry->d_name);
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if (stat(full_path, &st) == 0) {
|
if (stat(full_path, &st) == 0) {
|
||||||
@@ -2988,10 +3448,15 @@ int handle_pads_menu(void) {
|
|||||||
|
|
||||||
char input[10];
|
char input[10];
|
||||||
if (fgets(input, sizeof(input), stdin)) {
|
if (fgets(input, sizeof(input), stdin)) {
|
||||||
char choice = toupper(input[0]);
|
char choice = toupper(input[0]);
|
||||||
if (choice == 'G') {
|
if (choice == 'G') {
|
||||||
return handle_generate_menu();
|
int result = handle_generate_menu();
|
||||||
|
if (result == 0) {
|
||||||
|
// After successful pad generation, return to pads menu
|
||||||
|
return handle_pads_menu();
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -3060,7 +3525,12 @@ int handle_pads_menu(void) {
|
|||||||
|
|
||||||
// Handle actions first
|
// Handle actions first
|
||||||
if (toupper(input[0]) == 'G') {
|
if (toupper(input[0]) == 'G') {
|
||||||
return handle_generate_menu();
|
int result = handle_generate_menu();
|
||||||
|
if (result == 0) {
|
||||||
|
// After successful pad generation, return to pads menu
|
||||||
|
return handle_pads_menu();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
} else if (toupper(input[0]) == 'B') {
|
} else if (toupper(input[0]) == 'B') {
|
||||||
return 0; // Back to main menu
|
return 0; // Back to main menu
|
||||||
}
|
}
|
||||||
@@ -3147,8 +3617,15 @@ void get_directory_display(const char* file_path, char* result, size_t result_si
|
|||||||
if (path_after_media) {
|
if (path_after_media) {
|
||||||
path_after_media++; // Skip the slash
|
path_after_media++; // Skip the slash
|
||||||
|
|
||||||
|
// For /media/user/LABEL pattern, skip the username to get to the drive label
|
||||||
|
if (strstr(media_start, "/media/")) {
|
||||||
|
char* next_slash = strchr(path_after_media, '/');
|
||||||
|
if (next_slash) {
|
||||||
|
path_after_media = next_slash + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
// For /run/media/user/LABEL pattern, skip the username
|
// For /run/media/user/LABEL pattern, skip the username
|
||||||
if (strstr(media_start, "/run/media/")) {
|
else if (strstr(media_start, "/run/media/")) {
|
||||||
char* next_slash = strchr(path_after_media, '/');
|
char* next_slash = strchr(path_after_media, '/');
|
||||||
if (next_slash) {
|
if (next_slash) {
|
||||||
path_after_media = next_slash + 1;
|
path_after_media = next_slash + 1;
|
||||||
@@ -3157,15 +3634,23 @@ void get_directory_display(const char* file_path, char* result, size_t result_si
|
|||||||
|
|
||||||
// Extract just the USB label (up to next slash or end)
|
// Extract just the USB label (up to next slash or end)
|
||||||
char* label_end = strchr(path_after_media, '/');
|
char* label_end = strchr(path_after_media, '/');
|
||||||
|
char usb_label[32];
|
||||||
if (label_end) {
|
if (label_end) {
|
||||||
size_t label_len = label_end - path_after_media;
|
size_t label_len = label_end - path_after_media;
|
||||||
if (label_len > 11) label_len = 11; // Max 11 chars for display
|
if (label_len > sizeof(usb_label) - 1) label_len = sizeof(usb_label) - 1;
|
||||||
strncpy(result, path_after_media, label_len);
|
strncpy(usb_label, path_after_media, label_len);
|
||||||
result[label_len] = '\0';
|
usb_label[label_len] = '\0';
|
||||||
} else {
|
} else {
|
||||||
// USB label is the last part
|
// USB label is the last part
|
||||||
strncpy(result, path_after_media, result_size - 1);
|
strncpy(usb_label, path_after_media, sizeof(usb_label) - 1);
|
||||||
result[result_size - 1] = '\0';
|
usb_label[sizeof(usb_label) - 1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format with USB: prefix, limiting total length to fit in result
|
||||||
|
snprintf(result, result_size, "USB:%s", usb_label);
|
||||||
|
// Truncate if too long
|
||||||
|
if (strlen(result) > 11) {
|
||||||
|
result[11] = '\0';
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
Testing updated files directory functionality
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Testing files directory functionality
|
|
||||||
BIN
test_new.txt.otp
BIN
test_new.txt.otp
Binary file not shown.
Reference in New Issue
Block a user