Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1690b58c67 | ||
|
|
2e8eda5c67 | ||
|
|
74a4dc2533 |
35
relay2.log
35
relay2.log
@@ -1,35 +0,0 @@
|
|||||||
[34m[1m=== C Nostr Relay Server ===[0m
|
|
||||||
Event-based configuration system
|
|
||||||
|
|
||||||
[34m[INFO][0m Existing relay detected
|
|
||||||
[34m[INFO][0m Initializing event-based configuration system...
|
|
||||||
[32m[SUCCESS][0m Event-based configuration system initialized
|
|
||||||
[34m[INFO][0m Starting existing relay...
|
|
||||||
Relay pubkey: 6df436471c7965d6473e89998162e6b87cc3547d71a2db12f559a39f4596059a
|
|
||||||
[32m[SUCCESS][0m Existing relay startup prepared
|
|
||||||
[32m[SUCCESS][0m Database connection established: 6df436471c7965d6473e89998162e6b87cc3547d71a2db12f559a39f4596059a.nrdb
|
|
||||||
[34m[INFO][0m Database schema already exists, skipping initialization
|
|
||||||
[34m[INFO][0m Existing database schema version: 4
|
|
||||||
[33m[WARNING][0m No configuration event found in existing database
|
|
||||||
[32m[SUCCESS][0m Relay information initialized with default values
|
|
||||||
[34m[INFO][0m Initializing NIP-13 Proof of Work configuration
|
|
||||||
[34m[INFO][0m PoW configured in basic validation mode (default)
|
|
||||||
[34m[INFO][0m PoW Configuration: enabled=true, min_difficulty=0, validation_flags=0x1, mode=full
|
|
||||||
[34m[INFO][0m Initializing NIP-40 Expiration Timestamp configuration
|
|
||||||
[34m[INFO][0m Expiration Configuration: enabled=true, strict_mode=true, filter_responses=true, grace_period=300 seconds
|
|
||||||
[34m[INFO][0m Subscription limits: max_per_client=25, max_total=5000
|
|
||||||
[34m[INFO][0m Starting relay server...
|
|
||||||
[34m[INFO][0m Starting libwebsockets-based Nostr relay server...
|
|
||||||
[34m[INFO][0m Checking port availability: 8888
|
|
||||||
[33m[WARNING][0m Port 8888 is in use, trying port 8889 (attempt 2/5)
|
|
||||||
[34m[INFO][0m Checking port availability: 8889
|
|
||||||
[34m[INFO][0m Attempting to bind libwebsockets to port 8889
|
|
||||||
[33m[WARNING][0m WebSocket relay started on ws://127.0.0.1:8889 (configured port 8888 was unavailable)
|
|
||||||
[32m[SUCCESS][0m WebSocket relay started on ws://127.0.0.1:8889 (configured port 8888 was unavailable)
|
|
||||||
[34m[INFO][0m Received shutdown signal
|
|
||||||
[34m[INFO][0m Shutting down WebSocket server...
|
|
||||||
[32m[SUCCESS][0m WebSocket relay shut down cleanly
|
|
||||||
[34m[INFO][0m Cleaning up configuration system...
|
|
||||||
[32m[SUCCESS][0m Configuration system cleaned up
|
|
||||||
[34m[INFO][0m Database connection closed
|
|
||||||
[32m[SUCCESS][0m Server shutdown complete
|
|
||||||
37
relay3.log
37
relay3.log
@@ -1,37 +0,0 @@
|
|||||||
[34m[1m=== C Nostr Relay Server ===[0m
|
|
||||||
Event-based configuration system
|
|
||||||
|
|
||||||
[34m[INFO][0m Existing relay detected
|
|
||||||
[34m[INFO][0m Initializing event-based configuration system...
|
|
||||||
[32m[SUCCESS][0m Event-based configuration system initialized
|
|
||||||
[34m[INFO][0m Starting existing relay...
|
|
||||||
Relay pubkey: 6df436471c7965d6473e89998162e6b87cc3547d71a2db12f559a39f4596059a
|
|
||||||
[32m[SUCCESS][0m Existing relay startup prepared
|
|
||||||
[32m[SUCCESS][0m Database connection established: 6df436471c7965d6473e89998162e6b87cc3547d71a2db12f559a39f4596059a.nrdb
|
|
||||||
[34m[INFO][0m Database schema already exists, skipping initialization
|
|
||||||
[34m[INFO][0m Existing database schema version: 4
|
|
||||||
[33m[WARNING][0m No configuration event found in existing database
|
|
||||||
[32m[SUCCESS][0m Relay information initialized with default values
|
|
||||||
[34m[INFO][0m Initializing NIP-13 Proof of Work configuration
|
|
||||||
[34m[INFO][0m PoW configured in basic validation mode (default)
|
|
||||||
[34m[INFO][0m PoW Configuration: enabled=true, min_difficulty=0, validation_flags=0x1, mode=full
|
|
||||||
[34m[INFO][0m Initializing NIP-40 Expiration Timestamp configuration
|
|
||||||
[34m[INFO][0m Expiration Configuration: enabled=true, strict_mode=true, filter_responses=true, grace_period=300 seconds
|
|
||||||
[34m[INFO][0m Subscription limits: max_per_client=25, max_total=5000
|
|
||||||
[34m[INFO][0m Starting relay server...
|
|
||||||
[34m[INFO][0m Starting libwebsockets-based Nostr relay server...
|
|
||||||
[34m[INFO][0m Checking port availability: 8888
|
|
||||||
[33m[WARNING][0m Port 8888 is in use, trying port 8889 (attempt 2/5)
|
|
||||||
[34m[INFO][0m Checking port availability: 8889
|
|
||||||
[33m[WARNING][0m Port 8889 is in use, trying port 8890 (attempt 3/5)
|
|
||||||
[34m[INFO][0m Checking port availability: 8890
|
|
||||||
[34m[INFO][0m Attempting to bind libwebsockets to port 8890
|
|
||||||
[33m[WARNING][0m WebSocket relay started on ws://127.0.0.1:8890 (configured port 8888 was unavailable)
|
|
||||||
[32m[SUCCESS][0m WebSocket relay started on ws://127.0.0.1:8890 (configured port 8888 was unavailable)
|
|
||||||
[34m[INFO][0m Received shutdown signal
|
|
||||||
[34m[INFO][0m Shutting down WebSocket server...
|
|
||||||
[32m[SUCCESS][0m WebSocket relay shut down cleanly
|
|
||||||
[34m[INFO][0m Cleaning up configuration system...
|
|
||||||
[32m[SUCCESS][0m Configuration system cleaned up
|
|
||||||
[34m[INFO][0m Database connection closed
|
|
||||||
[32m[SUCCESS][0m Server shutdown complete
|
|
||||||
153
src/config.c
153
src/config.c
@@ -29,11 +29,14 @@ static cJSON* g_current_config = NULL;
|
|||||||
// Cache for initial configuration event (before database is initialized)
|
// Cache for initial configuration event (before database is initialized)
|
||||||
static cJSON* g_pending_config_event = NULL;
|
static cJSON* g_pending_config_event = NULL;
|
||||||
|
|
||||||
|
// Temporary storage for relay private key during first-time setup
|
||||||
|
static char g_temp_relay_privkey[65] = {0};
|
||||||
|
|
||||||
// ================================
|
// ================================
|
||||||
// UTILITY FUNCTIONS
|
// UTILITY FUNCTIONS
|
||||||
// ================================
|
// ================================
|
||||||
|
|
||||||
char** find_existing_nrdb_files(void) {
|
char** find_existing_db_files(void) {
|
||||||
DIR *dir;
|
DIR *dir;
|
||||||
struct dirent *entry;
|
struct dirent *entry;
|
||||||
char **files = NULL;
|
char **files = NULL;
|
||||||
@@ -342,7 +345,7 @@ int get_config_bool(const char* key, int default_value) {
|
|||||||
// ================================
|
// ================================
|
||||||
|
|
||||||
int is_first_time_startup(void) {
|
int is_first_time_startup(void) {
|
||||||
char** existing_files = find_existing_nrdb_files();
|
char** existing_files = find_existing_db_files();
|
||||||
if (existing_files) {
|
if (existing_files) {
|
||||||
// Free the array
|
// Free the array
|
||||||
for (int i = 0; existing_files[i]; i++) {
|
for (int i = 0; existing_files[i]; i++) {
|
||||||
@@ -437,13 +440,111 @@ int generate_random_private_key_bytes(unsigned char* privkey_bytes) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ================================
|
||||||
|
// SECURE RELAY PRIVATE KEY STORAGE
|
||||||
|
// ================================
|
||||||
|
|
||||||
|
int store_relay_private_key(const char* relay_privkey_hex) {
|
||||||
|
if (!relay_privkey_hex) {
|
||||||
|
log_error("Invalid relay private key for storage");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate private key format (must be 64 hex characters)
|
||||||
|
if (strlen(relay_privkey_hex) != 64) {
|
||||||
|
log_error("Invalid relay private key length (must be 64 hex characters)");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate hex format
|
||||||
|
for (int i = 0; i < 64; i++) {
|
||||||
|
char c = relay_privkey_hex[i];
|
||||||
|
if (!((c >= '0' && c <= '9') ||
|
||||||
|
(c >= 'a' && c <= 'f') ||
|
||||||
|
(c >= 'A' && c <= 'F'))) {
|
||||||
|
log_error("Invalid relay private key format (must be hex characters only)");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!g_db) {
|
||||||
|
log_error("Database not available for relay private key storage");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* sql = "INSERT OR REPLACE INTO relay_seckey (private_key_hex) VALUES (?)";
|
||||||
|
sqlite3_stmt* stmt;
|
||||||
|
|
||||||
|
int rc = sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL);
|
||||||
|
if (rc != SQLITE_OK) {
|
||||||
|
log_error("Failed to prepare relay private key storage query");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_bind_text(stmt, 1, relay_privkey_hex, -1, SQLITE_STATIC);
|
||||||
|
|
||||||
|
rc = sqlite3_step(stmt);
|
||||||
|
sqlite3_finalize(stmt);
|
||||||
|
|
||||||
|
if (rc == SQLITE_DONE) {
|
||||||
|
log_success("Relay private key stored securely in database");
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
log_error("Failed to store relay private key in database");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char* get_relay_private_key(void) {
|
||||||
|
if (!g_db) {
|
||||||
|
log_error("Database not available for relay private key retrieval");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* sql = "SELECT private_key_hex FROM relay_seckey";
|
||||||
|
sqlite3_stmt* stmt;
|
||||||
|
|
||||||
|
int rc = sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL);
|
||||||
|
if (rc != SQLITE_OK) {
|
||||||
|
log_error("Failed to prepare relay private key retrieval query");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* private_key = NULL;
|
||||||
|
if (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||||
|
const char* key_from_db = (const char*)sqlite3_column_text(stmt, 0);
|
||||||
|
if (key_from_db && strlen(key_from_db) == 64) {
|
||||||
|
private_key = malloc(65); // 64 chars + null terminator
|
||||||
|
if (private_key) {
|
||||||
|
strcpy(private_key, key_from_db);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3_finalize(stmt);
|
||||||
|
|
||||||
|
if (!private_key) {
|
||||||
|
log_error("Relay private key not found in secure storage");
|
||||||
|
}
|
||||||
|
|
||||||
|
return private_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* get_temp_relay_private_key(void) {
|
||||||
|
if (strlen(g_temp_relay_privkey) == 64) {
|
||||||
|
return g_temp_relay_privkey;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// ================================
|
// ================================
|
||||||
// DEFAULT CONFIG EVENT CREATION
|
// DEFAULT CONFIG EVENT CREATION
|
||||||
// ================================
|
// ================================
|
||||||
|
|
||||||
cJSON* create_default_config_event(const unsigned char* admin_privkey_bytes,
|
cJSON* create_default_config_event(const unsigned char* admin_privkey_bytes,
|
||||||
const char* relay_privkey_hex,
|
const char* relay_privkey_hex,
|
||||||
const char* relay_pubkey_hex) {
|
const char* relay_pubkey_hex,
|
||||||
|
const cli_options_t* cli_options) {
|
||||||
if (!admin_privkey_bytes || !relay_privkey_hex || !relay_pubkey_hex) {
|
if (!admin_privkey_bytes || !relay_privkey_hex || !relay_pubkey_hex) {
|
||||||
log_error("Invalid parameters for creating default config event");
|
log_error("Invalid parameters for creating default config event");
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -470,16 +571,31 @@ cJSON* create_default_config_event(const unsigned char* admin_privkey_bytes,
|
|||||||
cJSON_AddItemToArray(relay_pubkey_tag, cJSON_CreateString(relay_pubkey_hex));
|
cJSON_AddItemToArray(relay_pubkey_tag, cJSON_CreateString(relay_pubkey_hex));
|
||||||
cJSON_AddItemToArray(tags, relay_pubkey_tag);
|
cJSON_AddItemToArray(tags, relay_pubkey_tag);
|
||||||
|
|
||||||
cJSON* relay_privkey_tag = cJSON_CreateArray();
|
// Note: relay_privkey is now stored securely in relay_seckey table
|
||||||
cJSON_AddItemToArray(relay_privkey_tag, cJSON_CreateString("relay_privkey"));
|
// It is no longer included in the public configuration event
|
||||||
cJSON_AddItemToArray(relay_privkey_tag, cJSON_CreateString(relay_privkey_hex));
|
|
||||||
cJSON_AddItemToArray(tags, relay_privkey_tag);
|
|
||||||
|
|
||||||
// Add all default configuration values
|
// Add all default configuration values with command line overrides
|
||||||
for (size_t i = 0; i < DEFAULT_CONFIG_COUNT; i++) {
|
for (size_t i = 0; i < DEFAULT_CONFIG_COUNT; i++) {
|
||||||
cJSON* tag = cJSON_CreateArray();
|
cJSON* tag = cJSON_CreateArray();
|
||||||
cJSON_AddItemToArray(tag, cJSON_CreateString(DEFAULT_CONFIG_VALUES[i].key));
|
cJSON_AddItemToArray(tag, cJSON_CreateString(DEFAULT_CONFIG_VALUES[i].key));
|
||||||
cJSON_AddItemToArray(tag, cJSON_CreateString(DEFAULT_CONFIG_VALUES[i].value));
|
|
||||||
|
// Check for command line overrides
|
||||||
|
const char* value = DEFAULT_CONFIG_VALUES[i].value;
|
||||||
|
if (cli_options) {
|
||||||
|
// Override relay_port if specified on command line
|
||||||
|
if (cli_options->port_override > 0 && strcmp(DEFAULT_CONFIG_VALUES[i].key, "relay_port") == 0) {
|
||||||
|
char port_str[16];
|
||||||
|
snprintf(port_str, sizeof(port_str), "%d", cli_options->port_override);
|
||||||
|
cJSON_AddItemToArray(tag, cJSON_CreateString(port_str));
|
||||||
|
log_info("Using command line port override in configuration event");
|
||||||
|
printf(" Port: %d (overriding default %s)\n", cli_options->port_override, DEFAULT_CONFIG_VALUES[i].value);
|
||||||
|
} else {
|
||||||
|
cJSON_AddItemToArray(tag, cJSON_CreateString(value));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cJSON_AddItemToArray(tag, cJSON_CreateString(value));
|
||||||
|
}
|
||||||
|
|
||||||
cJSON_AddItemToArray(tags, tag);
|
cJSON_AddItemToArray(tags, tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -516,7 +632,7 @@ cJSON* create_default_config_event(const unsigned char* admin_privkey_bytes,
|
|||||||
// IMPLEMENTED FUNCTIONS
|
// IMPLEMENTED FUNCTIONS
|
||||||
// ================================
|
// ================================
|
||||||
|
|
||||||
int first_time_startup_sequence(void) {
|
int first_time_startup_sequence(const cli_options_t* cli_options) {
|
||||||
log_info("Starting first-time startup sequence...");
|
log_info("Starting first-time startup sequence...");
|
||||||
|
|
||||||
// 1. Generate admin keypair using /dev/urandom + nostr_core_lib
|
// 1. Generate admin keypair using /dev/urandom + nostr_core_lib
|
||||||
@@ -565,14 +681,19 @@ int first_time_startup_sequence(void) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. Create initial configuration event using defaults
|
// 5. Store relay private key in temporary storage for later secure storage
|
||||||
cJSON* config_event = create_default_config_event(admin_privkey_bytes, relay_privkey, relay_pubkey);
|
strncpy(g_temp_relay_privkey, relay_privkey, sizeof(g_temp_relay_privkey) - 1);
|
||||||
|
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) {
|
if (!config_event) {
|
||||||
log_error("Failed to create default configuration event");
|
log_error("Failed to create default configuration event");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6. Try to store configuration event in database, but cache it if database isn't ready
|
// 7. Try to store configuration event in database, but cache it if database isn't ready
|
||||||
if (store_config_event_in_database(config_event) == 0) {
|
if (store_config_event_in_database(config_event) == 0) {
|
||||||
log_success("Initial configuration event stored successfully");
|
log_success("Initial configuration event stored successfully");
|
||||||
} else {
|
} else {
|
||||||
@@ -584,16 +705,16 @@ int first_time_startup_sequence(void) {
|
|||||||
g_pending_config_event = cJSON_Duplicate(config_event, 1);
|
g_pending_config_event = cJSON_Duplicate(config_event, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7. Cache the current config
|
// 8. Cache the current config
|
||||||
if (g_current_config) {
|
if (g_current_config) {
|
||||||
cJSON_Delete(g_current_config);
|
cJSON_Delete(g_current_config);
|
||||||
}
|
}
|
||||||
g_current_config = cJSON_Duplicate(config_event, 1);
|
g_current_config = cJSON_Duplicate(config_event, 1);
|
||||||
|
|
||||||
// 8. Clean up
|
// 9. Clean up
|
||||||
cJSON_Delete(config_event);
|
cJSON_Delete(config_event);
|
||||||
|
|
||||||
// 9. Print admin private key for user to save
|
// 10. Print admin private key for user to save
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf("=================================================================\n");
|
printf("=================================================================\n");
|
||||||
printf("IMPORTANT: SAVE THIS ADMIN PRIVATE KEY SECURELY!\n");
|
printf("IMPORTANT: SAVE THIS ADMIN PRIVATE KEY SECURELY!\n");
|
||||||
|
|||||||
15
src/config.h
15
src/config.h
@@ -32,6 +32,12 @@ typedef struct {
|
|||||||
char config_file_path[512]; // Temporary for compatibility
|
char config_file_path[512]; // Temporary for compatibility
|
||||||
} config_manager_t;
|
} config_manager_t;
|
||||||
|
|
||||||
|
// Command line options structure for first-time startup
|
||||||
|
typedef struct {
|
||||||
|
int port_override; // -1 = not set, >0 = port value
|
||||||
|
// Future CLI options can be added here
|
||||||
|
} cli_options_t;
|
||||||
|
|
||||||
// Global configuration manager
|
// Global configuration manager
|
||||||
extern config_manager_t g_config_manager;
|
extern config_manager_t g_config_manager;
|
||||||
|
|
||||||
@@ -62,7 +68,7 @@ int get_config_bool(const char* key, int default_value);
|
|||||||
|
|
||||||
// First-time startup functions
|
// First-time startup functions
|
||||||
int is_first_time_startup(void);
|
int is_first_time_startup(void);
|
||||||
int first_time_startup_sequence(void);
|
int first_time_startup_sequence(const cli_options_t* cli_options);
|
||||||
int startup_existing_relay(const char* relay_pubkey);
|
int startup_existing_relay(const char* relay_pubkey);
|
||||||
|
|
||||||
// Configuration application functions
|
// Configuration application functions
|
||||||
@@ -70,7 +76,12 @@ int apply_configuration_from_event(const cJSON* event);
|
|||||||
int apply_runtime_config_handlers(const cJSON* old_event, const cJSON* new_event);
|
int apply_runtime_config_handlers(const cJSON* old_event, const cJSON* new_event);
|
||||||
|
|
||||||
// Utility functions
|
// Utility functions
|
||||||
char** find_existing_nrdb_files(void);
|
char** find_existing_db_files(void);
|
||||||
char* extract_pubkey_from_filename(const char* filename);
|
char* extract_pubkey_from_filename(const char* filename);
|
||||||
|
|
||||||
|
// Secure relay private key storage functions
|
||||||
|
int store_relay_private_key(const char* relay_privkey_hex);
|
||||||
|
char* get_relay_private_key(void);
|
||||||
|
const char* get_temp_relay_private_key(void); // For first-time startup only
|
||||||
|
|
||||||
#endif /* CONFIG_H */
|
#endif /* CONFIG_H */
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
#define DEFAULT_CONFIG_EVENT_H
|
#define DEFAULT_CONFIG_EVENT_H
|
||||||
|
|
||||||
#include <cjson/cJSON.h>
|
#include <cjson/cJSON.h>
|
||||||
|
#include "config.h" // For cli_options_t definition
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Default Configuration Event Template
|
* Default Configuration Event Template
|
||||||
@@ -61,8 +62,9 @@ static const struct {
|
|||||||
#define DEFAULT_CONFIG_COUNT (sizeof(DEFAULT_CONFIG_VALUES) / sizeof(DEFAULT_CONFIG_VALUES[0]))
|
#define DEFAULT_CONFIG_COUNT (sizeof(DEFAULT_CONFIG_VALUES) / sizeof(DEFAULT_CONFIG_VALUES[0]))
|
||||||
|
|
||||||
// Function to create default configuration event
|
// Function to create default configuration event
|
||||||
cJSON* create_default_config_event(const unsigned char* admin_privkey_bytes,
|
cJSON* create_default_config_event(const unsigned char* admin_privkey_bytes,
|
||||||
const char* relay_privkey_hex,
|
const char* relay_privkey_hex,
|
||||||
const char* relay_pubkey_hex);
|
const char* relay_pubkey_hex,
|
||||||
|
const cli_options_t* cli_options);
|
||||||
|
|
||||||
#endif /* DEFAULT_CONFIG_EVENT_H */
|
#endif /* DEFAULT_CONFIG_EVENT_H */
|
||||||
59
src/main.c
59
src/main.c
@@ -3132,14 +3132,19 @@ void print_usage(const char* program_name) {
|
|||||||
printf("Options:\n");
|
printf("Options:\n");
|
||||||
printf(" -h, --help Show this help message\n");
|
printf(" -h, --help Show this help message\n");
|
||||||
printf(" -v, --version Show version information\n");
|
printf(" -v, --version Show version information\n");
|
||||||
|
printf(" -p, --port PORT Override relay port (first-time startup only)\n");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf("Configuration:\n");
|
printf("Configuration:\n");
|
||||||
printf(" This relay uses event-based configuration stored in the database.\n");
|
printf(" This relay uses event-based configuration stored in the database.\n");
|
||||||
printf(" On first startup, keys are automatically generated and printed once.\n");
|
printf(" On first startup, keys are automatically generated and printed once.\n");
|
||||||
|
printf(" Command line options like --port only apply during first-time setup.\n");
|
||||||
|
printf(" After initial setup, all configuration is managed via database events.\n");
|
||||||
printf(" Database file: <relay_pubkey>.db (created automatically)\n");
|
printf(" Database file: <relay_pubkey>.db (created automatically)\n");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf("Examples:\n");
|
printf("Examples:\n");
|
||||||
printf(" %s # Start relay (auto-configure on first run)\n", program_name);
|
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 --help # Show this help\n", program_name);
|
printf(" %s --help # Show this help\n", program_name);
|
||||||
printf(" %s --version # Show version info\n", program_name);
|
printf(" %s --version # Show version info\n", program_name);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
@@ -3154,7 +3159,12 @@ void print_version() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
// Parse minimal command line arguments (no configuration overrides)
|
// Initialize CLI options structure
|
||||||
|
cli_options_t cli_options = {
|
||||||
|
.port_override = -1 // -1 = not set
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parse command line arguments
|
||||||
for (int i = 1; i < argc; i++) {
|
for (int i = 1; i < argc; i++) {
|
||||||
if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
|
if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
|
||||||
print_usage(argv[0]);
|
print_usage(argv[0]);
|
||||||
@@ -3162,6 +3172,30 @@ int main(int argc, char* argv[]) {
|
|||||||
} else if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--version") == 0) {
|
} else if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--version") == 0) {
|
||||||
print_version();
|
print_version();
|
||||||
return 0;
|
return 0;
|
||||||
|
} else if (strcmp(argv[i], "-p") == 0 || strcmp(argv[i], "--port") == 0) {
|
||||||
|
// Port override option
|
||||||
|
if (i + 1 >= argc) {
|
||||||
|
log_error("Port option requires a value. Use --help for usage information.");
|
||||||
|
print_usage(argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse port number
|
||||||
|
char* endptr;
|
||||||
|
long port = strtol(argv[i + 1], &endptr, 10);
|
||||||
|
|
||||||
|
if (endptr == argv[i + 1] || *endptr != '\0' || port < 1 || port > 65535) {
|
||||||
|
log_error("Invalid port number. Port must be between 1 and 65535.");
|
||||||
|
print_usage(argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cli_options.port_override = (int)port;
|
||||||
|
i++; // Skip the port argument
|
||||||
|
|
||||||
|
char port_msg[128];
|
||||||
|
snprintf(port_msg, sizeof(port_msg), "Port override specified: %d", cli_options.port_override);
|
||||||
|
log_info(port_msg);
|
||||||
} else {
|
} else {
|
||||||
log_error("Unknown argument. Use --help for usage information.");
|
log_error("Unknown argument. Use --help for usage information.");
|
||||||
print_usage(argv[0]);
|
print_usage(argv[0]);
|
||||||
@@ -3193,8 +3227,8 @@ int main(int argc, char* argv[]) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run first-time startup sequence (generates keys, creates database, etc.)
|
// Run first-time startup sequence (generates keys, sets up database path, but doesn't store private key yet)
|
||||||
if (first_time_startup_sequence() != 0) {
|
if (first_time_startup_sequence(&cli_options) != 0) {
|
||||||
log_error("Failed to complete first-time startup sequence");
|
log_error("Failed to complete first-time startup sequence");
|
||||||
cleanup_configuration_system();
|
cleanup_configuration_system();
|
||||||
nostr_cleanup();
|
nostr_cleanup();
|
||||||
@@ -3209,6 +3243,23 @@ int main(int argc, char* argv[]) {
|
|||||||
return 1;
|
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) {
|
||||||
|
if (store_relay_private_key(relay_privkey) != 0) {
|
||||||
|
log_error("Failed to store relay private key securely after database initialization");
|
||||||
|
cleanup_configuration_system();
|
||||||
|
nostr_cleanup();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
log_success("Relay private key stored securely in database");
|
||||||
|
} else {
|
||||||
|
log_error("Relay private key not available from first-time startup");
|
||||||
|
cleanup_configuration_system();
|
||||||
|
nostr_cleanup();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Retry storing the configuration event now that database is initialized
|
// Retry storing the configuration event now that database is initialized
|
||||||
if (retry_store_initial_config_event() != 0) {
|
if (retry_store_initial_config_event() != 0) {
|
||||||
log_warning("Failed to store initial configuration event after database init");
|
log_warning("Failed to store initial configuration event after database init");
|
||||||
@@ -3217,7 +3268,7 @@ int main(int argc, char* argv[]) {
|
|||||||
log_info("Existing relay detected");
|
log_info("Existing relay detected");
|
||||||
|
|
||||||
// Find existing database file
|
// Find existing database file
|
||||||
char** existing_files = find_existing_nrdb_files();
|
char** existing_files = find_existing_db_files();
|
||||||
if (!existing_files || !existing_files[0]) {
|
if (!existing_files || !existing_files[0]) {
|
||||||
log_error("No existing relay database found");
|
log_error("No existing relay database found");
|
||||||
nostr_cleanup();
|
nostr_cleanup();
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
/* Embedded SQL Schema for C Nostr Relay
|
/* Embedded SQL Schema for C Nostr Relay
|
||||||
* Generated from db/schema.sql - Do not edit manually
|
* Generated from db/schema.sql - Do not edit manually
|
||||||
* Schema Version: 4
|
* Schema Version: 5
|
||||||
*/
|
*/
|
||||||
#ifndef SQL_SCHEMA_H
|
#ifndef SQL_SCHEMA_H
|
||||||
#define SQL_SCHEMA_H
|
#define SQL_SCHEMA_H
|
||||||
|
|
||||||
/* Schema version constant */
|
/* Schema version constant */
|
||||||
#define EMBEDDED_SCHEMA_VERSION "4"
|
#define EMBEDDED_SCHEMA_VERSION "5"
|
||||||
|
|
||||||
/* Embedded SQL schema as C string literal */
|
/* Embedded SQL schema as C string literal */
|
||||||
static const char* const EMBEDDED_SCHEMA_SQL =
|
static const char* const EMBEDDED_SCHEMA_SQL =
|
||||||
@@ -15,7 +15,7 @@ static const char* const EMBEDDED_SCHEMA_SQL =
|
|||||||
-- Event-based configuration system using kind 33334 Nostr events\n\
|
-- Event-based configuration system using kind 33334 Nostr events\n\
|
||||||
\n\
|
\n\
|
||||||
-- Schema version tracking\n\
|
-- Schema version tracking\n\
|
||||||
PRAGMA user_version = 4;\n\
|
PRAGMA user_version = 5;\n\
|
||||||
\n\
|
\n\
|
||||||
-- Enable foreign key support\n\
|
-- Enable foreign key support\n\
|
||||||
PRAGMA foreign_keys = ON;\n\
|
PRAGMA foreign_keys = ON;\n\
|
||||||
@@ -58,8 +58,8 @@ CREATE TABLE schema_info (\n\
|
|||||||
\n\
|
\n\
|
||||||
-- Insert schema metadata\n\
|
-- Insert schema metadata\n\
|
||||||
INSERT INTO schema_info (key, value) VALUES\n\
|
INSERT INTO schema_info (key, value) VALUES\n\
|
||||||
('version', '4'),\n\
|
('version', '5'),\n\
|
||||||
('description', 'Event-based Nostr relay schema with kind 33334 configuration events'),\n\
|
('description', 'Event-based Nostr relay schema with secure relay private key storage'),\n\
|
||||||
('created_at', strftime('%s', 'now'));\n\
|
('created_at', strftime('%s', 'now'));\n\
|
||||||
\n\
|
\n\
|
||||||
-- Helper views for common queries\n\
|
-- Helper views for common queries\n\
|
||||||
@@ -128,6 +128,13 @@ BEGIN\n\
|
|||||||
AND id != NEW.id;\n\
|
AND id != NEW.id;\n\
|
||||||
END;\n\
|
END;\n\
|
||||||
\n\
|
\n\
|
||||||
|
-- Relay Private Key Secure Storage\n\
|
||||||
|
-- Stores the relay's private key separately from public configuration\n\
|
||||||
|
CREATE TABLE relay_seckey (\n\
|
||||||
|
private_key_hex TEXT NOT NULL CHECK (length(private_key_hex) = 64),\n\
|
||||||
|
created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))\n\
|
||||||
|
);\n\
|
||||||
|
\n\
|
||||||
-- Persistent Subscriptions Logging Tables (Phase 2)\n\
|
-- Persistent Subscriptions Logging Tables (Phase 2)\n\
|
||||||
-- Optional database logging for subscription analytics and debugging\n\
|
-- Optional database logging for subscription analytics and debugging\n\
|
||||||
\n\
|
\n\
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
[34m[1m=== C Nostr Relay Server ===[0m
|
|
||||||
Event-based configuration system
|
|
||||||
|
|
||||||
[34m[INFO][0m Existing relay detected
|
|
||||||
[34m[INFO][0m Initializing event-based configuration system...
|
|
||||||
[32m[SUCCESS][0m Event-based configuration system initialized
|
|
||||||
[34m[INFO][0m Starting existing relay...
|
|
||||||
Relay pubkey: 6df436471c7965d6473e89998162e6b87cc3547d71a2db12f559a39f4596059a
|
|
||||||
[32m[SUCCESS][0m Existing relay startup prepared
|
|
||||||
[32m[SUCCESS][0m Database connection established: 6df436471c7965d6473e89998162e6b87cc3547d71a2db12f559a39f4596059a.nrdb
|
|
||||||
[34m[INFO][0m Database schema already exists, skipping initialization
|
|
||||||
[34m[INFO][0m Existing database schema version: 4
|
|
||||||
[34m[INFO][0m Applying configuration from event...
|
|
||||||
[34m[INFO][0m Checking for runtime configuration changes...
|
|
||||||
[34m[INFO][0m Subscription limits changed - updating subscription manager
|
|
||||||
[34m[INFO][0m Subscription limits: max_per_client=25, max_total=5000
|
|
||||||
[34m[INFO][0m PoW configuration changed - reinitializing PoW system
|
|
||||||
[34m[INFO][0m Initializing NIP-13 Proof of Work configuration
|
|
||||||
[34m[INFO][0m PoW configured in basic validation mode
|
|
||||||
[34m[INFO][0m PoW Configuration: enabled=true, min_difficulty=0, validation_flags=0x1, mode=full
|
|
||||||
[34m[INFO][0m Expiration configuration changed - reinitializing expiration system
|
|
||||||
[34m[INFO][0m Initializing NIP-40 Expiration Timestamp configuration
|
|
||||||
[34m[INFO][0m Expiration Configuration: enabled=true, strict_mode=true, filter_responses=true, grace_period=300 seconds
|
|
||||||
[34m[INFO][0m Relay information changed - reinitializing relay info
|
|
||||||
[32m[SUCCESS][0m Relay information initialized with default values
|
|
||||||
[32m[SUCCESS][0m Configuration updated via kind 33334 event - 4 system components reinitialized
|
|
||||||
[32m[SUCCESS][0m Configuration applied from event (4 handlers executed)
|
|
||||||
[32m[SUCCESS][0m Configuration loaded from database
|
|
||||||
[32m[SUCCESS][0m Relay information initialized with default values
|
|
||||||
[34m[INFO][0m Initializing NIP-13 Proof of Work configuration
|
|
||||||
[34m[INFO][0m PoW configured in basic validation mode
|
|
||||||
[34m[INFO][0m PoW Configuration: enabled=true, min_difficulty=0, validation_flags=0x1, mode=full
|
|
||||||
[34m[INFO][0m Initializing NIP-40 Expiration Timestamp configuration
|
|
||||||
[34m[INFO][0m Expiration Configuration: enabled=true, strict_mode=true, filter_responses=true, grace_period=300 seconds
|
|
||||||
[34m[INFO][0m Subscription limits: max_per_client=25, max_total=5000
|
|
||||||
[34m[INFO][0m Starting relay server...
|
|
||||||
[34m[INFO][0m Starting libwebsockets-based Nostr relay server...
|
|
||||||
[34m[INFO][0m Attempting to bind to port 8888
|
|
||||||
[2025/09/06 20:34:16:8170] E: ERROR on binding fd 8 to port 8888 (-1 98)
|
|
||||||
[2025/09/06 20:34:16:8172] E: init server failed
|
|
||||||
[2025/09/06 20:34:16:8172] E: Failed to create default vhost
|
|
||||||
[31m[ERROR][0m Failed to create libwebsockets context after 1 attempts. Last attempted port: 8888
|
|
||||||
libwebsockets creation error: Inappropriate ioctl for device
|
|
||||||
[34m[INFO][0m Cleaning up configuration system...
|
|
||||||
[32m[SUCCESS][0m Configuration system cleaned up
|
|
||||||
[34m[INFO][0m Database connection closed
|
|
||||||
[31m[ERROR][0m Server shutdown with errors
|
|
||||||
Reference in New Issue
Block a user