tenseleyflow/gitswitch / 56b2994

Browse files

headers

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
56b29945c573f7a3919a62a32ba64b95ad4be850
Parents
4b19270
Tree
d4c7af1

10 changed files

StatusFile+-
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 */