v0.1.13 - Fix Kind 23458 test script: use websocat for bidirectional relay communication and correct nak decrypt flag (-p instead of --recipient-pubkey). Admin command system now fully functional end-to-end with NIP-44 encryption.
This commit is contained in:
316
src/admin_commands.c
Normal file
316
src/admin_commands.c
Normal file
@@ -0,0 +1,316 @@
|
||||
/*
|
||||
* Ginxsom Admin Commands Implementation
|
||||
*/
|
||||
|
||||
#include "admin_commands.h"
|
||||
#include "../nostr_core_lib/nostr_core/nostr_core.h"
|
||||
#include <sqlite3.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
// Forward declare app_log
|
||||
typedef enum {
|
||||
LOG_DEBUG = 0,
|
||||
LOG_INFO = 1,
|
||||
LOG_WARN = 2,
|
||||
LOG_ERROR = 3
|
||||
} log_level_t;
|
||||
|
||||
void app_log(log_level_t level, const char* format, ...);
|
||||
|
||||
// Global state
|
||||
static struct {
|
||||
int initialized;
|
||||
char db_path[512];
|
||||
} g_admin_state = {0};
|
||||
|
||||
// Initialize admin command system
|
||||
int admin_commands_init(const char *db_path) {
|
||||
if (g_admin_state.initialized) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
strncpy(g_admin_state.db_path, db_path, sizeof(g_admin_state.db_path) - 1);
|
||||
g_admin_state.initialized = 1;
|
||||
|
||||
app_log(LOG_INFO, "Admin command system initialized");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NIP-44 encryption helper
|
||||
int admin_encrypt_response(
|
||||
const unsigned char* server_privkey,
|
||||
const unsigned char* admin_pubkey,
|
||||
const char* plaintext_json,
|
||||
char* output,
|
||||
size_t output_size
|
||||
) {
|
||||
int result = nostr_nip44_encrypt(
|
||||
server_privkey,
|
||||
admin_pubkey,
|
||||
plaintext_json,
|
||||
output,
|
||||
output_size
|
||||
);
|
||||
|
||||
if (result != 0) {
|
||||
app_log(LOG_ERROR, "Failed to encrypt admin response: %d", result);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NIP-44 decryption helper
|
||||
int admin_decrypt_command(
|
||||
const unsigned char* server_privkey,
|
||||
const unsigned char* admin_pubkey,
|
||||
const char* encrypted_data,
|
||||
char* output,
|
||||
size_t output_size
|
||||
) {
|
||||
int result = nostr_nip44_decrypt(
|
||||
server_privkey,
|
||||
admin_pubkey,
|
||||
encrypted_data,
|
||||
output,
|
||||
output_size
|
||||
);
|
||||
|
||||
if (result != 0) {
|
||||
app_log(LOG_ERROR, "Failed to decrypt admin command: %d", result);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Create error response
|
||||
static cJSON* create_error_response(const char* query_type, const char* error_msg) {
|
||||
cJSON* response = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(response, "query_type", query_type);
|
||||
cJSON_AddStringToObject(response, "status", "error");
|
||||
cJSON_AddStringToObject(response, "error", error_msg);
|
||||
cJSON_AddNumberToObject(response, "timestamp", (double)time(NULL));
|
||||
return response;
|
||||
}
|
||||
|
||||
// Process admin command array and generate response
|
||||
cJSON* admin_commands_process(cJSON* command_array, const char* request_event_id) {
|
||||
(void)request_event_id; // Reserved for future use (e.g., logging, tracking)
|
||||
|
||||
if (!cJSON_IsArray(command_array) || cJSON_GetArraySize(command_array) < 1) {
|
||||
return create_error_response("unknown", "Invalid command format");
|
||||
}
|
||||
|
||||
cJSON* cmd_type = cJSON_GetArrayItem(command_array, 0);
|
||||
if (!cJSON_IsString(cmd_type)) {
|
||||
return create_error_response("unknown", "Command type must be string");
|
||||
}
|
||||
|
||||
const char* command = cmd_type->valuestring;
|
||||
app_log(LOG_INFO, "Processing admin command: %s", command);
|
||||
|
||||
// Route to appropriate handler
|
||||
if (strcmp(command, "config_query") == 0) {
|
||||
return admin_cmd_config_query(command_array);
|
||||
}
|
||||
else if (strcmp(command, "config_update") == 0) {
|
||||
return admin_cmd_config_update(command_array);
|
||||
}
|
||||
else if (strcmp(command, "stats_query") == 0) {
|
||||
return admin_cmd_stats_query(command_array);
|
||||
}
|
||||
else if (strcmp(command, "system_command") == 0) {
|
||||
// Check second parameter for system_status
|
||||
if (cJSON_GetArraySize(command_array) >= 2) {
|
||||
cJSON* subcmd = cJSON_GetArrayItem(command_array, 1);
|
||||
if (cJSON_IsString(subcmd) && strcmp(subcmd->valuestring, "system_status") == 0) {
|
||||
return admin_cmd_system_status(command_array);
|
||||
}
|
||||
}
|
||||
return create_error_response("system_command", "Unknown system command");
|
||||
}
|
||||
else if (strcmp(command, "blob_list") == 0) {
|
||||
return admin_cmd_blob_list(command_array);
|
||||
}
|
||||
else if (strcmp(command, "storage_stats") == 0) {
|
||||
return admin_cmd_storage_stats(command_array);
|
||||
}
|
||||
else if (strcmp(command, "sql_query") == 0) {
|
||||
return admin_cmd_sql_query(command_array);
|
||||
}
|
||||
else {
|
||||
char error_msg[256];
|
||||
snprintf(error_msg, sizeof(error_msg), "Unknown command: %s", command);
|
||||
return create_error_response("unknown", error_msg);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// COMMAND HANDLERS (Stub implementations - to be completed)
|
||||
// ============================================================================
|
||||
|
||||
cJSON* admin_cmd_config_query(cJSON* args) {
|
||||
cJSON* response = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(response, "query_type", "config_query");
|
||||
|
||||
// Open database
|
||||
sqlite3* db;
|
||||
int rc = sqlite3_open_v2(g_admin_state.db_path, &db, SQLITE_OPEN_READONLY, NULL);
|
||||
if (rc != SQLITE_OK) {
|
||||
cJSON_AddStringToObject(response, "status", "error");
|
||||
cJSON_AddStringToObject(response, "error", "Failed to open database");
|
||||
cJSON_AddNumberToObject(response, "timestamp", (double)time(NULL));
|
||||
return response;
|
||||
}
|
||||
|
||||
// Check if specific keys were requested (args[1] should be array of keys or null for all)
|
||||
cJSON* keys_array = NULL;
|
||||
if (cJSON_GetArraySize(args) >= 2) {
|
||||
keys_array = cJSON_GetArrayItem(args, 1);
|
||||
if (!cJSON_IsArray(keys_array) && !cJSON_IsNull(keys_array)) {
|
||||
cJSON_AddStringToObject(response, "status", "error");
|
||||
cJSON_AddStringToObject(response, "error", "Keys parameter must be array or null");
|
||||
cJSON_AddNumberToObject(response, "timestamp", (double)time(NULL));
|
||||
sqlite3_close(db);
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3_stmt* stmt;
|
||||
const char* sql;
|
||||
|
||||
if (keys_array && cJSON_IsArray(keys_array) && cJSON_GetArraySize(keys_array) > 0) {
|
||||
// Query specific keys
|
||||
int key_count = cJSON_GetArraySize(keys_array);
|
||||
|
||||
// Build SQL with placeholders
|
||||
char sql_buffer[1024] = "SELECT key, value, description FROM config WHERE key IN (?";
|
||||
for (int i = 1; i < key_count && i < 50; i++) { // Limit to 50 keys
|
||||
strncat(sql_buffer, ",?", sizeof(sql_buffer) - strlen(sql_buffer) - 1);
|
||||
}
|
||||
strncat(sql_buffer, ")", sizeof(sql_buffer) - strlen(sql_buffer) - 1);
|
||||
|
||||
rc = sqlite3_prepare_v2(db, sql_buffer, -1, &stmt, NULL);
|
||||
if (rc != SQLITE_OK) {
|
||||
cJSON_AddStringToObject(response, "status", "error");
|
||||
cJSON_AddStringToObject(response, "error", "Failed to prepare query");
|
||||
cJSON_AddNumberToObject(response, "timestamp", (double)time(NULL));
|
||||
sqlite3_close(db);
|
||||
return response;
|
||||
}
|
||||
|
||||
// Bind keys
|
||||
for (int i = 0; i < key_count && i < 50; i++) {
|
||||
cJSON* key_item = cJSON_GetArrayItem(keys_array, i);
|
||||
if (cJSON_IsString(key_item)) {
|
||||
sqlite3_bind_text(stmt, i + 1, key_item->valuestring, -1, SQLITE_STATIC);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Query all config values
|
||||
sql = "SELECT key, value, description FROM config ORDER BY key";
|
||||
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
|
||||
if (rc != SQLITE_OK) {
|
||||
cJSON_AddStringToObject(response, "status", "error");
|
||||
cJSON_AddStringToObject(response, "error", "Failed to prepare query");
|
||||
cJSON_AddNumberToObject(response, "timestamp", (double)time(NULL));
|
||||
sqlite3_close(db);
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
// Execute query and build result
|
||||
cJSON* config_obj = cJSON_CreateObject();
|
||||
int count = 0;
|
||||
|
||||
while ((rc = 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* description = (const char*)sqlite3_column_text(stmt, 2);
|
||||
|
||||
cJSON* entry = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(entry, "value", value ? value : "");
|
||||
if (description && strlen(description) > 0) {
|
||||
cJSON_AddStringToObject(entry, "description", description);
|
||||
}
|
||||
|
||||
cJSON_AddItemToObject(config_obj, key, entry);
|
||||
count++;
|
||||
}
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
sqlite3_close(db);
|
||||
|
||||
cJSON_AddStringToObject(response, "status", "success");
|
||||
cJSON_AddNumberToObject(response, "count", count);
|
||||
cJSON_AddItemToObject(response, "config", config_obj);
|
||||
cJSON_AddNumberToObject(response, "timestamp", (double)time(NULL));
|
||||
|
||||
app_log(LOG_INFO, "Config query returned %d entries", count);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
cJSON* admin_cmd_config_update(cJSON* args) {
|
||||
(void)args; // TODO: Parse args for config updates
|
||||
|
||||
cJSON* response = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(response, "query_type", "config_update");
|
||||
cJSON_AddStringToObject(response, "status", "not_implemented");
|
||||
cJSON_AddNumberToObject(response, "timestamp", (double)time(NULL));
|
||||
return response;
|
||||
}
|
||||
|
||||
cJSON* admin_cmd_stats_query(cJSON* args) {
|
||||
(void)args; // TODO: Parse args for stats filtering
|
||||
|
||||
cJSON* response = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(response, "query_type", "stats_query");
|
||||
cJSON_AddStringToObject(response, "status", "not_implemented");
|
||||
cJSON_AddNumberToObject(response, "timestamp", (double)time(NULL));
|
||||
return response;
|
||||
}
|
||||
|
||||
cJSON* admin_cmd_system_status(cJSON* args) {
|
||||
(void)args; // TODO: Parse args for status filtering
|
||||
|
||||
cJSON* response = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(response, "query_type", "system_status");
|
||||
cJSON_AddStringToObject(response, "status", "not_implemented");
|
||||
cJSON_AddNumberToObject(response, "timestamp", (double)time(NULL));
|
||||
return response;
|
||||
}
|
||||
|
||||
cJSON* admin_cmd_blob_list(cJSON* args) {
|
||||
(void)args; // TODO: Parse args for blob filtering
|
||||
|
||||
cJSON* response = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(response, "query_type", "blob_list");
|
||||
cJSON_AddStringToObject(response, "status", "not_implemented");
|
||||
cJSON_AddNumberToObject(response, "timestamp", (double)time(NULL));
|
||||
return response;
|
||||
}
|
||||
|
||||
cJSON* admin_cmd_storage_stats(cJSON* args) {
|
||||
(void)args; // TODO: Parse args for storage filtering
|
||||
|
||||
cJSON* response = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(response, "query_type", "storage_stats");
|
||||
cJSON_AddStringToObject(response, "status", "not_implemented");
|
||||
cJSON_AddNumberToObject(response, "timestamp", (double)time(NULL));
|
||||
return response;
|
||||
}
|
||||
|
||||
cJSON* admin_cmd_sql_query(cJSON* args) {
|
||||
(void)args; // TODO: Parse and validate SQL query
|
||||
|
||||
cJSON* response = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(response, "query_type", "sql_query");
|
||||
cJSON_AddStringToObject(response, "status", "not_implemented");
|
||||
cJSON_AddNumberToObject(response, "timestamp", (double)time(NULL));
|
||||
return response;
|
||||
}
|
||||
56
src/admin_commands.h
Normal file
56
src/admin_commands.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Ginxsom Admin Commands Interface
|
||||
*
|
||||
* Handles encrypted admin commands sent via Kind 23456 events
|
||||
* and generates encrypted responses as Kind 23457 events.
|
||||
*/
|
||||
|
||||
#ifndef ADMIN_COMMANDS_H
|
||||
#define ADMIN_COMMANDS_H
|
||||
|
||||
#include <cjson/cJSON.h>
|
||||
|
||||
// Command handler result codes
|
||||
typedef enum {
|
||||
ADMIN_CMD_SUCCESS = 0,
|
||||
ADMIN_CMD_ERROR_PARSE = -1,
|
||||
ADMIN_CMD_ERROR_UNKNOWN = -2,
|
||||
ADMIN_CMD_ERROR_INVALID = -3,
|
||||
ADMIN_CMD_ERROR_DATABASE = -4,
|
||||
ADMIN_CMD_ERROR_PERMISSION = -5
|
||||
} admin_cmd_result_t;
|
||||
|
||||
// Initialize admin command system
|
||||
int admin_commands_init(const char *db_path);
|
||||
|
||||
// Process an admin command and generate response
|
||||
// Returns cJSON response object (caller must free with cJSON_Delete)
|
||||
cJSON* admin_commands_process(cJSON* command_array, const char* request_event_id);
|
||||
|
||||
// Individual command handlers
|
||||
cJSON* admin_cmd_config_query(cJSON* args);
|
||||
cJSON* admin_cmd_config_update(cJSON* args);
|
||||
cJSON* admin_cmd_stats_query(cJSON* args);
|
||||
cJSON* admin_cmd_system_status(cJSON* args);
|
||||
cJSON* admin_cmd_blob_list(cJSON* args);
|
||||
cJSON* admin_cmd_storage_stats(cJSON* args);
|
||||
cJSON* admin_cmd_sql_query(cJSON* args);
|
||||
|
||||
// NIP-44 encryption/decryption helpers
|
||||
int admin_encrypt_response(
|
||||
const unsigned char* server_privkey,
|
||||
const unsigned char* admin_pubkey,
|
||||
const char* plaintext_json,
|
||||
char* output,
|
||||
size_t output_size
|
||||
);
|
||||
|
||||
int admin_decrypt_command(
|
||||
const unsigned char* server_privkey,
|
||||
const unsigned char* admin_pubkey,
|
||||
const char* encrypted_data,
|
||||
char* output,
|
||||
size_t output_size
|
||||
);
|
||||
|
||||
#endif /* ADMIN_COMMANDS_H */
|
||||
@@ -10,8 +10,8 @@
|
||||
// Version information (auto-updated by build system)
|
||||
#define VERSION_MAJOR 0
|
||||
#define VERSION_MINOR 1
|
||||
#define VERSION_PATCH 12
|
||||
#define VERSION "v0.1.12"
|
||||
#define VERSION_PATCH 13
|
||||
#define VERSION "v0.1.13"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
11
src/main.c
11
src/main.c
@@ -6,6 +6,7 @@
|
||||
#define _GNU_SOURCE
|
||||
#include "ginxsom.h"
|
||||
#include "relay_client.h"
|
||||
#include "admin_commands.h"
|
||||
#include "../nostr_core_lib/nostr_core/nostr_common.h"
|
||||
#include "../nostr_core_lib/nostr_core/utils.h"
|
||||
#include <getopt.h>
|
||||
@@ -2263,6 +2264,16 @@ if (!config_loaded /* && !initialize_server_config() */) {
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize admin commands system
|
||||
app_log(LOG_INFO, "Initializing admin commands system...");
|
||||
int admin_cmd_result = admin_commands_init(g_db_path);
|
||||
if (admin_cmd_result != 0) {
|
||||
app_log(LOG_WARN, "Failed to initialize admin commands system (result: %d)", admin_cmd_result);
|
||||
app_log(LOG_WARN, "Continuing without admin commands functionality");
|
||||
} else {
|
||||
app_log(LOG_INFO, "Admin commands system initialized successfully");
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// THIS IS WHERE THE REQUESTS ENTER THE FastCGI
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include "relay_client.h"
|
||||
#include "admin_commands.h"
|
||||
#include "../nostr_core_lib/nostr_core/nostr_core.h"
|
||||
#include <sqlite3.h>
|
||||
#include <stdio.h>
|
||||
@@ -529,7 +530,7 @@ int relay_client_publish_kind10002(void) {
|
||||
}
|
||||
}
|
||||
|
||||
// Send Kind 23457 admin response event
|
||||
// Send Kind 23459 admin response event
|
||||
int relay_client_send_admin_response(const char *recipient_pubkey, const char *response_content) {
|
||||
if (!g_relay_state.enabled || !g_relay_state.running || !g_relay_state.pool) {
|
||||
return -1;
|
||||
@@ -539,7 +540,7 @@ int relay_client_send_admin_response(const char *recipient_pubkey, const char *r
|
||||
return -1;
|
||||
}
|
||||
|
||||
app_log(LOG_INFO, "Sending Kind 23457 admin response to %s", recipient_pubkey);
|
||||
app_log(LOG_INFO, "Sending Kind 23459 admin response to %s", recipient_pubkey);
|
||||
|
||||
// TODO: Encrypt response_content using NIP-44
|
||||
// For now, use plaintext (stub implementation)
|
||||
@@ -560,9 +561,9 @@ int relay_client_send_admin_response(const char *recipient_pubkey, const char *r
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Create and sign Kind 23457 event
|
||||
// Create and sign Kind 23459 event
|
||||
cJSON* event = nostr_create_and_sign_event(
|
||||
23457, // kind
|
||||
23459, // kind
|
||||
encrypted_content, // content
|
||||
tags, // tags
|
||||
privkey_bytes, // private key
|
||||
@@ -572,7 +573,7 @@ int relay_client_send_admin_response(const char *recipient_pubkey, const char *r
|
||||
cJSON_Delete(tags);
|
||||
|
||||
if (!event) {
|
||||
app_log(LOG_ERROR, "Failed to create Kind 23457 event");
|
||||
app_log(LOG_ERROR, "Failed to create Kind 23459 event");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -583,16 +584,16 @@ int relay_client_send_admin_response(const char *recipient_pubkey, const char *r
|
||||
g_relay_state.relay_count,
|
||||
event,
|
||||
on_publish_response,
|
||||
(void*)"Kind 23457" // user_data to identify event type
|
||||
(void*)"Kind 23459" // user_data to identify event type
|
||||
);
|
||||
|
||||
cJSON_Delete(event);
|
||||
|
||||
if (result == 0) {
|
||||
app_log(LOG_INFO, "Kind 23457 admin response publish initiated");
|
||||
app_log(LOG_INFO, "Kind 23459 admin response publish initiated");
|
||||
return 0;
|
||||
} else {
|
||||
app_log(LOG_ERROR, "Failed to initiate Kind 23457 admin response publish");
|
||||
app_log(LOG_ERROR, "Failed to initiate Kind 23459 admin response publish");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -610,11 +611,11 @@ static void on_publish_response(const char* relay_url, const char* event_id, int
|
||||
}
|
||||
}
|
||||
|
||||
// Callback for received Kind 23456 admin command events
|
||||
// Callback for received Kind 23458 admin command events
|
||||
static void on_admin_command_event(cJSON* event, const char* relay_url, void* user_data) {
|
||||
(void)user_data;
|
||||
|
||||
app_log(LOG_INFO, "Received Kind 23456 admin command from relay: %s", relay_url);
|
||||
app_log(LOG_INFO, "Received Kind 23458 admin command from relay: %s", relay_url);
|
||||
|
||||
// Extract event fields
|
||||
cJSON* kind_json = cJSON_GetObjectItem(event, "kind");
|
||||
@@ -632,7 +633,7 @@ static void on_admin_command_event(cJSON* event, const char* relay_url, void* us
|
||||
const char* encrypted_content = cJSON_GetStringValue(content_json);
|
||||
const char* event_id = cJSON_GetStringValue(id_json);
|
||||
|
||||
if (kind != 23456) {
|
||||
if (kind != 23458) {
|
||||
app_log(LOG_WARN, "Unexpected event kind: %d", kind);
|
||||
return;
|
||||
}
|
||||
@@ -645,12 +646,98 @@ static void on_admin_command_event(cJSON* event, const char* relay_url, void* us
|
||||
|
||||
app_log(LOG_INFO, "Processing admin command (event ID: %s)", event_id);
|
||||
|
||||
// TODO: Decrypt content using NIP-44
|
||||
// For now, log the encrypted content
|
||||
app_log(LOG_DEBUG, "Encrypted command content: %s", encrypted_content);
|
||||
// Convert keys from hex to bytes
|
||||
unsigned char server_privkey[32];
|
||||
unsigned char admin_pubkey_bytes[32];
|
||||
|
||||
// TODO: Parse and execute command
|
||||
// TODO: Send response using relay_client_send_admin_response()
|
||||
if (nostr_hex_to_bytes(g_blossom_seckey, server_privkey, 32) != 0) {
|
||||
app_log(LOG_ERROR, "Failed to convert server private key from hex");
|
||||
return;
|
||||
}
|
||||
|
||||
if (nostr_hex_to_bytes(sender_pubkey, admin_pubkey_bytes, 32) != 0) {
|
||||
app_log(LOG_ERROR, "Failed to convert admin public key from hex");
|
||||
return;
|
||||
}
|
||||
|
||||
// Decrypt command content using NIP-44
|
||||
char decrypted_command[4096];
|
||||
if (admin_decrypt_command(server_privkey, admin_pubkey_bytes, encrypted_content,
|
||||
decrypted_command, sizeof(decrypted_command)) != 0) {
|
||||
app_log(LOG_ERROR, "Failed to decrypt admin command");
|
||||
|
||||
// Send error response
|
||||
cJSON* error_response = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(error_response, "status", "error");
|
||||
cJSON_AddStringToObject(error_response, "message", "Failed to decrypt command");
|
||||
char* error_json = cJSON_PrintUnformatted(error_response);
|
||||
cJSON_Delete(error_response);
|
||||
|
||||
char encrypted_response[4096];
|
||||
if (admin_encrypt_response(server_privkey, admin_pubkey_bytes, error_json,
|
||||
encrypted_response, sizeof(encrypted_response)) == 0) {
|
||||
relay_client_send_admin_response(sender_pubkey, encrypted_response);
|
||||
}
|
||||
free(error_json);
|
||||
return;
|
||||
}
|
||||
|
||||
app_log(LOG_DEBUG, "Decrypted command: %s", decrypted_command);
|
||||
|
||||
// Parse command JSON
|
||||
cJSON* command_json = cJSON_Parse(decrypted_command);
|
||||
if (!command_json) {
|
||||
app_log(LOG_ERROR, "Failed to parse command JSON");
|
||||
|
||||
cJSON* error_response = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(error_response, "status", "error");
|
||||
cJSON_AddStringToObject(error_response, "message", "Invalid JSON format");
|
||||
char* error_json = cJSON_PrintUnformatted(error_response);
|
||||
cJSON_Delete(error_response);
|
||||
|
||||
char encrypted_response[4096];
|
||||
if (admin_encrypt_response(server_privkey, admin_pubkey_bytes, error_json,
|
||||
encrypted_response, sizeof(encrypted_response)) == 0) {
|
||||
relay_client_send_admin_response(sender_pubkey, encrypted_response);
|
||||
}
|
||||
free(error_json);
|
||||
return;
|
||||
}
|
||||
|
||||
// Process command and get response
|
||||
cJSON* response_json = admin_commands_process(command_json, event_id);
|
||||
cJSON_Delete(command_json);
|
||||
|
||||
if (!response_json) {
|
||||
app_log(LOG_ERROR, "Failed to process admin command");
|
||||
response_json = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(response_json, "status", "error");
|
||||
cJSON_AddStringToObject(response_json, "message", "Failed to process command");
|
||||
}
|
||||
|
||||
// Convert response to JSON string
|
||||
char* response_str = cJSON_PrintUnformatted(response_json);
|
||||
cJSON_Delete(response_json);
|
||||
|
||||
if (!response_str) {
|
||||
app_log(LOG_ERROR, "Failed to serialize response JSON");
|
||||
return;
|
||||
}
|
||||
|
||||
// Encrypt and send response
|
||||
char encrypted_response[4096];
|
||||
if (admin_encrypt_response(server_privkey, admin_pubkey_bytes, response_str,
|
||||
encrypted_response, sizeof(encrypted_response)) != 0) {
|
||||
app_log(LOG_ERROR, "Failed to encrypt admin response");
|
||||
free(response_str);
|
||||
return;
|
||||
}
|
||||
|
||||
free(response_str);
|
||||
|
||||
if (relay_client_send_admin_response(sender_pubkey, encrypted_response) != 0) {
|
||||
app_log(LOG_ERROR, "Failed to send admin response");
|
||||
}
|
||||
}
|
||||
|
||||
// Callback for EOSE (End Of Stored Events) - new signature
|
||||
@@ -661,18 +748,18 @@ static void on_admin_subscription_eose(cJSON** events, int event_count, void* us
|
||||
app_log(LOG_INFO, "Received EOSE for admin command subscription");
|
||||
}
|
||||
|
||||
// Subscribe to admin commands (Kind 23456)
|
||||
// Subscribe to admin commands (Kind 23458)
|
||||
static int subscribe_to_admin_commands(void) {
|
||||
if (!g_relay_state.pool) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
app_log(LOG_INFO, "Subscribing to Kind 23456 admin commands...");
|
||||
app_log(LOG_INFO, "Subscribing to Kind 23458 admin commands...");
|
||||
|
||||
// Create subscription filter for Kind 23456 events addressed to us
|
||||
// Create subscription filter for Kind 23458 events addressed to us
|
||||
cJSON* filter = cJSON_CreateObject();
|
||||
cJSON* kinds = cJSON_CreateArray();
|
||||
cJSON_AddItemToArray(kinds, cJSON_CreateNumber(23456));
|
||||
cJSON_AddItemToArray(kinds, cJSON_CreateNumber(23458));
|
||||
cJSON_AddItemToObject(filter, "kinds", kinds);
|
||||
|
||||
cJSON* p_tags = cJSON_CreateArray();
|
||||
|
||||
Reference in New Issue
Block a user