Files
ginxsom/tests/auth_test.sh
Your Name 67154164f1 tests
2025-09-07 10:59:43 -04:00

360 lines
14 KiB
Bash
Executable File

#!/bin/bash
# auth_test.sh - Authentication System Test Suite
# Tests the unified nostr_core_lib authentication system integrated into ginxsom
# Configuration
SERVER_URL="http://localhost:9001"
UPLOAD_ENDPOINT="${SERVER_URL}/upload"
DB_PATH="db/ginxsom.db"
TEST_DIR="tests/auth_test_tmp"
# Test keys for different scenarios
TEST_USER1_PRIVKEY="5c0c523f52a5b6fad39ed2403092df8cebc36318b39383bca6c00808626fab3a"
TEST_USER1_PUBKEY="79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"
TEST_USER2_PRIVKEY="182c3a5e3b7a1b7e4f5c6b7c8b4a5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"
TEST_USER2_PUBKEY="c95195e5e7de1ad8c4d3c0ac4e8b5c0c4e0c4d3c1e5c8d4c2e7e9f4a5b6c7d8e"
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"
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"
exit 1
fi
# Check if database exists
if [[ ! -f "$DB_PATH" ]]; then
echo "[ERROR] 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');"
# 2. Blacklist for TEST_USER2 for upload operations (priority 5 - higher priority)
sqlite3 "$DB_PATH" "INSERT INTO auth_rules (rule_type, rule_target, operation, priority, enabled, description)
VALUES ('pubkey_blacklist', '$TEST_USER2_PUBKEY', 'upload', 5, 1, 'TEST_BLACKLIST_USER2');"
# 3. Hash blacklist (will be set after we create a test file)
echo "test content for hash blacklist" > "$TEST_DIR/blacklisted_file.txt"
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
# Helper functions
create_test_file() {
local filename="$1"
local content="${2:-test content for $filename}"
local filepath="$TEST_DIR/$filename"
echo "$content" > "$filepath"
echo "$filepath"
}
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[@]}"
}
test_upload() {
local test_name="$1"
local privkey="$2"
local file_path="$3"
local expected_status="${4:-ANY}"
echo "=== $test_name ==="
local file_hash=$(sha256sum "$file_path" | cut -d' ' -f1)
echo "File: $(basename "$file_path")"
echo "Hash: $file_hash"
echo "User pubkey: $(echo "$privkey" | nak key public)"
# Create auth event
local event=$(create_auth_event "$privkey" "upload" "$file_hash")
local auth_header="Nostr $(echo "$event" | base64 -w 0)"
# Make upload request
local response_file=$(mktemp)
local http_status=$(curl -s -w "%{http_code}" \
-H "Authorization: $auth_header" \
-H "Content-Type: text/plain" \
--data-binary "@$file_path" \
-X PUT "$UPLOAD_ENDPOINT" \
-o "$response_file")
echo "HTTP Status: $http_status"
echo "Server Response:"
cat "$response_file" | jq . 2>/dev/null || cat "$response_file"
echo
rm -f "$response_file"
if [[ "$expected_status" != "ANY" ]]; then
if [[ "$http_status" == "$expected_status" ]]; then
echo "✓ Expected HTTP $expected_status - PASSED"
else
echo "✗ Expected HTTP $expected_status, got $http_status - FAILED"
fi
fi
echo
}
# 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")
test_upload "Test 1: Whitelisted User Upload" "$TEST_USER1_PRIVKEY" "$test_file1" "200"
# Test 2: Blacklisted user (should fail)
test_file2=$(create_test_file "blacklisted_upload.txt" "Content from blacklisted user")
test_upload "Test 2: Blacklisted User Upload" "$TEST_USER2_PRIVKEY" "$test_file2" "403"
# Test 3: Whitelisted user uploading blacklisted hash (blacklist should win due to higher priority)
test_upload "Test 3: Whitelisted User + Blacklisted Hash" "$TEST_USER1_PRIVKEY" "$TEST_DIR/blacklisted_file.txt" "403"
# Test 4: Random user with no specific rules (should be allowed since no restrictive whitelist applies to all users)
test_file4=$(create_test_file "random_upload.txt" "Content from random user")
# Use a different private key that's not in any rules
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() {
local test_name="$1"
local auth_header="$2"
local file_content="${3:-failure_test_content}"
local expected_status="${4:-401}"
echo "=== $test_name ==="
local test_file=$(mktemp)
echo "$file_content" > "$test_file"
local response_file=$(mktemp)
local http_status=$(curl -s -w "%{http_code}" \
${auth_header:+-H "Authorization: $auth_header"} \
-H "Content-Type: text/plain" \
--data-binary "@$test_file" \
-X PUT "$UPLOAD_ENDPOINT" \
-o "$response_file")
echo "HTTP Status: $http_status"
echo "Server Response:"
cat "$response_file" | jq . 2>/dev/null || cat "$response_file"
echo
rm -f "$test_file" "$response_file"
if [[ "$http_status" == "$expected_status" ]]; then
echo "✓ Expected HTTP $expected_status - PASSED"
else
echo "✗ Expected HTTP $expected_status, got $http_status - FAILED"
fi
echo
}
# Test 6a: Missing Authorization Header
test_failure_mode "Test 6a: Missing Authorization Header" ""
# Test 6b: Invalid Authorization Prefix
test_failure_mode "Test 6b: Invalid Authorization Prefix" "Bearer invalidtoken123"
# 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 7a: Invalid JSON Structure
malformed_json='{"kind":24242,"content":"","created_at":' # Incomplete JSON
malformed_b64=$(echo -n "$malformed_json" | base64 -w 0)
test_failure_mode "Test 7a: Invalid JSON Structure" "Nostr $malformed_b64"
# Test 7b: Missing Required Fields
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 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
short_key_event=$(cat << EOF
{
"kind": 24242,
"content": "",
"created_at": $(date +%s),
"pubkey": "$short_pubkey",
"tags": [["t", "upload"], ["x", "$file_hash"]],
"id": "invalid_id",
"sig": "invalid_signature"
}
EOF
)
short_key_b64=$(echo -n "$short_key_event" | base64 -w 0)
test_failure_mode "Test 8a: Short Public Key" "Nostr $short_key_b64"
# Test 8b: Non-hex Public Key
echo "Test 8b: Non-hex Public Key"
echo "nonhex_key_test" > "$TEST_DIR/nonhex_key.txt"
file_hash=$(sha256sum "$TEST_DIR/nonhex_key.txt" | cut -d' ' -f1)
nonhex_pubkey="gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg" # Invalid hex
nonhex_key_event=$(cat << EOF
{
"kind": 24242,
"content": "",
"created_at": $(date +%s),
"pubkey": "$nonhex_pubkey",
"tags": [["t", "upload"], ["x", "$file_hash"]],
"id": "invalid_id",
"sig": "invalid_signature"
}
EOF
)
nonhex_key_b64=$(echo -n "$nonhex_key_event" | base64 -w 0)
test_failure_mode "Test 8b: Non-hex Public Key" "Nostr $nonhex_key_b64"
echo "=== Test 9: Wrong Event Kind ==="
# Test 9a: Wrong Kind (1 instead of 24242)
echo "Test 9a: Wrong Kind (kind 1 instead of 24242)"
echo "wrong_kind_test" > "$TEST_DIR/wrong_kind.txt"
file_hash=$(sha256sum "$TEST_DIR/wrong_kind.txt" | cut -d' ' -f1)
wrong_kind_event=$(nak event -k 1 -c "wrong kind test" --tag "t=upload" --tag "x=$file_hash" --sec "$TEST_USER1_PRIVKEY")
wrong_kind_b64=$(echo -n "$wrong_kind_event" | base64 -w 0)
test_failure_mode "Test 9a: Wrong Event Kind" "Nostr $wrong_kind_b64"
echo "=== Test 10: Missing or Invalid Tags ==="
# Test 10a: Missing 't' tag
echo "Test 10a: Missing 't' (method) tag"
echo "missing_t_tag_test" > "$TEST_DIR/missing_t_tag.txt"
file_hash=$(sha256sum "$TEST_DIR/missing_t_tag.txt" | cut -d' ' -f1)
missing_t_event=$(nak event -k 24242 -c "" --tag "x=$file_hash" --sec "$TEST_USER1_PRIVKEY")
missing_t_b64=$(echo -n "$missing_t_event" | base64 -w 0)
test_failure_mode "Test 10a: Missing 't' tag" "Nostr $missing_t_b64"
# Test 10b: Missing 'x' tag
echo "Test 10b: Missing 'x' (hash) tag"
echo "missing_x_tag_test" > "$TEST_DIR/missing_x_tag.txt"
missing_x_event=$(nak event -k 24242 -c "" --tag "t=upload" --sec "$TEST_USER1_PRIVKEY")
missing_x_b64=$(echo -n "$missing_x_event" | base64 -w 0)
test_failure_mode "Test 10b: Missing 'x' tag" "Nostr $missing_x_b64"
# Test 10c: Hash mismatch in 'x' tag
echo "Test 10c: Hash mismatch in 'x' tag"
echo "hash_mismatch_test" > "$TEST_DIR/hash_mismatch.txt"
wrong_hash="0000000000000000000000000000000000000000000000000000000000000000"
hash_mismatch_event=$(nak event -k 24242 -c "" --tag "t=upload" --tag "x=$wrong_hash" --sec "$TEST_USER1_PRIVKEY")
hash_mismatch_b64=$(echo -n "$hash_mismatch_event" | base64 -w 0)
test_failure_mode "Test 10c: Hash mismatch" "Nostr $hash_mismatch_b64"
echo "=== Test 11: Expired Events ==="
# Test 11a: Event with past expiration
echo "Test 11a: Event with past expiration"
echo "expired_event_test" > "$TEST_DIR/expired_event.txt"
file_hash=$(sha256sum "$TEST_DIR/expired_event.txt" | cut -d' ' -f1)
past_time=$(($(date +%s) - 3600)) # 1 hour ago
expired_event=$(nak event -k 24242 -c "" --tag "t=upload" --tag "x=$file_hash" --tag "expiration=$past_time" --sec "$TEST_USER1_PRIVKEY")
expired_b64=$(echo -n "$expired_event" | base64 -w 0)
test_failure_mode "Test 11a: Expired Event" "Nostr $expired_b64"
echo "=== Test 12: Invalid Signatures ==="
# Test 12a: Corrupted signature
echo "Test 12a: Corrupted signature"
echo "corrupted_sig_test" > "$TEST_DIR/corrupted_sig.txt"
file_hash=$(sha256sum "$TEST_DIR/corrupted_sig.txt" | cut -d' ' -f1)
valid_event=$(nak event -k 24242 -c "" --tag "t=upload" --tag "x=$file_hash" --sec "$TEST_USER1_PRIVKEY")
# Corrupt the signature by changing the last character
corrupted_event=$(echo "$valid_event" | sed 's/.\{1\}$/x/') # Replace last char with 'x'
corrupted_b64=$(echo -n "$corrupted_event" | base64 -w 0)
test_failure_mode "Test 12a: Corrupted Signature" "Nostr $corrupted_b64"
# Show final state
echo "=== Final Database State ==="
echo "Authentication rules left in database:"
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
echo "Auth config:"
sqlite3 "$DB_PATH" -header -column "SELECT key, value FROM auth_config WHERE key = 'auth_rules_enabled';"
echo
echo "=== Test Suite Completed ==="
echo "Comprehensive authentication and failure mode testing completed."
echo "Auth rules have been left in the database for inspection."
echo "To clean up, run: sqlite3 $DB_PATH \"DELETE FROM auth_rules WHERE description LIKE 'TEST_%';\""