994 lines
26 KiB
Markdown
994 lines
26 KiB
Markdown
# Ginxsom Management System Design
|
|
|
|
## Executive Summary
|
|
|
|
This document outlines the design for a secure management interface for ginxsom (Blossom media storage server) based on c-relay's proven admin system architecture. The design uses Kind 23456/23457 events with NIP-44 encryption over WebSocket for real-time admin operations.
|
|
|
|
## 1. System Architecture
|
|
|
|
### 1.1 High-Level Overview
|
|
|
|
```mermaid
|
|
graph TB
|
|
Admin[Admin Client] -->|WebSocket| WS[WebSocket Handler]
|
|
WS -->|Kind 23456| Auth[Admin Authorization]
|
|
Auth -->|Decrypt NIP-44| Decrypt[Command Decryption]
|
|
Decrypt -->|Parse JSON Array| Router[Command Router]
|
|
Router -->|Route by Command Type| Handlers[Unified Handlers]
|
|
Handlers -->|Execute| DB[(Database)]
|
|
Handlers -->|Execute| FS[File System]
|
|
Handlers -->|Generate Response| Encrypt[NIP-44 Encryption]
|
|
Encrypt -->|Kind 23457| WS
|
|
WS -->|WebSocket| Admin
|
|
|
|
style Admin fill:#e1f5ff
|
|
style Auth fill:#fff3cd
|
|
style Handlers fill:#d4edda
|
|
style DB fill:#f8d7da
|
|
```
|
|
|
|
### 1.2 Component Architecture
|
|
|
|
```mermaid
|
|
graph LR
|
|
subgraph "Admin Interface"
|
|
CLI[CLI Tool]
|
|
Web[Web Dashboard]
|
|
end
|
|
|
|
subgraph "ginxsom FastCGI Process"
|
|
WS[WebSocket Endpoint]
|
|
Auth[Authorization Layer]
|
|
Router[Command Router]
|
|
|
|
subgraph "Unified Handlers"
|
|
BlobH[Blob Handler]
|
|
StorageH[Storage Handler]
|
|
ConfigH[Config Handler]
|
|
StatsH[Stats Handler]
|
|
SystemH[System Handler]
|
|
end
|
|
|
|
DB[(SQLite Database)]
|
|
Storage[Blob Storage]
|
|
end
|
|
|
|
CLI -->|WebSocket| WS
|
|
Web -->|WebSocket| WS
|
|
WS --> Auth
|
|
Auth --> Router
|
|
Router --> BlobH
|
|
Router --> StorageH
|
|
Router --> ConfigH
|
|
Router --> StatsH
|
|
Router --> SystemH
|
|
|
|
BlobH --> DB
|
|
BlobH --> Storage
|
|
StorageH --> Storage
|
|
ConfigH --> DB
|
|
StatsH --> DB
|
|
SystemH --> DB
|
|
|
|
style Auth fill:#fff3cd
|
|
style Router fill:#d4edda
|
|
```
|
|
|
|
### 1.3 Data Flow for Admin Commands
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant Admin
|
|
participant WebSocket
|
|
participant Auth
|
|
participant Handler
|
|
participant Database
|
|
|
|
Admin->>WebSocket: Kind 23456 Event (NIP-44 encrypted)
|
|
WebSocket->>Auth: Verify admin signature
|
|
Auth->>Auth: Check pubkey matches admin_pubkey
|
|
Auth->>Auth: Verify event signature
|
|
Auth->>WebSocket: Authorization OK
|
|
WebSocket->>Handler: Decrypt & parse command array
|
|
Handler->>Handler: Validate command structure
|
|
Handler->>Database: Execute operation
|
|
Database-->>Handler: Result
|
|
Handler->>Handler: Build response JSON
|
|
Handler->>WebSocket: Encrypt response (NIP-44)
|
|
WebSocket->>Admin: Kind 23457 Event (encrypted response)
|
|
```
|
|
|
|
### 1.4 Integration with Existing Ginxsom
|
|
|
|
```mermaid
|
|
graph TB
|
|
subgraph "Existing Ginxsom"
|
|
Main[main.c]
|
|
BUD04[bud04.c - Mirror]
|
|
BUD06[bud06.c - Requirements]
|
|
BUD08[bud08.c - NIP-94]
|
|
BUD09[bud09.c - Report]
|
|
AdminAPI[admin_api.c - Basic Admin]
|
|
Validator[request_validator.c]
|
|
end
|
|
|
|
subgraph "New Management System"
|
|
AdminWS[admin_websocket.c]
|
|
AdminAuth[admin_auth.c]
|
|
AdminHandlers[admin_handlers.c]
|
|
AdminConfig[admin_config.c]
|
|
end
|
|
|
|
Main -->|Initialize| AdminWS
|
|
AdminWS -->|Use| AdminAuth
|
|
AdminWS -->|Route to| AdminHandlers
|
|
AdminHandlers -->|Query| BUD04
|
|
AdminHandlers -->|Query| BUD06
|
|
AdminHandlers -->|Query| BUD08
|
|
AdminHandlers -->|Query| BUD09
|
|
AdminHandlers -->|Update| AdminConfig
|
|
AdminAuth -->|Use| Validator
|
|
|
|
style AdminWS fill:#d4edda
|
|
style AdminAuth fill:#fff3cd
|
|
style AdminHandlers fill:#e1f5ff
|
|
```
|
|
|
|
## 2. Database Schema
|
|
|
|
### 2.1 Core Tables
|
|
|
|
Following c-relay's minimal approach, we need only two tables for key management:
|
|
|
|
#### relay_seckey Table
|
|
```sql
|
|
-- Stores relay's private key (used for signing Kind 23457 responses)
|
|
CREATE TABLE relay_seckey (
|
|
private_key_hex TEXT NOT NULL CHECK (length(private_key_hex) = 64),
|
|
created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))
|
|
);
|
|
```
|
|
|
|
**Note**: This table stores the relay's private key as plain hex (no encryption). The key is used to:
|
|
- Sign Kind 23457 response events
|
|
- Encrypt responses using NIP-44 (shared secret with admin pubkey)
|
|
|
|
#### config Table (Extended)
|
|
```sql
|
|
-- Existing config table, add admin_pubkey entry
|
|
INSERT INTO config (key, value, data_type, description, category, requires_restart)
|
|
VALUES (
|
|
'admin_pubkey',
|
|
'<64-char-hex-pubkey>',
|
|
'string',
|
|
'Public key of authorized admin (hex format)',
|
|
'security',
|
|
0
|
|
);
|
|
```
|
|
|
|
**Note**: Admin public key is stored in the config table, not a separate table. Admin private key is NEVER stored anywhere.
|
|
|
|
### 2.2 Schema Comparison with c-relay
|
|
|
|
| c-relay | ginxsom | Purpose |
|
|
|---------|---------|---------|
|
|
| `relay_seckey` (private_key_hex, created_at) | `relay_seckey` (private_key_hex, created_at) | Relay private key storage |
|
|
| `config` table entry for admin_pubkey | `config` table entry for admin_pubkey | Admin authorization |
|
|
| No audit log | No audit log | Keep it simple |
|
|
| No processed events tracking | No processed events tracking | Stateless processing |
|
|
|
|
### 2.3 Key Storage Strategy
|
|
|
|
**Relay Private Key**:
|
|
- Stored in `relay_seckey` table as plain 64-character hex
|
|
- Generated on first startup or provided via `--relay-privkey` CLI option
|
|
- Used for signing Kind 23457 responses and NIP-44 encryption
|
|
- Never exposed via API
|
|
|
|
**Admin Public Key**:
|
|
- Stored in `config` table as plain 64-character hex
|
|
- Generated on first startup or provided via `--admin-pubkey` CLI option
|
|
- Used to verify Kind 23456 command signatures
|
|
- Can be queried via admin API
|
|
|
|
**Admin Private Key**:
|
|
- NEVER stored anywhere in the system
|
|
- Kept only by the admin in their client/tool
|
|
- Used to sign Kind 23456 commands and decrypt Kind 23457 responses
|
|
|
|
## 3. API Design
|
|
|
|
### 3.1 Command Structure
|
|
|
|
Following c-relay's pattern, all commands use JSON array format:
|
|
|
|
```json
|
|
["command_name", {"param1": "value1", "param2": "value2"}]
|
|
```
|
|
|
|
### 3.2 Event Structure
|
|
|
|
#### Kind 23456 - Admin Command Event
|
|
|
|
```json
|
|
{
|
|
"kind": 23456,
|
|
"pubkey": "<admin-pubkey-hex>",
|
|
"created_at": 1234567890,
|
|
"tags": [
|
|
["p", "<relay-pubkey-hex>"]
|
|
],
|
|
"content": "<nip44-encrypted-command-array>",
|
|
"sig": "<signature>"
|
|
}
|
|
```
|
|
|
|
**Content (decrypted)**:
|
|
```json
|
|
["blob_list", {"limit": 100, "offset": 0}]
|
|
```
|
|
|
|
#### Kind 23457 - Admin Response Event
|
|
|
|
```json
|
|
{
|
|
"kind": 23457,
|
|
"pubkey": "<relay-pubkey-hex>",
|
|
"created_at": 1234567890,
|
|
"tags": [
|
|
["p", "<admin-pubkey-hex>"],
|
|
["e", "<original-command-event-id>"]
|
|
],
|
|
"content": "<nip44-encrypted-response>",
|
|
"sig": "<signature>"
|
|
}
|
|
```
|
|
|
|
**Content (decrypted)**:
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"blobs": [
|
|
{"sha256": "abc123...", "size": 1024, "type": "image/png"},
|
|
{"sha256": "def456...", "size": 2048, "type": "video/mp4"}
|
|
],
|
|
"total": 2
|
|
}
|
|
}
|
|
```
|
|
|
|
### 3.3 Command Categories
|
|
|
|
#### Blob Operations
|
|
- `blob_list` - List blobs with pagination
|
|
- `blob_info` - Get detailed blob information
|
|
- `blob_delete` - Delete blob(s)
|
|
- `blob_mirror` - Mirror blob from another server
|
|
|
|
#### Storage Management
|
|
- `storage_stats` - Get storage usage statistics
|
|
- `storage_quota` - Get/set storage quotas
|
|
- `storage_cleanup` - Clean up orphaned files
|
|
|
|
#### Configuration
|
|
- `config_get` - Get configuration value(s)
|
|
- `config_set` - Set configuration value(s)
|
|
- `config_list` - List all configuration
|
|
- `auth_rules_list` - List authentication rules
|
|
- `auth_rules_add` - Add authentication rule
|
|
- `auth_rules_remove` - Remove authentication rule
|
|
|
|
#### Statistics
|
|
- `stats_uploads` - Upload statistics
|
|
- `stats_bandwidth` - Bandwidth usage
|
|
- `stats_storage` - Storage usage over time
|
|
- `stats_users` - User activity statistics
|
|
|
|
#### System
|
|
- `system_info` - Get system information
|
|
- `system_restart` - Restart server (graceful)
|
|
- `system_backup` - Trigger database backup
|
|
- `system_restore` - Restore from backup
|
|
|
|
### 3.4 Command Examples
|
|
|
|
#### Example 1: List Blobs
|
|
```json
|
|
// Command (Kind 23456 content, decrypted)
|
|
["blob_list", {
|
|
"limit": 50,
|
|
"offset": 0,
|
|
"type": "image/*",
|
|
"sort": "created_at",
|
|
"order": "desc"
|
|
}]
|
|
|
|
// Response (Kind 23457 content, decrypted)
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"blobs": [
|
|
{
|
|
"sha256": "abc123...",
|
|
"size": 102400,
|
|
"type": "image/png",
|
|
"created": 1234567890,
|
|
"url": "https://blossom.example.com/abc123.png"
|
|
}
|
|
],
|
|
"total": 150,
|
|
"limit": 50,
|
|
"offset": 0
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Example 2: Delete Blob
|
|
```json
|
|
// Command
|
|
["blob_delete", {
|
|
"sha256": "abc123...",
|
|
"confirm": true
|
|
}]
|
|
|
|
// Response
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"deleted": true,
|
|
"sha256": "abc123...",
|
|
"freed_bytes": 102400
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Example 3: Get Storage Stats
|
|
```json
|
|
// Command
|
|
["storage_stats", {}]
|
|
|
|
// Response
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"total_blobs": 1500,
|
|
"total_bytes": 5368709120,
|
|
"total_bytes_human": "5.0 GB",
|
|
"disk_usage": {
|
|
"used": 5368709120,
|
|
"available": 94631291904,
|
|
"total": 100000000000,
|
|
"percent": 5.4
|
|
},
|
|
"by_type": {
|
|
"image/png": {"count": 500, "bytes": 2147483648},
|
|
"image/jpeg": {"count": 300, "bytes": 1610612736},
|
|
"video/mp4": {"count": 200, "bytes": 1610612736}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Example 4: Set Configuration
|
|
```json
|
|
// Command
|
|
["config_set", {
|
|
"max_upload_size": 10485760,
|
|
"allowed_mime_types": ["image/*", "video/mp4"]
|
|
}]
|
|
|
|
// Response
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"updated": ["max_upload_size", "allowed_mime_types"],
|
|
"requires_restart": false
|
|
}
|
|
}
|
|
```
|
|
|
|
### 3.5 Error Handling
|
|
|
|
All errors follow consistent format:
|
|
|
|
```json
|
|
{
|
|
"success": false,
|
|
"error": {
|
|
"code": "BLOB_NOT_FOUND",
|
|
"message": "Blob with hash abc123... not found",
|
|
"details": {
|
|
"sha256": "abc123..."
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
**Error Codes**:
|
|
- `UNAUTHORIZED` - Invalid admin signature
|
|
- `INVALID_COMMAND` - Unknown command or malformed structure
|
|
- `INVALID_PARAMS` - Missing or invalid parameters
|
|
- `BLOB_NOT_FOUND` - Requested blob doesn't exist
|
|
- `STORAGE_FULL` - Storage quota exceeded
|
|
- `DATABASE_ERROR` - Database operation failed
|
|
- `SYSTEM_ERROR` - Internal server error
|
|
|
|
## 4. File Structure
|
|
|
|
### 4.1 New Files to Create
|
|
|
|
```
|
|
src/
|
|
├── admin_websocket.c # WebSocket endpoint for admin commands
|
|
├── admin_websocket.h # WebSocket handler declarations
|
|
├── admin_auth.c # Admin authorization (adapted from c-relay)
|
|
├── admin_auth.h # Authorization function declarations
|
|
├── admin_handlers.c # Unified command handlers
|
|
├── admin_handlers.h # Handler function declarations
|
|
├── admin_config.c # Configuration management
|
|
├── admin_config.h # Config function declarations
|
|
└── admin_keys.c # Key generation and storage
|
|
admin_keys.h # Key management declarations
|
|
|
|
include/
|
|
└── admin_system.h # Public admin system interface
|
|
```
|
|
|
|
### 4.2 Files to Adapt from c-relay
|
|
|
|
| c-relay File | Purpose | Adaptation for ginxsom |
|
|
|--------------|---------|------------------------|
|
|
| `dm_admin.c` | Admin event processing | → `admin_websocket.c` (WebSocket instead of DM) |
|
|
| `api.c` (lines 768-838) | NIP-44 encryption/response | → `admin_handlers.c` (response generation) |
|
|
| `config.c` (lines 500-583) | Key storage/retrieval | → `admin_keys.c` (relay key management) |
|
|
| `main.c` (lines 1389-1556) | CLI argument parsing | → `main.c` (add admin CLI options) |
|
|
|
|
### 4.3 Integration with Existing Files
|
|
|
|
**src/main.c**:
|
|
- Add CLI options: `--admin-pubkey`, `--relay-privkey`
|
|
- Initialize admin WebSocket endpoint
|
|
- Generate keys on first startup
|
|
|
|
**src/admin_api.c** (existing):
|
|
- Keep existing basic admin API
|
|
- Add WebSocket admin endpoint
|
|
- Route Kind 23456 events to new handlers
|
|
|
|
**db/schema.sql**:
|
|
- Add `relay_seckey` table
|
|
- Add `admin_pubkey` to config table
|
|
|
|
## 5. Implementation Plan
|
|
|
|
### 5.1 Phase 1: Foundation (Week 1)
|
|
|
|
**Goal**: Set up key management and database schema
|
|
|
|
**Tasks**:
|
|
1. Create `relay_seckey` table in schema
|
|
2. Add `admin_pubkey` to config table
|
|
3. Implement `admin_keys.c`:
|
|
- `generate_relay_keypair()`
|
|
- `generate_admin_keypair()`
|
|
- `store_relay_private_key()`
|
|
- `load_relay_private_key()`
|
|
- `get_admin_pubkey()`
|
|
4. Update `main.c`:
|
|
- Add CLI options (`--admin-pubkey`, `--relay-privkey`)
|
|
- Generate keys on first startup
|
|
- Print keys once (like c-relay)
|
|
5. Test key generation and storage
|
|
|
|
**Deliverables**:
|
|
- Working key generation
|
|
- Keys stored in database
|
|
- CLI options functional
|
|
|
|
### 5.2 Phase 2: Authorization (Week 2)
|
|
|
|
**Goal**: Implement admin event authorization
|
|
|
|
**Tasks**:
|
|
1. Create `admin_auth.c` (adapted from c-relay's authorization):
|
|
- `verify_admin_event()` - Check Kind 23456 signature
|
|
- `check_admin_pubkey()` - Verify against stored admin_pubkey
|
|
- `verify_relay_target()` - Check 'p' tag matches relay pubkey
|
|
2. Add NIP-44 crypto functions (use existing nostr_core_lib):
|
|
- `decrypt_admin_command()` - Decrypt Kind 23456 content
|
|
- `encrypt_admin_response()` - Encrypt Kind 23457 content
|
|
3. Test authorization flow
|
|
4. Test encryption/decryption
|
|
|
|
**Deliverables**:
|
|
- Working authorization layer
|
|
- NIP-44 encryption functional
|
|
- Unit tests for auth
|
|
|
|
### 5.3 Phase 3: WebSocket Endpoint (Week 3)
|
|
|
|
**Goal**: Create WebSocket handler for admin commands
|
|
|
|
**Tasks**:
|
|
1. Create `admin_websocket.c`:
|
|
- WebSocket endpoint at `/admin` or similar
|
|
- Receive Kind 23456 events
|
|
- Route to authorization layer
|
|
- Parse command array from decrypted content
|
|
- Route to appropriate handler
|
|
- Build Kind 23457 response
|
|
- Send encrypted response
|
|
2. Integrate with existing FastCGI WebSocket handling
|
|
3. Add connection management
|
|
4. Test WebSocket communication
|
|
|
|
**Deliverables**:
|
|
- Working WebSocket endpoint
|
|
- Event routing functional
|
|
- Response generation working
|
|
|
|
### 5.4 Phase 4: Command Handlers (Week 4-5)
|
|
|
|
**Goal**: Implement unified command handlers
|
|
|
|
**Tasks**:
|
|
1. Create `admin_handlers.c` with unified handler pattern:
|
|
- `handle_blob_command()` - Blob operations
|
|
- `handle_storage_command()` - Storage management
|
|
- `handle_config_command()` - Configuration
|
|
- `handle_stats_command()` - Statistics
|
|
- `handle_system_command()` - System operations
|
|
2. Implement each command:
|
|
- Blob: list, info, delete, mirror
|
|
- Storage: stats, quota, cleanup
|
|
- Config: get, set, list, auth_rules
|
|
- Stats: uploads, bandwidth, storage, users
|
|
- System: info, restart, backup, restore
|
|
3. Add validation for each command
|
|
4. Test each command individually
|
|
|
|
**Deliverables**:
|
|
- All commands implemented
|
|
- Validation working
|
|
- Integration tests passing
|
|
|
|
### 5.5 Phase 5: Testing & Documentation (Week 6)
|
|
|
|
**Goal**: Comprehensive testing and documentation
|
|
|
|
**Tasks**:
|
|
1. Create test suite:
|
|
- Unit tests for each handler
|
|
- Integration tests for full flow
|
|
- Security tests for authorization
|
|
- Performance tests for WebSocket
|
|
2. Create admin CLI tool (simple Node.js/Python script):
|
|
- Generate Kind 23456 events
|
|
- Send via WebSocket
|
|
- Decrypt Kind 23457 responses
|
|
- Pretty-print results
|
|
3. Write documentation:
|
|
- Admin API reference
|
|
- CLI tool usage guide
|
|
- Security best practices
|
|
- Troubleshooting guide
|
|
4. Create example scripts
|
|
|
|
**Deliverables**:
|
|
- Complete test suite
|
|
- Working CLI tool
|
|
- Full documentation
|
|
- Example scripts
|
|
|
|
### 5.6 Phase 6: Web Dashboard (Optional, Week 7-8)
|
|
|
|
**Goal**: Create web-based admin interface
|
|
|
|
**Tasks**:
|
|
1. Design web UI (React/Vue/Svelte)
|
|
2. Implement WebSocket client
|
|
3. Create command forms
|
|
4. Add real-time updates
|
|
5. Deploy dashboard
|
|
|
|
**Deliverables**:
|
|
- Working web dashboard
|
|
- User documentation
|
|
- Deployment guide
|
|
|
|
## 6. Security Considerations
|
|
|
|
### 6.1 Key Security
|
|
|
|
**Relay Private Key**:
|
|
- Stored in database as plain hex (following c-relay pattern)
|
|
- Never exposed via API
|
|
- Used only for signing responses
|
|
- Backed up with database
|
|
|
|
**Admin Private Key**:
|
|
- NEVER stored on server
|
|
- Kept only by admin
|
|
- Used to sign commands
|
|
- Should be stored securely by admin (password manager, hardware key, etc.)
|
|
|
|
**Admin Public Key**:
|
|
- Stored in config table
|
|
- Used for authorization
|
|
- Can be rotated by updating config
|
|
|
|
### 6.2 Authorization Flow
|
|
|
|
1. Receive Kind 23456 event
|
|
2. Verify event signature (nostr_verify_event_signature)
|
|
3. Check pubkey matches admin_pubkey from config
|
|
4. Verify 'p' tag targets this relay
|
|
5. Decrypt content using NIP-44
|
|
6. Parse and validate command
|
|
7. Execute command
|
|
8. Encrypt response using NIP-44
|
|
9. Sign Kind 23457 response
|
|
10. Send response
|
|
|
|
### 6.3 Attack Mitigation
|
|
|
|
**Replay Attacks**:
|
|
- Check event timestamp (reject old events)
|
|
- Optional: Track processed event IDs (if needed)
|
|
|
|
**Unauthorized Access**:
|
|
- Strict pubkey verification
|
|
- Signature validation
|
|
- Relay targeting check
|
|
|
|
**Command Injection**:
|
|
- Validate all command parameters
|
|
- Use parameterized SQL queries
|
|
- Sanitize file paths
|
|
|
|
**DoS Protection**:
|
|
- Rate limit admin commands
|
|
- Timeout long-running operations
|
|
- Limit response sizes
|
|
|
|
## 7. Command Line Interface
|
|
|
|
### 7.1 CLI Options (Following c-relay Pattern)
|
|
|
|
```bash
|
|
ginxsom [OPTIONS]
|
|
|
|
Options:
|
|
-h, --help Show help message
|
|
-v, --version Show version information
|
|
-p, --port PORT Override server port
|
|
--strict-port Fail if exact port unavailable
|
|
-a, --admin-pubkey KEY Override admin public key (hex or npub)
|
|
-r, --relay-privkey KEY Override relay private key (hex or nsec)
|
|
--debug-level=N Set debug level (0-5)
|
|
|
|
Examples:
|
|
ginxsom # Start server (auto-generate keys on first run)
|
|
ginxsom -p 8080 # Start on port 8080
|
|
ginxsom -a <npub> # Set admin pubkey
|
|
ginxsom -r <nsec> # Set relay privkey
|
|
ginxsom --debug-level=3 # Enable info-level debugging
|
|
```
|
|
|
|
### 7.2 First Startup Behavior
|
|
|
|
On first startup (no database exists):
|
|
|
|
1. Generate relay keypair
|
|
2. Generate admin keypair
|
|
3. Print keys ONCE to console:
|
|
```
|
|
=== Ginxsom First Startup ===
|
|
|
|
Relay Keys (for server):
|
|
Public Key (npub): npub1...
|
|
Private Key (nsec): nsec1...
|
|
|
|
Admin Keys (for you):
|
|
Public Key (npub): npub1...
|
|
Private Key (nsec): nsec1...
|
|
|
|
IMPORTANT: Save these keys securely!
|
|
The admin private key will NOT be shown again.
|
|
The relay private key is stored in the database.
|
|
|
|
Database created: <relay-pubkey>.db
|
|
```
|
|
|
|
4. Store relay private key in database
|
|
5. Store admin public key in config
|
|
6. Start server
|
|
|
|
### 7.3 Subsequent Startups
|
|
|
|
On subsequent startups:
|
|
|
|
1. Find existing database file
|
|
2. Load relay private key from database
|
|
3. Load admin public key from config
|
|
4. Apply CLI overrides if provided
|
|
5. Start server
|
|
|
|
## 8. Comparison with c-relay
|
|
|
|
### 8.1 Similarities
|
|
|
|
| Feature | c-relay | ginxsom |
|
|
|---------|---------|---------|
|
|
| Event Types | Kind 23456/23457 | Kind 23456/23457 |
|
|
| Encryption | NIP-44 | NIP-44 |
|
|
| Command Format | JSON arrays | JSON arrays |
|
|
| Key Storage | relay_seckey table | relay_seckey table |
|
|
| Admin Auth | config table | config table |
|
|
| CLI Options | --admin-pubkey, --relay-privkey | --admin-pubkey, --relay-privkey |
|
|
| Response Format | Encrypted JSON | Encrypted JSON |
|
|
|
|
### 8.2 Differences
|
|
|
|
| Aspect | c-relay | ginxsom |
|
|
|--------|---------|---------|
|
|
| Transport | WebSocket (Nostr relay) | WebSocket (FastCGI) |
|
|
| Commands | Relay-specific (auth, config, stats) | Blossom-specific (blob, storage, mirror) |
|
|
| Database | SQLite (events) | SQLite (blobs + metadata) |
|
|
| File Storage | N/A | Blob storage on disk |
|
|
| Integration | Standalone relay | FastCGI + nginx |
|
|
|
|
### 8.3 Architectural Decisions
|
|
|
|
**Why follow c-relay's pattern?**
|
|
1. Proven in production
|
|
2. Simple and secure
|
|
3. No complex key management
|
|
4. Minimal database schema
|
|
5. Easy to understand and maintain
|
|
|
|
**What we're NOT doing (from initial design)**:
|
|
1. ❌ NIP-17 gift wrap (too complex)
|
|
2. ❌ Separate admin_keys table (use config)
|
|
3. ❌ Audit log table (keep it simple)
|
|
4. ❌ Processed events tracking (stateless)
|
|
5. ❌ Key encryption before storage (plain hex)
|
|
6. ❌ Migration strategy (new project)
|
|
|
|
## 9. Testing Strategy
|
|
|
|
### 9.1 Unit Tests
|
|
|
|
**admin_keys.c**:
|
|
- Key generation produces valid keys
|
|
- Keys can be stored and retrieved
|
|
- Invalid keys are rejected
|
|
|
|
**admin_auth.c**:
|
|
- Valid admin events pass authorization
|
|
- Invalid signatures are rejected
|
|
- Wrong pubkeys are rejected
|
|
- Expired events are rejected
|
|
|
|
**admin_handlers.c**:
|
|
- Each command handler works correctly
|
|
- Invalid parameters are rejected
|
|
- Error responses are properly formatted
|
|
|
|
### 9.2 Integration Tests
|
|
|
|
**Full Flow**:
|
|
1. Generate admin keypair
|
|
2. Create Kind 23456 command
|
|
3. Send via WebSocket
|
|
4. Verify authorization
|
|
5. Execute command
|
|
6. Receive Kind 23457 response
|
|
7. Decrypt and verify response
|
|
|
|
**Security Tests**:
|
|
- Unauthorized pubkey rejected
|
|
- Invalid signature rejected
|
|
- Replay attack prevented
|
|
- Command injection prevented
|
|
|
|
### 9.3 Performance Tests
|
|
|
|
- WebSocket connection handling
|
|
- Command processing latency
|
|
- Concurrent admin operations
|
|
- Large response handling
|
|
|
|
## 10. Future Enhancements
|
|
|
|
### 10.1 Short Term
|
|
|
|
1. **Command History**: Track admin commands for audit
|
|
2. **Multi-Admin Support**: Multiple authorized admin pubkeys
|
|
3. **Role-Based Access**: Different permission levels
|
|
4. **Batch Operations**: Execute multiple commands in one request
|
|
|
|
### 10.2 Long Term
|
|
|
|
1. **Web Dashboard**: Full-featured web UI
|
|
2. **Monitoring Integration**: Prometheus/Grafana metrics
|
|
3. **Backup Automation**: Scheduled backups
|
|
4. **Replication**: Multi-server blob replication
|
|
5. **Advanced Analytics**: Usage patterns, trends, predictions
|
|
|
|
## 11. References
|
|
|
|
### 11.1 Nostr NIPs
|
|
|
|
- **NIP-01**: Basic protocol flow
|
|
- **NIP-04**: Encrypted Direct Messages (deprecated, but reference)
|
|
- **NIP-19**: bech32-encoded entities (npub, nsec)
|
|
- **NIP-44**: Versioned Encryption (used for admin commands)
|
|
|
|
### 11.2 Blossom Specifications
|
|
|
|
- **BUD-01**: Blob Upload/Download
|
|
- **BUD-02**: Blob Descriptor
|
|
- **BUD-04**: Mirroring
|
|
- **BUD-06**: Upload Requirements
|
|
- **BUD-08**: NIP-94 Integration
|
|
- **BUD-09**: Blob Reporting
|
|
|
|
### 11.3 c-relay Source Files
|
|
|
|
- `c-relay/src/dm_admin.c` - Admin event processing
|
|
- `c-relay/src/api.c` - NIP-44 encryption
|
|
- `c-relay/src/config.c` - Key storage
|
|
- `c-relay/src/main.c` - CLI options
|
|
- `c-relay/src/sql_schema.h` - Database schema
|
|
|
|
## 12. Appendix
|
|
|
|
### 12.1 Example Admin CLI Tool (Python)
|
|
|
|
```python
|
|
#!/usr/bin/env python3
|
|
"""
|
|
Ginxsom Admin CLI Tool
|
|
Sends admin commands to ginxsom server via WebSocket
|
|
"""
|
|
|
|
import asyncio
|
|
import websockets
|
|
import json
|
|
from nostr_sdk import Keys, Event, EventBuilder, Kind
|
|
|
|
class GinxsomAdmin:
|
|
def __init__(self, server_url, admin_nsec, relay_npub):
|
|
self.server_url = server_url
|
|
self.admin_keys = Keys.parse(admin_nsec)
|
|
self.relay_pubkey = Keys.parse(relay_npub).public_key()
|
|
|
|
async def send_command(self, command, params):
|
|
"""Send admin command and wait for response"""
|
|
# Build command array
|
|
command_array = [command, params]
|
|
|
|
# Encrypt with NIP-44
|
|
encrypted = self.admin_keys.nip44_encrypt(
|
|
self.relay_pubkey,
|
|
json.dumps(command_array)
|
|
)
|
|
|
|
# Build Kind 23456 event
|
|
event = EventBuilder(
|
|
Kind(23456),
|
|
encrypted,
|
|
[["p", str(self.relay_pubkey)]]
|
|
).to_event(self.admin_keys)
|
|
|
|
# Send via WebSocket
|
|
async with websockets.connect(self.server_url) as ws:
|
|
await ws.send(json.dumps(event.as_json()))
|
|
|
|
# Wait for Kind 23457 response
|
|
response = await ws.recv()
|
|
response_event = Event.from_json(response)
|
|
|
|
# Decrypt response
|
|
decrypted = self.admin_keys.nip44_decrypt(
|
|
self.relay_pubkey,
|
|
response_event.content()
|
|
)
|
|
|
|
return json.loads(decrypted)
|
|
|
|
# Usage
|
|
async def main():
|
|
admin = GinxsomAdmin(
|
|
"ws://localhost:8080/admin",
|
|
"nsec1...", # Admin private key
|
|
"npub1..." # Relay public key
|
|
)
|
|
|
|
# List blobs
|
|
result = await admin.send_command("blob_list", {
|
|
"limit": 10,
|
|
"offset": 0
|
|
})
|
|
|
|
print(json.dumps(result, indent=2))
|
|
|
|
if __name__ == "__main__":
|
|
asyncio.run(main())
|
|
```
|
|
|
|
### 12.2 Database Schema SQL
|
|
|
|
```sql
|
|
-- Add to db/schema.sql
|
|
|
|
-- Relay Private Key Storage
|
|
CREATE TABLE relay_seckey (
|
|
private_key_hex TEXT NOT NULL CHECK (length(private_key_hex) = 64),
|
|
created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))
|
|
);
|
|
|
|
-- Admin Public Key (add to config table)
|
|
INSERT INTO config (key, value, data_type, description, category, requires_restart)
|
|
VALUES (
|
|
'admin_pubkey',
|
|
'', -- Set during first startup
|
|
'string',
|
|
'Public key of authorized admin (64-char hex)',
|
|
'security',
|
|
0
|
|
);
|
|
|
|
-- Relay Public Key (add to config table)
|
|
INSERT INTO config (key, value, data_type, description, category, requires_restart)
|
|
VALUES (
|
|
'relay_pubkey',
|
|
'', -- Set during first startup
|
|
'string',
|
|
'Public key of this relay (64-char hex)',
|
|
'server',
|
|
0
|
|
);
|
|
```
|
|
|
|
### 12.3 Makefile Updates
|
|
|
|
```makefile
|
|
# Add to Makefile
|
|
|
|
# Admin system objects
|
|
ADMIN_OBJS = build/admin_websocket.o \
|
|
build/admin_auth.o \
|
|
build/admin_handlers.o \
|
|
build/admin_config.o \
|
|
build/admin_keys.o
|
|
|
|
# Update main target
|
|
build/ginxsom-fcgi: $(OBJS) $(ADMIN_OBJS)
|
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
|
|
|
# Admin system rules
|
|
build/admin_websocket.o: src/admin_websocket.c
|
|
$(CC) $(CFLAGS) -c $< -o $@
|
|
|
|
build/admin_auth.o: src/admin_auth.c
|
|
$(CC) $(CFLAGS) -c $< -o $@
|
|
|
|
build/admin_handlers.o: src/admin_handlers.c
|
|
$(CC) $(CFLAGS) -c $< -o $@
|
|
|
|
build/admin_config.o: src/admin_config.c
|
|
$(CC) $(CFLAGS) -c $< -o $@
|
|
|
|
build/admin_keys.o: src/admin_keys.c
|
|
$(CC) $(CFLAGS) -c $< -o $@
|
|
```
|
|
|
|
---
|
|
|
|
**Document Version**: 2.0
|
|
**Last Updated**: 2025-01-16
|
|
**Status**: Ready for Implementation |