v0.3.11 - Working on admin api

This commit is contained in:
Your Name
2025-09-25 11:25:50 -04:00
parent be99595bde
commit 036b0823b9
9 changed files with 1635 additions and 201 deletions

View File

@@ -73,6 +73,16 @@ int is_config_table_ready(void);
int migrate_config_from_events_to_table(void);
int populate_config_table_from_event(const cJSON* event);
// Forward declarations for admin API query handlers
int handle_config_list_keys_query(cJSON* event, char* error_message, size_t error_size);
int handle_config_get_current_query(cJSON* event, char* error_message, size_t error_size);
int handle_auth_list_all_query(cJSON* event, char* error_message, size_t error_size);
int handle_auth_whitelist_query(cJSON* event, char* error_message, size_t error_size);
int handle_auth_blacklist_query(cJSON* event, char* error_message, size_t error_size);
int handle_auth_pattern_check_query(cJSON* event, char* error_message, size_t error_size);
int handle_clear_all_auth_rules_command(cJSON* event, char* error_message, size_t error_size);
int handle_system_status_query(cJSON* event, char* error_message, size_t error_size);
// Current configuration cache
static cJSON* g_current_config = NULL;
@@ -2055,7 +2065,7 @@ int add_pubkeys_to_config_table(void) {
// ADMIN EVENT PROCESSING FUNCTIONS
// ================================
// Process admin events (moved from main.c)
// Process admin events (updated for new Kind 23455/23456)
int process_admin_event_in_config(cJSON* event, char* error_message, size_t error_size) {
cJSON* kind_obj = cJSON_GetObjectItem(event, "kind");
if (!kind_obj || !cJSON_IsNumber(kind_obj)) {
@@ -2081,26 +2091,64 @@ int process_admin_event_in_config(cJSON* event, char* error_message, size_t erro
int kind = (int)cJSON_GetNumberValue(kind_obj);
switch (kind) {
case 33334:
case 23455: // New ephemeral configuration management
return process_admin_config_event(event, error_message, error_size);
case 33335:
case 23456: // New ephemeral auth rules management
return process_admin_auth_event(event, error_message, error_size);
case 33334: // Legacy addressable config events (backward compatibility)
return process_admin_config_event(event, error_message, error_size);
case 33335: // Legacy addressable auth events (backward compatibility)
return process_admin_auth_event(event, error_message, error_size);
default:
snprintf(error_message, error_size, "invalid: unsupported admin event kind");
snprintf(error_message, error_size, "invalid: unsupported admin event kind %d", kind);
return -1;
}
}
// Handle kind 33334 config events
// Handle Kind 23455 configuration management events and legacy Kind 33334
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;
// Parse content for action commands
cJSON* content_obj = cJSON_GetObjectItem(event, "content");
const char* content = content_obj ? cJSON_GetStringValue(content_obj) : "";
// Check if this is a query command
cJSON* content_json = cJSON_Parse(content);
char action_buffer[32] = "set"; // default action
const char* action = action_buffer;
if (content_json) {
cJSON* action_obj = cJSON_GetObjectItem(content_json, "action");
if (action_obj && cJSON_IsString(action_obj)) {
const char* action_str = cJSON_GetStringValue(action_obj);
if (action_str) {
strncpy(action_buffer, action_str, sizeof(action_buffer) - 1);
action_buffer[sizeof(action_buffer) - 1] = '\0';
}
}
cJSON_Delete(content_json);
}
log_info("Processing admin configuration event");
printf(" Kind: %d, Action: %s\n", kind, action);
// Handle query commands
if (strcmp(action, "list_config_keys") == 0) {
return handle_config_list_keys_query(event, error_message, error_size);
}
if (strcmp(action, "get_current_config") == 0) {
return handle_config_get_current_query(event, error_message, error_size);
}
// Handle configuration updates (set action)
cJSON* tags_obj = cJSON_GetObjectItem(event, "tags");
if (!tags_obj || !cJSON_IsArray(tags_obj)) {
snprintf(error_message, error_size, "invalid: configuration event must have tags");
return -1;
}
// Config table should already exist from embedded schema
// Begin transaction for atomic config updates
int rc = sqlite3_exec(g_db, "BEGIN IMMEDIATE TRANSACTION", NULL, NULL, NULL);
if (rc != SQLITE_OK) {
@@ -2127,8 +2175,8 @@ int process_admin_config_event(cJSON* event, char* error_message, size_t error_s
const char* key = cJSON_GetStringValue(tag_name);
const char* value = cJSON_GetStringValue(tag_value);
// Skip relay identifier tag
if (strcmp(key, "d") == 0) {
// Skip relay identifier tag (only for legacy addressable events)
if (kind == 33334 && strcmp(key, "d") == 0) {
continue;
}
@@ -2154,35 +2202,21 @@ int process_admin_config_event(cJSON* event, char* error_message, size_t error_s
return 0;
}
// Handle kind 33335 auth rule events
// Handle Kind 23456 auth rules management and legacy Kind 33335
int process_admin_auth_event(cJSON* event, char* error_message, size_t error_size) {
log_info("=== SERVER-SIDE AUTH RULE EVENT DEBUG ===");
cJSON* kind_obj = cJSON_GetObjectItem(event, "kind");
int kind = kind_obj ? (int)cJSON_GetNumberValue(kind_obj) : 0;
// Print the entire received event for debugging
char* debug_event_str = cJSON_Print(event);
if (debug_event_str) {
printf("Received Auth Event JSON: %s\n", debug_event_str);
free(debug_event_str);
}
log_info("Processing admin auth rule event");
cJSON* tags_obj = cJSON_GetObjectItem(event, "tags");
if (!tags_obj || !cJSON_IsArray(tags_obj)) {
log_error("Auth event missing or invalid tags array");
snprintf(error_message, error_size, "invalid: auth rule event must have tags");
return -1;
}
printf("Tags array size: %d\n", cJSON_GetArraySize(tags_obj));
// Extract action from content or tags
// Parse content for action commands
cJSON* content_obj = cJSON_GetObjectItem(event, "content");
const char* content = content_obj ? cJSON_GetStringValue(content_obj) : "";
printf("Event content: '%s'\n", content);
// Parse the action from content (should be "add" or "remove")
cJSON* content_json = cJSON_Parse(content);
char action_buffer[16] = "add"; // Local buffer for action string
const char* action = action_buffer; // default
char action_buffer[32] = "add"; // default action
const char* action = action_buffer;
if (content_json) {
cJSON* action_obj = cJSON_GetObjectItem(content_json, "action");
if (action_obj && cJSON_IsString(action_obj)) {
@@ -2194,7 +2228,35 @@ int process_admin_auth_event(cJSON* event, char* error_message, size_t error_siz
}
cJSON_Delete(content_json);
}
printf("Parsed action: '%s'\n", action);
printf(" Kind: %d, Action: %s\n", kind, action);
// Handle query commands
if (strcmp(action, "list_all") == 0) {
return handle_auth_list_all_query(event, error_message, error_size);
}
if (strcmp(action, "whitelist_only") == 0) {
return handle_auth_whitelist_query(event, error_message, error_size);
}
if (strcmp(action, "blacklist_only") == 0) {
return handle_auth_blacklist_query(event, error_message, error_size);
}
if (strcmp(action, "pattern_check") == 0) {
return handle_auth_pattern_check_query(event, error_message, error_size);
}
if (strcmp(action, "clear_all_auth_rules") == 0) {
return handle_clear_all_auth_rules_command(event, error_message, error_size);
}
if (strcmp(action, "system_status") == 0) {
return handle_system_status_query(event, error_message, error_size);
}
// Handle auth rule updates (add/remove actions)
cJSON* tags_obj = cJSON_GetObjectItem(event, "tags");
if (!tags_obj || !cJSON_IsArray(tags_obj)) {
snprintf(error_message, error_size, "invalid: auth rule event must have tags");
return -1;
}
// Begin transaction for atomic auth rule updates
int rc = sqlite3_exec(g_db, "BEGIN IMMEDIATE TRANSACTION", NULL, NULL, NULL);
@@ -2204,33 +2266,11 @@ int process_admin_auth_event(cJSON* event, char* error_message, size_t error_siz
}
int rules_processed = 0;
int tags_examined = 0;
int tags_skipped = 0;
// Process each tag as an auth rule specification
cJSON* tag = NULL;
cJSON_ArrayForEach(tag, tags_obj) {
tags_examined++;
printf("Examining tag #%d:\n", tags_examined);
char* tag_debug_str = cJSON_Print(tag);
if (tag_debug_str) {
printf(" Tag JSON: %s\n", tag_debug_str);
free(tag_debug_str);
}
if (!cJSON_IsArray(tag)) {
printf(" SKIPPED: Not an array\n");
tags_skipped++;
continue;
}
int tag_size = cJSON_GetArraySize(tag);
printf(" Tag array size: %d\n", tag_size);
if (tag_size < 3) {
printf(" SKIPPED: Array size < 3 (need at least 3 elements for auth rules)\n");
tags_skipped++;
if (!cJSON_IsArray(tag) || cJSON_GetArraySize(tag) < 3) {
continue;
}
@@ -2241,8 +2281,6 @@ int process_admin_auth_event(cJSON* event, char* error_message, size_t error_siz
if (!cJSON_IsString(rule_type_obj) ||
!cJSON_IsString(pattern_type_obj) ||
!cJSON_IsString(pattern_value_obj)) {
printf(" SKIPPED: One or more elements are not strings\n");
tags_skipped++;
continue;
}
@@ -2250,33 +2288,18 @@ int process_admin_auth_event(cJSON* event, char* error_message, size_t error_siz
const char* pattern_type = cJSON_GetStringValue(pattern_type_obj);
const char* pattern_value = cJSON_GetStringValue(pattern_value_obj);
printf(" Extracted rule: type='%s', pattern_type='%s', pattern_value='%s'\n",
rule_type, pattern_type, pattern_value);
// Process the auth rule based on action
if (strcmp(action, "add") == 0) {
printf(" Attempting to add rule to database...\n");
if (add_auth_rule_from_config(rule_type, pattern_type, pattern_value, "allow") == 0) {
printf(" SUCCESS: Rule added to database\n");
rules_processed++;
} else {
printf(" FAILED: Could not add rule to database\n");
}
} else if (strcmp(action, "remove") == 0) {
printf(" Attempting to remove rule from database...\n");
if (remove_auth_rule_from_config(rule_type, pattern_type, pattern_value) == 0) {
printf(" SUCCESS: Rule removed from database\n");
rules_processed++;
} else {
printf(" FAILED: Could not remove rule from database\n");
}
}
}
printf("Processing summary: examined=%d, skipped=%d, processed=%d\n",
tags_examined, tags_skipped, rules_processed);
log_info("=== END SERVER-SIDE AUTH RULE EVENT DEBUG ===");
if (rules_processed > 0) {
sqlite3_exec(g_db, "COMMIT", NULL, NULL, NULL);
@@ -2348,6 +2371,425 @@ int remove_auth_rule_from_config(const char* rule_type, const char* pattern_type
return (rc == SQLITE_DONE) ? 0 : -1;
}
// ================================
// ADMIN API QUERY HANDLERS
// ================================
// Handle configuration list keys query
int handle_config_list_keys_query(cJSON* event, char* error_message, size_t error_size) {
(void)event; // Suppress unused parameter warning
if (!g_db) {
snprintf(error_message, error_size, "database not available");
return -1;
}
log_info("Processing config list keys query");
const char* sql = "SELECT key, data_type, category FROM config ORDER BY category, key";
sqlite3_stmt* stmt;
int rc = sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL);
if (rc != SQLITE_OK) {
snprintf(error_message, error_size, "failed to prepare config keys query");
return -1;
}
printf("=== Configuration Keys ===\n");
int key_count = 0;
while (sqlite3_step(stmt) == SQLITE_ROW) {
const char* key = (const char*)sqlite3_column_text(stmt, 0);
const char* data_type = (const char*)sqlite3_column_text(stmt, 1);
const char* category = (const char*)sqlite3_column_text(stmt, 2);
printf(" [%s] %s (%s)\n", category ? category : "general", key ? key : "", data_type ? data_type : "string");
key_count++;
}
sqlite3_finalize(stmt);
printf("Total configuration keys: %d\n", key_count);
log_success("Configuration keys listed successfully");
return 0;
}
// Handle get current configuration query
int handle_config_get_current_query(cJSON* event, char* error_message, size_t error_size) {
(void)event; // Suppress unused parameter warning
if (!g_db) {
snprintf(error_message, error_size, "database not available");
return -1;
}
log_info("Processing get current config query");
const char* sql = "SELECT key, value, data_type, category FROM config ORDER BY category, key";
sqlite3_stmt* stmt;
int rc = sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL);
if (rc != SQLITE_OK) {
snprintf(error_message, error_size, "failed to prepare current config query");
return -1;
}
printf("=== Current Configuration ===\n");
int config_count = 0;
while (sqlite3_step(stmt) == SQLITE_ROW) {
const char* key = (const char*)sqlite3_column_text(stmt, 0);
const char* value = (const char*)sqlite3_column_text(stmt, 1);
const char* data_type = (const char*)sqlite3_column_text(stmt, 2);
const char* category = (const char*)sqlite3_column_text(stmt, 3);
printf(" [%s] %s = %s (%s)\n",
category ? category : "general",
key ? key : "",
value ? value : "",
data_type ? data_type : "string");
config_count++;
}
sqlite3_finalize(stmt);
printf("Total configuration items: %d\n", config_count);
log_success("Current configuration retrieved successfully");
return 0;
}
// Handle auth rules list all query
int handle_auth_list_all_query(cJSON* event, char* error_message, size_t error_size) {
(void)event; // Suppress unused parameter warning
if (!g_db) {
snprintf(error_message, error_size, "database not available");
return -1;
}
log_info("Processing auth rules list all query");
const char* sql = "SELECT rule_type, pattern_type, pattern_value, action FROM auth_rules ORDER BY rule_type, pattern_type";
sqlite3_stmt* stmt;
int rc = sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL);
if (rc != SQLITE_OK) {
snprintf(error_message, error_size, "failed to prepare auth rules query");
return -1;
}
printf("=== All Auth Rules ===\n");
int rule_count = 0;
while (sqlite3_step(stmt) == SQLITE_ROW) {
const char* rule_type = (const char*)sqlite3_column_text(stmt, 0);
const char* pattern_type = (const char*)sqlite3_column_text(stmt, 1);
const char* pattern_value = (const char*)sqlite3_column_text(stmt, 2);
const char* action = (const char*)sqlite3_column_text(stmt, 3);
printf(" %s %s:%s -> %s\n",
rule_type ? rule_type : "",
pattern_type ? pattern_type : "",
pattern_value ? pattern_value : "",
action ? action : "allow");
rule_count++;
}
sqlite3_finalize(stmt);
printf("Total auth rules: %d\n", rule_count);
log_success("Auth rules listed successfully");
return 0;
}
// Handle whitelist only query
int handle_auth_whitelist_query(cJSON* event, char* error_message, size_t error_size) {
(void)event; // Suppress unused parameter warning
if (!g_db) {
snprintf(error_message, error_size, "database not available");
return -1;
}
log_info("Processing whitelist rules query");
const char* sql = "SELECT rule_type, pattern_type, pattern_value, action FROM auth_rules WHERE rule_type LIKE '%whitelist%' ORDER BY pattern_type";
sqlite3_stmt* stmt;
int rc = sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL);
if (rc != SQLITE_OK) {
snprintf(error_message, error_size, "failed to prepare whitelist query");
return -1;
}
printf("=== Whitelist Rules ===\n");
int whitelist_count = 0;
while (sqlite3_step(stmt) == SQLITE_ROW) {
const char* rule_type = (const char*)sqlite3_column_text(stmt, 0);
const char* pattern_type = (const char*)sqlite3_column_text(stmt, 1);
const char* pattern_value = (const char*)sqlite3_column_text(stmt, 2);
const char* action = (const char*)sqlite3_column_text(stmt, 3);
printf(" %s %s:%s -> %s\n",
rule_type ? rule_type : "",
pattern_type ? pattern_type : "",
pattern_value ? pattern_value : "",
action ? action : "allow");
whitelist_count++;
}
sqlite3_finalize(stmt);
printf("Total whitelist rules: %d\n", whitelist_count);
log_success("Whitelist rules listed successfully");
return 0;
}
// Handle blacklist only query
int handle_auth_blacklist_query(cJSON* event, char* error_message, size_t error_size) {
(void)event; // Suppress unused parameter warning
if (!g_db) {
snprintf(error_message, error_size, "database not available");
return -1;
}
log_info("Processing blacklist rules query");
const char* sql = "SELECT rule_type, pattern_type, pattern_value, action FROM auth_rules WHERE rule_type LIKE '%blacklist%' ORDER BY pattern_type";
sqlite3_stmt* stmt;
int rc = sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL);
if (rc != SQLITE_OK) {
snprintf(error_message, error_size, "failed to prepare blacklist query");
return -1;
}
printf("=== Blacklist Rules ===\n");
int blacklist_count = 0;
while (sqlite3_step(stmt) == SQLITE_ROW) {
const char* rule_type = (const char*)sqlite3_column_text(stmt, 0);
const char* pattern_type = (const char*)sqlite3_column_text(stmt, 1);
const char* pattern_value = (const char*)sqlite3_column_text(stmt, 2);
const char* action = (const char*)sqlite3_column_text(stmt, 3);
printf(" %s %s:%s -> %s\n",
rule_type ? rule_type : "",
pattern_type ? pattern_type : "",
pattern_value ? pattern_value : "",
action ? action : "deny");
blacklist_count++;
}
sqlite3_finalize(stmt);
printf("Total blacklist rules: %d\n", blacklist_count);
log_success("Blacklist rules listed successfully");
return 0;
}
// Handle pattern check query
int handle_auth_pattern_check_query(cJSON* event, char* error_message, size_t error_size) {
// Parse tags to get the pattern to check
cJSON* tags_obj = cJSON_GetObjectItem(event, "tags");
if (!tags_obj || !cJSON_IsArray(tags_obj)) {
snprintf(error_message, error_size, "invalid: pattern check requires tags with pattern information");
return -1;
}
const char* check_pattern_type = NULL;
const char* check_pattern_value = NULL;
// Find pattern_check tag
cJSON* tag = NULL;
cJSON_ArrayForEach(tag, tags_obj) {
if (cJSON_IsArray(tag) && cJSON_GetArraySize(tag) >= 3) {
cJSON* tag_name = cJSON_GetArrayItem(tag, 0);
if (tag_name && cJSON_IsString(tag_name) &&
strcmp(cJSON_GetStringValue(tag_name), "pattern_check") == 0) {
cJSON* pattern_type_obj = cJSON_GetArrayItem(tag, 1);
cJSON* pattern_value_obj = cJSON_GetArrayItem(tag, 2);
if (pattern_type_obj && cJSON_IsString(pattern_type_obj) &&
pattern_value_obj && cJSON_IsString(pattern_value_obj)) {
check_pattern_type = cJSON_GetStringValue(pattern_type_obj);
check_pattern_value = cJSON_GetStringValue(pattern_value_obj);
break;
}
}
}
}
if (!check_pattern_type || !check_pattern_value) {
snprintf(error_message, error_size, "invalid: pattern_check tag format should be [\"pattern_check\", \"pattern_type\", \"pattern_value\"]");
return -1;
}
if (!g_db) {
snprintf(error_message, error_size, "database not available");
return -1;
}
log_info("Processing pattern check query");
printf(" Checking pattern: %s:%s\n", check_pattern_type, check_pattern_value);
const char* sql = "SELECT rule_type, pattern_type, pattern_value, action FROM auth_rules WHERE pattern_type = ? AND pattern_value = ? ORDER BY rule_type";
sqlite3_stmt* stmt;
int rc = sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL);
if (rc != SQLITE_OK) {
snprintf(error_message, error_size, "failed to prepare pattern check query");
return -1;
}
sqlite3_bind_text(stmt, 1, check_pattern_type, -1, SQLITE_STATIC);
sqlite3_bind_text(stmt, 2, check_pattern_value, -1, SQLITE_STATIC);
printf("=== Pattern Check Results ===\n");
printf("Pattern: %s:%s\n", check_pattern_type, check_pattern_value);
int match_count = 0;
while (sqlite3_step(stmt) == SQLITE_ROW) {
const char* rule_type = (const char*)sqlite3_column_text(stmt, 0);
const char* pattern_type = (const char*)sqlite3_column_text(stmt, 1);
const char* pattern_value = (const char*)sqlite3_column_text(stmt, 2);
const char* action = (const char*)sqlite3_column_text(stmt, 3);
printf(" MATCH: %s %s:%s -> %s\n",
rule_type ? rule_type : "",
pattern_type ? pattern_type : "",
pattern_value ? pattern_value : "",
action ? action : "allow");
match_count++;
}
sqlite3_finalize(stmt);
if (match_count == 0) {
printf(" No matching rules found for this pattern\n");
}
printf("Total matches: %d\n", match_count);
log_success("Pattern check completed successfully");
return 0;
}
// Handle clear all auth rules command
int handle_clear_all_auth_rules_command(cJSON* event, char* error_message, size_t error_size) {
(void)event; // Suppress unused parameter warning
if (!g_db) {
snprintf(error_message, error_size, "database not available");
return -1;
}
log_info("Processing clear all auth rules command");
// Count existing rules first
const char* count_sql = "SELECT COUNT(*) FROM auth_rules";
sqlite3_stmt* count_stmt;
int rc = sqlite3_prepare_v2(g_db, count_sql, -1, &count_stmt, NULL);
if (rc != SQLITE_OK) {
snprintf(error_message, error_size, "failed to prepare count query");
return -1;
}
int rule_count = 0;
if (sqlite3_step(count_stmt) == SQLITE_ROW) {
rule_count = sqlite3_column_int(count_stmt, 0);
}
sqlite3_finalize(count_stmt);
// Delete all auth rules (this operation succeeds even if table is empty)
const char* delete_sql = "DELETE FROM auth_rules";
rc = sqlite3_exec(g_db, delete_sql, NULL, NULL, NULL);
if (rc != SQLITE_OK) {
snprintf(error_message, error_size, "failed to execute clear auth rules command");
return -1;
}
// Always return success - clearing empty table is still a successful operation
if (rule_count > 0) {
printf("Cleared %d auth rules from database\n", rule_count);
log_success("All auth rules cleared successfully");
} else {
printf("Auth rules table was already empty - no rules to clear\n");
log_success("Clear auth rules completed successfully (table was already empty)");
}
return 0;
}
// Handle system status query
int handle_system_status_query(cJSON* event, char* error_message, size_t error_size) {
(void)event; // Suppress unused parameter warning
(void)error_message; // This command always succeeds
(void)error_size;
log_info("Processing system status query");
printf("=== System Status ===\n");
// Database status
printf("Database: %s\n", g_db ? "Connected" : "Not available");
if (strlen(g_database_path) > 0) {
printf("Database path: %s\n", g_database_path);
}
// Configuration status
printf("Unified cache: %s\n", g_unified_cache.cache_valid ? "Valid" : "Invalid");
printf("Admin pubkey: %s\n", g_unified_cache.admin_pubkey[0] ? g_unified_cache.admin_pubkey : "Not set");
printf("Relay pubkey: %s\n", g_unified_cache.relay_pubkey[0] ? g_unified_cache.relay_pubkey : "Not set");
// Count configuration items
if (g_db) {
const char* config_count_sql = "SELECT COUNT(*) FROM config";
sqlite3_stmt* stmt;
if (sqlite3_prepare_v2(g_db, config_count_sql, -1, &stmt, NULL) == SQLITE_OK) {
if (sqlite3_step(stmt) == SQLITE_ROW) {
int config_count = sqlite3_column_int(stmt, 0);
printf("Configuration items: %d\n", config_count);
}
sqlite3_finalize(stmt);
}
// Count auth rules
const char* auth_count_sql = "SELECT COUNT(*) FROM auth_rules";
if (sqlite3_prepare_v2(g_db, auth_count_sql, -1, &stmt, NULL) == SQLITE_OK) {
if (sqlite3_step(stmt) == SQLITE_ROW) {
int auth_count = sqlite3_column_int(stmt, 0);
printf("Auth rules: %d\n", auth_count);
}
sqlite3_finalize(stmt);
}
}
// Cache expiration
if (g_unified_cache.cache_expires > 0) {
time_t now = time(NULL);
long seconds_to_expire = g_unified_cache.cache_expires - now;
printf("Cache expires in: %ld seconds\n", seconds_to_expire);
}
printf("System time: %ld\n", (long)time(NULL));
log_success("System status retrieved successfully");
return 0;
}
// ================================
// CONFIGURATION CACHE MANAGEMENT
// ================================

View File

@@ -972,28 +972,28 @@ static void get_timestamp_string(char* buffer, size_t buffer_size) {
void log_info(const char* message) {
char timestamp[32];
get_timestamp_string(timestamp, sizeof(timestamp));
printf("[%s] " BLUE "[INFO]" RESET " %s\n", timestamp, message);
printf("[%s] [INFO] %s\n", timestamp, message);
fflush(stdout);
}
void log_success(const char* message) {
char timestamp[32];
get_timestamp_string(timestamp, sizeof(timestamp));
printf("[%s] " GREEN "[SUCCESS]" RESET " %s\n", timestamp, message);
printf("[%s] [SUCCESS] %s\n", timestamp, message);
fflush(stdout);
}
void log_error(const char* message) {
char timestamp[32];
get_timestamp_string(timestamp, sizeof(timestamp));
printf("[%s] " RED "[ERROR]" RESET " %s\n", timestamp, message);
printf("[%s] [ERROR] %s\n", timestamp, message);
fflush(stdout);
}
void log_warning(const char* message) {
char timestamp[32];
get_timestamp_string(timestamp, sizeof(timestamp));
printf("[%s] " YELLOW "[WARNING]" RESET " %s\n", timestamp, message);
printf("[%s] [WARNING] %s\n", timestamp, message);
fflush(stdout);
}
@@ -3243,7 +3243,7 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
// Cleanup event JSON string
free(event_json_str);
// Check for admin events (kinds 33334 and 33335) and intercept them
// Check for admin events (kinds 33334, 33335, 23455, and 23456) and intercept them
if (result == 0) {
cJSON* kind_obj = cJSON_GetObjectItem(event, "kind");
if (kind_obj && cJSON_IsNumber(kind_obj)) {
@@ -3251,7 +3251,21 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
log_info("DEBUG ADMIN: Checking if admin event processing is needed");
if (event_kind == 33334 || event_kind == 33335) {
// Log reception of Kind 23455 and 23456 events
if (event_kind == 23455 || event_kind == 23456) {
char* event_json_debug = cJSON_Print(event);
char debug_received_msg[1024];
snprintf(debug_received_msg, sizeof(debug_received_msg),
"RECEIVED Kind %d event: %s", event_kind,
event_json_debug ? event_json_debug : "Failed to serialize");
log_info(debug_received_msg);
if (event_json_debug) {
free(event_json_debug);
}
}
if (event_kind == 33334 || event_kind == 33335 || event_kind == 23455 || event_kind == 23456) {
// This is an admin event - process it through the admin API instead of normal storage
log_info("DEBUG ADMIN: Admin event detected, processing through admin API");
@@ -3263,6 +3277,21 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
"DEBUG ADMIN: process_admin_event_in_config returned %d", admin_result);
log_info(debug_admin_msg);
// Log results for Kind 23455 and 23456 events
if (event_kind == 23455 || event_kind == 23456) {
if (admin_result == 0) {
char success_result_msg[256];
snprintf(success_result_msg, sizeof(success_result_msg),
"SUCCESS: Kind %d event processed successfully", event_kind);
log_success(success_result_msg);
} else {
char error_result_msg[512];
snprintf(error_result_msg, sizeof(error_result_msg),
"ERROR: Kind %d event processing failed: %s", event_kind, admin_error);
log_error(error_result_msg);
}
}
if (admin_result != 0) {
log_error("DEBUG ADMIN: Failed to process admin event through admin API");
result = -1;

View File

@@ -629,28 +629,26 @@ static int check_database_auth_rules(const char *pubkey, const char *operation,
// Step 1: Check pubkey blacklist (highest priority)
const char *blacklist_sql =
"SELECT rule_type, description FROM auth_rules WHERE rule_type = "
"'pubkey_blacklist' AND rule_target = ? AND operation = ? AND enabled = "
"1 ORDER BY priority LIMIT 1";
"SELECT rule_type, action FROM auth_rules WHERE rule_type = "
"'blacklist' AND pattern_type = 'pubkey' AND pattern_value = ? LIMIT 1";
rc = sqlite3_prepare_v2(db, blacklist_sql, -1, &stmt, NULL);
if (rc == SQLITE_OK) {
sqlite3_bind_text(stmt, 1, pubkey, -1, SQLITE_STATIC);
sqlite3_bind_text(stmt, 2, operation ? operation : "", -1, SQLITE_STATIC);
if (sqlite3_step(stmt) == SQLITE_ROW) {
const char *description = (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: %s\n",
description ? description : "Unknown");
"VALIDATOR_DEBUG: RULES ENGINE - Blacklist rule matched: action=%s\n",
action ? action : "deny");
validator_debug_log(blacklist_msg);
// Set specific violation details for status code mapping
strcpy(g_last_rule_violation.violation_type, "pubkey_blacklist");
sprintf(g_last_rule_violation.reason, "%s: Public key blacklisted",
description ? description : "TEST_PUBKEY_BLACKLIST");
sprintf(g_last_rule_violation.reason, "Public key blacklisted: %s",
action ? action : "PUBKEY_BLACKLIST");
sqlite3_finalize(stmt);
sqlite3_close(db);
@@ -664,29 +662,27 @@ static int check_database_auth_rules(const char *pubkey, const char *operation,
// Step 2: Check hash blacklist
if (resource_hash) {
const char *hash_blacklist_sql =
"SELECT rule_type, description FROM auth_rules WHERE rule_type = "
"'hash_blacklist' AND rule_target = ? AND operation = ? AND enabled = "
"1 ORDER BY priority LIMIT 1";
"SELECT rule_type, action FROM auth_rules WHERE rule_type = "
"'blacklist' AND pattern_type = 'hash' AND pattern_value = ? LIMIT 1";
rc = sqlite3_prepare_v2(db, hash_blacklist_sql, -1, &stmt, NULL);
if (rc == SQLITE_OK) {
sqlite3_bind_text(stmt, 1, resource_hash, -1, SQLITE_STATIC);
sqlite3_bind_text(stmt, 2, operation ? operation : "", -1, SQLITE_STATIC);
if (sqlite3_step(stmt) == SQLITE_ROW) {
const char *description = (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: %s\n",
description ? description : "Unknown");
"VALIDATOR_DEBUG: RULES ENGINE - Hash blacklist rule matched: action=%s\n",
action ? action : "deny");
validator_debug_log(hash_blacklist_msg);
// Set specific violation details for status code mapping
strcpy(g_last_rule_violation.violation_type, "hash_blacklist");
sprintf(g_last_rule_violation.reason, "%s: File hash blacklisted",
description ? description : "TEST_HASH_BLACKLIST");
sprintf(g_last_rule_violation.reason, "File hash blacklisted: %s",
action ? action : "HASH_BLACKLIST");
sqlite3_finalize(stmt);
sqlite3_close(db);
@@ -703,22 +699,20 @@ static int check_database_auth_rules(const char *pubkey, const char *operation,
// Step 3: Check pubkey whitelist
const char *whitelist_sql =
"SELECT rule_type, description FROM auth_rules WHERE rule_type = "
"'pubkey_whitelist' AND rule_target = ? AND operation = ? AND enabled = "
"1 ORDER BY priority LIMIT 1";
"SELECT rule_type, action FROM auth_rules WHERE rule_type = "
"'whitelist' AND pattern_type = 'pubkey' AND pattern_value = ? LIMIT 1";
rc = sqlite3_prepare_v2(db, whitelist_sql, -1, &stmt, NULL);
if (rc == SQLITE_OK) {
sqlite3_bind_text(stmt, 1, pubkey, -1, SQLITE_STATIC);
sqlite3_bind_text(stmt, 2, operation ? operation : "", -1, SQLITE_STATIC);
if (sqlite3_step(stmt) == SQLITE_ROW) {
const char *description = (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 3 PASSED - "
"Pubkey whitelisted\n");
char whitelist_msg[256];
sprintf(whitelist_msg,
"VALIDATOR_DEBUG: RULES ENGINE - Whitelist rule matched: %s\n",
description ? description : "Unknown");
"VALIDATOR_DEBUG: RULES ENGINE - Whitelist rule matched: action=%s\n",
action ? action : "allow");
validator_debug_log(whitelist_msg);
sqlite3_finalize(stmt);
sqlite3_close(db);
@@ -731,12 +725,10 @@ static int check_database_auth_rules(const char *pubkey, const char *operation,
// Step 4: Check if any whitelist rules exist - if yes, deny by default
const char *whitelist_exists_sql =
"SELECT COUNT(*) FROM auth_rules WHERE rule_type = 'pubkey_whitelist' "
"AND operation = ? AND enabled = 1 LIMIT 1";
"SELECT COUNT(*) FROM auth_rules WHERE rule_type = 'whitelist' "
"AND pattern_type = 'pubkey' LIMIT 1";
rc = sqlite3_prepare_v2(db, whitelist_exists_sql, -1, &stmt, NULL);
if (rc == SQLITE_OK) {
sqlite3_bind_text(stmt, 1, operation ? operation : "", -1, SQLITE_STATIC);
if (sqlite3_step(stmt) == SQLITE_ROW) {
int whitelist_count = sqlite3_column_int(stmt, 0);
if (whitelist_count > 0) {