# Ginxsom Management System Design ## Executive Summary This document outlines the design for a secure management interface for ginxsom, a Blossom media storage server. The design adapts proven patterns from c-relay's management system while addressing ginxsom's specific requirements for blob storage, authentication, and FastCGI architecture. **Key Design Principles:** - **Security First**: NIP-17 gift wrap encryption for all admin commands - **Database-Centric**: Configuration and state stored in SQLite - **Unified Handler**: Tag-based routing similar to c-relay - **Two-Step Confirmation**: Critical operations require explicit confirmation - **Backwards Compatible**: Integrates with existing admin API without breaking changes --- ## Table of Contents 1. [System Architecture](#1-system-architecture) 2. [Database Schema](#2-database-schema) 3. [Keypair Management](#3-keypair-management) 4. [Authentication Architecture](#4-authentication-architecture) 5. [Management Commands](#5-management-commands) 6. [API Design](#6-api-design) 7. [File Structure](#7-file-structure) 8. [Implementation Plan](#8-implementation-plan) 9. [Security Considerations](#9-security-considerations) 10. [Migration Strategy](#10-migration-strategy) --- ## 1. System Architecture ### 1.1 Component Overview ```mermaid flowchart TB subgraph Client["Admin Client"] CLI[CLI Tool / nak] WEB[Web Interface] end subgraph Gateway["nginx Gateway"] NGINX[nginx] end subgraph FastCGI["FastCGI Application"] MAIN[main.c] VALIDATOR[request_validator.c] ADMIN[admin_api.c] MGMT[management_handler.c
NEW] DM[dm_admin.c
NEW] end subgraph Storage["Data Layer"] DB[(SQLite Database)] BLOBS[Blob Storage] KEYS[Key Storage
Memory Only] end CLI -->|NIP-17 Gift Wrap| NGINX WEB -->|NIP-17 Gift Wrap| NGINX NGINX -->|FastCGI| MAIN MAIN --> VALIDATOR VALIDATOR --> ADMIN ADMIN --> MGMT MGMT --> DM DM --> DB DM --> KEYS MGMT --> BLOBS style MGMT fill:#ff9 style DM fill:#ff9 style KEYS fill:#f99 ``` ### 1.2 Data Flow for Admin Commands ```mermaid sequenceDiagram participant Admin participant nginx participant FastCGI participant Validator participant DM Handler participant Database Admin->>nginx: POST /admin
NIP-17 Gift Wrap nginx->>FastCGI: Forward Request FastCGI->>Validator: Validate Auth Validator->>Validator: Decrypt Gift Wrap Validator->>Validator: Verify Admin Pubkey Validator-->>FastCGI: Auth Result alt Auth Failed FastCGI-->>Admin: 401/403 Error else Auth Success FastCGI->>DM Handler: Parse Command DM Handler->>DM Handler: Extract Tags DM Handler->>DM Handler: Route to Handler alt Critical Operation DM Handler->>Database: Store Pending Change DM Handler-->>Admin: Confirmation Required Admin->>nginx: POST /admin
Confirmation Event nginx->>FastCGI: Forward Confirmation FastCGI->>DM Handler: Execute Pending DM Handler->>Database: Apply Changes else Non-Critical DM Handler->>Database: Execute Directly end DM Handler->>DM Handler: Encrypt Response (NIP-44) DM Handler-->>Admin: Encrypted Result end ``` ### 1.3 Integration with Existing System The management system integrates with ginxsom's existing architecture: **Existing Components (Keep):** - [`src/main.c`](src/main.c:1): FastCGI request loop and routing - [`src/request_validator.c`](src/request_validator.c:1): Centralized authentication - [`src/admin_api.c`](src/admin_api.c:1): Current admin API endpoints - [`db/schema.sql`](db/schema.sql:1): Base database schema **New Components (Add):** - `src/management_handler.c`: Unified command handler - `src/dm_admin.c`: NIP-17 gift wrap processing - `src/keypair_manager.c`: Server and admin key management - `src/pending_changes.c`: Two-step confirmation system **Modified Components:** - [`src/main.c`](src/main.c:1640): Add `/admin` endpoint routing - [`src/request_validator.c`](src/request_validator.c:683): Add NIP-17 validation - [`db/schema.sql`](db/schema.sql:1): Add management tables --- ## 2. Database Schema ### 2.1 New Tables ```sql -- Server keypair (relay identity) CREATE TABLE IF NOT EXISTS server_keys ( id INTEGER PRIMARY KEY CHECK (id = 1), -- Singleton table public_key TEXT NOT NULL CHECK (length(public_key) = 64), private_key_encrypted TEXT NOT NULL, -- Encrypted with system key created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')), last_rotated INTEGER, UNIQUE(public_key) ); -- Admin public keys (authorized administrators) CREATE TABLE IF NOT EXISTS admin_keys ( id INTEGER PRIMARY KEY AUTOINCREMENT, public_key TEXT NOT NULL UNIQUE CHECK (length(public_key) = 64), name TEXT, -- Human-readable identifier permissions TEXT NOT NULL DEFAULT 'full', -- JSON array of permissions created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')), created_by TEXT, -- Admin pubkey who added this key last_used INTEGER, enabled INTEGER NOT NULL DEFAULT 1 CHECK (enabled IN (0, 1)) ); -- Pending changes requiring confirmation CREATE TABLE IF NOT EXISTS pending_changes ( id INTEGER PRIMARY KEY AUTOINCREMENT, change_type TEXT NOT NULL, -- 'delete_blob', 'update_config', 'add_admin', etc. change_data TEXT NOT NULL, -- JSON with change details requested_by TEXT NOT NULL, -- Admin pubkey requested_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')), expires_at INTEGER NOT NULL, -- Confirmation deadline confirmed INTEGER NOT NULL DEFAULT 0 CHECK (confirmed IN (0, 1)), confirmed_at INTEGER, executed INTEGER NOT NULL DEFAULT 0 CHECK (executed IN (0, 1)), executed_at INTEGER, result TEXT -- Execution result or error ); -- Admin command audit log CREATE TABLE IF NOT EXISTS admin_audit_log ( id INTEGER PRIMARY KEY AUTOINCREMENT, admin_pubkey TEXT NOT NULL, command TEXT NOT NULL, -- Command tag from event parameters TEXT, -- JSON with command parameters success INTEGER NOT NULL CHECK (success IN (0, 1)), error_message TEXT, timestamp INTEGER NOT NULL DEFAULT (strftime('%s', 'now')), client_ip TEXT, event_id TEXT -- Nostr event ID for traceability ); -- NIP-17 gift wrap tracking (prevent replay) CREATE TABLE IF NOT EXISTS gift_wrap_tracking ( event_id TEXT PRIMARY KEY, admin_pubkey TEXT NOT NULL, processed_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')), expires_at INTEGER NOT NULL ); -- Create indexes for performance CREATE INDEX IF NOT EXISTS idx_admin_keys_pubkey ON admin_keys(public_key); CREATE INDEX IF NOT EXISTS idx_admin_keys_enabled ON admin_keys(enabled); CREATE INDEX IF NOT EXISTS idx_pending_changes_expires ON pending_changes(expires_at); CREATE INDEX IF NOT EXISTS idx_pending_changes_requested_by ON pending_changes(requested_by); CREATE INDEX IF NOT EXISTS idx_audit_log_timestamp ON admin_audit_log(timestamp); CREATE INDEX IF NOT EXISTS idx_audit_log_admin ON admin_audit_log(admin_pubkey); CREATE INDEX IF NOT EXISTS idx_gift_wrap_expires ON gift_wrap_tracking(expires_at); ``` ### 2.2 Schema Extensions to Existing Tables ```sql -- Add management-related config keys INSERT OR IGNORE INTO config (key, value, description) VALUES ('server_pubkey', '', 'Server public key (relay identity)'), ('admin_dm_enabled', 'true', 'Enable NIP-17 DM-based admin commands'), ('admin_confirmation_timeout', '300', 'Seconds to confirm critical operations'), ('admin_session_timeout', '3600', 'Admin session timeout in seconds'), ('admin_rate_limit', '100', 'Max admin commands per hour per admin'), ('admin_audit_retention', '2592000', 'Audit log retention in seconds (30 days)'); ``` ### 2.3 Migration from Current Schema The current schema already has: - [`config`](db/schema.sql:21) table (unified configuration) - [`blobs`](db/schema.sql:8) table (blob metadata) - [`auth_rules`](db/schema.sql:47) table (authentication rules) **Migration Strategy:** 1. Add new tables without modifying existing ones 2. Populate `admin_keys` from existing `config.admin_pubkey` 3. Generate server keypair on first startup if not exists 4. Maintain backwards compatibility with existing admin API --- ## 3. Keypair Management ### 3.1 Server Keypair (Relay Identity) **Purpose:** Identifies the ginxsom server in Nostr ecosystem **Generation:** ```c // On first startup or explicit generation int generate_server_keypair(void) { unsigned char privkey[32]; unsigned char pubkey[32]; // Generate using nostr_core_lib if (nostr_generate_keypair(privkey, pubkey) != NOSTR_SUCCESS) { return -1; } // Store in database (encrypted) char pubkey_hex[65]; char privkey_hex[65]; nostr_bytes_to_hex(pubkey, 32, pubkey_hex); nostr_bytes_to_hex(privkey, 32, privkey_hex); // Encrypt private key before storage char encrypted_privkey[256]; encrypt_with_system_key(privkey_hex, encrypted_privkey); // Store in database return store_server_keypair(pubkey_hex, encrypted_privkey); } ``` **Storage:** - Public key: Stored in `server_keys.public_key` and `config.server_pubkey` - Private key: **NEVER** stored in database - kept in process memory only - On startup: Load from database, decrypt, keep in memory - On shutdown: Clear from memory securely **Command-Line Options:** ```bash # Generate new server keypair ginxsom-fcgi --generate-server-key # Import existing keypair ginxsom-fcgi --import-server-key # Show server public key ginxsom-fcgi --show-server-pubkey ``` ### 3.2 Admin Keypair Management **Purpose:** Authorize administrators to manage the server **Initial Setup:** ```bash # Generate admin keypair (done by admin, not server) ADMIN_PRIVKEY=$(nak key generate) ADMIN_PUBKEY=$(echo "$ADMIN_PRIVKEY" | nak key public) # Add admin to server (requires existing admin or direct DB access) sqlite3 db/ginxsom.db << EOF INSERT INTO admin_keys (public_key, name, permissions, created_by) VALUES ('$ADMIN_PUBKEY', 'Primary Admin', '["full"]', 'system'); EOF ``` **Runtime Management:** ```bash # Add new admin (via DM command) nak event -k 14 --envelope --sec $ADMIN_PRIVKEY \ --tag command add_admin \ --tag pubkey $NEW_ADMIN_PUBKEY \ --tag name "Secondary Admin" \ --tag permissions '["read","write"]' \ | curl -X POST http://localhost:9001/admin -d @- # List admins nak event -k 14 --envelope --sec $ADMIN_PRIVKEY \ --tag command list_admins \ | curl -X POST http://localhost:9001/admin -d @- # Revoke admin nak event -k 14 --envelope --sec $ADMIN_PRIVKEY \ --tag command revoke_admin \ --tag pubkey $ADMIN_TO_REVOKE \ | curl -X POST http://localhost:9001/admin -d @- ``` ### 3.3 Key Rotation **Server Key Rotation:** - Generate new keypair - Update database - Announce new pubkey via NIP-11 relay info - Keep old key for 30 days for transition **Admin Key Rotation:** - Admin generates new keypair - Uses old key to authorize new key - Old key remains valid during transition period - Explicit revocation of old key after confirmation --- ## 4. Authentication Architecture ### 4.1 NIP-17 Gift Wrap Overview **Why NIP-17?** - End-to-end encryption between admin and server - Prevents eavesdropping on admin commands - Provides forward secrecy - Standard Nostr protocol (interoperable) **Gift Wrap Structure:** ```json { "kind": 1059, "content": "", "tags": [ ["p", ""] ], "pubkey": "", "created_at": 1234567890, "sig": "" } ``` **Seal Structure (encrypted in gift wrap):** ```json { "kind": 13, "content": "", "tags": [ ["p", ""] ], "pubkey": "", "created_at": 1234567890 } ``` **Rumor Structure (encrypted in seal):** ```json { "kind": 14, "content": "", "tags": [ ["command", "list_blobs"], ["limit", "50"], ["offset", "0"] ], "pubkey": "", "created_at": 1234567890 } ``` ### 4.2 Authentication Flow ```mermaid sequenceDiagram participant Admin participant Server participant DB Admin->>Admin: Create Kind 14 Rumor
(command + params) Admin->>Admin: Wrap in Kind 13 Seal
(encrypt with server pubkey) Admin->>Admin: Wrap in Kind 1059 Gift
(encrypt with ephemeral key) Admin->>Server: POST /admin
Gift Wrap Event Server->>Server: Unwrap Gift
(decrypt with server privkey) Server->>Server: Unwrap Seal
(decrypt with admin pubkey) Server->>Server: Extract Rumor
(Kind 14 command) Server->>DB: Check admin_pubkey authorized alt Not Authorized Server-->>Admin: 403 Forbidden else Authorized Server->>DB: Check gift wrap not replayed alt Replayed Server-->>Admin: 409 Conflict (Replay) else Fresh Server->>DB: Store gift wrap ID Server->>Server: Parse command tags Server->>Server: Execute command Server->>DB: Log to audit_log Server->>Server: Encrypt response (NIP-44) Server-->>Admin: Encrypted Response end end ``` ### 4.3 Validation Rules **Gift Wrap Validation:** 1. Event kind must be 1059 2. Must have `p` tag with server pubkey 3. Signature must be valid 4. Created_at within acceptable time window (±5 minutes) **Seal Validation:** 1. Decryption must succeed with server private key 2. Event kind must be 13 3. Must have `p` tag with admin pubkey **Rumor Validation:** 1. Decryption must succeed with admin public key 2. Event kind must be 14 3. Admin pubkey must be in `admin_keys` table with `enabled=1` 4. Must have `command` tag 5. Event ID not in `gift_wrap_tracking` (prevent replay) 6. Created_at within acceptable time window **Integration with Existing Validator:** Add to [`src/request_validator.c`](src/request_validator.c:1): ```c // Add to event kind routing (around line 438) else if (event_kind == 1059) { // NIP-17 Gift Wrap for admin commands int gift_wrap_result = validate_gift_wrap_admin(event); if (gift_wrap_result != NOSTR_SUCCESS) { result->valid = 0; result->error_code = gift_wrap_result; strcpy(result->reason, "Gift wrap validation failed"); cJSON_Delete(event); return NOSTR_SUCCESS; } } ``` --- ## 5. Management Commands ### 5.1 Command Categories **Blob Operations:** - `list_blobs` - List blobs with filters - `get_blob_info` - Get detailed blob metadata - `delete_blob` - Delete blob (requires confirmation) - `mirror_blob` - Mirror blob from another server - `verify_blob` - Verify blob integrity **Storage Management:** - `get_storage_stats` - Get storage usage statistics - `get_disk_usage` - Get disk space information - `cleanup_orphans` - Remove orphaned files - `set_quota` - Set storage quota for user **Configuration:** - `get_config` - Get configuration values - `set_config` - Set configuration value (requires confirmation) - `list_auth_rules` - List authentication rules - `add_auth_rule` - Add authentication rule - `remove_auth_rule` - Remove authentication rule (requires confirmation) **Statistics:** - `get_stats` - Get server statistics - `get_upload_stats` - Get upload statistics by time period - `get_user_stats` - Get per-user statistics - `get_bandwidth_stats` - Get bandwidth usage **System:** - `get_health` - Get system health status - `get_version` - Get server version info - `backup_database` - Create database backup - `restore_database` - Restore from backup (requires confirmation) - `rotate_logs` - Rotate log files **Admin Management:** - `list_admins` - List admin keys - `add_admin` - Add new admin key (requires confirmation) - `revoke_admin` - Revoke admin key (requires confirmation) - `get_audit_log` - Get admin audit log ### 5.2 Command Structure **Request Format (Kind 14 Rumor):** ```json { "kind": 14, "content": "", "tags": [ ["command", "list_blobs"], ["limit", "50"], ["offset", "0"], ["filter_type", "image/*"], ["since", "1234567890"] ], "pubkey": "", "created_at": 1234567890 } ``` **Response Format (NIP-44 Encrypted):** ```json { "status": "success", "command": "list_blobs", "data": { "blobs": [...], "total": 1234, "limit": 50, "offset": 0 }, "timestamp": 1234567890 } ``` **Error Response:** ```json { "status": "error", "command": "list_blobs", "error": { "code": "INVALID_PARAMETER", "message": "Invalid limit value", "details": "Limit must be between 1 and 1000" }, "timestamp": 1234567890 } ``` ### 5.3 Two-Step Confirmation **Critical Operations Requiring Confirmation:** - `delete_blob` - Permanent data loss - `set_config` - System behavior changes - `add_admin` - Security implications - `revoke_admin` - Access control changes - `restore_database` - Data integrity risk **Confirmation Flow:** **Step 1: Request** ```json { "kind": 14, "tags": [ ["command", "delete_blob"], ["sha256", "abc123..."] ] } ``` **Step 1: Response** ```json { "status": "confirmation_required", "command": "delete_blob", "pending_id": "42", "details": { "sha256": "abc123...", "size": 1048576, "type": "image/jpeg", "uploaded_at": 1234567890 }, "expires_at": 1234568190, "message": "This will permanently delete the blob. Send confirmation within 5 minutes." } ``` **Step 2: Confirmation** ```json { "kind": 14, "tags": [ ["command", "confirm"], ["pending_id", "42"] ] } ``` **Step 2: Response** ```json { "status": "success", "command": "delete_blob", "data": { "sha256": "abc123...", "deleted": true }, "timestamp": 1234567900 } ``` --- ## 6. API Design ### 6.1 Endpoint Routing **New Endpoint:** - `POST /admin` - Unified admin command endpoint (NIP-17 gift wrap) **Existing Endpoints (Keep):** - `GET /api/stats` - Statistics (existing admin API) - `GET /api/config` - Configuration (existing admin API) - `PUT /api/config` - Update config (existing admin API) - `GET /api/files` - File listing (existing admin API) - `GET /api/health` - Health check (existing admin API) **Integration Strategy:** - New `/admin` endpoint for NIP-17 DM-based commands - Existing `/api/*` endpoints remain for backwards compatibility - Both systems share same database and authentication - Gradual migration path for clients ### 6.2 Request Handling **Handler Registration in [`src/main.c`](src/main.c:1640):** ```c // Add to main request loop (around line 1640) else if (strcmp(request_method, "POST") == 0 && strcmp(request_uri, "/admin") == 0) { // Handle NIP-17 gift wrap admin commands handle_admin_dm_request(); } ``` **Unified Handler Pattern:** ```c // src/management_handler.c void handle_admin_dm_request(void) { // 1. Read gift wrap event from request body char *event_json = read_request_body(); // 2. Validate and unwrap gift wrap admin_command_t cmd; int result = unwrap_admin_gift_wrap(event_json, &cmd); if (result != SUCCESS) { send_admin_error(result, "Failed to unwrap gift wrap"); return; } // 3. Check admin authorization if (!is_admin_authorized(cmd.admin_pubkey)) { send_admin_error(ERROR_UNAUTHORIZED, "Not authorized"); return; } // 4. Check for replay if (is_gift_wrap_replayed(cmd.event_id)) { send_admin_error(ERROR_REPLAY, "Gift wrap already processed"); return; } // 5. Route to command handler admin_response_t response; result = route_admin_command(&cmd, &response); // 6. Log to audit log log_admin_command(&cmd, result); // 7. Encrypt and send response send_admin_response(&response, cmd.admin_pubkey); } ``` ### 6.3 Tag-Based Routing **Command Router:** ```c int route_admin_command(admin_command_t *cmd, admin_response_t *response) { const char *command = get_tag_value(cmd->tags, "command"); if (!command) { return ERROR_MISSING_COMMAND; } // Blob operations if (strcmp(command, "list_blobs") == 0) { return handle_list_blobs(cmd, response); } else if (strcmp(command, "get_blob_info") == 0) { return handle_get_blob_info(cmd, response); } else if (strcmp(command, "delete_blob") == 0) { return handle_delete_blob(cmd, response); } // Storage management else if (strcmp(command, "get_storage_stats") == 0) { return handle_get_storage_stats(cmd, response); } else if (strcmp(command, "cleanup_orphans") == 0) { return handle_cleanup_orphans(cmd, response); } // Configuration else if (strcmp(command, "get_config") == 0) { return handle_get_config(cmd, response); } else if (strcmp(command, "set_config") == 0) { return handle_set_config(cmd, response); } // Admin management else if (strcmp(command, "list_admins") == 0) { return handle_list_admins(cmd, response); } else if (strcmp(command, "add_admin") == 0) { return handle_add_admin(cmd, response); } // Confirmation else if (strcmp(command, "confirm") == 0) { return handle_confirm_pending(cmd, response); } else { return ERROR_UNKNOWN_COMMAND; } } ``` --- ## 7. File Structure ### 7.1 New Files **Core Management:** ``` src/management_handler.c - Unified command handler and routing src/management_handler.h - Handler interface definitions src/dm_admin.c - NIP-17 gift wrap processing src/dm_admin.h - Gift wrap interface src/keypair_manager.c - Server and admin key management src/keypair_manager.h - Key management interface src/pending_changes.c - Two-step confirmation system src/pending_changes.h - Pending changes interface ``` **Command Handlers:** ``` src/commands/blob_commands.c - Blob operation handlers src/commands/storage_commands.c - Storage management handlers src/commands/config_commands.c - Configuration handlers src/commands/stats_commands.c - Statistics handlers src/commands/admin_commands.c - Admin management handlers src/commands/system_commands.c - System operation handlers ``` **Utilities:** ``` src/utils/encryption.c - NIP-44 encryption utilities src/utils/audit_log.c - Audit logging utilities src/utils/response_builder.c - Response formatting ``` ### 7.2 Modified Files **[`src/main.c`](src/main.c:1):** - Add `/admin` endpoint routing (line ~1640) - Initialize management system on startup - Add cleanup on shutdown **[`src/request_validator.c`](src/request_validator.c:1):** - Add Kind 1059 (gift wrap) validation (line ~438) - Add gift wrap unwrapping logic - Add replay prevention checks **[`src/admin_api.c`](src/admin_api.c:1):** - Keep existing endpoints for backwards compatibility - Add integration hooks for new management system - Share database access with new handlers **[`db/schema.sql`](db/schema.sql:1):** - Add new tables (server_keys, admin_keys, pending_changes, etc.) - Add indexes for performance - Add default configuration values **[`Makefile`](Makefile):** - Add new source files to build - Add dependencies for new modules - Update clean targets ### 7.3 Integration Points **With Existing Admin API:** ```c // src/admin_api.c - Add integration function void admin_api_notify_config_change(const char *key, const char *value) { // Called by management system when config changes // Invalidates cache, triggers reload nostr_request_validator_force_cache_refresh(); } ``` **With Request Validator:** ```c // src/request_validator.c - Add gift wrap validation int validate_gift_wrap_admin(cJSON *event) { // Validate Kind 1059 structure // Unwrap and validate seal // Unwrap and validate rumor // Check admin authorization // Check replay prevention return NOSTR_SUCCESS; } ``` **With Database:** ```c // All handlers use shared database connection // Consistent error handling // Transaction support for atomic operations ``` --- ## 8. Implementation Plan ### 8.1 Phase 1: Foundation (Week 1-2) **Goals:** - Database schema extensions - Keypair management - Basic gift wrap processing **Tasks:** 1. Create database migration script 2. Implement `keypair_manager.c` - Server keypair generation - Admin keypair storage - Key loading on startup 3. Implement `dm_admin.c` - Gift wrap unwrapping - Seal decryption - Rumor extraction 4. Add gift wrap validation to `request_validator.c` 5. Create test suite for gift wrap processing **Deliverables:** - Working keypair management - Gift wrap unwrap/validation - Database schema updated - Unit tests passing ### 8.2 Phase 2: Command Infrastructure (Week 3-4) **Goals:** - Unified command handler - Tag-based routing - Response encryption **Tasks:** 1. Implement `management_handler.c` - Request parsing - Command routing - Response building 2. Implement `pending_changes.c` - Two-step confirmation - Timeout handling - Execution tracking 3. Add `/admin` endpoint to `main.c` 4. Implement audit logging 5. Create command handler templates **Deliverables:** - Working command routing - Two-step confirmation system - Audit logging functional - Integration tests passing ### 8.3 Phase 3: Core Commands (Week 5-6) **Goals:** - Implement essential management commands - Integration with existing systems **Tasks:** 1. Implement blob commands - `list_blobs` - `get_blob_info` - `delete_blob` (with confirmation) 2. Implement storage commands - `get_storage_stats` - `get_disk_usage` - `cleanup_orphans` 3. Implement config commands - `get_config` - `set_config` (with confirmation) 4. Implement admin commands - `list_admins` - `add_admin` (with confirmation) - `revoke_admin` (with confirmation) 5. Integration testing with existing admin API **Deliverables:** - Core commands functional - Integration with existing API - End-to-end tests passing ### 8.4 Phase 4: Advanced Features (Week 7-8) **Goals:** - Statistics and monitoring - System operations - CLI tooling **Tasks:** 1. Implement stats commands - `get_stats` - `get_upload_stats` - `get_user_stats` 2. Implement system commands - `backup_database` - `restore_database` - `rotate_logs` 3. Create CLI tool for admin operations 4. Create web interface (optional) 5. Performance optimization 6. Security audit **Deliverables:** - All commands implemented - CLI tool functional - Performance benchmarks - Security review complete ### 8.5 Phase 5: Documentation & Deployment (Week 9-10) **Goals:** - Complete documentation - Deployment guides - Migration tools **Tasks:** 1. Write admin documentation 2. Create setup guides 3. Create migration scripts 4. Write troubleshooting guide 5. Create example scripts 6. Production deployment testing **Deliverables:** - Complete documentation - Migration tools - Deployment guides - Production-ready release --- ## 9. Security Considerations ### 9.1 Threat Model **Threats:** 1. **Unauthorized Access**: Attacker gains admin privileges 2. **Replay Attacks**: Reuse of captured gift wrap events 3. **Man-in-the-Middle**: Interception of admin commands 4. **Privilege Escalation**: Regular user gains admin access 5. **Data Exfiltration**: Unauthorized access to blob data 6. **Denial of Service**: Resource exhaustion via admin commands **Mitigations:** 1. **NIP-17 Encryption**: End-to-end encryption prevents MITM 2. **Gift Wrap Tracking**: Prevents replay attacks 3. **Admin Key Management**: Strict authorization checks 4. **Two-Step Confirmation**: Prevents accidental critical operations 5. **Audit Logging**: Tracks all admin actions 6. **Rate Limiting**: Prevents DoS via admin commands ### 9.2 Key Security **Server Private Key:** - **NEVER** stored in database - Loaded into memory on startup - Cleared on shutdown - Protected by OS memory protection - Consider using secure enclave if available **Admin Private Keys:** - **NEVER** stored on server - Managed by admin clients only - Rotated regularly - Revoked immediately if compromised **Database Encryption:** - Consider encrypting sensitive config values - Use system keyring for encryption keys - Implement key rotation mechanism ### 9.3 Access Control **Permission Levels:** ```json { "full": ["*"], "read": ["list_*", "get_*"], "write": ["list_*", "get_*", "set_*", "add_*"], "admin": ["list_*", "get_*", "set_*", "add_*", "delete_*", "revoke_*"] } ``` **Permission Checks:** ```c int check_admin_permission(const char *admin_pubkey, const char *command) { // Load admin permissions from database cJSON *permissions = get_admin_permissions(admin_pubkey); // Check if command is allowed if (has_permission(permissions, command)) { return 1; } // Check wildcard permissions if (has_permission(permissions, "*")) { return 1; } return 0; } ``` ### 9.4 Audit Trail **What to Log:** - All admin commands (success and failure) - Admin key additions/revocations - Configuration changes - Critical operations (delete, restore, etc.) - Authentication failures - Suspicious activity **Log Format:** ```json { "timestamp": 1234567890, "admin_pubkey": "abc123...", "command": "delete_blob", "parameters": {"sha256": "def456..."}, "success": true, "client_ip": "192.168.1.100", "event_id": "ghi789..." } ``` **Log Retention:** - Keep audit logs for 30 days minimum - Archive older logs to separate storage - Implement log rotation - Protect logs from tampering --- ## 10. Migration Strategy ### 10.1 Backwards Compatibility **Existing Admin API:** - Keep all existing `/api/*` endpoints - No breaking changes to current API - Gradual deprecation over 6 months - Clear migration documentation **Database:** - Additive schema changes only - No modifications to existing tables - Migration script handles upgrades - Rollback capability **Configuration:** - Existing config keys remain valid - New config keys added with defaults - No changes to config file format ### 10.2 Migration Steps **Step 1: Database Migration** ```bash # Backup existing database cp db/ginxsom.db db/ginxsom.db.backup # Run migration script sqlite3 db/ginxsom.db < db/migrations/002_add_management_system.sql # Verify migration sqlite3 db/ginxsom.db "SELECT name FROM sqlite_master WHERE type='table';" ``` **Step 2: Generate Server Keypair** ```bash # Generate server keypair ./build/ginxsom-fcgi --generate-server-key # Verify keypair ./build/ginxsom-fcgi --show-server-pubkey ``` **Step 3: Add Initial Admin** ```bash # Generate admin keypair ADMIN_PRIVKEY=$(nak key generate) ADMIN_PUBKEY=$(echo "$ADMIN_PRIVKEY" | nak key public) # Add to database sqlite3 db/ginxsom.db << EOF INSERT INTO admin_keys (public_key, name, permissions, created_by) VALUES ('$ADMIN_PUBKEY', 'Primary Admin', '["full"]', 'system'); EOF # Save admin private key securely echo "$ADMIN_PRIVKEY" > ~/.config/ginxsom/admin.key chmod 600 ~/.config/ginxsom/admin.key ``` **Step 4: Test New System** ```bash # Test gift wrap command nak event -k 14 --envelope --sec $ADMIN_PRIVKEY \ --tag command list_admins \ | curl -X POST http://localhost:9001/admin -d @- # Verify response ``` **Step 5: Update Clients** - Update admin scripts to use new `/admin` endpoint - Migrate from `/api/*` to NIP-17 commands - Test thoroughly before production ### 10.3 Rollback Plan **If Issues Occur:** 1. Stop ginxsom service 2. Restore database backup 3. Revert to previous version 4. Investigate issues 5. Fix and retry migration **Database Rollback:** ```bash # Stop service systemctl stop ginxsom # Restore backup cp db/ginxsom.db.backup db/ginxsom.db # Restart service systemctl start ginxsom ``` --- ## Appendix A: Command Reference ### Blob Commands **list_blobs** ```json { "command": "list_blobs", "limit": "50", "offset": "0", "filter_type": "image/*", "since": "1234567890" } ``` **get_blob_info** ```json { "command": "get_blob_info", "sha256": "abc123..." } ``` **delete_blob** (requires confirmation) ```json { "command": "delete_blob", "sha256": "abc123..." } ``` ### Storage Commands **get_storage_stats** ```json { "command": "get_storage_stats" } ``` **cleanup_orphans** ```json { "command": "cleanup_orphans", "dry_run": "true" } ``` ### Configuration Commands **get_config** ```json { "command": "get_config", "key": "max_file_size" } ``` **set_config** (requires confirmation) ```json { "command": "set_config", "key": "max_file_size", "value": "209715200" } ``` ### Admin Commands **list_admins** ```json { "command": "list_admins" } ``` **add_admin** (requires confirmation) ```json { "command": "add_admin", "pubkey": "def456...", "name": "Secondary Admin", "permissions": "[\"read\",\"write\"]" } ``` **revoke_admin** (requires confirmation) ```json { "command": "revoke_admin", "pubkey": "def456..." } ``` --- ## Appendix B: Example Scripts ### Setup Script ```bash #!/bin/bash # setup_admin.sh - Initial admin setup set -e echo "Ginxsom Admin Setup" echo "===================" # Generate admin keypair echo "Generating admin keypair..." ADMIN_PRIVKEY=$(nak key generate) ADMIN_PUBKEY=$(echo "$ADMIN_PRIVKEY" | nak key public) echo "Admin Public Key: $ADMIN_PUBKEY" # Save private key mkdir -p ~/.config/ginxsom echo "$ADMIN_PRIVKEY" > ~/.config/ginxsom/admin.key chmod 600 ~/.config/ginxsom/admin.key echo "Private key saved to ~/.config/ginxsom/admin.key" # Add to database echo "Adding admin to database..." sqlite3 db/ginxsom.db << EOF INSERT INTO admin_keys (public_key, name, permissions, created_by) VALUES ('$ADMIN_PUBKEY', 'Primary Admin', '["full"]', 'system'); EOF echo "Admin setup complete!" echo "Test with: ./admin_command.sh list_admins" ``` ### Admin Command Script ```bash #!/bin/bash # admin_command.sh - Send admin command ADMIN_PRIVKEY=$(cat ~/.config/ginxsom/admin.key) COMMAND=$1 shift # Build tags TAGS="" for arg in "$@"; do KEY=$(echo "$arg" | cut -d= -f1) VALUE=$(echo "$arg" | cut -d= -f2-) TAGS="$TAGS --tag $KEY \"$VALUE\"" done # Send command eval nak event -k 14 --envelope --sec "$ADMIN_PRIVKEY" \ --tag command "$COMMAND" \ $TAGS \ | curl -s -X POST http://localhost:9001/admin -d @- \ | jq . ``` ### Usage Examples ```bash # List admins ./admin_command.sh list_admins # Get storage stats ./admin_command.sh get_storage_stats # List blobs ./admin_command.sh list_blobs limit=10 offset=0 # Delete blob (with confirmation) ./admin_command.sh delete_blob sha256=abc123... # Then confirm ./admin_command.sh confirm pending_id=42 ``` --- ## Conclusion This design provides a secure, scalable management system for ginxsom that: 1. **Leverages Proven Patterns**: Adapts c-relay's successful architecture 2. **Maintains Security**: NIP-17 encryption and two-step confirmation 3. **Ensures Compatibility**: Integrates with existing admin API 4. **Enables Growth**: Extensible command system for future features 5. **Provides Auditability**: Complete audit trail of admin actions The phased implementation plan allows for incremental development and testing, while the migration strategy ensures smooth transition from the current system. **Next Steps:** 1. Review and approve design 2. Begin Phase 1 implementation 3. Set up development environment 4. Create test infrastructure 5. Start coding!