tests
This commit is contained in:
491
AUTH_API.md
Normal file
491
AUTH_API.md
Normal file
@@ -0,0 +1,491 @@
|
||||
# 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
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user