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

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

View File

@@ -1,6 +1,6 @@
# C-Nostr Relay # C-Nostr Relay
A high-performance Nostr relay implemented in C with SQLite backend, featuring a revolutionary **zero-configuration** approach using event-based configuration management. A high-performance Nostr relay implemented in C with SQLite backend, featuring nostr event-based management.
## Supported NIPs ## Supported NIPs
@@ -84,6 +84,7 @@ Use the web interface or send admin commands to customize:
**That's it!** Your relay is now running with zero configuration required. The event-based configuration system means you can adjust all settings through the web interface or admin API without editing config files. **That's it!** Your relay is now running with zero configuration required. The event-based configuration system means you can adjust all settings through the web interface or admin API without editing config files.
## Web Admin Interface ## Web Admin Interface
C-Relay includes a **built-in web-based administration interface** accessible at `http://localhost:8888/api/`. The interface provides: C-Relay includes a **built-in web-based administration interface** accessible at `http://localhost:8888/api/`. The interface provides:
@@ -96,6 +97,7 @@ C-Relay includes a **built-in web-based administration interface** accessible at
The web interface serves embedded static files with no external dependencies and includes proper CORS headers for browser compatibility. The web interface serves embedded static files with no external dependencies and includes proper CORS headers for browser compatibility.
## Administrator API ## Administrator API
C-Relay uses an innovative **event-based administration system** where all configuration and management commands are sent as signed Nostr events using the admin private key generated during first startup. All admin commands use **NIP-44 encrypted command arrays** for security and compatibility. C-Relay uses an innovative **event-based administration system** where all configuration and management commands are sent as signed Nostr events using the admin private key generated during first startup. All admin commands use **NIP-44 encrypted command arrays** for security and compatibility.
@@ -331,7 +333,7 @@ All admin commands return **signed EVENT responses** via WebSocket following sta
In addition to the above admin API, c-relay allows the administrator to direct message the relay to get information or control some settings. As long as the administrator is signed in with any nostr client that allows sending nip-17 direct messages (DMs), they can control the relay. In addition to the above admin API, c-relay allows the administrator to direct message the relay to get information or control some settings. As long as the administrator is signed in with any nostr client that allows sending nip-17 direct messages (DMs), they can control the relay.
The is possible because the relay is a full nostr citizen with it's own private and public key. The is possible because the relay is a full nostr citizen with it's own private and public key, and it knows the administrator's public key.

View File

@@ -50,9 +50,9 @@ if [ "$USE_DOCKER" = true ]; then
# Extract x86_64 binary # Extract x86_64 binary
sudo docker run --rm -v "$BUILD_DIR:/output" c-relay-static-builder-x86_64 \ sudo docker run --rm -v "$BUILD_DIR:/output" c-relay-static-builder-x86_64 \
sh -c "cp /c_relay_static_musl_x86_64 /output/" sh -c "cp /c_relay_static_musl_x86_64 /output/c_relay_static_x86_64"
echo "x86_64 static binary created: $BUILD_DIR/c_relay_static_musl_x86_64" echo "x86_64 static binary created: $BUILD_DIR/c_relay_static_x86_64"
# Build ARM64 static binary # Build ARM64 static binary
echo "Building ARM64 static binary with Docker..." echo "Building ARM64 static binary with Docker..."
@@ -65,9 +65,9 @@ if [ "$USE_DOCKER" = true ]; then
# Extract ARM64 binary # Extract ARM64 binary
sudo docker run --rm -v "$BUILD_DIR:/output" c-relay-static-builder-arm64 \ sudo docker run --rm -v "$BUILD_DIR:/output" c-relay-static-builder-arm64 \
sh -c "cp /c_relay_static_musl_x86_64 /output/c_relay_static_musl_arm64" sh -c "cp /c_relay_static_musl_arm64 /output/c_relay_static_arm64"
echo "ARM64 static binary created: $BUILD_DIR/c_relay_static_musl_arm64" echo "ARM64 static binary created: $BUILD_DIR/c_relay_static_arm64"
else else
# Native static build with regular gcc # Native static build with regular gcc
echo "Building static binary with gcc..." echo "Building static binary with gcc..."
@@ -108,8 +108,6 @@ else
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
echo "x86_64 static binary created: $BUILD_DIR/c_relay_static_x86_64" echo "x86_64 static binary created: $BUILD_DIR/c_relay_static_x86_64"
# Also create the musl-named version for compatibility
cp "$BUILD_DIR/c_relay_static_x86_64" "$BUILD_DIR/c_relay_static_musl_x86_64"
else else
echo "ERROR: Static build failed" echo "ERROR: Static build failed"
echo "This may be due to missing static libraries or incompatible library versions" echo "This may be due to missing static libraries or incompatible library versions"
@@ -120,7 +118,7 @@ fi
# Verify binaries # Verify binaries
echo "Verifying static binaries..." echo "Verifying static binaries..."
for binary in "$BUILD_DIR"/c_relay_static_musl_*; do for binary in "$BUILD_DIR"/c_relay_static_*; do
if [ -f "$binary" ]; then if [ -f "$binary" ]; then
echo "Binary: $(basename "$binary")" echo "Binary: $(basename "$binary")"
file "$binary" file "$binary"
@@ -141,6 +139,6 @@ done
echo "Static build complete!" echo "Static build complete!"
echo "Binaries available in: $BUILD_DIR/" echo "Binaries available in: $BUILD_DIR/"
ls -la "$BUILD_DIR"/c_relay_static_musl_* 2>/dev/null || echo "No static binaries found" ls -la "$BUILD_DIR"/c_relay_static_* 2>/dev/null || echo "No static binaries found"
echo "" echo ""
echo "These binaries should have minimal runtime dependencies and work across Linux distributions." echo "These binaries should have minimal runtime dependencies and work across Linux distributions."

View File

@@ -1 +1 @@
1567707 2377328

View File

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

View File

@@ -226,24 +226,18 @@ static int refresh_unified_cache_from_table(void) {
log_info("Refreshing unified configuration cache from database"); log_info("Refreshing unified configuration cache from database");
// Lock the cache for update (don't memset entire cache to avoid wiping relay_info) // 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); pthread_mutex_lock(&g_unified_cache.cache_lock);
log_info("DEBUG: Cache lock acquired");
// Load critical config values from table // 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"); const char* admin_pubkey = get_config_value_from_table("admin_pubkey");
if (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); 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'; g_unified_cache.admin_pubkey[sizeof(g_unified_cache.admin_pubkey) - 1] = '\0';
free((char*)admin_pubkey); free((char*)admin_pubkey);
} }
log_info("DEBUG: Loading relay_pubkey from table");
const char* relay_pubkey = get_config_value_from_table("relay_pubkey"); const char* relay_pubkey = get_config_value_from_table("relay_pubkey");
if (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); 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'; g_unified_cache.relay_pubkey[sizeof(g_unified_cache.relay_pubkey) - 1] = '\0';
free((char*)relay_pubkey); free((char*)relay_pubkey);
@@ -361,12 +355,10 @@ static int refresh_unified_cache_from_table(void) {
} }
// Set cache expiration // Set cache expiration
log_info("DEBUG: Setting cache expiration and validity");
int cache_timeout = get_cache_timeout(); int cache_timeout = get_cache_timeout();
g_unified_cache.cache_expires = time(NULL) + cache_timeout; g_unified_cache.cache_expires = time(NULL) + cache_timeout;
g_unified_cache.cache_valid = 1; g_unified_cache.cache_valid = 1;
log_info("DEBUG: Releasing cache lock");
pthread_mutex_unlock(&g_unified_cache.cache_lock); pthread_mutex_unlock(&g_unified_cache.cache_lock);
log_info("Unified configuration cache refreshed from database"); 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) // 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) { 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"); cJSON* kind_obj = cJSON_GetObjectItem(event, "kind");
if (!kind_obj || !cJSON_IsNumber(kind_obj)) { 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"); snprintf(error_message, error_size, "invalid: missing or invalid kind");
return -1; return -1;
} }
int kind = (int)cJSON_GetNumberValue(kind_obj); int kind = (int)cJSON_GetNumberValue(kind_obj);
log_info("DEBUG: Processing admin event");
printf(" Event kind: %d\n", kind); printf(" Event kind: %d\n", kind);
// Extract and log event details for debugging // Extract and log event details for debugging
cJSON* pubkey_obj = cJSON_GetObjectItem(event, "pubkey"); cJSON* pubkey_obj = cJSON_GetObjectItem(event, "pubkey");
cJSON* content_obj = cJSON_GetObjectItem(event, "content"); cJSON* content_obj = cJSON_GetObjectItem(event, "content");
cJSON* tags_obj = cJSON_GetObjectItem(event, "tags"); cJSON* tags_obj = cJSON_GetObjectItem(event, "tags");
const char* event_pubkey = pubkey_obj ? cJSON_GetStringValue(pubkey_obj) : "unknown"; const char* event_pubkey = pubkey_obj ? cJSON_GetStringValue(pubkey_obj) : "unknown";
const char* event_content = content_obj ? cJSON_GetStringValue(content_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(" Pubkey: %.16s...\n", event_pubkey ? event_pubkey : "null");
printf(" Content length: %zu\n", event_content ? strlen(event_content) : 0); printf(" Content length: %zu\n", event_content ? strlen(event_content) : 0);
printf(" Has tags: %s\n", tags_obj ? "yes" : "no"); printf(" Has tags: %s\n", tags_obj ? "yes" : "no");
if (tags_obj && cJSON_IsArray(tags_obj)) { if (tags_obj && cJSON_IsArray(tags_obj)) {
printf(" Tags count: %d\n", cJSON_GetArraySize(tags_obj)); printf(" Tags count: %d\n", cJSON_GetArraySize(tags_obj));
} }
// DEFENSE-IN-DEPTH: Use comprehensive admin authorization validation // DEFENSE-IN-DEPTH: Use comprehensive admin authorization validation
log_info("DEBUG: Checking admin authorization");
if (!is_authorized_admin_event(event)) { if (!is_authorized_admin_event(event)) {
// Log the unauthorized attempt for security monitoring // Log the unauthorized attempt for security monitoring
char log_msg[256]; char log_msg[256];
snprintf(log_msg, sizeof(log_msg), 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"); event_pubkey ? event_pubkey : "null");
log_warning(log_msg); log_warning(log_msg);
snprintf(error_message, error_size, "auth-required: not authorized admin"); snprintf(error_message, error_size, "auth-required: not authorized admin");
return -1; 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 // Route to appropriate handler based on kind
log_info("DEBUG: Routing to kind-specific handler");
switch (kind) { switch (kind) {
case 23456: // New ephemeral auth rules management 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); return process_admin_auth_event(event, error_message, error_size, wsi);
default: default:
log_error("DEBUG: Unsupported admin event kind"); log_error("Unsupported admin event kind");
printf(" Unsupported kind: %d\n", kind); printf(" Unsupported kind: %d\n", kind);
snprintf(error_message, error_size, "invalid: unsupported admin event kind %d", kind); snprintf(error_message, error_size, "invalid: unsupported admin event kind %d", kind);
return -1; 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 // Handle Kind 23456 auth rules management
int process_admin_auth_event(cJSON* event, char* error_message, size_t error_size, struct lws* wsi) { 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"); cJSON* kind_obj = cJSON_GetObjectItem(event, "kind");
int kind = kind_obj ? (int)cJSON_GetNumberValue(kind_obj) : 0; 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); printf(" Kind: %d\n", kind);
// Extract and log additional event details for debugging // Extract and log additional event details for debugging
cJSON* content_obj = cJSON_GetObjectItem(event, "content"); cJSON* content_obj = cJSON_GetObjectItem(event, "content");
cJSON* tags_obj = cJSON_GetObjectItem(event, "tags"); cJSON* tags_obj = cJSON_GetObjectItem(event, "tags");
const char* event_content = content_obj ? cJSON_GetStringValue(content_obj) : "unknown"; 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(" Content length: %zu\n", event_content ? strlen(event_content) : 0);
printf(" Has tags: %s\n", tags_obj ? "yes" : "no"); printf(" Has tags: %s\n", tags_obj ? "yes" : "no");
if (tags_obj && cJSON_IsArray(tags_obj)) { 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 // Route all Kind 23456 events through the unified handler
if (kind == 23456) { if (kind == 23456) {
log_info("DEBUG: Routing Kind 23456 to unified handler");
return handle_kind_23456_unified(event, error_message, error_size, wsi); 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); printf(" Unsupported kind: %d\n", kind);
snprintf(error_message, error_size, "invalid: unsupported auth event kind %d", kind); snprintf(error_message, error_size, "invalid: unsupported auth event kind %d", kind);
return -1; return -1;
@@ -2857,118 +2833,86 @@ int handle_kind_23456_unified(cJSON* event, char* error_message, size_t error_si
// Suppress unused parameter warning // Suppress unused parameter warning
(void)wsi; (void)wsi;
if (!event) { 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"); snprintf(error_message, error_size, "invalid: null event");
return -1; return -1;
} }
log_info("DEBUG: Processing Kind 23456 event through unified handler");
// Check if content is encrypted (NIP-44) // Check if content is encrypted (NIP-44)
cJSON* content_obj = cJSON_GetObjectItem(event, "content"); cJSON* content_obj = cJSON_GetObjectItem(event, "content");
if (!content_obj || !cJSON_IsString(content_obj)) { 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"); snprintf(error_message, error_size, "invalid: missing or invalid content");
return -1; return -1;
} }
const char* content = cJSON_GetStringValue(content_obj); 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; cJSON* decrypted_content = NULL;
// Check if content looks like NIP-44 encrypted content (base64 string, not JSON) // Check if content looks like NIP-44 encrypted content (base64 string, not JSON)
if (content && strlen(content) > 10 && content[0] != '[' && content[0] != '{') { 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 // Get relay private key for decryption
log_info("DEBUG: Retrieving relay private key for decryption");
char* relay_privkey = get_relay_private_key(); char* relay_privkey = get_relay_private_key();
if (!relay_privkey) { 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"); snprintf(error_message, error_size, "error: relay private key not available for decryption");
return -1; 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 // Get sender's pubkey from the event for NIP-44 decryption
cJSON* pubkey_obj = cJSON_GetObjectItem(event, "pubkey"); cJSON* pubkey_obj = cJSON_GetObjectItem(event, "pubkey");
if (!pubkey_obj || !cJSON_IsString(pubkey_obj)) { 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); free(relay_privkey);
snprintf(error_message, error_size, "invalid: missing sender pubkey in event"); snprintf(error_message, error_size, "invalid: missing sender pubkey in event");
return -1; return -1;
} }
const char* sender_pubkey = cJSON_GetStringValue(pubkey_obj); const char* sender_pubkey = cJSON_GetStringValue(pubkey_obj);
if (!sender_pubkey || strlen(sender_pubkey) != 64) { if (!sender_pubkey || strlen(sender_pubkey) != 64) {
log_error("DEBUG: Invalid sender pubkey format"); log_error("invalid: 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);
free(relay_privkey); free(relay_privkey);
snprintf(error_message, error_size, "invalid: invalid sender pubkey format"); snprintf(error_message, error_size, "invalid: invalid sender pubkey format");
return -1; return -1;
} }
log_info("DEBUG: Sender pubkey validated");
printf(" Sender pubkey: %.16s...\n", sender_pubkey);
// Convert relay private key from hex to bytes // 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]; unsigned char relay_privkey_bytes[32];
if (nostr_hex_to_bytes(relay_privkey, relay_privkey_bytes, 32) != NOSTR_SUCCESS) { 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); free(relay_privkey);
snprintf(error_message, error_size, "error: failed to convert relay private key"); snprintf(error_message, error_size, "error: failed to convert relay private key");
return -1; return -1;
} }
log_info("DEBUG: Relay private key converted successfully");
// Convert sender public key from hex to bytes // 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]; unsigned char sender_pubkey_bytes[32];
if (nostr_hex_to_bytes(sender_pubkey, sender_pubkey_bytes, 32) != NOSTR_SUCCESS) { 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); free(relay_privkey);
snprintf(error_message, error_size, "error: failed to convert sender public key"); snprintf(error_message, error_size, "error: failed to convert sender public key");
return -1; return -1;
} }
log_info("DEBUG: Sender public key converted successfully");
// Perform NIP-44 decryption (relay as recipient, admin as sender) // 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 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)); 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 // Clean up private key immediately after use
memset(relay_privkey_bytes, 0, 32); memset(relay_privkey_bytes, 0, 32);
free(relay_privkey); free(relay_privkey);
if (decrypt_result != NOSTR_SUCCESS) { if (decrypt_result != NOSTR_SUCCESS) {
log_error("DEBUG: NIP-44 decryption failed"); log_error("error: NIP-44 decryption failed");
printf(" Decryption result code: %d\n", decrypt_result);
snprintf(error_message, error_size, "error: NIP-44 decryption failed"); snprintf(error_message, error_size, "error: NIP-44 decryption failed");
return -1; 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) // 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); cJSON* potential_command_array = cJSON_Parse(decrypted_text);
if (potential_command_array && cJSON_IsArray(potential_command_array)) { 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 // Route to DM admin system
int dm_result = process_dm_admin_command(potential_command_array, event, error_message, error_size, wsi); int dm_result = process_dm_admin_command(potential_command_array, event, error_message, error_size, wsi);
cJSON_Delete(potential_command_array); 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) // 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 cJSON* inner_event = potential_command_array; // Reuse the parsed JSON
if (!inner_event || !cJSON_IsObject(inner_event)) { if (!inner_event || !cJSON_IsObject(inner_event)) {
log_error("DEBUG: Decrypted content is not valid inner event JSON"); log_error("error: decrypted content is not valid inner event JSON");
printf(" Decrypted content type: %s\n",
inner_event ? (cJSON_IsObject(inner_event) ? "object" : "other") : "null");
cJSON_Delete(inner_event); cJSON_Delete(inner_event);
snprintf(error_message, error_size, "error: decrypted content is not valid inner event JSON"); snprintf(error_message, error_size, "error: decrypted content is not valid inner event JSON");
return -1; 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 // Extract content from inner event
cJSON* inner_content_obj = cJSON_GetObjectItem(inner_event, "content"); cJSON* inner_content_obj = cJSON_GetObjectItem(inner_event, "content");
if (!inner_content_obj || !cJSON_IsString(inner_content_obj)) { 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); cJSON_Delete(inner_event);
snprintf(error_message, error_size, "error: inner event missing content field"); snprintf(error_message, error_size, "error: inner event missing content field");
return -1; return -1;
} }
const char* inner_content = cJSON_GetStringValue(inner_content_obj); 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) // 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); decrypted_content = cJSON_Parse(inner_content);
if (!decrypted_content || !cJSON_IsArray(decrypted_content)) { if (!decrypted_content || !cJSON_IsArray(decrypted_content)) {
log_error("DEBUG: Inner content is not valid JSON array"); log_error("error: inner content is not valid JSON array");
printf(" Inner content type: %s\n",
decrypted_content ? (cJSON_IsArray(decrypted_content) ? "array" : "other") : "null");
cJSON_Delete(inner_event); cJSON_Delete(inner_event);
snprintf(error_message, error_size, "error: inner content is not valid JSON array"); snprintf(error_message, error_size, "error: inner content is not valid JSON array");
return -1; 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 // Clean up inner event
cJSON_Delete(inner_event); cJSON_Delete(inner_event);
// Replace event content with decrypted command array for processing // Replace event content with decrypted command array for processing
log_info("DEBUG: Replacing event content with decrypted marker");
cJSON_DeleteItemFromObject(event, "content"); cJSON_DeleteItemFromObject(event, "content");
cJSON_AddStringToObject(event, "content", "decrypted"); 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 // Create new tags array with command tag first
cJSON* new_tags = cJSON_CreateArray(); cJSON* new_tags = cJSON_CreateArray();
// Add decrypted command as first tag // Add decrypted command as first tag
if (cJSON_GetArraySize(decrypted_content) > 0) { if (cJSON_GetArraySize(decrypted_content) > 0) {
log_info("DEBUG: Adding decrypted command as synthetic tag");
cJSON* first_item = cJSON_GetArrayItem(decrypted_content, 0); cJSON* first_item = cJSON_GetArrayItem(decrypted_content, 0);
if (cJSON_IsString(first_item)) { 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* command_tag = cJSON_CreateArray();
cJSON_AddItemToArray(command_tag, cJSON_Duplicate(first_item, 1)); 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++) { for (int i = 1; i < cJSON_GetArraySize(decrypted_content); i++) {
cJSON* item = cJSON_GetArrayItem(decrypted_content, i); cJSON* item = cJSON_GetArrayItem(decrypted_content, i);
if (item) { 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(command_tag, cJSON_Duplicate(item, 1));
} }
} }
cJSON_AddItemToArray(new_tags, command_tag); 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 { } 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 // Add existing tags
cJSON* existing_tags = cJSON_GetObjectItem(event, "tags"); cJSON* existing_tags = cJSON_GetObjectItem(event, "tags");
if (existing_tags && cJSON_IsArray(existing_tags)) { if (existing_tags && cJSON_IsArray(existing_tags)) {
printf(" Existing tags count: %d\n", cJSON_GetArraySize(existing_tags));
cJSON* tag = NULL; cJSON* tag = NULL;
cJSON_ArrayForEach(tag, existing_tags) { cJSON_ArrayForEach(tag, existing_tags) {
cJSON_AddItemToArray(new_tags, cJSON_Duplicate(tag, 1)); 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 // Replace event tags with new tags
cJSON_ReplaceItemInObject(event, "tags", new_tags); cJSON_ReplaceItemInObject(event, "tags", new_tags);
printf(" Final tag array size: %d\n", cJSON_GetArraySize(new_tags));
cJSON_Delete(decrypted_content); 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) // 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); const char* action_type = get_first_tag_name(event);
if (!action_type) { 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"); snprintf(error_message, error_size, "invalid: missing or invalid first tag");
return -1; return -1;
} }
log_info("DEBUG: Action type determined");
printf(" Action type: %s\n", action_type);
// Route to appropriate handler based on 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) { 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); const char* query_type = get_tag_value(event, action_type, 1);
if (!query_type) { 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"); snprintf(error_message, error_size, "invalid: missing auth_query type");
return -1; return -1;
} }
printf(" Query type: %s\n", query_type);
return handle_auth_query_unified(event, query_type, error_message, error_size, wsi); return handle_auth_query_unified(event, query_type, error_message, error_size, wsi);
} }
else if (strcmp(action_type, "config_query") == 0) { 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); const char* query_type = get_tag_value(event, action_type, 1);
if (!query_type) { 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"); snprintf(error_message, error_size, "invalid: missing config_query type");
return -1; return -1;
} }
printf(" Query type: %s\n", query_type);
return handle_config_query_unified(event, query_type, error_message, error_size, wsi); return handle_config_query_unified(event, query_type, error_message, error_size, wsi);
} }
else if (strcmp(action_type, "config_set") == 0) { 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_key = get_tag_value(event, action_type, 1);
const char* config_value = get_tag_value(event, action_type, 2); const char* config_value = get_tag_value(event, action_type, 2);
if (!config_key || !config_value) { 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"); snprintf(error_message, error_size, "invalid: missing config_set key or value");
return -1; 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); return handle_config_set_unified(event, config_key, config_value, error_message, error_size, wsi);
} }
else if (strcmp(action_type, "config_update") == 0) { 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); return handle_config_update_unified(event, error_message, error_size, wsi);
} }
else if (strcmp(action_type, "system_command") == 0) { 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); const char* command = get_tag_value(event, action_type, 1);
if (!command) { 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"); snprintf(error_message, error_size, "invalid: missing system_command type");
return -1; return -1;
} }
printf(" Command: %s\n", command);
return handle_system_command_unified(event, command, error_message, error_size, wsi); return handle_system_command_unified(event, command, error_message, error_size, wsi);
} }
else if (strcmp(action_type, "stats_query") == 0) { 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); return handle_stats_query_unified(event, error_message, error_size, wsi);
} }
else if (strcmp(action_type, "whitelist") == 0 || strcmp(action_type, "blacklist") == 0) { 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) // Handle auth rule modifications (existing logic from process_admin_auth_event)
return handle_auth_rule_modification_unified(event, error_message, error_size, wsi); return handle_auth_rule_modification_unified(event, error_message, error_size, wsi);
} }
else { else {
log_error("DEBUG: Unknown Kind 23456 action type"); char error_msg[256];
printf(" Unknown action: %s\n", action_type); 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); snprintf(error_message, error_size, "invalid: unknown Kind 23456 action type '%s'", action_type);
return -1; return -1;
} }

View File

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

View File

@@ -300,59 +300,48 @@ int init_database(const char* database_path_override) {
sqlite3_finalize(check_stmt); sqlite3_finalize(check_stmt);
if (has_events_table) { if (has_events_table) {
log_info("Database schema already exists, checking version");
// Check existing schema version and migrate if needed // Check existing schema version and migrate if needed
const char* version_sql = "SELECT value FROM schema_info WHERE key = 'version'"; const char* version_sql = "SELECT value FROM schema_info WHERE key = 'version'";
sqlite3_stmt* version_stmt; sqlite3_stmt* version_stmt;
const char* db_version = NULL; const char* db_version = NULL;
int needs_migration = 0; int needs_migration = 0;
if (sqlite3_prepare_v2(g_db, version_sql, -1, &version_stmt, NULL) == SQLITE_OK) { if (sqlite3_prepare_v2(g_db, version_sql, -1, &version_stmt, NULL) == SQLITE_OK) {
if (sqlite3_step(version_stmt) == SQLITE_ROW) { if (sqlite3_step(version_stmt) == SQLITE_ROW) {
db_version = (char*)sqlite3_column_text(version_stmt, 0); 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 // Check if migration is needed
if (!db_version || strcmp(db_version, "5") == 0) { if (!db_version || strcmp(db_version, "5") == 0) {
needs_migration = 1; needs_migration = 1;
log_info("Database migration needed: v5 -> v6 (adding auth_rules table)");
} else if (strcmp(db_version, "6") == 0) { } 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) { } else if (strcmp(db_version, EMBEDDED_SCHEMA_VERSION) == 0) {
log_info("Database is at current schema version"); // Database is at current schema version
} else { } else {
char warning_msg[256]; char warning_msg[256];
snprintf(warning_msg, sizeof(warning_msg), "Unknown database schema version: %s", db_version); snprintf(warning_msg, sizeof(warning_msg), "Unknown database schema version: %s", db_version);
log_warning(warning_msg); log_warning(warning_msg);
} }
} else { } else {
log_info("Database exists but no version information found, assuming migration needed");
needs_migration = 1; needs_migration = 1;
} }
sqlite3_finalize(version_stmt); sqlite3_finalize(version_stmt);
} else { } else {
log_info("Cannot read schema version, assuming migration needed");
needs_migration = 1; needs_migration = 1;
} }
// Perform migration if needed // Perform migration if needed
if (needs_migration) { if (needs_migration) {
log_info("Performing database schema migration to v6");
// Check if auth_rules table already exists // 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'"; const char* check_auth_rules_sql = "SELECT name FROM sqlite_master WHERE type='table' AND name='auth_rules'";
sqlite3_stmt* check_stmt; sqlite3_stmt* check_stmt;
int has_auth_rules = 0; int has_auth_rules = 0;
if (sqlite3_prepare_v2(g_db, check_auth_rules_sql, -1, &check_stmt, NULL) == SQLITE_OK) { 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); has_auth_rules = (sqlite3_step(check_stmt) == SQLITE_ROW);
sqlite3_finalize(check_stmt); sqlite3_finalize(check_stmt);
} }
if (!has_auth_rules) { if (!has_auth_rules) {
// Add auth_rules table matching sql_schema.h // Add auth_rules table matching sql_schema.h
const char* create_auth_rules_sql = const char* create_auth_rules_sql =
@@ -398,7 +387,7 @@ int init_database(const char* database_path_override) {
} }
log_success("Created auth_rules indexes"); log_success("Created auth_rules indexes");
} else { } else {
log_info("auth_rules table already exists, skipping creation"); // auth_rules table already exists, skipping creation
} }
// Update schema version to v6 // Update schema version to v6
@@ -421,8 +410,7 @@ int init_database(const char* database_path_override) {
} }
} else { } else {
// Initialize database schema using embedded SQL // Initialize database schema using embedded SQL
log_info("Initializing database schema from embedded SQL");
// Execute the embedded schema SQL // Execute the embedded schema SQL
char* error_msg = NULL; char* error_msg = NULL;
rc = sqlite3_exec(g_db, EMBEDDED_SCHEMA_SQL, NULL, NULL, &error_msg); 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_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 { } else {
log_error("Failed to check existing database schema"); 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) { 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)) { if (!cJSON_IsArray(filters)) {
log_error("REQ filters is not an array"); log_error("REQ filters is not an array");
return 0; return 0;
@@ -794,11 +774,6 @@ int handle_req_message(const char* sub_id, cJSON* filters, struct lws *wsi, stru
cJSON_Delete(filters_array); 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 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 // Default limit to prevent excessive queries
snprintf(sql_ptr, remaining, " LIMIT 500"); 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 // Execute query and send events
sqlite3_stmt* stmt; sqlite3_stmt* stmt;
int rc = sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL); 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); time_t current_time = time(NULL);
if (is_event_expired(event, current_time)) { if (is_event_expired(event, current_time)) {
// Skip this expired event // 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); cJSON_Delete(event);
continue; continue;
} }
@@ -1156,18 +1121,10 @@ int handle_req_message(const char* sub_id, cJSON* filters, struct lws *wsi, stru
cJSON_Delete(event_msg); cJSON_Delete(event_msg);
events_sent++; 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); 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; 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) { if (!targets_this_relay) {
// Admin event for different relay - not an error, just not for us // 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"); snprintf(error_buffer, error_buffer_size, "Admin event not targeting this relay");
return -1; return -1;
} }
@@ -1500,7 +1456,6 @@ int main(int argc, char* argv[]) {
// Handle configuration setup after database is initialized // Handle configuration setup after database is initialized
// Always populate defaults directly in config table (abandoning legacy event signing) // 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 // Populate default config values in table
if (populate_default_config_values() != 0) { 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"); log_success("Relay pubkey stored in config table for first-time startup");
} }
} else { } else {
log_info("Existing relay detected");
// Find existing database file // Find existing database file
char** existing_files = find_existing_db_files(); char** existing_files = find_existing_db_files();
if (!existing_files || !existing_files[0]) { 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 // Store both admin and relay pubkeys in config table for unified cache
if (admin_pubkey && strlen(admin_pubkey) == 64) { if (admin_pubkey && strlen(admin_pubkey) == 64) {
set_config_value_in_table("admin_pubkey", admin_pubkey, "string", "Administrator public key", "authentication", 0); 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) { if (relay_pubkey && strlen(relay_pubkey) == 64) {
set_config_value_in_table("relay_pubkey", relay_pubkey, "string", "Relay public key", "relay", 0); 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); cJSON_Delete(config_event);

View File

@@ -142,11 +142,7 @@ int handle_deletion_request(cJSON* event, char* error_message, size_t error_size
if (store_event(event) != 0) { if (store_event(event) != 0) {
log_warning("Failed to store deletion request event"); 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 error_message[0] = '\0'; // Success - empty error message
return 0; 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) { if (sqlite3_step(delete_stmt) == SQLITE_DONE && sqlite3_changes(g_db) > 0) {
deleted_count++; 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); sqlite3_finalize(delete_stmt);
} }
@@ -211,9 +203,6 @@ int delete_events_by_id(const char* requester_pubkey, cJSON* event_ids) {
} }
} else { } else {
sqlite3_finalize(check_stmt); 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); int changes = sqlite3_changes(g_db);
if (changes > 0) { if (changes > 0) {
deleted_count += changes; 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); sqlite3_finalize(delete_stmt);

View File

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

View File

@@ -27,7 +27,6 @@ struct pow_config {
// Initialize PoW configuration using configuration system // Initialize PoW configuration using configuration system
void init_pow_config() { void init_pow_config() {
log_info("Initializing NIP-13 Proof of Work configuration");
// Get all config values first (without holding mutex to avoid deadlock) // Get all config values first (without holding mutex to avoid deadlock)
int pow_enabled = get_config_bool("pow_enabled", 1); 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.reject_lower_targets = 1;
g_unified_cache.pow_config.strict_format = 1; g_unified_cache.pow_config.strict_format = 1;
g_unified_cache.pow_config.anti_spam_mode = 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) { } else if (strcmp(pow_mode, "full") == 0) {
g_unified_cache.pow_config.validation_flags = NOSTR_POW_VALIDATE_FULL; g_unified_cache.pow_config.validation_flags = NOSTR_POW_VALIDATE_FULL;
g_unified_cache.pow_config.require_nonce_tag = 1; g_unified_cache.pow_config.require_nonce_tag = 1;
log_info("PoW configured in full validation mode");
} else if (strcmp(pow_mode, "basic") == 0) { } else if (strcmp(pow_mode, "basic") == 0) {
g_unified_cache.pow_config.validation_flags = NOSTR_POW_VALIDATE_BASIC; 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) { } else if (strcmp(pow_mode, "disabled") == 0) {
g_unified_cache.pow_config.enabled = 0; g_unified_cache.pow_config.enabled = 0;
log_info("PoW validation disabled via configuration");
} }
free((char*)pow_mode); // Free dynamically allocated string free((char*)pow_mode); // Free dynamically allocated string
} else { } else {
// Default to basic mode // Default to basic mode
g_unified_cache.pow_config.validation_flags = NOSTR_POW_VALIDATE_BASIC; 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); 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; 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 return 0; // Success
} }

View File

@@ -34,7 +34,6 @@ void log_warning(const char* message);
// Initialize expiration configuration using configuration system // Initialize expiration configuration using configuration system
void init_expiration_config() { void init_expiration_config() {
log_info("Initializing NIP-40 Expiration Timestamp configuration");
// Get all config values first (without holding mutex to avoid deadlock) // Get all config values first (without holding mutex to avoid deadlock)
int expiration_enabled = get_config_bool("expiration_enabled", 1); int expiration_enabled = get_config_bool("expiration_enabled", 1);
@@ -56,15 +55,6 @@ void init_expiration_config() {
g_expiration_config.grace_period = 300; 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 // 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"); log_warning("Event rejected: expired timestamp");
return -1; return -1;
} else { } else {
// In non-strict mode, log but allow expired events // In non-strict mode, allow expired events
char debug_msg[256];
snprintf(debug_msg, sizeof(debug_msg),
"Accepting expired event (strict_mode disabled)");
log_info(debug_msg);
} }
} }

View File

@@ -83,10 +83,6 @@ void send_nip42_auth_challenge(struct lws* wsi, struct per_session_data* pss) {
free(msg_str); free(msg_str);
} }
cJSON_Delete(auth_msg); 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 // Handle NIP-42 signed authentication event from client

View File

@@ -139,21 +139,6 @@ struct {
char reason[500]; // specific reason string char reason[500]; // specific reason string
} g_last_rule_violation = {0}; } 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 // 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 // Initialize nostr_core_lib if not already done
if (nostr_crypto_init() != NOSTR_SUCCESS) { if (nostr_crypto_init() != NOSTR_SUCCESS) {
validator_debug_log(
"VALIDATOR: Failed to initialize nostr crypto system\n");
return NOSTR_ERROR_CRYPTO_INIT; return NOSTR_ERROR_CRYPTO_INIT;
} }
// Load initial configuration from database // Load initial configuration from database
int result = reload_auth_config(); int result = reload_auth_config();
if (result != NOSTR_SUCCESS) { if (result != NOSTR_SUCCESS) {
validator_debug_log(
"VALIDATOR: Failed to load configuration from database\n");
return result; 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_challenge_manager.last_cleanup = time(NULL);
g_validator_initialized = 1; g_validator_initialized = 1;
validator_debug_log(
"VALIDATOR: Request validator initialized successfully\n");
return NOSTR_SUCCESS; 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 // 1. Null Pointer Checks - Reject malformed requests instantly
if (!json_string || json_length == 0) { if (!json_string || json_length == 0) {
validator_debug_log("VALIDATOR_DEBUG: STEP 1 FAILED - Null input\n");
return NOSTR_ERROR_INVALID_INPUT; return NOSTR_ERROR_INVALID_INPUT;
} }
// 2. Initialization Check - Verify system is properly initialized // 2. Initialization Check - Verify system is properly initialized
if (!g_validator_initialized) { if (!g_validator_initialized) {
validator_debug_log("VALIDATOR_DEBUG: STEP 2 FAILED - Validator not initialized\n");
return NOSTR_ERROR_INVALID_INPUT; return NOSTR_ERROR_INVALID_INPUT;
} }
// 3. Parse JSON string to cJSON event object // 3. Parse JSON string to cJSON event object
cJSON *event = cJSON_ParseWithLength(json_string, json_length); cJSON *event = cJSON_ParseWithLength(json_string, json_length);
if (!event) { if (!event) {
validator_debug_log("VALIDATOR_DEBUG: STEP 3 FAILED - Failed to parse JSON event\n");
return NOSTR_ERROR_INVALID_INPUT; 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) || !tags || !cJSON_IsArray(tags) ||
!content || !cJSON_IsString(content) || !content || !cJSON_IsString(content) ||
!sig || !cJSON_IsString(sig)) { !sig || !cJSON_IsString(sig)) {
validator_debug_log("VALIDATOR_DEBUG: STEP 4 FAILED - Invalid event structure\n");
cJSON_Delete(event); cJSON_Delete(event);
return NOSTR_ERROR_INVALID_INPUT; return NOSTR_ERROR_INVALID_INPUT;
} }
int event_kind = (int)cJSON_GetNumberValue(kind); int event_kind = (int)cJSON_GetNumberValue(kind);
// 5. Check configuration using unified cache // 5. Check configuration using unified cache
int auth_required = nostr_auth_rules_enabled(); 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 // 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 // 6. Nostr Event Structure Validation using nostr_core_lib
int validation_result = nostr_validate_event(event); int validation_result = nostr_validate_event(event);
if (validation_result != NOSTR_SUCCESS) { 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); cJSON_Delete(event);
return validation_result; return validation_result;
} }
validator_debug_log("VALIDATOR_DEBUG: STEP 6 PASSED - Event structure and signature valid\n");
// 7. Extract pubkey for rule evaluation // 7. Extract pubkey for rule evaluation
const char *event_pubkey = cJSON_GetStringValue(pubkey); const char *event_pubkey = cJSON_GetStringValue(pubkey);
if (!event_pubkey || strlen(event_pubkey) != 64) { if (!event_pubkey || strlen(event_pubkey) != 64) {
validator_debug_log("VALIDATOR_DEBUG: STEP 7 FAILED - Invalid pubkey format\n");
cJSON_Delete(event); cJSON_Delete(event);
return NOSTR_ERROR_EVENT_INVALID_PUBKEY; 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 // PHASE 3: EVENT KIND SPECIFIC VALIDATION
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
// 8. Handle NIP-42 authentication challenge events (kind 22242) // 8. Handle NIP-42 authentication challenge events (kind 22242)
if (event_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 // Check NIP-42 mode using unified cache
const char* nip42_enabled = get_config_value("nip42_auth_enabled"); const char* nip42_enabled = get_config_value("nip42_auth_enabled");
if (nip42_enabled && strcmp(nip42_enabled, "false") == 0) { 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); free((char*)nip42_enabled);
cJSON_Delete(event); cJSON_Delete(event);
return NOSTR_ERROR_NIP42_DISABLED; 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 // TODO: Implement full NIP-42 challenge validation
// For now, accept all valid NIP-42 events // 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); cJSON_Delete(event);
return NOSTR_SUCCESS; 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 // 9. Check if authentication rules are enabled
if (!auth_required) { if (!auth_required) {
validator_debug_log("VALIDATOR_DEBUG: STEP 9 - Authentication disabled, skipping database auth rules\n");
} else { } else {
// 10. Check database authentication rules (only if auth enabled) // 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 // Create operation string with event kind for more specific rule matching
char operation_str[64]; 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 // If generic event check fails, try specific event kind check
rules_result = check_database_auth_rules(event_pubkey, operation_str, NULL); rules_result = check_database_auth_rules(event_pubkey, operation_str, NULL);
if (rules_result != NOSTR_SUCCESS) { 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); cJSON_Delete(event);
return rules_result; 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); pthread_mutex_unlock(&g_unified_cache.cache_lock);
if (pow_enabled && pow_min_difficulty > 0) { 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; nostr_pow_result_t pow_result;
int pow_validation_result = nostr_validate_pow(event, pow_min_difficulty, int pow_validation_result = nostr_validate_pow(event, pow_min_difficulty,
pow_validation_flags, &pow_result); pow_validation_flags, &pow_result);
if (pow_validation_result != NOSTR_SUCCESS) { 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); cJSON_Delete(event);
return pow_validation_result; 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 // 12. NIP-40 Expiration validation
// Always check expiration tags if present (following NIP-40 specification) // 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 *expiration_tag = NULL;
cJSON *tags_array = cJSON_GetObjectItem(event, "tags"); cJSON *tags_array = cJSON_GetObjectItem(event, "tags");
if (tags_array && cJSON_IsArray(tags_array)) { if (tags_array && cJSON_IsArray(tags_array)) {
cJSON *tag = NULL; cJSON *tag = NULL;
cJSON_ArrayForEach(tag, tags_array) { cJSON_ArrayForEach(tag, tags_array) {
if (!cJSON_IsArray(tag)) continue; if (!cJSON_IsArray(tag)) continue;
cJSON *tag_name = cJSON_GetArrayItem(tag, 0); cJSON *tag_name = cJSON_GetArrayItem(tag, 0);
if (!tag_name || !cJSON_IsString(tag_name)) continue; if (!tag_name || !cJSON_IsString(tag_name)) continue;
const char *tag_name_str = cJSON_GetStringValue(tag_name); const char *tag_name_str = cJSON_GetStringValue(tag_name);
if (strcmp(tag_name_str, "expiration") == 0) { if (strcmp(tag_name_str, "expiration") == 0) {
cJSON *tag_value = cJSON_GetArrayItem(tag, 1); 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) { if (expiration_tag) {
const char *expiration_str = cJSON_GetStringValue(expiration_tag); const char *expiration_str = cJSON_GetStringValue(expiration_tag);
// Validate that the expiration string contains only digits (and optional leading whitespace) // Validate that the expiration string contains only digits (and optional leading whitespace)
const char* p = expiration_str; const char* p = expiration_str;
// Skip leading whitespace // Skip leading whitespace
while (*p == ' ' || *p == '\t') p++; while (*p == ' ' || *p == '\t') p++;
// Check if we have at least one digit // Check if we have at least one digit
if (*p == '\0') { if (*p == '\0') {
validator_debug_log("VALIDATOR_DEBUG: STEP 12 SKIPPED - Empty expiration tag value, ignoring\n");
} else { } else {
// Validate that all remaining characters are digits // Validate that all remaining characters are digits
const char* digit_start = p; const char* digit_start = p;
while (*p >= '0' && *p <= '9') p++; while (*p >= '0' && *p <= '9') p++;
// If we didn't consume the entire string or found no digits, it's malformed // If we didn't consume the entire string or found no digits, it's malformed
if (*p != '\0' || p == digit_start) { 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 { } else {
// Valid numeric string, parse and check expiration // Valid numeric string, parse and check expiration
time_t expiration_time = (time_t)atol(expiration_str); time_t expiration_time = (time_t)atol(expiration_str);
time_t now = time(NULL); time_t now = time(NULL);
int grace_period = get_config_int("nip40_expiration_grace_period", 60); int grace_period = get_config_int("nip40_expiration_grace_period", 60);
if (expiration_time > 0 && now > expiration_time + grace_period) { 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); cJSON_Delete(event);
return NOSTR_ERROR_EVENT_EXPIRED; 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 // All validations passed
validator_debug_log("VALIDATOR_DEBUG: STEP 13 PASSED - All validations complete, event ACCEPTED\n");
cJSON_Delete(event); cJSON_Delete(event);
return NOSTR_SUCCESS; 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) { void nostr_request_validator_force_cache_refresh(void) {
// Use unified cache refresh from config.c // Use unified cache refresh from config.c
force_config_cache_refresh(); 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) { static int reload_auth_config(void) {
// Configuration is now handled by the unified cache in config.c // 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; return NOSTR_SUCCESS;
} }
@@ -598,35 +512,23 @@ static int reload_auth_config(void) {
* Check database authentication rules for the request * Check database authentication rules for the request
* Implements the 6-step rule evaluation engine from AUTH_API.md * 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) { const char *resource_hash) {
sqlite3 *db = NULL; sqlite3 *db = NULL;
sqlite3_stmt *stmt = NULL; sqlite3_stmt *stmt = NULL;
int rc; int rc;
if (!pubkey) { if (!pubkey) {
validator_debug_log(
"VALIDATOR_DEBUG: RULES ENGINE - Missing pubkey for rule evaluation\n");
return NOSTR_ERROR_INVALID_INPUT; 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 // Open database using global database path
if (strlen(g_database_path) == 0) { 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 return NOSTR_SUCCESS; // Default allow on DB error
} }
rc = sqlite3_open_v2(g_database_path, &db, SQLITE_OPEN_READONLY, NULL); rc = sqlite3_open_v2(g_database_path, &db, SQLITE_OPEN_READONLY, NULL);
if (rc != SQLITE_OK) { if (rc != SQLITE_OK) {
validator_debug_log(
"VALIDATOR_DEBUG: RULES ENGINE - Failed to open database\n");
return NOSTR_SUCCESS; // Default allow on DB error 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) { if (sqlite3_step(stmt) == SQLITE_ROW) {
const char *action = (const char *)sqlite3_column_text(stmt, 1); 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 // Set specific violation details for status code mapping
strcpy(g_last_rule_violation.violation_type, "pubkey_blacklist"); 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); sqlite3_finalize(stmt);
} }
validator_debug_log("VALIDATOR_DEBUG: RULES ENGINE - STEP 1 PASSED - Pubkey "
"not blacklisted\n");
// Step 2: Check hash blacklist // Step 2: Check hash blacklist
if (resource_hash) { if (resource_hash) {
@@ -673,14 +566,6 @@ int check_database_auth_rules(const char *pubkey, const char *operation,
if (sqlite3_step(stmt) == SQLITE_ROW) { if (sqlite3_step(stmt) == SQLITE_ROW) {
const char *action = (const char *)sqlite3_column_text(stmt, 1); 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 // Set specific violation details for status code mapping
strcpy(g_last_rule_violation.violation_type, "hash_blacklist"); 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); 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 // 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); sqlite3_bind_text(stmt, 1, pubkey, -1, SQLITE_STATIC);
if (sqlite3_step(stmt) == SQLITE_ROW) { 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_finalize(stmt);
sqlite3_close(db); sqlite3_close(db);
return NOSTR_SUCCESS; // Allow whitelisted pubkey return NOSTR_SUCCESS; // Allow whitelisted pubkey
} }
sqlite3_finalize(stmt); 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 // Step 4: Check if any whitelist rules exist - if yes, deny by default
const char *whitelist_exists_sql = 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) { if (sqlite3_step(stmt) == SQLITE_ROW) {
int whitelist_count = sqlite3_column_int(stmt, 0); int whitelist_count = sqlite3_column_int(stmt, 0);
if (whitelist_count > 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 // Set specific violation details for status code mapping
strcpy(g_last_rule_violation.violation_type, "whitelist_violation"); strcpy(g_last_rule_violation.violation_type, "whitelist_violation");
strcpy(g_last_rule_violation.reason, strcpy(g_last_rule_violation.reason,
@@ -750,12 +617,8 @@ int check_database_auth_rules(const char *pubkey, const char *operation,
} }
sqlite3_finalize(stmt); sqlite3_finalize(stmt);
} }
validator_debug_log("VALIDATOR_DEBUG: RULES ENGINE - STEP 4 PASSED - No "
"whitelist restrictions apply\n");
sqlite3_close(db); 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 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; 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->expires_at = now + g_challenge_manager.timeout_seconds;
entry->active = 1; 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; return NOSTR_SUCCESS;
} }

View File

@@ -209,12 +209,7 @@ int add_subscription_to_manager(subscription_t* sub) {
// Log subscription creation to database // Log subscription creation to database
log_subscription_created(sub); 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; 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 events sent counter before freeing
update_subscription_events_sent(sub_id, sub->events_sent); 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); free_subscription(sub);
return 0; return 0;
} }
@@ -274,34 +264,24 @@ int event_matches_filter(cJSON* event, subscription_filter_t* filter) {
if (filter->kinds && cJSON_IsArray(filter->kinds)) { if (filter->kinds && cJSON_IsArray(filter->kinds)) {
cJSON* event_kind = cJSON_GetObjectItem(event, "kind"); cJSON* event_kind = cJSON_GetObjectItem(event, "kind");
if (!event_kind || !cJSON_IsNumber(event_kind)) { if (!event_kind || !cJSON_IsNumber(event_kind)) {
log_info("DEBUG FILTER: kinds filter present but event has no valid kind");
return 0; return 0;
} }
int event_kind_val = (int)cJSON_GetNumberValue(event_kind); int event_kind_val = (int)cJSON_GetNumberValue(event_kind);
int kind_match = 0; 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* kind_item = NULL;
cJSON_ArrayForEach(kind_item, filter->kinds) { cJSON_ArrayForEach(kind_item, filter->kinds) {
if (cJSON_IsNumber(kind_item)) { if (cJSON_IsNumber(kind_item)) {
int filter_kind = (int)cJSON_GetNumberValue(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) { if (filter_kind == event_kind_val) {
kind_match = 1; kind_match = 1;
log_info("DEBUG FILTER: Kind match found!");
break; break;
} }
} }
} }
if (!kind_match) { if (!kind_match) {
log_info("DEBUG FILTER: No kind match - filter fails");
return 0; 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)) { if (filter->tag_filters && cJSON_IsObject(filter->tag_filters)) {
cJSON* event_tags = cJSON_GetObjectItem(event, "tags"); cJSON* event_tags = cJSON_GetObjectItem(event, "tags");
if (!event_tags || !cJSON_IsArray(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 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 // Check each tag filter
cJSON* tag_filter = NULL; cJSON* tag_filter = NULL;
cJSON_ArrayForEach(tag_filter, filter->tag_filters) { 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 '#' 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)) { if (!cJSON_IsArray(tag_filter)) {
continue; // Tag filter must be an array 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_name_str = cJSON_GetStringValue(event_tag_name);
const char* event_tag_value_str = cJSON_GetStringValue(event_tag_value); 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 // Check if tag name matches
if (strcmp(event_tag_name_str, tag_name) == 0) { 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 // Check if any of the filter values match this tag value
cJSON* filter_value = NULL; cJSON* filter_value = NULL;
cJSON_ArrayForEach(filter_value, tag_filter) { cJSON_ArrayForEach(filter_value, tag_filter) {
if (cJSON_IsString(filter_value)) { if (cJSON_IsString(filter_value)) {
const char* filter_value_str = cJSON_GetStringValue(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 // Support prefix matching for tag values
if (strncmp(event_tag_value_str, filter_value_str, strlen(filter_value_str)) == 0) { if (strncmp(event_tag_value_str, filter_value_str, strlen(filter_value_str)) == 0) {
tag_match = 1; tag_match = 1;
log_info("DEBUG FILTER: Tag value match found!");
break; break;
} }
} }
@@ -468,9 +427,6 @@ int event_matches_filter(cJSON* event, subscription_filter_t* filter) {
} }
if (!tag_match) { 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 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) // Check if an event matches any filter in a subscription (filters are OR'd together)
int event_matches_subscription(cJSON* event, subscription_t* subscription) { int event_matches_subscription(cJSON* event, subscription_t* subscription) {
if (!event || !subscription || !subscription->filters) { 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; 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; subscription_filter_t* filter = subscription->filters;
int filter_index = 0;
while (filter) { while (filter) {
int filter_matches = event_matches_filter(event, filter); if (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);
return 1; // Match found (OR logic) return 1; // Match found (OR logic)
} }
filter = filter->next; 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 return 0; // No filters matched
} }
@@ -534,11 +467,6 @@ int broadcast_event_to_subscriptions(cJSON* event) {
if (expiration_enabled && filter_responses) { if (expiration_enabled && filter_responses) {
time_t current_time = time(NULL); time_t current_time = time(NULL);
if (is_event_expired(event, current_time)) { 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 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); 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; subscription_t* sub = g_subscription_manager.active_subscriptions;
while (sub) { 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)) { if (sub->active && event_matches_subscription(event, sub)) {
// Create EVENT message for this subscription // Create EVENT message for this subscription
cJSON* event_msg = cJSON_CreateArray(); cJSON* event_msg = cJSON_CreateArray();
@@ -606,15 +517,9 @@ int broadcast_event_to_subscriptions(cJSON* event) {
// Update global statistics // Update global statistics
g_subscription_manager.total_events_broadcast += broadcasts; g_subscription_manager.total_events_broadcast += broadcasts;
pthread_mutex_unlock(&g_subscription_manager.subscriptions_lock); 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; return broadcasts;
} }

View File

@@ -120,7 +120,6 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
// Handle HTTP requests // Handle HTTP requests
{ {
char *requested_uri = (char *)in; char *requested_uri = (char *)in;
log_info("HTTP request received");
// Check if this is an OPTIONS request // Check if this is an OPTIONS request
char method[16] = {0}; 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 // Handle HTTP body transmission for NIP-11 or embedded files
{ {
void* user_data = lws_wsi_user(wsi); 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) { if (user_data) {
int type = *(int*)user_data; int type = *(int*)user_data;
if (type == 0) { if (type == 0) {
// NIP-11 // NIP-11
struct nip11_session_data* session_data = (struct nip11_session_data*)user_data; 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) { 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) // Allocate buffer for JSON body transmission (no LWS_PRE needed for body)
unsigned char *json_buf = malloc(session_data->json_length); unsigned char *json_buf = malloc(session_data->json_length);
if (!json_buf) { 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); lws_set_wsi_user(wsi, NULL);
return -1; return -1;
} }
log_info("NIP-11: Buffer allocated successfully");
// Copy JSON data to buffer // Copy JSON data to buffer
memcpy(json_buf, session_data->json_buffer, session_data->json_length); 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) { if (message) {
memcpy(message, in, len); memcpy(message, in, len);
message[len] = '\0'; message[len] = '\0';
// Parse JSON message (this is the normal program flow) // Parse JSON message (this is the normal program flow)
cJSON* json = cJSON_Parse(message); cJSON* json = cJSON_Parse(message);
if (json && cJSON_IsArray(json)) { 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 // Get message type
cJSON* type = cJSON_GetArrayItem(json, 0); cJSON* type = cJSON_GetArrayItem(json, 0);
if (type && cJSON_IsString(type)) { if (type && cJSON_IsString(type)) {
const char* msg_type = cJSON_GetStringValue(type); const char* msg_type = cJSON_GetStringValue(type);
if (strcmp(msg_type, "EVENT") == 0) { if (strcmp(msg_type, "EVENT") == 0) {
// Extract event for kind-specific NIP-42 authentication check // Extract event for kind-specific NIP-42 authentication check
cJSON* event_obj = cJSON_GetArrayItem(json, 1); 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 // Extract event kind for kind-specific NIP-42 authentication check
cJSON* kind_obj = cJSON_GetObjectItem(event_obj, "kind"); cJSON* kind_obj = cJSON_GetObjectItem(event_obj, "kind");
int event_kind = kind_obj && cJSON_IsNumber(kind_obj) ? (int)cJSON_GetNumberValue(kind_obj) : -1; int event_kind = kind_obj && cJSON_IsNumber(kind_obj) ? (int)cJSON_GetNumberValue(kind_obj) : -1;
// Extract pubkey and event ID for debugging // Extract pubkey and event ID for debugging
cJSON* pubkey_obj = cJSON_GetObjectItem(event_obj, "pubkey"); cJSON* pubkey_obj = cJSON_GetObjectItem(event_obj, "pubkey");
cJSON* id_obj = cJSON_GetObjectItem(event_obj, "id"); cJSON* id_obj = cJSON_GetObjectItem(event_obj, "id");
const char* event_pubkey = pubkey_obj ? cJSON_GetStringValue(pubkey_obj) : "unknown"; const char* event_pubkey = pubkey_obj ? cJSON_GetStringValue(pubkey_obj) : "unknown";
const char* event_id = id_obj ? cJSON_GetStringValue(id_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 // 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); 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_required && !pss->authenticated && !bypass_auth) {
if (!pss->auth_challenge_sent) { if (!pss->auth_challenge_sent) {
log_info("DEBUG AUTH: Sending NIP-42 authentication challenge");
send_nip42_auth_challenge(wsi, pss); send_nip42_auth_challenge(wsi, pss);
} else { } else {
char auth_msg[256]; 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); send_notice_message(wsi, auth_msg);
log_warning("Event rejected: NIP-42 authentication required for kind"); 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); cJSON_Delete(json);
free(message); free(message);
@@ -450,20 +415,13 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
return 0; return 0;
} }
log_info("DEBUG VALIDATION: Starting unified validator");
// Call unified validator with JSON string // Call unified validator with JSON string
size_t event_json_len = strlen(event_json_str); size_t event_json_len = strlen(event_json_str);
int validation_result = nostr_validate_unified_request(event_json_str, event_json_len); int validation_result = nostr_validate_unified_request(event_json_str, event_json_len);
// Map validation result to old result format (0 = success, -1 = failure) // Map validation result to old result format (0 = success, -1 = failure)
int result = (validation_result == NOSTR_SUCCESS) ? 0 : -1; 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 // Generate error message based on validation result
char error_message[512] = {0}; char error_message[512] = {0};
if (result != 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), snprintf(debug_error_msg, sizeof(debug_error_msg),
"DEBUG VALIDATION ERROR: %s", error_message); "DEBUG VALIDATION ERROR: %s", error_message);
log_warning(debug_error_msg); log_warning(debug_error_msg);
} else {
log_info("DEBUG VALIDATION: Event validated successfully using unified validator");
} }
// Cleanup event JSON string // 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); strncpy(error_message, "auth-required: protected event requires authentication", sizeof(error_message) - 1);
error_message[sizeof(error_message) - 1] = '\0'; error_message[sizeof(error_message) - 1] = '\0';
log_warning("Protected event rejected: authentication required"); log_warning("Protected event rejected: authentication required");
} else {
log_info("Protected event accepted: authenticated publisher");
} }
} }
} }