Moved auth system from nostr_core_lib back into ginxsom. Still debugging but so many changes I wanted to commit.
This commit is contained in:
191
AUTH_API.md
191
AUTH_API.md
@@ -1,8 +1,5 @@
|
||||
# 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
|
||||
|
||||
@@ -505,191 +502,3 @@ The rule evaluation order is specifically designed for security:
|
||||
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
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user