Compare commits

..

2 Commits

7 changed files with 51 additions and 349 deletions

View File

@@ -1 +1 @@
2377328
2442403

View File

@@ -132,7 +132,6 @@ void force_config_cache_refresh(void) {
g_unified_cache.cache_valid = 0;
g_unified_cache.cache_expires = 0;
pthread_mutex_unlock(&g_unified_cache.cache_lock);
log_info("Configuration cache forcibly invalidated");
}
// Update specific cache value without full refresh
@@ -211,7 +210,6 @@ int update_cache_value(const char* key, const char* value) {
pthread_mutex_unlock(&g_unified_cache.cache_lock);
log_info("Updated specific cache value");
printf(" Key: %s\n", key);
return 0;
}
@@ -223,8 +221,6 @@ static int refresh_unified_cache_from_table(void) {
return -1;
}
log_info("Refreshing unified configuration cache from database");
// Lock the cache for update (don't memset entire cache to avoid wiping relay_info)
pthread_mutex_lock(&g_unified_cache.cache_lock);
@@ -361,7 +357,6 @@ static int refresh_unified_cache_from_table(void) {
pthread_mutex_unlock(&g_unified_cache.cache_lock);
log_info("Unified configuration cache refreshed from database");
return 0;
}
@@ -502,7 +497,6 @@ int create_database_with_relay_pubkey(const char* relay_pubkey) {
strncpy(g_database_path, db_name, sizeof(g_database_path) - 1);
g_database_path[sizeof(g_database_path) - 1] = '\0';
log_info("Creating database with relay pubkey");
printf(" Database: %s\n", db_name);
free(db_name);
@@ -562,7 +556,6 @@ int store_config_event_in_database(const cJSON* event) {
free(tags_str);
if (rc == SQLITE_DONE) {
log_success("Configuration event stored in database");
return 0;
} else {
log_error("Failed to store configuration event");
@@ -576,7 +569,6 @@ cJSON* load_config_event_from_database(const char* relay_pubkey) {
}
// Configuration is now managed through config table, not events
log_info("Configuration events are no longer stored in events table");
return NULL;
}
@@ -793,8 +785,6 @@ int init_configuration_system(const char* config_dir_override, const char* confi
(void)config_dir_override;
(void)config_file_override;
log_info("Initializing event-based configuration system...");
// Initialize unified cache with proper structure initialization
pthread_mutex_lock(&g_unified_cache.cache_lock);
@@ -839,14 +829,11 @@ int init_configuration_system(const char* config_dir_override, const char* confi
g_unified_cache.nip70_protected_events_enabled = 0;
pthread_mutex_unlock(&g_unified_cache.cache_lock);
log_success("Event-based configuration system initialized with unified cache structures");
return 0;
}
void cleanup_configuration_system(void) {
log_info("Cleaning up configuration system...");
if (g_current_config) {
cJSON_Delete(g_current_config);
g_current_config = NULL;
@@ -907,7 +894,6 @@ void cleanup_configuration_system(void) {
memset(&g_unified_cache.expiration_config, 0, sizeof(g_unified_cache.expiration_config));
pthread_mutex_unlock(&g_unified_cache.cache_lock);
log_success("Configuration system cleaned up with proper JSON cleanup");
}
int set_database_config(const char* key, const char* value, const char* changed_by) {
@@ -1001,7 +987,6 @@ int store_relay_private_key(const char* relay_privkey_hex) {
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");
@@ -1064,8 +1049,6 @@ cJSON* create_default_config_event(const unsigned char* admin_privkey_bytes,
return NULL;
}
log_info("Creating default configuration event...");
// Create tags array with default configuration values
cJSON* tags = cJSON_CreateArray();
if (!tags) {
@@ -1101,7 +1084,6 @@ cJSON* create_default_config_event(const unsigned char* admin_privkey_bytes,
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));
@@ -1134,7 +1116,6 @@ cJSON* create_default_config_event(const unsigned char* admin_privkey_bytes,
cJSON* pubkey_obj = cJSON_GetObjectItem(event, "pubkey");
if (id_obj && pubkey_obj) {
log_success("Default configuration event created successfully");
printf(" Event ID: %s\n", cJSON_GetStringValue(id_obj));
printf(" Admin Public Key: %s\n", cJSON_GetStringValue(pubkey_obj));
}
@@ -1147,7 +1128,6 @@ cJSON* create_default_config_event(const unsigned char* admin_privkey_bytes,
// ================================
int first_time_startup_sequence(const cli_options_t* cli_options) {
log_info("Starting first-time startup sequence...");
// 1. Generate or use provided admin keypair
unsigned char admin_privkey_bytes[32];
@@ -1156,7 +1136,6 @@ int first_time_startup_sequence(const cli_options_t* cli_options) {
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';
@@ -1178,7 +1157,6 @@ int first_time_startup_sequence(const cli_options_t* cli_options) {
generated_admin_key = 0; // Did not generate a new key
} 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;
@@ -1201,7 +1179,6 @@ int first_time_startup_sequence(const cli_options_t* cli_options) {
if (cli_options && strlen(cli_options->relay_privkey_override) == 64) {
// Use provided relay private key
log_info("Using provided relay private key override");
strncpy(relay_privkey, cli_options->relay_privkey_override, sizeof(relay_privkey) - 1);
relay_privkey[sizeof(relay_privkey) - 1] = '\0';
@@ -1249,10 +1226,8 @@ int first_time_startup_sequence(const cli_options_t* cli_options) {
// 5. Store relay private key in temporary storage for later secure storage
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. Handle configuration setup - defaults will be populated after database initialization
log_info("Configuration setup prepared - defaults will be populated after database initialization");
// CLI overrides will be applied after database initialization in main.c
@@ -1285,7 +1260,6 @@ int first_time_startup_sequence(const cli_options_t* cli_options) {
printf("\n");
}
log_success("First-time startup sequence completed");
return 0;
}
@@ -1295,7 +1269,6 @@ int startup_existing_relay(const char* relay_pubkey) {
return -1;
}
log_info("Starting existing relay...");
printf(" Relay pubkey: %s\n", relay_pubkey);
// Store relay pubkey in unified cache
@@ -1321,12 +1294,9 @@ int startup_existing_relay(const char* relay_pubkey) {
}
// Configuration will be migrated from events to table after database initialization
log_info("Configuration migration will be performed after database is available");
// Load configuration event from database (after database is initialized)
// This will be done in apply_configuration_from_database()
log_success("Existing relay startup prepared");
return 0;
}
@@ -1724,7 +1694,6 @@ static int validate_configuration_event_fields(const cJSON* event, char* error_m
return -1;
}
log_info("Validating configuration event fields...");
cJSON* tags = cJSON_GetObjectItem(event, "tags");
if (!tags || !cJSON_IsArray(tags)) {
@@ -1779,10 +1748,7 @@ static int validate_configuration_event_fields(const cJSON* event, char* error_m
log_error(summary);
return -1;
}
char success_msg[256];
snprintf(success_msg, sizeof(success_msg), "%d configuration fields validated successfully", validated_fields);
log_success(success_msg);
return 0;
}
@@ -1791,9 +1757,7 @@ int process_configuration_event(const cJSON* event) {
log_error("Invalid configuration event");
return -1;
}
log_info("Processing configuration event...");
// Validate event structure
cJSON* kind_obj = cJSON_GetObjectItem(event, "kind");
cJSON* pubkey_obj = cJSON_GetObjectItem(event, "pubkey");
@@ -1819,22 +1783,19 @@ int process_configuration_event(const cJSON* event) {
}
// Comprehensive event validation using nostr_core_lib
log_info("Validating configuration event structure and signature...");
// First validate the event structure (fields, format, etc.)
if (nostr_validate_event_structure((cJSON*)event) != NOSTR_SUCCESS) {
log_error("Configuration event has invalid structure");
return -1;
}
// Then validate the cryptographic signature
if (nostr_verify_event_signature((cJSON*)event) != NOSTR_SUCCESS) {
log_error("Configuration event has invalid signature");
return -1;
}
log_success("Configuration event structure and signature validated successfully");
// NEW: Validate configuration field values
char validation_error[512];
if (validate_configuration_event_fields(event, validation_error, sizeof(validation_error)) != 0) {
@@ -2262,22 +2223,10 @@ int process_admin_event_in_config(cJSON* event, char* error_message, size_t erro
}
int kind = (int)cJSON_GetNumberValue(kind_obj);
printf(" Event kind: %d\n", kind);
// Extract and log event details for debugging
// Get event pubkey for authorization logging
cJSON* pubkey_obj = cJSON_GetObjectItem(event, "pubkey");
cJSON* content_obj = cJSON_GetObjectItem(event, "content");
cJSON* tags_obj = cJSON_GetObjectItem(event, "tags");
const char* event_pubkey = pubkey_obj ? cJSON_GetStringValue(pubkey_obj) : "unknown";
const char* event_content = content_obj ? cJSON_GetStringValue(content_obj) : "unknown";
printf(" Pubkey: %.16s...\n", event_pubkey ? event_pubkey : "null");
printf(" Content length: %zu\n", event_content ? strlen(event_content) : 0);
printf(" Has tags: %s\n", tags_obj ? "yes" : "no");
if (tags_obj && cJSON_IsArray(tags_obj)) {
printf(" Tags count: %d\n", cJSON_GetArraySize(tags_obj));
}
const char* event_pubkey = pubkey_obj ? cJSON_GetStringValue(pubkey_obj) : NULL;
// DEFENSE-IN-DEPTH: Use comprehensive admin authorization validation
if (!is_authorized_admin_event(event)) {
@@ -2306,12 +2255,7 @@ int process_admin_event_in_config(cJSON* event, char* error_message, size_t erro
// Handle legacy Kind 33334 configuration management events
int process_admin_config_event(cJSON* event, char* error_message, size_t error_size) {
cJSON* kind_obj = cJSON_GetObjectItem(event, "kind");
int kind = kind_obj ? (int)cJSON_GetNumberValue(kind_obj) : 0;
log_info("Processing admin configuration event");
printf(" Kind: %d\n", kind);
// Parse tags to find query commands according to API specification
cJSON* tags_obj = cJSON_GetObjectItem(event, "tags");
if (tags_obj && cJSON_IsArray(tags_obj)) {
@@ -2407,8 +2351,6 @@ int process_admin_auth_event(cJSON* event, char* error_message, size_t error_siz
cJSON* kind_obj = cJSON_GetObjectItem(event, "kind");
int kind = kind_obj ? (int)cJSON_GetNumberValue(kind_obj) : 0;
printf(" Kind: %d\n", kind);
// Extract and log additional event details for debugging
cJSON* content_obj = cJSON_GetObjectItem(event, "content");
cJSON* tags_obj = cJSON_GetObjectItem(event, "tags");
@@ -2570,7 +2512,6 @@ cJSON* create_admin_response_event(const char* encrypted_content, const char* re
return NULL;
}
log_info("Creating signed kind 23457 admin response event");
printf(" Recipient pubkey: %.16s...\n", recipient_pubkey);
printf(" Encrypted content length: %zu\n", strlen(encrypted_content));
@@ -2629,7 +2570,6 @@ cJSON* create_admin_response_event(const char* encrypted_content, const char* re
cJSON* pubkey_obj = cJSON_GetObjectItem(response_event, "pubkey");
if (id_obj && pubkey_obj) {
log_success("Kind 23457 admin response event created and signed successfully");
printf(" Event ID: %s\n", cJSON_GetStringValue(id_obj));
printf(" Relay pubkey: %.16s...\n", cJSON_GetStringValue(pubkey_obj));
}
@@ -2644,17 +2584,15 @@ char* encrypt_admin_response_content(const cJSON* response_data, const char* rec
return NULL;
}
log_info("Encrypting admin response content with NIP-44");
printf(" Recipient pubkey: %.16s...\n", recipient_pubkey);
// Convert response data to JSON string
char* response_json = cJSON_Print(response_data);
if (!response_json) {
log_error("Failed to serialize response data for encryption");
return NULL;
}
log_info("Response data serialized for encryption");
printf(" JSON length: %zu\n", strlen(response_json));
printf(" JSON preview: %.100s%s\n", response_json,
strlen(response_json) > 100 ? "..." : "");
@@ -2702,8 +2640,7 @@ char* encrypt_admin_response_content(const cJSON* response_data, const char* rec
printf(" Encryption result code: %d\n", encrypt_result);
return NULL;
}
log_success("Admin response content encrypted successfully with NIP-44");
printf(" Encrypted content length: %zu\n", strlen(encrypted_content));
printf(" Encrypted preview: %.50s...\n", encrypted_content);
@@ -2720,7 +2657,6 @@ int send_admin_response_event(const cJSON* response_data, const char* recipient_
return -1;
}
log_info("Sending admin response as signed kind 23457 event through relay distribution system");
printf(" Recipient pubkey: %.16s...\n", recipient_pubkey);
// Step 1: Encrypt response data using NIP-44
@@ -2739,18 +2675,15 @@ int send_admin_response_event(const cJSON* response_data, const char* recipient_
return -1;
}
log_info("Admin response event created successfully");
cJSON* id_obj = cJSON_GetObjectItem(response_event, "id");
if (id_obj) {
printf(" Event ID: %s\n", cJSON_GetStringValue(id_obj));
}
// Step 3: Store event in database for persistence
extern int store_event(cJSON* event);
if (store_event(response_event) != 0) {
log_warning("Failed to store admin response event in database (continuing with broadcast)");
} else {
log_info("Admin response event stored in database successfully");
}
// Step 4: Broadcast event to all matching subscriptions using relay's standard system
@@ -2758,10 +2691,9 @@ int send_admin_response_event(const cJSON* response_data, const char* recipient_
int broadcast_count = broadcast_event_to_subscriptions(response_event);
if (broadcast_count >= 0) {
log_success("Admin response event distributed through relay subscription system");
printf(" Event kind: 23457 (admin response)\n");
printf(" Subscriptions notified: %d\n", broadcast_count);
// Clean up and return success - event creation succeeded regardless of broadcast count
cJSON_Delete(response_event);
return 0;
@@ -3072,9 +3004,6 @@ int handle_auth_query_unified(cJSON* event, const char* query_type, char* error_
return -1;
}
log_info("Processing unified auth query");
printf(" Query type: %s\n", query_type);
const char* sql = NULL;
int use_pattern_param = 0;
char* pattern_value = NULL;
@@ -3170,7 +3099,6 @@ int handle_auth_query_unified(cJSON* event, const char* query_type, char* error_
// Send response as signed kind 23457 event
if (send_admin_response_event(response, admin_pubkey, wsi) == 0) {
printf("Total results: %d\n", rule_count);
log_success("Auth query completed successfully with signed response");
printf(" Response query_type: %s (mapped from %s)\n", mapped_query_type, query_type);
cJSON_Delete(response);
cJSON_Delete(results_array);
@@ -3193,9 +3121,6 @@ int handle_config_query_unified(cJSON* event, const char* query_type, char* erro
return -1;
}
log_info("Processing unified config query");
printf(" Query type: %s\n", query_type);
const char* sql = NULL;
int use_pattern_param = 0;
char* pattern_value = NULL;
@@ -3297,7 +3222,6 @@ int handle_config_query_unified(cJSON* event, const char* query_type, char* erro
// Send response as signed kind 23457 event
if (send_admin_response_event(response, admin_pubkey, wsi) == 0) {
printf("Total results: %d\n", config_count);
log_success("Config query completed successfully with signed response");
printf(" Response query_type: %s (mapped from %s)\n", mapped_query_type, query_type);
cJSON_Delete(response);
cJSON_Delete(results_array);
@@ -3320,10 +3244,6 @@ int handle_config_set_unified(cJSON* event, const char* config_key, const char*
return -1;
}
log_info("Processing unified config set command");
printf(" Key: %s\n", config_key);
printf(" Value: %s\n", config_value);
// Validate the configuration field before updating
char validation_error[512];
if (validate_config_field(config_key, config_value, validation_error, sizeof(validation_error)) != 0) {
@@ -3387,7 +3307,6 @@ int handle_config_set_unified(cJSON* event, const char* config_key, const char*
// Send response as signed kind 23457 event
if (send_admin_response_event(response, admin_pubkey, wsi) == 0) {
log_success("Config set command completed successfully with signed response");
cJSON_Delete(response);
return 0;
}
@@ -3406,9 +3325,6 @@ int handle_system_command_unified(cJSON* event, const char* command, char* error
return -1;
}
log_info("Processing unified system command");
printf(" Command: %s\n", command);
if (strcmp(command, "clear_all_auth_rules") == 0) {
// Count existing rules first
const char* count_sql = "SELECT COUNT(*) FROM auth_rules";
@@ -3456,7 +3372,6 @@ int handle_system_command_unified(cJSON* event, const char* command, char* error
// Send response as signed kind 23457 event
if (send_admin_response_event(response, admin_pubkey, wsi) == 0) {
log_success("Clear auth rules command completed successfully with signed response");
cJSON_Delete(response);
return 0;
}
@@ -3535,7 +3450,6 @@ int handle_system_command_unified(cJSON* event, const char* command, char* error
// Send response as signed kind 23457 event
if (send_admin_response_event(response, admin_pubkey, wsi) == 0) {
log_success("Delete auth rule command completed successfully with signed response");
cJSON_Delete(response);
return 0;
}
@@ -3597,7 +3511,6 @@ int handle_system_command_unified(cJSON* event, const char* command, char* error
// Send response as signed kind 23457 event
if (send_admin_response_event(response, admin_pubkey, wsi) == 0) {
log_success("System status query completed successfully with signed response");
cJSON_Delete(response);
return 0;
}
@@ -3630,11 +3543,8 @@ int handle_system_command_unified(cJSON* event, const char* command, char* error
// Send acknowledgment response as signed kind 23457 event
if (send_admin_response_event(response, admin_pubkey, wsi) == 0) {
log_success("Restart acknowledgment sent successfully - initiating shutdown");
// Trigger graceful shutdown by setting the global shutdown flag
g_shutdown_flag = 1;
log_info("Shutdown flag set - relay will restart gracefully");
cJSON_Delete(response);
return 0;
@@ -3748,7 +3658,6 @@ int handle_auth_rule_modification_unified(cJSON* event, char* error_message, siz
// Send response as signed kind 23457 event
if (send_admin_response_event(response, admin_pubkey, wsi) == 0) {
log_success("Auth rule modification completed successfully with signed response");
cJSON_Delete(response);
return 0;
}
@@ -3772,9 +3681,6 @@ int handle_stats_query_unified(cJSON* event, char* error_message, size_t error_s
return -1;
}
log_info("Processing unified stats query");
printf(" Query type: stats_query\n");
// Build response with database statistics
cJSON* response = cJSON_CreateObject();
cJSON_AddStringToObject(response, "query_type", "stats_query");
@@ -3886,7 +3792,6 @@ int handle_stats_query_unified(cJSON* event, char* error_message, size_t error_s
// Send response as signed kind 23457 event
if (send_admin_response_event(response, admin_pubkey, wsi) == 0) {
log_success("Stats query completed successfully with signed response");
cJSON_Delete(response);
return 0;
}
@@ -4009,11 +3914,6 @@ int handle_config_update_unified(cJSON* event, char* error_message, size_t error
const char* category = category_obj && cJSON_IsString(category_obj) ?
cJSON_GetStringValue(category_obj) : "general";
log_info("Processing config object");
printf(" Key: %s\n", key);
printf(" Value: %s\n", value);
printf(" Data type: %s\n", data_type);
printf(" Category: %s\n", category);
// Validate the configuration field before updating
char validation_error[512];
@@ -4269,7 +4169,6 @@ int handle_config_update_unified(cJSON* event, char* error_message, size_t error
// Send response as signed kind 23457 event
if (send_admin_response_event(response, admin_pubkey, wsi) == 0) {
log_success("Config update command completed successfully with signed response");
printf(" Response query_type: config_update\n");
cJSON_Delete(response);
return 0;
@@ -4571,7 +4470,6 @@ int process_startup_config_event(const cJSON* event) {
return -1;
}
log_info("Processing startup configuration event through admin API...");
// Validate event structure first
cJSON* kind_obj = cJSON_GetObjectItem(event, "kind");

View File

@@ -257,9 +257,7 @@ int process_dm_admin_command(cJSON* command_array, cJSON* event, char* error_mes
snprintf(error_message, error_size, "invalid: unknown DM command type '%s'", command_type);
}
if (result == 0) {
log_success("DM Admin: Command processed successfully");
} else {
if (result != 0) {
log_error("DM Admin: Command processing failed");
}
@@ -579,7 +577,6 @@ void cleanup_expired_pending_changes(void) {
while (current) {
pending_config_change_t* next = current->next;
if (now - current->timestamp > CONFIG_CHANGE_TIMEOUT) {
log_info("Cleaning up expired config change request");
remove_pending_change(current);
}
current = next;
@@ -650,9 +647,6 @@ int apply_config_change(const char* key, const char* value) {
}
sqlite3_finalize(stmt);
char log_msg[512];
snprintf(log_msg, sizeof(log_msg), "Configuration updated: %s = %s", key, normalized_value);
log_success(log_msg);
return 0;
}
@@ -912,8 +906,6 @@ char* generate_stats_json(void) {
return NULL;
}
log_info("Generating stats JSON from database");
// Build response with database statistics
cJSON* response = cJSON_CreateObject();
cJSON_AddStringToObject(response, "query_type", "stats_query");
@@ -1013,9 +1005,7 @@ char* generate_stats_json(void) {
char* json_string = cJSON_Print(response);
cJSON_Delete(response);
if (json_string) {
log_success("Stats JSON generated successfully");
} else {
if (!json_string) {
log_error("Failed to generate stats JSON");
}
@@ -1096,7 +1086,6 @@ int send_nip17_response(const char* sender_pubkey, const char* response_content,
strcmp(cJSON_GetStringValue(tag_name), "p") == 0) {
// Replace the p tag value with the correct user pubkey
cJSON_ReplaceItemInArray(tag, 1, cJSON_CreateString(sender_pubkey));
log_info("NIP-17: Fixed p tag in response gift wrap");
break;
}
}
@@ -1113,11 +1102,7 @@ int send_nip17_response(const char* sender_pubkey, const char* response_content,
}
// Broadcast the response event to active subscriptions
int broadcast_count = broadcast_event_to_subscriptions(gift_wraps[0]);
char debug_broadcast_msg[128];
snprintf(debug_broadcast_msg, sizeof(debug_broadcast_msg),
"NIP-17: Response broadcast to %d subscriptions", broadcast_count);
log_info(debug_broadcast_msg);
broadcast_event_to_subscriptions(gift_wraps[0]);
cJSON_Delete(gift_wraps[0]);
return 0;
@@ -1367,7 +1352,6 @@ cJSON* process_nip17_admin_message(cJSON* gift_wrap_event, char* error_message,
free(relay_privkey_hex);
// Step 3: Decrypt and parse inner event using library function
log_info("NIP-17: Attempting to decrypt gift wrap with nostr_nip17_receive_dm");
cJSON* inner_dm = nostr_nip17_receive_dm(gift_wrap_event, relay_privkey);
if (!inner_dm) {
log_error("NIP-17: nostr_nip17_receive_dm returned NULL");
@@ -1385,14 +1369,10 @@ cJSON* process_nip17_admin_message(cJSON* gift_wrap_event, char* error_message,
sprintf(privkey_hex + (i * 2), "%02x", relay_privkey[i]);
}
privkey_hex[64] = '\0';
char privkey_msg[128];
snprintf(privkey_msg, sizeof(privkey_msg), "NIP-17: Using relay private key: %.16s...", privkey_hex);
log_info(privkey_msg);
strncpy(error_message, "NIP-17: Failed to decrypt and parse inner DM event", error_size - 1);
return NULL;
}
log_info("NIP-17: Successfully decrypted gift wrap");
// Step 4: Process admin command
int result = process_nip17_admin_command(inner_dm, error_message, error_size, wsi);
@@ -1422,7 +1402,6 @@ cJSON* process_nip17_admin_message(cJSON* gift_wrap_event, char* error_message,
// If it's a plain text stats or config command, don't create additional response
if (strstr(content_lower, "stats") != NULL || strstr(content_lower, "statistics") != NULL ||
strstr(content_lower, "config") != NULL || strstr(content_lower, "configuration") != NULL) {
log_info("NIP-17: Plain text command already handled response, skipping generic response");
cJSON_Delete(inner_dm);
return NULL; // No additional response needed
}
@@ -1432,7 +1411,6 @@ cJSON* process_nip17_admin_message(cJSON* gift_wrap_event, char* error_message,
if (command_array && cJSON_IsArray(command_array) && cJSON_GetArraySize(command_array) > 0) {
cJSON* first_item = cJSON_GetArrayItem(command_array, 0);
if (cJSON_IsString(first_item) && strcmp(cJSON_GetStringValue(first_item), "stats") == 0) {
log_info("NIP-17: JSON stats command already handled response, skipping generic response");
cJSON_Delete(command_array);
cJSON_Delete(inner_dm);
return NULL; // No additional response needed
@@ -1442,7 +1420,6 @@ cJSON* process_nip17_admin_message(cJSON* gift_wrap_event, char* error_message,
}
} else if (result > 0) {
// Command was handled and response was sent, don't create generic response
log_info("NIP-17: Command handled with custom response, skipping generic response");
cJSON_Delete(inner_dm);
return NULL;
@@ -1588,7 +1565,6 @@ int process_nip17_admin_command(cJSON* dm_event, char* error_message, size_t err
// Check if sender is admin before processing any commands
cJSON* sender_pubkey_obj = cJSON_GetObjectItem(dm_event, "pubkey");
if (!sender_pubkey_obj || !cJSON_IsString(sender_pubkey_obj)) {
log_info("NIP-17: DM missing sender pubkey, treating as user DM");
return 0; // Not an error, just treat as user DM
}
const char* sender_pubkey = cJSON_GetStringValue(sender_pubkey_obj);
@@ -1597,11 +1573,6 @@ int process_nip17_admin_command(cJSON* dm_event, char* error_message, size_t err
const char* admin_pubkey = get_admin_pubkey_cached();
int is_admin = admin_pubkey && strlen(admin_pubkey) > 0 && strcmp(sender_pubkey, admin_pubkey) == 0;
log_info("NIP-17: Processing admin command from DM content");
char log_msg[256];
snprintf(log_msg, sizeof(log_msg), "NIP-17: Received DM content: '%.50s'%s", dm_content, strlen(dm_content) > 50 ? "..." : "");
log_info(log_msg);
// Parse DM content as JSON array of commands
cJSON* command_array = cJSON_Parse(dm_content);
if (!command_array || !cJSON_IsArray(command_array)) {
@@ -1623,9 +1594,6 @@ int process_nip17_admin_command(cJSON* dm_event, char* error_message, size_t err
// Check for stats commands
if (strstr(content_lower, "stats") != NULL || strstr(content_lower, "statistics") != NULL) {
log_info("NIP-17: Recognized plain text 'stats' command from admin");
log_info("NIP-17: Action: Generate and send relay statistics");
char* stats_text = generate_stats_text();
if (!stats_text) {
return -1;
@@ -1639,15 +1607,11 @@ int process_nip17_admin_command(cJSON* dm_event, char* error_message, size_t err
log_error(error_msg);
return -1;
}
log_success("NIP-17: Stats command processed successfully, response sent");
return 0;
}
// Check for config commands
else if (strstr(content_lower, "config") != NULL || strstr(content_lower, "configuration") != NULL) {
log_info("NIP-17: Recognized plain text 'config' command from admin");
log_info("NIP-17: Action: Generate and send relay configuration");
char* config_text = generate_config_text();
if (!config_text) {
return -1;
@@ -1661,8 +1625,7 @@ int process_nip17_admin_command(cJSON* dm_event, char* error_message, size_t err
log_error(error_msg);
return -1;
}
log_success("NIP-17: Config command processed successfully, response sent");
return 0;
}
else {
@@ -1670,7 +1633,7 @@ int process_nip17_admin_command(cJSON* dm_event, char* error_message, size_t err
int confirmation_result = handle_config_confirmation(sender_pubkey, dm_content);
if (confirmation_result != 0) {
if (confirmation_result > 0) {
log_success("NIP-17: Configuration confirmation processed successfully");
// Configuration confirmation processed successfully
} else if (confirmation_result == -2) {
// No pending changes
char no_pending_msg[256];
@@ -1691,7 +1654,6 @@ int process_nip17_admin_command(cJSON* dm_event, char* error_message, size_t err
int config_result = process_config_change_request(sender_pubkey, dm_content);
if (config_result != 0) {
if (config_result > 0) {
log_success("NIP-17: Configuration change request processed successfully");
return 1; // Return positive value to indicate response was handled
} else {
log_error("NIP-17: Configuration change request failed");
@@ -1699,12 +1661,10 @@ int process_nip17_admin_command(cJSON* dm_event, char* error_message, size_t err
}
}
log_info("NIP-17: Plain text content from admin not recognized as command, treating as user DM");
return 0; // Admin sent unrecognized plain text, treat as user DM
}
} else {
// Not admin, treat as user DM
log_info("NIP-17: Content is not JSON array and sender is not admin, treating as user DM");
return 0;
}
}
@@ -1713,8 +1673,6 @@ int process_nip17_admin_command(cJSON* dm_event, char* error_message, size_t err
if (cJSON_GetArraySize(command_array) > 0) {
cJSON* first_item = cJSON_GetArrayItem(command_array, 0);
if (cJSON_IsString(first_item) && strcmp(cJSON_GetStringValue(first_item), "stats") == 0) {
log_info("NIP-17: Processing 'stats' command directly");
// Get sender pubkey for response
cJSON* sender_pubkey_obj = cJSON_GetObjectItem(dm_event, "pubkey");
if (!sender_pubkey_obj || !cJSON_IsString(sender_pubkey_obj)) {
@@ -1742,8 +1700,7 @@ int process_nip17_admin_command(cJSON* dm_event, char* error_message, size_t err
strncpy(error_message, error_msg, error_size - 1);
return -1;
}
log_success("NIP-17: Stats command processed successfully");
return 0;
}
}

View File

@@ -219,13 +219,11 @@ void update_subscription_manager_config(void) {
"Subscription limits: max_per_client=%d, max_total=%d",
g_subscription_manager.max_subscriptions_per_client,
g_subscription_manager.max_total_subscriptions);
log_info(config_msg);
}
// Signal handler for graceful shutdown
void signal_handler(int sig) {
if (sig == SIGINT || sig == SIGTERM) {
log_info("Received shutdown signal");
g_server_running = 0;
}
}
@@ -287,10 +285,6 @@ int init_database(const char* database_path_override) {
return -1;
}
char success_msg[256];
snprintf(success_msg, sizeof(success_msg), "Database connection established: %s", db_path);
log_success(success_msg);
// Check if database is already initialized by looking for the events table
const char* check_sql = "SELECT name FROM sqlite_master WHERE type='table' AND name='events'";
sqlite3_stmt* check_stmt;
@@ -367,7 +361,6 @@ int init_database(const char* database_path_override) {
if (error_msg) sqlite3_free(error_msg);
return -1;
}
log_success("Created auth_rules table");
// Add indexes for auth_rules table
const char* create_auth_rules_indexes_sql =
@@ -385,7 +378,6 @@ int init_database(const char* database_path_override) {
if (index_error_msg) sqlite3_free(index_error_msg);
return -1;
}
log_success("Created auth_rules indexes");
} else {
// auth_rules table already exists, skipping creation
}
@@ -406,7 +398,6 @@ int init_database(const char* database_path_override) {
return -1;
}
log_success("Database migration to v6 completed successfully");
}
} else {
// Initialize database schema using embedded SQL
@@ -425,7 +416,6 @@ int init_database(const char* database_path_override) {
return -1;
}
log_success("Database schema initialized successfully");
}
} else {
log_error("Failed to check existing database schema");
@@ -440,7 +430,6 @@ void close_database() {
if (g_db) {
sqlite3_close(g_db);
g_db = NULL;
log_info("Database connection closed");
}
}
@@ -671,7 +660,6 @@ int store_event(cJSON* event) {
}
free(tags_json);
log_success("Event stored in database");
return 0;
}
@@ -1159,7 +1147,6 @@ int is_authorized_admin_event(cJSON* event, char* error_buffer, size_t error_buf
cJSON *tags = cJSON_GetObjectItem(event, "tags");
if (!tags || !cJSON_IsArray(tags)) {
// No tags array - treat as regular event for different relay
log_info("Admin event has no tags array - treating as event for different relay");
snprintf(error_buffer, error_buffer_size, "Admin event not targeting this relay (no tags)");
return -1;
}
@@ -1226,7 +1213,6 @@ int is_authorized_admin_event(cJSON* event, char* error_buffer, size_t error_buf
}
// All checks passed - authorized admin event
log_info("Admin event authorization successful");
return 0;
}
@@ -1323,7 +1309,6 @@ 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-pubkey") == 0) {
// Admin public key override option
if (i + 1 >= argc) {
@@ -1354,7 +1339,6 @@ int main(int argc, char* argv[]) {
cli_options.admin_pubkey_override[sizeof(cli_options.admin_pubkey_override) - 1] = '\0';
i++; // Skip the key argument
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) {
@@ -1385,11 +1369,9 @@ int main(int argc, char* argv[]) {
cli_options.relay_privkey_override[sizeof(cli_options.relay_privkey_override) - 1] = '\0';
i++; // Skip the key argument
log_info("Relay private key override specified");
} else if (strcmp(argv[i], "--strict-port") == 0) {
// Strict port mode option
cli_options.strict_port = 1;
log_info("Strict port mode enabled - will fail if exact port is unavailable");
} else {
log_error("Unknown argument. Use --help for usage information.");
print_usage(argv[0]);
@@ -1412,7 +1394,6 @@ int main(int argc, char* argv[]) {
// Check if this is first-time startup or existing relay
if (is_first_time_startup()) {
log_info("First-time startup detected");
// Initialize event-based configuration system
if (init_configuration_system(NULL, NULL) != 0) {
@@ -1446,7 +1427,6 @@ int main(int argc, char* argv[]) {
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();
@@ -1477,7 +1457,6 @@ int main(int argc, char* argv[]) {
close_database();
return 1;
}
log_info("Applied port override from command line");
printf(" Port: %d (overriding default)\n", cli_options.port_override);
}
@@ -1490,18 +1469,15 @@ int main(int argc, char* argv[]) {
return 1;
}
log_success("Configuration populated directly in config table after database initialization");
// Now store the pubkeys in config table since database is available
const char* admin_pubkey = get_admin_pubkey_cached();
const char* relay_pubkey_from_cache = get_relay_pubkey_cached();
if (admin_pubkey && strlen(admin_pubkey) == 64) {
set_config_value_in_table("admin_pubkey", admin_pubkey, "string", "Administrator public key", "authentication", 0);
log_success("Admin pubkey stored in config table for first-time startup");
}
if (relay_pubkey_from_cache && strlen(relay_pubkey_from_cache) == 64) {
set_config_value_in_table("relay_pubkey", relay_pubkey_from_cache, "string", "Relay public key", "relay", 0);
log_success("Relay pubkey stored in config table for first-time startup");
}
} else {
// Find existing database file
@@ -1569,7 +1545,6 @@ int main(int argc, char* argv[]) {
if (apply_configuration_from_event(config_event) != 0) {
log_warning("Failed to apply configuration from database");
} else {
log_success("Configuration loaded from database");
// Extract admin pubkey from the config event and store in config table for unified cache access
cJSON* pubkey_obj = cJSON_GetObjectItem(config_event, "pubkey");
@@ -1600,7 +1575,6 @@ int main(int argc, char* argv[]) {
close_database();
return 1;
}
log_info("Applied port override from command line for existing relay");
printf(" Port: %d (overriding configured port)\n", cli_options.port_override);
}
@@ -1631,7 +1605,6 @@ int main(int argc, char* argv[]) {
close_database();
return 1;
}
log_success("Unified request validator initialized");
// Initialize NIP-11 relay information
init_relay_info();
@@ -1645,7 +1618,6 @@ int main(int argc, char* argv[]) {
// Update subscription manager configuration
update_subscription_manager_config();
log_info("Starting relay server...");
// Start WebSocket Nostr relay server (port from configuration)
int result = start_websocket_relay(-1, cli_options.strict_port); // Let config system determine port, pass strict_port flag
@@ -1658,7 +1630,6 @@ int main(int argc, char* argv[]) {
close_database();
if (result == 0) {
log_success("Server shutdown complete");
} else {
log_error("Server shutdown with errors");
}

View File

@@ -224,8 +224,6 @@ void init_relay_info() {
g_unified_cache.relay_info.fees = cJSON_CreateObject();
pthread_mutex_unlock(&g_unified_cache.cache_lock);
log_success("Relay information initialized with default values");
}
// Clean up relay information JSON objects

View File

@@ -148,11 +148,6 @@ void handle_nip42_auth_signed_event(struct lws* wsi, struct per_session_data* ps
pss->auth_challenge_sent = 0;
pthread_mutex_unlock(&pss->session_lock);
char success_msg[256];
snprintf(success_msg, sizeof(success_msg),
"NIP-42 authentication successful for pubkey: %.16s...", authenticated_pubkey);
log_success(success_msg);
send_notice_message(wsi, "NIP-42 authentication successful");
} else {
// Authentication failed

View File

@@ -226,7 +226,6 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
free(session_data);
lws_set_wsi_user(wsi, NULL);
log_success("NIP-11 relay information served successfully");
return 0; // Close connection after successful transmission
}
} else if (type == 1) {
@@ -238,7 +237,6 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
break;
case LWS_CALLBACK_ESTABLISHED:
log_info("WebSocket connection established");
memset(pss, 0, sizeof(*pss));
pthread_mutex_init(&pss->session_lock, NULL);
@@ -451,10 +449,6 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
strncpy(error_message, "error: validation failed", sizeof(error_message) - 1);
break;
}
char debug_error_msg[256];
snprintf(debug_error_msg, sizeof(debug_error_msg),
"DEBUG VALIDATION ERROR: %s", error_message);
log_warning(debug_error_msg);
}
// Cleanup event JSON string
@@ -511,63 +505,34 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
cJSON* kind_obj = cJSON_GetObjectItem(event, "kind");
if (kind_obj && cJSON_IsNumber(kind_obj)) {
int event_kind = (int)cJSON_GetNumberValue(kind_obj);
log_info("DEBUG ADMIN: Checking if admin event processing is needed");
// Log reception of Kind 23456 events
if (event_kind == 23456) {
char* event_json_debug = cJSON_Print(event);
char debug_received_msg[1024];
snprintf(debug_received_msg, sizeof(debug_received_msg),
"RECEIVED Kind %d event: %s", event_kind,
event_json_debug ? event_json_debug : "Failed to serialize");
log_info(debug_received_msg);
if (event_json_debug) {
free(event_json_debug);
}
}
if (event_kind == 23456) {
// Enhanced admin event security - check authorization first
log_info("DEBUG ADMIN: Admin event detected, checking authorization");
char auth_error[512] = {0};
int auth_result = is_authorized_admin_event(event, auth_error, sizeof(auth_error));
if (auth_result != 0) {
// Authorization failed - log and reject
log_warning("DEBUG ADMIN: Admin event authorization failed");
log_warning("Admin event authorization failed");
result = -1;
size_t error_len = strlen(auth_error);
size_t copy_len = (error_len < sizeof(error_message) - 1) ? error_len : sizeof(error_message) - 1;
memcpy(error_message, auth_error, copy_len);
error_message[copy_len] = '\0';
char debug_auth_error_msg[600];
snprintf(debug_auth_error_msg, sizeof(debug_auth_error_msg),
"DEBUG ADMIN AUTH ERROR: %.400s", auth_error);
log_warning(debug_auth_error_msg);
} else {
// Authorization successful - process through admin API
log_info("DEBUG ADMIN: Admin event authorized, processing through admin API");
char admin_error[512] = {0};
int admin_result = process_admin_event_in_config(event, admin_error, sizeof(admin_error), wsi);
char debug_admin_msg[256];
snprintf(debug_admin_msg, sizeof(debug_admin_msg),
"DEBUG ADMIN: process_admin_event_in_config returned %d", admin_result);
log_info(debug_admin_msg);
// Log results for Kind 23456 events
if (event_kind == 23456) {
if (admin_result == 0) {
char success_result_msg[256];
snprintf(success_result_msg, sizeof(success_result_msg),
"SUCCESS: Kind %d event processed successfully", event_kind);
log_success(success_result_msg);
} else {
if (admin_result != 0) {
char error_result_msg[512];
snprintf(error_result_msg, sizeof(error_result_msg),
"ERROR: Kind %d event processing failed: %s", event_kind, admin_error);
@@ -576,25 +541,18 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
}
if (admin_result != 0) {
log_error("DEBUG ADMIN: Failed to process admin event through admin API");
log_error("Failed to process admin event");
result = -1;
size_t error_len = strlen(admin_error);
size_t copy_len = (error_len < sizeof(error_message) - 1) ? error_len : sizeof(error_message) - 1;
memcpy(error_message, admin_error, copy_len);
error_message[copy_len] = '\0';
char debug_admin_error_msg[600];
snprintf(debug_admin_error_msg, sizeof(debug_admin_error_msg),
"DEBUG ADMIN ERROR: %.400s", admin_error);
log_error(debug_admin_error_msg);
} else {
log_success("DEBUG ADMIN: Admin event processed successfully through admin API");
// Admin events are processed by the admin API, not broadcast to subscriptions
}
}
} else if (event_kind == 1059) {
// Check for NIP-17 gift wrap admin messages
log_info("DEBUG NIP17: Detected kind 1059 gift wrap event");
char nip17_error[512] = {0};
cJSON* response_event = process_nip17_admin_message(event, nip17_error, sizeof(nip17_error), wsi);
@@ -603,120 +561,81 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
// Check if this is an error or if the command was already handled
if (strlen(nip17_error) > 0) {
// There was an actual error
log_error("DEBUG NIP17: NIP-17 admin message processing failed");
log_error("NIP-17 admin message processing failed");
result = -1;
size_t error_len = strlen(nip17_error);
size_t copy_len = (error_len < sizeof(error_message) - 1) ? error_len : sizeof(error_message) - 1;
memcpy(error_message, nip17_error, copy_len);
error_message[copy_len] = '\0';
char debug_nip17_error_msg[600];
snprintf(debug_nip17_error_msg, sizeof(debug_nip17_error_msg),
"DEBUG NIP17 ERROR: %.400s", nip17_error);
log_error(debug_nip17_error_msg);
} else {
// No error message means the command was already handled (plain text commands)
log_success("DEBUG NIP17: NIP-17 admin message processed successfully (already handled)");
// Store the original gift wrap event in database
if (store_event(event) != 0) {
log_error("DEBUG NIP17: Failed to store gift wrap event in database");
log_error("Failed to store gift wrap event in database");
result = -1;
strncpy(error_message, "error: failed to store gift wrap event", sizeof(error_message) - 1);
} else {
log_info("DEBUG NIP17: Gift wrap event stored successfully in database");
}
}
} else {
log_success("DEBUG NIP17: NIP-17 admin message processed successfully");
// Store the original gift wrap event in database (unlike kind 23456)
if (store_event(event) != 0) {
log_error("DEBUG NIP17: Failed to store gift wrap event in database");
log_error("Failed to store gift wrap event in database");
result = -1;
strncpy(error_message, "error: failed to store gift wrap event", sizeof(error_message) - 1);
cJSON_Delete(response_event);
} else {
log_info("DEBUG NIP17: Gift wrap event stored successfully in database");
// Debug: Print response event before broadcasting
char* debug_before_broadcast = cJSON_Print(response_event);
if (debug_before_broadcast) {
log_info("DEBUG EVENT: Before broadcasting response event");
printf(" Response Event: %s\n", debug_before_broadcast);
free(debug_before_broadcast);
}
// Broadcast RESPONSE event to matching persistent subscriptions
int broadcast_count = broadcast_event_to_subscriptions(response_event);
char debug_broadcast_msg[128];
snprintf(debug_broadcast_msg, sizeof(debug_broadcast_msg),
"DEBUG NIP17 BROADCAST: Response event broadcast to %d subscriptions", broadcast_count);
log_info(debug_broadcast_msg);
broadcast_event_to_subscriptions(response_event);
// Clean up response event
cJSON_Delete(response_event);
}
}
} else if (event_kind == 14) {
// Check for DM stats commands addressed to relay
log_info("DEBUG DM: Detected kind 14 DM event");
char dm_error[512] = {0};
int dm_result = process_dm_stats_command(event, dm_error, sizeof(dm_error), wsi);
if (dm_result != 0) {
log_error("DEBUG DM: DM stats command processing failed");
log_error("DM stats command processing failed");
result = -1;
size_t error_len = strlen(dm_error);
size_t copy_len = (error_len < sizeof(error_message) - 1) ? error_len : sizeof(error_message) - 1;
memcpy(error_message, dm_error, copy_len);
error_message[copy_len] = '\0';
char debug_dm_error_msg[600];
snprintf(debug_dm_error_msg, sizeof(debug_dm_error_msg),
"DEBUG DM ERROR: %.400s", dm_error);
log_error(debug_dm_error_msg);
} else {
log_success("DEBUG DM: DM stats command processed successfully");
// Store the DM event in database
if (store_event(event) != 0) {
log_error("DEBUG DM: Failed to store DM event in database");
log_error("Failed to store DM event in database");
result = -1;
strncpy(error_message, "error: failed to store DM event", sizeof(error_message) - 1);
} else {
log_info("DEBUG DM: DM event stored successfully in database");
// Broadcast DM event to matching persistent subscriptions
int broadcast_count = broadcast_event_to_subscriptions(event);
char debug_broadcast_msg[128];
snprintf(debug_broadcast_msg, sizeof(debug_broadcast_msg),
"DEBUG DM BROADCAST: DM event broadcast to %d subscriptions", broadcast_count);
log_info(debug_broadcast_msg);
broadcast_event_to_subscriptions(event);
}
}
} else {
// Regular event - store in database and broadcast
log_info("DEBUG STORAGE: Regular event - storing in database");
if (store_event(event) != 0) {
log_error("DEBUG STORAGE: Failed to store event in database");
log_error("Failed to store event in database");
result = -1;
strncpy(error_message, "error: failed to store event", sizeof(error_message) - 1);
} else {
log_info("DEBUG STORAGE: Event stored successfully in database");
// Broadcast event to matching persistent subscriptions
int broadcast_count = broadcast_event_to_subscriptions(event);
char debug_broadcast_msg[128];
snprintf(debug_broadcast_msg, sizeof(debug_broadcast_msg),
"DEBUG BROADCAST: Event broadcast to %d subscriptions", broadcast_count);
log_info(debug_broadcast_msg);
broadcast_event_to_subscriptions(event);
}
}
} else {
// Event without valid kind - try normal storage
log_warning("DEBUG STORAGE: Event without valid kind - trying normal storage");
log_warning("Event without valid kind - trying normal storage");
if (store_event(event) != 0) {
log_error("DEBUG STORAGE: Failed to store event without kind in database");
log_error("Failed to store event without kind in database");
result = -1;
strncpy(error_message, "error: failed to store event", sizeof(error_message) - 1);
} else {
log_info("DEBUG STORAGE: Event without kind stored successfully in database");
broadcast_event_to_subscriptions(event);
}
}
@@ -731,25 +650,13 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
cJSON_AddItemToArray(response, cJSON_CreateBool(result == 0));
cJSON_AddItemToArray(response, cJSON_CreateString(strlen(error_message) > 0 ? error_message : ""));
// TODO: REPLACE - Remove wasteful cJSON_Print conversion
char *response_str = cJSON_Print(response);
if (response_str) {
char debug_response_msg[512];
snprintf(debug_response_msg, sizeof(debug_response_msg),
"DEBUG RESPONSE: Sending OK response: %s", response_str);
log_info(debug_response_msg);
size_t response_len = strlen(response_str);
unsigned char *buf = malloc(LWS_PRE + response_len);
if (buf) {
memcpy(buf + LWS_PRE, response_str, response_len);
int write_result = lws_write(wsi, buf + LWS_PRE, response_len, LWS_WRITE_TEXT);
char debug_write_msg[128];
snprintf(debug_write_msg, sizeof(debug_write_msg),
"DEBUG RESPONSE: lws_write returned %d", write_result);
log_info(debug_write_msg);
lws_write(wsi, buf + LWS_PRE, response_len, LWS_WRITE_TEXT);
free(buf);
}
free(response_str);
@@ -872,9 +779,7 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
pthread_mutex_unlock(&pss->session_lock);
}
char debug_msg[256];
snprintf(debug_msg, sizeof(debug_msg), "Closed subscription: %s", subscription_id);
log_info(debug_msg);
// Subscription closed
}
} else if (strcmp(msg_type, "AUTH") == 0) {
// Handle NIP-42 AUTH message
@@ -912,7 +817,6 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
break;
case LWS_CALLBACK_CLOSED:
log_info("WebSocket connection closed");
// Clean up session subscriptions
if (pss) {
@@ -992,7 +896,7 @@ int check_port_available(int port) {
int start_websocket_relay(int port_override, int strict_port) {
struct lws_context_creation_info info;
log_info("Starting libwebsockets-based Nostr relay server...");
// Starting libwebsockets-based Nostr relay server
memset(&info, 0, sizeof(info));
// Use port override if provided, otherwise use configuration
@@ -1020,9 +924,7 @@ int start_websocket_relay(int port_override, int strict_port) {
// Find an available port with pre-checking (or fail immediately in strict mode)
while (port_attempts < (strict_port ? 1 : max_port_attempts)) {
char attempt_msg[256];
snprintf(attempt_msg, sizeof(attempt_msg), "Checking port availability: %d", actual_port);
log_info(attempt_msg);
// Checking port availability
// Pre-check if port is available
if (!check_port_available(actual_port)) {
@@ -1053,9 +955,7 @@ int start_websocket_relay(int port_override, int strict_port) {
// Port appears available, try creating libwebsockets context
info.port = actual_port;
char binding_msg[256];
snprintf(binding_msg, sizeof(binding_msg), "Attempting to bind libwebsockets to port %d", actual_port);
log_info(binding_msg);
// Attempting to bind libwebsockets
ws_context = lws_create_context(&info);
if (ws_context) {
@@ -1106,7 +1006,6 @@ int start_websocket_relay(int port_override, int strict_port) {
} else {
snprintf(startup_msg, sizeof(startup_msg), "WebSocket relay started on ws://127.0.0.1:%d", actual_port);
}
log_success(startup_msg);
// Main event loop with proper signal handling
while (g_server_running && !g_shutdown_flag) {
@@ -1118,11 +1017,8 @@ int start_websocket_relay(int port_override, int strict_port) {
}
}
log_info("Shutting down WebSocket server...");
lws_context_destroy(ws_context);
ws_context = NULL;
log_success("WebSocket relay shut down cleanly");
return 0;
}
@@ -1236,7 +1132,7 @@ int process_dm_stats_command(cJSON* dm_event, char* error_message, size_t error_
return 0;
}
log_info("Processing DM stats command from admin");
// Processing DM stats command from admin
// Generate stats JSON
char* stats_json = generate_stats_json();
@@ -1287,15 +1183,10 @@ int process_dm_stats_command(cJSON* dm_event, char* error_message, size_t error_
}
// Broadcast to subscriptions
int broadcast_count = broadcast_event_to_subscriptions(dm_response);
char broadcast_msg[128];
snprintf(broadcast_msg, sizeof(broadcast_msg),
"DM stats response broadcast to %d subscriptions", broadcast_count);
log_info(broadcast_msg);
broadcast_event_to_subscriptions(dm_response);
cJSON_Delete(dm_response);
log_success("DM stats command processed successfully");
return 0;
}
@@ -1303,7 +1194,6 @@ int process_dm_stats_command(cJSON* dm_event, char* error_message, size_t error_
// Handle NIP-45 COUNT message
int handle_count_message(const char* sub_id, cJSON* filters, struct lws *wsi, struct per_session_data *pss) {
(void)pss; // Suppress unused parameter warning
log_info("Handling COUNT message for subscription");
if (!cJSON_IsArray(filters)) {
log_error("COUNT filters is not an array");
@@ -1493,10 +1383,7 @@ int handle_count_message(const char* sub_id, cJSON* filters, struct lws *wsi, st
remaining = sizeof(sql) - strlen(sql);
}
// Debug: Log the SQL query being executed
char debug_msg[1280];
snprintf(debug_msg, sizeof(debug_msg), "Executing COUNT SQL: %s", sql);
log_info(debug_msg);
// Execute count query
// Execute count query
sqlite3_stmt* stmt;
@@ -1513,17 +1400,13 @@ int handle_count_message(const char* sub_id, cJSON* filters, struct lws *wsi, st
filter_count = sqlite3_column_int(stmt, 0);
}
char count_debug[128];
snprintf(count_debug, sizeof(count_debug), "Filter %d returned count: %d", i + 1, filter_count);
log_info(count_debug);
// Filter count calculated
sqlite3_finalize(stmt);
total_count += filter_count;
}
char total_debug[128];
snprintf(total_debug, sizeof(total_debug), "Total COUNT result: %d", total_count);
log_info(total_debug);
// Total count calculated
// Send COUNT response - NIP-45 format: ["COUNT", <subscription_id>, {"count": <count>}]
cJSON* count_response = cJSON_CreateArray();