#define _GNU_SOURCE #include "config.h" #include "../nostr_core_lib/nostr_core/nostr_core.h" #include #include #include #include #include #include #include // External database connection (from main.c) extern sqlite3* g_db; // Logging functions (defined in main.c) extern void log_info(const char* message); extern void log_success(const char* message); extern void log_warning(const char* message); extern void log_error(const char* message); // Forward declarations for unified handlers extern int handle_auth_query_unified(cJSON* event, const char* query_type, char* error_message, size_t error_size, struct lws* wsi); extern int handle_config_query_unified(cJSON* event, const char* query_type, char* error_message, size_t error_size, struct lws* wsi); extern int handle_config_set_unified(cJSON* event, const char* config_key, const char* config_value, char* error_message, size_t error_size, struct lws* wsi); extern int handle_config_update_unified(cJSON* event, char* error_message, size_t error_size, struct lws* wsi); extern int handle_system_command_unified(cJSON* event, const char* command, char* error_message, size_t error_size, struct lws* wsi); extern int handle_stats_query_unified(cJSON* event, char* error_message, size_t error_size, struct lws* wsi); extern int handle_auth_rule_modification_unified(cJSON* event, char* error_message, size_t error_size, struct lws* wsi); // Forward declarations for tag parsing utilities extern const char* get_first_tag_name(cJSON* event); extern const char* get_tag_value(cJSON* event, const char* tag_name, int value_index); // ================================ // DIRECT MESSAGING ADMIN SYSTEM // ================================ // Process direct command arrays (DM control system) // This handles commands sent as direct JSON arrays, not wrapped in inner events int process_dm_admin_command(cJSON* command_array, cJSON* event, char* error_message, size_t error_size, struct lws* wsi) { if (!command_array || !cJSON_IsArray(command_array) || !event) { log_error("DM Admin: Invalid command array or event"); snprintf(error_message, error_size, "invalid: null command array or event"); return -1; } int array_size = cJSON_GetArraySize(command_array); if (array_size < 1) { log_error("DM Admin: Empty command array"); snprintf(error_message, error_size, "invalid: empty command array"); return -1; } // Get the command type from the first element cJSON* command_item = cJSON_GetArrayItem(command_array, 0); if (!command_item || !cJSON_IsString(command_item)) { log_error("DM Admin: First element is not a string command"); snprintf(error_message, error_size, "invalid: command must be a string"); return -1; } const char* command_type = cJSON_GetStringValue(command_item); log_info("DM Admin: Processing command"); printf(" Command: %s\n", command_type); printf(" Parameters: %d\n", array_size - 1); // Create synthetic tags from the command array for unified handler compatibility cJSON* synthetic_tags = cJSON_CreateArray(); // Add the command as the first tag cJSON* command_tag = cJSON_CreateArray(); cJSON_AddItemToArray(command_tag, cJSON_CreateString(command_type)); // Add remaining array elements as tag parameters for (int i = 1; i < array_size; i++) { cJSON* param = cJSON_GetArrayItem(command_array, i); if (param) { if (cJSON_IsString(param)) { cJSON_AddItemToArray(command_tag, cJSON_CreateString(cJSON_GetStringValue(param))); } else { // Convert non-string parameters to strings for tag compatibility char* param_str = cJSON_Print(param); if (param_str) { // Remove quotes from JSON string representation if (param_str[0] == '"' && param_str[strlen(param_str)-1] == '"') { param_str[strlen(param_str)-1] = '\0'; cJSON_AddItemToArray(command_tag, cJSON_CreateString(param_str + 1)); } else { cJSON_AddItemToArray(command_tag, cJSON_CreateString(param_str)); } free(param_str); } } } } cJSON_AddItemToArray(synthetic_tags, command_tag); // Add existing event tags cJSON* existing_tags = cJSON_GetObjectItem(event, "tags"); if (existing_tags && cJSON_IsArray(existing_tags)) { cJSON* tag = NULL; cJSON_ArrayForEach(tag, existing_tags) { cJSON_AddItemToArray(synthetic_tags, cJSON_Duplicate(tag, 1)); } } // Temporarily replace event tags with synthetic tags cJSON_ReplaceItemInObject(event, "tags", synthetic_tags); // Route to appropriate handler based on command type int result = -1; if (strcmp(command_type, "auth_query") == 0) { const char* query_type = get_tag_value(event, "auth_query", 1); if (!query_type) { log_error("DM Admin: Missing auth_query type parameter"); snprintf(error_message, error_size, "invalid: missing auth_query type"); } else { printf(" Query type: %s\n", query_type); result = handle_auth_query_unified(event, query_type, error_message, error_size, wsi); } } else if (strcmp(command_type, "config_query") == 0) { const char* query_type = get_tag_value(event, "config_query", 1); if (!query_type) { log_error("DM Admin: Missing config_query type parameter"); snprintf(error_message, error_size, "invalid: missing config_query type"); } else { printf(" Query type: %s\n", query_type); result = handle_config_query_unified(event, query_type, error_message, error_size, wsi); } } else if (strcmp(command_type, "config_set") == 0) { const char* config_key = get_tag_value(event, "config_set", 1); const char* config_value = get_tag_value(event, "config_set", 2); if (!config_key || !config_value) { log_error("DM Admin: Missing config_set parameters"); snprintf(error_message, error_size, "invalid: missing config_set key or value"); } else { printf(" Key: %s, Value: %s\n", config_key, config_value); result = handle_config_set_unified(event, config_key, config_value, error_message, error_size, wsi); } } else if (strcmp(command_type, "config_update") == 0) { result = handle_config_update_unified(event, error_message, error_size, wsi); } else if (strcmp(command_type, "system_command") == 0) { const char* command = get_tag_value(event, "system_command", 1); if (!command) { log_error("DM Admin: Missing system_command type parameter"); snprintf(error_message, error_size, "invalid: missing system_command type"); } else { printf(" System command: %s\n", command); result = handle_system_command_unified(event, command, error_message, error_size, wsi); } } else if (strcmp(command_type, "stats_query") == 0) { result = handle_stats_query_unified(event, error_message, error_size, wsi); } else if (strcmp(command_type, "whitelist") == 0 || strcmp(command_type, "blacklist") == 0) { printf(" Rule type: %s\n", command_type); result = handle_auth_rule_modification_unified(event, error_message, error_size, wsi); } else { log_error("DM Admin: Unknown command type"); printf(" Unknown command: %s\n", command_type); snprintf(error_message, error_size, "invalid: unknown DM command type '%s'", command_type); } if (result == 0) { log_success("DM Admin: Command processed successfully"); } else { log_error("DM Admin: Command processing failed"); } return result; } // Check if decrypted content is a direct command array (DM system) // Returns 1 if it's a valid command array, 0 if it should fall back to inner event parsing int is_dm_command_array(const char* decrypted_content) { if (!decrypted_content) { return 0; } // Quick check: must start with '[' for JSON array if (decrypted_content[0] != '[') { return 0; } // Try to parse as JSON array cJSON* parsed = cJSON_Parse(decrypted_content); if (!parsed) { return 0; } int is_array = cJSON_IsArray(parsed); cJSON_Delete(parsed); return is_array; }