358 lines
13 KiB
Markdown
358 lines
13 KiB
Markdown
# Event-Based Configuration System Implementation Plan
|
|
|
|
## Overview
|
|
|
|
This document provides a detailed implementation plan for transitioning the C Nostr Relay from command line arguments and file-based configuration to a pure event-based configuration system using kind 33334 Nostr events stored directly in the database.
|
|
|
|
## Implementation Phases
|
|
|
|
### Phase 0: File Structure Preparation ✅ COMPLETED
|
|
|
|
#### 0.1 Backup and Prepare Files ✅ COMPLETED
|
|
**Actions:**
|
|
1. ✅ Rename `src/config.c` to `src/config.c.old` - DONE
|
|
2. ✅ Rename `src/config.h` to `src/config.h.old` - DONE
|
|
3. ✅ Create new empty `src/config.c` and `src/config.h` - DONE
|
|
4. ✅ Create new `src/default_config_event.h` - DONE
|
|
|
|
### Phase 1: Database Schema and Core Infrastructure ✅ COMPLETED
|
|
|
|
#### 1.1 Update Database Naming System ✅ COMPLETED
|
|
**File:** `src/main.c`, new `src/config.c`, new `src/config.h`
|
|
|
|
```c
|
|
// New functions implemented: ✅
|
|
char* get_database_name_from_relay_pubkey(const char* relay_pubkey);
|
|
int create_database_with_relay_pubkey(const char* relay_pubkey);
|
|
```
|
|
|
|
**Changes Completed:** ✅
|
|
- ✅ Create completely new `src/config.c` and `src/config.h` files
|
|
- ✅ Rename old files to `src/config.c.old` and `src/config.h.old`
|
|
- ✅ Modify `init_database()` to use relay pubkey for database naming
|
|
- ✅ Use `nostr_core_lib` functions for all keypair generation
|
|
- ✅ Database path: `./<relay_pubkey>.nrdb`
|
|
- ✅ Remove all database path command line argument handling
|
|
|
|
#### 1.2 Configuration Event Storage ✅ COMPLETED
|
|
**File:** new `src/config.c`, new `src/default_config_event.h`
|
|
|
|
```c
|
|
// Configuration functions implemented: ✅
|
|
int store_config_event_in_database(const cJSON* event);
|
|
cJSON* load_config_event_from_database(const char* relay_pubkey);
|
|
```
|
|
|
|
**Changes Completed:** ✅
|
|
- ✅ Create new `src/default_config_event.h` for default configuration values
|
|
- ✅ Add functions to store/retrieve kind 33334 events from events table
|
|
- ✅ Use `nostr_core_lib` functions for all event validation
|
|
- ✅ Clean separation: default config values isolated in header file
|
|
- ✅ Remove existing config table dependencies
|
|
|
|
### Phase 2: Event Processing Integration ✅ COMPLETED
|
|
|
|
#### 2.1 Real-time Configuration Processing ✅ COMPLETED
|
|
**File:** `src/main.c` (event processing functions)
|
|
|
|
**Integration Points:** ✅ IMPLEMENTED
|
|
```c
|
|
// In existing event processing loop: ✅ IMPLEMENTED
|
|
// Added kind 33334 event detection in main event loop
|
|
if (kind_num == 33334) {
|
|
if (handle_configuration_event(event, error_message, sizeof(error_message)) == 0) {
|
|
// Configuration event processed successfully
|
|
}
|
|
}
|
|
|
|
// Configuration event processing implemented: ✅
|
|
int process_configuration_event(const cJSON* event);
|
|
int handle_configuration_event(cJSON* event, char* error_message, size_t error_size);
|
|
```
|
|
|
|
#### 2.2 Configuration Application System ⚠️ PARTIALLY COMPLETED
|
|
**File:** `src/config.c`
|
|
|
|
**Status:** Configuration access functions implemented, field handlers need completion
|
|
```c
|
|
// Configuration access implemented: ✅
|
|
const char* get_config_value(const char* key);
|
|
int get_config_int(const char* key, int default_value);
|
|
int get_config_bool(const char* key, int default_value);
|
|
|
|
// Field handlers need implementation: ⏳ IN PROGRESS
|
|
// Need to implement specific apply functions for runtime changes
|
|
```
|
|
|
|
### Phase 3: First-Time Startup System ✅ COMPLETED
|
|
|
|
#### 3.1 Key Generation and Initial Setup ✅ COMPLETED
|
|
**File:** new `src/config.c`, `src/default_config_event.h`
|
|
|
|
**Status:** ✅ FULLY IMPLEMENTED with secure /dev/urandom + nostr_core_lib validation
|
|
|
|
```c
|
|
int first_time_startup_sequence() {
|
|
// 1. Generate admin keypair using nostr_core_lib
|
|
unsigned char admin_privkey_bytes[32];
|
|
char admin_privkey[65], admin_pubkey[65];
|
|
|
|
if (nostr_generate_private_key(admin_privkey_bytes) != 0) {
|
|
return -1;
|
|
}
|
|
nostr_bytes_to_hex(admin_privkey_bytes, 32, admin_privkey);
|
|
|
|
unsigned char admin_pubkey_bytes[32];
|
|
if (nostr_ec_public_key_from_private_key(admin_privkey_bytes, admin_pubkey_bytes) != 0) {
|
|
return -1;
|
|
}
|
|
nostr_bytes_to_hex(admin_pubkey_bytes, 32, admin_pubkey);
|
|
|
|
// 2. Generate relay keypair using nostr_core_lib
|
|
unsigned char relay_privkey_bytes[32];
|
|
char relay_privkey[65], relay_pubkey[65];
|
|
|
|
if (nostr_generate_private_key(relay_privkey_bytes) != 0) {
|
|
return -1;
|
|
}
|
|
nostr_bytes_to_hex(relay_privkey_bytes, 32, relay_privkey);
|
|
|
|
unsigned char relay_pubkey_bytes[32];
|
|
if (nostr_ec_public_key_from_private_key(relay_privkey_bytes, relay_pubkey_bytes) != 0) {
|
|
return -1;
|
|
}
|
|
nostr_bytes_to_hex(relay_pubkey_bytes, 32, relay_pubkey);
|
|
|
|
// 3. Create database with relay pubkey name
|
|
if (create_database_with_relay_pubkey(relay_pubkey) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
// 4. Create initial configuration event using defaults from header
|
|
cJSON* config_event = create_default_config_event(admin_privkey_bytes, relay_privkey, relay_pubkey);
|
|
|
|
// 5. Store configuration event in database
|
|
store_config_event_in_database(config_event);
|
|
|
|
// 6. Print admin private key for user to save
|
|
printf("=== SAVE THIS ADMIN PRIVATE KEY ===\n");
|
|
printf("Admin Private Key: %s\n", admin_privkey);
|
|
printf("===================================\n");
|
|
|
|
return 0;
|
|
}
|
|
```
|
|
|
|
#### 3.2 Database Detection Logic ✅ COMPLETED
|
|
**File:** `src/main.c`
|
|
|
|
**Status:** ✅ FULLY IMPLEMENTED
|
|
```c
|
|
// Implemented functions: ✅
|
|
char** find_existing_nrdb_files(void);
|
|
char* extract_pubkey_from_filename(const char* filename);
|
|
int is_first_time_startup(void);
|
|
int first_time_startup_sequence(void);
|
|
int startup_existing_relay(const char* relay_pubkey);
|
|
```
|
|
|
|
### Phase 4: Legacy System Removal ✅ PARTIALLY COMPLETED
|
|
|
|
#### 4.1 Remove Command Line Arguments ✅ COMPLETED
|
|
**File:** `src/main.c`
|
|
|
|
**Status:** ✅ COMPLETED
|
|
- ✅ All argument parsing logic removed except --help and --version
|
|
- ✅ `--port`, `--config-dir`, `--config-file`, `--database-path` handling removed
|
|
- ✅ Environment variable override systems removed
|
|
- ✅ Clean help and version functions implemented
|
|
|
|
#### 4.2 Remove Configuration File System ✅ COMPLETED
|
|
**File:** `src/config.c`
|
|
|
|
**Status:** ✅ COMPLETED - New file created from scratch
|
|
- ✅ All legacy file-based configuration functions removed
|
|
- ✅ XDG configuration directory logic removed
|
|
- ✅ Pure event-based system implemented
|
|
|
|
#### 4.3 Remove Legacy Database Tables ⏳ PENDING
|
|
**File:** `src/sql_schema.h`
|
|
|
|
**Status:** ⏳ NEEDS COMPLETION
|
|
```sql
|
|
-- Still need to remove these tables:
|
|
DROP TABLE IF EXISTS config;
|
|
DROP TABLE IF EXISTS config_history;
|
|
DROP TABLE IF EXISTS config_file_cache;
|
|
DROP VIEW IF EXISTS active_config;
|
|
```
|
|
|
|
### Phase 5: Configuration Management
|
|
|
|
#### 5.1 Configuration Field Mapping
|
|
**File:** `src/config.c`
|
|
|
|
```c
|
|
// Map configuration tags to current system
|
|
static const config_field_handler_t config_handlers[] = {
|
|
{"auth_enabled", 0, apply_auth_enabled},
|
|
{"relay_port", 1, apply_relay_port}, // requires restart
|
|
{"max_connections", 0, apply_max_connections},
|
|
{"relay_description", 0, apply_relay_description},
|
|
{"relay_contact", 0, apply_relay_contact},
|
|
{"relay_pubkey", 1, apply_relay_pubkey}, // requires restart
|
|
{"relay_privkey", 1, apply_relay_privkey}, // requires restart
|
|
{"pow_min_difficulty", 0, apply_pow_difficulty},
|
|
{"nip40_expiration_enabled", 0, apply_expiration_enabled},
|
|
{"max_subscriptions_per_client", 0, apply_max_subscriptions},
|
|
{"max_event_tags", 0, apply_max_event_tags},
|
|
{"max_content_length", 0, apply_max_content_length},
|
|
{"default_limit", 0, apply_default_limit},
|
|
{"max_limit", 0, apply_max_limit},
|
|
// ... etc
|
|
};
|
|
```
|
|
|
|
#### 5.2 Startup Configuration Loading
|
|
**File:** `src/main.c`
|
|
|
|
```c
|
|
int startup_existing_relay(const char* relay_pubkey) {
|
|
// 1. Open database
|
|
if (init_database_with_pubkey(relay_pubkey) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
// 2. Load configuration event from database
|
|
cJSON* config_event = load_config_event_from_database(relay_pubkey);
|
|
if (!config_event) {
|
|
log_error("No configuration event found in database");
|
|
return -1;
|
|
}
|
|
|
|
// 3. Apply all configuration from event
|
|
if (apply_configuration_from_event(config_event) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
// 4. Continue with normal startup
|
|
return start_relay_services();
|
|
}
|
|
```
|
|
|
|
## Implementation Order - PROGRESS STATUS
|
|
|
|
### Step 1: Core Infrastructure ✅ COMPLETED
|
|
1. ✅ Implement database naming with relay pubkey
|
|
2. ✅ Add key generation functions using `nostr_core_lib`
|
|
3. ✅ Create configuration event storage/retrieval functions
|
|
4. ✅ Test basic event creation and storage
|
|
|
|
### Step 2: Event Processing Integration ✅ MOSTLY COMPLETED
|
|
1. ✅ Add kind 33334 event detection to event processing loop
|
|
2. ✅ Implement configuration event validation
|
|
3. ⚠️ Create configuration application handlers (basic access implemented, runtime handlers pending)
|
|
4. ⏳ Test real-time configuration updates (infrastructure ready)
|
|
|
|
### Step 3: First-Time Startup ✅ COMPLETED
|
|
1. ✅ Implement first-time startup detection
|
|
2. ✅ Add automatic key generation and database creation
|
|
3. ✅ Create default configuration event generation
|
|
4. ✅ Test complete first-time startup flow
|
|
|
|
### Step 4: Legacy Removal ⚠️ MOSTLY COMPLETED
|
|
1. ✅ Remove command line argument parsing
|
|
2. ✅ Remove configuration file system
|
|
3. ⏳ Remove legacy database tables (pending)
|
|
4. ✅ Update all references to use event-based config
|
|
|
|
### Step 5: Testing and Validation ⚠️ PARTIALLY COMPLETED
|
|
1. ✅ Test complete startup flow (first time and existing)
|
|
2. ⏳ Test configuration updates via events (infrastructure ready)
|
|
3. ⚠️ Test error handling and recovery (basic error handling implemented)
|
|
4. ⏳ Performance testing and optimization (pending)
|
|
|
|
## Migration Strategy
|
|
|
|
### For Existing Installations
|
|
Since the new system uses a completely different approach:
|
|
|
|
1. **No Automatic Migration**: The new system starts fresh
|
|
2. **Manual Migration**: Users can manually copy configuration values
|
|
3. **Documentation**: Provide clear migration instructions
|
|
4. **Coexistence**: Old and new systems use different database names
|
|
|
|
### Migration Steps for Users
|
|
1. Stop existing relay
|
|
2. Note current configuration values
|
|
3. Start new relay (generates keys and new database)
|
|
4. Create kind 33334 event with desired configuration using admin private key
|
|
5. Send event to relay to update configuration
|
|
|
|
## Testing Requirements
|
|
|
|
### Unit Tests
|
|
- Key generation functions
|
|
- Configuration event creation and validation
|
|
- Database naming logic
|
|
- Configuration application handlers
|
|
|
|
### Integration Tests
|
|
- Complete first-time startup flow
|
|
- Configuration update via events
|
|
- Error handling scenarios
|
|
- Database operations
|
|
|
|
### Performance Tests
|
|
- Startup time comparison
|
|
- Configuration update response time
|
|
- Memory usage analysis
|
|
|
|
## Security Considerations
|
|
|
|
1. **Admin Private Key**: Never stored, only printed once
|
|
2. **Event Validation**: All configuration events must be signed by admin
|
|
3. **Database Security**: Relay database contains relay private key
|
|
4. **Key Generation**: Use `nostr_core_lib` for cryptographically secure generation
|
|
|
|
## Files to Modify
|
|
|
|
### Major Changes
|
|
- `src/main.c` - Startup logic, event processing, argument removal
|
|
- `src/config.c` - Complete rewrite for event-based configuration
|
|
- `src/config.h` - Update function signatures and structures
|
|
- `src/sql_schema.h` - Remove config tables
|
|
|
|
### Minor Changes
|
|
- `Makefile` - Remove any config file generation
|
|
- `systemd/` - Update service files if needed
|
|
- Documentation updates
|
|
|
|
## Backwards Compatibility
|
|
|
|
**Breaking Changes:**
|
|
- Command line arguments removed (except --help, --version)
|
|
- Configuration files no longer used
|
|
- Database naming scheme changed
|
|
- Configuration table removed
|
|
|
|
**Migration Required:** This is a breaking change that requires manual migration for existing installations.
|
|
|
|
## Success Criteria - CURRENT STATUS
|
|
|
|
1. ✅ **Zero Command Line Arguments**: Relay starts with just `./c-relay`
|
|
2. ✅ **Automatic First-Time Setup**: Generates keys and database automatically
|
|
3. ⚠️ **Real-Time Configuration**: Infrastructure ready, handlers need completion
|
|
4. ✅ **Single Database File**: All configuration and data in one `.nrdb` file
|
|
5. ⚠️ **Admin Control**: Event processing implemented, signature validation ready
|
|
6. ⚠️ **Clean Codebase**: Most legacy code removed, database tables cleanup pending
|
|
|
|
## Risk Mitigation
|
|
|
|
1. **Backup Strategy**: Document manual backup procedures for relay database
|
|
2. **Key Loss Recovery**: Document recovery procedures if admin key is lost
|
|
3. **Testing Coverage**: Comprehensive test suite before deployment
|
|
4. **Rollback Plan**: Keep old version available during transition period
|
|
5. **Documentation**: Comprehensive user and developer documentation
|
|
|
|
This implementation plan provides a clear path from the current system to the new event-based configuration architecture while maintaining security and reliability. |