#!/bin/bash set -euo pipefail SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) URL="${1:-http://127.0.0.1:7703}" # Use test tokens from environment or defaults TOKEN="${TEST_TOKEN1:-t570H7DmK2VBfCwUmtFaUXyzVklL90E1}" echo "Testing input validation at $URL" echo "======================================" PASS_COUNT=0 FAIL_COUNT=0 # Helper function to test an upload with expected result test_upload() { local test_name="$1" local metadata="$2" local expected_result="$3" # "success" or "error" local file_content="${4:-test content}" echo "" echo "Test: $test_name" echo "Metadata: $metadata" # Create a temp file local temp_file=$(mktemp) echo "$file_content" > "$temp_file" # Perform upload local response=$(curl -s -X PUT \ -H "Authorization: Bearer $TOKEN" \ -F "file=@$temp_file" \ -F "metadata=$metadata" \ "$URL/upload" 2>/dev/null || echo '{"result":"error","error":"curl failed"}') rm -f "$temp_file" local result=$(echo "$response" | jq -r '.result' 2>/dev/null || echo "parse_error") if [ "$expected_result" = "error" ]; then if [ "$result" = "error" ]; then echo " ✓ Correctly rejected invalid input" echo " Error: $(echo "$response" | jq -r '.error' 2>/dev/null)" ((PASS_COUNT++)) else echo " ✗ FAILED: Expected rejection but got: $response" ((FAIL_COUNT++)) fi else if [ "$result" = "success" ]; then echo " ✓ Correctly accepted valid input" ((PASS_COUNT++)) else echo " ✗ FAILED: Expected success but got: $response" ((FAIL_COUNT++)) fi fi } # Test update endpoint test_update() { local test_name="$1" local body="$2" local expected_result="$3" # "success" or "error" echo "" echo "Test: $test_name" echo "Body: $body" local response=$(curl -s -X PUT \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d "$body" \ "$URL/update" 2>/dev/null || echo '{"result":"error","error":"curl failed"}') local result=$(echo "$response" | jq -r '.result' 2>/dev/null || echo "parse_error") if [ "$expected_result" = "error" ]; then if [ "$result" = "error" ]; then echo " ✓ Correctly rejected invalid input" echo " Error: $(echo "$response" | jq -r '.error' 2>/dev/null)" ((PASS_COUNT++)) else echo " ✗ FAILED: Expected rejection but got: $response" ((FAIL_COUNT++)) fi else if [ "$result" = "success" ]; then echo " ✓ Correctly accepted valid input" ((PASS_COUNT++)) else echo " ✗ FAILED: Expected success but got: $response" ((FAIL_COUNT++)) fi fi } echo "" echo "1. Testing Label:Tag Validation" echo "================================" # Valid label:tag test_upload "Valid label:tag" '{"labeltags":["test:v1"]}' "success" # Invalid: missing colon test_upload "Missing colon" '{"labeltags":["testv1"]}' "error" # Invalid: empty label test_upload "Empty label" '{"labeltags":[":v1"]}' "error" # Invalid: empty tag test_upload "Empty tag" '{"labeltags":["test:"]}' "error" # Invalid: multiple colons test_upload "Multiple colons" '{"labeltags":["test:v1:extra"]}' "error" # Invalid: special characters test_upload "Invalid characters" '{"labeltags":["test@#$:v1"]}' "error" # Invalid: starts with non-alphanumeric test_upload "Starts with dash" '{"labeltags":["-test:v1"]}' "error" # Valid: with allowed special chars test_upload "Valid special chars" '{"labeltags":["test_project-1.0:v1"]}' "success" # Invalid: too long label (>255 chars) LONG_LABEL="" for i in {1..256}; do LONG_LABEL="${LONG_LABEL}a"; done test_upload "Label too long" "{\"labeltags\":[\"${LONG_LABEL}:v1\"]}" "error" # Invalid: too long tag (>255 chars) LONG_TAG="" for i in {1..256}; do LONG_TAG="${LONG_TAG}a"; done test_upload "Tag too long" "{\"labeltags\":[\"test:${LONG_TAG}\"]}" "error" # Invalid: too many labeltags (>100) MANY_TAGS='{"labeltags":[' for i in {1..101}; do if [ $i -gt 1 ]; then MANY_TAGS="${MANY_TAGS},"; fi MANY_TAGS="${MANY_TAGS}\"test${i}:v${i}\"" done MANY_TAGS="${MANY_TAGS}]}" test_upload "Too many labeltags" "$MANY_TAGS" "error" # Invalid: duplicate labeltags test_upload "Duplicate labeltags" '{"labeltags":["test:v1","test:v1"]}' "error" echo "" echo "2. Testing Metadata Validation" echo "===============================" # Valid metadata with various fields test_upload "Valid metadata" '{"labeltags":["test:meta1"],"custom_field":"value","number":123,"bool":true}' "success" # Invalid: metadata not an object test_upload "Metadata not object" '["not","an","object"]' "error" # Invalid: field name with invalid characters test_upload "Invalid field name" '{"labeltags":["test:meta2"],"field-with-dash":"value"}' "error" # Invalid: field name starting with number test_upload "Field starts with number" '{"labeltags":["test:meta3"],"123field":"value"}' "error" # Invalid: field value too long (>4096 chars) LONG_VALUE="" for i in {1..4097}; do LONG_VALUE="${LONG_VALUE}a"; done test_upload "Field value too long" "{\"labeltags\":[\"test:meta4\"],\"field\":\"${LONG_VALUE}\"}" "error" # Invalid: nested object too deep (>5 levels) DEEP_NESTED='{"labeltags":["test:meta5"],"l1":{"l2":{"l3":{"l4":{"l5":{"l6":"too deep"}}}}}}' test_upload "Nested too deep" "$DEEP_NESTED" "error" # Valid: nested object within limit VALID_NESTED='{"labeltags":["test:meta6"],"l1":{"l2":{"l3":{"l4":{"l5":"ok"}}}}}' test_upload "Valid nested" "$VALID_NESTED" "success" echo "" echo "3. Testing Filename Validation" echo "===============================" # Invalid: directory traversal test_upload "Directory traversal" '{"labeltags":["test:file1"],"filename":"../etc/passwd"}' "error" # Invalid: null byte test_upload "Null byte in filename" "{\"labeltags\":[\"test:file2\"],\"filename\":\"file\\u0000.txt\"}" "error" # Invalid: path separator test_upload "Path separator" '{"labeltags":["test:file3"],"filename":"path/to/file.txt"}' "error" # Invalid: Windows reserved name test_upload "Windows reserved" '{"labeltags":["test:file4"],"filename":"CON.txt"}' "error" # Valid: normal filename test_upload "Valid filename" '{"labeltags":["test:file5"],"filename":"valid_file-123.txt"}' "success" echo "" echo "4. Testing Hash Validation (via update endpoint)" echo "=================================================" # First create a valid object to update echo "Creating test object..." TEMP_FILE=$(mktemp) echo "test content for update" > "$TEMP_FILE" CREATE_RESPONSE=$(curl -s -X PUT \ -H "Authorization: Bearer $TOKEN" \ -F "file=@$TEMP_FILE" \ -F 'metadata={"labeltags":["test:update1"]}' \ "$URL/upload") rm -f "$TEMP_FILE" HASH=$(echo "$CREATE_RESPONSE" | jq -r '.hash' 2>/dev/null || echo "") if [ ! -z "$HASH" ]; then # Valid hash update test_update "Valid hash update" "{\"hash\":\"$HASH\",\"metadata\":{\"updated\":true}}" "success" # Invalid: hash wrong length test_update "Hash wrong length" '{"hash":"abc123","metadata":{"updated":true}}' "error" # Invalid: hash with invalid characters test_update "Hash invalid chars" '{"hash":"zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz","metadata":{"updated":true}}' "error" # Invalid: empty hash test_update "Empty hash" '{"hash":"","metadata":{"updated":true}}' "error" else echo " ⚠ Skipping hash validation tests (couldn't create test object)" fi echo "" echo "5. Testing Delete Endpoint Validation" echo "======================================" # Test delete with invalid hash echo "" echo "Test: Delete with invalid hash" DELETE_RESPONSE=$(curl -s -H "Authorization: Bearer $TOKEN" \ "$URL/deleteobject?hash=invalid" 2>/dev/null) DELETE_RESULT=$(echo "$DELETE_RESPONSE" | jq -r '.result' 2>/dev/null || echo "parse_error") if [ "$DELETE_RESULT" = "error" ]; then echo " ✓ Correctly rejected invalid hash" echo " Error: $(echo "$DELETE_RESPONSE" | jq -r '.error' 2>/dev/null)" ((PASS_COUNT++)) else echo " ✗ FAILED: Expected rejection but got: $DELETE_RESPONSE" ((FAIL_COUNT++)) fi echo "" echo "======================================" echo "Test Results:" echo " Passed: $PASS_COUNT" echo " Failed: $FAIL_COUNT" echo "" if [ $FAIL_COUNT -eq 0 ]; then echo "✓ All input validation tests passed!" exit 0 else echo "✗ Some tests failed" exit 1 fi