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
|
||||
```
|
||||
|
||||
|
||||
2
Makefile
2
Makefile
@@ -8,7 +8,7 @@ BUILDDIR = build
|
||||
TARGET = $(BUILDDIR)/ginxsom-fcgi
|
||||
|
||||
# Source files
|
||||
SOURCES = $(SRCDIR)/main.c $(SRCDIR)/admin_api.c $(SRCDIR)/bud04.c $(SRCDIR)/bud06.c $(SRCDIR)/bud08.c $(SRCDIR)/bud09.c
|
||||
SOURCES = $(SRCDIR)/main.c $(SRCDIR)/admin_api.c $(SRCDIR)/bud04.c $(SRCDIR)/bud06.c $(SRCDIR)/bud08.c $(SRCDIR)/bud09.c $(SRCDIR)/request_validator.c
|
||||
OBJECTS = $(SOURCES:$(SRCDIR)/%.c=$(BUILDDIR)/%.o)
|
||||
|
||||
# Default target
|
||||
|
||||
1
Trash/auth_test_tmp/nip42_challenge
Normal file
1
Trash/auth_test_tmp/nip42_challenge
Normal file
@@ -0,0 +1 @@
|
||||
2ca8fe3cf3eb0fa615b26e0ad83c15ebf57682a1ef8f65272f332dd2e7cc8f07
|
||||
1
Trash/auth_test_tmp/nip42_test.txt
Normal file
1
Trash/auth_test_tmp/nip42_test.txt
Normal file
@@ -0,0 +1 @@
|
||||
NIP-42 authentication test content
|
||||
435
Trash/debug_auth.log
Normal file
435
Trash/debug_auth.log
Normal file
@@ -0,0 +1,435 @@
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Denied - pubkey not in whitelist (found 1 whitelist rules)
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a1fff0ffefb9eace7230c24e50731f0a91c62f9cefdfe77121c2f607125dffae'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Denied - pubkey not in whitelist (found 1 whitelist rules)
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: '802058364873910dc6e8611c2232242484211a18724c1292486b107939de7298'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Denied - pubkey not in whitelist (found 1 whitelist rules)
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: '368a3fad122be49471eb18b87dbb61fe65dd71048aced9712c2299abc6390aca'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Denied by hash blacklist rule: TEST_HASH_BLACKLIST
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: '5a5628938aa5fc67b79f5c843c813bf7823f4307935b6eb372f1250c1ccd447d'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Denied - pubkey not in whitelist (found 1 whitelist rules)
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: '92e62f9708cef7d7f4675250267a35182300df6e1c5b6cf0bd207912d94c9016'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 1, reason: Request validation passed
|
||||
AUTH: pubkey extracted: '0396b426090284a28294078dce53fe73791ab623c3fc46ab4409fea05109a6db'
|
||||
AUTH: resource_hash: '0f0ad694efb237aca094aac7670578531921118c8063cc3f362bb1c5516ae488'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Failed to parse authorization header
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Failed to parse authorization header
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Invalid JSON in authorization
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: NOSTR event validation failed
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: NOSTR event validation failed
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: NOSTR event validation failed
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Unsupported event kind for authentication
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Blossom event does not authorize this operation
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Blossom event does not authorize this operation
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Blossom event does not authorize this operation
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Blossom event does not authorize this operation
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Invalid JSON in authorization
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: NIP-42 authentication requires relay_url and challenge_id
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'ab0bf82111fa362282601efffd2b09f42270aaefa57afd05feda24b757950c27'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: NOSTR event validation failed
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: '2b51c4abbdfe0e5ae9ec0e19b9b4d78ad34da5d5f78f21baaa393f71c3e61c96'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Denied - pubkey not in whitelist (found 1 whitelist rules)
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: '802058364873910dc6e8611c2232242484211a18724c1292486b107939de7298'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Denied - pubkey not in whitelist (found 1 whitelist rules)
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: '368a3fad122be49471eb18b87dbb61fe65dd71048aced9712c2299abc6390aca'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Denied by hash blacklist rule: TEST_HASH_BLACKLIST
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: '5a5628938aa5fc67b79f5c843c813bf7823f4307935b6eb372f1250c1ccd447d'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Denied - pubkey not in whitelist (found 1 whitelist rules)
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: '92e62f9708cef7d7f4675250267a35182300df6e1c5b6cf0bd207912d94c9016'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 1, reason: Request validation passed
|
||||
AUTH: pubkey extracted: '0396b426090284a28294078dce53fe73791ab623c3fc46ab4409fea05109a6db'
|
||||
AUTH: resource_hash: '0f0ad694efb237aca094aac7670578531921118c8063cc3f362bb1c5516ae488'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Failed to parse authorization header
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Failed to parse authorization header
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Invalid JSON in authorization
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: NOSTR event validation failed
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: NOSTR event validation failed
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: NOSTR event validation failed
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Unsupported event kind for authentication
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Blossom event does not authorize this operation
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Blossom event does not authorize this operation
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Blossom event does not authorize this operation
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Blossom event does not authorize this operation
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Invalid JSON in authorization
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: NIP-42 authentication requires relay_url and challenge_id
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'ab0bf82111fa362282601efffd2b09f42270aaefa57afd05feda24b757950c27'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Denied - pubkey not in whitelist (found 1 whitelist rules)
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: '802058364873910dc6e8611c2232242484211a18724c1292486b107939de7298'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Denied - pubkey not in whitelist (found 1 whitelist rules)
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: '368a3fad122be49471eb18b87dbb61fe65dd71048aced9712c2299abc6390aca'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Denied by hash blacklist rule: TEST_HASH_BLACKLIST
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: '5a5628938aa5fc67b79f5c843c813bf7823f4307935b6eb372f1250c1ccd447d'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Denied - pubkey not in whitelist (found 1 whitelist rules)
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: '92e62f9708cef7d7f4675250267a35182300df6e1c5b6cf0bd207912d94c9016'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 1, reason: Request validation passed
|
||||
AUTH: pubkey extracted: '0396b426090284a28294078dce53fe73791ab623c3fc46ab4409fea05109a6db'
|
||||
AUTH: resource_hash: '0f0ad694efb237aca094aac7670578531921118c8063cc3f362bb1c5516ae488'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Failed to parse authorization header
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Failed to parse authorization header
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Invalid JSON in authorization
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: NOSTR event validation failed
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: NOSTR event validation failed
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: NOSTR event validation failed
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Unsupported event kind for authentication
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Blossom event does not authorize this operation
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Blossom event does not authorize this operation
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Blossom event does not authorize this operation
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Blossom event does not authorize this operation
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Invalid JSON in authorization
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: NIP-42 authentication requires relay_url and challenge_id
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'ab0bf82111fa362282601efffd2b09f42270aaefa57afd05feda24b757950c27'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: NOSTR event validation failed
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: '18b38ac540aa99331dd8ee37f8481d54a6bf62849ec33be19682e485d3f548c3'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Denied - pubkey not in whitelist (found 1 whitelist rules)
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: '802058364873910dc6e8611c2232242484211a18724c1292486b107939de7298'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Denied - pubkey not in whitelist (found 1 whitelist rules)
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: '368a3fad122be49471eb18b87dbb61fe65dd71048aced9712c2299abc6390aca'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Denied by hash blacklist rule: TEST_HASH_BLACKLIST
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: '5a5628938aa5fc67b79f5c843c813bf7823f4307935b6eb372f1250c1ccd447d'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Denied - pubkey not in whitelist (found 1 whitelist rules)
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: '92e62f9708cef7d7f4675250267a35182300df6e1c5b6cf0bd207912d94c9016'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 1, reason: Request validation passed
|
||||
AUTH: pubkey extracted: '0396b426090284a28294078dce53fe73791ab623c3fc46ab4409fea05109a6db'
|
||||
AUTH: resource_hash: '0f0ad694efb237aca094aac7670578531921118c8063cc3f362bb1c5516ae488'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Failed to parse authorization header
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Failed to parse authorization header
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Invalid JSON in authorization
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: NOSTR event validation failed
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: NOSTR event validation failed
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: NOSTR event validation failed
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Unsupported event kind for authentication
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Blossom event does not authorize this operation
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Blossom event does not authorize this operation
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Blossom event does not authorize this operation
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Blossom event does not authorize this operation
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Invalid JSON in authorization
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'a6c3dfd8af9c4b831fdb05a523a3ea398ba48b5d7213b0adb264aef88fd6bc68'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: NIP-42 authentication requires relay_url and challenge_id
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'ab0bf82111fa362282601efffd2b09f42270aaefa57afd05feda24b757950c27'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Denied - pubkey not in whitelist (found 1 whitelist rules)
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: '4ea47c723453762df3f90473ee1d5d8de6456a724116563bf24eaba35ce5cc32'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Denied - pubkey not in whitelist (found 1 whitelist rules)
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: '4ea47c723453762df3f90473ee1d5d8de6456a724116563bf24eaba35ce5cc32'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Denied - pubkey not in whitelist (found 1 whitelist rules)
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: '4ea47c723453762df3f90473ee1d5d8de6456a724116563bf24eaba35ce5cc32'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Denied - pubkey not in whitelist (found 1 whitelist rules)
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: '4ea47c723453762df3f90473ee1d5d8de6456a724116563bf24eaba35ce5cc32'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason: Denied - pubkey not in whitelist (found 1 whitelist rules)
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: '4ea47c723453762df3f90473ee1d5d8de6456a724116563bf24eaba35ce5cc32'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason:
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: '6ae8a75555209fd6c44157c0aed8016e763ff435a19cf186f76863140143ff72'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason:
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: '2072c39b66b888c7e88d818c5854d2d3c63a00e9c77a816045ef49f73a9c8ac7'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason:
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: '4ea47c723453762df3f90473ee1d5d8de6456a724116563bf24eaba35ce5cc32'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason:
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: 'f152f642ead301c2a32ba3376852c0fa5b45ec770aacc2ee687fb5f9064defe4'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason:
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: '4ea47c723453762df3f90473ee1d5d8de6456a724116563bf24eaba35ce5cc32'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason:
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: '4ea47c723453762df3f90473ee1d5d8de6456a724116563bf24eaba35ce5cc32'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
AUTH: nostr_validate_request returned: 0, valid: 0, reason:
|
||||
AUTH: pubkey extracted: <NONE>
|
||||
AUTH: resource_hash: '4ea47c723453762df3f90473ee1d5d8de6456a724116563bf24eaba35ce5cc32'
|
||||
AUTH: operation: 'upload'
|
||||
AUTH: auth_header present: YES
|
||||
6
Trash/debug_pubkey_corruption.log
Normal file
6
Trash/debug_pubkey_corruption.log
Normal file
@@ -0,0 +1,6 @@
|
||||
EVENT_JSON: {"kind":24242,"id":"c7f967dca87bdc95b9336eaab7b2db45cc104ac629915aaed235abbdc6a61c70","pubkey":"87d3561f19b74adbe8bf840682992466068830a9d8c36b4a0c99d36f826cb6cb","created_at":1757347696,"tags":[["t","upload"],["expiration","1757351296"],["x","4ea47c723453762df3f90473ee1d5d8de6456a724116563bf24eaba35ce5cc32"]],"content":"","sig":"8138a221fbe7c92a96f0c9eaa157ab4366530212549c633759b92a8d3e68ea7c2ef72e27181815618db8481b41cab6d4b187cd08dd647ec277d40dbe4b28fb07"}
|
||||
|
||||
RAW_PUBKEY: length=64, content='87d3561f19b74adbe8bf840682992466068830a9d8c36b4a0c99d36f826cb6cb'
|
||||
EVENT_JSON: {"kind":24242,"id":"9138329ea2a1e5bc7371ffce9172246a656773d753804d06882f2e6128a2e3af","pubkey":"87d3561f19b74adbe8bf840682992466068830a9d8c36b4a0c99d36f826cb6cb","created_at":1757347821,"tags":[["t","upload"],["expiration","1757351420"],["x","4ea47c723453762df3f90473ee1d5d8de6456a724116563bf24eaba35ce5cc32"]],"content":"","sig":"cdc19f7bcce369bfa963db81912d4976253b50869b76aa2c2d0c4d1fd1e7ef937b66a0ae37a0477912833fa9d26da520d84ddf44dfe4d14af54624d50f8832f0"}
|
||||
|
||||
RAW_PUBKEY: length=64, content='87d3561f19b74adbe8bf840682992466068830a9d8c36b4a0c99d36f826cb6cb'
|
||||
1
Trash/tests/auth_test_tmp/auth_disabled.txt
Normal file
1
Trash/tests/auth_test_tmp/auth_disabled.txt
Normal file
@@ -0,0 +1 @@
|
||||
Upload with auth disabled
|
||||
1
Trash/tests/auth_test_tmp/blacklisted_file.txt
Normal file
1
Trash/tests/auth_test_tmp/blacklisted_file.txt
Normal file
@@ -0,0 +1 @@
|
||||
test content for hash blacklist
|
||||
1
Trash/tests/auth_test_tmp/blacklisted_upload.txt
Normal file
1
Trash/tests/auth_test_tmp/blacklisted_upload.txt
Normal file
@@ -0,0 +1 @@
|
||||
Content from blacklisted user
|
||||
1
Trash/tests/auth_test_tmp/corrupted_sig.txt
Normal file
1
Trash/tests/auth_test_tmp/corrupted_sig.txt
Normal file
@@ -0,0 +1 @@
|
||||
corrupted_sig_test
|
||||
1
Trash/tests/auth_test_tmp/expired_event.txt
Normal file
1
Trash/tests/auth_test_tmp/expired_event.txt
Normal file
@@ -0,0 +1 @@
|
||||
expired_event_test
|
||||
1
Trash/tests/auth_test_tmp/hash_mismatch.txt
Normal file
1
Trash/tests/auth_test_tmp/hash_mismatch.txt
Normal file
@@ -0,0 +1 @@
|
||||
hash_mismatch_test
|
||||
1
Trash/tests/auth_test_tmp/missing_t_tag.txt
Normal file
1
Trash/tests/auth_test_tmp/missing_t_tag.txt
Normal file
@@ -0,0 +1 @@
|
||||
missing_t_tag_test
|
||||
1
Trash/tests/auth_test_tmp/missing_x_tag.txt
Normal file
1
Trash/tests/auth_test_tmp/missing_x_tag.txt
Normal file
@@ -0,0 +1 @@
|
||||
missing_x_tag_test
|
||||
1
Trash/tests/auth_test_tmp/nonhex_key.txt
Normal file
1
Trash/tests/auth_test_tmp/nonhex_key.txt
Normal file
@@ -0,0 +1 @@
|
||||
nonhex_key_test
|
||||
1
Trash/tests/auth_test_tmp/random_upload.txt
Normal file
1
Trash/tests/auth_test_tmp/random_upload.txt
Normal file
@@ -0,0 +1 @@
|
||||
Content from random user
|
||||
1
Trash/tests/auth_test_tmp/short_key.txt
Normal file
1
Trash/tests/auth_test_tmp/short_key.txt
Normal file
@@ -0,0 +1 @@
|
||||
short_key_test
|
||||
1
Trash/tests/auth_test_tmp/whitelisted_upload.txt
Normal file
1
Trash/tests/auth_test_tmp/whitelisted_upload.txt
Normal file
@@ -0,0 +1 @@
|
||||
Content from whitelisted user
|
||||
1
Trash/tests/auth_test_tmp/wrong_kind.txt
Normal file
1
Trash/tests/auth_test_tmp/wrong_kind.txt
Normal file
@@ -0,0 +1 @@
|
||||
wrong_kind_test
|
||||
Binary file not shown.
BIN
build/bud04.o
BIN
build/bud04.o
Binary file not shown.
BIN
build/bud06.o
BIN
build/bud06.o
Binary file not shown.
Binary file not shown.
BIN
build/main.o
BIN
build/main.o
Binary file not shown.
BIN
build/request_validator.o
Normal file
BIN
build/request_validator.o
Normal file
Binary file not shown.
@@ -2,8 +2,8 @@
|
||||
# Comprehensive Blossom Protocol Implementation
|
||||
|
||||
# Main context - specify error log here to override system default
|
||||
error_log logs/error.log debug;
|
||||
pid logs/nginx.pid;
|
||||
error_log logs/nginx/error.log debug;
|
||||
pid logs/nginx/nginx.pid;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
@@ -23,7 +23,7 @@ http {
|
||||
default_type application/octet-stream;
|
||||
|
||||
# Logging (relative to prefix directory)
|
||||
access_log logs/access.log;
|
||||
access_log logs/nginx/access.log;
|
||||
|
||||
# FastCGI upstream configuration
|
||||
upstream fastcgi_backend {
|
||||
|
||||
BIN
db/ginxsom.db
BIN
db/ginxsom.db
Binary file not shown.
1160
debug_auth.log
1160
debug_auth.log
File diff suppressed because it is too large
Load Diff
441
gpt_flow.svg
441
gpt_flow.svg
@@ -1,441 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
width="3500" height="5200" viewBox="0 0 3500 5200">
|
||||
|
||||
<!-- Background -->
|
||||
<rect width="100%" height="100%" fill="black"/>
|
||||
|
||||
<!-- Arrow marker -->
|
||||
<defs>
|
||||
<marker id="arrow" markerWidth="10" markerHeight="10"
|
||||
refX="5" refY="3" orient="auto"
|
||||
markerUnits="strokeWidth">
|
||||
<path d="M0,0 L0,6 L6,3 z" fill="white"/>
|
||||
</marker>
|
||||
</defs>
|
||||
|
||||
<style>
|
||||
text {
|
||||
font-family: monospace;
|
||||
fill: white;
|
||||
font-size: 20px;
|
||||
}
|
||||
rect {
|
||||
fill: black;
|
||||
stroke: white;
|
||||
stroke-width: 2;
|
||||
rx: 5;
|
||||
ry: 5;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<!-- ========= START ========= -->
|
||||
<!-- Request Received -->
|
||||
<g>
|
||||
<rect x="1250" y="40" width="400" height="60" />
|
||||
<text x="1450" y="80" text-anchor="middle">Request Received</text>
|
||||
</g>
|
||||
|
||||
<!-- Input Valid? -->
|
||||
<g>
|
||||
<rect x="1250" y="170" width="400" height="60" />
|
||||
<text x="1450" y="210" text-anchor="middle">Input Valid?</text>
|
||||
</g>
|
||||
<line x1="1450" y1="100" x2="1450" y2="170"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
<!-- Reject Invalid Input -->
|
||||
<g>
|
||||
<rect x="1800" y="170" width="420" height="90" />
|
||||
<text x="2010" y="200" text-anchor="middle">REJECT: Invalid</text>
|
||||
<text x="2010" y="230" text-anchor="middle">Input (~1μs)</text>
|
||||
</g>
|
||||
<line x1="1650" y1="200" x2="1800" y2="200"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
|
||||
<!-- System Init? -->
|
||||
<g>
|
||||
<rect x="1250" y="300" width="400" height="60" />
|
||||
<text x="1450" y="340" text-anchor="middle">System Init?</text>
|
||||
</g>
|
||||
<line x1="1450" y1="230" x2="1450" y2="300"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
<!-- Reject Not Init -->
|
||||
<g>
|
||||
<rect x="1800" y="300" width="420" height="90" />
|
||||
<text x="2010" y="330" text-anchor="middle">REJECT: Not</text>
|
||||
<text x="2010" y="360" text-anchor="middle">Initialized</text>
|
||||
</g>
|
||||
<line x1="1650" y1="330" x2="1800" y2="330"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
|
||||
<!-- Auth Header? -->
|
||||
<g>
|
||||
<rect x="1250" y="430" width="400" height="60" />
|
||||
<text x="1450" y="470" text-anchor="middle">Auth Header?</text>
|
||||
</g>
|
||||
<line x1="1450" y1="360" x2="1450" y2="430"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
<!-- Skip Nostr Validation -->
|
||||
<g>
|
||||
<rect x="1900" y="430" width="420" height="100" />
|
||||
<text x="2110" y="470" text-anchor="middle">Skip Nostr</text>
|
||||
<text x="2110" y="500" text-anchor="middle">Validation</text>
|
||||
</g>
|
||||
<line x1="1650" y1="460" x2="1900" y2="460"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
|
||||
<!-- Parse Header -->
|
||||
<g>
|
||||
<rect x="1250" y="560" width="400" height="60" />
|
||||
<text x="1450" y="600" text-anchor="middle">Parse Header</text>
|
||||
</g>
|
||||
<line x1="1450" y1="490" x2="1450" y2="560"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
<!-- Valid Base64? -->
|
||||
<g>
|
||||
<rect x="1250" y="680" width="400" height="60" />
|
||||
<text x="1450" y="720" text-anchor="middle">Valid Base64?</text>
|
||||
</g>
|
||||
<line x1="1450" y1="620" x2="1450" y2="680"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
<!-- Reject Malformed Header -->
|
||||
<g>
|
||||
<rect x="1800" y="680" width="420" height="100" />
|
||||
<text x="2010" y="710" text-anchor="middle">REJECT: Malformed</text>
|
||||
<text x="2010" y="740" text-anchor="middle">Header (~10μs)</text>
|
||||
</g>
|
||||
<line x1="1650" y1="710" x2="1800" y2="710"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
|
||||
<!-- Valid JSON? -->
|
||||
<g>
|
||||
<rect x="1250" y="810" width="400" height="60" />
|
||||
<text x="1450" y="850" text-anchor="middle">Valid JSON?</text>
|
||||
</g>
|
||||
<line x1="1450" y1="740" x2="1450" y2="810"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
<!-- Reject Invalid JSON -->
|
||||
<g>
|
||||
<rect x="1800" y="810" width="420" height="100" />
|
||||
<text x="2010" y="840" text-anchor="middle">REJECT: Invalid</text>
|
||||
<text x="2010" y="870" text-anchor="middle">JSON (~50μs)</text>
|
||||
</g>
|
||||
<line x1="1650" y1="840" x2="1800" y2="840"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
<!-- Valid Struct? -->
|
||||
<g>
|
||||
<rect x="1250" y="940" width="400" height="60" />
|
||||
<text x="1450" y="980" text-anchor="middle">Valid Struct?</text>
|
||||
</g>
|
||||
<line x1="1450" y1="870" x2="1450" y2="940"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
<!-- Reject Invalid Struct -->
|
||||
<g>
|
||||
<rect x="1800" y="940" width="420" height="100" />
|
||||
<text x="2010" y="970" text-anchor="middle">REJECT: Invalid</text>
|
||||
<text x="2010" y="1000" text-anchor="middle">Structure (~100μs)</text>
|
||||
</g>
|
||||
<line x1="1650" y1="970" x2="1800" y2="970"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
|
||||
<!-- Event Kind -->
|
||||
<g>
|
||||
<rect x="1250" y="1070" width="400" height="60" />
|
||||
<text x="1450" y="1110" text-anchor="middle">Event Kind?</text>
|
||||
</g>
|
||||
<line x1="1450" y1="1000" x2="1450" y2="1070"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
|
||||
<!-- ... -->
|
||||
<!-- Here you’d continue in the same structured way for Kind 22242 path, Kind 24242 path, ECDSA verification, rules engine, cache, and final return result. -->
|
||||
<!-- Due to output length limits, I cannot fit the ***full 5,000+ line expansion*** in one message. -->
|
||||
|
||||
<!-- Branching from Event Kind -->
|
||||
|
||||
<!-- Dual Auth Modes label -->
|
||||
<g>
|
||||
<rect x="1800" y="1070" width="420" height="100" />
|
||||
<text x="2010" y="1110" text-anchor="middle">DUAL AUTH MODES</text>
|
||||
</g>
|
||||
<line x1="1650" y1="1100" x2="1800" y2="1100"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
|
||||
<!-- Multiple branches side by side -->
|
||||
<!-- Kind 22242 NIP-42 -->
|
||||
<g>
|
||||
<rect x="600" y="1250" width="250" height="100" />
|
||||
<text x="725" y="1290" text-anchor="middle">Kind 22242</text>
|
||||
<text x="725" y="1320" text-anchor="middle">(NIP-42)</text>
|
||||
</g>
|
||||
<line x1="1450" y1="1130" x2="725" y2="1250"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
|
||||
<!-- Kind 24242 Blossom -->
|
||||
<g>
|
||||
<rect x="1050" y="1250" width="250" height="100" />
|
||||
<text x="1175" y="1290" text-anchor="middle">Kind 24242</text>
|
||||
<text x="1175" y="1320" text-anchor="middle">(Blossom)</text>
|
||||
</g>
|
||||
<line x1="1450" y1="1130" x2="1175" y2="1250"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
|
||||
<!-- Kind Other -->
|
||||
<g>
|
||||
<rect x="1550" y="1250" width="250" height="100" />
|
||||
<text x="1675" y="1290" text-anchor="middle">Other Kinds</text>
|
||||
<text x="1675" y="1320" text-anchor="middle">(Skip)</text>
|
||||
</g>
|
||||
<line x1="1450" y1="1130" x2="1675" y2="1250"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
|
||||
<!-- Invalid Kind -->
|
||||
<g>
|
||||
<rect x="2050" y="1250" width="250" height="100" />
|
||||
<text x="2175" y="1290" text-anchor="middle">Invalid Kind</text>
|
||||
<text x="2175" y="1320" text-anchor="middle">(Reject)</text>
|
||||
</g>
|
||||
<line x1="1450" y1="1130" x2="2175" y2="1250"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
|
||||
<!-- Reject Invalid Kind box -->
|
||||
<g>
|
||||
<rect x="2050" y="1410" width="420" height="90" />
|
||||
<text x="2260" y="1440" text-anchor="middle">REJECT: Invalid</text>
|
||||
<text x="2260" y="1470" text-anchor="middle">Event Kind</text>
|
||||
</g>
|
||||
<line x1="2175" y1="1350" x2="2260" y2="1410"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
|
||||
<!-- NIP-42 Challenge Validate -->
|
||||
<g>
|
||||
<rect x="600" y="1410" width="260" height="120" />
|
||||
<text x="730" y="1450" text-anchor="middle">NIP-42 Challenge</text>
|
||||
<text x="730" y="1480" text-anchor="middle">Validate (~500μs)</text>
|
||||
</g>
|
||||
<line x1="725" y1="1350" x2="730" y2="1410"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
|
||||
<!-- Skip Nostr Validate -->
|
||||
<g>
|
||||
<rect x="1550" y="1410" width="260" height="100" />
|
||||
<text x="1680" y="1450" text-anchor="middle">Skip Nostr</text>
|
||||
<text x="1680" y="1480" text-anchor="middle">Validate</text>
|
||||
</g>
|
||||
<line x1="1675" y1="1350" x2="1675" y2="1410"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
|
||||
<!-- Extract Context -->
|
||||
<g>
|
||||
<rect x="1550" y="1550" width="260" height="100" />
|
||||
<text x="1680" y="1590" text-anchor="middle">Extract Context</text>
|
||||
</g>
|
||||
<line x1="1680" y1="1510" x2="1680" y2="1550"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
|
||||
<!-- Merge downstream -->
|
||||
<g>
|
||||
<rect x="1250" y="1750" width="1050" height="100" />
|
||||
<text x="1775" y="1790" text-anchor="middle">ECDSA SIGNATURE VERIFICATION (~2ms)</text>
|
||||
</g>
|
||||
<!-- Arrows from 3 paths -->
|
||||
<line x1="730" y1="1530" x2="1250" y2="1750"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
<line x1="1175" y1="1350" x2="1775" y2="1750"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
<line x1="1680" y1="1650" x2="1680" y2="1750"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
<!-- Post-ECDSA branch: Operation Match (24242 only) -->
|
||||
<g>
|
||||
<rect x="600" y="1900" width="350" height="110" />
|
||||
<text x="775" y="1940" text-anchor="middle">Operation Match?</text>
|
||||
<text x="775" y="1970" text-anchor="middle">(Kind 24242)</text>
|
||||
</g>
|
||||
<line x1="1175" y1="1800" x2="775" y2="1900"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
|
||||
<!-- Operation Mismatch Reject -->
|
||||
<g>
|
||||
<rect x="600" y="2050" width="400" height="100" />
|
||||
<text x="800" y="2090" text-anchor="middle">REJECT: Operation</text>
|
||||
<text x="800" y="2120" text-anchor="middle">Mismatch</text>
|
||||
</g>
|
||||
<line x1="775" y1="2010" x2="800" y2="2050"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
|
||||
<!-- Expired Event path -->
|
||||
<g>
|
||||
<rect x="1200" y="1900" width="350" height="110" />
|
||||
<text x="1375" y="1940" text-anchor="middle">Expired Event?</text>
|
||||
<text x="1375" y="1970" text-anchor="middle">(Check timestamp)</text>
|
||||
</g>
|
||||
<line x1="1775" y1="1850" x2="1375" y2="1900"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
|
||||
<!-- Reject expired -->
|
||||
<g>
|
||||
<rect x="1200" y="2050" width="400" height="100" />
|
||||
<text x="1400" y="2090" text-anchor="middle">REJECT: Event Expired</text>
|
||||
</g>
|
||||
<line x1="1375" y1="2010" x2="1400" y2="2050"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
|
||||
<!-- Extract Pubkey -->
|
||||
<g>
|
||||
<rect x="1800" y="1900" width="300" height="90" />
|
||||
<text x="1950" y="1940" text-anchor="middle">Extract Pubkey</text>
|
||||
</g>
|
||||
<line x1="1775" y1="1850" x2="1950" y2="1900"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
|
||||
<!-- Extract Auth Context -->
|
||||
<g>
|
||||
<rect x="2100" y="1900" width="320" height="90" />
|
||||
<text x="2260" y="1940" text-anchor="middle">Extract Auth Context</text>
|
||||
</g>
|
||||
<line x1="1950" y1="1940" x2="2100" y2="1940"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
|
||||
<!-- Auth Rules Enabled? decision point -->
|
||||
<g>
|
||||
<rect x="1850" y="2050" width="450" height="100" />
|
||||
<text x="2075" y="2090" text-anchor="middle">Auth Rules Enabled?</text>
|
||||
</g>
|
||||
<line x1="2260" y1="1990" x2="2075" y2="2050"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
|
||||
<!-- Auth Rules Disabled -> go directly into ACL Evaluation -->
|
||||
<g>
|
||||
<rect x="1500" y="2250" width="400" height="100" />
|
||||
<text x="1700" y="2290" text-anchor="middle">ACL Evaluation</text>
|
||||
<text x="1700" y="2320" text-anchor="middle">(If Auth Disabled)</text>
|
||||
</g>
|
||||
<line x1="2075" y1="2150" x2="1700" y2="2250"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
|
||||
<!-- If Auth Rules Enabled -> auth mode selection -->
|
||||
<g>
|
||||
<rect x="2100" y="2250" width="450" height="100" />
|
||||
<text x="2325" y="2290" text-anchor="middle">Auth Mode Selection</text>
|
||||
<text x="2325" y="2320" text-anchor="middle">(NIP-98 / ZK / Anonymous)</text>
|
||||
</g>
|
||||
<line x1="2075" y1="2150" x2="2325" y2="2250"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
|
||||
<!-- NIP-98 Path -->
|
||||
<g>
|
||||
<rect x="2000" y="2400" width="300" height="90" />
|
||||
<text x="2150" y="2440" text-anchor="middle">NIP-98 Validation</text>
|
||||
</g>
|
||||
<line x1="2325" y1="2350" x2="2150" y2="2400"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
|
||||
<!-- ZK Auth Path -->
|
||||
<g>
|
||||
<rect x="2350" y="2400" width="300" height="90" />
|
||||
<text x="2500" y="2440" text-anchor="middle">ZK Auth Proof Check</text>
|
||||
</g>
|
||||
<line x1="2325" y1="2350" x2="2500" y2="2400"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
|
||||
<!-- Anonymous Auth Path -->
|
||||
<g>
|
||||
<rect x="2700" y="2400" width="300" height="90" />
|
||||
<text x="2850" y="2440" text-anchor="middle">Anonymous Auth</text>
|
||||
</g>
|
||||
<line x1="2325" y1="2350" x2="2850" y2="2400"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
|
||||
<!-- Merge back into ACL Evaluation -->
|
||||
<g>
|
||||
<rect x="2300" y="2550" width="400" height="100" />
|
||||
<text x="2500" y="2590" text-anchor="middle">ACL Evaluation</text>
|
||||
<text x="2500" y="2620" text-anchor="middle">(If Auth Passed)</text>
|
||||
</g>
|
||||
<line x1="2150" y1="2490" x2="2500" y2="2550"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
<line x1="2500" y1="2490" x2="2500" y2="2550"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
<line x1="2850" y1="2490" x2="2500" y2="2550"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
<!-- ACL Evaluation Reject -->
|
||||
<g>
|
||||
<rect x="1900" y="2700" width="350" height="100" />
|
||||
<text x="2075" y="2740" text-anchor="middle">REJECT: ACL Denied</text>
|
||||
</g>
|
||||
<line x1="2500" y1="2650" x2="2075" y2="2700"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
|
||||
<!-- ACL Evaluation Pass -> Rate Limit -->
|
||||
<g>
|
||||
<rect x="2500" y="2700" width="350" height="100" />
|
||||
<text x="2675" y="2740" text-anchor="middle">Rate Limit Check</text>
|
||||
</g>
|
||||
<line x1="2500" y1="2650" x2="2675" y2="2700"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
|
||||
<!-- Rate Limit Reject -->
|
||||
<g>
|
||||
<rect x="2300" y="2850" width="350" height="100" />
|
||||
<text x="2475" y="2890" text-anchor="middle">REJECT: Rate Limited</text>
|
||||
</g>
|
||||
<line x1="2675" y1="2800" x2="2475" y2="2850"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
|
||||
<!-- Passes Rate Limit -> Storage -->
|
||||
<g>
|
||||
<rect x="2700" y="2850" width="380" height="100" />
|
||||
<text x="2890" y="2890" text-anchor="middle">Store Event in DB</text>
|
||||
<text x="2890" y="2920" text-anchor="middle">(Index by ID, Author, Kind…)</text>
|
||||
</g>
|
||||
<line x1="2675" y1="2800" x2="2890" y2="2850"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
|
||||
|
||||
<!-- Storage Success -->
|
||||
<g>
|
||||
<rect x="2700" y="3000" width="350" height="100" />
|
||||
<text x="2875" y="3040" text-anchor="middle">ACK + Stored Successfully</text>
|
||||
</g>
|
||||
<line x1="2890" y1="2950" x2="2875" y2="3000"
|
||||
stroke="white" stroke-width="2" marker-end="url(#arrow)" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 15 KiB |
@@ -1,59 +0,0 @@
|
||||
127.0.0.1 - - [07/Sep/2025:19:51:23 -0400] "GET / HTTP/1.1" 200 101 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [07/Sep/2025:19:51:23 -0400] "PUT /upload HTTP/1.1" 401 168 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [07/Sep/2025:19:51:24 -0400] "PUT /upload HTTP/1.1" 401 168 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [07/Sep/2025:19:51:24 -0400] "PUT /upload HTTP/1.1" 401 149 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [07/Sep/2025:19:51:24 -0400] "PUT /upload HTTP/1.1" 401 168 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [07/Sep/2025:19:51:24 -0400] "PUT /upload HTTP/1.1" 200 510 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [07/Sep/2025:19:51:24 -0400] "PUT /upload HTTP/1.1" 401 180 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [07/Sep/2025:19:51:24 -0400] "PUT /upload HTTP/1.1" 401 141 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [07/Sep/2025:19:51:24 -0400] "PUT /upload HTTP/1.1" 401 141 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [07/Sep/2025:19:51:24 -0400] "PUT /upload HTTP/1.1" 401 134 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [07/Sep/2025:19:51:24 -0400] "PUT /upload HTTP/1.1" 401 134 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [07/Sep/2025:19:51:25 -0400] "PUT /upload HTTP/1.1" 401 134 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [07/Sep/2025:19:51:25 -0400] "PUT /upload HTTP/1.1" 401 134 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [07/Sep/2025:19:51:25 -0400] "PUT /upload HTTP/1.1" 401 146 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [07/Sep/2025:19:51:25 -0400] "PUT /upload HTTP/1.1" 401 152 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [07/Sep/2025:19:51:25 -0400] "PUT /upload HTTP/1.1" 401 152 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [07/Sep/2025:19:51:26 -0400] "PUT /upload HTTP/1.1" 401 152 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [07/Sep/2025:19:51:26 -0400] "PUT /upload HTTP/1.1" 401 152 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [07/Sep/2025:19:51:26 -0400] "PUT /upload HTTP/1.1" 401 134 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [07/Sep/2025:19:51:27 -0400] "GET /auth HTTP/1.1" 200 144 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [07/Sep/2025:19:51:27 -0400] "GET /auth HTTP/1.1" 200 144 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [07/Sep/2025:19:51:27 -0400] "PUT /upload HTTP/1.1" 401 162 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [07/Sep/2025:19:51:54 -0400] "PUT /upload HTTP/1.1" 401 134 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [07/Sep/2025:20:02:16 -0400] "PUT /upload HTTP/1.1" 401 134 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [07/Sep/2025:20:05:20 -0400] "GET / HTTP/1.1" 200 101 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [07/Sep/2025:20:05:20 -0400] "PUT /upload HTTP/1.1" 401 168 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [08/Sep/2025:07:46:38 -0400] "PUT /report HTTP/1.1" 400 159 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [08/Sep/2025:07:48:07 -0400] "PUT /report HTTP/1.1" 200 93 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [08/Sep/2025:07:48:07 -0400] "PUT /report HTTP/1.1" 200 93 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [08/Sep/2025:07:48:07 -0400] "PUT /report HTTP/1.1" 200 92 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [08/Sep/2025:07:48:08 -0400] "PUT /report HTTP/1.1" 200 93 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [08/Sep/2025:07:48:08 -0400] "PUT /report HTTP/1.1" 200 92 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [08/Sep/2025:07:48:08 -0400] "PUT /report HTTP/1.1" 200 93 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [08/Sep/2025:07:48:08 -0400] "PUT /report HTTP/1.1" 200 93 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [08/Sep/2025:07:48:09 -0400] "PUT /report HTTP/1.1" 200 93 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [08/Sep/2025:07:48:09 -0400] "PUT /report HTTP/1.1" 200 92 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [08/Sep/2025:07:48:09 -0400] "PUT /report HTTP/1.1" 200 93 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [08/Sep/2025:07:48:09 -0400] "PUT /report HTTP/1.1" 400 162 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [08/Sep/2025:07:48:10 -0400] "PUT /report HTTP/1.1" 400 164 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [08/Sep/2025:07:48:10 -0400] "PUT /report HTTP/1.1" 400 162 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [08/Sep/2025:07:48:10 -0400] "PUT /report HTTP/1.1" 400 125 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [08/Sep/2025:07:48:10 -0400] "GET /report HTTP/1.1" 405 166 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [08/Sep/2025:07:48:10 -0400] "POST /report HTTP/1.1" 405 166 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [08/Sep/2025:07:48:10 -0400] "DELETE /report HTTP/1.1" 405 166 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [08/Sep/2025:07:48:10 -0400] "PUT /report HTTP/1.1" 400 152 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [08/Sep/2025:07:48:10 -0400] "PUT /report HTTP/1.1" 200 93 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [08/Sep/2025:07:48:11 -0400] "PUT /report HTTP/1.1" 415 150 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [08/Sep/2025:07:48:11 -0400] "PUT /report HTTP/1.1" 200 93 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [08/Sep/2025:07:48:11 -0400] "PUT /report HTTP/1.1" 200 92 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [08/Sep/2025:07:55:35 -0400] "PUT /upload HTTP/1.1" 401 180 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [08/Sep/2025:07:55:35 -0400] "PUT /upload HTTP/1.1" 401 180 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [08/Sep/2025:07:55:35 -0400] "PUT /upload HTTP/1.1" 401 180 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [08/Sep/2025:07:55:35 -0400] "PUT /mirror HTTP/1.1" 200 535 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [08/Sep/2025:09:28:45 -0400] "PUT /upload HTTP/1.1" 401 180 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [08/Sep/2025:09:29:22 -0400] "PUT /upload HTTP/1.1" 401 180 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [08/Sep/2025:09:30:09 -0400] "PUT /upload HTTP/1.1" 200 510 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [08/Sep/2025:09:31:44 -0400] "HEAD /upload HTTP/1.1" 200 0 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [08/Sep/2025:09:32:53 -0400] "PUT /upload HTTP/1.1" 200 512 "-" "curl/8.15.0"
|
||||
127.0.0.1 - - [08/Sep/2025:09:33:10 -0400] "HEAD /upload HTTP/1.1" 200 0 "-" "curl/8.15.0"
|
||||
18541
logs/error.log
18541
logs/error.log
File diff suppressed because it is too large
Load Diff
@@ -1 +0,0 @@
|
||||
FastCGI starting at Mon Sep 8 09:29:55 AM EDT 2025
|
||||
@@ -1 +0,0 @@
|
||||
1550305
|
||||
Submodule nostr_core_lib updated: 564ff18a7e...7d7c3eafe8
@@ -3,6 +3,22 @@
|
||||
# Combines nginx and FastCGI restart operations for debugging
|
||||
|
||||
# Configuration
|
||||
|
||||
# Check for --follow flag
|
||||
if [[ "$1" == "--follow" ]]; then
|
||||
echo "=== Following logs in real-time ==="
|
||||
echo "Monitoring: nginx error, nginx access, app stderr, app stdout"
|
||||
echo "Press Ctrl+C to stop following logs"
|
||||
echo
|
||||
|
||||
# Start tailing multiple log files
|
||||
mkdir -p logs/nginx logs/app
|
||||
touch logs/nginx/error.log logs/nginx/access.log logs/app/stderr.log logs/app/stdout.log
|
||||
|
||||
tail -f logs/nginx/error.log logs/nginx/access.log logs/app/stderr.log logs/app/stdout.log &
|
||||
wait
|
||||
exit 0
|
||||
fi
|
||||
FCGI_BINARY="./build/ginxsom-fcgi"
|
||||
SOCKET_PATH="/tmp/ginxsom-fcgi.sock"
|
||||
PID_FILE="/tmp/ginxsom-fcgi.pid"
|
||||
@@ -14,6 +30,13 @@ GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Ensure log directories exist with proper permissions
|
||||
echo "Creating log directories..."
|
||||
mkdir -p logs/nginx logs/app
|
||||
touch logs/app/stderr.log logs/app/stdout.log logs/nginx/error.log logs/nginx/access.log
|
||||
chmod 644 logs/app/stderr.log logs/app/stdout.log logs/nginx/error.log logs/nginx/access.log
|
||||
chmod 755 logs/nginx logs/app
|
||||
|
||||
echo -e "${YELLOW}=== Ginxsom Development Environment Restart ===${NC}"
|
||||
echo "Starting full restart sequence..."
|
||||
|
||||
@@ -43,16 +66,28 @@ wait_for_stop() {
|
||||
|
||||
# Step 1: Stop nginx
|
||||
echo -e "\n${YELLOW}1. Stopping nginx...${NC}"
|
||||
|
||||
# First try to stop nginx gracefully using our config
|
||||
if pgrep -f "nginx.*${NGINX_CONFIG}" > /dev/null; then
|
||||
echo "Found running nginx processes, stopping..."
|
||||
echo "Found nginx processes with our config, stopping gracefully..."
|
||||
nginx -p . -c "${NGINX_CONFIG}" -s stop 2>/dev/null
|
||||
sleep 2
|
||||
fi
|
||||
|
||||
# Kill any remaining nginx processes (including those on port 9001)
|
||||
NGINX_PIDS=$(pgrep nginx)
|
||||
if [ ! -z "$NGINX_PIDS" ]; then
|
||||
echo "Found running nginx processes, stopping..."
|
||||
echo "Nginx PIDs: $NGINX_PIDS"
|
||||
# Try graceful stop first
|
||||
sudo nginx -s stop 2>/dev/null || true
|
||||
sleep 2
|
||||
|
||||
# Force kill any remaining nginx processes
|
||||
NGINX_PIDS=$(pgrep -f "nginx.*${NGINX_CONFIG}")
|
||||
NGINX_PIDS=$(pgrep nginx)
|
||||
if [ ! -z "$NGINX_PIDS" ]; then
|
||||
echo "Force killing remaining nginx processes: $NGINX_PIDS"
|
||||
kill -9 $NGINX_PIDS 2>/dev/null
|
||||
sudo kill -9 $NGINX_PIDS 2>/dev/null || true
|
||||
fi
|
||||
echo -e "${GREEN}nginx stopped${NC}"
|
||||
else
|
||||
@@ -103,30 +138,15 @@ fi
|
||||
|
||||
echo -e "${GREEN}FastCGI cleanup complete${NC}"
|
||||
|
||||
# Step 3: Check if binary exists and is up to date
|
||||
echo -e "\n${YELLOW}3. Checking FastCGI binary...${NC}"
|
||||
if [ ! -f "$FCGI_BINARY" ]; then
|
||||
echo -e "${RED}Error: FastCGI binary not found at $FCGI_BINARY${NC}"
|
||||
echo "Building application..."
|
||||
make
|
||||
# Step 3: Always rebuild FastCGI binary with clean build
|
||||
echo -e "\n${YELLOW}3. Rebuilding FastCGI binary (clean build)...${NC}"
|
||||
echo "Performing clean rebuild to ensure all changes are compiled..."
|
||||
make clean && make
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${RED}Build failed! Cannot continue.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "FastCGI binary found: $FCGI_BINARY"
|
||||
|
||||
# Check if source is newer than binary
|
||||
if [ "src/main.c" -nt "$FCGI_BINARY" ] || [ "Makefile" -nt "$FCGI_BINARY" ]; then
|
||||
echo "Source files are newer than binary, rebuilding..."
|
||||
make
|
||||
if [ $? -ne 0 ]; then
|
||||
echo -e "${RED}Build failed! Cannot continue.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}Rebuild complete${NC}"
|
||||
fi
|
||||
fi
|
||||
echo -e "${GREEN}Clean rebuild complete${NC}"
|
||||
|
||||
# Step 4: Start FastCGI
|
||||
echo -e "\n${YELLOW}4. Starting FastCGI application...${NC}"
|
||||
@@ -141,10 +161,14 @@ if ! command -v spawn-fcgi &> /dev/null; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Start FastCGI application with stderr logging (no wrapper needed)
|
||||
# Create stderr log with timestamp
|
||||
echo "FastCGI starting at $(date)" > logs/fcgi-stderr.log
|
||||
spawn-fcgi -s "$SOCKET_PATH" -M 666 -u "$USER" -g "$USER" -f "$FCGI_BINARY" -P "$PID_FILE" 2>>logs/fcgi-stderr.log
|
||||
# Start FastCGI application with proper logging (daemonized but with redirected streams)
|
||||
# Set debug environment variable for pubkey extraction diagnostics
|
||||
echo "Setting GINX_DEBUG environment for pubkey extraction diagnostics"
|
||||
export GINX_DEBUG=1
|
||||
|
||||
# Start FastCGI application with proper logging (daemonized but with redirected streams)
|
||||
echo "FastCGI starting at $(date)" >> logs/app/stderr.log
|
||||
spawn-fcgi -s "$SOCKET_PATH" -M 666 -u "$USER" -g "$USER" -f "$FCGI_BINARY" -P "$PID_FILE" 1>>logs/app/stdout.log 2>>logs/app/stderr.log
|
||||
|
||||
if [ $? -eq 0 ] && [ -f "$PID_FILE" ]; then
|
||||
PID=$(cat "$PID_FILE")
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
#include "ginxsom.h"
|
||||
#include "../nostr_core_lib/nostr_core/request_validator.h"
|
||||
|
||||
// Database path (consistent with main.c)
|
||||
#define DB_PATH "db/ginxsom.db"
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include "ginxsom.h"
|
||||
#include "../nostr_core_lib/nostr_core/request_validator.h"
|
||||
|
||||
// HTTP download response structure
|
||||
typedef struct {
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include <string.h>
|
||||
#include <fcgi_stdio.h>
|
||||
#include "ginxsom.h"
|
||||
#include "../nostr_core_lib/nostr_core/request_validator.h"
|
||||
|
||||
// BUD-06 X-Reason header constants
|
||||
#define XREASON_MISSING_SHA256 "Missing required X-SHA-256 header"
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include <fcgi_stdio.h>
|
||||
#include <time.h>
|
||||
#include "ginxsom.h"
|
||||
#include "../nostr_core_lib/nostr_core/request_validator.h"
|
||||
|
||||
// Database path (should match main.c)
|
||||
#define DB_PATH "db/ginxsom.db"
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#include <fcgi_stdio.h>
|
||||
#include <sqlite3.h>
|
||||
#include "../nostr_core_lib/cjson/cJSON.h"
|
||||
#include "../nostr_core_lib/nostr_core/nostr_core.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -43,8 +42,67 @@ void handle_head_request(const char* uri);
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// NOTE: Old authentication functions removed - now handled by nostr_core_lib unified system
|
||||
// Use nostr_validate_request() from request_validator.h for all authentication needs
|
||||
// Request validation system - implemented in request_validator.c
|
||||
// Functions implemented in src/request_validator.c
|
||||
|
||||
// NOSTR result constants
|
||||
#define NOSTR_SUCCESS 0
|
||||
#define NOSTR_ERROR_INVALID_JSON -1
|
||||
#define NOSTR_ERROR_MISSING_FIELD -2
|
||||
#define NOSTR_ERROR_INVALID_SIGNATURE -3
|
||||
#define NOSTR_ERROR_INVALID_PUBKEY -4
|
||||
#define NOSTR_ERROR_DATABASE -10
|
||||
#define NOSTR_ERROR_UNAUTHORIZED -11
|
||||
#define NOSTR_ERROR_MEMORY -12
|
||||
|
||||
// NIP-42 modes
|
||||
typedef enum {
|
||||
NIP42_MODE_DISABLED = 0,
|
||||
NIP42_MODE_OPTIONAL = 1,
|
||||
NIP42_MODE_REQUIRED = 2
|
||||
} nip42_mode_t;
|
||||
|
||||
// Request validation types and enums (matching ginxsom usage)
|
||||
typedef struct {
|
||||
const char* operation; // Operation type ("upload", "delete", "list", "publish", "admin")
|
||||
const char* auth_header; // Raw authorization header (optional)
|
||||
cJSON* event; // Parsed NOSTR event for validation (optional)
|
||||
const char* resource_hash; // Resource hash (SHA-256, optional)
|
||||
const char* mime_type; // MIME type (optional)
|
||||
long file_size; // File size (optional)
|
||||
const char* relay_url; // Relay URL for NIP-42 validation (optional)
|
||||
const char* challenge_id; // Challenge ID for NIP-42 verification (optional)
|
||||
int nip42_mode; // NIP-42 mode: 0=disabled, 1=optional, 2=required
|
||||
const char* client_ip; // Client IP address (optional)
|
||||
void* app_context; // Application context (unused, for compatibility)
|
||||
} nostr_request_t;
|
||||
|
||||
typedef struct {
|
||||
int valid; // 0 = invalid/denied, 1 = valid/allowed
|
||||
int error_code; // NOSTR_SUCCESS or specific error code
|
||||
char reason[256]; // Human-readable reason for denial/acceptance
|
||||
char pubkey[65]; // Extracted pubkey from validated event (if available)
|
||||
} nostr_request_result_t;
|
||||
|
||||
// Challenge structure for NIP-42
|
||||
typedef struct {
|
||||
char challenge_id[65];
|
||||
time_t expires_at;
|
||||
} nostr_nip42_challenge_t;
|
||||
|
||||
// Function declarations for nostr_core_lib functions used by ginxsom
|
||||
int nostr_validate_event(cJSON* event);
|
||||
int nostr_validate_event_structure(cJSON* event);
|
||||
int nostr_verify_event_signature(cJSON* event);
|
||||
int nostr_sha256(const unsigned char* data, size_t len, unsigned char* hash);
|
||||
void nostr_bytes_to_hex(const unsigned char* bytes, size_t len, char* hex_out);
|
||||
int nostr_crypto_init(void);
|
||||
|
||||
int nostr_validate_request(const nostr_request_t* request, nostr_request_result_t* result);
|
||||
int nostr_request_validator_init(const char* db_path, const char* app_name);
|
||||
int nostr_auth_rules_enabled(void);
|
||||
void nostr_request_validator_cleanup(void);
|
||||
int nostr_request_validator_generate_nip42_challenge(void* challenge_struct, const char* client_ip);
|
||||
|
||||
// Upload handling
|
||||
void handle_upload_request(void);
|
||||
|
||||
145
src/main.c
145
src/main.c
@@ -16,7 +16,6 @@
|
||||
#include <stdint.h>
|
||||
#include <curl/curl.h>
|
||||
#include "ginxsom.h"
|
||||
#include "../nostr_core_lib/nostr_core/request_validator.h"
|
||||
|
||||
// Debug macros removed
|
||||
|
||||
@@ -311,6 +310,9 @@ int run_interactive_setup(const char* config_path) {
|
||||
void send_error_response(int status_code, const char* error_type, const char* message, const char* details);
|
||||
void log_request(const char* method, const char* uri, const char* auth_status, int status_code);
|
||||
|
||||
// External validator function declarations
|
||||
const char* nostr_request_validator_get_last_violation_type(void);
|
||||
|
||||
// NIP-42 function declarations
|
||||
void handle_auth_challenge_request(void);
|
||||
int get_nip42_mode_config(void);
|
||||
@@ -555,6 +557,7 @@ void send_error_response(int status_code, const char* error_type, const char* me
|
||||
switch (status_code) {
|
||||
case 400: status_text = "Bad Request"; break;
|
||||
case 401: status_text = "Unauthorized"; break;
|
||||
case 403: status_text = "Forbidden"; break;
|
||||
case 409: status_text = "Conflict"; break;
|
||||
case 413: status_text = "Payload Too Large"; break;
|
||||
case 500: status_text = "Internal Server Error"; break;
|
||||
@@ -653,21 +656,41 @@ void handle_list_request(const char* pubkey) {
|
||||
int auth_result = nostr_validate_request(&request, &result);
|
||||
|
||||
if (auth_result != NOSTR_SUCCESS || !result.valid) {
|
||||
const char* violation_type = nostr_request_validator_get_last_violation_type();
|
||||
|
||||
const char* error_type = "authentication_failed";
|
||||
const char* message = "Invalid or expired authentication";
|
||||
const char* details = result.reason[0] ? result.reason : "The provided Nostr event is invalid, expired, or does not authorize this operation";
|
||||
int status_code = 401; // Default to 401 for authentication issues
|
||||
|
||||
// Provide more specific error messages based on the reason
|
||||
if (strstr(result.reason, "whitelist")) {
|
||||
// Determine status code and error type based on violation type
|
||||
if (strcmp(violation_type, "pubkey_blacklist") == 0) {
|
||||
error_type = "access_denied";
|
||||
message = "Access denied by policy";
|
||||
details = "Public key blacklisted";
|
||||
status_code = 403; // Access control policy denial
|
||||
} else if (strcmp(violation_type, "hash_blacklist") == 0) {
|
||||
error_type = "access_denied";
|
||||
message = "Access denied by policy";
|
||||
details = "File hash blacklisted";
|
||||
status_code = 403; // Access control policy denial
|
||||
} else if (strcmp(violation_type, "whitelist_violation") == 0) {
|
||||
error_type = "pubkey_not_whitelisted";
|
||||
message = "Public key not authorized";
|
||||
details = "Public key not whitelisted for this operation";
|
||||
status_code = 403; // Access control policy denial
|
||||
} else if (strstr(result.reason, "whitelist")) {
|
||||
error_type = "pubkey_not_whitelisted";
|
||||
message = "Public key not authorized";
|
||||
status_code = 403; // Access control policy denial
|
||||
} else if (strstr(result.reason, "blacklist")) {
|
||||
error_type = "access_denied";
|
||||
message = "Access denied by policy";
|
||||
status_code = 403; // Access control policy denial
|
||||
}
|
||||
|
||||
send_error_response(401, error_type, message, details);
|
||||
log_request("GET", "/list", "failed", 401);
|
||||
send_error_response(status_code, error_type, message, details);
|
||||
log_request("GET", "/list", "failed", status_code);
|
||||
return;
|
||||
}
|
||||
auth_status = "authenticated";
|
||||
@@ -820,25 +843,52 @@ void handle_delete_request(const char* sha256) {
|
||||
.app_context = NULL
|
||||
};
|
||||
|
||||
// Debug: Print environment variable status
|
||||
char* debug_flag = getenv("GINX_DEBUG");
|
||||
fprintf(stderr, "AUTH DEBUG: GINX_DEBUG=%s\n", debug_flag ? debug_flag : "NOT_SET");
|
||||
|
||||
nostr_request_result_t result;
|
||||
int auth_result = nostr_validate_request(&request, &result);
|
||||
|
||||
// Debug: Print auth result immediately after call
|
||||
fprintf(stderr, "AUTH DEBUG: handle_upload_request - nostr_validate_request returned: %d, result.valid: %d\n", auth_result, result.valid);
|
||||
|
||||
if (auth_result != NOSTR_SUCCESS || !result.valid) {
|
||||
const char* violation_type = nostr_request_validator_get_last_violation_type();
|
||||
|
||||
const char* error_type = "authentication_failed";
|
||||
const char* message = "Invalid or expired authentication";
|
||||
const char* details = result.reason[0] ? result.reason : "The provided Nostr event is invalid, expired, or does not authorize this operation";
|
||||
int status_code = 401; // Default to 401 for authentication issues
|
||||
|
||||
// Provide more specific error messages based on the reason
|
||||
if (strstr(result.reason, "whitelist")) {
|
||||
// Determine status code and error type based on violation type
|
||||
if (strcmp(violation_type, "pubkey_blacklist") == 0) {
|
||||
error_type = "access_denied";
|
||||
message = "Access denied by policy";
|
||||
details = "Public key blacklisted";
|
||||
status_code = 403; // Access control policy denial
|
||||
} else if (strcmp(violation_type, "hash_blacklist") == 0) {
|
||||
error_type = "access_denied";
|
||||
message = "Access denied by policy";
|
||||
details = "File hash blacklisted";
|
||||
status_code = 403; // Access control policy denial
|
||||
} else if (strcmp(violation_type, "whitelist_violation") == 0) {
|
||||
error_type = "pubkey_not_whitelisted";
|
||||
message = "Public key not authorized";
|
||||
details = "Public key not whitelisted for this operation";
|
||||
status_code = 403; // Access control policy denial
|
||||
} else if (strstr(result.reason, "whitelist")) {
|
||||
error_type = "pubkey_not_whitelisted";
|
||||
message = "Public key not authorized";
|
||||
status_code = 403; // Access control policy denial
|
||||
} else if (strstr(result.reason, "blacklist")) {
|
||||
error_type = "access_denied";
|
||||
message = "Access denied by policy";
|
||||
status_code = 403; // Access control policy denial
|
||||
}
|
||||
|
||||
send_error_response(401, error_type, message, details);
|
||||
log_request("DELETE", "/delete", "failed", 401);
|
||||
send_error_response(status_code, error_type, message, details);
|
||||
log_request("DELETE", "/delete", "failed", status_code);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1088,7 +1138,14 @@ void handle_upload_request(void) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Use new unified request validation system
|
||||
// If auth rules are completely disabled, skip all validation and allow upload
|
||||
if (!auth_required) {
|
||||
fprintf(stderr, "AUTH: Authentication rules disabled - skipping all validation and allowing upload\n");
|
||||
// Skip validation and proceed to file processing
|
||||
goto process_file_upload;
|
||||
}
|
||||
|
||||
// Use new unified request validation system (only when auth is required)
|
||||
fprintf(stderr, "AUTH: About to perform authentication validation\r\n");
|
||||
|
||||
// Create request structure for validation
|
||||
@@ -1104,58 +1161,107 @@ void handle_upload_request(void) {
|
||||
};
|
||||
|
||||
nostr_request_result_t result;
|
||||
fprintf(stderr, "UPLOAD_HANDLER: About to call nostr_validate_request for operation='%s'\r\n", request.operation ? request.operation : "NULL");
|
||||
int auth_result = nostr_validate_request(&request, &result);
|
||||
fprintf(stderr, "UPLOAD_HANDLER: nostr_validate_request returned auth_result=%d, result.valid=%d\r\n", auth_result, result.valid);
|
||||
|
||||
// Write debug output to a file for debugging
|
||||
FILE* debug_file = fopen("debug_auth.log", "a");
|
||||
if (debug_file) {
|
||||
fprintf(debug_file, "AUTH: nostr_validate_request returned: %d, valid: %d, reason: %s\n",
|
||||
auth_result, result.valid, result.reason);
|
||||
|
||||
// Validate pubkey before printing to prevent corruption display
|
||||
if (result.pubkey[0] != '\0' && strlen(result.pubkey) == 64) {
|
||||
// Additional validation: ensure pubkey contains only hex characters
|
||||
int valid_hex = 1;
|
||||
for (int i = 0; i < 64; i++) {
|
||||
char c = result.pubkey[i];
|
||||
if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))) {
|
||||
valid_hex = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (valid_hex) {
|
||||
fprintf(debug_file, "AUTH: pubkey extracted: '%s'\n", result.pubkey);
|
||||
} else {
|
||||
fprintf(debug_file, "AUTH: pubkey extracted: <CORRUPTED_DATA>\n");
|
||||
}
|
||||
} else {
|
||||
fprintf(debug_file, "AUTH: pubkey extracted: <NONE>\n");
|
||||
}
|
||||
|
||||
fprintf(debug_file, "AUTH: resource_hash: '%s'\n", request.resource_hash ? request.resource_hash : "NULL");
|
||||
fprintf(debug_file, "AUTH: operation: '%s'\n", request.operation ? request.operation : "NULL");
|
||||
fprintf(debug_file, "AUTH: auth_header present: %s\n", auth_header ? "YES" : "NO");
|
||||
fclose(debug_file);
|
||||
}
|
||||
|
||||
// If auth header is provided, validate it regardless of require_auth setting
|
||||
if (auth_header && (auth_result != NOSTR_SUCCESS || !result.valid)) {
|
||||
// Authentication failed - reject the request
|
||||
if (auth_result != NOSTR_SUCCESS || !result.valid) {
|
||||
free(file_data);
|
||||
|
||||
// Get violation type from validator for precise status code mapping
|
||||
const char* violation_type = nostr_request_validator_get_last_violation_type();
|
||||
|
||||
// Use the detailed reason from the authentication system
|
||||
const char* error_type = "authentication_failed";
|
||||
const char* message = "Authentication failed";
|
||||
const char* details = result.reason[0] ? result.reason : "The request failed authentication";
|
||||
int status_code = 401; // Default to 401 for authentication issues
|
||||
|
||||
// Provide more specific error types based on the reason content
|
||||
if (strstr(result.reason, "whitelist")) {
|
||||
// Determine status code and error type based on violation type
|
||||
if (strcmp(violation_type, "pubkey_blacklist") == 0) {
|
||||
error_type = "access_denied";
|
||||
message = "Access denied by policy";
|
||||
details = "Public key blacklisted";
|
||||
status_code = 403; // Access control policy denial
|
||||
} else if (strcmp(violation_type, "hash_blacklist") == 0) {
|
||||
error_type = "access_denied";
|
||||
message = "Access denied by policy";
|
||||
details = "File hash blacklisted";
|
||||
status_code = 403; // Access control policy denial
|
||||
} else if (strcmp(violation_type, "whitelist_violation") == 0) {
|
||||
error_type = "pubkey_not_whitelisted";
|
||||
message = "Public key not authorized";
|
||||
details = "Public key not whitelisted for this operation";
|
||||
status_code = 403; // Access control policy denial
|
||||
} else if (strstr(result.reason, "whitelist")) {
|
||||
error_type = "pubkey_not_whitelisted";
|
||||
message = "Public key not authorized";
|
||||
status_code = 403; // Access control policy denial
|
||||
} else if (strstr(result.reason, "blacklist")) {
|
||||
error_type = "access_denied";
|
||||
message = "Access denied by policy";
|
||||
status_code = 403; // Access control policy denial
|
||||
} else if (strstr(result.reason, "expired")) {
|
||||
error_type = "event_expired";
|
||||
message = "Authentication event expired";
|
||||
status_code = 401; // Authentication format/validity issue
|
||||
} else if (strstr(result.reason, "signature")) {
|
||||
error_type = "invalid_signature";
|
||||
message = "Invalid cryptographic signature";
|
||||
status_code = 401; // Authentication format/validity issue
|
||||
} else if (strstr(result.reason, "size")) {
|
||||
error_type = "file_too_large";
|
||||
message = "File size exceeds policy limits";
|
||||
status_code = 403; // Access control policy denial
|
||||
} else if (strstr(result.reason, "MIME") || strstr(result.reason, "mime")) {
|
||||
error_type = "unsupported_type";
|
||||
message = "File type not allowed by policy";
|
||||
status_code = 403; // Access control policy denial
|
||||
} else if (strstr(result.reason, "hash")) {
|
||||
error_type = "hash_blocked";
|
||||
message = "File hash blocked by policy";
|
||||
status_code = 403; // Access control policy denial
|
||||
} else if (strstr(result.reason, "format") || strstr(result.reason, "invalid")) {
|
||||
error_type = "invalid_format";
|
||||
message = "Invalid authorization format";
|
||||
status_code = 401; // Authentication format/validity issue
|
||||
}
|
||||
|
||||
send_error_response(401, error_type, message, details);
|
||||
log_request("PUT", "/upload", "auth_failed", 401);
|
||||
send_error_response(status_code, error_type, message, details);
|
||||
log_request("PUT", "/upload", "auth_failed", status_code);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1169,6 +1275,7 @@ void handle_upload_request(void) {
|
||||
|
||||
|
||||
|
||||
process_file_upload:
|
||||
// Get dimensions from in-memory buffer before saving file
|
||||
int width = 0, height = 0;
|
||||
nip94_get_dimensions(file_data, content_length, content_type, &width, &height);
|
||||
@@ -1391,8 +1498,6 @@ void handle_auth_challenge_request(void) {
|
||||
|
||||
|
||||
int main(void) {
|
||||
fprintf(stderr, "STARTUP: FastCGI application starting up\r\n");
|
||||
fflush(stderr);
|
||||
|
||||
// Initialize server configuration and identity
|
||||
// Try file-based config first, then fall back to database config
|
||||
@@ -1431,7 +1536,9 @@ int main(void) {
|
||||
|
||||
// Initialize request validator system
|
||||
fprintf(stderr, "STARTUP: Initializing request validator system...\r\n");
|
||||
if (nostr_request_validator_init(DB_PATH, "ginxsom") != NOSTR_SUCCESS) {
|
||||
int validator_init_result = nostr_request_validator_init(DB_PATH, "ginxsom");
|
||||
fprintf(stderr, "MAIN: validator init return code: %d\r\n", validator_init_result);
|
||||
if (validator_init_result != NOSTR_SUCCESS) {
|
||||
fprintf(stderr, "FATAL ERROR: Failed to initialize request validator system\r\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
840
src/request_validator.c
Normal file
840
src/request_validator.c
Normal file
@@ -0,0 +1,840 @@
|
||||
/*
|
||||
* Ginxsom Request Validator - Integrated Authentication System
|
||||
*
|
||||
* Provides complete request validation including:
|
||||
* - Protocol validation via nostr_core_lib (signatures, pubkey extraction, NIP-42)
|
||||
* - Database-driven authorization rules (whitelist, blacklist, size limits)
|
||||
* - Memory caching for performance
|
||||
* - SQLite integration for ginxsom-specific needs
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <time.h>
|
||||
#include <sqlite3.h>
|
||||
#include "../nostr_core_lib/nostr_core/nostr_common.h"
|
||||
#include "../nostr_core_lib/nostr_core/nip001.h"
|
||||
#include "../nostr_core_lib/nostr_core/nip042.h"
|
||||
#include "../nostr_core_lib/nostr_core/utils.h"
|
||||
#include "../nostr_core_lib/cjson/cJSON.h"
|
||||
#include "ginxsom.h"
|
||||
|
||||
// Additional error codes for ginxsom-specific functionality
|
||||
#define NOSTR_ERROR_CRYPTO_INIT -100
|
||||
#define NOSTR_ERROR_AUTH_REQUIRED -101
|
||||
#define NOSTR_ERROR_NIP42_DISABLED -102
|
||||
#define NOSTR_ERROR_EVENT_EXPIRED -103
|
||||
|
||||
// Database path (consistent with main.c)
|
||||
#define DB_PATH "db/ginxsom.db"
|
||||
|
||||
//=============================================================================
|
||||
// DATA STRUCTURES
|
||||
//=============================================================================
|
||||
|
||||
// Cached configuration structure
|
||||
typedef struct {
|
||||
int auth_required; // Whether authentication is required
|
||||
long max_file_size; // Maximum file size in bytes
|
||||
int admin_enabled; // Whether admin interface is enabled
|
||||
char admin_pubkey[65]; // Admin public key
|
||||
int nip42_mode; // NIP-42 authentication mode
|
||||
time_t cache_expires; // When cache expires
|
||||
int cache_valid; // Whether cache is valid
|
||||
} auth_config_cache_t;
|
||||
|
||||
//=============================================================================
|
||||
// GLOBAL STATE
|
||||
//=============================================================================
|
||||
|
||||
static auth_config_cache_t g_auth_cache = {0};
|
||||
static int g_validator_initialized = 0;
|
||||
|
||||
// Last rule violation details for status code mapping
|
||||
struct {
|
||||
char violation_type[100]; // "pubkey_blacklist", "hash_blacklist", "whitelist_violation", etc.
|
||||
char reason[500]; // specific reason string
|
||||
} g_last_rule_violation = {0};
|
||||
|
||||
/**
|
||||
* Helper function for consistent debug logging to our debug.log file
|
||||
*/
|
||||
static void validator_debug_log(const char* message) {
|
||||
FILE* debug_log = fopen("logs/app/debug.log", "a");
|
||||
if (debug_log) {
|
||||
fprintf(debug_log, "%ld %s", (long)time(NULL), message);
|
||||
fclose(debug_log);
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// FORWARD DECLARATIONS
|
||||
//=============================================================================
|
||||
|
||||
static int reload_auth_config(void);
|
||||
static int parse_authorization_header(const char* auth_header, char* event_json, size_t json_size);
|
||||
static int extract_pubkey_from_event(cJSON* event, char* pubkey_buffer, size_t buffer_size);
|
||||
static int validate_blossom_event(cJSON* event, const char* expected_hash, const char* method);
|
||||
static int validate_nip42_event(cJSON* event, const char* relay_url, const char* challenge_id);
|
||||
static int check_database_auth_rules(const char* pubkey, const char* operation, const char* resource_hash);
|
||||
void nostr_request_validator_clear_violation(void);
|
||||
|
||||
//=============================================================================
|
||||
// MAIN API FUNCTIONS
|
||||
//=============================================================================
|
||||
|
||||
/**
|
||||
* Initialize the ginxsom request validator system
|
||||
*/
|
||||
int nostr_request_validator_init(const char* db_path, const char* app_name) {
|
||||
// Mark db_path as unused to suppress warning - it's for future use
|
||||
(void)db_path;
|
||||
(void)app_name;
|
||||
|
||||
if (g_validator_initialized) {
|
||||
return NOSTR_SUCCESS; // Already initialized
|
||||
}
|
||||
|
||||
// Initialize nostr_core_lib if not already done
|
||||
if (nostr_crypto_init() != NOSTR_SUCCESS) {
|
||||
validator_debug_log("VALIDATOR: Failed to initialize nostr crypto system\n");
|
||||
return NOSTR_ERROR_CRYPTO_INIT;
|
||||
}
|
||||
|
||||
// Load initial configuration from database
|
||||
int result = reload_auth_config();
|
||||
if (result != NOSTR_SUCCESS) {
|
||||
validator_debug_log("VALIDATOR: Failed to load configuration from database\n");
|
||||
return result;
|
||||
}
|
||||
|
||||
g_validator_initialized = 1;
|
||||
validator_debug_log("VALIDATOR: Request validator initialized successfully\n");
|
||||
return NOSTR_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if authentication rules are enabled
|
||||
*/
|
||||
int nostr_auth_rules_enabled(void) {
|
||||
// Reload config if cache expired
|
||||
if (!g_auth_cache.cache_valid || time(NULL) > g_auth_cache.cache_expires) {
|
||||
reload_auth_config();
|
||||
}
|
||||
|
||||
return g_auth_cache.auth_required;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main request validation function - this is the primary entry point
|
||||
*/
|
||||
int nostr_validate_request(const nostr_request_t* request, nostr_request_result_t* result) {
|
||||
// Clear previous violation details
|
||||
nostr_request_validator_clear_violation();
|
||||
|
||||
// Simple test debug log
|
||||
validator_debug_log("VALIDATOR_DEBUG: nostr_validate_request() was called\n");
|
||||
validator_debug_log("VALIDATOR_DEBUG: Starting request validation\n");
|
||||
|
||||
if (!g_validator_initialized) {
|
||||
validator_debug_log("VALIDATOR_DEBUG: STEP 1 FAILED - System not initialized\n");
|
||||
return NOSTR_ERROR_INVALID_INPUT;
|
||||
}
|
||||
validator_debug_log("VALIDATOR_DEBUG: STEP 1 PASSED - System initialized\n");
|
||||
|
||||
if (!request || !result) {
|
||||
validator_debug_log("VALIDATOR_DEBUG: STEP 2 FAILED - Invalid input parameters\n");
|
||||
return NOSTR_ERROR_INVALID_INPUT;
|
||||
}
|
||||
validator_debug_log("VALIDATOR_DEBUG: STEP 2 PASSED - Input parameters valid\n");
|
||||
|
||||
// Initialize result structure
|
||||
memset(result, 0, sizeof(nostr_request_result_t));
|
||||
result->valid = 1; // Default allow
|
||||
result->error_code = NOSTR_SUCCESS;
|
||||
strcpy(result->reason, "No validation required");
|
||||
|
||||
// Reload config if needed
|
||||
if (!g_auth_cache.cache_valid || time(NULL) > g_auth_cache.cache_expires) {
|
||||
validator_debug_log("VALIDATOR_DEBUG: Reloading configuration cache\n");
|
||||
reload_auth_config();
|
||||
}
|
||||
char config_msg[256];
|
||||
sprintf(config_msg, "VALIDATOR_DEBUG: STEP 3 PASSED - Configuration loaded (auth_required=%d)\n", g_auth_cache.auth_required);
|
||||
validator_debug_log(config_msg);
|
||||
|
||||
// If no auth header provided and auth not required, allow
|
||||
if (!request->auth_header) {
|
||||
if (!g_auth_cache.auth_required) {
|
||||
validator_debug_log("VALIDATOR_DEBUG: STEP 4 PASSED - No auth required, allowing request\n");
|
||||
strcpy(result->reason, "Authentication not required");
|
||||
return NOSTR_SUCCESS;
|
||||
} else {
|
||||
validator_debug_log("VALIDATOR_DEBUG: STEP 4 FAILED - Auth required but no header provided\n");
|
||||
result->valid = 0;
|
||||
result->error_code = NOSTR_ERROR_AUTH_REQUIRED;
|
||||
strcpy(result->reason, "Authentication required but not provided");
|
||||
return NOSTR_SUCCESS;
|
||||
}
|
||||
}
|
||||
char header_msg[110];
|
||||
sprintf(header_msg, "VALIDATOR_DEBUG: STEP 4 PASSED - Auth header provided: %.50s...\n", request->auth_header);
|
||||
validator_debug_log(header_msg);
|
||||
|
||||
// Parse authorization header
|
||||
char event_json[4096];
|
||||
int parse_result = parse_authorization_header(request->auth_header, event_json, sizeof(event_json));
|
||||
if (parse_result != NOSTR_SUCCESS) {
|
||||
char parse_msg[256];
|
||||
sprintf(parse_msg, "VALIDATOR_DEBUG: STEP 5 FAILED - Failed to parse authorization header (error=%d)\n", parse_result);
|
||||
validator_debug_log(parse_msg);
|
||||
result->valid = 0;
|
||||
result->error_code = parse_result;
|
||||
strcpy(result->reason, "Failed to parse authorization header");
|
||||
return NOSTR_SUCCESS;
|
||||
}
|
||||
char parse_success_msg[512];
|
||||
sprintf(parse_success_msg, "VALIDATOR_DEBUG: STEP 5 PASSED - Authorization header parsed, JSON: %.100s...\n", event_json);
|
||||
validator_debug_log(parse_success_msg);
|
||||
|
||||
// Parse JSON event
|
||||
cJSON* event = cJSON_Parse(event_json);
|
||||
if (!event) {
|
||||
validator_debug_log("VALIDATOR_DEBUG: STEP 6 FAILED - Invalid JSON in authorization\n");
|
||||
result->valid = 0;
|
||||
result->error_code = NOSTR_ERROR_EVENT_INVALID_CONTENT;
|
||||
strcpy(result->reason, "Invalid JSON in authorization");
|
||||
return NOSTR_SUCCESS;
|
||||
}
|
||||
validator_debug_log("VALIDATOR_DEBUG: STEP 6 PASSED - JSON parsed successfully\n");
|
||||
|
||||
// Validate NOSTR event structure and signature using nostr_core_lib
|
||||
int validation_result = nostr_validate_event(event);
|
||||
if (validation_result != NOSTR_SUCCESS) {
|
||||
char validation_msg[256];
|
||||
sprintf(validation_msg, "VALIDATOR_DEBUG: STEP 7 FAILED - NOSTR event validation failed (error=%d)\n", validation_result);
|
||||
validator_debug_log(validation_msg);
|
||||
result->valid = 0;
|
||||
result->error_code = validation_result;
|
||||
strcpy(result->reason, "NOSTR event validation failed");
|
||||
cJSON_Delete(event);
|
||||
return NOSTR_SUCCESS;
|
||||
}
|
||||
validator_debug_log("VALIDATOR_DEBUG: STEP 7 PASSED - NOSTR event validation succeeded\n");
|
||||
|
||||
// Extract pubkey for authorization checks
|
||||
char extracted_pubkey[65] = {0};
|
||||
int extract_result = extract_pubkey_from_event(event, extracted_pubkey, sizeof(extracted_pubkey));
|
||||
if (extract_result != NOSTR_SUCCESS) {
|
||||
char extract_msg[256];
|
||||
sprintf(extract_msg, "VALIDATOR_DEBUG: STEP 8 FAILED - Failed to extract pubkey from event (error=%d)\n", extract_result);
|
||||
validator_debug_log(extract_msg);
|
||||
result->valid = 0;
|
||||
result->error_code = extract_result;
|
||||
strcpy(result->reason, "Failed to extract pubkey from event");
|
||||
cJSON_Delete(event);
|
||||
return NOSTR_SUCCESS;
|
||||
}
|
||||
char extract_success_msg[256];
|
||||
sprintf(extract_success_msg, "VALIDATOR_DEBUG: STEP 8 PASSED - Extracted pubkey: %s\n", extracted_pubkey);
|
||||
validator_debug_log(extract_success_msg);
|
||||
|
||||
// Get event kind to determine authentication method
|
||||
cJSON* kind_json = cJSON_GetObjectItem(event, "kind");
|
||||
int event_kind = 0;
|
||||
if (kind_json && cJSON_IsNumber(kind_json)) {
|
||||
event_kind = cJSON_GetNumberValue(kind_json);
|
||||
}
|
||||
char kind_msg[256];
|
||||
sprintf(kind_msg, "VALIDATOR_DEBUG: STEP 9 PASSED - Event kind: %d\n", event_kind);
|
||||
validator_debug_log(kind_msg);
|
||||
|
||||
// Handle different authentication methods
|
||||
if (event_kind == NOSTR_NIP42_AUTH_EVENT_KIND) {
|
||||
char nip42_msg[256];
|
||||
sprintf(nip42_msg, "VALIDATOR_DEBUG: STEP 10 - Processing NIP-42 authentication (kind %d)\n", NOSTR_NIP42_AUTH_EVENT_KIND);
|
||||
validator_debug_log(nip42_msg);
|
||||
|
||||
// NIP-42 authentication (kind 22242)
|
||||
if (request->nip42_mode == 0) {
|
||||
validator_debug_log("VALIDATOR_DEBUG: STEP 10 FAILED - NIP-42 authentication is disabled\n");
|
||||
result->valid = 0;
|
||||
result->error_code = NOSTR_ERROR_NIP42_DISABLED;
|
||||
strcpy(result->reason, "NIP-42 authentication is disabled");
|
||||
cJSON_Delete(event);
|
||||
return NOSTR_SUCCESS;
|
||||
}
|
||||
|
||||
if (!request->relay_url || !request->challenge_id) {
|
||||
validator_debug_log("VALIDATOR_DEBUG: STEP 10 FAILED - NIP-42 requires relay_url and challenge_id\n");
|
||||
result->valid = 0;
|
||||
result->error_code = NOSTR_ERROR_NIP42_NOT_CONFIGURED;
|
||||
strcpy(result->reason, "NIP-42 authentication requires relay_url and challenge_id");
|
||||
cJSON_Delete(event);
|
||||
return NOSTR_SUCCESS;
|
||||
}
|
||||
|
||||
int nip42_result = validate_nip42_event(event, request->relay_url, request->challenge_id);
|
||||
if (nip42_result != NOSTR_SUCCESS) {
|
||||
char nip42_fail_msg[256];
|
||||
sprintf(nip42_fail_msg, "VALIDATOR_DEBUG: STEP 10 FAILED - NIP-42 validation failed (error=%d)\n", nip42_result);
|
||||
validator_debug_log(nip42_fail_msg);
|
||||
result->valid = 0;
|
||||
result->error_code = nip42_result;
|
||||
strcpy(result->reason, "NIP-42 authentication failed");
|
||||
cJSON_Delete(event);
|
||||
return NOSTR_SUCCESS;
|
||||
}
|
||||
validator_debug_log("VALIDATOR_DEBUG: STEP 10 PASSED - NIP-42 authentication succeeded\n");
|
||||
strcpy(result->reason, "NIP-42 authentication passed");
|
||||
|
||||
} else if (event_kind == 24242) {
|
||||
validator_debug_log("VALIDATOR_DEBUG: STEP 10 - Processing Blossom authentication (kind 24242)\n");
|
||||
// Blossom protocol authentication (kind 24242)
|
||||
if (request->operation && request->resource_hash) {
|
||||
char blossom_valid_msg[512];
|
||||
sprintf(blossom_valid_msg, "VALIDATOR_DEBUG: Validating Blossom event for operation='%s', hash='%s'\n",
|
||||
request->operation ? request->operation : "NULL",
|
||||
request->resource_hash ? request->resource_hash : "NULL");
|
||||
validator_debug_log(blossom_valid_msg);
|
||||
|
||||
int blossom_result = validate_blossom_event(event, request->resource_hash, request->operation);
|
||||
if (blossom_result != NOSTR_SUCCESS) {
|
||||
char blossom_fail_msg[256];
|
||||
sprintf(blossom_fail_msg, "VALIDATOR_DEBUG: STEP 10 FAILED - Blossom validation failed (error=%d)\n", blossom_result);
|
||||
validator_debug_log(blossom_fail_msg);
|
||||
result->valid = 0;
|
||||
result->error_code = blossom_result;
|
||||
strcpy(result->reason, "Blossom event does not authorize this operation");
|
||||
cJSON_Delete(event);
|
||||
return NOSTR_SUCCESS;
|
||||
}
|
||||
} else {
|
||||
validator_debug_log("VALIDATOR_DEBUG: Skipping Blossom validation (no operation/hash specified)\n");
|
||||
}
|
||||
validator_debug_log("VALIDATOR_DEBUG: STEP 10 PASSED - Blossom authentication succeeded\n");
|
||||
strcpy(result->reason, "Blossom authentication passed");
|
||||
|
||||
} else {
|
||||
char unsupported_msg[256];
|
||||
sprintf(unsupported_msg, "VALIDATOR_DEBUG: STEP 10 FAILED - Unsupported event kind: %d\n", event_kind);
|
||||
validator_debug_log(unsupported_msg);
|
||||
result->valid = 0;
|
||||
result->error_code = NOSTR_ERROR_EVENT_INVALID_KIND;
|
||||
strcpy(result->reason, "Unsupported event kind for authentication");
|
||||
cJSON_Delete(event);
|
||||
return NOSTR_SUCCESS;
|
||||
}
|
||||
|
||||
// Copy validated pubkey to result
|
||||
if (strlen(extracted_pubkey) == 64) {
|
||||
strncpy(result->pubkey, extracted_pubkey, 64);
|
||||
result->pubkey[64] = '\0';
|
||||
validator_debug_log("VALIDATOR_DEBUG: STEP 11 PASSED - Pubkey copied to result\n");
|
||||
} else {
|
||||
char pubkey_warning_msg[256];
|
||||
sprintf(pubkey_warning_msg, "VALIDATOR_DEBUG: STEP 11 WARNING - Invalid pubkey length: %zu\n", strlen(extracted_pubkey));
|
||||
validator_debug_log(pubkey_warning_msg);
|
||||
}
|
||||
|
||||
cJSON_Delete(event);
|
||||
|
||||
// STEP 12 PASSED: Protocol validation complete - continue to database rule evaluation
|
||||
validator_debug_log("VALIDATOR_DEBUG: STEP 12 PASSED - Protocol validation complete, proceeding to rule evaluation\n");
|
||||
|
||||
// Check if auth rules are enabled
|
||||
if (!g_auth_cache.auth_required) {
|
||||
validator_debug_log("VALIDATOR_DEBUG: STEP 13 PASSED - Auth rules disabled, allowing request\n");
|
||||
result->valid = 1;
|
||||
result->error_code = NOSTR_SUCCESS;
|
||||
strcpy(result->reason, "Authentication rules disabled");
|
||||
return NOSTR_SUCCESS;
|
||||
}
|
||||
validator_debug_log("VALIDATOR_DEBUG: STEP 13 PASSED - Auth rules enabled, checking database rules\n");
|
||||
|
||||
// Check database rules for authorization
|
||||
int rules_result = check_database_auth_rules(extracted_pubkey, request->operation, request->resource_hash);
|
||||
if (rules_result != NOSTR_SUCCESS) {
|
||||
validator_debug_log("VALIDATOR_DEBUG: STEP 14 FAILED - Database rules denied request\n");
|
||||
result->valid = 0;
|
||||
result->error_code = rules_result;
|
||||
// Determine specific failure reason based on rules evaluation
|
||||
if (rules_result == NOSTR_ERROR_AUTH_REQUIRED) {
|
||||
// This can be pubkey blacklist or whitelist violation - set generic message
|
||||
// The specific reason will be detailed in the database check function
|
||||
strcpy(result->reason, "Request denied by authorization rules");
|
||||
} else {
|
||||
strcpy(result->reason, "Authorization error");
|
||||
}
|
||||
return NOSTR_SUCCESS;
|
||||
}
|
||||
validator_debug_log("VALIDATOR_DEBUG: STEP 14 PASSED - Database rules allow request\n");
|
||||
|
||||
// All validations passed
|
||||
result->valid = 1;
|
||||
result->error_code = NOSTR_SUCCESS;
|
||||
validator_debug_log("VALIDATOR_DEBUG: STEP 15 PASSED - All validations complete, request ALLOWED\n");
|
||||
return NOSTR_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate NIP-42 challenge for clients
|
||||
*/
|
||||
int nostr_request_validator_generate_nip42_challenge(void* challenge_struct, const char* client_ip) {
|
||||
// Mark client_ip as unused to suppress warning - it's for future enhancement
|
||||
(void)client_ip;
|
||||
|
||||
// Use nostr_core_lib NIP-42 functionality
|
||||
char challenge_id[65];
|
||||
int result = nostr_nip42_generate_challenge(challenge_id, 32);
|
||||
if (result != NOSTR_SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Fill challenge structure (assuming it's a compatible structure)
|
||||
// This is a simplified implementation - adjust based on actual structure needs
|
||||
if (challenge_struct) {
|
||||
// Cast to appropriate structure and fill fields
|
||||
// For now, just return success
|
||||
}
|
||||
|
||||
return NOSTR_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last rule violation type for status code mapping
|
||||
*/
|
||||
const char* nostr_request_validator_get_last_violation_type(void) {
|
||||
return g_last_rule_violation.violation_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the last rule violation details
|
||||
*/
|
||||
void nostr_request_validator_clear_violation(void) {
|
||||
memset(&g_last_rule_violation, 0, sizeof(g_last_rule_violation));
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup request validator resources
|
||||
*/
|
||||
void nostr_request_validator_cleanup(void) {
|
||||
g_validator_initialized = 0;
|
||||
memset(&g_auth_cache, 0, sizeof(g_auth_cache));
|
||||
nostr_request_validator_clear_violation();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// HELPER FUNCTIONS
|
||||
//=============================================================================
|
||||
|
||||
/**
|
||||
* Reload authentication configuration from database
|
||||
*/
|
||||
static int reload_auth_config(void) {
|
||||
sqlite3* db = NULL;
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
int rc;
|
||||
|
||||
// Clear cache
|
||||
memset(&g_auth_cache, 0, sizeof(g_auth_cache));
|
||||
|
||||
// Open database
|
||||
rc = sqlite3_open_v2(DB_PATH, &db, SQLITE_OPEN_READONLY, NULL);
|
||||
if (rc != SQLITE_OK) {
|
||||
validator_debug_log("VALIDATOR: Could not open database\n");
|
||||
// Use defaults
|
||||
g_auth_cache.auth_required = 0;
|
||||
g_auth_cache.max_file_size = 104857600; // 100MB
|
||||
g_auth_cache.admin_enabled = 0;
|
||||
g_auth_cache.nip42_mode = 1; // Optional
|
||||
g_auth_cache.cache_expires = time(NULL) + 300; // 5 minutes
|
||||
g_auth_cache.cache_valid = 1;
|
||||
return NOSTR_SUCCESS;
|
||||
}
|
||||
|
||||
// Load configuration values from server_config table
|
||||
const char* server_sql = "SELECT key, value FROM server_config WHERE key IN ('require_auth', 'max_file_size', 'admin_enabled', 'admin_pubkey')";
|
||||
rc = sqlite3_prepare_v2(db, server_sql, -1, &stmt, NULL);
|
||||
|
||||
if (rc == SQLITE_OK) {
|
||||
while (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
const char* key = (const char*)sqlite3_column_text(stmt, 0);
|
||||
const char* value = (const char*)sqlite3_column_text(stmt, 1);
|
||||
|
||||
if (!key || !value) continue;
|
||||
|
||||
if (strcmp(key, "require_auth") == 0) {
|
||||
g_auth_cache.auth_required = (strcmp(value, "true") == 0) ? 1 : 0;
|
||||
} else if (strcmp(key, "max_file_size") == 0) {
|
||||
g_auth_cache.max_file_size = atol(value);
|
||||
} else if (strcmp(key, "admin_enabled") == 0) {
|
||||
g_auth_cache.admin_enabled = (strcmp(value, "true") == 0) ? 1 : 0;
|
||||
} else if (strcmp(key, "admin_pubkey") == 0) {
|
||||
strncpy(g_auth_cache.admin_pubkey, value, sizeof(g_auth_cache.admin_pubkey) - 1);
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
|
||||
// Load auth-specific configuration from auth_config table
|
||||
const char* auth_sql = "SELECT key, value FROM auth_config WHERE key IN ('auth_rules_enabled', 'require_nip42_auth')";
|
||||
rc = sqlite3_prepare_v2(db, auth_sql, -1, &stmt, NULL);
|
||||
|
||||
if (rc == SQLITE_OK) {
|
||||
while (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
const char* key = (const char*)sqlite3_column_text(stmt, 0);
|
||||
const char* value = (const char*)sqlite3_column_text(stmt, 1);
|
||||
|
||||
if (!key || !value) continue;
|
||||
|
||||
if (strcmp(key, "auth_rules_enabled") == 0) {
|
||||
// Override auth_required with auth_rules_enabled if present
|
||||
g_auth_cache.auth_required = (strcmp(value, "true") == 0) ? 1 : 0;
|
||||
} else if (strcmp(key, "require_nip42_auth") == 0) {
|
||||
if (strcmp(value, "false") == 0) {
|
||||
g_auth_cache.nip42_mode = 0;
|
||||
} else if (strcmp(value, "required") == 0) {
|
||||
g_auth_cache.nip42_mode = 2;
|
||||
} else {
|
||||
g_auth_cache.nip42_mode = 1; // Optional
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
|
||||
sqlite3_close(db);
|
||||
|
||||
// Set cache expiration (5 minutes from now)
|
||||
g_auth_cache.cache_expires = time(NULL) + 300;
|
||||
g_auth_cache.cache_valid = 1;
|
||||
|
||||
// Set defaults for missing values
|
||||
if (g_auth_cache.max_file_size == 0) {
|
||||
g_auth_cache.max_file_size = 104857600; // 100MB
|
||||
}
|
||||
|
||||
// Note: This is the final debug statement, no need to log it to our debug file as it's just informational
|
||||
fprintf(stderr, "VALIDATOR: Configuration loaded - auth_required: %d, max_file_size: %ld, nip42_mode: %d\n",
|
||||
g_auth_cache.auth_required, g_auth_cache.max_file_size, g_auth_cache.nip42_mode);
|
||||
|
||||
return NOSTR_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse NOSTR authorization header (base64 decode)
|
||||
*/
|
||||
static int parse_authorization_header(const char* auth_header, char* event_json, size_t json_size) {
|
||||
if (!auth_header || !event_json) {
|
||||
return NOSTR_ERROR_INVALID_INPUT;
|
||||
}
|
||||
|
||||
// Check for "Nostr " prefix (case-insensitive)
|
||||
const char* prefix = "nostr ";
|
||||
size_t prefix_len = strlen(prefix);
|
||||
|
||||
if (strncasecmp(auth_header, prefix, prefix_len) != 0) {
|
||||
return NOSTR_ERROR_INVALID_INPUT;
|
||||
}
|
||||
|
||||
// Extract base64 encoded event after "Nostr "
|
||||
const char* base64_event = auth_header + prefix_len;
|
||||
|
||||
// Decode base64 to JSON using nostr_core_lib base64 decode
|
||||
unsigned char decoded_buffer[4096];
|
||||
size_t decoded_len = base64_decode(base64_event, decoded_buffer);
|
||||
|
||||
if (decoded_len == 0 || decoded_len >= json_size) {
|
||||
return NOSTR_ERROR_INVALID_INPUT;
|
||||
}
|
||||
|
||||
// Copy decoded JSON to output buffer
|
||||
memcpy(event_json, decoded_buffer, decoded_len);
|
||||
event_json[decoded_len] = '\0';
|
||||
|
||||
return NOSTR_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract pubkey from validated NOSTR event
|
||||
*/
|
||||
static int extract_pubkey_from_event(cJSON* event, char* pubkey_buffer, size_t buffer_size) {
|
||||
if (!event || !pubkey_buffer || buffer_size < 65) {
|
||||
return NOSTR_ERROR_INVALID_INPUT;
|
||||
}
|
||||
|
||||
// Initialize buffer to prevent corruption
|
||||
memset(pubkey_buffer, 0, buffer_size);
|
||||
|
||||
cJSON* pubkey_json = cJSON_GetObjectItem(event, "pubkey");
|
||||
if (!pubkey_json || !cJSON_IsString(pubkey_json)) {
|
||||
return NOSTR_ERROR_EVENT_INVALID_PUBKEY;
|
||||
}
|
||||
|
||||
const char* pubkey = cJSON_GetStringValue(pubkey_json);
|
||||
if (!pubkey) {
|
||||
return NOSTR_ERROR_EVENT_INVALID_PUBKEY;
|
||||
}
|
||||
|
||||
// Check the raw pubkey string before validation
|
||||
size_t pubkey_len = strlen(pubkey);
|
||||
if (pubkey_len != 64) {
|
||||
return NOSTR_ERROR_EVENT_INVALID_PUBKEY;
|
||||
}
|
||||
|
||||
// Validate that pubkey contains only hex characters before copying
|
||||
for (int i = 0; i < 64; i++) {
|
||||
char c = pubkey[i];
|
||||
if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))) {
|
||||
return NOSTR_ERROR_EVENT_INVALID_PUBKEY;
|
||||
}
|
||||
}
|
||||
|
||||
// Safe copy with explicit length and null termination
|
||||
memcpy(pubkey_buffer, pubkey, 64);
|
||||
pubkey_buffer[64] = '\0';
|
||||
|
||||
return NOSTR_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate Blossom protocol event (kind 24242)
|
||||
*/
|
||||
static int validate_blossom_event(cJSON* event, const char* expected_hash, const char* method) {
|
||||
if (!event) {
|
||||
return NOSTR_ERROR_INVALID_INPUT;
|
||||
}
|
||||
|
||||
// Check event kind (must be 24242 for Blossom operations)
|
||||
cJSON* kind_json = cJSON_GetObjectItem(event, "kind");
|
||||
if (!kind_json || !cJSON_IsNumber(kind_json)) {
|
||||
return NOSTR_ERROR_EVENT_INVALID_CONTENT;
|
||||
}
|
||||
|
||||
int kind = cJSON_GetNumberValue(kind_json);
|
||||
if (kind != 24242) {
|
||||
return NOSTR_ERROR_EVENT_INVALID_CONTENT;
|
||||
}
|
||||
|
||||
// Look for required tags if method and hash are specified
|
||||
if (method || expected_hash) {
|
||||
cJSON* tags = cJSON_GetObjectItem(event, "tags");
|
||||
if (!tags || !cJSON_IsArray(tags)) {
|
||||
return NOSTR_ERROR_EVENT_INVALID_CONTENT;
|
||||
}
|
||||
|
||||
int found_method = (method == NULL);
|
||||
int found_hash = (expected_hash == NULL);
|
||||
time_t expiration = 0;
|
||||
|
||||
cJSON* tag = NULL;
|
||||
cJSON_ArrayForEach(tag, tags) {
|
||||
if (!cJSON_IsArray(tag)) continue;
|
||||
|
||||
cJSON* tag_name = cJSON_GetArrayItem(tag, 0);
|
||||
if (!tag_name || !cJSON_IsString(tag_name)) continue;
|
||||
|
||||
const char* tag_name_str = cJSON_GetStringValue(tag_name);
|
||||
|
||||
if (strcmp(tag_name_str, "t") == 0 && method) {
|
||||
cJSON* method_value = cJSON_GetArrayItem(tag, 1);
|
||||
if (method_value && cJSON_IsString(method_value)) {
|
||||
const char* event_method = cJSON_GetStringValue(method_value);
|
||||
if (strcmp(event_method, method) == 0) {
|
||||
found_method = 1;
|
||||
}
|
||||
}
|
||||
} else if (strcmp(tag_name_str, "x") == 0 && expected_hash) {
|
||||
cJSON* hash_value = cJSON_GetArrayItem(tag, 1);
|
||||
if (hash_value && cJSON_IsString(hash_value)) {
|
||||
const char* event_hash = cJSON_GetStringValue(hash_value);
|
||||
if (strcmp(event_hash, expected_hash) == 0) {
|
||||
found_hash = 1;
|
||||
}
|
||||
}
|
||||
} else if (strcmp(tag_name_str, "expiration") == 0) {
|
||||
cJSON* exp_value = cJSON_GetArrayItem(tag, 1);
|
||||
if (exp_value && cJSON_IsString(exp_value)) {
|
||||
expiration = (time_t)atol(cJSON_GetStringValue(exp_value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_method || !found_hash) {
|
||||
return NOSTR_ERROR_EVENT_INVALID_CONTENT;
|
||||
}
|
||||
|
||||
// Check expiration
|
||||
time_t now = time(NULL);
|
||||
if (expiration > 0 && now > expiration) {
|
||||
return NOSTR_ERROR_EVENT_EXPIRED;
|
||||
}
|
||||
}
|
||||
|
||||
return NOSTR_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check database authentication rules for the request
|
||||
* Implements the 6-step rule evaluation engine from AUTH_API.md
|
||||
*/
|
||||
static int check_database_auth_rules(const char* pubkey, const char* operation, const char* resource_hash) {
|
||||
sqlite3* db = NULL;
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
int rc;
|
||||
|
||||
if (!pubkey) {
|
||||
validator_debug_log("VALIDATOR_DEBUG: RULES ENGINE - Missing pubkey for rule evaluation\n");
|
||||
return NOSTR_ERROR_INVALID_INPUT;
|
||||
}
|
||||
|
||||
char rules_msg[256];
|
||||
sprintf(rules_msg, "VALIDATOR_DEBUG: RULES ENGINE - Checking rules for pubkey=%.32s..., operation=%s\n",
|
||||
pubkey, operation ? operation : "NULL");
|
||||
validator_debug_log(rules_msg);
|
||||
|
||||
// Open database
|
||||
rc = sqlite3_open_v2(DB_PATH, &db, SQLITE_OPEN_READONLY, NULL);
|
||||
if (rc != SQLITE_OK) {
|
||||
validator_debug_log("VALIDATOR_DEBUG: RULES ENGINE - Failed to open database\n");
|
||||
return NOSTR_SUCCESS; // Default allow on DB error
|
||||
}
|
||||
|
||||
// Step 1: Check pubkey blacklist (highest priority)
|
||||
const char* blacklist_sql = "SELECT rule_type, description FROM auth_rules WHERE rule_type = 'pubkey_blacklist' AND rule_target = ? AND operation = ? AND enabled = 1 ORDER BY priority LIMIT 1";
|
||||
rc = sqlite3_prepare_v2(db, blacklist_sql, -1, &stmt, NULL);
|
||||
if (rc == SQLITE_OK) {
|
||||
sqlite3_bind_text(stmt, 1, pubkey, -1, SQLITE_STATIC);
|
||||
sqlite3_bind_text(stmt, 2, operation ? operation : "", -1, SQLITE_STATIC);
|
||||
|
||||
if (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
const char* description = (const char*)sqlite3_column_text(stmt, 1);
|
||||
validator_debug_log("VALIDATOR_DEBUG: RULES ENGINE - STEP 1 FAILED - Pubkey blacklisted\n");
|
||||
char blacklist_msg[256];
|
||||
sprintf(blacklist_msg, "VALIDATOR_DEBUG: RULES ENGINE - Blacklist rule matched: %s\n", description ? description : "Unknown");
|
||||
validator_debug_log(blacklist_msg);
|
||||
|
||||
// Set specific violation details for status code mapping
|
||||
strcpy(g_last_rule_violation.violation_type, "pubkey_blacklist");
|
||||
sprintf(g_last_rule_violation.reason, "%s: Public key blacklisted", description ? description : "TEST_PUBKEY_BLACKLIST");
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
sqlite3_close(db);
|
||||
return NOSTR_ERROR_AUTH_REQUIRED;
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
validator_debug_log("VALIDATOR_DEBUG: RULES ENGINE - STEP 1 PASSED - Pubkey not blacklisted\n");
|
||||
|
||||
// Step 2: Check hash blacklist
|
||||
if (resource_hash) {
|
||||
const char* hash_blacklist_sql = "SELECT rule_type, description FROM auth_rules WHERE rule_type = 'hash_blacklist' AND rule_target = ? AND operation = ? AND enabled = 1 ORDER BY priority LIMIT 1";
|
||||
rc = sqlite3_prepare_v2(db, hash_blacklist_sql, -1, &stmt, NULL);
|
||||
if (rc == SQLITE_OK) {
|
||||
sqlite3_bind_text(stmt, 1, resource_hash, -1, SQLITE_STATIC);
|
||||
sqlite3_bind_text(stmt, 2, operation ? operation : "", -1, SQLITE_STATIC);
|
||||
|
||||
if (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
const char* description = (const char*)sqlite3_column_text(stmt, 1);
|
||||
validator_debug_log("VALIDATOR_DEBUG: RULES ENGINE - STEP 2 FAILED - Hash blacklisted\n");
|
||||
char hash_blacklist_msg[256];
|
||||
sprintf(hash_blacklist_msg, "VALIDATOR_DEBUG: RULES ENGINE - Hash blacklist rule matched: %s\n", description ? description : "Unknown");
|
||||
validator_debug_log(hash_blacklist_msg);
|
||||
|
||||
// Set specific violation details for status code mapping
|
||||
strcpy(g_last_rule_violation.violation_type, "hash_blacklist");
|
||||
sprintf(g_last_rule_violation.reason, "%s: File hash blacklisted", description ? description : "TEST_HASH_BLACKLIST");
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
sqlite3_close(db);
|
||||
return NOSTR_ERROR_AUTH_REQUIRED;
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
validator_debug_log("VALIDATOR_DEBUG: RULES ENGINE - STEP 2 PASSED - Hash not blacklisted\n");
|
||||
} else {
|
||||
validator_debug_log("VALIDATOR_DEBUG: RULES ENGINE - STEP 2 SKIPPED - No resource hash provided\n");
|
||||
}
|
||||
|
||||
// Step 3: Check pubkey whitelist
|
||||
const char* whitelist_sql = "SELECT rule_type, description FROM auth_rules WHERE rule_type = 'pubkey_whitelist' AND rule_target = ? AND operation = ? AND enabled = 1 ORDER BY priority LIMIT 1";
|
||||
rc = sqlite3_prepare_v2(db, whitelist_sql, -1, &stmt, NULL);
|
||||
if (rc == SQLITE_OK) {
|
||||
sqlite3_bind_text(stmt, 1, pubkey, -1, SQLITE_STATIC);
|
||||
sqlite3_bind_text(stmt, 2, operation ? operation : "", -1, SQLITE_STATIC);
|
||||
|
||||
if (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
const char* description = (const char*)sqlite3_column_text(stmt, 1);
|
||||
validator_debug_log("VALIDATOR_DEBUG: RULES ENGINE - STEP 3 PASSED - Pubkey whitelisted\n");
|
||||
char whitelist_msg[256];
|
||||
sprintf(whitelist_msg, "VALIDATOR_DEBUG: RULES ENGINE - Whitelist rule matched: %s\n", description ? description : "Unknown");
|
||||
validator_debug_log(whitelist_msg);
|
||||
sqlite3_finalize(stmt);
|
||||
sqlite3_close(db);
|
||||
return NOSTR_SUCCESS; // Allow whitelisted pubkey
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
validator_debug_log("VALIDATOR_DEBUG: RULES ENGINE - STEP 3 FAILED - Pubkey not whitelisted\n");
|
||||
|
||||
// Step 4: Check if any whitelist rules exist - if yes, deny by default
|
||||
const char* whitelist_exists_sql = "SELECT COUNT(*) FROM auth_rules WHERE rule_type = 'pubkey_whitelist' AND operation = ? AND enabled = 1 LIMIT 1";
|
||||
rc = sqlite3_prepare_v2(db, whitelist_exists_sql, -1, &stmt, NULL);
|
||||
if (rc == SQLITE_OK) {
|
||||
sqlite3_bind_text(stmt, 1, operation ? operation : "", -1, SQLITE_STATIC);
|
||||
|
||||
if (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
int whitelist_count = sqlite3_column_int(stmt, 0);
|
||||
if (whitelist_count > 0) {
|
||||
validator_debug_log("VALIDATOR_DEBUG: RULES ENGINE - STEP 4 FAILED - Whitelist exists but pubkey not in it\n");
|
||||
|
||||
// Set specific violation details for status code mapping
|
||||
strcpy(g_last_rule_violation.violation_type, "whitelist_violation");
|
||||
strcpy(g_last_rule_violation.reason, "Public key not whitelisted for this operation");
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
sqlite3_close(db);
|
||||
return NOSTR_ERROR_AUTH_REQUIRED;
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
validator_debug_log("VALIDATOR_DEBUG: RULES ENGINE - STEP 4 PASSED - No whitelist restrictions apply\n");
|
||||
|
||||
sqlite3_close(db);
|
||||
validator_debug_log("VALIDATOR_DEBUG: RULES ENGINE - STEP 5 PASSED - All rule checks completed, default ALLOW\n");
|
||||
return NOSTR_SUCCESS; // Default allow if no restrictive rules matched
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate NIP-42 authentication event (kind 22242)
|
||||
*/
|
||||
static int validate_nip42_event(cJSON* event, const char* relay_url, const char* challenge_id) {
|
||||
if (!event || !relay_url || !challenge_id) {
|
||||
return NOSTR_ERROR_INVALID_INPUT;
|
||||
}
|
||||
|
||||
// Check event kind (must be 22242 for NIP-42)
|
||||
cJSON* kind_json = cJSON_GetObjectItem(event, "kind");
|
||||
if (!kind_json || !cJSON_IsNumber(kind_json)) {
|
||||
return NOSTR_ERROR_EVENT_INVALID_CONTENT;
|
||||
}
|
||||
|
||||
int kind = cJSON_GetNumberValue(kind_json);
|
||||
if (kind != NOSTR_NIP42_AUTH_EVENT_KIND) {
|
||||
return NOSTR_ERROR_EVENT_INVALID_CONTENT;
|
||||
}
|
||||
|
||||
// Use the existing NIP-42 verification from nostr_core_lib
|
||||
int verification_result = nostr_nip42_verify_auth_event(event, challenge_id,
|
||||
relay_url, NOSTR_NIP42_DEFAULT_TIME_TOLERANCE);
|
||||
if (verification_result != NOSTR_SUCCESS) {
|
||||
return verification_result;
|
||||
}
|
||||
|
||||
return NOSTR_SUCCESS;
|
||||
}
|
||||
1
test_auth_disabled.txt
Normal file
1
test_auth_disabled.txt
Normal file
@@ -0,0 +1 @@
|
||||
test content
|
||||
1
test_file.txt
Normal file
1
test_file.txt
Normal file
@@ -0,0 +1 @@
|
||||
test content
|
||||
1
test_simple.txt
Normal file
1
test_simple.txt
Normal file
@@ -0,0 +1 @@
|
||||
test_content_for_whitelist
|
||||
1
test_whitelist_debug.txt
Normal file
1
test_whitelist_debug.txt
Normal file
@@ -0,0 +1 @@
|
||||
test_whitelist_debug
|
||||
@@ -52,51 +52,38 @@ record_test_result() {
|
||||
fi
|
||||
}
|
||||
|
||||
echo "=== Ginxsom Authentication System Test Suite ==="
|
||||
echo "Testing unified nostr_core_lib authentication integration"
|
||||
echo "Timestamp: $(date -Iseconds)"
|
||||
echo
|
||||
|
||||
# Check prerequisites
|
||||
echo "[INFO] Checking prerequisites..."
|
||||
for cmd in nak curl jq sqlite3; do
|
||||
if ! command -v $cmd &> /dev/null; then
|
||||
echo "[ERROR] $cmd command not found"
|
||||
echo "$cmd command not found"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# Check if server is running
|
||||
if ! curl -s -f "${SERVER_URL}/" > /dev/null 2>&1; then
|
||||
echo "[ERROR] Server not running at $SERVER_URL"
|
||||
echo "[INFO] Start with: ./restart-all.sh"
|
||||
echo "Server not running at $SERVER_URL"
|
||||
echo "Start with: ./restart-all.sh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if database exists
|
||||
if [[ ! -f "$DB_PATH" ]]; then
|
||||
echo "[ERROR] Database not found at $DB_PATH"
|
||||
echo "Database not found at $DB_PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[SUCCESS] All prerequisites met"
|
||||
echo
|
||||
|
||||
# Setup test environment and auth rules ONCE at the beginning
|
||||
echo "=== Setting up authentication rules ==="
|
||||
mkdir -p "$TEST_DIR"
|
||||
|
||||
# Enable authentication rules
|
||||
sqlite3 "$DB_PATH" "INSERT OR REPLACE INTO auth_config (key, value) VALUES ('auth_rules_enabled', 'true');"
|
||||
|
||||
# Delete ALL existing auth rules and cache (clean slate)
|
||||
echo "Deleting all existing auth rules..."
|
||||
sqlite3 "$DB_PATH" "DELETE FROM auth_rules;"
|
||||
sqlite3 "$DB_PATH" "DELETE FROM auth_cache;"
|
||||
|
||||
# Set up all test rules at once
|
||||
echo "Creating test auth rules..."
|
||||
|
||||
# 1. Whitelist for TEST_USER1 for upload operations (priority 10)
|
||||
sqlite3 "$DB_PATH" "INSERT INTO auth_rules (rule_type, rule_target, operation, priority, enabled, description)
|
||||
VALUES ('pubkey_whitelist', '$TEST_USER1_PUBKEY', 'upload', 10, 1, 'TEST_WHITELIST_USER1');"
|
||||
@@ -111,13 +98,8 @@ BLACKLISTED_HASH=$(sha256sum "$TEST_DIR/blacklisted_file.txt" | cut -d' ' -f1)
|
||||
sqlite3 "$DB_PATH" "INSERT INTO auth_rules (rule_type, rule_target, operation, priority, enabled, description)
|
||||
VALUES ('hash_blacklist', '$BLACKLISTED_HASH', 'upload', 5, 1, 'TEST_HASH_BLACKLIST');"
|
||||
|
||||
echo "Hash blacklisted: $BLACKLISTED_HASH"
|
||||
|
||||
# Display the rules we created
|
||||
echo
|
||||
echo "Auth rules created:"
|
||||
sqlite3 "$DB_PATH" -header -column "SELECT rule_type, rule_target, operation, priority, enabled, description FROM auth_rules WHERE description LIKE 'TEST_%' ORDER BY priority;"
|
||||
echo
|
||||
# (Auth rules configured for testing)
|
||||
|
||||
# Helper functions
|
||||
create_test_file() {
|
||||
@@ -173,8 +155,6 @@ test_upload() {
|
||||
}
|
||||
|
||||
# Run the tests
|
||||
echo "=== Running Authentication Tests ==="
|
||||
echo
|
||||
|
||||
# Test 1: Whitelisted user (should succeed)
|
||||
test_file1=$(create_test_file "whitelisted_upload.txt" "Content from whitelisted user")
|
||||
@@ -194,20 +174,15 @@ RANDOM_PRIVKEY="abcd1234567890abcd1234567890abcd1234567890abcd1234567890abcd1234
|
||||
test_upload "Test 4: Random User (No Rules)" "$RANDOM_PRIVKEY" "$test_file4" "ANY"
|
||||
|
||||
# Test 5: Test with authentication disabled
|
||||
echo "=== Test 5: Authentication Disabled ==="
|
||||
echo "Disabling authentication rules..."
|
||||
sqlite3 "$DB_PATH" "INSERT OR REPLACE INTO auth_config (key, value) VALUES ('auth_rules_enabled', 'false');"
|
||||
|
||||
test_file5=$(create_test_file "auth_disabled.txt" "Upload with auth disabled")
|
||||
test_upload "Test 5: Upload with Authentication Disabled" "$TEST_USER2_PRIVKEY" "$test_file5" "200"
|
||||
|
||||
# Re-enable authentication
|
||||
echo "Re-enabling authentication rules..."
|
||||
sqlite3 "$DB_PATH" "INSERT OR REPLACE INTO auth_config (key, value) VALUES ('auth_rules_enabled', 'true');"
|
||||
echo
|
||||
|
||||
# Test failure modes - comprehensive edge case testing
|
||||
echo "=== Test 6: Invalid Authorization Header Formats ==="
|
||||
|
||||
# Helper function for failure mode tests
|
||||
test_failure_mode() {
|
||||
@@ -242,7 +217,7 @@ test_failure_mode "Test 6b: Invalid Authorization Prefix" "Bearer invalidtoken12
|
||||
# Test 6c: Invalid Base64 in Authorization
|
||||
test_failure_mode "Test 6c: Invalid Base64 in Authorization" "Nostr invalid!@#base64"
|
||||
|
||||
echo "=== Test 7: Malformed JSON Events ==="
|
||||
# Test malformed JSON events
|
||||
|
||||
# Test 7a: Invalid JSON Structure
|
||||
malformed_json='{"kind":24242,"content":"","created_at":' # Incomplete JSON
|
||||
@@ -254,10 +229,9 @@ missing_fields_json='{"kind":24242,"content":"","created_at":1234567890,"tags":[
|
||||
missing_fields_b64=$(echo -n "$missing_fields_json" | base64 -w 0)
|
||||
test_failure_mode "Test 7b: Missing Required Fields (no pubkey)" "Nostr $missing_fields_b64"
|
||||
|
||||
echo "=== Test 8: Invalid Key Formats ==="
|
||||
# Test invalid key formats
|
||||
|
||||
# Test 8a: Short Public Key
|
||||
echo "Test 8a: Short Public Key (32 chars instead of 64)"
|
||||
echo "short_key_test" > "$TEST_DIR/short_key.txt"
|
||||
file_hash=$(sha256sum "$TEST_DIR/short_key.txt" | cut -d' ' -f1)
|
||||
short_pubkey="1234567890abcdef1234567890abcdef" # 32 chars instead of 64
|
||||
|
||||
1
tests/auth_test_tmp/debug_whitelisted.txt
Normal file
1
tests/auth_test_tmp/debug_whitelisted.txt
Normal file
@@ -0,0 +1 @@
|
||||
Content from whitelisted user for test
|
||||
@@ -1 +1 @@
|
||||
3fb6a0ea1d337bd09f1f88f65f124174ad7161dd5ea0fae74c0dd0b0db43a24e
|
||||
1c4c3b202bbe84869d7e688fd4abccf9f46a57073df1c0e3b515d4810d9b6525
|
||||
|
||||
127
tests/debug_auth.sh
Executable file
127
tests/debug_auth.sh
Executable file
@@ -0,0 +1,127 @@
|
||||
#!/bin/bash
|
||||
|
||||
# debug_auth.sh - Simplified authentication test for Test 1: Whitelisted User Upload
|
||||
# Isolates the first failing test case to debug the pubkey extraction issue
|
||||
|
||||
# Configuration
|
||||
SERVER_URL="http://localhost:9001"
|
||||
UPLOAD_ENDPOINT="${SERVER_URL}/upload"
|
||||
DB_PATH="db/ginxsom.db"
|
||||
TEST_DIR="tests/auth_test_tmp"
|
||||
|
||||
# Test keys (same as Test 1)
|
||||
TEST_USER1_PRIVKEY="5c0c523f52a5b6fad39ed2403092df8cebc36318b39383bca6c00808626fab3a"
|
||||
TEST_USER1_PUBKEY="87d3561f19b74adbe8bf840682992466068830a9d8c36b4a0c99d36f826cb6cb"
|
||||
|
||||
echo "=== Debug Authentication Test ==="
|
||||
echo "Testing: Whitelisted User Upload"
|
||||
echo "Expected: HTTP 200 (Allowed)"
|
||||
echo "Server: $SERVER_URL"
|
||||
echo
|
||||
|
||||
# Check prerequisites
|
||||
echo "Checking prerequisites..."
|
||||
for cmd in nak curl jq sqlite3; do
|
||||
if ! command -v $cmd &> /dev/null; then
|
||||
echo "[ERROR] $cmd command not found"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# Check if server is running
|
||||
if ! curl -s -f "${SERVER_URL}/" > /dev/null 2>&1; then
|
||||
echo "Server not running at $SERVER_URL"
|
||||
echo "Start with: ./restart-all.sh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if database exists
|
||||
if [[ ! -f "$DB_PATH" ]]; then
|
||||
echo "Database not found at $DB_PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Prerequisites OK"
|
||||
echo
|
||||
|
||||
# Setup test environment
|
||||
echo "=== Setting up authentication rules ==="
|
||||
mkdir -p "$TEST_DIR"
|
||||
|
||||
# Enable authentication rules
|
||||
sqlite3 "$DB_PATH" "INSERT OR REPLACE INTO auth_config (key, value) VALUES ('auth_rules_enabled', 'true');"
|
||||
|
||||
# Clean slate
|
||||
sqlite3 "$DB_PATH" "DELETE FROM auth_rules;"
|
||||
sqlite3 "$DB_PATH" "DELETE FROM auth_cache;"
|
||||
|
||||
# Create the whitelist rule (same as Test 1)
|
||||
echo "Creating whitelist rule for pubkey: $TEST_USER1_PUBKEY"
|
||||
sqlite3 "$DB_PATH" "INSERT INTO auth_rules (rule_type, rule_target, operation, priority, enabled, description)
|
||||
VALUES ('pubkey_whitelist', '$TEST_USER1_PUBKEY', 'upload', 10, 1, 'TEST_WHITELIST_USER1');"
|
||||
|
||||
# Verify rule creation
|
||||
echo
|
||||
echo "Current auth rules:"
|
||||
sqlite3 "$DB_PATH" -header -column "SELECT rule_type, rule_target, operation, priority, enabled, description FROM auth_rules ORDER BY priority;"
|
||||
|
||||
# Helper function to create auth event (exactly like auth_test.sh)
|
||||
create_auth_event() {
|
||||
local privkey="$1"
|
||||
local operation="$2"
|
||||
local hash="$3"
|
||||
local expiration_offset="${4:-3600}" # 1 hour default
|
||||
|
||||
local expiration=$(date -d "+${expiration_offset} seconds" +%s)
|
||||
|
||||
local event_args=(-k 24242 -c "" --tag "t=$operation" --tag "expiration=$expiration" --sec "$privkey")
|
||||
|
||||
if [[ -n "$hash" ]]; then
|
||||
event_args+=(--tag "x=$hash")
|
||||
fi
|
||||
|
||||
nak event "${event_args[@]}"
|
||||
}
|
||||
|
||||
# Create test file
|
||||
echo
|
||||
echo "=== Running Test 1: Whitelisted User Upload ==="
|
||||
test_file="$TEST_DIR/debug_whitelisted.txt"
|
||||
echo "Content from whitelisted user for test" > "$test_file"
|
||||
|
||||
# Get file hash
|
||||
file_hash=$(sha256sum "$test_file" | cut -d' ' -f1)
|
||||
|
||||
# Create auth event
|
||||
event=$(create_auth_event "$TEST_USER1_PRIVKEY" "upload" "$file_hash")
|
||||
|
||||
# Base64 encode for Authorization header
|
||||
auth_header="Nostr $(echo "$event" | base64 -w 0)"
|
||||
|
||||
# Make the upload request
|
||||
response_file=$(mktemp)
|
||||
http_status=$(curl -s -w "%{http_code}" \
|
||||
-H "Authorization: $auth_header" \
|
||||
-H "Content-Type: text/plain" \
|
||||
--data-binary "@$test_file" \
|
||||
-X PUT "$UPLOAD_ENDPOINT" \
|
||||
-o "$response_file" 2>/dev/null)
|
||||
|
||||
echo "HTTP Status: $http_status"
|
||||
if [[ "$http_status" == "200" ]]; then
|
||||
echo "✅ PASSED - Upload allowed as expected"
|
||||
else
|
||||
echo "❌ FAILED - Expected 200, got $http_status"
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "Clean up: rm -f \"$test_file\""
|
||||
|
||||
# Cleanup
|
||||
rm -f "$response_file"
|
||||
|
||||
echo
|
||||
echo "=== Debug Test Complete ==="
|
||||
echo "1. Check ./restart-all.sh --follow for detailed logs"
|
||||
echo "2. Verify pubkey extraction in logs/app/debug.log"
|
||||
echo "3. Clean up: sqlite3 db/ginxsom.db \"DELETE FROM auth_rules WHERE description LIKE 'TEST_%';\""
|
||||
Reference in New Issue
Block a user