v0.7.4 - Remove excessive debug logging from entire codebase - preserve user-facing error logging

This commit is contained in:
Your Name
2025-10-10 10:21:30 -04:00
parent b89c011ad5
commit c90676d2b2
15 changed files with 96 additions and 762 deletions

View File

@@ -23,8 +23,6 @@ int store_event(cJSON* event);
// Handle HTTP request for embedded files (assumes GET)
int handle_embedded_file_request(struct lws* wsi, const char* requested_uri) {
log_info("Handling embedded file request");
const char* file_path;
// Handle /api requests
@@ -124,7 +122,6 @@ int handle_embedded_file_request(struct lws* wsi, const char* requested_uri) {
// Request callback for body transmission
lws_callback_on_writable(wsi);
log_success("Embedded file headers sent, body transmission scheduled");
return 0;
}
@@ -165,6 +162,5 @@ int handle_embedded_file_writeable(struct lws* wsi) {
free(session_data);
lws_set_wsi_user(wsi, NULL);
log_success("Embedded file served successfully");
return 0;
}

View File

@@ -226,24 +226,18 @@ static int refresh_unified_cache_from_table(void) {
log_info("Refreshing unified configuration cache from database");
// Lock the cache for update (don't memset entire cache to avoid wiping relay_info)
log_info("DEBUG: Acquiring cache lock for refresh");
pthread_mutex_lock(&g_unified_cache.cache_lock);
log_info("DEBUG: Cache lock acquired");
// Load critical config values from table
log_info("DEBUG: Loading admin_pubkey from table");
const char* admin_pubkey = get_config_value_from_table("admin_pubkey");
if (admin_pubkey) {
log_info("DEBUG: Setting admin_pubkey in cache");
strncpy(g_unified_cache.admin_pubkey, admin_pubkey, sizeof(g_unified_cache.admin_pubkey) - 1);
g_unified_cache.admin_pubkey[sizeof(g_unified_cache.admin_pubkey) - 1] = '\0';
free((char*)admin_pubkey);
}
log_info("DEBUG: Loading relay_pubkey from table");
const char* relay_pubkey = get_config_value_from_table("relay_pubkey");
if (relay_pubkey) {
log_info("DEBUG: Setting relay_pubkey in cache");
strncpy(g_unified_cache.relay_pubkey, relay_pubkey, sizeof(g_unified_cache.relay_pubkey) - 1);
g_unified_cache.relay_pubkey[sizeof(g_unified_cache.relay_pubkey) - 1] = '\0';
free((char*)relay_pubkey);
@@ -361,12 +355,10 @@ static int refresh_unified_cache_from_table(void) {
}
// Set cache expiration
log_info("DEBUG: Setting cache expiration and validity");
int cache_timeout = get_cache_timeout();
g_unified_cache.cache_expires = time(NULL) + cache_timeout;
g_unified_cache.cache_valid = 1;
log_info("DEBUG: Releasing cache lock");
pthread_mutex_unlock(&g_unified_cache.cache_lock);
log_info("Unified configuration cache refreshed from database");
@@ -2262,60 +2254,50 @@ extern int is_authorized_admin_event(cJSON* event);
// Process admin events (updated for Kind 23456)
int process_admin_event_in_config(cJSON* event, char* error_message, size_t error_size, struct lws* wsi) {
log_info("DEBUG: Entering process_admin_event_in_config()");
cJSON* kind_obj = cJSON_GetObjectItem(event, "kind");
if (!kind_obj || !cJSON_IsNumber(kind_obj)) {
log_error("DEBUG: Missing or invalid kind in admin event");
log_error("Missing or invalid kind in admin event");
snprintf(error_message, error_size, "invalid: missing or invalid kind");
return -1;
}
int kind = (int)cJSON_GetNumberValue(kind_obj);
log_info("DEBUG: Processing admin event");
printf(" Event kind: %d\n", kind);
// Extract and log event details for debugging
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";
log_info("DEBUG: Event details");
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));
}
// DEFENSE-IN-DEPTH: Use comprehensive admin authorization validation
log_info("DEBUG: Checking admin authorization");
if (!is_authorized_admin_event(event)) {
// Log the unauthorized attempt for security monitoring
char log_msg[256];
snprintf(log_msg, sizeof(log_msg),
"DEBUG: Unauthorized admin event attempt in config processing - pubkey: %.16s...",
"Unauthorized admin event attempt in config processing - pubkey: %.16s...",
event_pubkey ? event_pubkey : "null");
log_warning(log_msg);
snprintf(error_message, error_size, "auth-required: not authorized admin");
return -1;
}
// Log successful admin authorization for audit trail
log_info("DEBUG: Admin event authorized successfully in config processing");
// Route to appropriate handler based on kind
log_info("DEBUG: Routing to kind-specific handler");
switch (kind) {
case 23456: // New ephemeral auth rules management
log_info("DEBUG: Routing to process_admin_auth_event (kind 23456)");
return process_admin_auth_event(event, error_message, error_size, wsi);
default:
log_error("DEBUG: Unsupported admin event kind");
log_error("Unsupported admin event kind");
printf(" Unsupported kind: %d\n", kind);
snprintf(error_message, error_size, "invalid: unsupported admin event kind %d", kind);
return -1;
@@ -2422,21 +2404,17 @@ int process_admin_config_event(cJSON* event, char* error_message, size_t error_s
// Handle Kind 23456 auth rules management
int process_admin_auth_event(cJSON* event, char* error_message, size_t error_size, struct lws* wsi) {
log_info("DEBUG: Entering process_admin_auth_event()");
cJSON* kind_obj = cJSON_GetObjectItem(event, "kind");
int kind = kind_obj ? (int)cJSON_GetNumberValue(kind_obj) : 0;
log_info("DEBUG: Processing admin auth rule event through unified handler");
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");
const char* event_content = content_obj ? cJSON_GetStringValue(content_obj) : "unknown";
log_info("DEBUG: Auth event details");
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)) {
@@ -2445,12 +2423,10 @@ int process_admin_auth_event(cJSON* event, char* error_message, size_t error_siz
// Route all Kind 23456 events through the unified handler
if (kind == 23456) {
log_info("DEBUG: Routing Kind 23456 to unified handler");
return handle_kind_23456_unified(event, error_message, error_size, wsi);
}
log_error("DEBUG: Unsupported auth event kind in process_admin_auth_event");
printf(" Unsupported kind: %d\n", kind);
snprintf(error_message, error_size, "invalid: unsupported auth event kind %d", kind);
return -1;
@@ -2857,118 +2833,86 @@ int handle_kind_23456_unified(cJSON* event, char* error_message, size_t error_si
// Suppress unused parameter warning
(void)wsi;
if (!event) {
log_error("DEBUG: Null event passed to handle_kind_23456_unified");
log_error("invalid: null event");
snprintf(error_message, error_size, "invalid: null event");
return -1;
}
log_info("DEBUG: Processing Kind 23456 event through unified handler");
// Check if content is encrypted (NIP-44)
cJSON* content_obj = cJSON_GetObjectItem(event, "content");
if (!content_obj || !cJSON_IsString(content_obj)) {
log_error("DEBUG: Missing or invalid content in Kind 23456 event");
log_error("invalid: missing or invalid content");
snprintf(error_message, error_size, "invalid: missing or invalid content");
return -1;
}
const char* content = cJSON_GetStringValue(content_obj);
log_info("DEBUG: Event content analysis");
printf(" Content length: %zu\n", content ? strlen(content) : 0);
printf(" Content preview: %.50s%s\n", content ? content : "null",
(content && strlen(content) > 50) ? "..." : "");
cJSON* decrypted_content = NULL;
// Check if content looks like NIP-44 encrypted content (base64 string, not JSON)
if (content && strlen(content) > 10 && content[0] != '[' && content[0] != '{') {
log_info("DEBUG: Detected NIP-44 encrypted content, attempting decryption");
printf(" Content appears to be base64 encrypted\n");
// Get relay private key for decryption
log_info("DEBUG: Retrieving relay private key for decryption");
char* relay_privkey = get_relay_private_key();
if (!relay_privkey) {
log_error("DEBUG: Relay private key not available for decryption");
log_error("error: relay private key not available for decryption");
snprintf(error_message, error_size, "error: relay private key not available for decryption");
return -1;
}
log_info("DEBUG: Relay private key retrieved successfully");
printf(" Relay privkey length: %zu\n", strlen(relay_privkey));
// Get sender's pubkey from the event for NIP-44 decryption
cJSON* pubkey_obj = cJSON_GetObjectItem(event, "pubkey");
if (!pubkey_obj || !cJSON_IsString(pubkey_obj)) {
log_error("DEBUG: Missing sender pubkey in event");
log_error("invalid: missing sender pubkey in event");
free(relay_privkey);
snprintf(error_message, error_size, "invalid: missing sender pubkey in event");
return -1;
}
const char* sender_pubkey = cJSON_GetStringValue(pubkey_obj);
if (!sender_pubkey || strlen(sender_pubkey) != 64) {
log_error("DEBUG: Invalid sender pubkey format");
printf(" Sender pubkey: %s\n", sender_pubkey ? sender_pubkey : "null");
printf(" Sender pubkey length: %zu\n", sender_pubkey ? strlen(sender_pubkey) : 0);
log_error("invalid: invalid sender pubkey format");
free(relay_privkey);
snprintf(error_message, error_size, "invalid: invalid sender pubkey format");
return -1;
}
log_info("DEBUG: Sender pubkey validated");
printf(" Sender pubkey: %.16s...\n", sender_pubkey);
// Convert relay private key from hex to bytes
log_info("DEBUG: Converting relay private key from hex to bytes");
unsigned char relay_privkey_bytes[32];
if (nostr_hex_to_bytes(relay_privkey, relay_privkey_bytes, 32) != NOSTR_SUCCESS) {
log_error("DEBUG: Failed to convert relay private key from hex");
log_error("error: failed to convert relay private key");
free(relay_privkey);
snprintf(error_message, error_size, "error: failed to convert relay private key");
return -1;
}
log_info("DEBUG: Relay private key converted successfully");
// Convert sender public key from hex to bytes
log_info("DEBUG: Converting sender public key from hex to bytes");
unsigned char sender_pubkey_bytes[32];
if (nostr_hex_to_bytes(sender_pubkey, sender_pubkey_bytes, 32) != NOSTR_SUCCESS) {
log_error("DEBUG: Failed to convert sender public key from hex");
log_error("error: failed to convert sender public key");
free(relay_privkey);
snprintf(error_message, error_size, "error: failed to convert sender public key");
return -1;
}
log_info("DEBUG: Sender public key converted successfully");
// Perform NIP-44 decryption (relay as recipient, admin as sender)
log_info("DEBUG: Performing NIP-44 decryption");
printf(" Encrypted content length: %zu\n", strlen(content));
char decrypted_text[4096]; // Buffer for decrypted content
int decrypt_result = nostr_nip44_decrypt(relay_privkey_bytes, sender_pubkey_bytes, content, decrypted_text, sizeof(decrypted_text));
// Clean up private key immediately after use
memset(relay_privkey_bytes, 0, 32);
free(relay_privkey);
if (decrypt_result != NOSTR_SUCCESS) {
log_error("DEBUG: NIP-44 decryption failed");
printf(" Decryption result code: %d\n", decrypt_result);
log_error("error: NIP-44 decryption failed");
snprintf(error_message, error_size, "error: NIP-44 decryption failed");
return -1;
}
log_info("DEBUG: NIP-44 decryption successful");
printf(" Decrypted content: %s\n", decrypted_text);
printf(" Decrypted length: %zu\n", strlen(decrypted_text));
// Check if decrypted content is a direct command array (DM control system)
log_info("DEBUG: Checking if decrypted content is direct command array");
cJSON* potential_command_array = cJSON_Parse(decrypted_text);
if (potential_command_array && cJSON_IsArray(potential_command_array)) {
log_info("DEBUG: Detected direct command array - routing to DM admin system");
printf(" Direct command array detected, size: %d\n", cJSON_GetArraySize(potential_command_array));
// Route to DM admin system
int dm_result = process_dm_admin_command(potential_command_array, event, error_message, error_size, wsi);
cJSON_Delete(potential_command_array);
@@ -2977,74 +2921,51 @@ int handle_kind_23456_unified(cJSON* event, char* error_message, size_t error_si
}
// If not a direct command array, try parsing as inner event JSON (NIP-17)
log_info("DEBUG: Not a direct command array, parsing as inner event JSON");
cJSON* inner_event = potential_command_array; // Reuse the parsed JSON
if (!inner_event || !cJSON_IsObject(inner_event)) {
log_error("DEBUG: Decrypted content is not valid inner event JSON");
printf(" Decrypted content type: %s\n",
inner_event ? (cJSON_IsObject(inner_event) ? "object" : "other") : "null");
log_error("error: decrypted content is not valid inner event JSON");
cJSON_Delete(inner_event);
snprintf(error_message, error_size, "error: decrypted content is not valid inner event JSON");
return -1;
}
log_info("DEBUG: Inner event parsed successfully");
printf(" Inner event kind: %d\n", (int)cJSON_GetNumberValue(cJSON_GetObjectItem(inner_event, "kind")));
// Extract content from inner event
cJSON* inner_content_obj = cJSON_GetObjectItem(inner_event, "content");
if (!inner_content_obj || !cJSON_IsString(inner_content_obj)) {
log_error("DEBUG: Inner event missing content field");
log_error("error: inner event missing content field");
cJSON_Delete(inner_event);
snprintf(error_message, error_size, "error: inner event missing content field");
return -1;
}
const char* inner_content = cJSON_GetStringValue(inner_content_obj);
log_info("DEBUG: Extracted inner content");
printf(" Inner content: %s\n", inner_content);
// Parse inner content as JSON array (the command array)
log_info("DEBUG: Parsing inner content as command JSON array");
decrypted_content = cJSON_Parse(inner_content);
if (!decrypted_content || !cJSON_IsArray(decrypted_content)) {
log_error("DEBUG: Inner content is not valid JSON array");
printf(" Inner content type: %s\n",
decrypted_content ? (cJSON_IsArray(decrypted_content) ? "array" : "other") : "null");
log_error("error: inner content is not valid JSON array");
cJSON_Delete(inner_event);
snprintf(error_message, error_size, "error: inner content is not valid JSON array");
return -1;
}
log_info("DEBUG: Inner content parsed successfully as JSON array");
printf(" Array size: %d\n", cJSON_GetArraySize(decrypted_content));
// Clean up inner event
cJSON_Delete(inner_event);
// Replace event content with decrypted command array for processing
log_info("DEBUG: Replacing event content with decrypted marker");
cJSON_DeleteItemFromObject(event, "content");
cJSON_AddStringToObject(event, "content", "decrypted");
// Create synthetic tags from decrypted command array
log_info("DEBUG: Creating synthetic tags from decrypted command array");
printf(" Decrypted content array size: %d\n", cJSON_GetArraySize(decrypted_content));
// Create synthetic tags from decrypted command array
// Create new tags array with command tag first
cJSON* new_tags = cJSON_CreateArray();
// Add decrypted command as first tag
if (cJSON_GetArraySize(decrypted_content) > 0) {
log_info("DEBUG: Adding decrypted command as synthetic tag");
cJSON* first_item = cJSON_GetArrayItem(decrypted_content, 0);
if (cJSON_IsString(first_item)) {
const char* command_name = cJSON_GetStringValue(first_item);
log_info("DEBUG: Creating command tag");
printf(" Command: %s\n", command_name ? command_name : "null");
cJSON* command_tag = cJSON_CreateArray();
cJSON_AddItemToArray(command_tag, cJSON_Duplicate(first_item, 1));
@@ -3052,139 +2973,91 @@ int handle_kind_23456_unified(cJSON* event, char* error_message, size_t error_si
for (int i = 1; i < cJSON_GetArraySize(decrypted_content); i++) {
cJSON* item = cJSON_GetArrayItem(decrypted_content, i);
if (item) {
if (cJSON_IsString(item)) {
printf(" Arg %d: %s\n", i, cJSON_GetStringValue(item));
} else {
printf(" Arg %d: (non-string)\n", i);
}
cJSON_AddItemToArray(command_tag, cJSON_Duplicate(item, 1));
}
}
cJSON_AddItemToArray(new_tags, command_tag);
log_info("DEBUG: Synthetic command tag added to new tags array");
printf(" New tags after adding command: %d\n", cJSON_GetArraySize(new_tags));
} else {
log_error("DEBUG: First item in decrypted array is not a string");
log_error("error: first item in decrypted array is not a string");
}
} else {
log_error("DEBUG: Decrypted array is empty");
}
// Add existing tags
cJSON* existing_tags = cJSON_GetObjectItem(event, "tags");
if (existing_tags && cJSON_IsArray(existing_tags)) {
printf(" Existing tags count: %d\n", cJSON_GetArraySize(existing_tags));
cJSON* tag = NULL;
cJSON_ArrayForEach(tag, existing_tags) {
cJSON_AddItemToArray(new_tags, cJSON_Duplicate(tag, 1));
}
printf(" New tags after adding existing: %d\n", cJSON_GetArraySize(new_tags));
}
// Replace event tags with new tags
cJSON_ReplaceItemInObject(event, "tags", new_tags);
printf(" Final tag array size: %d\n", cJSON_GetArraySize(new_tags));
cJSON_Delete(decrypted_content);
} else {
log_info("DEBUG: Content does not appear to be NIP-44 encrypted");
printf(" Content starts with: %c\n", content ? content[0] : '?');
printf(" Content length: %zu\n", content ? strlen(content) : 0);
}
// Parse first tag to determine action type (now from decrypted content if applicable)
log_info("DEBUG: Parsing first tag to determine action type");
cJSON* tags_obj = cJSON_GetObjectItem(event, "tags");
if (tags_obj && cJSON_IsArray(tags_obj)) {
printf(" Tags array size: %d\n", cJSON_GetArraySize(tags_obj));
for (int i = 0; i < cJSON_GetArraySize(tags_obj); i++) {
cJSON* tag = cJSON_GetArrayItem(tags_obj, i);
if (tag && cJSON_IsArray(tag) && cJSON_GetArraySize(tag) > 0) {
cJSON* tag_name = cJSON_GetArrayItem(tag, 0);
if (tag_name && cJSON_IsString(tag_name)) {
printf(" Tag %d: %s\n", i, cJSON_GetStringValue(tag_name));
}
}
}
} else {
printf(" No tags array found\n");
}
const char* action_type = get_first_tag_name(event);
if (!action_type) {
log_error("DEBUG: Missing or invalid first tag after processing");
log_error("invalid: missing or invalid first tag");
snprintf(error_message, error_size, "invalid: missing or invalid first tag");
return -1;
}
log_info("DEBUG: Action type determined");
printf(" Action type: %s\n", action_type);
// Route to appropriate handler based on action type
log_info("DEBUG: Routing to action-specific handler");
if (strcmp(action_type, "auth_query") == 0) {
log_info("DEBUG: Routing to auth_query handler");
const char* query_type = get_tag_value(event, action_type, 1);
if (!query_type) {
log_error("DEBUG: Missing auth_query type parameter");
log_error("invalid: missing auth_query type");
snprintf(error_message, error_size, "invalid: missing auth_query type");
return -1;
}
printf(" Query type: %s\n", query_type);
return handle_auth_query_unified(event, query_type, error_message, error_size, wsi);
}
else if (strcmp(action_type, "config_query") == 0) {
log_info("DEBUG: Routing to config_query handler");
const char* query_type = get_tag_value(event, action_type, 1);
if (!query_type) {
log_error("DEBUG: Missing config_query type parameter");
log_error("invalid: missing config_query type");
snprintf(error_message, error_size, "invalid: missing config_query type");
return -1;
}
printf(" Query type: %s\n", query_type);
return handle_config_query_unified(event, query_type, error_message, error_size, wsi);
}
else if (strcmp(action_type, "config_set") == 0) {
log_info("DEBUG: Routing to config_set handler");
const char* config_key = get_tag_value(event, action_type, 1);
const char* config_value = get_tag_value(event, action_type, 2);
if (!config_key || !config_value) {
log_error("DEBUG: Missing config_set parameters");
log_error("invalid: missing config_set key or value");
snprintf(error_message, error_size, "invalid: missing config_set key or value");
return -1;
}
printf(" Key: %s, Value: %s\n", config_key, config_value);
return handle_config_set_unified(event, config_key, config_value, error_message, error_size, wsi);
}
else if (strcmp(action_type, "config_update") == 0) {
log_info("DEBUG: Routing to config_update handler");
return handle_config_update_unified(event, error_message, error_size, wsi);
}
else if (strcmp(action_type, "system_command") == 0) {
log_info("DEBUG: Routing to system_command handler");
const char* command = get_tag_value(event, action_type, 1);
if (!command) {
log_error("DEBUG: Missing system_command type parameter");
log_error("invalid: missing system_command type");
snprintf(error_message, error_size, "invalid: missing system_command type");
return -1;
}
printf(" Command: %s\n", command);
return handle_system_command_unified(event, command, error_message, error_size, wsi);
}
else if (strcmp(action_type, "stats_query") == 0) {
log_info("DEBUG: Routing to stats_query handler");
return handle_stats_query_unified(event, error_message, error_size, wsi);
}
else if (strcmp(action_type, "whitelist") == 0 || strcmp(action_type, "blacklist") == 0) {
log_info("DEBUG: Routing to auth rule modification handler");
printf(" Rule type: %s\n", action_type);
// Handle auth rule modifications (existing logic from process_admin_auth_event)
return handle_auth_rule_modification_unified(event, error_message, error_size, wsi);
}
else {
log_error("DEBUG: Unknown Kind 23456 action type");
printf(" Unknown action: %s\n", action_type);
char error_msg[256];
snprintf(error_msg, sizeof(error_msg), "invalid: unknown Kind 23456 action type '%s'", action_type);
log_error(error_msg);
snprintf(error_message, error_size, "invalid: unknown Kind 23456 action type '%s'", action_type);
return -1;
}

View File

@@ -157,9 +157,6 @@ int process_dm_admin_command(cJSON* command_array, cJSON* event, char* error_mes
}
const char* command_type = cJSON_GetStringValue(command_item);
log_info("DM Admin: Processing command");
printf(" Command: %s\n", command_type);
printf(" Parameters: %d\n", array_size - 1);
// Create synthetic tags from the command array for unified handler compatibility
cJSON* synthetic_tags = cJSON_CreateArray();
@@ -214,7 +211,6 @@ int process_dm_admin_command(cJSON* command_array, cJSON* event, char* error_mes
log_error("DM Admin: Missing auth_query type parameter");
snprintf(error_message, error_size, "invalid: missing auth_query type");
} else {
printf(" Query type: %s\n", query_type);
result = handle_auth_query_unified(event, query_type, error_message, error_size, wsi);
}
}
@@ -224,7 +220,6 @@ int process_dm_admin_command(cJSON* command_array, cJSON* event, char* error_mes
log_error("DM Admin: Missing config_query type parameter");
snprintf(error_message, error_size, "invalid: missing config_query type");
} else {
printf(" Query type: %s\n", query_type);
result = handle_config_query_unified(event, query_type, error_message, error_size, wsi);
}
}
@@ -235,7 +230,6 @@ int process_dm_admin_command(cJSON* command_array, cJSON* event, char* error_mes
log_error("DM Admin: Missing config_set parameters");
snprintf(error_message, error_size, "invalid: missing config_set key or value");
} else {
printf(" Key: %s, Value: %s\n", config_key, config_value);
result = handle_config_set_unified(event, config_key, config_value, error_message, error_size, wsi);
}
}
@@ -248,7 +242,6 @@ int process_dm_admin_command(cJSON* command_array, cJSON* event, char* error_mes
log_error("DM Admin: Missing system_command type parameter");
snprintf(error_message, error_size, "invalid: missing system_command type");
} else {
printf(" System command: %s\n", command);
result = handle_system_command_unified(event, command, error_message, error_size, wsi);
}
}
@@ -256,7 +249,6 @@ int process_dm_admin_command(cJSON* command_array, cJSON* event, char* error_mes
result = handle_stats_query_unified(event, error_message, error_size, wsi);
}
else if (strcmp(command_type, "whitelist") == 0 || strcmp(command_type, "blacklist") == 0) {
printf(" Rule type: %s\n", command_type);
result = handle_auth_rule_modification_unified(event, error_message, error_size, wsi);
}
else {
@@ -291,11 +283,6 @@ int parse_config_command(const char* message, char* key, char* value) {
return 0;
}
log_info("DEBUG: Parsing config command");
char debug_msg[256];
snprintf(debug_msg, sizeof(debug_msg), "DEBUG: Input message: '%.100s'", message);
log_info(debug_msg);
// Clean up the message - convert to lowercase and trim
char clean_msg[512];
size_t msg_len = strlen(message);
@@ -408,7 +395,6 @@ int parse_config_command(const char* message, char* key, char* value) {
}
}
log_info("DEBUG: No config command pattern matched");
return 0; // No pattern matched
}
@@ -603,7 +589,6 @@ void cleanup_expired_pending_changes(void) {
// Apply a configuration change to the database
int apply_config_change(const char* key, const char* value) {
if (!key || !value) {
log_error("DEBUG: apply_config_change called with NULL key or value");
return -1;
}
@@ -613,11 +598,6 @@ int apply_config_change(const char* key, const char* value) {
return -1;
}
log_info("DEBUG: Applying config change");
char debug_msg[256];
snprintf(debug_msg, sizeof(debug_msg), "DEBUG: Key='%s', Value='%s'", key, value);
log_info(debug_msg);
// Normalize boolean values
char normalized_value[256];
strncpy(normalized_value, value, sizeof(normalized_value) - 1);
@@ -630,11 +610,6 @@ int apply_config_change(const char* key, const char* value) {
strcpy(normalized_value, "false");
}
log_info("DEBUG: Normalized value");
char norm_msg[256];
snprintf(norm_msg, sizeof(norm_msg), "DEBUG: Normalized value='%s'", normalized_value);
log_info(norm_msg);
// Determine the data type based on the configuration key
const char* data_type = "string"; // Default to string
for (int i = 0; known_configs[i].key != NULL; i++) {
@@ -654,7 +629,6 @@ int apply_config_change(const char* key, const char* value) {
sqlite3_stmt* stmt;
const char* sql = "INSERT OR REPLACE INTO config (key, value, data_type) VALUES (?, ?, ?)";
log_info("DEBUG: Preparing SQL statement");
if (sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL) != SQLITE_OK) {
log_error("Failed to prepare config update statement");
const char* err_msg = sqlite3_errmsg(g_db);
@@ -662,12 +636,10 @@ int apply_config_change(const char* key, const char* value) {
return -1;
}
log_info("DEBUG: Binding parameters");
sqlite3_bind_text(stmt, 1, key, -1, SQLITE_STATIC);
sqlite3_bind_text(stmt, 2, normalized_value, -1, SQLITE_STATIC);
sqlite3_bind_text(stmt, 3, data_type, -1, SQLITE_STATIC);
log_info("DEBUG: Executing SQL statement");
int result = sqlite3_step(stmt);
if (result != SQLITE_DONE) {
log_error("Failed to update configuration in database");
@@ -678,8 +650,6 @@ int apply_config_change(const char* key, const char* value) {
}
sqlite3_finalize(stmt);
log_info("DEBUG: SQL execution successful");
char log_msg[512];
snprintf(log_msg, sizeof(log_msg), "Configuration updated: %s = %s", key, normalized_value);
log_success(log_msg);
@@ -784,11 +754,9 @@ int handle_config_confirmation(const char* admin_pubkey, const char* response) {
if (is_yes) {
// Apply the configuration change
log_info("DEBUG: Applying configuration change");
int result = apply_config_change(change->config_key, change->new_value);
if (result == 0) {
// Send success response
log_info("DEBUG: Configuration change applied successfully, sending success response");
char success_msg[1024];
snprintf(success_msg, sizeof(success_msg),
"✅ Configuration Updated\n"
@@ -803,10 +771,7 @@ int handle_config_confirmation(const char* admin_pubkey, const char* response) {
char error_msg[256];
int send_result = send_nip17_response(admin_pubkey, success_msg, error_msg, sizeof(error_msg));
if (send_result != 0) {
log_error("DEBUG: Failed to send success response");
log_error(error_msg);
} else {
log_success("DEBUG: Success response sent");
}
// Remove the pending change
@@ -814,7 +779,6 @@ int handle_config_confirmation(const char* admin_pubkey, const char* response) {
return 1; // Success
} else {
// Send error response
log_error("DEBUG: Configuration change failed, sending error response");
char error_msg[1024];
snprintf(error_msg, sizeof(error_msg),
"❌ Configuration Update Failed\n"
@@ -829,10 +793,7 @@ int handle_config_confirmation(const char* admin_pubkey, const char* response) {
char send_error_msg[256];
int send_result = send_nip17_response(admin_pubkey, error_msg, send_error_msg, sizeof(send_error_msg));
if (send_result != 0) {
log_error("DEBUG: Failed to send error response");
log_error(send_error_msg);
} else {
log_success("DEBUG: Error response sent");
}
// Remove the pending change
@@ -929,21 +890,14 @@ int process_config_change_request(const char* admin_pubkey, const char* message)
}
// Generate and send confirmation message
log_info("DEBUG: Generating confirmation message");
char* confirmation = generate_config_change_confirmation(key, current_value, value);
if (confirmation) {
log_info("DEBUG: Confirmation message generated, sending response");
char error_msg[256];
int send_result = send_nip17_response(admin_pubkey, confirmation, error_msg, sizeof(error_msg));
if (send_result == 0) {
log_success("DEBUG: Confirmation response sent successfully");
} else {
log_error("DEBUG: Failed to send confirmation response");
if (send_result != 0) {
log_error(error_msg);
}
free(confirmation);
} else {
log_error("DEBUG: Failed to generate confirmation message");
}
free(change_id);

View File

@@ -300,59 +300,48 @@ int init_database(const char* database_path_override) {
sqlite3_finalize(check_stmt);
if (has_events_table) {
log_info("Database schema already exists, checking version");
// Check existing schema version and migrate if needed
const char* version_sql = "SELECT value FROM schema_info WHERE key = 'version'";
sqlite3_stmt* version_stmt;
const char* db_version = NULL;
int needs_migration = 0;
if (sqlite3_prepare_v2(g_db, version_sql, -1, &version_stmt, NULL) == SQLITE_OK) {
if (sqlite3_step(version_stmt) == SQLITE_ROW) {
db_version = (char*)sqlite3_column_text(version_stmt, 0);
char version_msg[256];
snprintf(version_msg, sizeof(version_msg), "Existing database schema version: %s",
db_version ? db_version : "unknown");
log_info(version_msg);
// Check if migration is needed
if (!db_version || strcmp(db_version, "5") == 0) {
needs_migration = 1;
log_info("Database migration needed: v5 -> v6 (adding auth_rules table)");
} else if (strcmp(db_version, "6") == 0) {
log_info("Database is already at current schema version v6");
// Database is already at current schema version v6
} else if (strcmp(db_version, EMBEDDED_SCHEMA_VERSION) == 0) {
log_info("Database is at current schema version");
// Database is at current schema version
} else {
char warning_msg[256];
snprintf(warning_msg, sizeof(warning_msg), "Unknown database schema version: %s", db_version);
log_warning(warning_msg);
}
} else {
log_info("Database exists but no version information found, assuming migration needed");
needs_migration = 1;
}
sqlite3_finalize(version_stmt);
} else {
log_info("Cannot read schema version, assuming migration needed");
needs_migration = 1;
}
// Perform migration if needed
if (needs_migration) {
log_info("Performing database schema migration to v6");
// Check if auth_rules table already exists
const char* check_auth_rules_sql = "SELECT name FROM sqlite_master WHERE type='table' AND name='auth_rules'";
sqlite3_stmt* check_stmt;
int has_auth_rules = 0;
if (sqlite3_prepare_v2(g_db, check_auth_rules_sql, -1, &check_stmt, NULL) == SQLITE_OK) {
has_auth_rules = (sqlite3_step(check_stmt) == SQLITE_ROW);
sqlite3_finalize(check_stmt);
}
if (!has_auth_rules) {
// Add auth_rules table matching sql_schema.h
const char* create_auth_rules_sql =
@@ -398,7 +387,7 @@ int init_database(const char* database_path_override) {
}
log_success("Created auth_rules indexes");
} else {
log_info("auth_rules table already exists, skipping creation");
// auth_rules table already exists, skipping creation
}
// Update schema version to v6
@@ -421,8 +410,7 @@ int init_database(const char* database_path_override) {
}
} else {
// Initialize database schema using embedded SQL
log_info("Initializing database schema from embedded SQL");
// Execute the embedded schema SQL
char* error_msg = NULL;
rc = sqlite3_exec(g_db, EMBEDDED_SCHEMA_SQL, NULL, NULL, &error_msg);
@@ -438,12 +426,6 @@ int init_database(const char* database_path_override) {
}
log_success("Database schema initialized successfully");
// Log schema version information
char version_msg[256];
snprintf(version_msg, sizeof(version_msg), "Database schema version: %s",
EMBEDDED_SCHEMA_VERSION);
log_info(version_msg);
}
} else {
log_error("Failed to check existing database schema");
@@ -752,8 +734,6 @@ cJSON* retrieve_event(const char* event_id) {
/////////////////////////////////////////////////////////////////////////////////////////
int handle_req_message(const char* sub_id, cJSON* filters, struct lws *wsi, struct per_session_data *pss) {
log_info("Handling REQ message for persistent subscription");
if (!cJSON_IsArray(filters)) {
log_error("REQ filters is not an array");
return 0;
@@ -794,11 +774,6 @@ int handle_req_message(const char* sub_id, cJSON* filters, struct lws *wsi, stru
cJSON_Delete(filters_array);
char debug_msg[256];
snprintf(debug_msg, sizeof(debug_msg),
"Generated %d synthetic config events for subscription %s",
config_events_sent, sub_id);
log_info(debug_msg);
break; // Only generate once per subscription
}
}
@@ -1075,12 +1050,7 @@ int handle_req_message(const char* sub_id, cJSON* filters, struct lws *wsi, stru
// Default limit to prevent excessive queries
snprintf(sql_ptr, remaining, " LIMIT 500");
}
// Debug: Log the SQL query being executed
char debug_msg[1280];
snprintf(debug_msg, sizeof(debug_msg), "Executing SQL: %s", sql);
log_info(debug_msg);
// Execute query and send events
sqlite3_stmt* stmt;
int rc = sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL);
@@ -1125,11 +1095,6 @@ int handle_req_message(const char* sub_id, cJSON* filters, struct lws *wsi, stru
time_t current_time = time(NULL);
if (is_event_expired(event, current_time)) {
// Skip this expired event
cJSON* event_id_obj = cJSON_GetObjectItem(event, "id");
const char* event_id = event_id_obj ? cJSON_GetStringValue(event_id_obj) : "unknown";
char debug_msg[256];
snprintf(debug_msg, sizeof(debug_msg), "Filtering expired event from subscription: %.16s", event_id);
log_info(debug_msg);
cJSON_Delete(event);
continue;
}
@@ -1156,18 +1121,10 @@ int handle_req_message(const char* sub_id, cJSON* filters, struct lws *wsi, stru
cJSON_Delete(event_msg);
events_sent++;
}
char row_debug[128];
snprintf(row_debug, sizeof(row_debug), "Query returned %d rows", row_count);
log_info(row_debug);
sqlite3_finalize(stmt);
}
char events_debug[128];
snprintf(events_debug, sizeof(events_debug), "Total events sent: %d", events_sent);
log_info(events_debug);
return events_sent;
}
/////////////////////////////////////////////////////////////////////////////////////////
@@ -1230,7 +1187,6 @@ int is_authorized_admin_event(cJSON* event, char* error_buffer, size_t error_buf
if (!targets_this_relay) {
// Admin event for different relay - not an error, just not for us
log_info("Admin event targets different relay - treating as regular event");
snprintf(error_buffer, error_buffer_size, "Admin event not targeting this relay");
return -1;
}
@@ -1500,7 +1456,6 @@ int main(int argc, char* argv[]) {
// Handle configuration setup after database is initialized
// Always populate defaults directly in config table (abandoning legacy event signing)
log_info("Populating config table with defaults after database initialization");
// Populate default config values in table
if (populate_default_config_values() != 0) {
@@ -1549,8 +1504,6 @@ int main(int argc, char* argv[]) {
log_success("Relay pubkey stored in config table for first-time startup");
}
} else {
log_info("Existing relay detected");
// Find existing database file
char** existing_files = find_existing_db_files();
if (!existing_files || !existing_files[0]) {
@@ -1625,12 +1578,10 @@ int main(int argc, char* argv[]) {
// Store both admin and relay pubkeys in config table for unified cache
if (admin_pubkey && strlen(admin_pubkey) == 64) {
set_config_value_in_table("admin_pubkey", admin_pubkey, "string", "Administrator public key", "authentication", 0);
log_info("Admin pubkey stored in config table for existing relay");
}
if (relay_pubkey && strlen(relay_pubkey) == 64) {
set_config_value_in_table("relay_pubkey", relay_pubkey, "string", "Relay public key", "relay", 0);
log_info("Relay pubkey stored in config table for existing relay");
}
}
cJSON_Delete(config_event);

View File

@@ -142,11 +142,7 @@ int handle_deletion_request(cJSON* event, char* error_message, size_t error_size
if (store_event(event) != 0) {
log_warning("Failed to store deletion request event");
}
char debug_msg[256];
snprintf(debug_msg, sizeof(debug_msg), "Deletion request processed: %d events deleted", deleted_count);
log_info(debug_msg);
error_message[0] = '\0'; // Success - empty error message
return 0;
}
@@ -196,10 +192,6 @@ int delete_events_by_id(const char* requester_pubkey, cJSON* event_ids) {
if (sqlite3_step(delete_stmt) == SQLITE_DONE && sqlite3_changes(g_db) > 0) {
deleted_count++;
char debug_msg[128];
snprintf(debug_msg, sizeof(debug_msg), "Deleted event by ID: %.16s...", id);
log_info(debug_msg);
}
sqlite3_finalize(delete_stmt);
}
@@ -211,9 +203,6 @@ int delete_events_by_id(const char* requester_pubkey, cJSON* event_ids) {
}
} else {
sqlite3_finalize(check_stmt);
char debug_msg[128];
snprintf(debug_msg, sizeof(debug_msg), "Event not found for deletion: %.16s...", id);
log_info(debug_msg);
}
}
@@ -287,10 +276,6 @@ int delete_events_by_address(const char* requester_pubkey, cJSON* addresses, lon
int changes = sqlite3_changes(g_db);
if (changes > 0) {
deleted_count += changes;
char debug_msg[128];
snprintf(debug_msg, sizeof(debug_msg), "Deleted %d events by address: %.32s...", changes, addr);
log_info(debug_msg);
}
}
sqlite3_finalize(delete_stmt);

View File

@@ -36,191 +36,128 @@ extern unified_config_cache_t g_unified_cache;
// Helper function to parse comma-separated string into cJSON array
cJSON* parse_comma_separated_array(const char* csv_string) {
log_info("parse_comma_separated_array called");
if (!csv_string || strlen(csv_string) == 0) {
log_info("Empty or null csv_string, returning empty array");
return cJSON_CreateArray();
}
log_info("Creating cJSON array");
cJSON* array = cJSON_CreateArray();
if (!array) {
log_info("Failed to create cJSON array");
return NULL;
}
log_info("Duplicating csv_string");
char* csv_copy = strdup(csv_string);
if (!csv_copy) {
log_info("Failed to duplicate csv_string");
cJSON_Delete(array);
return NULL;
}
log_info("Starting token parsing");
char* token = strtok(csv_copy, ",");
while (token) {
log_info("Processing token");
// Trim whitespace
while (*token == ' ') token++;
char* end = token + strlen(token) - 1;
while (end > token && *end == ' ') *end-- = '\0';
if (strlen(token) > 0) {
log_info("Token has content, parsing");
// Try to parse as number first (for supported_nips)
char* endptr;
long num = strtol(token, &endptr, 10);
if (*endptr == '\0') {
log_info("Token is number, adding to array");
// It's a number
cJSON_AddItemToArray(array, cJSON_CreateNumber(num));
} else {
log_info("Token is string, adding to array");
// It's a string
cJSON_AddItemToArray(array, cJSON_CreateString(token));
}
} else {
log_info("Token is empty, skipping");
}
token = strtok(NULL, ",");
}
log_info("Freeing csv_copy");
free(csv_copy);
log_info("Returning parsed array");
return array;
}
// Initialize relay information using configuration system
void init_relay_info() {
log_info("Initializing relay information from configuration...");
// Get all config values first (without holding mutex to avoid deadlock)
// Note: These may be dynamically allocated strings that need to be freed
log_info("Fetching relay configuration values...");
const char* relay_name = get_config_value("relay_name");
log_info("relay_name fetched");
const char* relay_description = get_config_value("relay_description");
log_info("relay_description fetched");
const char* relay_software = get_config_value("relay_software");
log_info("relay_software fetched");
const char* relay_version = get_config_value("relay_version");
log_info("relay_version fetched");
const char* relay_contact = get_config_value("relay_contact");
log_info("relay_contact fetched");
const char* relay_pubkey = get_config_value("relay_pubkey");
log_info("relay_pubkey fetched");
const char* supported_nips_csv = get_config_value("supported_nips");
log_info("supported_nips fetched");
const char* language_tags_csv = get_config_value("language_tags");
log_info("language_tags fetched");
const char* relay_countries_csv = get_config_value("relay_countries");
log_info("relay_countries fetched");
const char* posting_policy = get_config_value("posting_policy");
log_info("posting_policy fetched");
const char* payments_url = get_config_value("payments_url");
log_info("payments_url fetched");
// Get config values for limitations
log_info("Fetching limitation configuration values...");
int max_message_length = get_config_int("max_message_length", 16384);
log_info("max_message_length fetched");
int max_subscriptions_per_client = get_config_int("max_subscriptions_per_client", 20);
log_info("max_subscriptions_per_client fetched");
int max_limit = get_config_int("max_limit", 5000);
log_info("max_limit fetched");
int max_event_tags = get_config_int("max_event_tags", 100);
log_info("max_event_tags fetched");
int max_content_length = get_config_int("max_content_length", 8196);
log_info("max_content_length fetched");
int default_limit = get_config_int("default_limit", 500);
log_info("default_limit fetched");
int admin_enabled = get_config_bool("admin_enabled", 0);
log_info("admin_enabled fetched");
pthread_mutex_lock(&g_unified_cache.cache_lock);
// Update relay information fields
log_info("Storing string values in cache...");
if (relay_name) {
log_info("Storing relay_name");
strncpy(g_unified_cache.relay_info.name, relay_name, sizeof(g_unified_cache.relay_info.name) - 1);
free((char*)relay_name); // Free dynamically allocated string
log_info("relay_name stored and freed");
} else {
log_info("Using default relay_name");
strncpy(g_unified_cache.relay_info.name, "C Nostr Relay", sizeof(g_unified_cache.relay_info.name) - 1);
}
if (relay_description) {
log_info("Storing relay_description");
strncpy(g_unified_cache.relay_info.description, relay_description, sizeof(g_unified_cache.relay_info.description) - 1);
free((char*)relay_description); // Free dynamically allocated string
log_info("relay_description stored and freed");
} else {
log_info("Using default relay_description");
strncpy(g_unified_cache.relay_info.description, "A high-performance Nostr relay implemented in C with SQLite storage", sizeof(g_unified_cache.relay_info.description) - 1);
}
if (relay_software) {
log_info("Storing relay_software");
strncpy(g_unified_cache.relay_info.software, relay_software, sizeof(g_unified_cache.relay_info.software) - 1);
free((char*)relay_software); // Free dynamically allocated string
log_info("relay_software stored and freed");
} else {
log_info("Using default relay_software");
strncpy(g_unified_cache.relay_info.software, "https://git.laantungir.net/laantungir/c-relay.git", sizeof(g_unified_cache.relay_info.software) - 1);
}
if (relay_version) {
log_info("Storing relay_version");
strncpy(g_unified_cache.relay_info.version, relay_version, sizeof(g_unified_cache.relay_info.version) - 1);
free((char*)relay_version); // Free dynamically allocated string
log_info("relay_version stored and freed");
} else {
log_info("Using default relay_version");
strncpy(g_unified_cache.relay_info.version, "0.2.0", sizeof(g_unified_cache.relay_info.version) - 1);
}
if (relay_contact) {
log_info("Storing relay_contact");
strncpy(g_unified_cache.relay_info.contact, relay_contact, sizeof(g_unified_cache.relay_info.contact) - 1);
free((char*)relay_contact); // Free dynamically allocated string
log_info("relay_contact stored and freed");
}
if (relay_pubkey) {
log_info("Storing relay_pubkey");
strncpy(g_unified_cache.relay_info.pubkey, relay_pubkey, sizeof(g_unified_cache.relay_info.pubkey) - 1);
free((char*)relay_pubkey); // Free dynamically allocated string
log_info("relay_pubkey stored and freed");
}
if (posting_policy) {
log_info("Storing posting_policy");
strncpy(g_unified_cache.relay_info.posting_policy, posting_policy, sizeof(g_unified_cache.relay_info.posting_policy) - 1);
free((char*)posting_policy); // Free dynamically allocated string
log_info("posting_policy stored and freed");
}
if (payments_url) {
log_info("Storing payments_url");
strncpy(g_unified_cache.relay_info.payments_url, payments_url, sizeof(g_unified_cache.relay_info.payments_url) - 1);
free((char*)payments_url); // Free dynamically allocated string
log_info("payments_url stored and freed");
}
// Initialize supported NIPs array from config
log_info("Initializing supported_nips array");
if (supported_nips_csv) {
log_info("Parsing supported_nips from config");
g_unified_cache.relay_info.supported_nips = parse_comma_separated_array(supported_nips_csv);
log_info("supported_nips parsed successfully");
free((char*)supported_nips_csv); // Free dynamically allocated string
log_info("supported_nips_csv freed");
} else {
log_info("Using default supported_nips");
// Fallback to default supported NIPs
g_unified_cache.relay_info.supported_nips = cJSON_CreateArray();
if (g_unified_cache.relay_info.supported_nips) {
@@ -233,14 +170,11 @@ void init_relay_info() {
cJSON_AddItemToArray(g_unified_cache.relay_info.supported_nips, cJSON_CreateNumber(40)); // NIP-40: Expiration Timestamp
cJSON_AddItemToArray(g_unified_cache.relay_info.supported_nips, cJSON_CreateNumber(42)); // NIP-42: Authentication
}
log_info("Default supported_nips created");
}
// Initialize server limitations using configuration
log_info("Initializing server limitations");
g_unified_cache.relay_info.limitation = cJSON_CreateObject();
if (g_unified_cache.relay_info.limitation) {
log_info("Adding limitation fields");
cJSON_AddNumberToObject(g_unified_cache.relay_info.limitation, "max_message_length", max_message_length);
cJSON_AddNumberToObject(g_unified_cache.relay_info.limitation, "max_subscriptions", max_subscriptions_per_client);
cJSON_AddNumberToObject(g_unified_cache.relay_info.limitation, "max_limit", max_limit);
@@ -254,25 +188,16 @@ void init_relay_info() {
cJSON_AddNumberToObject(g_unified_cache.relay_info.limitation, "created_at_lower_limit", 0);
cJSON_AddNumberToObject(g_unified_cache.relay_info.limitation, "created_at_upper_limit", 2147483647);
cJSON_AddNumberToObject(g_unified_cache.relay_info.limitation, "default_limit", default_limit);
log_info("Limitation fields added");
} else {
log_info("Failed to create limitation object");
}
// Initialize empty retention policies (can be configured later)
log_info("Initializing retention policies");
g_unified_cache.relay_info.retention = cJSON_CreateArray();
// Initialize language tags from config
log_info("Initializing language_tags");
if (language_tags_csv) {
log_info("Parsing language_tags from config");
g_unified_cache.relay_info.language_tags = parse_comma_separated_array(language_tags_csv);
log_info("language_tags parsed successfully");
free((char*)language_tags_csv); // Free dynamically allocated string
log_info("language_tags_csv freed");
} else {
log_info("Using default language_tags");
// Fallback to global
g_unified_cache.relay_info.language_tags = cJSON_CreateArray();
if (g_unified_cache.relay_info.language_tags) {
@@ -281,15 +206,10 @@ void init_relay_info() {
}
// Initialize relay countries from config
log_info("Initializing relay_countries");
if (relay_countries_csv) {
log_info("Parsing relay_countries from config");
g_unified_cache.relay_info.relay_countries = parse_comma_separated_array(relay_countries_csv);
log_info("relay_countries parsed successfully");
free((char*)relay_countries_csv); // Free dynamically allocated string
log_info("relay_countries_csv freed");
} else {
log_info("Using default relay_countries");
// Fallback to global
g_unified_cache.relay_info.relay_countries = cJSON_CreateArray();
if (g_unified_cache.relay_info.relay_countries) {
@@ -298,14 +218,11 @@ void init_relay_info() {
}
// Initialize content tags as empty array
log_info("Initializing tags");
g_unified_cache.relay_info.tags = cJSON_CreateArray();
// Initialize fees as empty object (no payment required by default)
log_info("Initializing fees");
g_unified_cache.relay_info.fees = cJSON_CreateObject();
log_info("Unlocking cache mutex");
pthread_mutex_unlock(&g_unified_cache.cache_lock);
log_success("Relay information initialized with default values");
@@ -518,7 +435,6 @@ cJSON* generate_relay_info_json() {
g_unified_cache.relay_info.tags = cJSON_CreateArray();
g_unified_cache.relay_info.fees = cJSON_CreateObject();
log_info("NIP-11 relay_info rebuilt directly from config table");
}
// Add basic relay information
@@ -610,7 +526,6 @@ struct nip11_session_data {
// Handle NIP-11 HTTP request with proper asynchronous buffer management
int handle_nip11_http_request(struct lws* wsi, const char* accept_header) {
log_info("Handling NIP-11 relay information request");
// Check if client accepts application/nostr+json
int accepts_nostr_json = 0;
@@ -696,9 +611,6 @@ int handle_nip11_http_request(struct lws* wsi, const char* accept_header) {
}
size_t json_len = strlen(json_string);
log_info("Generated NIP-11 JSON");
printf(" JSON length: %zu bytes\n", json_len);
printf(" JSON preview: %.100s%s\n", json_string, json_len > 100 ? "..." : "");
// Allocate session data to manage buffer lifetime across callbacks
struct nip11_session_data* session_data = malloc(sizeof(struct nip11_session_data));
@@ -791,8 +703,7 @@ int handle_nip11_http_request(struct lws* wsi, const char* accept_header) {
// Request callback for body transmission
lws_callback_on_writable(wsi);
log_success("NIP-11 headers sent, body transmission scheduled");
return 0;
}

View File

@@ -27,7 +27,6 @@ struct pow_config {
// Initialize PoW configuration using configuration system
void init_pow_config() {
log_info("Initializing NIP-13 Proof of Work configuration");
// Get all config values first (without holding mutex to avoid deadlock)
int pow_enabled = get_config_bool("pow_enabled", 1);
@@ -48,36 +47,20 @@ void init_pow_config() {
g_unified_cache.pow_config.reject_lower_targets = 1;
g_unified_cache.pow_config.strict_format = 1;
g_unified_cache.pow_config.anti_spam_mode = 1;
log_info("PoW configured in strict anti-spam mode");
} else if (strcmp(pow_mode, "full") == 0) {
g_unified_cache.pow_config.validation_flags = NOSTR_POW_VALIDATE_FULL;
g_unified_cache.pow_config.require_nonce_tag = 1;
log_info("PoW configured in full validation mode");
} else if (strcmp(pow_mode, "basic") == 0) {
g_unified_cache.pow_config.validation_flags = NOSTR_POW_VALIDATE_BASIC;
log_info("PoW configured in basic validation mode");
} else if (strcmp(pow_mode, "disabled") == 0) {
g_unified_cache.pow_config.enabled = 0;
log_info("PoW validation disabled via configuration");
}
free((char*)pow_mode); // Free dynamically allocated string
} else {
// Default to basic mode
g_unified_cache.pow_config.validation_flags = NOSTR_POW_VALIDATE_BASIC;
log_info("PoW configured in basic validation mode (default)");
}
// Log final configuration
char config_msg[512];
snprintf(config_msg, sizeof(config_msg),
"PoW Configuration: enabled=%s, min_difficulty=%d, validation_flags=0x%x, mode=%s",
g_unified_cache.pow_config.enabled ? "true" : "false",
g_unified_cache.pow_config.min_pow_difficulty,
g_unified_cache.pow_config.validation_flags,
g_unified_cache.pow_config.anti_spam_mode ? "anti-spam" :
(g_unified_cache.pow_config.validation_flags & NOSTR_POW_VALIDATE_FULL) ? "full" : "basic");
log_info(config_msg);
pthread_mutex_unlock(&g_unified_cache.cache_lock);
}
@@ -175,17 +158,5 @@ int validate_event_pow(cJSON* event, char* error_message, size_t error_size) {
return validation_result;
}
// Log successful PoW validation (only if minimum difficulty is required)
if (min_pow_difficulty > 0 || pow_result.has_nonce_tag) {
char debug_msg[256];
snprintf(debug_msg, sizeof(debug_msg),
"PoW validated: difficulty=%d, target=%d, nonce=%llu%s",
pow_result.actual_difficulty,
pow_result.committed_target,
(unsigned long long)pow_result.nonce_value,
pow_result.has_nonce_tag ? "" : " (no nonce tag)");
log_info(debug_msg);
}
return 0; // Success
}

View File

@@ -34,7 +34,6 @@ void log_warning(const char* message);
// Initialize expiration configuration using configuration system
void init_expiration_config() {
log_info("Initializing NIP-40 Expiration Timestamp configuration");
// Get all config values first (without holding mutex to avoid deadlock)
int expiration_enabled = get_config_bool("expiration_enabled", 1);
@@ -56,15 +55,6 @@ void init_expiration_config() {
g_expiration_config.grace_period = 300;
}
// Log final configuration
char config_msg[512];
snprintf(config_msg, sizeof(config_msg),
"Expiration Configuration: enabled=%s, strict_mode=%s, filter_responses=%s, grace_period=%ld seconds",
g_expiration_config.enabled ? "true" : "false",
g_expiration_config.strict_mode ? "true" : "false",
g_expiration_config.filter_responses ? "true" : "false",
g_expiration_config.grace_period);
log_info(config_msg);
}
// Extract expiration timestamp from event tags
@@ -161,11 +151,7 @@ int validate_event_expiration(cJSON* event, char* error_message, size_t error_si
log_warning("Event rejected: expired timestamp");
return -1;
} else {
// In non-strict mode, log but allow expired events
char debug_msg[256];
snprintf(debug_msg, sizeof(debug_msg),
"Accepting expired event (strict_mode disabled)");
log_info(debug_msg);
// In non-strict mode, allow expired events
}
}

View File

@@ -83,10 +83,6 @@ void send_nip42_auth_challenge(struct lws* wsi, struct per_session_data* pss) {
free(msg_str);
}
cJSON_Delete(auth_msg);
char debug_msg[128];
snprintf(debug_msg, sizeof(debug_msg), "NIP-42 auth challenge sent: %.16s...", challenge);
log_info(debug_msg);
}
// Handle NIP-42 signed authentication event from client

View File

@@ -139,21 +139,6 @@ struct {
char reason[500]; // specific reason string
} g_last_rule_violation = {0};
/**
* Helper function for consistent debug logging to main relay.log file
*/
static void validator_debug_log(const char *message) {
FILE *relay_log = fopen("relay.log", "a");
if (relay_log) {
// Use same format as main logging system
time_t now = time(NULL);
struct tm *tm_info = localtime(&now);
char timestamp[20];
strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", tm_info);
fprintf(relay_log, "[%s] [DEBUG] %s", timestamp, message);
fclose(relay_log);
}
}
//=============================================================================
// FORWARD DECLARATIONS
@@ -188,16 +173,12 @@ int ginxsom_request_validator_init(const char *db_path, const char *app_name) {
// Initialize nostr_core_lib if not already done
if (nostr_crypto_init() != NOSTR_SUCCESS) {
validator_debug_log(
"VALIDATOR: Failed to initialize nostr crypto system\n");
return NOSTR_ERROR_CRYPTO_INIT;
}
// Load initial configuration from database
int result = reload_auth_config();
if (result != NOSTR_SUCCESS) {
validator_debug_log(
"VALIDATOR: Failed to load configuration from database\n");
return result;
}
@@ -215,8 +196,6 @@ int ginxsom_request_validator_init(const char *db_path, const char *app_name) {
g_challenge_manager.last_cleanup = time(NULL);
g_validator_initialized = 1;
validator_debug_log(
"VALIDATOR: Request validator initialized successfully\n");
return NOSTR_SUCCESS;
}
@@ -257,20 +236,17 @@ int nostr_validate_unified_request(const char* json_string, size_t json_length)
// 1. Null Pointer Checks - Reject malformed requests instantly
if (!json_string || json_length == 0) {
validator_debug_log("VALIDATOR_DEBUG: STEP 1 FAILED - Null input\n");
return NOSTR_ERROR_INVALID_INPUT;
}
// 2. Initialization Check - Verify system is properly initialized
if (!g_validator_initialized) {
validator_debug_log("VALIDATOR_DEBUG: STEP 2 FAILED - Validator not initialized\n");
return NOSTR_ERROR_INVALID_INPUT;
}
// 3. Parse JSON string to cJSON event object
cJSON *event = cJSON_ParseWithLength(json_string, json_length);
if (!event) {
validator_debug_log("VALIDATOR_DEBUG: STEP 3 FAILED - Failed to parse JSON event\n");
return NOSTR_ERROR_INVALID_INPUT;
}
@@ -290,20 +266,14 @@ int nostr_validate_unified_request(const char* json_string, size_t json_length)
!tags || !cJSON_IsArray(tags) ||
!content || !cJSON_IsString(content) ||
!sig || !cJSON_IsString(sig)) {
validator_debug_log("VALIDATOR_DEBUG: STEP 4 FAILED - Invalid event structure\n");
cJSON_Delete(event);
return NOSTR_ERROR_INVALID_INPUT;
}
int event_kind = (int)cJSON_GetNumberValue(kind);
// 5. Check configuration using unified cache
int auth_required = nostr_auth_rules_enabled();
char config_msg[256];
sprintf(config_msg, "VALIDATOR_DEBUG: STEP 5 PASSED - Event kind: %d, auth_required: %d\n",
event_kind, auth_required);
validator_debug_log(config_msg);
/////////////////////////////////////////////////////////////////////
// PHASE 2: NOSTR EVENT VALIDATION
@@ -312,39 +282,26 @@ int nostr_validate_unified_request(const char* json_string, size_t json_length)
// 6. Nostr Event Structure Validation using nostr_core_lib
int validation_result = nostr_validate_event(event);
if (validation_result != NOSTR_SUCCESS) {
char validation_msg[256];
sprintf(validation_msg, "VALIDATOR_DEBUG: STEP 6 FAILED - NOSTR event validation failed (error=%d)\n",
validation_result);
validator_debug_log(validation_msg);
cJSON_Delete(event);
return validation_result;
}
validator_debug_log("VALIDATOR_DEBUG: STEP 6 PASSED - Event structure and signature valid\n");
// 7. Extract pubkey for rule evaluation
const char *event_pubkey = cJSON_GetStringValue(pubkey);
if (!event_pubkey || strlen(event_pubkey) != 64) {
validator_debug_log("VALIDATOR_DEBUG: STEP 7 FAILED - Invalid pubkey format\n");
cJSON_Delete(event);
return NOSTR_ERROR_EVENT_INVALID_PUBKEY;
}
char pubkey_msg[256];
sprintf(pubkey_msg, "VALIDATOR_DEBUG: STEP 7 PASSED - Extracted pubkey: %.16s...\n", event_pubkey);
validator_debug_log(pubkey_msg);
/////////////////////////////////////////////////////////////////////
// PHASE 3: EVENT KIND SPECIFIC VALIDATION
/////////////////////////////////////////////////////////////////////
// 8. Handle NIP-42 authentication challenge events (kind 22242)
if (event_kind == 22242) {
validator_debug_log("VALIDATOR_DEBUG: STEP 8 - Processing NIP-42 challenge response\n");
// Check NIP-42 mode using unified cache
const char* nip42_enabled = get_config_value("nip42_auth_enabled");
if (nip42_enabled && strcmp(nip42_enabled, "false") == 0) {
validator_debug_log("VALIDATOR_DEBUG: STEP 8 FAILED - NIP-42 is disabled\n");
free((char*)nip42_enabled);
cJSON_Delete(event);
return NOSTR_ERROR_NIP42_DISABLED;
@@ -353,7 +310,6 @@ int nostr_validate_unified_request(const char* json_string, size_t json_length)
// TODO: Implement full NIP-42 challenge validation
// For now, accept all valid NIP-42 events
validator_debug_log("VALIDATOR_DEBUG: STEP 8 PASSED - NIP-42 challenge response accepted\n");
cJSON_Delete(event);
return NOSTR_SUCCESS;
}
@@ -364,10 +320,8 @@ int nostr_validate_unified_request(const char* json_string, size_t json_length)
// 9. Check if authentication rules are enabled
if (!auth_required) {
validator_debug_log("VALIDATOR_DEBUG: STEP 9 - Authentication disabled, skipping database auth rules\n");
} else {
// 10. Check database authentication rules (only if auth enabled)
validator_debug_log("VALIDATOR_DEBUG: STEP 10 - Checking database authentication rules\n");
// Create operation string with event kind for more specific rule matching
char operation_str[64];
@@ -379,17 +333,10 @@ int nostr_validate_unified_request(const char* json_string, size_t json_length)
// If generic event check fails, try specific event kind check
rules_result = check_database_auth_rules(event_pubkey, operation_str, NULL);
if (rules_result != NOSTR_SUCCESS) {
char rules_msg[256];
sprintf(rules_msg, "VALIDATOR_DEBUG: STEP 10 FAILED - Database rules denied request (kind=%d)\n", event_kind);
validator_debug_log(rules_msg);
cJSON_Delete(event);
return rules_result;
}
}
char rules_success_msg[256];
sprintf(rules_success_msg, "VALIDATOR_DEBUG: STEP 10 PASSED - Database rules allow request (kind=%d)\n", event_kind);
validator_debug_log(rules_success_msg);
}
/////////////////////////////////////////////////////////////////////
@@ -404,44 +351,30 @@ int nostr_validate_unified_request(const char* json_string, size_t json_length)
pthread_mutex_unlock(&g_unified_cache.cache_lock);
if (pow_enabled && pow_min_difficulty > 0) {
validator_debug_log("VALIDATOR_DEBUG: STEP 11 - Validating NIP-13 Proof of Work\n");
nostr_pow_result_t pow_result;
int pow_validation_result = nostr_validate_pow(event, pow_min_difficulty,
pow_validation_flags, &pow_result);
if (pow_validation_result != NOSTR_SUCCESS) {
char pow_msg[256];
sprintf(pow_msg, "VALIDATOR_DEBUG: STEP 11 FAILED - PoW validation failed (error=%d, difficulty=%d/%d)\n",
pow_validation_result, pow_result.actual_difficulty, pow_min_difficulty);
validator_debug_log(pow_msg);
cJSON_Delete(event);
return pow_validation_result;
}
char pow_success_msg[256];
sprintf(pow_success_msg, "VALIDATOR_DEBUG: STEP 11 PASSED - PoW validated (difficulty=%d, target=%d)\n",
pow_result.actual_difficulty, pow_result.committed_target);
validator_debug_log(pow_success_msg);
} else {
validator_debug_log("VALIDATOR_DEBUG: STEP 11 SKIPPED - PoW validation disabled or min_difficulty=0\n");
}
// 12. NIP-40 Expiration validation
// Always check expiration tags if present (following NIP-40 specification)
validator_debug_log("VALIDATOR_DEBUG: STEP 12 - Starting NIP-40 Expiration validation\n");
cJSON *expiration_tag = NULL;
cJSON *tags_array = cJSON_GetObjectItem(event, "tags");
if (tags_array && cJSON_IsArray(tags_array)) {
cJSON *tag = NULL;
cJSON_ArrayForEach(tag, tags_array) {
if (!cJSON_IsArray(tag)) continue;
cJSON *tag_name = cJSON_GetArrayItem(tag, 0);
if (!tag_name || !cJSON_IsString(tag_name)) continue;
const char *tag_name_str = cJSON_GetStringValue(tag_name);
if (strcmp(tag_name_str, "expiration") == 0) {
cJSON *tag_value = cJSON_GetArrayItem(tag, 1);
@@ -452,57 +385,40 @@ int nostr_validate_unified_request(const char* json_string, size_t json_length)
}
}
}
if (expiration_tag) {
const char *expiration_str = cJSON_GetStringValue(expiration_tag);
// Validate that the expiration string contains only digits (and optional leading whitespace)
const char* p = expiration_str;
// Skip leading whitespace
while (*p == ' ' || *p == '\t') p++;
// Check if we have at least one digit
if (*p == '\0') {
validator_debug_log("VALIDATOR_DEBUG: STEP 12 SKIPPED - Empty expiration tag value, ignoring\n");
} else {
// Validate that all remaining characters are digits
const char* digit_start = p;
while (*p >= '0' && *p <= '9') p++;
// If we didn't consume the entire string or found no digits, it's malformed
if (*p != '\0' || p == digit_start) {
char malformed_msg[256];
sprintf(malformed_msg, "VALIDATOR_DEBUG: STEP 12 SKIPPED - Malformed expiration tag value '%.32s', ignoring\n",
expiration_str);
validator_debug_log(malformed_msg);
} else {
// Valid numeric string, parse and check expiration
time_t expiration_time = (time_t)atol(expiration_str);
time_t now = time(NULL);
int grace_period = get_config_int("nip40_expiration_grace_period", 60);
if (expiration_time > 0 && now > expiration_time + grace_period) {
char exp_msg[256];
sprintf(exp_msg, "VALIDATOR_DEBUG: STEP 12 FAILED - Event expired (now=%ld, exp=%ld, grace=%d)\n",
(long)now, (long)expiration_time, grace_period);
validator_debug_log(exp_msg);
cJSON_Delete(event);
return NOSTR_ERROR_EVENT_EXPIRED;
}
char exp_success_msg[256];
sprintf(exp_success_msg, "VALIDATOR_DEBUG: STEP 12 PASSED - Event not expired (exp=%ld, now=%ld)\n",
(long)expiration_time, (long)now);
validator_debug_log(exp_success_msg);
}
}
} else {
validator_debug_log("VALIDATOR_DEBUG: STEP 12 SKIPPED - No expiration tag found\n");
}
// All validations passed
validator_debug_log("VALIDATOR_DEBUG: STEP 13 PASSED - All validations complete, event ACCEPTED\n");
cJSON_Delete(event);
return NOSTR_SUCCESS;
}
@@ -578,7 +494,6 @@ void nostr_request_result_free_file_data(nostr_request_result_t *result) {
void nostr_request_validator_force_cache_refresh(void) {
// Use unified cache refresh from config.c
force_config_cache_refresh();
validator_debug_log("VALIDATOR: Cache forcibly invalidated via unified cache\n");
}
/**
@@ -586,7 +501,6 @@ void nostr_request_validator_force_cache_refresh(void) {
*/
static int reload_auth_config(void) {
// Configuration is now handled by the unified cache in config.c
validator_debug_log("VALIDATOR: Using unified cache system for configuration\n");
return NOSTR_SUCCESS;
}
@@ -598,35 +512,23 @@ static int reload_auth_config(void) {
* Check database authentication rules for the request
* Implements the 6-step rule evaluation engine from AUTH_API.md
*/
int check_database_auth_rules(const char *pubkey, const char *operation,
int check_database_auth_rules(const char *pubkey, const char *operation __attribute__((unused)),
const char *resource_hash) {
sqlite3 *db = NULL;
sqlite3_stmt *stmt = NULL;
int rc;
if (!pubkey) {
validator_debug_log(
"VALIDATOR_DEBUG: RULES ENGINE - Missing pubkey for rule evaluation\n");
return NOSTR_ERROR_INVALID_INPUT;
}
char rules_msg[256];
sprintf(rules_msg,
"VALIDATOR_DEBUG: RULES ENGINE - Checking rules for pubkey=%.32s..., "
"operation=%s\n",
pubkey, operation ? operation : "NULL");
validator_debug_log(rules_msg);
// Open database using global database path
if (strlen(g_database_path) == 0) {
validator_debug_log("VALIDATOR_DEBUG: RULES ENGINE - No database path available\n");
return NOSTR_SUCCESS; // Default allow on DB error
}
rc = sqlite3_open_v2(g_database_path, &db, SQLITE_OPEN_READONLY, NULL);
if (rc != SQLITE_OK) {
validator_debug_log(
"VALIDATOR_DEBUG: RULES ENGINE - Failed to open database\n");
return NOSTR_SUCCESS; // Default allow on DB error
}
@@ -640,13 +542,6 @@ int check_database_auth_rules(const char *pubkey, const char *operation,
if (sqlite3_step(stmt) == SQLITE_ROW) {
const char *action = (const char *)sqlite3_column_text(stmt, 1);
validator_debug_log("VALIDATOR_DEBUG: RULES ENGINE - STEP 1 FAILED - "
"Pubkey blacklisted\n");
char blacklist_msg[256];
sprintf(blacklist_msg,
"VALIDATOR_DEBUG: RULES ENGINE - Blacklist rule matched: action=%s\n",
action ? action : "deny");
validator_debug_log(blacklist_msg);
// Set specific violation details for status code mapping
strcpy(g_last_rule_violation.violation_type, "pubkey_blacklist");
@@ -659,8 +554,6 @@ int check_database_auth_rules(const char *pubkey, const char *operation,
}
sqlite3_finalize(stmt);
}
validator_debug_log("VALIDATOR_DEBUG: RULES ENGINE - STEP 1 PASSED - Pubkey "
"not blacklisted\n");
// Step 2: Check hash blacklist
if (resource_hash) {
@@ -673,14 +566,6 @@ int check_database_auth_rules(const char *pubkey, const char *operation,
if (sqlite3_step(stmt) == SQLITE_ROW) {
const char *action = (const char *)sqlite3_column_text(stmt, 1);
validator_debug_log("VALIDATOR_DEBUG: RULES ENGINE - STEP 2 FAILED - "
"Hash blacklisted\n");
char hash_blacklist_msg[256];
sprintf(
hash_blacklist_msg,
"VALIDATOR_DEBUG: RULES ENGINE - Hash blacklist rule matched: action=%s\n",
action ? action : "deny");
validator_debug_log(hash_blacklist_msg);
// Set specific violation details for status code mapping
strcpy(g_last_rule_violation.violation_type, "hash_blacklist");
@@ -693,11 +578,6 @@ int check_database_auth_rules(const char *pubkey, const char *operation,
}
sqlite3_finalize(stmt);
}
validator_debug_log("VALIDATOR_DEBUG: RULES ENGINE - STEP 2 PASSED - Hash "
"not blacklisted\n");
} else {
validator_debug_log("VALIDATOR_DEBUG: RULES ENGINE - STEP 2 SKIPPED - No "
"resource hash provided\n");
}
// Step 3: Check pubkey whitelist
@@ -709,22 +589,12 @@ int check_database_auth_rules(const char *pubkey, const char *operation,
sqlite3_bind_text(stmt, 1, pubkey, -1, SQLITE_STATIC);
if (sqlite3_step(stmt) == SQLITE_ROW) {
const char *action = (const char *)sqlite3_column_text(stmt, 1);
validator_debug_log("VALIDATOR_DEBUG: RULES ENGINE - STEP 3 PASSED - "
"Pubkey whitelisted\n");
char whitelist_msg[256];
sprintf(whitelist_msg,
"VALIDATOR_DEBUG: RULES ENGINE - Whitelist rule matched: action=%s\n",
action ? action : "allow");
validator_debug_log(whitelist_msg);
sqlite3_finalize(stmt);
sqlite3_close(db);
return NOSTR_SUCCESS; // Allow whitelisted pubkey
}
sqlite3_finalize(stmt);
}
validator_debug_log("VALIDATOR_DEBUG: RULES ENGINE - STEP 3 FAILED - Pubkey "
"not whitelisted\n");
// Step 4: Check if any whitelist rules exist - if yes, deny by default
const char *whitelist_exists_sql =
@@ -735,9 +605,6 @@ int check_database_auth_rules(const char *pubkey, const char *operation,
if (sqlite3_step(stmt) == SQLITE_ROW) {
int whitelist_count = sqlite3_column_int(stmt, 0);
if (whitelist_count > 0) {
validator_debug_log("VALIDATOR_DEBUG: RULES ENGINE - STEP 4 FAILED - "
"Whitelist exists but pubkey not in it\n");
// Set specific violation details for status code mapping
strcpy(g_last_rule_violation.violation_type, "whitelist_violation");
strcpy(g_last_rule_violation.reason,
@@ -750,12 +617,8 @@ int check_database_auth_rules(const char *pubkey, const char *operation,
}
sqlite3_finalize(stmt);
}
validator_debug_log("VALIDATOR_DEBUG: RULES ENGINE - STEP 4 PASSED - No "
"whitelist restrictions apply\n");
sqlite3_close(db);
validator_debug_log("VALIDATOR_DEBUG: RULES ENGINE - STEP 5 PASSED - All "
"rule checks completed, default ALLOW\n");
return NOSTR_SUCCESS; // Default allow if no restrictive rules matched
}
@@ -821,11 +684,6 @@ static void cleanup_expired_challenges(void) {
}
g_challenge_manager.last_cleanup = now;
char cleanup_msg[256];
sprintf(cleanup_msg, "NIP-42: Cleaned up challenges, %d active remaining\n",
active_count);
validator_debug_log(cleanup_msg);
}
/**
@@ -877,12 +735,6 @@ static int store_challenge(const char *challenge_id, const char *client_ip) {
entry->expires_at = now + g_challenge_manager.timeout_seconds;
entry->active = 1;
char store_msg[256];
sprintf(store_msg,
"NIP-42: Stored challenge %.16s... (expires in %d seconds)\n",
challenge_id, g_challenge_manager.timeout_seconds);
validator_debug_log(store_msg);
return NOSTR_SUCCESS;
}

View File

@@ -209,12 +209,7 @@ int add_subscription_to_manager(subscription_t* sub) {
// Log subscription creation to database
log_subscription_created(sub);
char debug_msg[256];
snprintf(debug_msg, sizeof(debug_msg), "Added subscription '%s' (total: %d)",
sub->id, g_subscription_manager.total_subscriptions);
log_info(debug_msg);
return 0;
}
@@ -242,12 +237,7 @@ int remove_subscription_from_manager(const char* sub_id, struct lws* wsi) {
// Update events sent counter before freeing
update_subscription_events_sent(sub_id, sub->events_sent);
char debug_msg[256];
snprintf(debug_msg, sizeof(debug_msg), "Removed subscription '%s' (total: %d)",
sub_id, g_subscription_manager.total_subscriptions);
log_info(debug_msg);
free_subscription(sub);
return 0;
}
@@ -274,34 +264,24 @@ int event_matches_filter(cJSON* event, subscription_filter_t* filter) {
if (filter->kinds && cJSON_IsArray(filter->kinds)) {
cJSON* event_kind = cJSON_GetObjectItem(event, "kind");
if (!event_kind || !cJSON_IsNumber(event_kind)) {
log_info("DEBUG FILTER: kinds filter present but event has no valid kind");
return 0;
}
int event_kind_val = (int)cJSON_GetNumberValue(event_kind);
int kind_match = 0;
char debug_kinds_msg[256];
snprintf(debug_kinds_msg, sizeof(debug_kinds_msg), "DEBUG FILTER: Checking kinds - event kind: %d", event_kind_val);
log_info(debug_kinds_msg);
cJSON* kind_item = NULL;
cJSON_ArrayForEach(kind_item, filter->kinds) {
if (cJSON_IsNumber(kind_item)) {
int filter_kind = (int)cJSON_GetNumberValue(kind_item);
char debug_kind_check_msg[256];
snprintf(debug_kind_check_msg, sizeof(debug_kind_check_msg), "DEBUG FILTER: Comparing event kind %d with filter kind %d", event_kind_val, filter_kind);
log_info(debug_kind_check_msg);
if (filter_kind == event_kind_val) {
kind_match = 1;
log_info("DEBUG FILTER: Kind match found!");
break;
}
}
}
if (!kind_match) {
log_info("DEBUG FILTER: No kind match - filter fails");
return 0;
}
}
@@ -390,14 +370,9 @@ int event_matches_filter(cJSON* event, subscription_filter_t* filter) {
if (filter->tag_filters && cJSON_IsObject(filter->tag_filters)) {
cJSON* event_tags = cJSON_GetObjectItem(event, "tags");
if (!event_tags || !cJSON_IsArray(event_tags)) {
log_info("DEBUG FILTER: tag filters present but event has no valid tags array");
return 0; // Event has no tags but filter requires tags
}
char debug_tags_msg[256];
snprintf(debug_tags_msg, sizeof(debug_tags_msg), "DEBUG FILTER: Checking tag filters - event has %d tags", cJSON_GetArraySize(event_tags));
log_info(debug_tags_msg);
// Check each tag filter
cJSON* tag_filter = NULL;
cJSON_ArrayForEach(tag_filter, filter->tag_filters) {
@@ -407,10 +382,6 @@ int event_matches_filter(cJSON* event, subscription_filter_t* filter) {
const char* tag_name = tag_filter->string + 1; // Skip the '#'
char debug_tag_filter_msg[256];
snprintf(debug_tag_filter_msg, sizeof(debug_tag_filter_msg), "DEBUG FILTER: Checking tag filter #%s", tag_name);
log_info(debug_tag_filter_msg);
if (!cJSON_IsArray(tag_filter)) {
continue; // Tag filter must be an array
}
@@ -434,28 +405,16 @@ int event_matches_filter(cJSON* event, subscription_filter_t* filter) {
const char* event_tag_name_str = cJSON_GetStringValue(event_tag_name);
const char* event_tag_value_str = cJSON_GetStringValue(event_tag_value);
char debug_event_tag_msg[256];
snprintf(debug_event_tag_msg, sizeof(debug_event_tag_msg), "DEBUG FILTER: Event tag: %s = %s", event_tag_name_str, event_tag_value_str);
log_info(debug_event_tag_msg);
// Check if tag name matches
if (strcmp(event_tag_name_str, tag_name) == 0) {
char debug_tag_name_match_msg[256];
snprintf(debug_tag_name_match_msg, sizeof(debug_tag_name_match_msg), "DEBUG FILTER: Tag name '%s' matches filter", tag_name);
log_info(debug_tag_name_match_msg);
// Check if any of the filter values match this tag value
cJSON* filter_value = NULL;
cJSON_ArrayForEach(filter_value, tag_filter) {
if (cJSON_IsString(filter_value)) {
const char* filter_value_str = cJSON_GetStringValue(filter_value);
char debug_filter_value_msg[256];
snprintf(debug_filter_value_msg, sizeof(debug_filter_value_msg), "DEBUG FILTER: Comparing event tag value '%s' with filter value '%s'", event_tag_value_str, filter_value_str);
log_info(debug_filter_value_msg);
// Support prefix matching for tag values
if (strncmp(event_tag_value_str, filter_value_str, strlen(filter_value_str)) == 0) {
tag_match = 1;
log_info("DEBUG FILTER: Tag value match found!");
break;
}
}
@@ -468,9 +427,6 @@ int event_matches_filter(cJSON* event, subscription_filter_t* filter) {
}
if (!tag_match) {
char debug_tag_fail_msg[256];
snprintf(debug_tag_fail_msg, sizeof(debug_tag_fail_msg), "DEBUG FILTER: Tag filter #%s failed - no match found", tag_name);
log_info(debug_tag_fail_msg);
return 0; // This tag filter didn't match, so the event doesn't match
}
}
@@ -482,40 +438,17 @@ int event_matches_filter(cJSON* event, subscription_filter_t* filter) {
// Check if an event matches any filter in a subscription (filters are OR'd together)
int event_matches_subscription(cJSON* event, subscription_t* subscription) {
if (!event || !subscription || !subscription->filters) {
char debug_msg[256];
snprintf(debug_msg, sizeof(debug_msg), "DEBUG MATCH: Subscription '%s' - invalid parameters (event: %p, subscription: %p, filters: %p)",
subscription ? subscription->id : "NULL", event, subscription, subscription ? subscription->filters : NULL);
log_info(debug_msg);
return 0;
}
char debug_start_msg[256];
snprintf(debug_start_msg, sizeof(debug_start_msg), "DEBUG MATCH: Checking subscription '%s' filters", subscription->id);
log_info(debug_start_msg);
subscription_filter_t* filter = subscription->filters;
int filter_index = 0;
while (filter) {
int filter_matches = event_matches_filter(event, filter);
char debug_filter_msg[256];
snprintf(debug_filter_msg, sizeof(debug_filter_msg), "DEBUG MATCH: Subscription '%s' filter %d - %s",
subscription->id, filter_index, filter_matches ? "MATCHES" : "no match");
log_info(debug_filter_msg);
if (filter_matches) {
char debug_match_msg[256];
snprintf(debug_match_msg, sizeof(debug_match_msg), "DEBUG MATCH: Subscription '%s' - MATCH FOUND", subscription->id);
log_info(debug_match_msg);
if (event_matches_filter(event, filter)) {
return 1; // Match found (OR logic)
}
filter = filter->next;
filter_index++;
}
char debug_no_match_msg[256];
snprintf(debug_no_match_msg, sizeof(debug_no_match_msg), "DEBUG MATCH: Subscription '%s' - NO MATCHES", subscription->id);
log_info(debug_no_match_msg);
return 0; // No filters matched
}
@@ -534,11 +467,6 @@ int broadcast_event_to_subscriptions(cJSON* event) {
if (expiration_enabled && filter_responses) {
time_t current_time = time(NULL);
if (is_event_expired(event, current_time)) {
char debug_msg[256];
cJSON* event_id_obj = cJSON_GetObjectItem(event, "id");
const char* event_id = event_id_obj ? cJSON_GetStringValue(event_id_obj) : "unknown";
snprintf(debug_msg, sizeof(debug_msg), "Skipping broadcast of expired event: %.16s", event_id);
log_info(debug_msg);
return 0; // Don't broadcast expired events
}
}
@@ -547,25 +475,8 @@ int broadcast_event_to_subscriptions(cJSON* event) {
pthread_mutex_lock(&g_subscription_manager.subscriptions_lock);
// Debug: Log total active subscriptions
int total_active = 0;
subscription_t* count_sub = g_subscription_manager.active_subscriptions;
while (count_sub) {
total_active++;
count_sub = count_sub->next;
}
char debug_total_msg[128];
snprintf(debug_total_msg, sizeof(debug_total_msg), "DEBUG BROADCAST: Broadcasting event to %d total active subscriptions", total_active);
log_info(debug_total_msg);
subscription_t* sub = g_subscription_manager.active_subscriptions;
while (sub) {
// Debug: Log each subscription being checked
char debug_sub_msg[256];
snprintf(debug_sub_msg, sizeof(debug_sub_msg), "DEBUG BROADCAST: Checking subscription '%s' (active: %d)", sub->id, sub->active);
log_info(debug_sub_msg);
if (sub->active && event_matches_subscription(event, sub)) {
// Create EVENT message for this subscription
cJSON* event_msg = cJSON_CreateArray();
@@ -606,15 +517,9 @@ int broadcast_event_to_subscriptions(cJSON* event) {
// Update global statistics
g_subscription_manager.total_events_broadcast += broadcasts;
pthread_mutex_unlock(&g_subscription_manager.subscriptions_lock);
if (broadcasts > 0) {
char debug_msg[256];
snprintf(debug_msg, sizeof(debug_msg), "Broadcasted event to %d subscriptions", broadcasts);
log_info(debug_msg);
}
return broadcasts;
}

View File

@@ -120,7 +120,6 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
// Handle HTTP requests
{
char *requested_uri = (char *)in;
log_info("HTTP request received");
// Check if this is an OPTIONS request
char method[16] = {0};
@@ -186,20 +185,12 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
// Handle HTTP body transmission for NIP-11 or embedded files
{
void* user_data = lws_wsi_user(wsi);
char debug_msg[256];
snprintf(debug_msg, sizeof(debug_msg), "HTTP_WRITEABLE: user_data=%p", user_data);
log_info(debug_msg);
if (user_data) {
int type = *(int*)user_data;
if (type == 0) {
// NIP-11
struct nip11_session_data* session_data = (struct nip11_session_data*)user_data;
snprintf(debug_msg, sizeof(debug_msg), "NIP-11: session_data=%p, type=%d, json_length=%zu, headers_sent=%d, body_sent=%d",
session_data, session_data->type, session_data->json_length, session_data->headers_sent, session_data->body_sent);
log_info(debug_msg);
if (session_data->headers_sent && !session_data->body_sent) {
snprintf(debug_msg, sizeof(debug_msg), "NIP-11: Attempting to send body, json_length=%zu", session_data->json_length);
log_info(debug_msg);
// Allocate buffer for JSON body transmission (no LWS_PRE needed for body)
unsigned char *json_buf = malloc(session_data->json_length);
if (!json_buf) {
@@ -210,7 +201,6 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
lws_set_wsi_user(wsi, NULL);
return -1;
}
log_info("NIP-11: Buffer allocated successfully");
// Copy JSON data to buffer
memcpy(json_buf, session_data->json_buffer, session_data->json_length);
@@ -280,24 +270,15 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
if (message) {
memcpy(message, in, len);
message[len] = '\0';
// Parse JSON message (this is the normal program flow)
cJSON* json = cJSON_Parse(message);
if (json && cJSON_IsArray(json)) {
// Log the complete parsed JSON message once
char* complete_message = cJSON_Print(json);
if (complete_message) {
char debug_msg[2048];
snprintf(debug_msg, sizeof(debug_msg),
"Received complete WebSocket message: %s", complete_message);
log_info(debug_msg);
free(complete_message);
}
// Get message type
cJSON* type = cJSON_GetArrayItem(json, 0);
if (type && cJSON_IsString(type)) {
const char* msg_type = cJSON_GetStringValue(type);
if (strcmp(msg_type, "EVENT") == 0) {
// Extract event for kind-specific NIP-42 authentication check
cJSON* event_obj = cJSON_GetArrayItem(json, 1);
@@ -305,19 +286,13 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
// Extract event kind for kind-specific NIP-42 authentication check
cJSON* kind_obj = cJSON_GetObjectItem(event_obj, "kind");
int event_kind = kind_obj && cJSON_IsNumber(kind_obj) ? (int)cJSON_GetNumberValue(kind_obj) : -1;
// Extract pubkey and event ID for debugging
cJSON* pubkey_obj = cJSON_GetObjectItem(event_obj, "pubkey");
cJSON* id_obj = cJSON_GetObjectItem(event_obj, "id");
const char* event_pubkey = pubkey_obj ? cJSON_GetStringValue(pubkey_obj) : "unknown";
const char* event_id = id_obj ? cJSON_GetStringValue(id_obj) : "unknown";
char debug_event_msg[512];
snprintf(debug_event_msg, sizeof(debug_event_msg),
"DEBUG EVENT: Processing kind %d event from pubkey %.16s... ID %.16s...",
event_kind, event_pubkey, event_id);
log_info(debug_event_msg);
// Check if NIP-42 authentication is required for this event kind or globally
int auth_required = is_nip42_auth_globally_required() || is_nip42_auth_required_for_kind(event_kind);
@@ -346,15 +321,8 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
}
}
char debug_auth_msg[256];
snprintf(debug_auth_msg, sizeof(debug_auth_msg),
"DEBUG AUTH: auth_required=%d, bypass_auth=%d, pss->authenticated=%d, event_kind=%d",
auth_required, bypass_auth, pss ? pss->authenticated : -1, event_kind);
log_info(debug_auth_msg);
if (pss && auth_required && !pss->authenticated && !bypass_auth) {
if (!pss->auth_challenge_sent) {
log_info("DEBUG AUTH: Sending NIP-42 authentication challenge");
send_nip42_auth_challenge(wsi, pss);
} else {
char auth_msg[256];
@@ -367,9 +335,6 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
}
send_notice_message(wsi, auth_msg);
log_warning("Event rejected: NIP-42 authentication required for kind");
char debug_msg[128];
snprintf(debug_msg, sizeof(debug_msg), "Auth required for kind %d", event_kind);
log_info(debug_msg);
}
cJSON_Delete(json);
free(message);
@@ -450,20 +415,13 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
return 0;
}
log_info("DEBUG VALIDATION: Starting unified validator");
// Call unified validator with JSON string
size_t event_json_len = strlen(event_json_str);
int validation_result = nostr_validate_unified_request(event_json_str, event_json_len);
// Map validation result to old result format (0 = success, -1 = failure)
int result = (validation_result == NOSTR_SUCCESS) ? 0 : -1;
char debug_validation_msg[256];
snprintf(debug_validation_msg, sizeof(debug_validation_msg),
"DEBUG VALIDATION: validation_result=%d, result=%d", validation_result, result);
log_info(debug_validation_msg);
// Generate error message based on validation result
char error_message[512] = {0};
if (result != 0) {
@@ -497,8 +455,6 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
snprintf(debug_error_msg, sizeof(debug_error_msg),
"DEBUG VALIDATION ERROR: %s", error_message);
log_warning(debug_error_msg);
} else {
log_info("DEBUG VALIDATION: Event validated successfully using unified validator");
}
// Cleanup event JSON string
@@ -545,8 +501,6 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
strncpy(error_message, "auth-required: protected event requires authentication", sizeof(error_message) - 1);
error_message[sizeof(error_message) - 1] = '\0';
log_warning("Protected event rejected: authentication required");
} else {
log_info("Protected event accepted: authenticated publisher");
}
}
}