Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d655258311 |
@@ -3078,10 +3078,14 @@
|
||||
messageDiv.className = 'log-entry';
|
||||
|
||||
const directionColor = direction === 'sent' ? '#007bff' : '#28a745';
|
||||
|
||||
// Convert newlines to <br> tags for proper HTML display
|
||||
const formattedMessage = message.replace(/\n/g, '<br>');
|
||||
|
||||
messageDiv.innerHTML = `
|
||||
<span class="log-timestamp">${timestamp}</span>
|
||||
<span style="color: ${directionColor}; font-weight: bold;">[${direction.toUpperCase()}]</span>
|
||||
${message}
|
||||
<span style="white-space: pre-wrap;">${formattedMessage}</span>
|
||||
`;
|
||||
|
||||
// Remove the "No messages received yet" placeholder if it exists
|
||||
|
||||
629
src/dm_admin.c
629
src/dm_admin.c
@@ -36,9 +36,13 @@ extern const char* get_tag_value(cJSON* event, const char* tag_name, int value_i
|
||||
// Forward declarations for config functions
|
||||
extern const char* get_relay_pubkey_cached(void);
|
||||
extern char* get_relay_private_key(void);
|
||||
extern const char* get_config_value(const char* key);
|
||||
extern int get_config_bool(const char* key, int default_value);
|
||||
extern const char* get_admin_pubkey_cached(void);
|
||||
|
||||
// Forward declarations for database functions
|
||||
extern int store_event(cJSON* event);
|
||||
extern int broadcast_event_to_subscriptions(cJSON* event);
|
||||
|
||||
// Forward declarations for stats generation
|
||||
extern char* generate_stats_json(void);
|
||||
@@ -315,6 +319,224 @@ char* generate_stats_json(void) {
|
||||
return json_string;
|
||||
}
|
||||
|
||||
// Unified NIP-17 response sender - handles all common response logic
|
||||
int send_nip17_response(const char* sender_pubkey, const char* response_content,
|
||||
char* error_message, size_t error_size) {
|
||||
if (!sender_pubkey || !response_content || !error_message) {
|
||||
if (error_message) {
|
||||
strncpy(error_message, "NIP-17: Invalid parameters for response", error_size - 1);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get relay keys for signing
|
||||
const char* relay_pubkey = get_relay_pubkey_cached();
|
||||
char* relay_privkey_hex = get_relay_private_key();
|
||||
if (!relay_pubkey || !relay_privkey_hex) {
|
||||
if (relay_privkey_hex) free(relay_privkey_hex);
|
||||
strncpy(error_message, "NIP-17: Could not get relay keys for response", error_size - 1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Convert relay private key to bytes
|
||||
unsigned char relay_privkey[32];
|
||||
if (nostr_hex_to_bytes(relay_privkey_hex, relay_privkey, sizeof(relay_privkey)) != 0) {
|
||||
free(relay_privkey_hex);
|
||||
strncpy(error_message, "NIP-17: Failed to convert relay private key for response", error_size - 1);
|
||||
return -1;
|
||||
}
|
||||
free(relay_privkey_hex);
|
||||
|
||||
// Create DM response event using library function
|
||||
cJSON* dm_response = nostr_nip17_create_chat_event(
|
||||
response_content, // message content
|
||||
(const char**)&sender_pubkey, // recipient pubkeys
|
||||
1, // num recipients
|
||||
NULL, // subject (optional)
|
||||
NULL, // reply_to_event_id (optional)
|
||||
NULL, // reply_relay_url (optional)
|
||||
relay_pubkey // sender pubkey
|
||||
);
|
||||
|
||||
if (!dm_response) {
|
||||
strncpy(error_message, "NIP-17: Failed to create DM response event", error_size - 1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Create and sign gift wrap using library function
|
||||
cJSON* gift_wraps[1];
|
||||
int send_result = nostr_nip17_send_dm(
|
||||
dm_response, // dm_event
|
||||
(const char**)&sender_pubkey, // recipient_pubkeys
|
||||
1, // num_recipients
|
||||
relay_privkey, // sender_private_key
|
||||
gift_wraps, // gift_wraps_out
|
||||
1 // max_gift_wraps
|
||||
);
|
||||
|
||||
cJSON_Delete(dm_response);
|
||||
|
||||
if (send_result != 1 || !gift_wraps[0]) {
|
||||
strncpy(error_message, "NIP-17: Failed to create and sign response gift wrap", error_size - 1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Fix the p tag in the gift wrap - library function may use wrong pubkey
|
||||
cJSON* gift_wrap_tags = cJSON_GetObjectItem(gift_wraps[0], "tags");
|
||||
if (gift_wrap_tags && cJSON_IsArray(gift_wrap_tags)) {
|
||||
// Find and replace the p tag with the correct user pubkey
|
||||
cJSON* tag = NULL;
|
||||
cJSON_ArrayForEach(tag, gift_wrap_tags) {
|
||||
if (cJSON_IsArray(tag) && cJSON_GetArraySize(tag) >= 2) {
|
||||
cJSON* tag_name = cJSON_GetArrayItem(tag, 0);
|
||||
if (tag_name && cJSON_IsString(tag_name) &&
|
||||
strcmp(cJSON_GetStringValue(tag_name), "p") == 0) {
|
||||
// Replace the p tag value with the correct user pubkey
|
||||
cJSON_ReplaceItemInArray(tag, 1, cJSON_CreateString(sender_pubkey));
|
||||
log_info("NIP-17: Fixed p tag in response gift wrap");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Store the gift wrap in database
|
||||
int store_result = store_event(gift_wraps[0]);
|
||||
|
||||
if (store_result != 0) {
|
||||
cJSON_Delete(gift_wraps[0]);
|
||||
strncpy(error_message, "NIP-17: Failed to store response gift wrap", error_size - 1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Broadcast the response event to active subscriptions
|
||||
int broadcast_count = broadcast_event_to_subscriptions(gift_wraps[0]);
|
||||
char debug_broadcast_msg[128];
|
||||
snprintf(debug_broadcast_msg, sizeof(debug_broadcast_msg),
|
||||
"NIP-17: Response broadcast to %d subscriptions", broadcast_count);
|
||||
log_info(debug_broadcast_msg);
|
||||
|
||||
cJSON_Delete(gift_wraps[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Generate config text from database
|
||||
char* generate_config_text(void) {
|
||||
extern sqlite3* g_db;
|
||||
if (!g_db) {
|
||||
log_error("NIP-17: Database not available for config query");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Build comprehensive config text from database
|
||||
char* config_text = malloc(8192);
|
||||
if (!config_text) {
|
||||
log_error("NIP-17: Failed to allocate memory for config text");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int offset = 0;
|
||||
|
||||
// Header
|
||||
offset += snprintf(config_text + offset, 8192 - offset,
|
||||
"🔧 Relay Configuration\n"
|
||||
"━━━━━━━━━━━━━━━━━━━━━━━━\n");
|
||||
|
||||
// Query all config values from database
|
||||
sqlite3_stmt* stmt;
|
||||
if (sqlite3_prepare_v2(g_db, "SELECT key, value FROM config ORDER BY key", -1, &stmt, NULL) == SQLITE_OK) {
|
||||
while (sqlite3_step(stmt) == SQLITE_ROW && offset < 8192 - 200) {
|
||||
const char* key = (const char*)sqlite3_column_text(stmt, 0);
|
||||
const char* value = (const char*)sqlite3_column_text(stmt, 1);
|
||||
|
||||
if (key && value) {
|
||||
offset += snprintf(config_text + offset, 8192 - offset,
|
||||
"%s: %s\n", key, value);
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
} else {
|
||||
free(config_text);
|
||||
log_error("NIP-17: Failed to query config from database");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Footer
|
||||
offset += snprintf(config_text + offset, 8192 - offset,
|
||||
"\n✅ Configuration retrieved successfully");
|
||||
|
||||
return config_text;
|
||||
}
|
||||
|
||||
// Generate human-readable stats text
|
||||
char* generate_stats_text(void) {
|
||||
char* stats_json = generate_stats_json();
|
||||
if (!stats_json) {
|
||||
log_error("NIP-17: Failed to generate stats for plain text command");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Parse the JSON to extract values for human-readable format
|
||||
cJSON* stats_obj = cJSON_Parse(stats_json);
|
||||
char* stats_text = malloc(4096);
|
||||
if (!stats_text) {
|
||||
free(stats_json);
|
||||
if (stats_obj) cJSON_Delete(stats_obj);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (stats_obj) {
|
||||
cJSON* total_events = cJSON_GetObjectItem(stats_obj, "total_events");
|
||||
cJSON* db_size = cJSON_GetObjectItem(stats_obj, "database_size_bytes");
|
||||
cJSON* time_stats = cJSON_GetObjectItem(stats_obj, "time_stats");
|
||||
|
||||
long long total = total_events ? (long long)cJSON_GetNumberValue(total_events) : 0;
|
||||
long long db_bytes = db_size ? (long long)cJSON_GetNumberValue(db_size) : 0;
|
||||
double db_mb = db_bytes / (1024.0 * 1024.0);
|
||||
|
||||
long long last_24h = 0, last_7d = 0, last_30d = 0;
|
||||
if (time_stats) {
|
||||
cJSON* h24 = cJSON_GetObjectItem(time_stats, "last_24h");
|
||||
cJSON* d7 = cJSON_GetObjectItem(time_stats, "last_7d");
|
||||
cJSON* d30 = cJSON_GetObjectItem(time_stats, "last_30d");
|
||||
last_24h = h24 ? (long long)cJSON_GetNumberValue(h24) : 0;
|
||||
last_7d = d7 ? (long long)cJSON_GetNumberValue(d7) : 0;
|
||||
last_30d = d30 ? (long long)cJSON_GetNumberValue(d30) : 0;
|
||||
}
|
||||
|
||||
snprintf(stats_text, 4096,
|
||||
"📊 Relay Statistics\n"
|
||||
"━━━━━━━━━━━━━━━━━━━━\n"
|
||||
"Total Events: %lld\n"
|
||||
"Database Size: %.2f MB (%lld bytes)\n"
|
||||
"\n"
|
||||
"📈 Recent Activity\n"
|
||||
"━━━━━━━━━━━━━━━━━━━\n"
|
||||
"Last 24 hours: %lld events\n"
|
||||
"Last 7 days: %lld events\n"
|
||||
"Last 30 days: %lld events\n"
|
||||
"\n"
|
||||
"✅ Statistics retrieved successfully",
|
||||
total, db_mb, db_bytes, last_24h, last_7d, last_30d
|
||||
);
|
||||
|
||||
cJSON_Delete(stats_obj);
|
||||
} else {
|
||||
// Fallback if JSON parsing fails
|
||||
snprintf(stats_text, 4096,
|
||||
"📊 Relay Statistics\n"
|
||||
"━━━━━━━━━━━━━━━━━━━━\n"
|
||||
"Raw data: %s\n"
|
||||
"\n"
|
||||
"⚠️ Could not parse statistics data",
|
||||
stats_json
|
||||
);
|
||||
}
|
||||
|
||||
free(stats_json);
|
||||
return stats_text;
|
||||
}
|
||||
|
||||
// Main NIP-17 processing function
|
||||
cJSON* process_nip17_admin_message(cJSON* gift_wrap_event, char* error_message, size_t error_size, struct lws* wsi) {
|
||||
if (!gift_wrap_event || !error_message) {
|
||||
@@ -375,8 +597,50 @@ cJSON* process_nip17_admin_message(cJSON* gift_wrap_event, char* error_message,
|
||||
// Step 4: Process admin command
|
||||
int result = process_nip17_admin_command(inner_dm, error_message, error_size, wsi);
|
||||
|
||||
// Step 5: Create response if command was processed successfully
|
||||
// Step 5: For plain text commands (stats/config), the response is already handled
|
||||
// Only create a generic response for other command types that don't handle their own responses
|
||||
if (result == 0) {
|
||||
// Extract content to check if it's a plain text command
|
||||
cJSON* content_obj = cJSON_GetObjectItem(inner_dm, "content");
|
||||
if (content_obj && cJSON_IsString(content_obj)) {
|
||||
const char* dm_content = cJSON_GetStringValue(content_obj);
|
||||
|
||||
// Check if it's a plain text command that already handled its response
|
||||
char content_lower[256];
|
||||
size_t content_len = strlen(dm_content);
|
||||
size_t copy_len = content_len < sizeof(content_lower) - 1 ? content_len : sizeof(content_lower) - 1;
|
||||
memcpy(content_lower, dm_content, copy_len);
|
||||
content_lower[copy_len] = '\0';
|
||||
|
||||
// Convert to lowercase
|
||||
for (size_t i = 0; i < copy_len; i++) {
|
||||
if (content_lower[i] >= 'A' && content_lower[i] <= 'Z') {
|
||||
content_lower[i] = content_lower[i] + 32;
|
||||
}
|
||||
}
|
||||
|
||||
// If it's a plain text stats or config command, don't create additional response
|
||||
if (strstr(content_lower, "stats") != NULL || strstr(content_lower, "statistics") != NULL ||
|
||||
strstr(content_lower, "config") != NULL || strstr(content_lower, "configuration") != NULL) {
|
||||
log_info("NIP-17: Plain text command already handled response, skipping generic response");
|
||||
cJSON_Delete(inner_dm);
|
||||
return NULL; // No additional response needed
|
||||
}
|
||||
|
||||
// Check if it's a JSON array command that might be stats
|
||||
cJSON* command_array = cJSON_Parse(dm_content);
|
||||
if (command_array && cJSON_IsArray(command_array) && cJSON_GetArraySize(command_array) > 0) {
|
||||
cJSON* first_item = cJSON_GetArrayItem(command_array, 0);
|
||||
if (cJSON_IsString(first_item) && strcmp(cJSON_GetStringValue(first_item), "stats") == 0) {
|
||||
log_info("NIP-17: JSON stats command already handled response, skipping generic response");
|
||||
cJSON_Delete(command_array);
|
||||
cJSON_Delete(inner_dm);
|
||||
return NULL; // No additional response needed
|
||||
}
|
||||
cJSON_Delete(command_array);
|
||||
}
|
||||
}
|
||||
|
||||
// Get sender pubkey for response from the decrypted DM event
|
||||
cJSON* sender_pubkey_obj = cJSON_GetObjectItem(inner_dm, "pubkey");
|
||||
if (sender_pubkey_obj && cJSON_IsString(sender_pubkey_obj)) {
|
||||
@@ -557,112 +821,20 @@ int process_nip17_admin_command(cJSON* dm_event, char* error_message, size_t err
|
||||
log_info("NIP-17: Recognized plain text 'stats' command from admin");
|
||||
log_info("NIP-17: Action: Generate and send relay statistics");
|
||||
|
||||
// Generate stats JSON
|
||||
char* stats_json = generate_stats_json();
|
||||
if (!stats_json) {
|
||||
log_error("NIP-17: Failed to generate stats for plain text command");
|
||||
char* stats_text = generate_stats_text();
|
||||
if (!stats_text) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get relay keys for signing
|
||||
const char* relay_pubkey = get_relay_pubkey_cached();
|
||||
char* relay_privkey_hex = get_relay_private_key();
|
||||
if (!relay_pubkey || !relay_privkey_hex) {
|
||||
free(stats_json);
|
||||
log_error("NIP-17: Could not get relay keys for stats response");
|
||||
char error_msg[256];
|
||||
int result = send_nip17_response(sender_pubkey, stats_text, error_msg, sizeof(error_msg));
|
||||
free(stats_text);
|
||||
|
||||
if (result != 0) {
|
||||
log_error(error_msg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Convert relay private key to bytes
|
||||
unsigned char relay_privkey[32];
|
||||
if (nostr_hex_to_bytes(relay_privkey_hex, relay_privkey, sizeof(relay_privkey)) != 0) {
|
||||
free(stats_json);
|
||||
free(relay_privkey_hex);
|
||||
log_error("NIP-17: Failed to convert relay private key for stats response");
|
||||
return -1;
|
||||
}
|
||||
free(relay_privkey_hex);
|
||||
|
||||
// Create DM response event using library function
|
||||
cJSON* dm_response = nostr_nip17_create_chat_event(
|
||||
stats_json, // message content
|
||||
(const char**)&sender_pubkey, // recipient pubkeys
|
||||
1, // num recipients
|
||||
NULL, // subject (optional)
|
||||
NULL, // reply_to_event_id (optional)
|
||||
NULL, // reply_relay_url (optional)
|
||||
relay_pubkey // sender pubkey
|
||||
);
|
||||
|
||||
free(stats_json);
|
||||
|
||||
if (!dm_response) {
|
||||
log_error("NIP-17: Failed to create DM response event for stats");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Create and sign gift wrap using library function
|
||||
cJSON* gift_wraps[1];
|
||||
int send_result = nostr_nip17_send_dm(
|
||||
dm_response, // dm_event
|
||||
(const char**)&sender_pubkey, // recipient_pubkeys
|
||||
1, // num_recipients
|
||||
relay_privkey, // sender_private_key
|
||||
gift_wraps, // gift_wraps_out
|
||||
1 // max_gift_wraps
|
||||
);
|
||||
|
||||
cJSON_Delete(dm_response);
|
||||
|
||||
if (send_result != 1 || !gift_wraps[0]) {
|
||||
log_error("NIP-17: Failed to create and sign response gift wrap for stats");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Fix the p tag in the gift wrap - library function may use wrong pubkey
|
||||
cJSON* gift_wrap_tags = cJSON_GetObjectItem(gift_wraps[0], "tags");
|
||||
if (gift_wrap_tags && cJSON_IsArray(gift_wrap_tags)) {
|
||||
// Find and replace the p tag with the correct user pubkey
|
||||
cJSON* tag = NULL;
|
||||
cJSON_ArrayForEach(tag, gift_wrap_tags) {
|
||||
if (cJSON_IsArray(tag) && cJSON_GetArraySize(tag) >= 2) {
|
||||
cJSON* tag_name = cJSON_GetArrayItem(tag, 0);
|
||||
if (tag_name && cJSON_IsString(tag_name) &&
|
||||
strcmp(cJSON_GetStringValue(tag_name), "p") == 0) {
|
||||
// Replace the p tag value with the correct user pubkey
|
||||
cJSON_ReplaceItemInArray(tag, 1, cJSON_CreateString(sender_pubkey));
|
||||
log_info("NIP-17: Fixed p tag in stats response gift wrap");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Debug print to show the response event
|
||||
char* response_debug = cJSON_Print(gift_wraps[0]);
|
||||
if (response_debug) {
|
||||
log_info("DM Admin: Response event created");
|
||||
printf(" Response event: %s\n", response_debug);
|
||||
free(response_debug);
|
||||
}
|
||||
|
||||
// Debug: Print event before storing
|
||||
char* debug_before_store = cJSON_Print(gift_wraps[0]);
|
||||
if (debug_before_store) {
|
||||
log_info("DEBUG EVENT: Before storing in database");
|
||||
printf(" Event: %s\n", debug_before_store);
|
||||
free(debug_before_store);
|
||||
}
|
||||
|
||||
// Store the gift wrap in database
|
||||
int store_result = store_event(gift_wraps[0]);
|
||||
cJSON_Delete(gift_wraps[0]);
|
||||
|
||||
if (store_result != 0) {
|
||||
log_error("NIP-17: Failed to store response gift wrap for stats");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
log_success("NIP-17: Stats command processed successfully, response sent");
|
||||
return 0;
|
||||
}
|
||||
@@ -671,129 +843,20 @@ int process_nip17_admin_command(cJSON* dm_event, char* error_message, size_t err
|
||||
log_info("NIP-17: Recognized plain text 'config' command from admin");
|
||||
log_info("NIP-17: Action: Generate and send relay configuration");
|
||||
|
||||
// Get relay pubkey for config response
|
||||
const char* relay_pubkey = get_relay_pubkey_cached();
|
||||
|
||||
// Generate config JSON - for now, use a simple config summary
|
||||
cJSON* config_response = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(config_response, "command", "config");
|
||||
cJSON_AddStringToObject(config_response, "relay_pubkey", relay_pubkey ? relay_pubkey : "unknown");
|
||||
|
||||
// Add some basic config values
|
||||
const char* port = get_config_value("relay_port");
|
||||
const char* nip42_auth = get_config_bool("nip42_auth_required_events", 0) ? "enabled" : "disabled";
|
||||
const char* nip42_sub = get_config_bool("nip42_auth_required_subscriptions", 0) ? "enabled" : "disabled";
|
||||
|
||||
cJSON_AddStringToObject(config_response, "relay_port", port ? port : "8888");
|
||||
cJSON_AddStringToObject(config_response, "nip42_auth_events", nip42_auth);
|
||||
cJSON_AddStringToObject(config_response, "nip42_auth_subscriptions", nip42_sub);
|
||||
|
||||
char* config_json = cJSON_Print(config_response);
|
||||
cJSON_Delete(config_response);
|
||||
|
||||
if (!config_json) {
|
||||
log_error("NIP-17: Failed to generate config JSON for plain text command");
|
||||
char* config_text = generate_config_text();
|
||||
if (!config_text) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get relay keys for signing
|
||||
char* relay_privkey_hex = get_relay_private_key();
|
||||
if (!relay_privkey_hex) {
|
||||
free(config_json);
|
||||
log_error("NIP-17: Could not get relay private key for config response");
|
||||
char error_msg[256];
|
||||
int result = send_nip17_response(sender_pubkey, config_text, error_msg, sizeof(error_msg));
|
||||
free(config_text);
|
||||
|
||||
if (result != 0) {
|
||||
log_error(error_msg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Convert relay private key to bytes
|
||||
unsigned char relay_privkey[32];
|
||||
if (nostr_hex_to_bytes(relay_privkey_hex, relay_privkey, sizeof(relay_privkey)) != 0) {
|
||||
free(config_json);
|
||||
free(relay_privkey_hex);
|
||||
log_error("NIP-17: Failed to convert relay private key for config response");
|
||||
return -1;
|
||||
}
|
||||
free(relay_privkey_hex);
|
||||
|
||||
// Create DM response event using library function
|
||||
cJSON* dm_response = nostr_nip17_create_chat_event(
|
||||
config_json, // message content
|
||||
(const char**)&sender_pubkey, // recipient pubkeys
|
||||
1, // num recipients
|
||||
NULL, // subject (optional)
|
||||
NULL, // reply_to_event_id (optional)
|
||||
NULL, // reply_relay_url (optional)
|
||||
relay_pubkey // sender pubkey (already declared above)
|
||||
);
|
||||
|
||||
free(config_json);
|
||||
|
||||
if (!dm_response) {
|
||||
log_error("NIP-17: Failed to create DM response event for config");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Create and sign gift wrap using library function
|
||||
cJSON* gift_wraps[1];
|
||||
int send_result = nostr_nip17_send_dm(
|
||||
dm_response, // dm_event
|
||||
(const char**)&sender_pubkey, // recipient_pubkeys
|
||||
1, // num_recipients
|
||||
relay_privkey, // sender_private_key
|
||||
gift_wraps, // gift_wraps_out
|
||||
1 // max_gift_wraps
|
||||
);
|
||||
|
||||
cJSON_Delete(dm_response);
|
||||
|
||||
if (send_result != 1 || !gift_wraps[0]) {
|
||||
log_error("NIP-17: Failed to create and sign response gift wrap for config");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Fix the p tag in the gift wrap - library function may use wrong pubkey
|
||||
cJSON* gift_wrap_tags = cJSON_GetObjectItem(gift_wraps[0], "tags");
|
||||
if (gift_wrap_tags && cJSON_IsArray(gift_wrap_tags)) {
|
||||
// Find and replace the p tag with the correct user pubkey
|
||||
cJSON* tag = NULL;
|
||||
cJSON_ArrayForEach(tag, gift_wrap_tags) {
|
||||
if (cJSON_IsArray(tag) && cJSON_GetArraySize(tag) >= 2) {
|
||||
cJSON* tag_name = cJSON_GetArrayItem(tag, 0);
|
||||
if (tag_name && cJSON_IsString(tag_name) &&
|
||||
strcmp(cJSON_GetStringValue(tag_name), "p") == 0) {
|
||||
// Replace the p tag value with the correct user pubkey
|
||||
cJSON_ReplaceItemInArray(tag, 1, cJSON_CreateString(sender_pubkey));
|
||||
log_info("NIP-17: Fixed p tag in config response gift wrap");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Debug: Print event after p tag fix
|
||||
char* debug_after_fix = cJSON_Print(gift_wraps[0]);
|
||||
if (debug_after_fix) {
|
||||
log_info("DEBUG EVENT: After p tag fix");
|
||||
printf(" Event: %s\n", debug_after_fix);
|
||||
free(debug_after_fix);
|
||||
}
|
||||
|
||||
// Debug print to show the response event
|
||||
char* response_debug = cJSON_Print(gift_wraps[0]);
|
||||
if (response_debug) {
|
||||
log_info("DM Admin: Response event created");
|
||||
printf(" Response event: %s\n", response_debug);
|
||||
free(response_debug);
|
||||
}
|
||||
|
||||
// Store the gift wrap in database
|
||||
int store_result = store_event(gift_wraps[0]);
|
||||
cJSON_Delete(gift_wraps[0]);
|
||||
|
||||
if (store_result != 0) {
|
||||
log_error("NIP-17: Failed to store response gift wrap for config");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
log_success("NIP-17: Config command processed successfully, response sent");
|
||||
return 0;
|
||||
}
|
||||
@@ -814,7 +877,16 @@ int process_nip17_admin_command(cJSON* dm_event, char* error_message, size_t err
|
||||
if (cJSON_IsString(first_item) && strcmp(cJSON_GetStringValue(first_item), "stats") == 0) {
|
||||
log_info("NIP-17: Processing 'stats' command directly");
|
||||
|
||||
// Generate stats JSON
|
||||
// Get sender pubkey for response
|
||||
cJSON* sender_pubkey_obj = cJSON_GetObjectItem(dm_event, "pubkey");
|
||||
if (!sender_pubkey_obj || !cJSON_IsString(sender_pubkey_obj)) {
|
||||
cJSON_Delete(command_array);
|
||||
strncpy(error_message, "NIP-17: DM missing sender pubkey", error_size - 1);
|
||||
return -1;
|
||||
}
|
||||
const char* sender_pubkey = cJSON_GetStringValue(sender_pubkey_obj);
|
||||
|
||||
// Generate stats JSON (for JSON array commands, use JSON format)
|
||||
char* stats_json = generate_stats_json();
|
||||
if (!stats_json) {
|
||||
cJSON_Delete(command_array);
|
||||
@@ -822,114 +894,17 @@ int process_nip17_admin_command(cJSON* dm_event, char* error_message, size_t err
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get sender pubkey for response
|
||||
cJSON* sender_pubkey_obj = cJSON_GetObjectItem(dm_event, "pubkey");
|
||||
if (!sender_pubkey_obj || !cJSON_IsString(sender_pubkey_obj)) {
|
||||
free(stats_json);
|
||||
cJSON_Delete(command_array);
|
||||
strncpy(error_message, "NIP-17: DM missing sender pubkey", error_size - 1);
|
||||
return -1;
|
||||
}
|
||||
const char* sender_pubkey = cJSON_GetStringValue(sender_pubkey_obj);
|
||||
|
||||
// Get relay keys for signing
|
||||
const char* relay_pubkey = get_relay_pubkey_cached();
|
||||
char* relay_privkey_hex = get_relay_private_key();
|
||||
if (!relay_pubkey || !relay_privkey_hex) {
|
||||
free(stats_json);
|
||||
cJSON_Delete(command_array);
|
||||
if (relay_privkey_hex) free(relay_privkey_hex);
|
||||
strncpy(error_message, "NIP-17: Could not get relay keys", error_size - 1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Convert relay private key to bytes
|
||||
unsigned char relay_privkey[32];
|
||||
if (nostr_hex_to_bytes(relay_privkey_hex, relay_privkey, sizeof(relay_privkey)) != 0) {
|
||||
free(stats_json);
|
||||
free(relay_privkey_hex);
|
||||
cJSON_Delete(command_array);
|
||||
strncpy(error_message, "NIP-17: Failed to convert relay private key", error_size - 1);
|
||||
return -1;
|
||||
}
|
||||
free(relay_privkey_hex);
|
||||
|
||||
// Create DM response event using library function
|
||||
cJSON* dm_response = nostr_nip17_create_chat_event(
|
||||
stats_json, // message content
|
||||
(const char**)&sender_pubkey, // recipient pubkeys
|
||||
1, // num recipients
|
||||
NULL, // subject (optional)
|
||||
NULL, // reply_to_event_id (optional)
|
||||
NULL, // reply_relay_url (optional)
|
||||
relay_pubkey // sender pubkey
|
||||
);
|
||||
|
||||
char error_msg[256];
|
||||
int result = send_nip17_response(sender_pubkey, stats_json, error_msg, sizeof(error_msg));
|
||||
free(stats_json);
|
||||
|
||||
if (!dm_response) {
|
||||
cJSON_Delete(command_array);
|
||||
strncpy(error_message, "NIP-17: Failed to create DM response event", error_size - 1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Create and sign gift wrap using library function
|
||||
cJSON* gift_wraps[1];
|
||||
int send_result = nostr_nip17_send_dm(
|
||||
dm_response, // dm_event
|
||||
(const char**)&sender_pubkey, // recipient_pubkeys
|
||||
1, // num_recipients
|
||||
relay_privkey, // sender_private_key
|
||||
gift_wraps, // gift_wraps_out
|
||||
1 // max_gift_wraps
|
||||
);
|
||||
|
||||
cJSON_Delete(dm_response);
|
||||
|
||||
if (send_result != 1 || !gift_wraps[0]) {
|
||||
cJSON_Delete(command_array);
|
||||
strncpy(error_message, "NIP-17: Failed to create and sign response gift wrap", error_size - 1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Fix the p tag in the gift wrap - library function may use wrong pubkey
|
||||
cJSON* gift_wrap_tags = cJSON_GetObjectItem(gift_wraps[0], "tags");
|
||||
if (gift_wrap_tags && cJSON_IsArray(gift_wrap_tags)) {
|
||||
// Find and replace the p tag with the correct user pubkey
|
||||
cJSON* tag = NULL;
|
||||
cJSON_ArrayForEach(tag, gift_wrap_tags) {
|
||||
if (cJSON_IsArray(tag) && cJSON_GetArraySize(tag) >= 2) {
|
||||
cJSON* tag_name = cJSON_GetArrayItem(tag, 0);
|
||||
if (tag_name && cJSON_IsString(tag_name) &&
|
||||
strcmp(cJSON_GetStringValue(tag_name), "p") == 0) {
|
||||
// Replace the p tag value with the correct user pubkey
|
||||
cJSON_ReplaceItemInArray(tag, 1, cJSON_CreateString(sender_pubkey));
|
||||
log_info("NIP-17: Fixed p tag in JSON array stats response gift wrap");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Debug print to show the response event
|
||||
char* response_debug = cJSON_Print(gift_wraps[0]);
|
||||
if (response_debug) {
|
||||
log_info("DM Admin: Response event created");
|
||||
printf(" Response event: %s\n", response_debug);
|
||||
free(response_debug);
|
||||
}
|
||||
|
||||
// Store the gift wrap in database
|
||||
int store_result = store_event(gift_wraps[0]);
|
||||
cJSON_Delete(gift_wraps[0]);
|
||||
|
||||
if (store_result != 0) {
|
||||
cJSON_Delete(command_array);
|
||||
strncpy(error_message, "NIP-17: Failed to store response gift wrap", error_size - 1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
cJSON_Delete(command_array);
|
||||
|
||||
if (result != 0) {
|
||||
log_error(error_msg);
|
||||
strncpy(error_message, error_msg, error_size - 1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
log_success("NIP-17: Stats command processed successfully");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -18,4 +18,10 @@ int process_nip17_admin_command(cJSON* dm_event, char* error_message, size_t err
|
||||
int is_nip17_gift_wrap_for_relay(cJSON* gift_wrap_event);
|
||||
char* generate_stats_json(void);
|
||||
|
||||
// Unified NIP-17 response functions
|
||||
int send_nip17_response(const char* sender_pubkey, const char* response_content,
|
||||
char* error_message, size_t error_size);
|
||||
char* generate_config_text(void);
|
||||
char* generate_stats_text(void);
|
||||
|
||||
#endif // DM_ADMIN_H
|
||||
File diff suppressed because one or more lines are too long
@@ -644,17 +644,32 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
|
||||
cJSON* response_event = process_nip17_admin_message(event, nip17_error, sizeof(nip17_error), wsi);
|
||||
|
||||
if (!response_event) {
|
||||
log_error("DEBUG NIP17: NIP-17 admin message processing failed");
|
||||
result = -1;
|
||||
size_t error_len = strlen(nip17_error);
|
||||
size_t copy_len = (error_len < sizeof(error_message) - 1) ? error_len : sizeof(error_message) - 1;
|
||||
memcpy(error_message, nip17_error, copy_len);
|
||||
error_message[copy_len] = '\0';
|
||||
// Check if this is an error or if the command was already handled
|
||||
if (strlen(nip17_error) > 0) {
|
||||
// There was an actual error
|
||||
log_error("DEBUG NIP17: NIP-17 admin message processing failed");
|
||||
result = -1;
|
||||
size_t error_len = strlen(nip17_error);
|
||||
size_t copy_len = (error_len < sizeof(error_message) - 1) ? error_len : sizeof(error_message) - 1;
|
||||
memcpy(error_message, nip17_error, copy_len);
|
||||
error_message[copy_len] = '\0';
|
||||
|
||||
char debug_nip17_error_msg[600];
|
||||
snprintf(debug_nip17_error_msg, sizeof(debug_nip17_error_msg),
|
||||
"DEBUG NIP17 ERROR: %.400s", nip17_error);
|
||||
log_error(debug_nip17_error_msg);
|
||||
char debug_nip17_error_msg[600];
|
||||
snprintf(debug_nip17_error_msg, sizeof(debug_nip17_error_msg),
|
||||
"DEBUG NIP17 ERROR: %.400s", nip17_error);
|
||||
log_error(debug_nip17_error_msg);
|
||||
} else {
|
||||
// No error message means the command was already handled (plain text commands)
|
||||
log_success("DEBUG NIP17: NIP-17 admin message processed successfully (already handled)");
|
||||
// Store the original gift wrap event in database
|
||||
if (store_event(event) != 0) {
|
||||
log_error("DEBUG NIP17: Failed to store gift wrap event in database");
|
||||
result = -1;
|
||||
strncpy(error_message, "error: failed to store gift wrap event", sizeof(error_message) - 1);
|
||||
} else {
|
||||
log_info("DEBUG NIP17: Gift wrap event stored successfully in database");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log_success("DEBUG NIP17: NIP-17 admin message processed successfully");
|
||||
// Store the original gift wrap event in database (unlike kind 23456)
|
||||
|
||||
Reference in New Issue
Block a user