headers
Authored by
mfwolffe <wolffemf@dukes.jmu.edu>
- SHA
56b29945c573f7a3919a62a32ba64b95ad4be850- Parents
-
4b19270 - Tree
d4c7af1
56b2994
56b29945c573f7a3919a62a32ba64b95ad4be8504b19270
d4c7af1| Status | File | + | - |
|---|---|---|---|
| A |
src/accounts.h
|
119 | 0 |
| A |
src/config.h
|
101 | 0 |
| A |
src/display.h
|
159 | 0 |
| A |
src/error.h
|
200 | 0 |
| A |
src/git_ops.h
|
133 | 0 |
| A |
src/gitswitch.h
|
84 | 0 |
| A |
src/gpg_manager.h
|
107 | 0 |
| A |
src/ssh_manager.h
|
88 | 0 |
| A |
src/toml_parser.h
|
194 | 0 |
| A |
src/utils.h
|
155 | 0 |
src/accounts.hadded@@ -0,0 +1,119 @@ | ||
| 1 | +/* Account management and operations */ | |
| 2 | + | |
| 3 | +#ifndef ACCOUNTS_H | |
| 4 | +#define ACCOUNTS_H | |
| 5 | + | |
| 6 | +#include "gitswitch.h" | |
| 7 | + | |
| 8 | +/* Account validation result */ | |
| 9 | +typedef struct { | |
| 10 | + bool valid; | |
| 11 | + char error_message[512]; | |
| 12 | + char warnings[1024]; | |
| 13 | +} account_validation_t; | |
| 14 | + | |
| 15 | +/* Function prototypes */ | |
| 16 | + | |
| 17 | +/** | |
| 18 | + * Initialize accounts system | |
| 19 | + */ | |
| 20 | +int accounts_init(gitswitch_ctx_t *ctx); | |
| 21 | + | |
| 22 | +/** | |
| 23 | + * Switch to specified account | |
| 24 | + * - Validates account exists and is properly configured | |
| 25 | + * - Coordinates SSH and GPG switching | |
| 26 | + * - Updates git configuration | |
| 27 | + * - Verifies switch was successful | |
| 28 | + */ | |
| 29 | +int accounts_switch(gitswitch_ctx_t *ctx, const char *identifier); | |
| 30 | + | |
| 31 | +/** | |
| 32 | + * Add new account interactively | |
| 33 | + * - Prompts for account details | |
| 34 | + * - Validates input | |
| 35 | + * - Tests SSH/GPG configuration if provided | |
| 36 | + * - Saves to configuration | |
| 37 | + */ | |
| 38 | +int accounts_add_interactive(gitswitch_ctx_t *ctx); | |
| 39 | + | |
| 40 | +/** | |
| 41 | + * Remove account with confirmation | |
| 42 | + * - Shows account details | |
| 43 | + * - Prompts for confirmation | |
| 44 | + * - Cleans up associated SSH/GPG resources | |
| 45 | + * - Updates configuration | |
| 46 | + */ | |
| 47 | +int accounts_remove(gitswitch_ctx_t *ctx, const char *identifier); | |
| 48 | + | |
| 49 | +/** | |
| 50 | + * List all configured accounts | |
| 51 | + * - Shows account details in formatted table | |
| 52 | + * - Indicates current active account | |
| 53 | + * - Shows validation status for each account | |
| 54 | + */ | |
| 55 | +int accounts_list(const gitswitch_ctx_t *ctx); | |
| 56 | + | |
| 57 | +/** | |
| 58 | + * Show current account status | |
| 59 | + * - Displays currently active git configuration | |
| 60 | + * - Shows SSH keys loaded | |
| 61 | + * - Shows GPG signing configuration | |
| 62 | + * - Indicates scope (local/global) | |
| 63 | + */ | |
| 64 | +int accounts_show_status(const gitswitch_ctx_t *ctx); | |
| 65 | + | |
| 66 | +/** | |
| 67 | + * Validate account configuration | |
| 68 | + * - Checks required fields are present | |
| 69 | + * - Validates email format | |
| 70 | + * - Verifies SSH key file exists and has correct permissions | |
| 71 | + * - Validates GPG key exists and is usable | |
| 72 | + * - Tests connectivity if possible | |
| 73 | + */ | |
| 74 | +int accounts_validate(const account_t *account); | |
| 75 | + | |
| 76 | +/** | |
| 77 | + * Find account by various identifiers | |
| 78 | + * - Numeric ID (exact match) | |
| 79 | + * - Name (exact or partial match) | |
| 80 | + * - Email (exact match) | |
| 81 | + * - Description (partial match) | |
| 82 | + */ | |
| 83 | +account_t *accounts_find(const gitswitch_ctx_t *ctx, const char *identifier); | |
| 84 | + | |
| 85 | +/** | |
| 86 | + * Get next available account ID | |
| 87 | + */ | |
| 88 | +uint32_t accounts_get_next_id(const gitswitch_ctx_t *ctx); | |
| 89 | + | |
| 90 | +/** | |
| 91 | + * Clone account configuration (for editing) | |
| 92 | + */ | |
| 93 | +int accounts_clone(const account_t *src, account_t *dst); | |
| 94 | + | |
| 95 | +/** | |
| 96 | + * Compare two accounts for equality | |
| 97 | + */ | |
| 98 | +bool accounts_equal(const account_t *a, const account_t *b); | |
| 99 | + | |
| 100 | +/** | |
| 101 | + * Initialize account structure with defaults | |
| 102 | + */ | |
| 103 | +void accounts_init_struct(account_t *account); | |
| 104 | + | |
| 105 | +/** | |
| 106 | + * Clean up account resources | |
| 107 | + */ | |
| 108 | +void accounts_cleanup_struct(account_t *account); | |
| 109 | + | |
| 110 | +/** | |
| 111 | + * Run comprehensive health check on all accounts | |
| 112 | + * - Validates configuration | |
| 113 | + * - Tests SSH connectivity | |
| 114 | + * - Verifies GPG functionality | |
| 115 | + * - Reports issues and recommendations | |
| 116 | + */ | |
| 117 | +int accounts_health_check(const gitswitch_ctx_t *ctx); | |
| 118 | + | |
| 119 | +#endif /* ACCOUNTS_H */ | |
src/config.hadded@@ -0,0 +1,101 @@ | ||
| 1 | +/* Configuration file management and TOML parsing */ | |
| 2 | + | |
| 3 | +#ifndef CONFIG_H | |
| 4 | +#define CONFIG_H | |
| 5 | + | |
| 6 | +#include "gitswitch.h" | |
| 7 | + | |
| 8 | +/* Configuration file format version */ | |
| 9 | +#define CONFIG_FORMAT_VERSION "1.0" | |
| 10 | + | |
| 11 | +/* Default configuration template */ | |
| 12 | +extern const char *default_config_template; | |
| 13 | + | |
| 14 | +/* Function prototypes */ | |
| 15 | + | |
| 16 | +/** | |
| 17 | + * Initialize configuration system | |
| 18 | + * - Locates configuration file | |
| 19 | + * - Creates default config if none exists | |
| 20 | + * - Validates configuration format | |
| 21 | + */ | |
| 22 | +int config_init(gitswitch_ctx_t *ctx); | |
| 23 | + | |
| 24 | +/** | |
| 25 | + * Load configuration from TOML file | |
| 26 | + * - Parses TOML configuration | |
| 27 | + * - Validates all required fields | |
| 28 | + * - Populates gitswitch_ctx_t structure | |
| 29 | + */ | |
| 30 | +int config_load(gitswitch_ctx_t *ctx, const char *config_path); | |
| 31 | + | |
| 32 | +/** | |
| 33 | + * Save configuration to TOML file | |
| 34 | + * - Creates backup of existing config | |
| 35 | + * - Writes updated configuration | |
| 36 | + * - Validates written file | |
| 37 | + */ | |
| 38 | +int config_save(const gitswitch_ctx_t *ctx, const char *config_path); | |
| 39 | + | |
| 40 | +/** | |
| 41 | + * Create default configuration file | |
| 42 | + */ | |
| 43 | +int config_create_default(const char *config_path); | |
| 44 | + | |
| 45 | +/** | |
| 46 | + * Validate configuration structure | |
| 47 | + * - Checks all required fields are present | |
| 48 | + * - Validates account data integrity | |
| 49 | + * - Verifies file paths exist and are accessible | |
| 50 | + */ | |
| 51 | +int config_validate(const gitswitch_ctx_t *ctx); | |
| 52 | + | |
| 53 | +/** | |
| 54 | + * Get configuration file path | |
| 55 | + * - Checks environment variables | |
| 56 | + * - Falls back to default location | |
| 57 | + * - Creates directories if needed | |
| 58 | + */ | |
| 59 | +int config_get_path(char *path_buffer, size_t buffer_size); | |
| 60 | + | |
| 61 | +/** | |
| 62 | + * Add new account to configuration | |
| 63 | + */ | |
| 64 | +int config_add_account(gitswitch_ctx_t *ctx, const account_t *account); | |
| 65 | + | |
| 66 | +/** | |
| 67 | + * Remove account from configuration | |
| 68 | + */ | |
| 69 | +int config_remove_account(gitswitch_ctx_t *ctx, uint32_t account_id); | |
| 70 | + | |
| 71 | +/** | |
| 72 | + * Update existing account in configuration | |
| 73 | + */ | |
| 74 | +int config_update_account(gitswitch_ctx_t *ctx, const account_t *account); | |
| 75 | + | |
| 76 | +/** | |
| 77 | + * Find account by ID or name/description | |
| 78 | + */ | |
| 79 | +account_t *config_find_account(gitswitch_ctx_t *ctx, const char *identifier); | |
| 80 | + | |
| 81 | +/** | |
| 82 | + * Parse git scope from string | |
| 83 | + */ | |
| 84 | +git_scope_t config_parse_scope(const char *scope_str); | |
| 85 | + | |
| 86 | +/** | |
| 87 | + * Convert git scope to string | |
| 88 | + */ | |
| 89 | +const char *config_scope_to_string(git_scope_t scope); | |
| 90 | + | |
| 91 | +/** | |
| 92 | + * Backup configuration file with timestamp | |
| 93 | + */ | |
| 94 | +int config_backup(const char *config_path); | |
| 95 | + | |
| 96 | +/** | |
| 97 | + * Migrate configuration from older format versions | |
| 98 | + */ | |
| 99 | +int config_migrate(const char *config_path); | |
| 100 | + | |
| 101 | +#endif /* CONFIG_H */ | |
src/display.hadded@@ -0,0 +1,159 @@ | ||
| 1 | +/* Display and user interface functions */ | |
| 2 | + | |
| 3 | +#ifndef DISPLAY_H | |
| 4 | +#define DISPLAY_H | |
| 5 | + | |
| 6 | +#include <stdbool.h> | |
| 7 | +#include "gitswitch.h" | |
| 8 | + | |
| 9 | +/* Forward declarations - only declare what we need for Phase 2 */ | |
| 10 | + | |
| 11 | +/* Color codes */ | |
| 12 | +#define COLOR_RESET "\033[0m" | |
| 13 | +#define COLOR_RED "\033[31m" | |
| 14 | +#define COLOR_GREEN "\033[32m" | |
| 15 | +#define COLOR_YELLOW "\033[33m" | |
| 16 | +#define COLOR_BLUE "\033[34m" | |
| 17 | +#define COLOR_MAGENTA "\033[35m" | |
| 18 | +#define COLOR_CYAN "\033[36m" | |
| 19 | +#define COLOR_WHITE "\033[37m" | |
| 20 | +#define COLOR_BOLD "\033[1m" | |
| 21 | +#define COLOR_DIM "\033[2m" | |
| 22 | + | |
| 23 | +/* Status indicators */ | |
| 24 | +#define STATUS_SUCCESS "[OK]" | |
| 25 | +#define STATUS_ERROR "[ERROR]" | |
| 26 | +#define STATUS_WARNING "[WARN]" | |
| 27 | +#define STATUS_INFO "[INFO]" | |
| 28 | + | |
| 29 | +/* Function prototypes */ | |
| 30 | + | |
| 31 | +/** | |
| 32 | + * Initialize display system | |
| 33 | + * - Detect terminal capabilities | |
| 34 | + * - Set up color output based on TTY and preferences | |
| 35 | + */ | |
| 36 | +int display_init(bool force_color, bool no_color); | |
| 37 | + | |
| 38 | +/** | |
| 39 | + * Print formatted header with decorative border | |
| 40 | + */ | |
| 41 | +void display_header(const char *title); | |
| 42 | + | |
| 43 | +/** | |
| 44 | + * Print status message with appropriate color and icon | |
| 45 | + */ | |
| 46 | +void display_status(const char *level, const char *message, ...); | |
| 47 | + | |
| 48 | +/** | |
| 49 | + * Print account information in formatted table | |
| 50 | + */ | |
| 51 | +void display_account(const account_t *account, bool is_current); | |
| 52 | + | |
| 53 | +/** | |
| 54 | + * Print accounts list in formatted table | |
| 55 | + */ | |
| 56 | +void display_accounts_list(const gitswitch_ctx_t *ctx); | |
| 57 | + | |
| 58 | +/* These functions will be implemented in later phases | |
| 59 | +void display_current_status(const git_current_config_t *config); | |
| 60 | +void display_ssh_status(const ssh_config_t *ssh_config); | |
| 61 | +void display_gpg_status(const gpg_config_t *gpg_config); | |
| 62 | +void display_validation_results(const account_validation_t *validation); | |
| 63 | +*/ | |
| 64 | + | |
| 65 | +/** | |
| 66 | + * Print health check results | |
| 67 | + */ | |
| 68 | +void display_health_check(const gitswitch_ctx_t *ctx); | |
| 69 | + | |
| 70 | +/** | |
| 71 | + * Display interactive account selection menu | |
| 72 | + * Returns selected account ID or 0 if cancelled | |
| 73 | + */ | |
| 74 | +uint32_t display_account_menu(const gitswitch_ctx_t *ctx); | |
| 75 | + | |
| 76 | +/** | |
| 77 | + * Prompt user for account information during add/edit | |
| 78 | + */ | |
| 79 | +int display_prompt_account_info(account_t *account, bool is_edit); | |
| 80 | + | |
| 81 | +/** | |
| 82 | + * Confirm dangerous operations (account removal, etc.) | |
| 83 | + */ | |
| 84 | +bool display_confirm(const char *message, ...); | |
| 85 | + | |
| 86 | +/** | |
| 87 | + * Display progress indicator for long operations | |
| 88 | + */ | |
| 89 | +void display_progress(const char *operation, int percent); | |
| 90 | + | |
| 91 | +/** | |
| 92 | + * Clear current line (for progress updates) | |
| 93 | + */ | |
| 94 | +void display_clear_line(void); | |
| 95 | + | |
| 96 | +/** | |
| 97 | + * Print error message with context | |
| 98 | + */ | |
| 99 | +void display_error(const char *context, const char *message, ...); | |
| 100 | + | |
| 101 | +/** | |
| 102 | + * Print warning message | |
| 103 | + */ | |
| 104 | +void display_warning(const char *message, ...); | |
| 105 | + | |
| 106 | +/** | |
| 107 | + * Print success message | |
| 108 | + */ | |
| 109 | +void display_success(const char *message, ...); | |
| 110 | + | |
| 111 | +/** | |
| 112 | + * Print info message | |
| 113 | + */ | |
| 114 | +void display_info(const char *message, ...); | |
| 115 | + | |
| 116 | +/** | |
| 117 | + * Format and colorize text based on content type | |
| 118 | + */ | |
| 119 | +const char *display_colorize(const char *text, const char *type); | |
| 120 | + | |
| 121 | +/** | |
| 122 | + * Check if terminal supports color output | |
| 123 | + */ | |
| 124 | +bool display_supports_color(void); | |
| 125 | + | |
| 126 | +/** | |
| 127 | + * Get user input with prompt and validation | |
| 128 | + */ | |
| 129 | +int display_get_input(const char *prompt, char *buffer, size_t buffer_size, | |
| 130 | + bool (*validator)(const char *)); | |
| 131 | + | |
| 132 | +/** | |
| 133 | + * Get password/sensitive input (hidden) | |
| 134 | + */ | |
| 135 | +int display_get_password(const char *prompt, char *buffer, size_t buffer_size); | |
| 136 | + | |
| 137 | +/** | |
| 138 | + * Show help text for command or general usage | |
| 139 | + */ | |
| 140 | +void display_help(const char *command); | |
| 141 | + | |
| 142 | +/** | |
| 143 | + * Display version and build information | |
| 144 | + */ | |
| 145 | +void display_version(void); | |
| 146 | + | |
| 147 | +/** | |
| 148 | + * Print configuration file location and status | |
| 149 | + */ | |
| 150 | +void display_config_info(const gitswitch_ctx_t *ctx); | |
| 151 | + | |
| 152 | +/** | |
| 153 | + * Format table with proper column alignment | |
| 154 | + */ | |
| 155 | +void display_table_header(const char **headers, const int *widths, int columns); | |
| 156 | +void display_table_row(const char **values, const int *widths, int columns); | |
| 157 | +void display_table_separator(const int *widths, int columns); | |
| 158 | + | |
| 159 | +#endif /* DISPLAY_H */ | |
src/error.hadded@@ -0,0 +1,200 @@ | ||
| 1 | +/* Error handling and logging utilities */ | |
| 2 | + | |
| 3 | +#ifndef ERROR_H | |
| 4 | +#define ERROR_H | |
| 5 | + | |
| 6 | +#include <stdio.h> | |
| 7 | +#include <stdarg.h> | |
| 8 | +#include <errno.h> | |
| 9 | +#include <stdbool.h> | |
| 10 | + | |
| 11 | +/* Error codes */ | |
| 12 | +typedef enum { | |
| 13 | + ERR_SUCCESS = 0, | |
| 14 | + ERR_INVALID_ARGS = 1, | |
| 15 | + ERR_CONFIG_NOT_FOUND = 2, | |
| 16 | + ERR_CONFIG_INVALID = 3, | |
| 17 | + ERR_CONFIG_WRITE_FAILED = 4, | |
| 18 | + ERR_ACCOUNT_NOT_FOUND = 5, | |
| 19 | + ERR_ACCOUNT_INVALID = 6, | |
| 20 | + ERR_ACCOUNT_EXISTS = 7, | |
| 21 | + ERR_GIT_NOT_FOUND = 8, | |
| 22 | + ERR_GIT_CONFIG_FAILED = 9, | |
| 23 | + ERR_GIT_NOT_REPO = 10, | |
| 24 | + ERR_GIT_NOT_REPOSITORY = 10, /* Alias for consistency */ | |
| 25 | + ERR_GIT_CONFIG_NOT_FOUND = 11, | |
| 26 | + ERR_GIT_REPOSITORY_INVALID = 12, | |
| 27 | + ERR_SSH_AGENT_FAILED = 13, | |
| 28 | + ERR_SSH_KEY_FAILED = 14, | |
| 29 | + ERR_SSH_KEY_NOT_FOUND = 15, | |
| 30 | + ERR_SSH_CONNECTION_FAILED = 16, | |
| 31 | + ERR_SSH_NOT_FOUND = 29, | |
| 32 | + ERR_SSH_AGENT_NOT_FOUND = 30, | |
| 33 | + ERR_SSH_KEY_LOAD_FAILED = 31, | |
| 34 | + ERR_SSH_AGENT_START_FAILED = 32, | |
| 35 | + ERR_SSH_KEY_INVALID = 33, | |
| 36 | + ERR_SSH_KEY_PERMISSIONS = 34, | |
| 37 | + ERR_SSH_KEY_OWNERSHIP = 35, | |
| 38 | + ERR_SSH_AGENT_SOCKET_INVALID = 36, | |
| 39 | + ERR_GPG_NOT_FOUND = 37, | |
| 40 | + ERR_GPG_KEY_FAILED = 38, | |
| 41 | + ERR_GPG_KEY_NOT_FOUND = 39, | |
| 42 | + ERR_GPG_SIGNING_FAILED = 40, | |
| 43 | + ERR_MEMORY_ALLOCATION = 41, | |
| 44 | + ERR_FILE_IO = 42, | |
| 45 | + ERR_PERMISSION_DENIED = 43, | |
| 46 | + ERR_NETWORK_ERROR = 44, | |
| 47 | + ERR_SYSTEM_CALL = 45, | |
| 48 | + ERR_SYSTEM_REQUIREMENT = 46, | |
| 49 | + ERR_SYSTEM_COMMAND_FAILED = 47, | |
| 50 | + ERR_INVALID_PATH = 48, | |
| 51 | + ERR_UNKNOWN = 99 | |
| 52 | +} error_code_t; | |
| 53 | + | |
| 54 | +/* Log levels */ | |
| 55 | +typedef enum { | |
| 56 | + LOG_LEVEL_DEBUG, | |
| 57 | + LOG_LEVEL_INFO, | |
| 58 | + LOG_LEVEL_WARNING, | |
| 59 | + LOG_LEVEL_ERROR, | |
| 60 | + LOG_LEVEL_CRITICAL | |
| 61 | +} log_level_t; | |
| 62 | + | |
| 63 | +/* Error context for detailed error reporting */ | |
| 64 | +typedef struct { | |
| 65 | + error_code_t code; | |
| 66 | + char message[512]; | |
| 67 | + char details[1024]; | |
| 68 | + const char *file; | |
| 69 | + int line; | |
| 70 | + const char *function; | |
| 71 | + int system_errno; | |
| 72 | +} error_context_t; | |
| 73 | + | |
| 74 | +/* Global error context */ | |
| 75 | +extern error_context_t g_last_error; | |
| 76 | + | |
| 77 | +/* Logging configuration */ | |
| 78 | +extern log_level_t g_log_level; | |
| 79 | +extern FILE *g_log_file; | |
| 80 | +extern bool g_log_to_stderr; | |
| 81 | + | |
| 82 | +/* Macros for error reporting with context */ | |
| 83 | +#define set_error(code, fmt, ...) \ | |
| 84 | + set_error_context((code), __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) | |
| 85 | + | |
| 86 | +#define set_system_error(code, fmt, ...) \ | |
| 87 | + set_system_error_context((code), __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) | |
| 88 | + | |
| 89 | +/* Logging macros */ | |
| 90 | +#define log_debug(fmt, ...) \ | |
| 91 | + log_message(LOG_LEVEL_DEBUG, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) | |
| 92 | + | |
| 93 | +#define log_info(fmt, ...) \ | |
| 94 | + log_message(LOG_LEVEL_INFO, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) | |
| 95 | + | |
| 96 | +#define log_warning(fmt, ...) \ | |
| 97 | + log_message(LOG_LEVEL_WARNING, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) | |
| 98 | + | |
| 99 | +#define log_error(fmt, ...) \ | |
| 100 | + log_message(LOG_LEVEL_ERROR, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) | |
| 101 | + | |
| 102 | +#define log_critical(fmt, ...) \ | |
| 103 | + log_message(LOG_LEVEL_CRITICAL, __FILE__, __LINE__, __func__, fmt, ##__VA_ARGS__) | |
| 104 | + | |
| 105 | +/* Function prototypes */ | |
| 106 | + | |
| 107 | +/** | |
| 108 | + * Initialize error handling and logging system | |
| 109 | + */ | |
| 110 | +int error_init(log_level_t level, const char *log_file_path); | |
| 111 | + | |
| 112 | +/** | |
| 113 | + * Cleanup error handling system | |
| 114 | + */ | |
| 115 | +void error_cleanup(void); | |
| 116 | + | |
| 117 | +/** | |
| 118 | + * Set error context with detailed information | |
| 119 | + */ | |
| 120 | +void set_error_context(error_code_t code, const char *file, int line, | |
| 121 | + const char *function, const char *fmt, ...); | |
| 122 | + | |
| 123 | +/** | |
| 124 | + * Set error context including system errno | |
| 125 | + */ | |
| 126 | +void set_system_error_context(error_code_t code, const char *file, int line, | |
| 127 | + const char *function, const char *fmt, ...); | |
| 128 | + | |
| 129 | +/** | |
| 130 | + * Get last error information | |
| 131 | + */ | |
| 132 | +const error_context_t *get_last_error(void); | |
| 133 | + | |
| 134 | +/** | |
| 135 | + * Clear last error | |
| 136 | + */ | |
| 137 | +void clear_error(void); | |
| 138 | + | |
| 139 | +/** | |
| 140 | + * Convert error code to human-readable string | |
| 141 | + */ | |
| 142 | +const char *error_code_to_string(error_code_t code); | |
| 143 | + | |
| 144 | +/** | |
| 145 | + * Log message with context information | |
| 146 | + */ | |
| 147 | +void log_message(log_level_t level, const char *file, int line, | |
| 148 | + const char *function, const char *fmt, ...); | |
| 149 | + | |
| 150 | +/** | |
| 151 | + * Set logging level | |
| 152 | + */ | |
| 153 | +void set_log_level(log_level_t level); | |
| 154 | + | |
| 155 | +/** | |
| 156 | + * Set log output file (NULL for stderr) | |
| 157 | + */ | |
| 158 | +int set_log_file(const char *file_path); | |
| 159 | + | |
| 160 | +/** | |
| 161 | + * Enable/disable logging to stderr | |
| 162 | + */ | |
| 163 | +void set_log_to_stderr(bool enable); | |
| 164 | + | |
| 165 | +/** | |
| 166 | + * Format error message for user display | |
| 167 | + */ | |
| 168 | +void format_error_message(char *buffer, size_t buffer_size, | |
| 169 | + const error_context_t *error); | |
| 170 | + | |
| 171 | +/** | |
| 172 | + * Print formatted error to stderr | |
| 173 | + */ | |
| 174 | +void print_error(const char *prefix); | |
| 175 | + | |
| 176 | +/** | |
| 177 | + * Check if error level should be logged | |
| 178 | + */ | |
| 179 | +bool should_log(log_level_t level); | |
| 180 | + | |
| 181 | +/** | |
| 182 | + * Get current timestamp for logging | |
| 183 | + */ | |
| 184 | +void get_timestamp(char *buffer, size_t buffer_size); | |
| 185 | + | |
| 186 | +/** | |
| 187 | + * Safe string functions that set error context on failure | |
| 188 | + */ | |
| 189 | +int safe_strncpy(char *dest, const char *src, size_t dest_size); | |
| 190 | +int safe_strncat(char *dest, const char *src, size_t dest_size); | |
| 191 | +int safe_snprintf(char *buffer, size_t buffer_size, const char *fmt, ...); | |
| 192 | + | |
| 193 | +/** | |
| 194 | + * Memory allocation functions that set error context on failure | |
| 195 | + */ | |
| 196 | +void *safe_malloc(size_t size); | |
| 197 | +void *safe_calloc(size_t nmemb, size_t size); | |
| 198 | +void *safe_realloc(void *ptr, size_t size); | |
| 199 | + | |
| 200 | +#endif /* ERROR_H */ | |
src/git_ops.hadded@@ -0,0 +1,133 @@ | ||
| 1 | +/* Git configuration operations */ | |
| 2 | + | |
| 3 | +#ifndef GIT_OPS_H | |
| 4 | +#define GIT_OPS_H | |
| 5 | + | |
| 6 | +#include "gitswitch.h" | |
| 7 | + | |
| 8 | +/* Git configuration keys */ | |
| 9 | +#define GIT_CONFIG_USER_NAME "user.name" | |
| 10 | +#define GIT_CONFIG_USER_EMAIL "user.email" | |
| 11 | +#define GIT_CONFIG_USER_SIGNINGKEY "user.signingkey" | |
| 12 | +#define GIT_CONFIG_COMMIT_GPGSIGN "commit.gpgsign" | |
| 13 | +#define GIT_CONFIG_GPG_PROGRAM "gpg.program" | |
| 14 | +#define GIT_CONFIG_CORE_SSHCOMMAND "core.sshcommand" | |
| 15 | + | |
| 16 | +/* Current git configuration */ | |
| 17 | +typedef struct { | |
| 18 | + char name[MAX_NAME_LEN]; | |
| 19 | + char email[MAX_EMAIL_LEN]; | |
| 20 | + char signing_key[MAX_KEY_ID_LEN]; | |
| 21 | + bool gpg_signing_enabled; | |
| 22 | + git_scope_t scope; | |
| 23 | + bool valid; | |
| 24 | +} git_current_config_t; | |
| 25 | + | |
| 26 | +/* Function prototypes */ | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * Initialize git operations | |
| 30 | + * - Verify git is available | |
| 31 | + * - Check git version compatibility | |
| 32 | + * - Validate current repository if in local scope | |
| 33 | + */ | |
| 34 | +int git_ops_init(void); | |
| 35 | + | |
| 36 | +/** | |
| 37 | + * Set git configuration for account | |
| 38 | + * - Sets user.name and user.email | |
| 39 | + * - Configures GPG signing if enabled | |
| 40 | + * - Sets SSH command if custom SSH configuration needed | |
| 41 | + * - Validates configuration was set correctly | |
| 42 | + */ | |
| 43 | +int git_set_config(const account_t *account, git_scope_t scope); | |
| 44 | + | |
| 45 | +/** | |
| 46 | + * Get current git configuration | |
| 47 | + * - Reads current user.name and user.email | |
| 48 | + * - Gets GPG signing configuration | |
| 49 | + * - Determines configuration scope | |
| 50 | + * - Returns structured configuration data | |
| 51 | + */ | |
| 52 | +int git_get_current_config(git_current_config_t *config); | |
| 53 | + | |
| 54 | +/** | |
| 55 | + * Clear git configuration (unset values) | |
| 56 | + */ | |
| 57 | +int git_clear_config(git_scope_t scope); | |
| 58 | + | |
| 59 | +/** | |
| 60 | + * Validate git repository | |
| 61 | + * - Checks if current directory is a git repository | |
| 62 | + * - Verifies repository is not bare | |
| 63 | + * - Checks repository health | |
| 64 | + */ | |
| 65 | +int git_validate_repository(void); | |
| 66 | + | |
| 67 | +/** | |
| 68 | + * Get git configuration scope (local, global, system) | |
| 69 | + * Returns the scope where the configuration is currently set | |
| 70 | + */ | |
| 71 | +git_scope_t git_get_config_scope(const char *config_key); | |
| 72 | + | |
| 73 | +/** | |
| 74 | + * Test git configuration | |
| 75 | + * - Creates a test commit (dry-run) | |
| 76 | + * - Validates signing if enabled | |
| 77 | + * - Verifies SSH access to remotes if applicable | |
| 78 | + */ | |
| 79 | +int git_test_config(const account_t *account, git_scope_t scope); | |
| 80 | + | |
| 81 | +/** | |
| 82 | + * Set single git configuration value | |
| 83 | + */ | |
| 84 | +int git_set_config_value(const char *key, const char *value, git_scope_t scope); | |
| 85 | + | |
| 86 | +/** | |
| 87 | + * Get single git configuration value | |
| 88 | + */ | |
| 89 | +int git_get_config_value(const char *key, char *value, size_t value_size, | |
| 90 | + git_scope_t scope); | |
| 91 | + | |
| 92 | +/** | |
| 93 | + * Unset git configuration value | |
| 94 | + */ | |
| 95 | +int git_unset_config_value(const char *key, git_scope_t scope); | |
| 96 | + | |
| 97 | +/** | |
| 98 | + * List all git configuration values for debugging | |
| 99 | + */ | |
| 100 | +int git_list_config(git_scope_t scope, char *output, size_t output_size); | |
| 101 | + | |
| 102 | +/** | |
| 103 | + * Configure SSH command for git operations | |
| 104 | + * - Sets core.sshCommand to use specific SSH key | |
| 105 | + * - Handles SSH agent socket specification | |
| 106 | + * - Configures SSH options for security | |
| 107 | + */ | |
| 108 | +int git_configure_ssh(const account_t *account, git_scope_t scope); | |
| 109 | + | |
| 110 | +/** | |
| 111 | + * Configure GPG for git operations | |
| 112 | + * - Sets user.signingkey | |
| 113 | + * - Enables/disables commit.gpgsign | |
| 114 | + * - Sets gpg.program if using custom GPG | |
| 115 | + */ | |
| 116 | +int git_configure_gpg(const account_t *account, git_scope_t scope); | |
| 117 | + | |
| 118 | +/** | |
| 119 | + * Check if current directory is a git repository | |
| 120 | + */ | |
| 121 | +bool git_is_repository(void); | |
| 122 | + | |
| 123 | +/** | |
| 124 | + * Get repository root directory | |
| 125 | + */ | |
| 126 | +int git_get_repo_root(char *path, size_t path_size); | |
| 127 | + | |
| 128 | +/** | |
| 129 | + * Convert scope enum to git config scope string | |
| 130 | + */ | |
| 131 | +const char *git_scope_to_flag(git_scope_t scope); | |
| 132 | + | |
| 133 | +#endif /* GIT_OPS_H */ | |
src/gitswitch.hadded@@ -0,0 +1,84 @@ | ||
| 1 | +/* gitswitch-c: Main header with common definitions and constants */ | |
| 2 | + | |
| 3 | +#ifndef GITSWITCH_H | |
| 4 | +#define GITSWITCH_H | |
| 5 | + | |
| 6 | +#include <stddef.h> | |
| 7 | +#include <stdbool.h> | |
| 8 | +#include <stdint.h> | |
| 9 | + | |
| 10 | +/* Version information */ | |
| 11 | +#define GITSWITCH_VERSION "1.0.0-dev" | |
| 12 | +#define GITSWITCH_NAME "gitswitch-c" | |
| 13 | + | |
| 14 | +/* Configuration constants */ | |
| 15 | +#define MAX_PATH_LEN 4096 | |
| 16 | +#define MAX_NAME_LEN 256 | |
| 17 | +#define MAX_EMAIL_LEN 320 /* RFC 5321 limit */ | |
| 18 | +#define MAX_DESC_LEN 512 | |
| 19 | +#define MAX_KEY_ID_LEN 64 | |
| 20 | +#define MAX_ACCOUNTS 64 | |
| 21 | + | |
| 22 | +/* Default configuration paths */ | |
| 23 | +#define DEFAULT_CONFIG_DIR ".config/gitswitch" | |
| 24 | +#define DEFAULT_CONFIG_FILE "accounts.toml" | |
| 25 | +#define DEFAULT_SSH_DIR ".ssh" | |
| 26 | +#define DEFAULT_GPG_DIR ".gnupg" | |
| 27 | + | |
| 28 | +/* Exit codes */ | |
| 29 | +#define EXIT_SUCCESS 0 | |
| 30 | +#define EXIT_FAILURE 1 | |
| 31 | +#define EXIT_CONFIG_ERROR 2 | |
| 32 | +#define EXIT_VALIDATION_ERROR 3 | |
| 33 | +#define EXIT_SSH_ERROR 4 | |
| 34 | +#define EXIT_GPG_ERROR 5 | |
| 35 | + | |
| 36 | +/* Git scopes */ | |
| 37 | +typedef enum { | |
| 38 | + GIT_SCOPE_LOCAL, | |
| 39 | + GIT_SCOPE_GLOBAL, | |
| 40 | + GIT_SCOPE_SYSTEM | |
| 41 | +} git_scope_t; | |
| 42 | + | |
| 43 | +/* Account structure */ | |
| 44 | +typedef struct { | |
| 45 | + uint32_t id; | |
| 46 | + char name[MAX_NAME_LEN]; | |
| 47 | + char email[MAX_EMAIL_LEN]; | |
| 48 | + char description[MAX_DESC_LEN]; | |
| 49 | + git_scope_t preferred_scope; | |
| 50 | + | |
| 51 | + /* SSH configuration */ | |
| 52 | + bool ssh_enabled; | |
| 53 | + char ssh_key_path[MAX_PATH_LEN]; | |
| 54 | + char ssh_host_alias[MAX_NAME_LEN]; | |
| 55 | + | |
| 56 | + /* GPG configuration */ | |
| 57 | + bool gpg_enabled; | |
| 58 | + bool gpg_signing_enabled; | |
| 59 | + char gpg_key_id[MAX_KEY_ID_LEN]; | |
| 60 | + | |
| 61 | +} account_t; | |
| 62 | + | |
| 63 | +/* Global configuration */ | |
| 64 | +typedef struct { | |
| 65 | + git_scope_t default_scope; | |
| 66 | + char config_path[MAX_PATH_LEN]; | |
| 67 | + bool verbose; | |
| 68 | + bool dry_run; | |
| 69 | + bool color_output; | |
| 70 | +} config_t; | |
| 71 | + | |
| 72 | +/* Application context */ | |
| 73 | +typedef struct { | |
| 74 | + config_t config; | |
| 75 | + account_t accounts[MAX_ACCOUNTS]; | |
| 76 | + size_t account_count; | |
| 77 | + account_t *current_account; | |
| 78 | +} gitswitch_ctx_t; | |
| 79 | + | |
| 80 | +/* Function prototypes */ | |
| 81 | +int gitswitch_init(gitswitch_ctx_t *ctx); | |
| 82 | +void gitswitch_cleanup(gitswitch_ctx_t *ctx); | |
| 83 | + | |
| 84 | +#endif /* GITSWITCH_H */ | |
src/gpg_manager.hadded@@ -0,0 +1,107 @@ | ||
| 1 | +/* GPG key management with proper isolation and signing configuration */ | |
| 2 | + | |
| 3 | +#ifndef GPG_MANAGER_H | |
| 4 | +#define GPG_MANAGER_H | |
| 5 | + | |
| 6 | +#include "gitswitch.h" | |
| 7 | + | |
| 8 | +/* GPG management modes */ | |
| 9 | +typedef enum { | |
| 10 | + GPG_MODE_SYSTEM, /* Use system GPG configuration */ | |
| 11 | + GPG_MODE_ISOLATED, /* Use isolated GNUPGHOME per account */ | |
| 12 | + GPG_MODE_SHARED /* Shared GNUPGHOME with key switching */ | |
| 13 | +} gpg_mode_t; | |
| 14 | + | |
| 15 | +/* GPG configuration structure */ | |
| 16 | +typedef struct { | |
| 17 | + gpg_mode_t mode; | |
| 18 | + char gnupg_home[MAX_PATH_LEN]; /* GNUPGHOME path */ | |
| 19 | + char current_key_id[MAX_KEY_ID_LEN]; | |
| 20 | + bool signing_enabled; | |
| 21 | + bool home_owned; /* Whether we created this GNUPGHOME */ | |
| 22 | +} gpg_config_t; | |
| 23 | + | |
| 24 | +/* Function prototypes */ | |
| 25 | + | |
| 26 | +/** | |
| 27 | + * Initialize GPG manager with specified mode | |
| 28 | + */ | |
| 29 | +int gpg_manager_init(gpg_config_t *gpg_config, gpg_mode_t mode); | |
| 30 | + | |
| 31 | +/** | |
| 32 | + * Cleanup GPG manager | |
| 33 | + */ | |
| 34 | +void gpg_manager_cleanup(gpg_config_t *gpg_config); | |
| 35 | + | |
| 36 | +/** | |
| 37 | + * Switch to account's GPG configuration with proper isolation | |
| 38 | + * - Sets appropriate GNUPGHOME if using isolated mode | |
| 39 | + * - Configures git signing key | |
| 40 | + * - Enables/disables git commit signing | |
| 41 | + * - Validates key exists and is usable | |
| 42 | + */ | |
| 43 | +int gpg_switch_account(gpg_config_t *gpg_config, const account_t *account); | |
| 44 | + | |
| 45 | +/** | |
| 46 | + * Create isolated GNUPGHOME for account | |
| 47 | + * - Creates directory with proper permissions (700) | |
| 48 | + * - Imports account's GPG key if available | |
| 49 | + * - Sets up basic GPG configuration | |
| 50 | + */ | |
| 51 | +int gpg_create_isolated_home(gpg_config_t *gpg_config, const account_t *account); | |
| 52 | + | |
| 53 | +/** | |
| 54 | + * Import GPG key from file or keyserver | |
| 55 | + * - Supports ASCII-armored and binary key formats | |
| 56 | + * - Validates key after import | |
| 57 | + * - Sets trust level appropriately | |
| 58 | + */ | |
| 59 | +int gpg_import_key(gpg_config_t *gpg_config, const char *key_source); | |
| 60 | + | |
| 61 | +/** | |
| 62 | + * Export GPG public key for backup/sharing | |
| 63 | + */ | |
| 64 | +int gpg_export_public_key(gpg_config_t *gpg_config, const char *key_id, | |
| 65 | + char *output, size_t output_size); | |
| 66 | + | |
| 67 | +/** | |
| 68 | + * List available GPG keys | |
| 69 | + */ | |
| 70 | +int gpg_list_keys(gpg_config_t *gpg_config, char *output, size_t output_size); | |
| 71 | + | |
| 72 | +/** | |
| 73 | + * Validate GPG key exists and is usable | |
| 74 | + * - Checks key exists in keyring | |
| 75 | + * - Verifies key is not expired | |
| 76 | + * - Tests signing capability if required | |
| 77 | + */ | |
| 78 | +int gpg_validate_key(gpg_config_t *gpg_config, const char *key_id); | |
| 79 | + | |
| 80 | +/** | |
| 81 | + * Configure git GPG signing | |
| 82 | + * - Sets user.signingkey | |
| 83 | + * - Enables/disables commit.gpgsign | |
| 84 | + * - Sets gpg.program if needed | |
| 85 | + */ | |
| 86 | +int gpg_configure_git_signing(gpg_config_t *gpg_config, const account_t *account, | |
| 87 | + git_scope_t scope); | |
| 88 | + | |
| 89 | +/** | |
| 90 | + * Test GPG signing by creating a test signature | |
| 91 | + */ | |
| 92 | +int gpg_test_signing(gpg_config_t *gpg_config, const char *key_id); | |
| 93 | + | |
| 94 | +/** | |
| 95 | + * Generate new GPG key for account | |
| 96 | + * - Creates key with account name and email | |
| 97 | + * - Uses secure key parameters | |
| 98 | + * - Exports public key for verification | |
| 99 | + */ | |
| 100 | +int gpg_generate_key(gpg_config_t *gpg_config, const account_t *account); | |
| 101 | + | |
| 102 | +/** | |
| 103 | + * Set environment variables for GPG operation | |
| 104 | + */ | |
| 105 | +int gpg_set_environment(const gpg_config_t *gpg_config); | |
| 106 | + | |
| 107 | +#endif /* GPG_MANAGER_H */ | |
src/ssh_manager.hadded@@ -0,0 +1,88 @@ | ||
| 1 | +/* SSH key and agent management with proper isolation */ | |
| 2 | + | |
| 3 | +#ifndef SSH_MANAGER_H | |
| 4 | +#define SSH_MANAGER_H | |
| 5 | + | |
| 6 | +#include "gitswitch.h" | |
| 7 | + | |
| 8 | +/* SSH agent management modes */ | |
| 9 | +typedef enum { | |
| 10 | + SSH_AGENT_SYSTEM, /* Use system SSH agent */ | |
| 11 | + SSH_AGENT_ISOLATED, /* Use isolated SSH agent per account */ | |
| 12 | + SSH_AGENT_NONE /* No SSH agent management */ | |
| 13 | +} ssh_agent_mode_t; | |
| 14 | + | |
| 15 | +/* SSH configuration structure */ | |
| 16 | +typedef struct { | |
| 17 | + ssh_agent_mode_t mode; | |
| 18 | + char agent_socket_path[MAX_PATH_LEN]; | |
| 19 | + pid_t agent_pid; | |
| 20 | + bool agent_owned; /* Whether we started this agent */ | |
| 21 | +} ssh_config_t; | |
| 22 | + | |
| 23 | +/* Function prototypes */ | |
| 24 | + | |
| 25 | +/** | |
| 26 | + * Initialize SSH manager with specified mode | |
| 27 | + */ | |
| 28 | +int ssh_manager_init(ssh_config_t *ssh_config, ssh_agent_mode_t mode); | |
| 29 | + | |
| 30 | +/** | |
| 31 | + * Cleanup SSH manager, stopping owned agents | |
| 32 | + */ | |
| 33 | +void ssh_manager_cleanup(ssh_config_t *ssh_config); | |
| 34 | + | |
| 35 | +/** | |
| 36 | + * Switch to account's SSH configuration with proper isolation | |
| 37 | + * - Clears current SSH agent keys if using isolated mode | |
| 38 | + * - Loads account's SSH key into appropriate agent | |
| 39 | + * - Updates SSH_AUTH_SOCK environment if needed | |
| 40 | + * - Validates key is properly loaded | |
| 41 | + */ | |
| 42 | +int ssh_switch_account(ssh_config_t *ssh_config, const account_t *account); | |
| 43 | + | |
| 44 | +/** | |
| 45 | + * Start isolated SSH agent for account | |
| 46 | + * Returns socket path and PID for cleanup | |
| 47 | + */ | |
| 48 | +int ssh_start_isolated_agent(ssh_config_t *ssh_config, const account_t *account); | |
| 49 | + | |
| 50 | +/** | |
| 51 | + * Stop SSH agent (only if we own it) | |
| 52 | + */ | |
| 53 | +int ssh_stop_agent(ssh_config_t *ssh_config); | |
| 54 | + | |
| 55 | +/** | |
| 56 | + * Clear all keys from SSH agent | |
| 57 | + */ | |
| 58 | +int ssh_clear_agent_keys(ssh_config_t *ssh_config); | |
| 59 | + | |
| 60 | +/** | |
| 61 | + * Add key to SSH agent with validation | |
| 62 | + * - Verifies key file exists and has correct permissions | |
| 63 | + * - Loads key into agent | |
| 64 | + * - Confirms key was loaded successfully | |
| 65 | + */ | |
| 66 | +int ssh_add_key(ssh_config_t *ssh_config, const char *key_path); | |
| 67 | + | |
| 68 | +/** | |
| 69 | + * List loaded SSH keys for verification | |
| 70 | + */ | |
| 71 | +int ssh_list_keys(ssh_config_t *ssh_config, char *output, size_t output_size); | |
| 72 | + | |
| 73 | +/** | |
| 74 | + * Validate SSH key file permissions and format | |
| 75 | + */ | |
| 76 | +int ssh_validate_key_file(const char *key_path); | |
| 77 | + | |
| 78 | +/** | |
| 79 | + * Set SSH host alias in ~/.ssh/config if specified | |
| 80 | + */ | |
| 81 | +int ssh_configure_host_alias(const account_t *account); | |
| 82 | + | |
| 83 | +/** | |
| 84 | + * Test SSH connection to verify authentication | |
| 85 | + */ | |
| 86 | +int ssh_test_connection(const account_t *account, const char *host); | |
| 87 | + | |
| 88 | +#endif /* SSH_MANAGER_H */ | |
src/toml_parser.hadded@@ -0,0 +1,194 @@ | ||
| 1 | +/* Minimal, security-focused TOML parser for gitswitch-c configuration | |
| 2 | + * Designed specifically for our configuration structure with extensive validation | |
| 3 | + */ | |
| 4 | + | |
| 5 | +#ifndef TOML_PARSER_H | |
| 6 | +#define TOML_PARSER_H | |
| 7 | + | |
| 8 | +#include <stdbool.h> | |
| 9 | +#include <stddef.h> | |
| 10 | + | |
| 11 | +/* Maximum limits for security */ | |
| 12 | +#define TOML_MAX_KEY_LEN 64 | |
| 13 | +#define TOML_MAX_VALUE_LEN 512 | |
| 14 | +#define TOML_MAX_SECTION_LEN 64 | |
| 15 | +#define TOML_MAX_SECTIONS 32 | |
| 16 | +#define TOML_MAX_KEYS_PER_SECTION 16 | |
| 17 | +#define TOML_MAX_FILE_SIZE (64 * 1024) /* 64KB max config file */ | |
| 18 | + | |
| 19 | +/* TOML value types */ | |
| 20 | +typedef enum { | |
| 21 | + TOML_TYPE_STRING, | |
| 22 | + TOML_TYPE_INTEGER, | |
| 23 | + TOML_TYPE_BOOLEAN, | |
| 24 | + TOML_TYPE_INVALID | |
| 25 | +} toml_value_type_t; | |
| 26 | + | |
| 27 | +/* TOML key-value pair */ | |
| 28 | +typedef struct { | |
| 29 | + char key[TOML_MAX_KEY_LEN]; | |
| 30 | + char value[TOML_MAX_VALUE_LEN]; | |
| 31 | + toml_value_type_t type; | |
| 32 | + bool is_set; | |
| 33 | +} toml_keyvalue_t; | |
| 34 | + | |
| 35 | +/* TOML section */ | |
| 36 | +typedef struct { | |
| 37 | + char name[TOML_MAX_SECTION_LEN]; | |
| 38 | + toml_keyvalue_t keys[TOML_MAX_KEYS_PER_SECTION]; | |
| 39 | + size_t key_count; | |
| 40 | + bool is_set; | |
| 41 | +} toml_section_t; | |
| 42 | + | |
| 43 | +/* TOML document structure */ | |
| 44 | +typedef struct { | |
| 45 | + toml_section_t sections[TOML_MAX_SECTIONS]; | |
| 46 | + size_t section_count; | |
| 47 | + char file_path[512]; | |
| 48 | + bool is_valid; | |
| 49 | +} toml_document_t; | |
| 50 | + | |
| 51 | +/* Parser state for security tracking */ | |
| 52 | +typedef struct { | |
| 53 | + const char *input; | |
| 54 | + size_t input_length; | |
| 55 | + size_t position; | |
| 56 | + size_t line_number; | |
| 57 | + size_t column_number; | |
| 58 | + bool has_error; | |
| 59 | + char error_message[256]; | |
| 60 | +} toml_parser_state_t; | |
| 61 | + | |
| 62 | +/* Function prototypes */ | |
| 63 | + | |
| 64 | +/** | |
| 65 | + * Initialize a TOML document structure | |
| 66 | + */ | |
| 67 | +void toml_init_document(toml_document_t *doc); | |
| 68 | + | |
| 69 | +/** | |
| 70 | + * Parse TOML from file with comprehensive security validation | |
| 71 | + * - Validates file size limits | |
| 72 | + * - Sanitizes all input | |
| 73 | + * - Checks for malicious patterns | |
| 74 | + * - Validates UTF-8 encoding | |
| 75 | + */ | |
| 76 | +int toml_parse_file(const char *file_path, toml_document_t *doc); | |
| 77 | + | |
| 78 | +/** | |
| 79 | + * Parse TOML from string buffer with security validation | |
| 80 | + */ | |
| 81 | +int toml_parse_string(const char *toml_string, size_t length, toml_document_t *doc); | |
| 82 | + | |
| 83 | +/** | |
| 84 | + * Get string value from TOML document with validation | |
| 85 | + * Returns validated and sanitized string value | |
| 86 | + */ | |
| 87 | +int toml_get_string(const toml_document_t *doc, const char *section, | |
| 88 | + const char *key, char *value, size_t value_size); | |
| 89 | + | |
| 90 | +/** | |
| 91 | + * Get integer value from TOML document with range validation | |
| 92 | + */ | |
| 93 | +int toml_get_integer(const toml_document_t *doc, const char *section, | |
| 94 | + const char *key, int *value); | |
| 95 | + | |
| 96 | +/** | |
| 97 | + * Get boolean value from TOML document | |
| 98 | + */ | |
| 99 | +int toml_get_boolean(const toml_document_t *doc, const char *section, | |
| 100 | + const char *key, bool *value); | |
| 101 | + | |
| 102 | +/** | |
| 103 | + * Set string value in TOML document with validation | |
| 104 | + */ | |
| 105 | +int toml_set_string(toml_document_t *doc, const char *section, | |
| 106 | + const char *key, const char *value); | |
| 107 | + | |
| 108 | +/** | |
| 109 | + * Set integer value in TOML document | |
| 110 | + */ | |
| 111 | +int toml_set_integer(toml_document_t *doc, const char *section, | |
| 112 | + const char *key, int value); | |
| 113 | + | |
| 114 | +/** | |
| 115 | + * Set boolean value in TOML document | |
| 116 | + */ | |
| 117 | +int toml_set_boolean(toml_document_t *doc, const char *section, | |
| 118 | + const char *key, bool value); | |
| 119 | + | |
| 120 | +/** | |
| 121 | + * Write TOML document to file with atomic operations | |
| 122 | + * - Creates backup of existing file | |
| 123 | + * - Uses temporary file for atomic write | |
| 124 | + * - Validates written content | |
| 125 | + */ | |
| 126 | +int toml_write_file(const toml_document_t *doc, const char *file_path); | |
| 127 | + | |
| 128 | +/** | |
| 129 | + * Generate TOML string from document | |
| 130 | + */ | |
| 131 | +int toml_generate_string(const toml_document_t *doc, char *buffer, size_t buffer_size); | |
| 132 | + | |
| 133 | +/** | |
| 134 | + * Validate TOML document structure for our specific config schema | |
| 135 | + */ | |
| 136 | +int toml_validate_gitswitch_schema(const toml_document_t *doc); | |
| 137 | + | |
| 138 | +/** | |
| 139 | + * Check if section exists in document | |
| 140 | + */ | |
| 141 | +bool toml_has_section(const toml_document_t *doc, const char *section); | |
| 142 | + | |
| 143 | +/** | |
| 144 | + * Check if key exists in section | |
| 145 | + */ | |
| 146 | +bool toml_has_key(const toml_document_t *doc, const char *section, const char *key); | |
| 147 | + | |
| 148 | +/** | |
| 149 | + * Get list of all sections in document | |
| 150 | + */ | |
| 151 | +int toml_get_sections(const toml_document_t *doc, char sections[][TOML_MAX_SECTION_LEN], | |
| 152 | + size_t max_sections, size_t *section_count); | |
| 153 | + | |
| 154 | +/** | |
| 155 | + * Get list of all keys in a section | |
| 156 | + */ | |
| 157 | +int toml_get_keys(const toml_document_t *doc, const char *section, | |
| 158 | + char keys[][TOML_MAX_KEY_LEN], size_t max_keys, size_t *key_count); | |
| 159 | + | |
| 160 | +/** | |
| 161 | + * Security validation functions | |
| 162 | + */ | |
| 163 | + | |
| 164 | +/** | |
| 165 | + * Validate that input contains only safe characters | |
| 166 | + */ | |
| 167 | +bool toml_validate_safe_characters(const char *input, size_t length); | |
| 168 | + | |
| 169 | +/** | |
| 170 | + * Sanitize string value removing potentially dangerous content | |
| 171 | + */ | |
| 172 | +int toml_sanitize_string(const char *input, char *output, size_t output_size); | |
| 173 | + | |
| 174 | +/** | |
| 175 | + * Validate file path for security (no directory traversal, etc.) | |
| 176 | + */ | |
| 177 | +bool toml_validate_file_path(const char *path); | |
| 178 | + | |
| 179 | +/** | |
| 180 | + * Check for TOML injection patterns | |
| 181 | + */ | |
| 182 | +bool toml_check_injection_patterns(const char *input, size_t length); | |
| 183 | + | |
| 184 | +/** | |
| 185 | + * Cleanup and free TOML document resources | |
| 186 | + */ | |
| 187 | +void toml_cleanup_document(toml_document_t *doc); | |
| 188 | + | |
| 189 | +/** | |
| 190 | + * Get last parser error message | |
| 191 | + */ | |
| 192 | +const char *toml_get_error_message(const toml_parser_state_t *state); | |
| 193 | + | |
| 194 | +#endif /* TOML_PARSER_H */ | |
src/utils.hadded@@ -0,0 +1,155 @@ | ||
| 1 | +/* Utility functions and helpers */ | |
| 2 | + | |
| 3 | +#ifndef UTILS_H | |
| 4 | +#define UTILS_H | |
| 5 | + | |
| 6 | +#include <sys/types.h> | |
| 7 | +#include <stdbool.h> | |
| 8 | +#include <time.h> | |
| 9 | + | |
| 10 | +#include "gitswitch.h" | |
| 11 | + | |
| 12 | +/* File permissions */ | |
| 13 | +#define PERM_USER_RWX 0700 | |
| 14 | +#define PERM_USER_RW 0600 | |
| 15 | +#define PERM_USER_R 0400 | |
| 16 | + | |
| 17 | +/* Path manipulation constants */ | |
| 18 | +#define PATH_SEPARATOR "/" | |
| 19 | +#define HOME_PREFIX "~/" | |
| 20 | + | |
| 21 | +/* Function prototypes */ | |
| 22 | + | |
| 23 | +/** | |
| 24 | + * Safe printf utilities - fixes signed/unsigned comparison warnings | |
| 25 | + */ | |
| 26 | +static inline bool safe_snprintf_check(int result, size_t buffer_size) { | |
| 27 | + return (result >= 0 && (size_t)result < buffer_size); | |
| 28 | +} | |
| 29 | + | |
| 30 | +/** | |
| 31 | + * String utilities | |
| 32 | + */ | |
| 33 | +char *trim_whitespace(char *str); | |
| 34 | +bool string_empty(const char *str); | |
| 35 | +bool string_equals(const char *a, const char *b); | |
| 36 | +bool string_starts_with(const char *str, const char *prefix); | |
| 37 | +bool string_ends_with(const char *str, const char *suffix); | |
| 38 | +int string_replace(char *str, size_t str_size, const char *old, const char *new); | |
| 39 | + | |
| 40 | +/** | |
| 41 | + * Path utilities | |
| 42 | + */ | |
| 43 | +int expand_path(const char *path, char *expanded_path, size_t path_size); | |
| 44 | +int get_home_directory(char *home_path, size_t path_size); | |
| 45 | +int join_path(char *result, size_t result_size, const char *base, const char *component); | |
| 46 | +bool path_exists(const char *path); | |
| 47 | +bool is_directory(const char *path); | |
| 48 | +bool is_regular_file(const char *path); | |
| 49 | +int create_directory_recursive(const char *path, mode_t mode); | |
| 50 | +int get_file_permissions(const char *path, mode_t *mode); | |
| 51 | +int set_file_permissions(const char *path, mode_t mode); | |
| 52 | + | |
| 53 | +/** | |
| 54 | + * File utilities | |
| 55 | + */ | |
| 56 | +int read_file_to_string(const char *file_path, char *buffer, size_t buffer_size); | |
| 57 | +int write_string_to_file(const char *file_path, const char *content, mode_t mode); | |
| 58 | +int copy_file(const char *src_path, const char *dst_path); | |
| 59 | +int backup_file(const char *file_path, const char *backup_suffix); | |
| 60 | +bool file_is_readable(const char *file_path); | |
| 61 | +bool file_is_writable(const char *file_path); | |
| 62 | +size_t get_file_size(const char *file_path); | |
| 63 | +time_t get_file_mtime(const char *file_path); | |
| 64 | + | |
| 65 | +/** | |
| 66 | + * Process utilities | |
| 67 | + */ | |
| 68 | +int execute_command(const char *command, char *output, size_t output_size); | |
| 69 | +int execute_command_with_input(const char *command, const char *input, | |
| 70 | + char *output, size_t output_size); | |
| 71 | +bool command_exists(const char *command); | |
| 72 | +pid_t start_background_process(const char *command, char *pidfile_path); | |
| 73 | +int kill_process_by_pidfile(const char *pidfile_path); | |
| 74 | +bool process_is_running(pid_t pid); | |
| 75 | + | |
| 76 | +/** | |
| 77 | + * Environment utilities | |
| 78 | + */ | |
| 79 | +int get_env_var(const char *name, char *buffer, size_t buffer_size); | |
| 80 | +int set_env_var(const char *name, const char *value, bool overwrite); | |
| 81 | +int unset_env_var(const char *name); | |
| 82 | + | |
| 83 | +/** | |
| 84 | + * Validation utilities | |
| 85 | + */ | |
| 86 | +bool validate_email(const char *email); | |
| 87 | +bool validate_name(const char *name); | |
| 88 | +bool validate_key_id(const char *key_id); | |
| 89 | +bool validate_file_path(const char *path); | |
| 90 | + | |
| 91 | +/** | |
| 92 | + * Security utilities | |
| 93 | + */ | |
| 94 | +void secure_zero_memory(void *ptr, size_t size); | |
| 95 | +int generate_random_string(char *buffer, size_t buffer_size, const char *charset); | |
| 96 | +bool check_file_permissions_safe(const char *file_path, mode_t expected_mode); | |
| 97 | + | |
| 98 | +/** | |
| 99 | + * Configuration utilities | |
| 100 | + */ | |
| 101 | +int get_config_directory(char *config_dir, size_t dir_size); | |
| 102 | +int ensure_config_directory_exists(void); | |
| 103 | + | |
| 104 | +/** | |
| 105 | + * Terminal utilities | |
| 106 | + */ | |
| 107 | +bool is_terminal(int fd); | |
| 108 | +int get_terminal_size(int *width, int *height); | |
| 109 | +void disable_echo(void); | |
| 110 | +void enable_echo(void); | |
| 111 | + | |
| 112 | +/** | |
| 113 | + * Time utilities | |
| 114 | + */ | |
| 115 | +void get_current_time_string(char *buffer, size_t buffer_size); | |
| 116 | +void get_timestamp_string(char *buffer, size_t buffer_size); | |
| 117 | +bool is_timestamp_expired(time_t timestamp, int max_age_seconds); | |
| 118 | + | |
| 119 | +/** | |
| 120 | + * Comparison utilities | |
| 121 | + */ | |
| 122 | +int compare_strings(const void *a, const void *b); | |
| 123 | +int compare_accounts_by_id(const void *a, const void *b); | |
| 124 | +int compare_accounts_by_name(const void *a, const void *b); | |
| 125 | + | |
| 126 | +/** | |
| 127 | + * Array utilities | |
| 128 | + */ | |
| 129 | +void sort_accounts(account_t *accounts, size_t count, | |
| 130 | + int (*compare)(const void *, const void *)); | |
| 131 | +account_t *find_account_in_array(account_t *accounts, size_t count, | |
| 132 | + const char *identifier); | |
| 133 | + | |
| 134 | +/** | |
| 135 | + * Memory utilities | |
| 136 | + */ | |
| 137 | +void *safe_memset(void *ptr, int value, size_t size); | |
| 138 | +void *safe_memcpy(void *dest, const void *src, size_t size); | |
| 139 | +int safe_mlock(void *ptr, size_t size); | |
| 140 | +int safe_munlock(void *ptr, size_t size); | |
| 141 | + | |
| 142 | +/** | |
| 143 | + * Cleanup utilities | |
| 144 | + */ | |
| 145 | +void cleanup_temporary_files(void); | |
| 146 | +int register_cleanup_handler(void (*handler)(void)); | |
| 147 | + | |
| 148 | +/** | |
| 149 | + * Debug utilities | |
| 150 | + */ | |
| 151 | +void dump_account(const account_t *account); | |
| 152 | +void dump_config(const config_t *config); | |
| 153 | +void dump_context(const gitswitch_ctx_t *ctx); | |
| 154 | + | |
| 155 | +#endif /* UTILS_H */ | |