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

23 KiB

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)

  1. 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
  2. JSON Parsing (lines 150-156)

    • Parse Nostr event JSON using cJSON
    • Early exit: Invalid JSON rejected before signature verification
  3. 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
  4. 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
  5. 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
  6. Public Key Extraction (lines 181-184)

    • Extract validated public key from event for rule evaluation

Phase 3: Authentication Rules (Database Queries)

  1. Rules System Check (line 191)

    • Quick config check if authentication rules are enabled
    • Early exit: If disabled, allow request immediately
  2. 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)
  3. 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
  4. Whitelist Default Denial (lines 1097-1121)

    • If whitelist rules exist but none matched, deny request
    • Prevents whitelist bypass attacks
  5. 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

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

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

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:

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:

-- 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

#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:

// 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