v0.7.4 - Remove excessive debug logging from entire codebase - preserve user-facing error logging
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
217
src/config.c
217
src/config.c
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
71
src/main.c
71
src/main.c
@@ -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);
|
||||
|
||||
17
src/nip009.c
17
src/nip009.c
@@ -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);
|
||||
|
||||
91
src/nip011.c
91
src/nip011.c
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
29
src/nip013.c
29
src/nip013.c
@@ -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
|
||||
}
|
||||
16
src/nip040.c
16
src/nip040.c
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user