v0.3.15 - How can administration take so long

This commit is contained in:
Your Name
2025-09-27 15:50:42 -04:00
parent c1c05991cf
commit 6fd3e531c3
10 changed files with 343 additions and 218 deletions

View File

@@ -342,7 +342,7 @@ int store_config_event_in_database(const cJSON* event) {
return -1;
}
// Insert or replace the configuration event (kind 33334 is replaceable)
// Insert or replace the configuration event
const char* sql = "INSERT OR REPLACE INTO events (id, pubkey, created_at, kind, event_type, content, sig, tags) VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
sqlite3_stmt* stmt;
@@ -357,7 +357,7 @@ int store_config_event_in_database(const cJSON* event) {
sqlite3_bind_text(stmt, 2, cJSON_GetStringValue(pubkey_obj), -1, SQLITE_STATIC);
sqlite3_bind_int64(stmt, 3, (sqlite3_int64)cJSON_GetNumberValue(created_at_obj));
sqlite3_bind_int(stmt, 4, (int)cJSON_GetNumberValue(kind_obj));
sqlite3_bind_text(stmt, 5, "addressable", -1, SQLITE_STATIC); // kind 33334 is addressable
sqlite3_bind_text(stmt, 5, "regular", -1, SQLITE_STATIC);
sqlite3_bind_text(stmt, 6, cJSON_GetStringValue(content_obj), -1, SQLITE_STATIC);
sqlite3_bind_text(stmt, 7, cJSON_GetStringValue(sig_obj), -1, SQLITE_STATIC);
sqlite3_bind_text(stmt, 8, tags_str, -1, SQLITE_TRANSIENT);
@@ -384,26 +384,9 @@ cJSON* load_config_event_from_database(const char* relay_pubkey) {
sqlite3_stmt* stmt;
int rc;
// Try to get admin pubkey from cache, otherwise find the most recent kind 33334 event
const char* admin_pubkey = get_admin_pubkey_cached();
if (admin_pubkey && strlen(admin_pubkey) > 0) {
sql = "SELECT id, pubkey, created_at, kind, content, sig, tags FROM events WHERE kind = 33334 AND pubkey = ? ORDER BY created_at DESC LIMIT 1";
rc = sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL);
if (rc != SQLITE_OK) {
log_error("Failed to prepare configuration event query");
return NULL;
}
sqlite3_bind_text(stmt, 1, admin_pubkey, -1, SQLITE_STATIC);
} else {
// During existing relay startup, we don't know the admin pubkey yet
// Look for any kind 33334 configuration event (should only be one per relay)
sql = "SELECT id, pubkey, created_at, kind, content, sig, tags FROM events WHERE kind = 33334 ORDER BY created_at DESC LIMIT 1";
rc = sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL);
if (rc != SQLITE_OK) {
log_error("Failed to prepare configuration event query");
return NULL;
}
}
// Configuration is now managed through config table, not events
log_info("Configuration events are no longer stored in events table");
return NULL;
cJSON* event = NULL;
if (sqlite3_step(stmt) == SQLITE_ROW) {
@@ -937,7 +920,7 @@ cJSON* create_default_config_event(const unsigned char* admin_privkey_bytes,
// Create and sign event using nostr_core_lib
cJSON* event = nostr_create_and_sign_event(
33334, // kind
23455, // kind
"C Nostr Relay Configuration", // content
tags, // tags
admin_privkey_bytes, // private key bytes for signing
@@ -1614,7 +1597,7 @@ int process_configuration_event(const cJSON* event) {
cJSON* kind_obj = cJSON_GetObjectItem(event, "kind");
cJSON* pubkey_obj = cJSON_GetObjectItem(event, "pubkey");
if (!kind_obj || cJSON_GetNumberValue(kind_obj) != 33334) {
if (!kind_obj || (cJSON_GetNumberValue(kind_obj) != 23455 && cJSON_GetNumberValue(kind_obj) != 23456)) {
log_error("Invalid event kind for configuration");
return -1;
}
@@ -1775,7 +1758,7 @@ int apply_runtime_config_handlers(const cJSON* old_config, const cJSON* new_conf
if (handlers_applied > 0) {
char audit_msg[512];
snprintf(audit_msg, sizeof(audit_msg),
"Configuration updated via kind 33334 event - %d system components reinitialized",
"Configuration updated via admin event - %d system components reinitialized",
handlers_applied);
log_success(audit_msg);
} else {
@@ -1832,7 +1815,7 @@ int apply_configuration_from_event(const cJSON* event) {
// REAL-TIME EVENT HANDLER (called from main.c)
// ================================
// Handle kind 33334 configuration events received via WebSocket
// Handle configuration events received via WebSocket
int handle_configuration_event(cJSON* event, char* error_message, size_t error_size) {
if (!event) {
snprintf(error_message, error_size, "invalid: null configuration event");
@@ -2121,12 +2104,6 @@ int process_admin_event_in_config(cJSON* event, char* error_message, size_t erro
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);
case 33334: // Legacy addressable config events (backward compatibility)
log_info("DEBUG: Routing to process_admin_config_event (legacy kind 33334)");
return process_admin_config_event(event, error_message, error_size);
case 33335: // Legacy addressable auth events (backward compatibility)
log_info("DEBUG: Routing to process_admin_auth_event (legacy kind 33335)");
return process_admin_auth_event(event, error_message, error_size, wsi);
default:
log_error("DEBUG: Unsupported admin event kind");
printf(" Unsupported kind: %d\n", kind);
@@ -2135,7 +2112,7 @@ int process_admin_event_in_config(cJSON* event, char* error_message, size_t erro
}
}
// Handle Kind 23455 configuration management events and legacy Kind 33334
// Handle Kind 23455 configuration management events
int process_admin_config_event(cJSON* event, char* error_message, size_t error_size) {
cJSON* kind_obj = cJSON_GetObjectItem(event, "kind");
int kind = kind_obj ? (int)cJSON_GetNumberValue(kind_obj) : 0;
@@ -2211,10 +2188,6 @@ int process_admin_config_event(cJSON* event, char* error_message, size_t error_s
continue;
}
// Skip relay identifier tag (only for legacy addressable events)
if (kind == 33334 && strcmp(key, "d") == 0) {
continue;
}
// Update configuration in table
if (update_config_in_table(key, value) == 0) {
@@ -2238,7 +2211,7 @@ int process_admin_config_event(cJSON* event, char* error_message, size_t error_s
return 0;
}
// Handle Kind 23456 auth rules management and legacy Kind 33335
// Handle Kind 23456 auth rules management
int process_admin_auth_event(cJSON* event, char* error_message, size_t error_size, struct lws* wsi) {
log_info("DEBUG: Entering process_admin_auth_event()");
@@ -2267,13 +2240,6 @@ int process_admin_auth_event(cJSON* event, char* error_message, size_t error_siz
return handle_kind_23456_unified(event, error_message, error_size, wsi);
}
// Legacy Kind 33335 events use the unified handler as well
if (kind == 33335) {
log_info("DEBUG: Routing legacy Kind 33335 to unified handler");
// For legacy events, we still use the unified handler but may need special processing
// The unified handler already supports all the functionality
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);
@@ -3072,6 +3038,85 @@ int handle_system_command_unified(cJSON* event, const char* command, char* error
snprintf(error_message, error_size, "failed to send clear auth rules response");
return -1;
}
else if (strcmp(command, "delete_auth_rule") == 0) {
// Get rule parameters from tags
const char* rule_type = get_tag_value(event, "system_command", 2);
const char* pattern_type = get_tag_value(event, "system_command", 3);
const char* pattern_value = get_tag_value(event, "system_command", 4);
if (!rule_type || !pattern_type || !pattern_value) {
snprintf(error_message, error_size, "invalid: delete_auth_rule requires rule_type, pattern_type, and pattern_value");
return -1;
}
log_info("Processing delete auth rule command");
printf(" Rule type: %s\n", rule_type);
printf(" Pattern type: %s\n", pattern_type);
printf(" Pattern value: %s\n", pattern_value);
// Check if rule exists before deletion
const char* check_sql = "SELECT COUNT(*) FROM auth_rules WHERE rule_type = ? AND pattern_type = ? AND pattern_value = ?";
sqlite3_stmt* check_stmt;
int check_rc = sqlite3_prepare_v2(g_db, check_sql, -1, &check_stmt, NULL);
if (check_rc != SQLITE_OK) {
snprintf(error_message, error_size, "failed to prepare rule existence check");
return -1;
}
sqlite3_bind_text(check_stmt, 1, rule_type, -1, SQLITE_STATIC);
sqlite3_bind_text(check_stmt, 2, pattern_type, -1, SQLITE_STATIC);
sqlite3_bind_text(check_stmt, 3, pattern_value, -1, SQLITE_STATIC);
int rule_exists = 0;
if (sqlite3_step(check_stmt) == SQLITE_ROW) {
rule_exists = sqlite3_column_int(check_stmt, 0) > 0;
}
sqlite3_finalize(check_stmt);
if (!rule_exists) {
snprintf(error_message, error_size, "error: auth rule not found");
return -1;
}
// Delete the specific auth rule
if (remove_auth_rule_from_config(rule_type, pattern_type, pattern_value) != 0) {
snprintf(error_message, error_size, "failed to delete auth rule from database");
return -1;
}
// Build response
cJSON* response = cJSON_CreateObject();
cJSON_AddStringToObject(response, "command", "delete_auth_rule");
cJSON_AddStringToObject(response, "rule_type", rule_type);
cJSON_AddStringToObject(response, "pattern_type", pattern_type);
cJSON_AddStringToObject(response, "pattern_value", pattern_value);
cJSON_AddStringToObject(response, "status", "success");
cJSON_AddNumberToObject(response, "timestamp", (double)time(NULL));
printf("Deleted auth rule: %s %s:%s\n", rule_type, pattern_type, pattern_value);
// Get admin pubkey from event for response
cJSON* pubkey_obj = cJSON_GetObjectItem(event, "pubkey");
const char* admin_pubkey = pubkey_obj ? cJSON_GetStringValue(pubkey_obj) : NULL;
if (!admin_pubkey) {
cJSON_Delete(response);
snprintf(error_message, error_size, "missing admin pubkey for response");
return -1;
}
// Send response as signed kind 23457 event
if (send_admin_response_event(response, admin_pubkey, wsi) == 0) {
log_success("Delete auth rule command completed successfully with signed response");
cJSON_Delete(response);
return 0;
}
cJSON_Delete(response);
snprintf(error_message, error_size, "failed to send delete auth rule response");
return -1;
}
else if (strcmp(command, "system_status") == 0) {
// Build system status response
cJSON* response = cJSON_CreateObject();
@@ -3535,7 +3580,7 @@ int process_startup_config_event(const cJSON* event) {
// Validate event structure first
cJSON* kind_obj = cJSON_GetObjectItem(event, "kind");
if (!kind_obj || cJSON_GetNumberValue(kind_obj) != 33334) {
if (!kind_obj || cJSON_GetNumberValue(kind_obj) != 23455) {
log_error("Invalid event kind for startup configuration");
return -1;
}
@@ -3633,14 +3678,14 @@ int process_startup_config_event_with_fallback(const cJSON* event) {
// DYNAMIC EVENT GENERATION FROM CONFIG TABLE
// ================================
// Generate synthetic kind 33334 configuration event from current config table data
// Generate synthetic configuration event from current config table data
cJSON* generate_config_event_from_table(void) {
if (!g_db) {
log_error("Database not available for config event generation");
return NULL;
}
log_info("Generating synthetic kind 33334 event from config table...");
log_info("Generating synthetic configuration event from config table...");
// Get relay pubkey for event generation
const char* relay_pubkey = get_config_value("relay_pubkey");
@@ -3664,7 +3709,7 @@ cJSON* generate_config_event_from_table(void) {
cJSON_AddStringToObject(event, "id", "synthetic_config_event_id");
cJSON_AddStringToObject(event, "pubkey", relay_pubkey); // Use relay pubkey as event author
cJSON_AddNumberToObject(event, "created_at", (double)time(NULL));
cJSON_AddNumberToObject(event, "kind", 33334);
cJSON_AddNumberToObject(event, "kind", 23455);
cJSON_AddStringToObject(event, "content", "C Nostr Relay Configuration");
cJSON_AddStringToObject(event, "sig", "synthetic_signature");
@@ -3724,13 +3769,13 @@ cJSON* generate_config_event_from_table(void) {
char success_msg[256];
snprintf(success_msg, sizeof(success_msg),
"Generated synthetic kind 33334 event with %d configuration items", config_items_added);
"Generated synthetic configuration event with %d configuration items", config_items_added);
log_success(success_msg);
return event;
}
// Check if a REQ filter requests kind 33334 events
// Check if a REQ filter requests configuration events
int req_filter_requests_config_events(const cJSON* filter) {
if (!filter || !cJSON_IsObject(filter)) {
return 0;
@@ -3741,10 +3786,11 @@ int req_filter_requests_config_events(const cJSON* filter) {
return 0;
}
// Check if kinds array contains 33334
// Check if kinds array contains configuration event kinds
cJSON* kind_item = NULL;
cJSON_ArrayForEach(kind_item, kinds) {
if (cJSON_IsNumber(kind_item) && (int)cJSON_GetNumberValue(kind_item) == 33334) {
int kind_val = (int)cJSON_GetNumberValue(kind_item);
if (cJSON_IsNumber(kind_item) && (kind_val == 23455 || kind_val == 23456)) {
return 1;
}
}
@@ -3758,7 +3804,7 @@ cJSON* generate_synthetic_config_event_for_subscription(const char* sub_id, cons
return NULL;
}
// Check if any filter requests kind 33334
// Check if any filter requests configuration events
int requests_config = 0;
if (cJSON_IsArray(filters)) {
@@ -3778,7 +3824,7 @@ cJSON* generate_synthetic_config_event_for_subscription(const char* sub_id, cons
return NULL;
}
log_info("Generating synthetic kind 33334 event for subscription");
log_info("Generating synthetic configuration event for subscription");
// Generate synthetic config event from table
cJSON* config_event = generate_config_event_from_table();
@@ -3793,12 +3839,12 @@ cJSON* generate_synthetic_config_event_for_subscription(const char* sub_id, cons
cJSON_AddItemToArray(event_msg, cJSON_CreateString(sub_id));
cJSON_AddItemToArray(event_msg, config_event);
log_success("Generated synthetic kind 33334 configuration event message");
log_success("Generated synthetic configuration event message");
return event_msg;
}
/**
* Generate a synthetic kind 33334 configuration event from config table data
* Generate a synthetic configuration event from config table data
* This allows WebSocket clients to fetch configuration via REQ messages
* Returns JSON string that must be freed by caller
*/