351 lines
10 KiB
Markdown
351 lines
10 KiB
Markdown
# C Nostr Relay - Event-Based Configuration System
|
|
|
|
A high-performance Nostr relay implemented in C with SQLite backend, featuring a revolutionary **zero-configuration** approach using event-based configuration management.
|
|
|
|
## 📜 Supported NIPs
|
|
|
|
<!--
|
|
NOTE FOR ASSISTANTS: When updating the NIPs checklist below, ONLY change [ ] to [x] to mark as complete.
|
|
Do NOT modify the formatting, add emojis, or change the text. Keep the simple format consistent.
|
|
-->
|
|
|
|
- [x] NIP-01: Basic protocol flow implementation
|
|
- [x] NIP-09: Event deletion
|
|
- [x] NIP-11: Relay information document
|
|
- [x] NIP-13: Proof of Work
|
|
- [x] NIP-15: End of Stored Events Notice
|
|
- [x] NIP-20: Command Results
|
|
- [x] NIP-33: Parameterized Replaceable Events
|
|
- [x] NIP-40: Expiration Timestamp
|
|
- [x] NIP-42: Authentication of clients to relays
|
|
- [ ] NIP-45: Counting results
|
|
- [ ] NIP-50: Keywords filter
|
|
- [ ] NIP-70: Protected Events
|
|
|
|
## 🔧 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. Admin commands use ephemeral kinds 23455 and 23456 with **optional NIP-44 encryption** for enhanced security.
|
|
|
|
### Authentication
|
|
|
|
All admin commands require signing with the admin private key displayed during first-time startup. **Save this key securely** - it cannot be recovered and is needed for all administrative operations.
|
|
|
|
### Security Options
|
|
|
|
**Standard Mode (Plaintext):** Commands sent in tags as normal
|
|
**Encrypted Mode (NIP-44):** Commands encrypted in content field, no tags used
|
|
|
|
### Kind 23455: Configuration Management (Ephemeral)
|
|
Update relay configuration parameters or query available settings.
|
|
|
|
**Configuration Update:**
|
|
```json
|
|
{
|
|
"kind": 23455,
|
|
"content": "<optional nip-44 encrypted tags>",
|
|
"tags": [
|
|
["config_key1", "config_value1"],
|
|
["config_key2", "config_value2"]
|
|
]
|
|
}
|
|
```
|
|
|
|
**Query Available Config Keys:**
|
|
```json
|
|
{
|
|
"kind": 23455,
|
|
"content": "<optional nip-44 encrypted tags>",
|
|
"tags": [
|
|
["config_query", "list_all_keys"]
|
|
]
|
|
}
|
|
```
|
|
|
|
**Get Current Configuration:**
|
|
```json
|
|
{
|
|
"kind": 23455,
|
|
"content": "<optional nip-44 encrypted tags>",
|
|
"tags": [
|
|
["config_query", "get_current_config"]
|
|
]
|
|
}
|
|
```
|
|
|
|
**Available Configuration Keys:**
|
|
|
|
**Basic Relay Settings:**
|
|
- `relay_description`: Relay description text
|
|
- `relay_contact`: Contact information
|
|
- `max_connections`: Maximum concurrent connections
|
|
- `max_subscriptions_per_client`: Max subscriptions per client
|
|
- `max_event_tags`: Maximum tags per event
|
|
- `max_content_length`: Maximum event content length
|
|
|
|
**Authentication & Access Control:**
|
|
- `auth_enabled`: Enable whitelist/blacklist auth rules (`true`/`false`)
|
|
- `nip42_auth_required`: Enable NIP-42 cryptographic authentication (`true`/`false`)
|
|
- `nip42_auth_required_kinds`: Event kinds requiring NIP-42 auth (comma-separated)
|
|
- `nip42_challenge_timeout`: NIP-42 challenge expiration seconds
|
|
|
|
**Proof of Work & Validation:**
|
|
- `pow_min_difficulty`: Minimum proof-of-work difficulty
|
|
- `nip40_expiration_enabled`: Enable event expiration (`true`/`false`)
|
|
|
|
### Kind 23456: Auth Rules & System Management (Ephemeral)
|
|
Manage whitelist/blacklist rules and system administration commands.
|
|
|
|
**Add Blacklist Rule:**
|
|
```json
|
|
{
|
|
"kind": 23456,
|
|
"content": "<optional nip-44 encrypted tags>",
|
|
"tags": [
|
|
["blacklist", "pubkey", "deadbeef1234abcd..."]
|
|
]
|
|
}
|
|
```
|
|
|
|
**Add Whitelist Rule:**
|
|
```json
|
|
{
|
|
"kind": 23456,
|
|
"content": "<optional nip-44 encrypted tags>",
|
|
"tags": [
|
|
["whitelist", "pubkey", "cafebabe5678efgh..."]
|
|
]
|
|
}
|
|
```
|
|
|
|
**Remove Rule:**
|
|
```json
|
|
{
|
|
"kind": 23456,
|
|
"content": "<optional nip-44 encrypted tags>",
|
|
"tags": [
|
|
["blacklist", "pubkey", "deadbeef1234abcd..."]
|
|
]
|
|
}
|
|
```
|
|
|
|
**Query Auth Rules:**
|
|
```json
|
|
{
|
|
"kind": 23456,
|
|
"content": "<optional nip-44 encrypted tags>",
|
|
"tags": [
|
|
["auth_query", "all"]
|
|
]
|
|
}
|
|
```
|
|
|
|
**Query Specific Rule Type:**
|
|
```json
|
|
{
|
|
"kind": 23456,
|
|
"content": "<optional nip-44 encrypted tags>",
|
|
"tags": [
|
|
["auth_query", "whitelist"]
|
|
]
|
|
}
|
|
```
|
|
|
|
**Query Specific Pattern:**
|
|
```json
|
|
{
|
|
"kind": 23456,
|
|
"content": "<optional nip-44 encrypted tags>",
|
|
"tags": [
|
|
["auth_query", "pattern", "deadbeef1234abcd..."]
|
|
]
|
|
}
|
|
```
|
|
|
|
**Clear All Auth Rules:**
|
|
```json
|
|
{
|
|
"kind": 23456,
|
|
"content": "<optional nip-44 encrypted tags>",
|
|
"tags": [
|
|
["system_command", "clear_all_auth_rules"]
|
|
]
|
|
}
|
|
```
|
|
|
|
### Response Format
|
|
All admin commands return JSON responses via WebSocket:
|
|
|
|
**Success Response:**
|
|
```json
|
|
["OK", "event_id", true, "Operation completed successfully"]
|
|
```
|
|
|
|
**Error Response:**
|
|
```json
|
|
["OK", "event_id", false, "Error: invalid configuration value"]
|
|
```
|
|
|
|
### Command Examples
|
|
|
|
**Using `nak` CLI tool:**
|
|
|
|
```bash
|
|
# Set environment variables
|
|
ADMIN_PRIVKEY="your_admin_private_key_here"
|
|
RELAY_PUBKEY="your_relay_public_key_here"
|
|
RELAY_URL="ws://localhost:8888"
|
|
|
|
# List all available configuration keys
|
|
nak event -k 23455 --content "Discovery query" \
|
|
-t "config_query=list_all_keys" \
|
|
--sec $ADMIN_PRIVKEY | nak event $RELAY_URL
|
|
|
|
# Enable whitelist/blacklist auth rules
|
|
nak event -k 23455 --content "Enable auth rules" \
|
|
-t "auth_enabled=true" \
|
|
--sec $ADMIN_PRIVKEY | nak event $RELAY_URL
|
|
|
|
# Add user to blacklist
|
|
nak event -k 23456 --content "Block spam user" \
|
|
-t "blacklist=pubkey;$SPAM_USER_PUBKEY" \
|
|
--sec $ADMIN_PRIVKEY | nak event $RELAY_URL
|
|
|
|
# Add user to whitelist
|
|
nak event -k 23456 --content "Allow trusted user" \
|
|
-t "whitelist=pubkey;$TRUSTED_USER_PUBKEY" \
|
|
--sec $ADMIN_PRIVKEY | nak event $RELAY_URL
|
|
|
|
# Query all current auth rules
|
|
nak event -k 23456 --content "Get all auth rules" \
|
|
-t "auth_query=all" \
|
|
--sec $ADMIN_PRIVKEY | nak event $RELAY_URL
|
|
|
|
# Query only whitelist rules
|
|
nak event -k 23456 --content "Get whitelist rules" \
|
|
-t "auth_query=whitelist" \
|
|
--sec $ADMIN_PRIVKEY | nak event $RELAY_URL
|
|
|
|
# Query only blacklist rules
|
|
nak event -k 23456 --content "Get blacklist rules" \
|
|
-t "auth_query=blacklist" \
|
|
--sec $ADMIN_PRIVKEY | nak event $RELAY_URL
|
|
|
|
# Check if specific pattern exists
|
|
nak event -k 23456 --content "Check user status" \
|
|
-t "auth_query=pattern;$CHECK_USER_PUBKEY" \
|
|
--sec $ADMIN_PRIVKEY | nak event $RELAY_URL
|
|
|
|
# Clear all auth rules (for testing)
|
|
nak event -k 23456 --content "Clear all rules" \
|
|
-t "system_command=clear_all_auth_rules" \
|
|
--sec $ADMIN_PRIVKEY | nak event $RELAY_URL
|
|
|
|
# Update relay description
|
|
nak event -k 23455 --content "Update description" \
|
|
-t "relay_description=My awesome relay" \
|
|
--sec $ADMIN_PRIVKEY | nak event $RELAY_URL
|
|
|
|
# Set connection limits
|
|
nak event -k 23455 --content "Update limits" \
|
|
-t "max_connections=500" \
|
|
-t "max_subscriptions_per_client=10" \
|
|
--sec $ADMIN_PRIVKEY | nak event $RELAY_URL
|
|
```
|
|
|
|
**For encrypted commands (NIP-44), use empty tags and encrypted content:**
|
|
```bash
|
|
# Enable auth rules (encrypted)
|
|
ENCRYPTED_TAGS=$(echo '[["auth_enabled","true"]]' | nip44_encrypt_with_relay_pubkey)
|
|
nak event -k 23455 --content "{\"encrypted_tags\":\"$ENCRYPTED_TAGS\"}" \
|
|
--sec $ADMIN_PRIVKEY | nak event $RELAY_URL
|
|
|
|
# Add user to blacklist (encrypted)
|
|
ENCRYPTED_TAGS=$(echo '[["blacklist","pubkey","'$SPAM_USER_PUBKEY'"]]' | nip44_encrypt_with_relay_pubkey)
|
|
nak event -k 23456 --content "{\"encrypted_tags\":\"$ENCRYPTED_TAGS\"}" \
|
|
--sec $ADMIN_PRIVKEY | nak event $RELAY_URL
|
|
```
|
|
|
|
### Authentication Systems
|
|
|
|
C-Relay supports **two independent authentication systems**:
|
|
|
|
#### 1. Auth Rules (Whitelist/Blacklist)
|
|
- **Config Key**: `auth_enabled=true`
|
|
- **Purpose**: Block or allow specific pubkeys from publishing events
|
|
- **Method**: Database-driven rules enforcement
|
|
- **Use Case**: Spam prevention, content moderation
|
|
|
|
#### 2. NIP-42 Cryptographic Authentication
|
|
- **Config Key**: `nip42_auth_required=true`
|
|
- **Purpose**: Require cryptographic proof of pubkey ownership
|
|
- **Method**: Challenge-response authentication protocol
|
|
- **Use Case**: Verified identity, premium features
|
|
|
|
**Important**: These systems can be used independently or together:
|
|
- `auth_enabled=true` + `nip42_auth_required=false`: Only whitelist/blacklist rules
|
|
- `auth_enabled=false` + `nip42_auth_required=true`: Only NIP-42 auth challenges
|
|
- Both `true`: Users must pass NIP-42 auth AND not be blacklisted
|
|
|
|
### Security Considerations
|
|
|
|
- **Private Key Protection**: Admin private key grants full relay control
|
|
- **Network Access**: Admin commands should only be sent over secure connections
|
|
- **Backup**: Keep secure backups of admin private key
|
|
- **Rotation**: Consider implementing admin key rotation for production deployments
|
|
|
|
### Troubleshooting
|
|
|
|
**Common Issues:**
|
|
- `auth-required: not authorized admin`: Verify you're using the correct admin private key
|
|
- `invalid: missing or invalid kind`: Ensure event kind is 23455 or 23456
|
|
- `error: failed to process configuration event`: Check configuration key/value validity
|
|
- `no valid auth rules found`: Verify tag format uses semicolon syntax for multi-element tags
|
|
|
|
**Debug Commands:**
|
|
```bash
|
|
# Check if relay is accepting connections
|
|
echo '["REQ","test",{}]' | websocat ws://localhost:8888
|
|
|
|
# Test admin authentication
|
|
nak event -k 23455 --content "Test auth" \
|
|
-t "test_config=true" \
|
|
--sec $ADMIN_PRIVKEY | nak event ws://localhost:8888
|
|
|
|
# Discover available configuration keys
|
|
nak event -k 23455 --content "Discovery query" \
|
|
-t "config_query=list_all_keys" \
|
|
--sec $ADMIN_PRIVKEY | nak event ws://localhost:8888
|
|
|
|
# Query current auth rules
|
|
nak event -k 23456 --content "Get auth rules" \
|
|
-t "auth_query=all" \
|
|
--sec $ADMIN_PRIVKEY | nak event ws://localhost:8888
|
|
```
|
|
|
|
### Configuration Discovery
|
|
|
|
Before making changes, admins can query the relay to discover all available configuration options:
|
|
|
|
```bash
|
|
# Get list of all editable configuration keys with descriptions
|
|
nak event -k 23455 --content '{"query":"list_config_keys","description":"Discovery"}' \
|
|
-t "config_query=list_all_keys" \
|
|
--sec $ADMIN_PRIVKEY | nak event $RELAY_URL
|
|
|
|
# Get current values of all configuration parameters
|
|
nak event -k 23455 --content '{"query":"get_config","description":"Current state"}' \
|
|
-t "config_query=get_current_config" \
|
|
--sec $ADMIN_PRIVKEY | nak event $RELAY_URL
|
|
```
|
|
|
|
**Expected Response Format:**
|
|
```json
|
|
["EVENT", "subscription_id", {
|
|
"kind": 23455,
|
|
"content": "{\"config_keys\": [\"auth_enabled\", \"max_connections\", ...], \"descriptions\": {...}}",
|
|
"tags": [["response_type", "config_keys_list"]]
|
|
}]
|
|
```
|
|
|
|
|