Files
ginxsom/AUTH_API.md
Your Name 67154164f1 tests
2025-09-07 10:59:43 -04:00

492 lines
23 KiB
Markdown

# Authentication API Documentation
## Overview
The nostr_core_lib unified request validation system provides a comprehensive authentication and authorization framework for Nostr-based applications. It combines Nostr event validation with flexible rule-based authentication in a single API call.
## Authentication Flow and Order of Operations
### Authentication Flow Diagram
```
┌─────────────────────┐
│ Request Received │
└──────────┬──────────┘
┌─────────────┐ ╔═══════════════════╗
│ Input Valid?├─No─►║ REJECT: Invalid ║
└──────┬──────┘ ║ Input (~1μs) ║
│Yes ╚═══════════════════╝
┌─────────────┐ ╔═══════════════════╗
│System Init? ├─No─►║ REJECT: Not ║
└──────┬──────┘ ║ Initialized ║
│Yes ╚═══════════════════╝
┌─────────────┐
│Auth Header? │
└──────┬──────┘
│Yes
▼ ┌─────────────────────┐
┌─────────────┐ No │ │
│Parse Header ├────────────┤ Skip Nostr │
└──────┬──────┘ │ Validation │
│ │ │
▼ └──────────┬──────────┘
┌─────────────┐ ╔═══════════════════╗ │
│Valid Base64?├─No─►║ REJECT: Malformed ║ │
└──────┬──────┘ ║ Header (~10μs) ║ │
│Yes ╚═══════════════════╝ │
▼ │
┌─────────────┐ ╔═══════════════════╗ │
│Valid JSON? ├─No─►║ REJECT: Invalid ║ │
└──────┬──────┘ ║ JSON (~50μs) ║ │
│Yes ╚═══════════════════╝ │
▼ │
┌─────────────┐ ╔═══════════════════╗ │
│Valid Struct?├─No─►║ REJECT: Invalid ║ │
└──────┬──────┘ ║ Structure (~100μs)║ │
│Yes ╚═══════════════════╝ │
▼ │
┌─────────────────┐ ╔═══════════════════╗ │
│ ECDSA Signature │No ║ REJECT: Invalid ║ │
│ Verify (~2ms) ├──►║ Signature (~2ms) ║ │
└─────────┬───────┘ ╚═══════════════════╝ │
│Yes │
▼ │
┌─────────────────┐ ╔═══════════════════╗ │
│Operation Match? │No ║ REJECT: Unauth. ║ |
└─────────┬───────┘ ║ Operation (~200μs)║ │
│Yes ╚═══════════════════╝ │
▼ │
┌─────────────────┐ ╔═══════════════════╗ │
│Event Expired? │Yes║ REJECT: Expired ║ │
└─────────┬───────┘ ║ Event (~50μs) ║ │
│No ╚═══════════════════╝ │
▼ │
┌─────────────────┐ │
│Extract Pubkey │ │
└─────────┬───────┘ │
│ │
▼◄───────────────────────────────────────┘
┌─────────────────┐ ╔═══════════════════╗
│Auth Rules │ No ║ ALLOW: Rules ║
│Enabled? ├────►║ Disabled ║
└─────────┬───────┘ ╚═══════════════════╝
│Yes
┌─────────────────┐
│Generate Cache │
│Key (SHA-256) │
└─────────┬───────┘
┌─────────────────┐ ╔═══════════════════╗
│Cache Hit? │ Yes ║ RETURN: Cached ║
│(~100μs lookup) ├────►║ Decision (~100μs) ║
└─────────┬───────┘ ╚═══════════════════╝
│No
╔═══════════════════════════════════════╗
║ RULE EVALUATION ENGINE ║
║ (Priority Order) ║
╚═══════════════════════════════════════╝
┌─────────────────┐ ╔═══════════════════╗
│1. Pubkey │ Yes ║ DENY: Pubkey ║
│ Blacklisted? ├────►║ Blocked ║
└─────────┬───────┘ ╚═══════════════════╝
│No
┌─────────────────┐ ╔═══════════════════╗
│2. Hash │ Yes ║ DENY: Hash ║
│ Blacklisted? ├────►║ Blocked ║
└─────────┬───────┘ ╚═══════════════════╝
│No
┌─────────────────┐ ╔═══════════════════╗
│3. MIME Type │ Yes ║ DENY: MIME ║
│ Blacklisted? ├────►║ Blocked ║
└─────────┬───────┘ ╚═══════════════════╝
│No
┌─────────────────┐ ╔═══════════════════╗
│4. Size Limit │ Yes ║ DENY: File ║
│ Exceeded? ├────►║ Too Large ║
└─────────┬───────┘ ╚═══════════════════╝
│No
┌─────────────────┐ ╔═══════════════════╗
│5. Pubkey │ Yes ║ ALLOW: Pubkey ║
│ Whitelisted? ├────►║ Whitelisted ║
└─────────┬───────┘ ╚═══════════════════╝
│No
┌─────────────────┐ ╔═══════════════════╗
│6. MIME Type │ Yes ║ ALLOW: MIME ║
│ Whitelisted? ├────►║ Whitelisted ║
└─────────┬───────┘ ╚═══════════════════╝
│No
┌─────────────────┐ ╔═══════════════════╗
│Whitelist Rules │ Yes ║ DENY: Not in ║
│Exist? ├────►║ Whitelist ║
└─────────┬───────┘ ╚═══════════════════╝
│No
╔═══════════════════╗
║ ALLOW: Default ║
║ Allow Policy ║
╚═══════════════════╝
┌─────────────────┐
│ Cache Decision │
│ (5min TTL) │
└─────────┬───────┘
┌─────────────────┐
│ Return Result │
│ to Application │
└─────────────────┘
```
### Performance Timeline (ASCII)
```
Fast Path (Cache Hit) - Total: ~101μs
┌─────┬─────────────────────────────────────────────────────────────────┬──────┐
│ 1μs │ 100μs Cache Lookup │ 1μs │
└─────┴─────────────────────────────────────────────────────────────────┴──────┘
Input │ │ Return
Valid │ SQLite SELECT │ Result
Typical Path (Valid Request) - Total: ~2.4ms
┌──┬───┬────┬─────────────────────────┬────────┬────┬──┐
│1μ│50μ│100μ│ 2000μs │ 200μs │100μ│1μ│
└──┴───┴────┴─────────────────────────┴────────┴────┴──┘
│ │ │ │ │ │ │
│ │ │ │ ECDSA Signature │ Rule │Cache│Return
│ │ │ │ Verification │ Eval │Store│Result
│ │ │ │ (Most Expensive) │ │ │
│ │ │
│ │ JSON Parse
│ Header Parse
Input Validation
Worst Case (Full Validation) - Total: ~2.7ms
┌──┬───┬────┬─────────────────────────┬─────────┬────┬──┐
│1μ│50μ│100μ│ 2000μs │ 500μs │100μ│1μ│
└──┴───┴────┴─────────────────────────┴─────────┴────┴──┘
All 6 Rule Checks
(Multiple DB Queries)
```
### Request Processing Flow (DDoS-Optimized)
The authentication system is designed with **performance and DDoS protection** as primary concerns. Here's the exact order of operations:
#### Phase 1: Input Validation (Immediate Rejection)
1. **Null Pointer Checks** - Reject malformed requests instantly (lines 122-128)
2. **Initialization Check** - Verify system is properly initialized
3. **Basic Structure Validation** - Ensure required fields are present
#### Phase 2: Nostr Event Validation (CPU Intensive)
4. **Authorization Header Parsing** (lines 139-148)
- Extract base64-encoded Nostr event from `Authorization: Nostr <base64>` header
- Decode base64 to JSON (memory allocation + decoding)
- **Early exit**: Invalid base64 or malformed header rejected immediately
5. **JSON Parsing** (lines 150-156)
- Parse Nostr event JSON using cJSON
- **Early exit**: Invalid JSON rejected before signature verification
6. **Nostr Event Structure Validation** (lines 159-166)
- Validate event has required fields (kind, pubkey, sig, etc.)
- Check event kind is 24242 for Blossom operations
- **Early exit**: Invalid structure rejected before expensive crypto operations
7. **Cryptographic Signature Verification** (lines 159-166)
- **Most CPU-intensive operation** - ECDSA signature verification
- Validates event authenticity using secp256k1
- **Early exit**: Invalid signatures rejected before database queries
8. **Operation-Specific Validation** (lines 169-178)
- Verify event authorizes the requested operation (upload/delete/list)
- Check required tags (t=operation, x=hash, expiration)
- Validate timestamp and expiration
- **Early exit**: Expired or mismatched events rejected
9. **Public Key Extraction** (lines 181-184)
- Extract validated public key from event for rule evaluation
#### Phase 3: Authentication Rules (Database Queries)
10. **Rules System Check** (line 191)
- Quick config check if authentication rules are enabled
- **Early exit**: If disabled, allow request immediately
11. **Cache Lookup** (lines 1051-1054)
- Generate SHA-256 cache key from request parameters
- Check SQLite cache for previous decision
- **Early exit**: Cache hit returns cached decision (5-minute TTL)
12. **Rule Evaluation** (Priority Order - lines 1061-1094):
- **a. Pubkey Blacklist** (highest priority) - Immediate denial if matched
- **b. Hash Blacklist** - Block specific content hashes
- **c. MIME Type Blacklist** - Block dangerous file types
- **d. File Size Limits** - Enforce upload size restrictions
- **e. Pubkey Whitelist** - Allow specific users (only if not denied above)
- **f. MIME Type Whitelist** - Allow specific file types
13. **Whitelist Default Denial** (lines 1097-1121)
- If whitelist rules exist but none matched, deny request
- Prevents whitelist bypass attacks
14. **Cache Storage** (line 1124)
- Store decision in cache for future requests (5-minute TTL)
### DDoS Protection Features
#### **Fail-Fast Design**
- **Input validation** happens before any expensive operations
- **Authorization header parsing** fails fast on malformed data
- **JSON parsing** rejects invalid data before signature verification
- **Structure validation** happens before cryptographic operations
#### **Expensive Operations Last**
- **Signature verification** only after structure validation
- **Database queries** only after successful Nostr validation
- **Cache prioritized** over database queries
#### **Caching Strategy**
- **SHA-256 cache keys** prevent cache pollution attacks
- **5-minute TTL** balances performance with rule changes
- **LRU eviction** prevents memory exhaustion
- **Per-request caching** includes all parameters (pubkey, operation, hash, MIME, size)
#### **Resource Limits**
- **JSON parsing** limited to 4KB buffer size
- **Cache entries** limited to prevent memory exhaustion
- **Database connection pooling** (single connection with proper cleanup)
- **String length limits** on all inputs
#### **Attack Mitigation**
- **Base64 bombs** - Limited decode buffer size (4KB)
- **JSON bombs** - cJSON library handles malformed JSON safely
- **Cache poisoning** - Cryptographic cache keys prevent collisions
- **Rule bypass** - Whitelist default denial prevents unauthorized access
- **Replay attacks** - Timestamp and expiration validation
- **Hash collision attacks** - Full SHA-256 verification
### Performance Characteristics
#### **Best Case** (Cached Decision):
1. Input validation: ~1μs
2. Cache lookup: ~100μs (SQLite SELECT)
3. **Total: ~101μs**
#### **Worst Case** (Full Validation + Rule Evaluation):
1. Input validation: ~1μs
2. Base64 decoding: ~50μs
3. JSON parsing: ~100μs
4. Signature verification: ~2000μs (ECDSA)
5. Database queries: ~500μs (6 rule checks)
6. Cache storage: ~100μs
7. **Total: ~2751μs (~2.7ms)**
#### **Typical Case** (Valid Request, Rules Enabled):
1. Full validation: ~2200μs
2. Cache miss, 2-3 rule checks: ~200μs
3. **Total: ~2400μs (~2.4ms)**
### Security Order Rationale
The rule evaluation order is specifically designed for security:
1. **Blacklists First** - Immediate denial of known bad actors
2. **Resource Limits** - Prevent resource exhaustion attacks
3. **Whitelists Last** - Only allow after passing all security checks
4. **Default Deny** - If whitelists exist but don't match, deny
This ensures that even if an attacker bypasses one layer, subsequent layers will catch the attack.
## Core API
### Primary Function
```c
int nostr_validate_request(nostr_request_t* request, nostr_request_result_t* result);
```
This single function handles:
- Nostr event signature validation
- Event structure validation (required fields, timestamps)
- Authentication rule evaluation
- Public key extraction and validation
### Request Structure
```c
typedef struct {
const char* event_json; // Raw Nostr event JSON
const char* app_id; // Application identifier ("ginxsom", "c-relay")
const char* operation; // Operation type ("upload", "delete", "list")
const char* content_hash; // SHA-256 hash for file operations (optional)
const char* mime_type; // MIME type for upload operations (optional)
size_t content_size; // File size for upload operations (0 if N/A)
} nostr_request_t;
```
### Result Structure
```c
typedef struct {
int is_valid; // 1 if request is valid, 0 otherwise
int error_code; // Specific error code (see Error Codes)
char error_message[512]; // Human-readable error description
char pubkey[65]; // Extracted public key (hex, null-terminated)
time_t timestamp; // Event timestamp
char event_id[65]; // Event ID (hex, null-terminated)
} nostr_request_result_t;
```
## Authentication Rules System
The system supports priority-based authentication rules that are evaluated in order:
### Rule Types
1. **NOSTR_AUTH_RULE_PUBKEY_WHITELIST** - Allow specific public keys
2. **NOSTR_AUTH_RULE_PUBKEY_BLACKLIST** - Block specific public keys
3. **NOSTR_AUTH_RULE_HASH_BLACKLIST** - Block specific content hashes
4. **NOSTR_AUTH_RULE_MIME_RESTRICTION** - Restrict allowed MIME types
5. **NOSTR_AUTH_RULE_SIZE_LIMIT** - Enforce maximum file sizes
### Rule Evaluation
- Rules are processed by priority (lower numbers = higher priority)
- First matching rule determines the outcome
- ALLOW rules permit the request
- DENY rules reject the request
- If no rules match, the default action is ALLOW
### Rule Caching
The system includes an intelligent caching mechanism:
- LRU (Least Recently Used) eviction policy
- Configurable cache size (default: 1000 entries)
- Cache keys based on pubkey + operation + content hash
- Automatic cache invalidation when rules change
## Database Backend
### Pluggable Architecture
The system uses a pluggable database backend interface:
```c
typedef struct {
int (*init)(const char* connection_string, void** context);
int (*get_rules)(void* context, const char* app_id,
nostr_auth_rule_t** rules, int* count);
int (*cleanup)(void* context);
} nostr_db_backend_t;
```
### SQLite Implementation
Default implementation uses SQLite with the following schema:
```sql
-- Authentication rules table (per application)
CREATE TABLE auth_rules_[APP_ID] (
id INTEGER PRIMARY KEY AUTOINCREMENT,
priority INTEGER NOT NULL,
rule_type INTEGER NOT NULL,
action INTEGER NOT NULL,
pattern TEXT,
value_int INTEGER,
created_at INTEGER DEFAULT (strftime('%s', 'now')),
updated_at INTEGER DEFAULT (strftime('%s', 'now'))
);
```
## Error Codes
The system uses specific error codes for different failure scenarios:
- **-50**: `NOSTR_AUTH_ERROR_INVALID_EVENT` - Malformed Nostr event
- **-51**: `NOSTR_AUTH_ERROR_INVALID_SIGNATURE` - Invalid event signature
- **-52**: `NOSTR_AUTH_ERROR_PUBKEY_BLOCKED` - Public key is blacklisted
- **-53**: `NOSTR_AUTH_ERROR_HASH_BLOCKED` - Content hash is blacklisted
- **-54**: `NOSTR_AUTH_ERROR_MIME_RESTRICTED` - MIME type not allowed
- **-55**: `NOSTR_AUTH_ERROR_SIZE_EXCEEDED` - File size limit exceeded
## Usage Examples
### Basic Validation
```c
#include "nostr_core/request_validator.h"
// Initialize the system (once per application)
int result = nostr_request_validator_init("db/myapp.db", "myapp");
if (result != 0) {
fprintf(stderr, "Failed to initialize validator: %d\n", result);
return -1;
}
// Validate a request
nostr_request_t request = {
.event_json = "{\"kind\":24242,\"pubkey\":\"abc123...\",\"sig\":\"def456...\"}",
.app_id = "myapp",
.operation = "upload",
.content_hash = "sha256hash...",
.mime_type = "text/plain",
.content_size = 1024
};
nostr_request_result_t result;
int status = nostr_validate_request(&request, &result);
if (result.is_valid) {
printf("Request authorized for pubkey: %s\n", result.pubkey);
} else {
printf("Request denied: %s (code: %d)\n", result.error_message, result.error_code);
}
```
### Ginxsom Integration
The ginxsom application has been updated to use this system:
```c
// Replace old authenticate_request_with_rules() calls with:
nostr_request_t auth_request = {
.event_json = event_json,
.app_id = "ginxsom",
.operation = "upload", // or "list", "delete"
.content_hash = calculated_hash,
.mime_type = detected_mime_type,
.content_size = file_size
};
nostr_request_result_t auth_result;
int auth_status = nostr_validate_request(&auth_request, &auth_result);
if (!auth_result.is_valid) {
printf("Status: 403\r\n");
printf("Content-Type: application/json\r\n\r\n");
printf("{\"error\":\"Authentication failed\",\"message\":\"%s\"}\n",
auth_result.error_message);
return;
}
// Use auth_result.pubkey for the authenticated public key
```