Last push before major bug fixes

This commit is contained in:
Your Name
2025-10-01 14:53:20 -04:00
parent 4658ede9d6
commit 524f9bd84f
7 changed files with 211 additions and 115 deletions

View File

@@ -921,40 +921,46 @@ int first_time_startup_sequence(const cli_options_t* cli_options) {
// 1. Generate or use provided admin keypair
unsigned char admin_privkey_bytes[32];
char admin_privkey[65], admin_pubkey[65];
if (cli_options && strlen(cli_options->admin_privkey_override) == 64) {
// Use provided admin private key
log_info("Using provided admin private key override");
strncpy(admin_privkey, cli_options->admin_privkey_override, sizeof(admin_privkey) - 1);
admin_privkey[sizeof(admin_privkey) - 1] = '\0';
// Convert hex string to bytes
if (nostr_hex_to_bytes(admin_privkey, admin_privkey_bytes, 32) != NOSTR_SUCCESS) {
log_error("Failed to convert admin private key hex to bytes");
return -1;
}
// Validate the private key
if (nostr_ec_private_key_verify(admin_privkey_bytes) != NOSTR_SUCCESS) {
log_error("Provided admin private key is invalid");
return -1;
if (cli_options && strlen(cli_options->admin_pubkey_override) == 64) {
// Use provided admin public key directly - skip private key generation entirely
log_info("Using provided admin public key override - skipping private key generation");
strncpy(admin_pubkey, cli_options->admin_pubkey_override, sizeof(admin_pubkey) - 1);
admin_pubkey[sizeof(admin_pubkey) - 1] = '\0';
// Validate the public key format (must be 64 hex characters)
for (int i = 0; i < 64; i++) {
char c = admin_pubkey[i];
if (!((c >= '0' && c <= '9') ||
(c >= 'a' && c <= 'f') ||
(c >= 'A' && c <= 'F'))) {
log_error("Invalid admin public key format - must contain only hex characters");
return -1;
}
}
// Skip private key generation - we only need the pubkey for admin verification
// Set a dummy private key that will never be used (not displayed or stored)
memset(admin_privkey_bytes, 0, 32); // Zero out for security
memset(admin_privkey, 0, sizeof(admin_privkey)); // Zero out the hex string
} else {
// Generate random admin keypair using /dev/urandom + nostr_core_lib
log_info("Generating random admin keypair");
if (generate_random_private_key_bytes(admin_privkey_bytes) != 0) {
log_error("Failed to generate admin private key");
return -1;
}
nostr_bytes_to_hex(admin_privkey_bytes, 32, admin_privkey);
// Derive public key from private key
unsigned char admin_pubkey_bytes[32];
if (nostr_ec_public_key_from_private_key(admin_privkey_bytes, admin_pubkey_bytes) != NOSTR_SUCCESS) {
log_error("Failed to derive admin public key");
return -1;
}
nostr_bytes_to_hex(admin_pubkey_bytes, 32, admin_pubkey);
}
unsigned char admin_pubkey_bytes[32];
if (nostr_ec_public_key_from_private_key(admin_privkey_bytes, admin_pubkey_bytes) != NOSTR_SUCCESS) {
log_error("Failed to derive admin public key");
return -1;
}
nostr_bytes_to_hex(admin_pubkey_bytes, 32, admin_pubkey);
// 2. Generate or use provided relay keypair
unsigned char relay_privkey_bytes[32];
char relay_privkey[65], relay_pubkey[65];
@@ -1011,34 +1017,43 @@ int first_time_startup_sequence(const cli_options_t* cli_options) {
g_temp_relay_privkey[sizeof(g_temp_relay_privkey) - 1] = '\0';
log_info("Relay private key cached for secure storage after database initialization");
// 6. Create initial configuration event using defaults (without private key)
cJSON* config_event = create_default_config_event(admin_privkey_bytes, relay_privkey, relay_pubkey, cli_options);
if (!config_event) {
log_error("Failed to create default configuration event");
return -1;
}
// 7. Process configuration through admin API instead of storing in events table
if (process_startup_config_event_with_fallback(config_event) == 0) {
log_success("Initial configuration processed successfully through admin API");
// 6. Handle configuration setup based on admin key availability
if (cli_options && strlen(cli_options->admin_pubkey_override) == 64) {
// Admin pubkey provided - will populate config table after database initialization
log_info("Admin pubkey provided - config table will be populated after database initialization");
} else {
log_warning("Failed to process initial configuration - will retry after database init");
// Cache the event for later processing
if (g_pending_config_event) {
cJSON_Delete(g_pending_config_event);
// Admin private key available - create signed configuration event
log_info("Admin private key available - creating signed configuration event");
// Create initial configuration event using defaults
cJSON* config_event = create_default_config_event(admin_privkey_bytes, relay_privkey, relay_pubkey, cli_options);
if (!config_event) {
log_error("Failed to create default configuration event");
return -1;
}
g_pending_config_event = cJSON_Duplicate(config_event, 1);
// Process configuration through admin API instead of storing in events table
if (process_startup_config_event_with_fallback(config_event) == 0) {
log_success("Initial configuration processed successfully through admin API");
} else {
log_warning("Failed to process initial configuration - will retry after database init");
// Cache the event for later processing
if (g_pending_config_event) {
cJSON_Delete(g_pending_config_event);
}
g_pending_config_event = cJSON_Duplicate(config_event, 1);
}
// Cache the current config
if (g_current_config) {
cJSON_Delete(g_current_config);
}
g_current_config = cJSON_Duplicate(config_event, 1);
// Clean up
cJSON_Delete(config_event);
}
// 8. Cache the current config
if (g_current_config) {
cJSON_Delete(g_current_config);
}
g_current_config = cJSON_Duplicate(config_event, 1);
// 9. Clean up
cJSON_Delete(config_event);
// 10. Print admin private key for user to save
printf("\n");
printf("=================================================================\n");

View File

@@ -96,7 +96,7 @@ typedef struct {
// Command line options structure for first-time startup
typedef struct {
int port_override; // -1 = not set, >0 = port value
char admin_privkey_override[65]; // Empty string = not set, 64-char hex = override
char admin_pubkey_override[65]; // Empty string = not set, 64-char hex = override
char relay_privkey_override[65]; // Empty string = not set, 64-char hex = override
int strict_port; // 0 = allow port increment, 1 = fail if exact port unavailable
} cli_options_t;

View File

@@ -1204,9 +1204,9 @@ void print_usage(const char* program_name) {
printf(" -h, --help Show this help message\n");
printf(" -v, --version Show version information\n");
printf(" -p, --port PORT Override relay port (first-time startup only)\n");
printf(" -a, --admin-privkey HEX Override admin private key (64-char hex)\n");
printf(" -r, --relay-privkey HEX Override relay private key (64-char hex)\n");
printf(" --strict-port Fail if exact port is unavailable (no port increment)\n");
printf(" -a, --admin-pubkey HEX Override admin public key (64-char hex)\n");
printf(" -r, --relay-privkey HEX Override relay private key (64-char hex)\n");
printf("\n");
printf("Configuration:\n");
printf(" This relay uses event-based configuration stored in the database.\n");
@@ -1221,12 +1221,12 @@ void print_usage(const char* program_name) {
printf("\n");
printf("Examples:\n");
printf(" %s # Start relay (auto-configure on first run)\n", program_name);
printf(" %s -p 8080 # First-time setup with port 8080\n", program_name);
printf(" %s --port 9000 # First-time setup with port 9000\n", program_name);
printf(" %s --strict-port # Fail if default port 8888 is unavailable\n", program_name);
printf(" %s -p 8080 # First-time setup with port 8080\n", program_name);
printf(" %s --port 9000 # First-time setup with port 9000\n", program_name);
printf(" %s --strict-port # Fail if default port 8888 is unavailable\n", program_name);
printf(" %s -p 8080 --strict-port # Fail if port 8080 is unavailable\n", program_name);
printf(" %s --help # Show this help\n", program_name);
printf(" %s --version # Show version info\n", program_name);
printf(" %s --help # Show this help\n", program_name);
printf(" %s --version # Show version info\n", program_name);
printf("\n");
}
@@ -1242,7 +1242,7 @@ int main(int argc, char* argv[]) {
// Initialize CLI options structure
cli_options_t cli_options = {
.port_override = -1, // -1 = not set
.admin_privkey_override = {0}, // Empty string = not set
.admin_pubkey_override = {0}, // Empty string = not set
.relay_privkey_override = {0}, // Empty string = not set
.strict_port = 0 // 0 = allow port increment (default)
};
@@ -1279,36 +1279,36 @@ int main(int argc, char* argv[]) {
char port_msg[128];
snprintf(port_msg, sizeof(port_msg), "Port override specified: %d", cli_options.port_override);
log_info(port_msg);
} else if (strcmp(argv[i], "-a") == 0 || strcmp(argv[i], "--admin-privkey") == 0) {
// Admin private key override option
} else if (strcmp(argv[i], "-a") == 0 || strcmp(argv[i], "--admin-pubkey") == 0) {
// Admin public key override option
if (i + 1 >= argc) {
log_error("Admin privkey option requires a value. Use --help for usage information.");
log_error("Admin pubkey option requires a value. Use --help for usage information.");
print_usage(argv[0]);
return 1;
}
// Validate private key format (must be 64 hex characters)
// Validate public key format (must be 64 hex characters)
if (strlen(argv[i + 1]) != 64) {
log_error("Invalid admin private key length. Must be exactly 64 hex characters.");
log_error("Invalid admin public key length. Must be exactly 64 hex characters.");
print_usage(argv[0]);
return 1;
}
// Validate hex format
for (int j = 0; j < 64; j++) {
char c = argv[i + 1][j];
if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))) {
log_error("Invalid admin private key format. Must contain only hex characters (0-9, a-f, A-F).");
log_error("Invalid admin public key format. Must contain only hex characters (0-9, a-f, A-F).");
print_usage(argv[0]);
return 1;
}
}
strncpy(cli_options.admin_privkey_override, argv[i + 1], sizeof(cli_options.admin_privkey_override) - 1);
cli_options.admin_privkey_override[sizeof(cli_options.admin_privkey_override) - 1] = '\0';
strncpy(cli_options.admin_pubkey_override, argv[i + 1], sizeof(cli_options.admin_pubkey_override) - 1);
cli_options.admin_pubkey_override[sizeof(cli_options.admin_pubkey_override) - 1] = '\0';
i++; // Skip the key argument
log_info("Admin private key override specified");
log_info("Admin public key override specified");
} else if (strcmp(argv[i], "-r") == 0 || strcmp(argv[i], "--relay-privkey") == 0) {
// Relay private key override option
if (i + 1 >= argc) {
@@ -1389,7 +1389,7 @@ int main(int argc, char* argv[]) {
nostr_cleanup();
return 1;
}
// Now that database is available, store the relay private key securely
const char* relay_privkey = get_temp_relay_private_key();
if (relay_privkey) {
@@ -1406,17 +1406,36 @@ int main(int argc, char* argv[]) {
nostr_cleanup();
return 1;
}
// Systematically add pubkeys to config table
if (add_pubkeys_to_config_table() != 0) {
log_warning("Failed to add pubkeys to config table systematically");
// Handle configuration setup after database is initialized
if (cli_options.admin_pubkey_override && strlen(cli_options.admin_pubkey_override) == 64) {
// Admin pubkey provided - populate config table directly
log_info("Populating config table for admin pubkey override after database initialization");
// Populate default config values in table
if (populate_default_config_values() != 0) {
log_error("Failed to populate default config values");
cleanup_configuration_system();
nostr_cleanup();
close_database();
return 1;
}
// Add pubkeys to config table
if (add_pubkeys_to_config_table() != 0) {
log_error("Failed to add pubkeys to config table");
cleanup_configuration_system();
nostr_cleanup();
close_database();
return 1;
}
log_success("Configuration populated directly in config table after database initialization");
} else {
log_success("Pubkeys added to config table systematically");
}
// Retry storing the configuration event now that database is initialized
if (retry_store_initial_config_event() != 0) {
log_warning("Failed to store initial configuration event after database init");
// Admin private key available - retry storing initial config event
if (retry_store_initial_config_event() != 0) {
log_warning("Failed to store initial config event - will retry later");
}
}
// Now store the pubkeys in config table since database is available