# 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 ╚═══════════════════╝ │ ▼ │ ┌─────────────┐ ╔═══════════════════╗ │ │Event Kind? │ ║ ║ │ └──────┬──────┘ ║ DUAL AUTH MODES ║ │ │ ╚═══════════════════╝ │ ▼ │ ┌─────────────────────────────────────────────────────┐ │ │ ▼ ▼ ▼ ▼ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ Kind │ │ Kind │ │ Other │ │ Invalid │ │ 22242 │ │ 24242 │ │ Kinds │ │ Kind │ │ (NIP-42) │ │(Blossom) │ │ (Skip) │ │(Reject) │ └─────┬────┘ └─────┬────┘ └─────┬────┘ └─────┬────┘ │ │ │ │ ▼ │ ▼ ▼ ┌──────────┐ │ ┌──────────┐ ╔═══════════════════╗ │ NIP-42 │ │ │ Skip │ ║ REJECT: Invalid ║ │Challenge │ │ │ Nostr │ ║ Event Kind ║ │Validate │ │ │Validate │ ╚═══════════════════╝ │(~500μs) │ │ └─────┬────┘ │ └─────┬────┘ │ │ │ │ │ ▼ │ │ │ ┌──────────┐ │ │ │ │ Extract │ │ │ │ │ Context │ │ │ │ └─────┬────┘ │ │ │ │ │ ▼ ▼ ▼ ▼ ┌────────────────────────────────────────────────────────────┐ │ ECDSA SIGNATURE VERIFICATION │ │ (~2ms) │ └───────────────────────────┬────────────────────────────────┘ │Yes ▼ │ ┌─────────────────┐ ╔═══════════════════╗ │Operation Match? │No ║ REJECT: Unauth. ║ │(Kind 24242 only)├──►║ Operation (~200μs)║ └─────────┬───────┘ ╚═══════════════════╝ │Yes/Skip(Kind 22242) ▼ │ ┌─────────────────┐ ╔═══════════════════╗ │ │Event Expired? │Yes║ REJECT: Expired ║ │ └─────────┬───────┘ ║ Event (~50μs) ║ │ │No ╚═══════════════════╝ │ ▼ │ ┌─────────────────┐ │ │Extract Pubkey │ │ │& Auth Context │ │ └─────────┬───────┘ │ │ │ ▼◄───────────────────────────────────────┘ ┌─────────────────┐ ╔═══════════════════╗ │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 │ └─────────────────┘ ``` ### Authentication Flow (Mermaid) ```mermaid flowchart TD A[Request Received] --> B{Input Valid?} B -->|No| R1[REJECT: Invalid Input ~1μs] B -->|Yes| C{System Init?} C -->|No| R2[REJECT: Not Initialized] C -->|Yes| D{Auth Header?} D -->|No| SKIP[Skip Nostr Validation] D -->|Yes| E{Valid Base64?} E -->|No| R3[REJECT: Malformed Header ~10μs] E -->|Yes| F{Valid JSON?} F -->|No| R4[REJECT: Invalid JSON ~50μs] F -->|Yes| G{Valid Struct?} G -->|No| R5[REJECT: Invalid Structure ~100μs] G -->|Yes| H{Event Kind?} %% Event Kind Branching H --> I[Kind 22242
NIP-42] H --> J[Kind 24242
Blossom] H --> K[Other Kinds
Skip] H --> L[Invalid Kind] L --> R6[REJECT: Invalid Event Kind] %% NIP-42 Path I --> M[NIP-42 Challenge
Validation ~500μs] M --> N[ECDSA Signature
Verification ~2ms] %% Blossom Path J --> N %% Skip Path K --> SKIP SKIP --> O[Extract Context] O --> N %% Signature Verification N -->|No| R7[REJECT: Invalid Signature ~2ms] N -->|Yes| P{Operation Match?
Kind 24242 only} P -->|No| R8[REJECT: Unauthorized Operation ~200μs] P -->|Yes/Skip 22242| Q{Event Expired?} Q -->|Yes| R9[REJECT: Expired Event ~50μs] Q -->|No| S[Extract Pubkey & Auth Context] %% Rules Engine S --> T{Auth Rules Enabled?} T -->|No| ALLOW1[ALLOW: Rules Disabled] T -->|Yes| U[Generate Cache Key SHA-256] U --> V{Cache Hit?} V -->|Yes| CACHED[RETURN: Cached Decision ~100μs] V -->|No| W[RULE EVALUATION ENGINE
Priority Order] %% Rule Checks W --> X1{1. Pubkey Blacklisted?} X1 -->|Yes| DENY1[DENY: Pubkey Blocked] X1 -->|No| X2{2. Hash Blacklisted?} X2 -->|Yes| DENY2[DENY: Hash Blocked] X2 -->|No| X3{3. MIME Blacklisted?} X3 -->|Yes| DENY3[DENY: MIME Blocked] X3 -->|No| X4{4. Size Limit Exceeded?} X4 -->|Yes| DENY4[DENY: File Too Large] X4 -->|No| X5{5. Pubkey Whitelisted?} X5 -->|Yes| ALLOW2[ALLOW: Pubkey Whitelisted] X5 -->|No| X6{6. MIME Whitelisted?} X6 -->|Yes| ALLOW3[ALLOW: MIME Whitelisted] X6 -->|No| X7{Whitelist Rules Exist?} X7 -->|Yes| DENY5[DENY: Not in Whitelist] X7 -->|No| ALLOW4[ALLOW: Default Policy] %% Final Steps ALLOW2 --> CACHE[Cache Decision 5min TTL] ALLOW3 --> CACHE ALLOW4 --> CACHE DENY1 --> CACHE DENY2 --> CACHE DENY3 --> CACHE DENY4 --> CACHE DENY5 --> CACHE CACHE --> RESULT[Return Result to Application] %% Styling classDef rejectBox fill:#ff4444,stroke:#ffffff,color:#ffffff classDef allowBox fill:#44ff44,stroke:#ffffff,color:#000000 classDef processBox fill:#4444ff,stroke:#ffffff,color:#ffffff classDef decisionBox fill:#ffff44,stroke:#000000,color:#000000 class R1,R2,R3,R4,R5,R6,R7,R8,R9,DENY1,DENY2,DENY3,DENY4,DENY5 rejectBox class ALLOW1,ALLOW2,ALLOW3,ALLOW4,CACHED allowBox class A,M,N,S,U,W,CACHE,RESULT,SKIP,O processBox class B,C,D,E,F,G,H,P,Q,T,V,X1,X2,X3,X4,X5,X6,X7 decisionBox ``` ### 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) ``` ### Dual Authentication Architecture The system supports **two authentication modes** that can work independently or together: #### **NIP-42 Authentication (Kind 22242)** - **Purpose**: Client identity authentication ("who you are") - **Use Case**: Relay client authentication, WebSocket connections - **Event Structure**: Contains `relay` URL and `challenge` tags - **Flow**: Challenge/response pattern with relay-generated challenges - **Validation**: Verifies client identity against relay URL and challenge - **Database Storage**: Client sessions and challenge tracking #### **Blossom Protocol Authentication (Kind 24242)** - **Purpose**: Operation authorization ("what you can do") - **Use Case**: File upload/delete/list operations - **Event Structure**: Contains operation tag `t=upload|delete|list` and content hash `x=hash` - **Flow**: Direct operation authorization with expiration - **Validation**: Verifies operation permissions and content integrity - **Database Storage**: Operation-specific authentication rules #### **Integration Strategy** ``` ┌─────────────────┐ ┌─────────────────┐ │ NIP-42 Auth │ │ Blossom Auth │ │ (Kind 22242) │ │ (Kind 24242) │ │ │ │ │ │ Client Identity │ │ Operation Perms │ │ Challenge/Resp │ │ File Operations │ └─────────┬───────┘ └─────────┬───────┘ │ │ └──────┬─────────┬─────┘ │ │ ▼ ▼ ┌─────────────────┐ │ Unified Rules │ │ Engine │ │ │ │ • Pubkey Rules │ │ • Hash Rules │ │ • MIME Rules │ │ • Size Limits │ └─────────────────┘ ``` #### **Event Kind Processing** - **Kind 22242** (NIP-42): Validates against stored challenge + relay URL - **Kind 24242** (Blossom): Validates operation tags + content integrity - **Other Kinds**: Skip Nostr validation, proceed to rule evaluation - **Invalid Kind**: Reject immediately #### **Dual Mode Benefits** - **Backwards Compatibility**: Existing Blossom clients continue working - **Enhanced Security**: NIP-42 provides cryptographic client identity - **Flexible Deployment**: Relays can require either or both methods - **Performance**: Separate validation paths optimize for each use case ### 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 ` 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.) - **Early exit**: Invalid structure rejected before expensive crypto operations 7. **Event Kind Routing** (NEW - Dual Authentication) - **Kind 22242** (NIP-42): Route to NIP-42 challenge validation - **Kind 24242** (Blossom): Route to Blossom operation validation - **Other Kinds**: Skip Nostr validation, proceed to rules - **Invalid Kind**: Reject immediately 8. **NIP-42 Challenge Validation** (Kind 22242 Only) - Validate `relay` tag matches configured relay URL - Verify `challenge` tag exists and matches stored challenge - Check challenge expiration and single-use constraints - **Performance**: ~500μs additional validation overhead 9. **Cryptographic Signature Verification** (Both Paths) - **Most CPU-intensive operation** - ECDSA signature verification - Validates event authenticity using secp256k1 - **Early exit**: Invalid signatures rejected before database queries 10. **Operation-Specific Validation** (Kind 24242 Only) - 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 11. **Public Key Extraction** (Both Paths) - Extract validated public key from event for rule evaluation - Store authentication context (NIP-42 vs Blossom) for rule processing #### 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: ### Authentication Rule Errors - **-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 ### NIP-42 Specific Errors - **-200**: `NIP42_ERROR_INVALID_RELAY_URL` - Relay URL mismatch or missing - **-201**: `NIP42_ERROR_INVALID_CHALLENGE` - Challenge missing or malformed - **-202**: `NIP42_ERROR_CHALLENGE_EXPIRED` - Challenge has expired - **-203**: `NIP42_ERROR_CHALLENGE_USED` - Challenge already consumed - **-204**: `NIP42_ERROR_CHALLENGE_NOT_FOUND` - Challenge not found in storage - **-205**: `NIP42_ERROR_WRONG_EVENT_KIND` - Expected kind 22242 for NIP-42 - **-206**: `NIP42_ERROR_MISSING_TAGS` - Required relay or challenge tags missing - **-207**: `NIP42_ERROR_URL_NORMALIZATION` - Failed to normalize relay URL - **-208**: `NIP42_ERROR_VALIDATION_FAILED` - General NIP-42 validation failure ## 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 ```