#!/bin/bash # Input Validation Test Suite for C-Relay # Comprehensive testing of input boundary conditions and malformed data set -e # Configuration RELAY_HOST="127.0.0.1" RELAY_PORT="8888" TEST_TIMEOUT=10 # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Test counters TOTAL_TESTS=0 PASSED_TESTS=0 FAILED_TESTS=0 # Function to test input validation test_input_validation() { local description="$1" local message="$2" local expect_success="${3:-false}" TOTAL_TESTS=$((TOTAL_TESTS + 1)) echo -n "Testing $description... " # Send message via websocat and capture response local response response=$(echo "$message" | timeout $TEST_TIMEOUT websocat -B 1048576 ws://$RELAY_HOST:$RELAY_PORT 2>/dev/null | head -3 || echo 'TIMEOUT') if [[ "$response" == "TIMEOUT" ]]; then echo -e "${RED}FAILED${NC} - Connection timeout" FAILED_TESTS=$((FAILED_TESTS + 1)) return 1 fi # Check if response indicates success or proper error handling if [[ "$expect_success" == "true" ]]; then # Valid input should get EOSE, EVENT, NOTICE (non-error), or COUNT response if [[ "$response" == *"EOSE"* ]] || [[ "$response" == *"EVENT"* ]] || [[ "$response" == *"COUNT"* ]] || [[ "$response" == *"NOTICE"* && ! "$response" == *"error:"* ]]; then echo -e "${GREEN}PASSED${NC} - Input accepted correctly" PASSED_TESTS=$((PASSED_TESTS + 1)) return 0 else echo -e "${RED}FAILED${NC} - Valid input rejected: $response" FAILED_TESTS=$((FAILED_TESTS + 1)) return 1 fi else # Invalid input should get error NOTICE, NOTICE, connection failure, or empty response (connection closed) if [[ "$response" == *"error:"* ]] || [[ "$response" == *"NOTICE"* ]] || [[ "$response" == *"CONNECTION_FAILED"* ]] || [[ -z "$response" ]]; then echo -e "${GREEN}PASSED${NC} - Invalid input properly rejected" PASSED_TESTS=$((PASSED_TESTS + 1)) return 0 else echo -e "${RED}FAILED${NC} - Invalid input not rejected: $response" FAILED_TESTS=$((FAILED_TESTS + 1)) return 1 fi fi } echo "==========================================" echo "C-Relay Input Validation Test Suite" echo "==========================================" echo "Testing against relay at ws://$RELAY_HOST:$RELAY_PORT" echo # Test basic connectivity first echo "=== Basic Connectivity Test ===" test_input_validation "Basic connectivity" '["REQ","basic_test",{}]' true echo echo "=== Message Type Validation ===" # Test invalid message types test_input_validation "Invalid message type - string" '["INVALID","test",{}]' false test_input_validation "Invalid message type - number" '[123,"test",{}]' false test_input_validation "Invalid message type - null" '[null,"test",{}]' false test_input_validation "Invalid message type - object" '[{"type":"invalid"},"test",{}]' false test_input_validation "Empty message type" '["","test",{}]' false test_input_validation "Very long message type" '["'$(printf 'a%.0s' {1..1000})'","test",{}]' false echo echo "=== Message Structure Validation ===" # Test malformed message structures test_input_validation "Too few arguments" '["REQ"]' false test_input_validation "Too many arguments" '["REQ","test",{}, "extra"]' false test_input_validation "Non-array message" '"not an array"' false test_input_validation "Empty array" '[]' false test_input_validation "Nested arrays incorrectly" '[["REQ","test",{}]]' false echo echo "=== Subscription ID Boundary Tests ===" # Test subscription ID limits test_input_validation "Valid subscription ID" '["REQ","valid_sub_123",{}]' true test_input_validation "Empty subscription ID" '["REQ","",{}]' false test_input_validation "Subscription ID with spaces" '["REQ","sub with spaces",{}]' false test_input_validation "Subscription ID with newlines" '["REQ","sub\nwith\nlines",{}]' false test_input_validation "Subscription ID with tabs" '["REQ","sub\twith\ttabs",{}]' false test_input_validation "Subscription ID with control chars" '["REQ","sub\x01\x02",{}]' false test_input_validation "Unicode subscription ID" '["REQ","test๐Ÿš€",{}]' false test_input_validation "Very long subscription ID" '["REQ","'$(printf 'a%.0s' {1..200})'",{}]' false echo echo "=== Filter Object Validation ===" # Test filter object structure test_input_validation "Valid empty filter" '["REQ","test",{}]' true test_input_validation "Non-object filter" '["REQ","test","not an object"]' false test_input_validation "Null filter" '["REQ","test",null]' false test_input_validation "Array filter" '["REQ","test",[]]' false test_input_validation "Filter with invalid keys" '["REQ","test",{"invalid_key":"value"}]' true echo echo "=== Authors Field Validation ===" # Test authors field with valid 64-char hex pubkey test_input_validation "Valid authors array" '["REQ","test",{"authors":["0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"]}]' true test_input_validation "Empty authors array" '["REQ","test",{"authors":[]}]' true test_input_validation "Non-array authors" '["REQ","test",{"authors":"not an array"}]' false test_input_validation "Invalid hex in authors" '["REQ","test",{"authors":["invalid_hex"]}]' false test_input_validation "Short pubkey in authors" '["REQ","test",{"authors":["0123456789abcdef"]}]' false echo echo "=== IDs Field Validation ===" # Test ids field test_input_validation "Valid ids array" '["REQ","test",{"ids":["0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"]}]' true test_input_validation "Empty ids array" '["REQ","test",{"ids":[]}]' true test_input_validation "Non-array ids" '["REQ","test",{"ids":"not an array"}]' false echo echo "=== Kinds Field Validation ===" # Test kinds field test_input_validation "Valid kinds array" '["REQ","test",{"kinds":[1,2,3]}]' true test_input_validation "Empty kinds array" '["REQ","test",{"kinds":[]}]' true test_input_validation "Non-array kinds" '["REQ","test",{"kinds":"not an array"}]' false test_input_validation "String in kinds" '["REQ","test",{"kinds":["1"]}]' false echo echo "=== Timestamp Field Validation ===" # Test timestamp fields test_input_validation "Valid since timestamp" '["REQ","test",{"since":1234567890}]' true test_input_validation "Valid until timestamp" '["REQ","test",{"until":1234567890}]' true test_input_validation "String since timestamp" '["REQ","test",{"since":"1234567890"}]' false test_input_validation "Negative timestamp" '["REQ","test",{"since":-1}]' false echo echo "=== Limit Field Validation ===" # Test limit field test_input_validation "Valid limit" '["REQ","test",{"limit":100}]' true test_input_validation "Zero limit" '["REQ","test",{"limit":0}]' true test_input_validation "String limit" '["REQ","test",{"limit":"100"}]' false test_input_validation "Negative limit" '["REQ","test",{"limit":-1}]' false echo echo "=== Multiple Filters ===" # Test multiple filters test_input_validation "Two valid filters" '["REQ","test",{"kinds":[1]},{"kinds":[2]}]' true test_input_validation "Many filters" '["REQ","test",{},{},{},{},{}]' true echo echo "=== Test Results ===" echo "Total tests: $TOTAL_TESTS" echo "Passed: $PASSED_TESTS" echo "Failed: $FAILED_TESTS" if [ $FAILED_TESTS -eq 0 ]; then echo -e "${GREEN}โœ“ All input validation tests passed!${NC}" echo "The relay properly validates input." exit 0 else echo -e "${RED}โœ— Some input validation tests failed${NC}" echo "The relay may have input validation issues." exit 1 fi