v0.1.8 - Removed cache functionality for now

This commit is contained in:
Your Name
2025-11-13 10:59:14 -04:00
parent 455aab1eac
commit c1b615de32
8 changed files with 120 additions and 68 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -68,19 +68,6 @@ CREATE TABLE IF NOT EXISTS auth_rules (
UNIQUE(rule_type, rule_target, operation) UNIQUE(rule_type, rule_target, operation)
); );
-- Cache table for authentication decisions (5-minute TTL)
CREATE TABLE IF NOT EXISTS auth_rules_cache (
cache_key TEXT PRIMARY KEY NOT NULL, -- SHA-256 hash of request parameters
decision INTEGER NOT NULL, -- 1 = allow, 0 = deny
reason TEXT, -- Reason for decision
pubkey TEXT, -- Public key from request
operation TEXT, -- Operation type
resource_hash TEXT, -- Resource hash (if applicable)
created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')),
expires_at INTEGER NOT NULL, -- Expiration timestamp
CHECK (decision IN (0, 1))
);
-- Indexes for performance optimization -- Indexes for performance optimization
CREATE INDEX IF NOT EXISTS idx_auth_rules_type_target ON auth_rules(rule_type, rule_target); CREATE INDEX IF NOT EXISTS idx_auth_rules_type_target ON auth_rules(rule_type, rule_target);
@@ -89,9 +76,6 @@ CREATE INDEX IF NOT EXISTS idx_auth_rules_enabled ON auth_rules(enabled);
CREATE INDEX IF NOT EXISTS idx_auth_rules_priority ON auth_rules(priority); CREATE INDEX IF NOT EXISTS idx_auth_rules_priority ON auth_rules(priority);
CREATE INDEX IF NOT EXISTS idx_auth_rules_type_operation ON auth_rules(rule_type, operation, enabled); CREATE INDEX IF NOT EXISTS idx_auth_rules_type_operation ON auth_rules(rule_type, operation, enabled);
-- Index for cache expiration cleanup
CREATE INDEX IF NOT EXISTS idx_auth_cache_expires ON auth_rules_cache(expires_at);
CREATE INDEX IF NOT EXISTS idx_auth_cache_pubkey ON auth_rules_cache(pubkey);
-- View for storage statistics -- View for storage statistics
CREATE VIEW IF NOT EXISTS storage_stats AS CREATE VIEW IF NOT EXISTS storage_stats AS

View File

@@ -10,8 +10,8 @@
// Version information (auto-updated by build system) // Version information (auto-updated by build system)
#define VERSION_MAJOR 0 #define VERSION_MAJOR 0
#define VERSION_MINOR 1 #define VERSION_MINOR 1
#define VERSION_PATCH 7 #define VERSION_PATCH 8
#define VERSION "v0.1.7" #define VERSION "v0.1.8"
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>

View File

@@ -115,7 +115,7 @@ static int validate_nip42_event(cJSON *event, const char *relay_url,
const char *challenge_id); const char *challenge_id);
static int validate_admin_event(cJSON *event, const char *method, const char *endpoint); static int validate_admin_event(cJSON *event, const char *method, const char *endpoint);
static int check_database_auth_rules(const char *pubkey, const char *operation, static int check_database_auth_rules(const char *pubkey, const char *operation,
const char *resource_hash); const char *resource_hash, const char *mime_type);
void nostr_request_validator_clear_violation(void); void nostr_request_validator_clear_violation(void);
// NIP-42 challenge management functions // NIP-42 challenge management functions
@@ -820,7 +820,7 @@ int nostr_validate_unified_request(const nostr_unified_request_t *request,
} }
int rules_result = check_database_auth_rules( int rules_result = check_database_auth_rules(
extracted_pubkey, request->operation, hash_for_rules); extracted_pubkey, request->operation, hash_for_rules, request->mime_type);
if (rules_result != NOSTR_SUCCESS) { if (rules_result != NOSTR_SUCCESS) {
validator_debug_log( validator_debug_log(
"VALIDATOR_DEBUG: STEP 14 FAILED - Database rules denied request\n"); "VALIDATOR_DEBUG: STEP 14 FAILED - Database rules denied request\n");
@@ -1316,7 +1316,7 @@ static int validate_blossom_event(cJSON *event, const char *expected_hash,
* Implements the 6-step rule evaluation engine from AUTH_API.md * Implements the 6-step rule evaluation engine from AUTH_API.md
*/ */
static int check_database_auth_rules(const char *pubkey, const char *operation, static int check_database_auth_rules(const char *pubkey, const char *operation,
const char *resource_hash) { const char *resource_hash, const char *mime_type) {
sqlite3 *db = NULL; sqlite3 *db = NULL;
sqlite3_stmt *stmt = NULL; sqlite3_stmt *stmt = NULL;
int rc; int rc;
@@ -1330,8 +1330,8 @@ static int check_database_auth_rules(const char *pubkey, const char *operation,
char rules_msg[256]; char rules_msg[256];
sprintf(rules_msg, sprintf(rules_msg,
"VALIDATOR_DEBUG: RULES ENGINE - Checking rules for pubkey=%.32s..., " "VALIDATOR_DEBUG: RULES ENGINE - Checking rules for pubkey=%.32s..., "
"operation=%s\n", "operation=%s, mime_type=%s\n",
pubkey, operation ? operation : "NULL"); pubkey, operation ? operation : "NULL", mime_type ? mime_type : "NULL");
validator_debug_log(rules_msg); validator_debug_log(rules_msg);
// Open database // Open database
@@ -1418,7 +1418,49 @@ static int check_database_auth_rules(const char *pubkey, const char *operation,
"resource hash provided\n"); "resource hash provided\n");
} }
// Step 3: Check pubkey whitelist // Step 3: Check MIME type blacklist
if (mime_type) {
// Match both exact MIME type and wildcard patterns (e.g., 'image/*')
const char *mime_blacklist_sql =
"SELECT rule_type, description FROM auth_rules WHERE rule_type = "
"'mime_blacklist' AND (rule_target = ? OR rule_target LIKE '%/*' AND ? LIKE REPLACE(rule_target, '*', '%')) AND (operation = ? OR operation = '*') AND enabled = "
"1 ORDER BY priority LIMIT 1";
rc = sqlite3_prepare_v2(db, mime_blacklist_sql, -1, &stmt, NULL);
if (rc == SQLITE_OK) {
sqlite3_bind_text(stmt, 1, mime_type, -1, SQLITE_STATIC);
sqlite3_bind_text(stmt, 2, mime_type, -1, SQLITE_STATIC);
sqlite3_bind_text(stmt, 3, 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 FAILED - "
"MIME type blacklisted\n");
char mime_blacklist_msg[256];
sprintf(
mime_blacklist_msg,
"VALIDATOR_DEBUG: RULES ENGINE - MIME blacklist rule matched: %s\n",
description ? description : "Unknown");
validator_debug_log(mime_blacklist_msg);
// Set specific violation details for status code mapping
strcpy(g_last_rule_violation.violation_type, "mime_blacklist");
sprintf(g_last_rule_violation.reason, "%s: MIME type blacklisted",
description ? description : "TEST_MIME_BLACKLIST");
sqlite3_finalize(stmt);
sqlite3_close(db);
return NOSTR_ERROR_AUTH_REQUIRED;
}
sqlite3_finalize(stmt);
}
validator_debug_log("VALIDATOR_DEBUG: RULES ENGINE - STEP 3 PASSED - MIME "
"type not blacklisted\n");
} else {
validator_debug_log("VALIDATOR_DEBUG: RULES ENGINE - STEP 3 SKIPPED - No "
"MIME type provided\n");
}
// Step 4: Check pubkey whitelist
// Match both exact operation and wildcard '*' // Match both exact operation and wildcard '*'
const char *whitelist_sql = const char *whitelist_sql =
"SELECT rule_type, description FROM auth_rules WHERE rule_type = " "SELECT rule_type, description FROM auth_rules WHERE rule_type = "
@@ -1447,7 +1489,72 @@ static int check_database_auth_rules(const char *pubkey, const char *operation,
validator_debug_log("VALIDATOR_DEBUG: RULES ENGINE - STEP 3 FAILED - Pubkey " validator_debug_log("VALIDATOR_DEBUG: RULES ENGINE - STEP 3 FAILED - Pubkey "
"not whitelisted\n"); "not whitelisted\n");
// Step 4: Check if any whitelist rules exist - if yes, deny by default // Step 5: Check MIME type whitelist (only if not already denied)
if (mime_type) {
// Match both exact MIME type and wildcard patterns (e.g., 'image/*')
const char *mime_whitelist_sql =
"SELECT rule_type, description FROM auth_rules WHERE rule_type = "
"'mime_whitelist' AND (rule_target = ? OR rule_target LIKE '%/*' AND ? LIKE REPLACE(rule_target, '*', '%')) AND (operation = ? OR operation = '*') AND enabled = "
"1 ORDER BY priority LIMIT 1";
rc = sqlite3_prepare_v2(db, mime_whitelist_sql, -1, &stmt, NULL);
if (rc == SQLITE_OK) {
sqlite3_bind_text(stmt, 1, mime_type, -1, SQLITE_STATIC);
sqlite3_bind_text(stmt, 2, mime_type, -1, SQLITE_STATIC);
sqlite3_bind_text(stmt, 3, 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 5 PASSED - "
"MIME type whitelisted\n");
char mime_whitelist_msg[256];
sprintf(mime_whitelist_msg,
"VALIDATOR_DEBUG: RULES ENGINE - MIME whitelist rule matched: %s\n",
description ? description : "Unknown");
validator_debug_log(mime_whitelist_msg);
sqlite3_finalize(stmt);
sqlite3_close(db);
return NOSTR_SUCCESS; // Allow whitelisted MIME type
}
sqlite3_finalize(stmt);
}
validator_debug_log("VALIDATOR_DEBUG: RULES ENGINE - STEP 5 FAILED - MIME "
"type not whitelisted\n");
} else {
validator_debug_log("VALIDATOR_DEBUG: RULES ENGINE - STEP 5 SKIPPED - No "
"MIME type provided\n");
}
// Step 6: Check if any MIME whitelist rules exist - if yes, deny by default
// Match both exact operation and wildcard '*'
const char *mime_whitelist_exists_sql =
"SELECT COUNT(*) FROM auth_rules WHERE rule_type = 'mime_whitelist' "
"AND (operation = ? OR operation = '*') AND enabled = 1 LIMIT 1";
rc = sqlite3_prepare_v2(db, mime_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 mime_whitelist_count = sqlite3_column_int(stmt, 0);
if (mime_whitelist_count > 0) {
validator_debug_log("VALIDATOR_DEBUG: RULES ENGINE - STEP 6 FAILED - "
"MIME whitelist exists but type not in it\n");
// Set specific violation details for status code mapping
strcpy(g_last_rule_violation.violation_type, "mime_whitelist_violation");
strcpy(g_last_rule_violation.reason,
"MIME type 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 6 PASSED - No "
"MIME whitelist restrictions apply\n");
// Step 7: Check if any whitelist rules exist - if yes, deny by default
// Match both exact operation and wildcard '*' // Match both exact operation and wildcard '*'
const char *whitelist_exists_sql = const char *whitelist_exists_sql =
"SELECT COUNT(*) FROM auth_rules WHERE rule_type = 'pubkey_whitelist' " "SELECT COUNT(*) FROM auth_rules WHERE rule_type = 'pubkey_whitelist' "
@@ -1478,7 +1585,7 @@ static int check_database_auth_rules(const char *pubkey, const char *operation,
"whitelist restrictions apply\n"); "whitelist restrictions apply\n");
sqlite3_close(db); sqlite3_close(db);
validator_debug_log("VALIDATOR_DEBUG: RULES ENGINE - STEP 5 PASSED - All " validator_debug_log("VALIDATOR_DEBUG: RULES ENGINE - STEP 7 PASSED - All "
"rule checks completed, default ALLOW\n"); "rule checks completed, default ALLOW\n");
return NOSTR_SUCCESS; // Default allow if no restrictive rules matched return NOSTR_SUCCESS; // Default allow if no restrictive rules matched
} }

View File

@@ -132,7 +132,6 @@ test_upload() {
# Clean up any existing rules from previous tests # Clean up any existing rules from previous tests
echo "Cleaning up existing auth rules..." echo "Cleaning up existing auth rules..."
sqlite3 "$DB_PATH" "DELETE FROM auth_rules;" 2>/dev/null sqlite3 "$DB_PATH" "DELETE FROM auth_rules;" 2>/dev/null
sqlite3 "$DB_PATH" "DELETE FROM auth_rules_cache;" 2>/dev/null
# Enable authentication rules # Enable authentication rules
echo "Enabling authentication rules..." echo "Enabling authentication rules..."
@@ -180,7 +179,6 @@ echo
# Clean rules # Clean rules
sqlite3 "$DB_PATH" "DELETE FROM auth_rules;" sqlite3 "$DB_PATH" "DELETE FROM auth_rules;"
sqlite3 "$DB_PATH" "DELETE FROM auth_rules_cache;"
# Test 3: Create a file and blacklist its hash # Test 3: Create a file and blacklist its hash
test_file5=$(create_test_file "hash_blacklist_test.txt" "This specific file is blacklisted") test_file5=$(create_test_file "hash_blacklist_test.txt" "This specific file is blacklisted")
@@ -299,39 +297,11 @@ test_upload "Test 9a: Disabled Rule Not Enforced" "$TEST_USER1_PRIVKEY" "$test_f
# Test 9b: Enable the rule # Test 9b: Enable the rule
echo "Enabling the blacklist rule..." echo "Enabling the blacklist rule..."
sqlite3 "$DB_PATH" "UPDATE auth_rules SET enabled = 1 WHERE rule_target = '$TEST_USER1_PUBKEY';" sqlite3 "$DB_PATH" "UPDATE auth_rules SET enabled = 1 WHERE rule_target = '$TEST_USER1_PUBKEY';"
sqlite3 "$DB_PATH" "DELETE FROM auth_rules_cache;" # Clear cache
# Test 9c: Upload should now be denied # Test 9c: Upload should now be denied
test_file13=$(create_test_file "enabled_rule_test.txt" "Testing enabled rule") test_file13=$(create_test_file "enabled_rule_test.txt" "Testing enabled rule")
test_upload "Test 9c: Enabled Rule Enforced" "$TEST_USER1_PRIVKEY" "$test_file13" "403" test_upload "Test 9c: Enabled Rule Enforced" "$TEST_USER1_PRIVKEY" "$test_file13" "403"
echo
echo "=== SECTION 10: CACHE FUNCTIONALITY ==="
echo
# Clean rules
sqlite3 "$DB_PATH" "DELETE FROM auth_rules;"
sqlite3 "$DB_PATH" "DELETE FROM auth_rules_cache;"
# Test 10: Add a blacklist rule and verify cache is populated
echo "Adding blacklist rule to test caching..."
sqlite3 "$DB_PATH" "INSERT INTO auth_rules (rule_type, rule_target, operation, priority, description) VALUES ('pubkey_blacklist', '$TEST_USER2_PUBKEY', 'upload', 10, 'Cache test');"
# Test 10a: First request (cache miss)
test_file14=$(create_test_file "cache_test1.txt" "First request - cache miss")
test_upload "Test 10a: First Request (Cache Miss)" "$TEST_USER2_PRIVKEY" "$test_file14" "403"
# Test 10b: Second request (should hit cache)
test_file15=$(create_test_file "cache_test2.txt" "Second request - cache hit")
test_upload "Test 10b: Second Request (Cache Hit)" "$TEST_USER2_PRIVKEY" "$test_file15" "403"
# Test 10c: Verify cache entry exists
CACHE_COUNT=$(sqlite3 "$DB_PATH" "SELECT COUNT(*) FROM auth_rules_cache WHERE pubkey = '$TEST_USER2_PUBKEY';" 2>/dev/null)
if [[ "$CACHE_COUNT" -gt 0 ]]; then
record_test_result "Test 10c: Cache Entry Created" "1" "1"
else
record_test_result "Test 10c: Cache Entry Created" "1" "0"
fi
echo echo
echo "=== SECTION 11: CLEANUP AND RESET ===" echo "=== SECTION 11: CLEANUP AND RESET ==="
@@ -340,26 +310,18 @@ echo
# Clean up all test rules # Clean up all test rules
echo "Cleaning up test rules..." echo "Cleaning up test rules..."
sqlite3 "$DB_PATH" "DELETE FROM auth_rules;" sqlite3 "$DB_PATH" "DELETE FROM auth_rules;"
sqlite3 "$DB_PATH" "DELETE FROM auth_rules_cache;"
# Verify cleanup # Verify cleanup
RULE_COUNT=$(sqlite3 "$DB_PATH" "SELECT COUNT(*) FROM auth_rules;" 2>/dev/null) RULE_COUNT=$(sqlite3 "$DB_PATH" "SELECT COUNT(*) FROM auth_rules;" 2>/dev/null)
if [[ "$RULE_COUNT" -eq 0 ]]; then if [[ "$RULE_COUNT" -eq 0 ]]; then
record_test_result "Test 11a: Rules Cleanup" "0" "0" record_test_result "Test 10a: Rules Cleanup" "0" "0"
else else
record_test_result "Test 11a: Rules Cleanup" "0" "$RULE_COUNT" record_test_result "Test 10a: Rules Cleanup" "0" "$RULE_COUNT"
fi
CACHE_COUNT=$(sqlite3 "$DB_PATH" "SELECT COUNT(*) FROM auth_rules_cache;" 2>/dev/null)
if [[ "$CACHE_COUNT" -eq 0 ]]; then
record_test_result "Test 11b: Cache Cleanup" "0" "0"
else
record_test_result "Test 11b: Cache Cleanup" "0" "$CACHE_COUNT"
fi fi
# Test that uploads work again after cleanup # Test that uploads work again after cleanup
test_file16=$(create_test_file "cleanup_test.txt" "Testing after cleanup") test_file16=$(create_test_file "cleanup_test.txt" "Testing after cleanup")
test_upload "Test 11c: Upload After Cleanup" "$TEST_USER1_PRIVKEY" "$test_file16" "200" test_upload "Test 10b: Upload After Cleanup" "$TEST_USER1_PRIVKEY" "$test_file16" "200"
echo echo
echo "==========================================" echo "=========================================="
@@ -382,7 +344,6 @@ if [[ $TESTS_FAILED -eq 0 ]]; then
echo "- Operation-specific rules: Working" echo "- Operation-specific rules: Working"
echo "- Wildcard operations: Working" echo "- Wildcard operations: Working"
echo "- Enable/disable rules: Working" echo "- Enable/disable rules: Working"
echo "- Cache functionality: Working"
else else
echo "⚠️ Some tests failed. Check output above for details." echo "⚠️ Some tests failed. Check output above for details."
echo "Success rate: $(( (TESTS_PASSED * 100) / TOTAL_TESTS ))%" echo "Success rate: $(( (TESTS_PASSED * 100) / TOTAL_TESTS ))%"