v0.1.8 - Removed cache functionality for now
This commit is contained in:
Binary file not shown.
BIN
build/main.o
BIN
build/main.o
Binary file not shown.
Binary file not shown.
BIN
db/ginxsom.db
BIN
db/ginxsom.db
Binary file not shown.
@@ -68,19 +68,6 @@ CREATE TABLE IF NOT EXISTS auth_rules (
|
||||
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
|
||||
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_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
|
||||
CREATE VIEW IF NOT EXISTS storage_stats AS
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
// Version information (auto-updated by build system)
|
||||
#define VERSION_MAJOR 0
|
||||
#define VERSION_MINOR 1
|
||||
#define VERSION_PATCH 7
|
||||
#define VERSION "v0.1.7"
|
||||
#define VERSION_PATCH 8
|
||||
#define VERSION "v0.1.8"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -115,7 +115,7 @@ static int validate_nip42_event(cJSON *event, const char *relay_url,
|
||||
const char *challenge_id);
|
||||
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,
|
||||
const char *resource_hash);
|
||||
const char *resource_hash, const char *mime_type);
|
||||
void nostr_request_validator_clear_violation(void);
|
||||
|
||||
// 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(
|
||||
extracted_pubkey, request->operation, hash_for_rules);
|
||||
extracted_pubkey, request->operation, hash_for_rules, request->mime_type);
|
||||
if (rules_result != NOSTR_SUCCESS) {
|
||||
validator_debug_log(
|
||||
"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
|
||||
*/
|
||||
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_stmt *stmt = NULL;
|
||||
int rc;
|
||||
@@ -1330,8 +1330,8 @@ static int check_database_auth_rules(const char *pubkey, const char *operation,
|
||||
char rules_msg[256];
|
||||
sprintf(rules_msg,
|
||||
"VALIDATOR_DEBUG: RULES ENGINE - Checking rules for pubkey=%.32s..., "
|
||||
"operation=%s\n",
|
||||
pubkey, operation ? operation : "NULL");
|
||||
"operation=%s, mime_type=%s\n",
|
||||
pubkey, operation ? operation : "NULL", mime_type ? mime_type : "NULL");
|
||||
validator_debug_log(rules_msg);
|
||||
|
||||
// Open database
|
||||
@@ -1418,7 +1418,49 @@ static int check_database_auth_rules(const char *pubkey, const char *operation,
|
||||
"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 '*'
|
||||
const char *whitelist_sql =
|
||||
"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 "
|
||||
"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 '*'
|
||||
const char *whitelist_exists_sql =
|
||||
"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");
|
||||
|
||||
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");
|
||||
return NOSTR_SUCCESS; // Default allow if no restrictive rules matched
|
||||
}
|
||||
|
||||
@@ -132,7 +132,6 @@ test_upload() {
|
||||
# Clean up any existing rules from previous tests
|
||||
echo "Cleaning up existing auth rules..."
|
||||
sqlite3 "$DB_PATH" "DELETE FROM auth_rules;" 2>/dev/null
|
||||
sqlite3 "$DB_PATH" "DELETE FROM auth_rules_cache;" 2>/dev/null
|
||||
|
||||
# Enable authentication rules
|
||||
echo "Enabling authentication rules..."
|
||||
@@ -180,7 +179,6 @@ echo
|
||||
|
||||
# Clean 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_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
|
||||
echo "Enabling the blacklist rule..."
|
||||
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_file13=$(create_test_file "enabled_rule_test.txt" "Testing enabled rule")
|
||||
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 "=== SECTION 11: CLEANUP AND RESET ==="
|
||||
@@ -340,26 +310,18 @@ echo
|
||||
# Clean up all test rules
|
||||
echo "Cleaning up test rules..."
|
||||
sqlite3 "$DB_PATH" "DELETE FROM auth_rules;"
|
||||
sqlite3 "$DB_PATH" "DELETE FROM auth_rules_cache;"
|
||||
|
||||
# Verify cleanup
|
||||
RULE_COUNT=$(sqlite3 "$DB_PATH" "SELECT COUNT(*) FROM auth_rules;" 2>/dev/null)
|
||||
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
|
||||
record_test_result "Test 11a: 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"
|
||||
record_test_result "Test 10a: Rules Cleanup" "0" "$RULE_COUNT"
|
||||
fi
|
||||
|
||||
# Test that uploads work again 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 "=========================================="
|
||||
@@ -382,7 +344,6 @@ if [[ $TESTS_FAILED -eq 0 ]]; then
|
||||
echo "- Operation-specific rules: Working"
|
||||
echo "- Wildcard operations: Working"
|
||||
echo "- Enable/disable rules: Working"
|
||||
echo "- Cache functionality: Working"
|
||||
else
|
||||
echo "⚠️ Some tests failed. Check output above for details."
|
||||
echo "Success rate: $(( (TESTS_PASSED * 100) / TOTAL_TESTS ))%"
|
||||
|
||||
Reference in New Issue
Block a user