# Ginxsom Admin Commands Implementation Plan ## Overview This document outlines the implementation plan for Ginxsom's admin command system, adapted from c-relay's event-based administration system. Commands are sent as NIP-44 encrypted Kind 23456 events and responses are returned as Kind 23457 events. ## Command Analysis: c-relay vs Ginxsom ### Commands to Implement (Blossom-Relevant) | c-relay Command | Ginxsom Equivalent | Rationale | |-----------------|-------------------|-----------| | `config_query` | `config_query` | Query Blossom server configuration | | `config_update` | `config_update` | Update server settings dynamically | | `stats_query` | `stats_query` | Database statistics (blobs, storage, etc.) | | `system_status` | `system_status` | Server health and status | | `sql_query` | `sql_query` | Direct database queries for debugging | | N/A | `blob_list` | List blobs by pubkey or criteria | | N/A | `storage_stats` | Storage usage and capacity info | | N/A | `mirror_status` | Status of mirroring operations | | N/A | `report_query` | Query content reports (BUD-09) | ### Commands to Exclude (Not Blossom-Relevant) | c-relay Command | Reason for Exclusion | |-----------------|---------------------| | `auth_add_blacklist` | Blossom uses different auth model (per-blob, not per-pubkey) | | `auth_add_whitelist` | Same as above | | `auth_delete_rule` | Same as above | | `auth_query_all` | Same as above | | `system_clear_auth` | Same as above | **Note**: Blossom's authentication is event-based per operation (upload/delete), not relay-level whitelist/blacklist. Auth rules in Ginxsom are configured via the `auth_rules` table but managed differently than c-relay. ## Event Structure ### Admin Command Event (Kind 23456) ```json { "id": "event_id", "pubkey": "admin_public_key", "created_at": 1234567890, "kind": 23456, "content": "NIP44_ENCRYPTED_COMMAND_ARRAY", "tags": [ ["p", "blossom_server_pubkey"] ], "sig": "event_signature" } ``` ### Admin Response Event (Kind 23457) ```json { "id": "response_event_id", "pubkey": "blossom_server_pubkey", "created_at": 1234567890, "kind": 23457, "content": "NIP44_ENCRYPTED_RESPONSE_OBJECT", "tags": [ ["p", "admin_public_key"], ["e", "request_event_id"] ], "sig": "response_event_signature" } ``` ## Command Specifications ### 1. Configuration Management #### `config_query` Query server configuration parameters. **Command Format:** ```json ["config_query", "all"] ["config_query", "category", "blossom"] ["config_query", "key", "max_file_size"] ``` **Response:** ```json { "query_type": "config_all", "total_results": 15, "timestamp": 1234567890, "data": [ { "key": "max_file_size", "value": "104857600", "data_type": "integer", "category": "blossom", "description": "Maximum file size in bytes" }, { "key": "enable_relay_connect", "value": "true", "data_type": "boolean", "category": "relay", "description": "Enable relay client functionality" } ] } ``` **Configuration Categories:** - `blossom`: Blossom protocol settings (max_file_size, storage_path, etc.) - `relay`: Relay client settings (enable_relay_connect, kind_0_content, etc.) - `auth`: Authentication settings (auth_enabled, nip42_required, etc.) - `limits`: Rate limits and quotas - `system`: System-level settings #### `config_update` Update configuration parameters dynamically. **Command Format:** ```json ["config_update", [ { "key": "max_file_size", "value": "209715200", "data_type": "integer", "category": "blossom" }, { "key": "enable_relay_connect", "value": "true", "data_type": "boolean", "category": "relay" } ]] ``` **Response:** ```json { "query_type": "config_update", "status": "success", "total_results": 2, "timestamp": 1234567890, "data": [ { "key": "max_file_size", "value": "209715200", "status": "updated", "restart_required": false }, { "key": "enable_relay_connect", "value": "true", "status": "updated", "restart_required": true } ] } ``` ### 2. Statistics and Monitoring #### `stats_query` Get comprehensive database and storage statistics. **Command Format:** ```json ["stats_query"] ``` **Response:** ```json { "query_type": "stats_query", "timestamp": 1234567890, "database_size_bytes": 1048576, "storage_size_bytes": 10737418240, "total_blobs": 1543, "unique_uploaders": 234, "blob_types": [ {"type": "image/jpeg", "count": 856, "size_bytes": 5368709120, "percentage": 55.4}, {"type": "image/png", "count": 432, "size_bytes": 3221225472, "percentage": 28.0}, {"type": "video/mp4", "count": 123, "size_bytes": 2147483648, "percentage": 8.0} ], "time_stats": { "total": 1543, "last_24h": 45, "last_7d": 234, "last_30d": 876 }, "top_uploaders": [ {"pubkey": "abc123...", "blob_count": 234, "total_bytes": 1073741824, "percentage": 15.2}, {"pubkey": "def456...", "blob_count": 187, "total_bytes": 858993459, "percentage": 12.1} ] } ``` #### `system_status` Get current system status and health metrics. **Command Format:** ```json ["system_command", "system_status"] ``` **Response:** ```json { "query_type": "system_status", "timestamp": 1234567890, "uptime_seconds": 86400, "version": "0.1.0", "relay_client": { "enabled": true, "connected_relays": 1, "relay_status": [ { "url": "wss://relay.laantungir.net", "state": "connected", "events_received": 12, "events_published": 3 } ] }, "storage": { "path": "/home/teknari/lt_gitea/ginxsom/blobs", "total_bytes": 10737418240, "available_bytes": 53687091200, "usage_percentage": 16.7 }, "database": { "path": "db/52e366edfa4e9cc6a6d4653828e51ccf828a2f5a05227d7a768f33b5a198681a.db", "size_bytes": 1048576, "total_blobs": 1543 } } ``` ### 3. Blossom-Specific Commands #### `blob_list` List blobs with filtering options. **Command Format:** ```json ["blob_list", "all"] ["blob_list", "pubkey", "abc123..."] ["blob_list", "type", "image/jpeg"] ["blob_list", "recent", 50] ``` **Response:** ```json { "query_type": "blob_list", "total_results": 50, "timestamp": 1234567890, "data": [ { "sha256": "b1674191a88ec5cdd733e4240a81803105dc412d6c6708d53ab94fc248f4f553", "size": 184292, "type": "application/pdf", "uploaded_at": 1725105921, "uploader_pubkey": "abc123...", "url": "https://cdn.example.com/b1674191a88ec5cdd733e4240a81803105dc412d6c6708d53ab94fc248f4f553.pdf" } ] } ``` #### `storage_stats` Get detailed storage statistics. **Command Format:** ```json ["storage_stats"] ``` **Response:** ```json { "query_type": "storage_stats", "timestamp": 1234567890, "storage_path": "/home/teknari/lt_gitea/ginxsom/blobs", "total_bytes": 10737418240, "available_bytes": 53687091200, "used_bytes": 10737418240, "usage_percentage": 16.7, "blob_count": 1543, "average_blob_size": 6958592, "largest_blob": { "sha256": "abc123...", "size": 104857600, "type": "video/mp4" }, "by_type": [ {"type": "image/jpeg", "count": 856, "total_bytes": 5368709120}, {"type": "image/png", "count": 432, "total_bytes": 3221225472} ] } ``` #### `mirror_status` Get status of blob mirroring operations (BUD-04). **Command Format:** ```json ["mirror_status"] ["mirror_status", "sha256", "abc123..."] ``` **Response:** ```json { "query_type": "mirror_status", "timestamp": 1234567890, "total_mirrors": 23, "data": [ { "sha256": "abc123...", "source_url": "https://cdn.example.com/abc123.jpg", "status": "completed", "mirrored_at": 1725105921, "size": 1048576 } ] } ``` #### `report_query` Query content reports (BUD-09). **Command Format:** ```json ["report_query", "all"] ["report_query", "blob", "abc123..."] ["report_query", "type", "nudity"] ``` **Response:** ```json { "query_type": "report_query", "total_results": 12, "timestamp": 1234567890, "data": [ { "report_id": 1, "blob_sha256": "abc123...", "report_type": "nudity", "reporter_pubkey": "def456...", "content": "Inappropriate content", "reported_at": 1725105921 } ] } ``` ### 4. Database Queries #### `sql_query` Execute read-only SQL queries for debugging. **Command Format:** ```json ["sql_query", "SELECT * FROM blobs LIMIT 10"] ``` **Response:** ```json { "query_type": "sql_query", "request_id": "request_event_id", "timestamp": 1234567890, "query": "SELECT * FROM blobs LIMIT 10", "execution_time_ms": 12, "row_count": 10, "columns": ["sha256", "size", "type", "uploaded_at", "uploader_pubkey"], "rows": [ ["b1674191...", 184292, "application/pdf", 1725105921, "abc123..."] ] } ``` **Security:** - Only SELECT statements allowed - Query timeout: 5 seconds - Result row limit: 1000 rows - All queries logged ## Implementation Architecture ### 1. Command Processing Flow ``` 1. Relay client receives Kind 23456 event 2. Verify sender is admin_pubkey 3. Decrypt content using NIP-44 4. Parse command array 5. Validate command structure 6. Execute command handler 7. Generate response object 8. Encrypt response using NIP-44 9. Create Kind 23457 event 10. Publish to relays ``` ### 2. Code Structure **New Files:** - `src/admin_commands.c` - Command handlers - `src/admin_commands.h` - Command interface - `src/nip44.c` - NIP-44 encryption wrapper (uses nostr_core_lib) - `src/nip44.h` - NIP-44 interface **Modified Files:** - `src/relay_client.c` - Add command processing to `on_admin_command_event()` - `src/main.c` - Initialize admin command system ### 3. Database Schema Additions ```sql -- Admin command log CREATE TABLE IF NOT EXISTS admin_commands ( id INTEGER PRIMARY KEY AUTOINCREMENT, event_id TEXT NOT NULL, command_type TEXT NOT NULL, admin_pubkey TEXT NOT NULL, executed_at INTEGER NOT NULL, execution_time_ms INTEGER, status TEXT NOT NULL, error TEXT ); -- Create index for command history queries CREATE INDEX IF NOT EXISTS idx_admin_commands_executed ON admin_commands(executed_at DESC); ``` ### 4. Configuration Keys **Blossom Category:** - `max_file_size` - Maximum upload size in bytes - `storage_path` - Blob storage directory - `cdn_origin` - CDN URL for blob descriptors - `enable_nip94` - Include NIP-94 tags in responses **Relay Category:** - `enable_relay_connect` - Enable relay client - `kind_0_content` - Profile metadata JSON - `kind_10002_tags` - Relay list JSON array **Auth Category:** - `auth_enabled` - Enable auth rules system - `require_auth_upload` - Require auth for uploads - `require_auth_delete` - Require auth for deletes **Limits Category:** - `max_blobs_per_user` - Per-user blob limit - `rate_limit_uploads` - Uploads per minute - `max_total_storage` - Total storage limit in bytes ## Implementation Phases ### Phase 1: NIP-44 Encryption Support - Integrate nostr_core_lib NIP-44 functions - Create encryption/decryption wrappers - Test with sample data ### Phase 2: Command Infrastructure - Create admin_commands.c/h - Implement command parser - Add command logging to database - Implement response builder ### Phase 3: Core Commands - Implement `config_query` - Implement `config_update` - Implement `stats_query` - Implement `system_status` ### Phase 4: Blossom Commands - Implement `blob_list` - Implement `storage_stats` - Implement `mirror_status` - Implement `report_query` ### Phase 5: Advanced Features - Implement `sql_query` with security - Add command history tracking - Implement rate limiting for admin commands ### Phase 6: Testing & Documentation - Create test suite for each command - Update README.md with admin API section - Create example scripts using nak tool ## Security Considerations 1. **Authentication**: Only admin_pubkey can send commands 2. **Encryption**: All commands/responses use NIP-44 3. **Logging**: All admin actions logged to database 4. **Rate Limiting**: Prevent admin command flooding 5. **SQL Safety**: Only SELECT allowed, with timeout and row limits 6. **Input Validation**: Strict validation of all command parameters ## Testing Strategy 1. **Unit Tests**: Test each command handler independently 2. **Integration Tests**: Test full command flow with encryption 3. **Security Tests**: Verify auth checks and SQL injection prevention 4. **Performance Tests**: Ensure commands don't block relay operations 5. **Manual Tests**: Use nak tool to send real encrypted commands ## Documentation Updates Add new section to README.md after "Content Reporting (BUD-09)": ```markdown ## Administrator API Ginxsom uses an event-based administration system where commands are sent as NIP-44 encrypted Kind 23456 events and responses are returned as Kind 23457 events. This provides secure, cryptographically authenticated remote management. [Full admin API documentation here]