diff --git a/.gitignore b/.gitignore index 824a7d1..d9fe61c 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,5 @@ src/version.h dev-config/ db/ copy_executable_local.sh -nostr_login_lite/ \ No newline at end of file +nostr_login_lite/ +style_guide/ \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md index 4d82f1b..a34dc63 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -48,20 +48,30 @@ - Schema version 4 with JSON tag storage - **Critical**: Event expiration filtering done at application level, not SQL level -### Configuration Event Structure +### Admin API Event Structure ```json { - "kind": 23455, - "content": "C Nostr Relay Configuration", + "kind": 23456, + "content": "base64_nip44_encrypted_command_array", "tags": [ - ["d", ""], - ["relay_description", "value"], - ["max_subscriptions_per_client", "25"], - ["pow_min_difficulty", "16"] + ["p", ""] ] } ``` +**Configuration Commands** (encrypted in content): +- `["relay_description", "My Relay"]` +- `["max_subscriptions_per_client", "25"]` +- `["pow_min_difficulty", "16"]` + +**Auth Rule Commands** (encrypted in content): +- `["blacklist", "pubkey", "hex_pubkey_value"]` +- `["whitelist", "pubkey", "hex_pubkey_value"]` + +**Query Commands** (encrypted in content): +- `["auth_query", "all"]` +- `["system_command", "system_status"]` + ### Process Management ```bash # Kill existing relay processes diff --git a/IMPLEMENT_API.md b/IMPLEMENT_API.md deleted file mode 100644 index f89d712..0000000 --- a/IMPLEMENT_API.md +++ /dev/null @@ -1,513 +0,0 @@ -# Implementation Plan: Enhanced Admin Event API Structure - -## Current Issue - -The current admin event routing at [`main.c:3248-3268`](src/main.c:3248) has a security vulnerability: - -```c -if (event_kind == 23455 || event_kind == 23456) { - // Admin event processing - int admin_result = process_admin_event_in_config(event, admin_error, sizeof(admin_error), wsi); -} else { - // Regular event storage and broadcasting -} -``` - -**Problem**: Any event with these kinds gets routed to admin processing, regardless of authorization. This allows unauthorized users to send admin events that could be processed as legitimate admin commands. - -**Note**: Event kinds 33334 and 33335 are no longer used and have been removed from the admin event routing. - -## Required Security Enhancement - -Admin events must be validated for proper authorization BEFORE routing to admin processing: - -1. **Relay Public Key Check**: Event must have a `p` tag equal to the relay's public key -2. **Admin Signature Check**: Event must be signed by an authorized admin private key -3. **Fallback to Regular Processing**: If authorization fails, treat as regular event (not admin event) - -## Implementation Plan - -### Phase 1: Add Admin Authorization Validation - -#### 1.1 Create Consolidated Admin Authorization Function -**Location**: [`src/main.c`](src/main.c) or [`src/config.c`](src/config.c) - -```c -/** - * Consolidated admin event authorization validator - * Implements defense-in-depth security for admin events - * - * @param event - The event to validate for admin authorization - * @param error_message - Buffer for detailed error messages - * @param error_size - Size of error message buffer - * @return 0 if authorized, -1 if unauthorized, -2 if validation error - */ -int is_authorized_admin_event(cJSON* event, char* error_message, size_t error_size) { - if (!event) { - snprintf(error_message, error_size, "admin_auth: null event"); - return -2; - } - - // Extract event components - cJSON* kind_obj = cJSON_GetObjectItem(event, "kind"); - cJSON* pubkey_obj = cJSON_GetObjectItem(event, "pubkey"); - cJSON* tags_obj = cJSON_GetObjectItem(event, "tags"); - - if (!kind_obj || !pubkey_obj || !tags_obj) { - snprintf(error_message, error_size, "admin_auth: missing required fields"); - return -2; - } - - // Validation Layer 1: Kind Check - int event_kind = (int)cJSON_GetNumberValue(kind_obj); - if (event_kind != 23455 && event_kind != 23456) { - snprintf(error_message, error_size, "admin_auth: not an admin event kind"); - return -1; - } - - // Validation Layer 2: Relay Targeting Check - const char* relay_pubkey = get_config_value("relay_pubkey"); - if (!relay_pubkey) { - snprintf(error_message, error_size, "admin_auth: relay pubkey not configured"); - return -2; - } - - // Check for 'p' tag targeting this relay - int has_relay_target = 0; - if (cJSON_IsArray(tags_obj)) { - cJSON* tag = NULL; - cJSON_ArrayForEach(tag, tags_obj) { - if (cJSON_IsArray(tag) && cJSON_GetArraySize(tag) >= 2) { - cJSON* tag_name = cJSON_GetArrayItem(tag, 0); - cJSON* tag_value = cJSON_GetArrayItem(tag, 1); - - if (cJSON_IsString(tag_name) && cJSON_IsString(tag_value)) { - const char* name = cJSON_GetStringValue(tag_name); - const char* value = cJSON_GetStringValue(tag_value); - - if (strcmp(name, "p") == 0 && strcmp(value, relay_pubkey) == 0) { - has_relay_target = 1; - break; - } - } - } - } - } - - if (!has_relay_target) { - // Admin event for different relay - not unauthorized, just not for us - snprintf(error_message, error_size, "admin_auth: admin event for different relay"); - return -1; - } - - // Validation Layer 3: Admin Signature Check (only if targeting this relay) - const char* event_pubkey = cJSON_GetStringValue(pubkey_obj); - if (!event_pubkey) { - snprintf(error_message, error_size, "admin_auth: invalid pubkey format"); - return -2; - } - - const char* admin_pubkey = get_config_value("admin_pubkey"); - if (!admin_pubkey || strcmp(event_pubkey, admin_pubkey) != 0) { - // This is the ONLY case where we log as "Unauthorized admin event attempt" - // because it's targeting THIS relay but from wrong admin - snprintf(error_message, error_size, "admin_auth: unauthorized admin for this relay"); - log_warning("SECURITY: Unauthorized admin event attempt for this relay"); - return -1; - } - - // All validation layers passed - log_info("ADMIN: Admin event authorized"); - return 0; -} - -``` - -#### 1.2 Update Event Routing Logic -**Location**: [`main.c:3248`](src/main.c:3248) - -```c -// Current problematic code: -if (event_kind == 23455 || event_kind == 23456) { - // Admin event processing - int admin_result = process_admin_event_in_config(event, admin_error, sizeof(admin_error), wsi); -} else { - // Regular event storage and broadcasting -} - -// Enhanced secure code with consolidated authorization: -if (result == 0) { - cJSON* kind_obj = cJSON_GetObjectItem(event, "kind"); - if (kind_obj && cJSON_IsNumber(kind_obj)) { - int event_kind = (int)cJSON_GetNumberValue(kind_obj); - - // Check if this is an admin event - if (event_kind == 23455 || event_kind == 23456) { - // Use consolidated authorization check - char auth_error[512] = {0}; - int auth_result = is_authorized_admin_event(event, auth_error, sizeof(auth_error)); - - if (auth_result == 0) { - // Authorized admin event - process through admin API - char admin_error[512] = {0}; - int admin_result = process_admin_event_in_config(event, admin_error, sizeof(admin_error), wsi); - - if (admin_result != 0) { - result = -1; - strncpy(error_message, admin_error, sizeof(error_message) - 1); - } - // Admin events are NOT broadcast to subscriptions - } else { - // Unauthorized admin event - treat as regular event - log_warning("Unauthorized admin event treated as regular event"); - if (store_event(event) != 0) { - result = -1; - strncpy(error_message, "error: failed to store event", sizeof(error_message) - 1); - } else { - broadcast_event_to_subscriptions(event); - } - } - } else { - // Regular event - normal processing - if (store_event(event) != 0) { - result = -1; - strncpy(error_message, "error: failed to store event", sizeof(error_message) - 1); - } else { - broadcast_event_to_subscriptions(event); - } - } - } -} -``` - -### Phase 2: Enhanced Admin Event Processing - -#### 2.1 Admin Event Validation in Config System -**Location**: [`src/config.c`](src/config.c) - [`process_admin_event_in_config()`](src/config.c:2065) - -Add additional validation within the admin processing function: - -```c -int process_admin_event_in_config(cJSON* event, char* error_buffer, size_t error_buffer_size, struct lws* wsi) { - // Double-check authorization (defense in depth) - if (!is_authorized_admin_event(event)) { - snprintf(error_buffer, error_buffer_size, "unauthorized: not a valid admin event"); - return -1; - } - - // Continue with existing admin event processing... - // ... rest of function unchanged -} -``` - -#### 2.2 Logging and Monitoring -Add comprehensive logging for admin event attempts: - -```c -// In the routing logic - enhanced logging -cJSON* kind_obj = cJSON_GetObjectItem(event, "kind"); -cJSON* pubkey_obj = cJSON_GetObjectItem(event, "pubkey"); -int event_kind = kind_obj ? cJSON_GetNumberValue(kind_obj) : -1; -const char* event_pubkey = pubkey_obj ? cJSON_GetStringValue(pubkey_obj) : "unknown"; - -if (is_authorized_admin_event(event)) { - char log_msg[256]; - snprintf(log_msg, sizeof(log_msg), - "ADMIN EVENT: Authorized admin event (kind=%d) from pubkey=%.16s...", - event_kind, event_pubkey); - log_info(log_msg); -} else if (event_kind == 23455 || event_kind == 23456) { - // This catches unauthorized admin event attempts - char log_msg[256]; - snprintf(log_msg, sizeof(log_msg), - "SECURITY: Unauthorized admin event attempt (kind=%d) from pubkey=%.16s...", - event_kind, event_pubkey); - log_warning(log_msg); -} -``` - -## Phase 3: Unified Output Flow Architecture - -### 3.1 Current Output Flow Analysis - -After analyzing both [`main.c`](src/main.c) and [`config.c`](src/config.c), the **admin event responses already flow through the standard WebSocket output pipeline**. This is the correct architecture and requires no changes. - -#### Standard WebSocket Output Pipeline - -**Regular Events** ([`main.c:2978-2996`](src/main.c:2978)): -```c -// Database query responses -unsigned char* buf = malloc(LWS_PRE + msg_len); -memcpy(buf + LWS_PRE, msg_str, msg_len); -lws_write(wsi, buf + LWS_PRE, msg_len, LWS_WRITE_TEXT); -free(buf); -``` - -**OK Responses** ([`main.c:3342-3375`](src/main.c:3342)): -```c -// Event processing results: ["OK", event_id, success_boolean, message] -unsigned char *buf = malloc(LWS_PRE + response_len); -memcpy(buf + LWS_PRE, response_str, response_len); -lws_write(wsi, buf + LWS_PRE, response_len, LWS_WRITE_TEXT); -free(buf); -``` - -#### Admin Event Output Pipeline (Already Unified) - -**Admin Responses** ([`config.c:2363-2414`](src/config.c:2363)): -```c -// Admin query responses use IDENTICAL pattern -int send_websocket_response_data(struct lws* wsi, cJSON* response_data) { - unsigned char* buf = malloc(LWS_PRE + response_len); - memcpy(buf + LWS_PRE, response_str, response_len); - - // Same lws_write() call as regular events - int result = lws_write(wsi, buf + LWS_PRE, response_len, LWS_WRITE_TEXT); - - free(buf); - return result; -} -``` - -### 3.2 Unified Output Flow Confirmation - -✅ **Admin responses already use the same WebSocket transmission mechanism as regular events** - -✅ **Both admin and regular events use identical buffer allocation patterns** - -✅ **Both admin and regular events use the same [`lws_write()`](src/config.c:2393) function** - -✅ **Both admin and regular events follow the same cleanup patterns** - -### 3.3 Output Flow Integration Points - -The admin event processing in [`config.c:2436`](src/config.c:2436) already integrates correctly with the unified output system: - -1. **Admin Query Processing** ([`config.c:2568-2583`](src/config.c:2568)): - - Auth queries return structured JSON via [`send_websocket_response_data()`](src/config.c:2571) - - System commands return status data via [`send_websocket_response_data()`](src/config.c:2631) - -2. **Response Format Consistency**: - - Admin responses use standard JSON format - - Regular events use standard Nostr event format - - Both transmitted through same WebSocket pipeline - -3. **Error Handling Consistency**: - - Admin errors returned via same WebSocket connection - - Regular event errors returned via OK messages - - Both use identical transmission mechanism - -### 3.4 Key Architectural Benefits - -**No Changes Required**: The output flow is already unified and correctly implemented. - -**Security Separation**: Admin events are processed separately but responses flow through the same secure WebSocket channel. - -**Performance Consistency**: Both admin and regular responses use the same optimized transmission path. - -**Maintenance Simplicity**: Single WebSocket output pipeline reduces complexity and potential bugs. - -### 3.5 Admin Event Flow Summary - -``` -Admin Event Input → Authorization Check → Admin Processing → Unified WebSocket Output -Regular Event Input → Validation → Storage + Broadcast → Unified WebSocket Output -``` - -Both flows converge at the **Unified WebSocket Output** stage, which is already correctly implemented. - -## Phase 4: Integration Points for Secure Admin Event Routing - -### 4.1 Configuration System Integration - -**Required Configuration Values**: -- `admin_pubkey` - Public key of authorized administrator -- `relay_pubkey` - Public key of this relay instance - -**Integration Points**: -1. [`get_config_value()`](src/config.c) - Used by authorization function -2. [`get_relay_pubkey_cached()`](src/config.c) - Used for relay targeting validation -3. Configuration loading during startup - Must ensure admin/relay pubkeys are available - -### 4.3 Forward Declarations Required - -**Location**: [`src/main.c`](src/main.c) - Add near other forward declarations (around line 230) - -```c -// Forward declarations for enhanced admin event authorization -int is_authorized_admin_event(cJSON* event, char* error_message, size_t error_size); -``` - -### 4.4 Error Handling Integration - -**Enhanced Error Response System**: - -```c -// In main.c event processing - enhanced error handling for admin events -if (auth_result != 0) { - // Admin authorization failed - send detailed OK response - cJSON* event_id = cJSON_GetObjectItem(event, "id"); - if (event_id && cJSON_IsString(event_id)) { - cJSON* response = cJSON_CreateArray(); - cJSON_AddItemToArray(response, cJSON_CreateString("OK")); - cJSON_AddItemToArray(response, cJSON_CreateString(cJSON_GetStringValue(event_id))); - cJSON_AddItemToArray(response, cJSON_CreateBool(0)); // Failed - cJSON_AddItemToArray(response, cJSON_CreateString(auth_error)); - - // Send via standard WebSocket output pipeline - char *response_str = cJSON_Print(response); - if (response_str) { - size_t response_len = strlen(response_str); - unsigned char *buf = malloc(LWS_PRE + response_len); - if (buf) { - memcpy(buf + LWS_PRE, response_str, response_len); - lws_write(wsi, buf + LWS_PRE, response_len, LWS_WRITE_TEXT); - free(buf); - } - free(response_str); - } - cJSON_Delete(response); - } -} -``` - -### 4.5 Logging Integration Points - -**Console Logging**: Uses existing [`log_warning()`](src/main.c:993), [`log_info()`](src/main.c:972) functions - -**Security Event Categories**: -- Admin authorization success logged via `log_info()` -- Admin authorization failures logged via `log_warning()` -- Admin event processing logged via existing admin logging - -## Phase 5: Detailed Function Specifications - -### 5.1 Core Authorization Function - -**Function**: `is_authorized_admin_event()` -**Location**: [`src/main.c`](src/main.c) or [`src/config.c`](src/config.c) -**Dependencies**: -- `get_config_value()` for admin/relay pubkeys -- `log_warning()` and `log_info()` for logging -- `cJSON` library for event parsing - -**Return Values**: -- `0` - Event is authorized for admin processing -- `-1` - Event is unauthorized (treat as regular event) -- `-2` - Validation error (malformed event) - -**Error Handling**: Detailed error messages in provided buffer for client feedback - -### 5.2 Enhanced Event Routing - -**Location**: [`main.c:3248-3340`](src/main.c:3248) -**Integration**: Replaces existing admin event routing logic -**Dependencies**: -- `is_authorized_admin_event()` for authorization -- `process_admin_event_in_config()` for admin processing -- `store_event()` and `broadcast_event_to_subscriptions()` for regular events - -**Security Features**: -- Graceful degradation for unauthorized admin events -- Comprehensive logging of authorization attempts -- No broadcast of admin events to subscriptions -- Detailed error responses for failed authorization - -### 5.4 Defense-in-Depth Validation - -**Primary Validation**: In main event routing logic -**Secondary Validation**: In `process_admin_event_in_config()` function -**Tertiary Validation**: In individual admin command handlers - -**Validation Layers**: -1. **Kind Check** - Must be admin event kind (23455/23456) -2. **Relay Targeting Check** - Must have 'p' tag with this relay's pubkey -3. **Admin Signature Check** - Must be signed by authorized admin (only if targeting this relay) -4. **Processing Check** - Additional validation in admin handlers - -**Security Logic**: -- If no 'p' tag for this relay → Admin event for different relay (not unauthorized) -- If 'p' tag for this relay + wrong admin signature → "Unauthorized admin event attempt" - -## Phase 6: Event Flow Documentation - -### 6.1 Complete Event Processing Flow - -``` -┌─────────────────┐ -│ WebSocket Input │ -└─────────┬───────┘ - │ - ▼ -┌─────────────────┐ -│ Unified │ -│ Validation │ ← nostr_validate_unified_request() -└─────────┬───────┘ - │ - ▼ -┌─────────────────┐ -│ Kind-Based │ -│ Routing Check │ ← Check if kind 23455/23456 -└─────────┬───────┘ - │ - ┌────▼────┐ - │ Admin? │ - └────┬────┘ - │ - ┌─────▼─────┐ ┌─────────────┐ - │ YES │ │ NO │ - │ │ │ │ - ▼ │ ▼ │ -┌─────────────┐ │ ┌─────────────┐ │ -│ Admin │ │ │ Regular │ │ -│ Authorization│ │ │ Event │ │ -│ Check │ │ │ Processing │ │ -└─────┬───────┘ │ └─────┬───────┘ │ - │ │ │ │ - ┌────▼────┐ │ ▼ │ - │Authorized?│ │ ┌─────────────┐ │ - └────┬────┘ │ │ store_event()│ │ - │ │ │ + │ │ -┌─────▼─────┐ │ │ broadcast() │ │ -│ YES NO │ │ └─────┬───────┘ │ -│ │ │ │ │ │ │ -│ ▼ ▼ │ │ ▼ │ -│┌─────┐┌───┴┐ │ ┌─────────────┐ │ -││Admin││Treat│ │ │ WebSocket │ │ -││API ││as │ │ │ OK Response │ │ -││ ││Reg │ │ └─────────────┘ │ -│└──┬──┘└───┬┘ │ │ -│ │ │ │ │ -│ ▼ │ │ │ -│┌─────────┐│ │ │ -││WebSocket││ │ │ -││Response ││ │ │ -│└─────────┘│ │ │ -└───────────┴───┘ │ - │ │ - └───────────────────────────┘ - │ - ▼ - ┌─────────────┐ - │ Unified │ - │ WebSocket │ - │ Output │ - └─────────────┘ -``` - -### 6.2 Security Decision Points - -1. **Event Kind Check** - Identifies potential admin events -2. **Authorization Validation** - Three-layer security check -3. **Routing Decision** - Admin API vs Regular processing -4. **Response Generation** - Unified output pipeline -5. **Audit Logging** - Security event tracking - -### 6.3 Error Handling Paths - -**Validation Errors**: Return detailed error messages via OK response -**Authorization Failures**: Log security event + treat as regular event -**Processing Errors**: Return admin-specific error responses -**System Errors**: Fallback to standard error handling - -This completes the comprehensive implementation plan for the enhanced admin event API structure with unified output flow architecture. diff --git a/README.md b/README.md index 460b0a7..077a08c 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Do NOT modify the formatting, add emojis, or change the text. Keep the simple fo ## 🔧 Administrator API -C-Relay uses an innovative **event-based administration system** where all configuration and management commands are sent as signed Nostr events using the admin private key generated during first startup. All admin commands use **tag-based parameters** for simplicity and compatibility. +C-Relay uses an innovative **event-based administration system** where all configuration and management commands are sent as signed Nostr events using the admin private key generated during first startup. All admin commands use **NIP-44 encrypted command arrays** for security and compatibility. ### Authentication @@ -32,7 +32,7 @@ All admin commands require signing with the admin private key displayed during f ### Event Structure -All admin commands use the same unified event structure with tag-based parameters: +All admin commands use the same unified event structure with NIP-44 encrypted content: **Admin Command Event:** ```json @@ -41,14 +41,16 @@ All admin commands use the same unified event structure with tag-based parameter "pubkey": "admin_public_key", "created_at": 1234567890, "kind": 23456, - "content": "", + "content": "AqHBUgcM7dXFYLQuDVzGwMST1G8jtWYyVvYxXhVGEu4nAb4LVw...", "tags": [ - ["p", "relay_public_key"], + ["p", "relay_public_key"] ], "sig": "event_signature" } ``` +The `content` field contains a NIP-44 encrypted JSON array representing the command. + **Admin Response Event:** ```json ["EVENT", "temp_sub_id", { @@ -56,7 +58,7 @@ All admin commands use the same unified event structure with tag-based parameter "pubkey": "relay_public_key", "created_at": 1234567890, "kind": 23457, - "content": "", + "content": "BpKCVhfN8eYtRmPqSvWxZnMkL2gHjUiOp3rTyEwQaS5dFg...", "tags": [ ["p", "admin_public_key"] ], @@ -64,15 +66,17 @@ All admin commands use the same unified event structure with tag-based parameter }] ``` +The `content` field contains a NIP-44 encrypted JSON response object. + ### Admin Commands -All commands are sent as nip44 encrypted content. The following table lists all available commands: +All commands are sent as NIP-44 encrypted JSON arrays in the event content. The following table lists all available commands: -| Command Type | Tag Format | Description | -|--------------|------------|-------------| +| Command Type | Command Format | Description | +|--------------|----------------|-------------| | **Configuration Management** | -| `config_update` | `["relay_description", "My Relay"]` | Update relay configuration parameters | -| `config_query` | `["config_query", "list_all_keys"]` | List all available configuration keys | +| `config_update` | `["config_update", [{"key": "auth_enabled", "value": "true", "data_type": "boolean", "category": "auth"}, {"key": "relay_description", "value": "My Relay", "data_type": "string", "category": "relay"}, ...]]` | Update relay configuration parameters (supports multiple updates) | +| `config_query` | `["config_query", "all"]` | Query all configuration parameters | | **Auth Rules Management** | | `auth_add_blacklist` | `["blacklist", "pubkey", "abc123..."]` | Add pubkey to blacklist | | `auth_add_whitelist` | `["whitelist", "pubkey", "def456..."]` | Add pubkey to whitelist | @@ -117,7 +121,7 @@ All admin commands return **signed EVENT responses** via WebSocket following sta "pubkey": "relay_public_key", "created_at": 1234567890, "kind": 23457, - "content": "nip44 encrypted:{\"status\": \"success\", \"message\": \"Operation completed successfully\"}", + "content": "nip44 encrypted:{\"query_type\": \"config_update\", \"status\": \"success\", \"message\": \"Operation completed successfully\", \"timestamp\": 1234567890}", "tags": [ ["p", "admin_public_key"] ], @@ -132,7 +136,7 @@ All admin commands return **signed EVENT responses** via WebSocket following sta "pubkey": "relay_public_key", "created_at": 1234567890, "kind": 23457, - "content": "nip44 encrypted:{\"status\": \"error\", \"message\": \"Error: invalid configuration value\"}", + "content": "nip44 encrypted:{\"query_type\": \"config_update\", \"status\": \"error\", \"error\": \"invalid configuration value\", \"timestamp\": 1234567890}", "tags": [ ["p", "admin_public_key"] ], @@ -147,7 +151,7 @@ All admin commands return **signed EVENT responses** via WebSocket following sta "pubkey": "relay_public_key", "created_at": 1234567890, "kind": 23457, - "content": "nip44 encrypted:{\"query_type\": \"auth_rules\", \"total_results\": 2, \"data\": [{\"rule_type\": \"blacklist\", \"pattern_type\": \"pubkey\", \"pattern_value\": \"abc123...\", \"action\": \"deny\"}]}", + "content": "nip44 encrypted:{\"query_type\": \"auth_rules_all\", \"total_results\": 2, \"timestamp\": 1234567890, \"data\": [{\"rule_type\": \"blacklist\", \"pattern_type\": \"pubkey\", \"pattern_value\": \"abc123...\", \"action\": \"allow\"}]}", "tags": [ ["p", "admin_public_key"] ], @@ -162,7 +166,7 @@ All admin commands return **signed EVENT responses** via WebSocket following sta "pubkey": "relay_public_key", "created_at": 1234567890, "kind": 23457, - "content": "nip44 encrypted:{\"query_type\": \"config_keys\", \"config_keys\": [\"auth_enabled\", \"max_connections\"], \"descriptions\": {\"auth_enabled\": \"Enable whitelist/blacklist rules\"}}", + "content": "nip44 encrypted:{\"query_type\": \"config_all\", \"total_results\": 27, \"timestamp\": 1234567890, \"data\": [{\"key\": \"auth_enabled\", \"value\": \"false\", \"data_type\": \"boolean\", \"category\": \"auth\", \"description\": \"Enable NIP-42 authentication\"}, {\"key\": \"relay_description\", \"value\": \"My Relay\", \"data_type\": \"string\", \"category\": \"relay\", \"description\": \"Relay description text\"}]}", "tags": [ ["p", "admin_public_key"] ], @@ -170,3 +174,32 @@ All admin commands return **signed EVENT responses** via WebSocket following sta }] ``` +**Configuration Update Success Response:** +```json +["EVENT", "temp_sub_id", { + "id": "response_event_id", + "pubkey": "relay_public_key", + "created_at": 1234567890, + "kind": 23457, + "content": "nip44 encrypted:{\"query_type\": \"config_update\", \"total_results\": 2, \"timestamp\": 1234567890, \"status\": \"success\", \"data\": [{\"key\": \"auth_enabled\", \"value\": \"true\", \"status\": \"updated\"}, {\"key\": \"relay_description\", \"value\": \"My Updated Relay\", \"status\": \"updated\"}]}", + "tags": [ + ["p", "admin_public_key"] + ], + "sig": "response_event_signature" +}] +``` + +**Configuration Update Error Response:** +```json +["EVENT", "temp_sub_id", { + "id": "response_event_id", + "pubkey": "relay_public_key", + "created_at": 1234567890, + "kind": 23457, + "content": "nip44 encrypted:{\"query_type\": \"config_update\", \"status\": \"error\", \"error\": \"field validation failed: invalid port number '99999' (must be 1-65535)\", \"timestamp\": 1234567890}", + "tags": [ + ["p", "admin_public_key"] + ], + "sig": "response_event_signature" +}] +``` diff --git a/api/index.html b/api/index.html index 274117c..353144c 100644 --- a/api/index.html +++ b/api/index.html @@ -6,6 +6,29 @@ C-Relay Admin API