#!/bin/bash

# Security Audit Script for Portfolio Tracker
# This script performs various security checks and penetration tests

set -e

API_BASE_URL="${API_BASE_URL:-http://localhost:3000}"
RESULTS_DIR="./security-audit-results"
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
REPORT_FILE="$RESULTS_DIR/security_audit_$TIMESTAMP.json"

echo "🔍 Starting Security Audit for Portfolio Tracker"
echo "Target: $API_BASE_URL"
echo "Results will be saved to: $REPORT_FILE"

# Create results directory
mkdir -p "$RESULTS_DIR"

# Initialize results JSON
cat > "$REPORT_FILE" << EOF
{
  "timestamp": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")",
  "target": "$API_BASE_URL",
  "tests": {}
}
EOF

# Function to add test result to JSON
add_test_result() {
  local test_name="$1"
  local status="$2"
  local details="$3"
  
  # Use jq to update the JSON file
  jq --arg name "$test_name" --arg status "$status" --arg details "$details" \
    '.tests[$name] = {"status": $status, "details": $details, "timestamp": now | strftime("%Y-%m-%dT%H:%M:%SZ")}' \
    "$REPORT_FILE" > "$REPORT_FILE.tmp" && mv "$REPORT_FILE.tmp" "$REPORT_FILE"
}

# Function to test HTTP response
test_http_response() {
  local url="$1"
  local expected_status="$2"
  local test_name="$3"
  
  echo "Testing: $test_name"
  
  response=$(curl -s -w "%{http_code}" -o /dev/null "$url" || echo "000")
  
  if [ "$response" = "$expected_status" ]; then
    add_test_result "$test_name" "PASS" "HTTP $response as expected"
    echo "✅ PASS: $test_name"
  else
    add_test_result "$test_name" "FAIL" "Expected HTTP $expected_status, got $response"
    echo "❌ FAIL: $test_name (Expected $expected_status, got $response)"
  fi
}

# Function to test security headers
test_security_headers() {
  echo "🔒 Testing Security Headers"
  
  headers=$(curl -s -I "$API_BASE_URL" || echo "")
  
  # Test for required security headers
  declare -A required_headers=(
    ["X-Content-Type-Options"]="nosniff"
    ["X-Frame-Options"]="DENY"
    ["X-XSS-Protection"]="1; mode=block"
    ["Strict-Transport-Security"]=""
    ["Content-Security-Policy"]=""
    ["Referrer-Policy"]=""
    ["Permissions-Policy"]=""
  )
  
  for header in "${!required_headers[@]}"; do
    if echo "$headers" | grep -qi "$header"; then
      add_test_result "security_header_$header" "PASS" "Header present"
      echo "✅ PASS: $header header present"
    else
      add_test_result "security_header_$header" "FAIL" "Header missing"
      echo "❌ FAIL: $header header missing"
    fi
  done
}

# Function to test rate limiting
test_rate_limiting() {
  echo "🚦 Testing Rate Limiting"
  
  # Test general rate limiting
  echo "Testing general rate limiting..."
  for i in {1..15}; do
    response=$(curl -s -w "%{http_code}" -o /dev/null "$API_BASE_URL/health" || echo "000")
    if [ "$response" = "429" ]; then
      add_test_result "rate_limiting_general" "PASS" "Rate limiting triggered after $i requests"
      echo "✅ PASS: Rate limiting working (triggered after $i requests)"
      return
    fi
    sleep 0.1
  done
  
  add_test_result "rate_limiting_general" "WARN" "Rate limiting not triggered in 15 requests"
  echo "⚠️  WARN: Rate limiting not triggered in 15 requests"
}

# Function to test SQL injection protection
test_sql_injection() {
  echo "💉 Testing SQL Injection Protection"
  
  # Common SQL injection payloads
  declare -a payloads=(
    "' OR '1'='1"
    "'; DROP TABLE users; --"
    "' UNION SELECT * FROM users --"
    "1' OR 1=1 --"
    "admin'--"
    "' OR 'x'='x"
  )
  
  for payload in "${payloads[@]}"; do
    encoded_payload=$(printf '%s' "$payload" | jq -sRr @uri)
    response=$(curl -s -w "%{http_code}" -o /dev/null "$API_BASE_URL/api/users?search=$encoded_payload" || echo "000")
    
    if [ "$response" = "400" ] || [ "$response" = "403" ]; then
      add_test_result "sql_injection_protection" "PASS" "SQL injection payload blocked"
      echo "✅ PASS: SQL injection payload blocked"
      return
    fi
  done
  
  add_test_result "sql_injection_protection" "FAIL" "SQL injection payloads not blocked"
  echo "❌ FAIL: SQL injection payloads not blocked"
}

# Function to test XSS protection
test_xss_protection() {
  echo "🕷️  Testing XSS Protection"
  
  # Common XSS payloads
  declare -a payloads=(
    "<script>alert('xss')</script>"
    "<img src=x onerror=alert('xss')>"
    "javascript:alert('xss')"
    "<svg onload=alert('xss')>"
    "<iframe src=javascript:alert('xss')></iframe>"
  )
  
  for payload in "${payloads[@]}"; do
    encoded_payload=$(printf '%s' "$payload" | jq -sRr @uri)
    response=$(curl -s -w "%{http_code}" -o /dev/null "$API_BASE_URL/api/search?q=$encoded_payload" || echo "000")
    
    if [ "$response" = "400" ] || [ "$response" = "403" ]; then
      add_test_result "xss_protection" "PASS" "XSS payload blocked"
      echo "✅ PASS: XSS payload blocked"
      return
    fi
  done
  
  add_test_result "xss_protection" "FAIL" "XSS payloads not blocked"
  echo "❌ FAIL: XSS payloads not blocked"
}

# Function to test path traversal protection
test_path_traversal() {
  echo "📁 Testing Path Traversal Protection"
  
  # Common path traversal payloads
  declare -a payloads=(
    "../../../etc/passwd"
    "..\\..\\..\\windows\\system32\\drivers\\etc\\hosts"
    "%2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fpasswd"
    "....//....//....//etc/passwd"
  )
  
  for payload in "${payloads[@]}"; do
    encoded_payload=$(printf '%s' "$payload" | jq -sRr @uri)
    response=$(curl -s -w "%{http_code}" -o /dev/null "$API_BASE_URL/api/files/$encoded_payload" || echo "000")
    
    if [ "$response" = "400" ] || [ "$response" = "403" ] || [ "$response" = "404" ]; then
      add_test_result "path_traversal_protection" "PASS" "Path traversal payload blocked"
      echo "✅ PASS: Path traversal payload blocked"
      return
    fi
  done
  
  add_test_result "path_traversal_protection" "FAIL" "Path traversal payloads not blocked"
  echo "❌ FAIL: Path traversal payloads not blocked"
}

# Function to test HTTPS configuration
test_https_config() {
  echo "🔐 Testing HTTPS Configuration"
  
  if [[ "$API_BASE_URL" == https://* ]]; then
    # Test SSL/TLS configuration
    ssl_info=$(echo | openssl s_client -connect "${API_BASE_URL#https://}" -servername "${API_BASE_URL#https://}" 2>/dev/null | openssl x509 -noout -text 2>/dev/null || echo "")
    
    if [ -n "$ssl_info" ]; then
      add_test_result "https_certificate" "PASS" "HTTPS certificate valid"
      echo "✅ PASS: HTTPS certificate valid"
      
      # Check for strong cipher suites
      cipher_info=$(echo | openssl s_client -connect "${API_BASE_URL#https://}" -cipher 'ECDHE+AESGCM:ECDHE+CHACHA20:DHE+AESGCM:DHE+CHACHA20:!aNULL:!MD5:!DSS' 2>/dev/null | grep "Cipher is" || echo "")
      
      if [ -n "$cipher_info" ]; then
        add_test_result "https_strong_ciphers" "PASS" "Strong cipher suites supported"
        echo "✅ PASS: Strong cipher suites supported"
      else
        add_test_result "https_strong_ciphers" "FAIL" "Weak cipher suites detected"
        echo "❌ FAIL: Weak cipher suites detected"
      fi
    else
      add_test_result "https_certificate" "FAIL" "HTTPS certificate invalid or missing"
      echo "❌ FAIL: HTTPS certificate invalid or missing"
    fi
  else
    add_test_result "https_enabled" "WARN" "HTTPS not enabled"
    echo "⚠️  WARN: HTTPS not enabled"
  fi
}

# Function to test authentication security
test_auth_security() {
  echo "🔑 Testing Authentication Security"
  
  # Test for authentication bypass
  response=$(curl -s -w "%{http_code}" -o /dev/null "$API_BASE_URL/api/users/profile" || echo "000")
  
  if [ "$response" = "401" ]; then
    add_test_result "auth_required" "PASS" "Authentication required for protected endpoints"
    echo "✅ PASS: Authentication required for protected endpoints"
  else
    add_test_result "auth_required" "FAIL" "Authentication bypass possible"
    echo "❌ FAIL: Authentication bypass possible"
  fi
  
  # Test for weak authentication
  weak_tokens=("" "null" "undefined" "admin" "test" "123456")
  
  for token in "${weak_tokens[@]}"; do
    response=$(curl -s -w "%{http_code}" -o /dev/null -H "Authorization: Bearer $token" "$API_BASE_URL/api/users/profile" || echo "000")
    
    if [ "$response" = "401" ] || [ "$response" = "403" ]; then
      continue
    else
      add_test_result "weak_token_protection" "FAIL" "Weak token accepted: $token"
      echo "❌ FAIL: Weak token accepted: $token"
      return
    fi
  done
  
  add_test_result "weak_token_protection" "PASS" "Weak tokens rejected"
  echo "✅ PASS: Weak tokens rejected"
}

# Function to test CORS configuration
test_cors_config() {
  echo "🌐 Testing CORS Configuration"
  
  # Test CORS headers
  cors_response=$(curl -s -H "Origin: https://evil.com" -H "Access-Control-Request-Method: GET" -H "Access-Control-Request-Headers: X-Requested-With" -X OPTIONS "$API_BASE_URL" || echo "")
  
  if echo "$cors_response" | grep -qi "Access-Control-Allow-Origin: https://evil.com"; then
    add_test_result "cors_wildcard" "FAIL" "CORS allows arbitrary origins"
    echo "❌ FAIL: CORS allows arbitrary origins"
  else
    add_test_result "cors_wildcard" "PASS" "CORS properly configured"
    echo "✅ PASS: CORS properly configured"
  fi
}

# Function to test information disclosure
test_info_disclosure() {
  echo "ℹ️  Testing Information Disclosure"
  
  # Test for server information disclosure
  server_header=$(curl -s -I "$API_BASE_URL" | grep -i "server:" || echo "")
  
  if echo "$server_header" | grep -qi "express\|node\|nginx/[0-9]"; then
    add_test_result "server_info_disclosure" "WARN" "Server information disclosed: $server_header"
    echo "⚠️  WARN: Server information disclosed"
  else
    add_test_result "server_info_disclosure" "PASS" "Server information properly hidden"
    echo "✅ PASS: Server information properly hidden"
  fi
  
  # Test for error information disclosure
  error_response=$(curl -s "$API_BASE_URL/nonexistent-endpoint" || echo "")
  
  if echo "$error_response" | grep -qi "stack\|trace\|error.*at\|internal server error"; then
    add_test_result "error_info_disclosure" "FAIL" "Detailed error information disclosed"
    echo "❌ FAIL: Detailed error information disclosed"
  else
    add_test_result "error_info_disclosure" "PASS" "Error information properly handled"
    echo "✅ PASS: Error information properly handled"
  fi
}

# Run all security tests
echo "🚀 Starting security tests..."

test_security_headers
test_rate_limiting
test_sql_injection
test_xss_protection
test_path_traversal
test_https_config
test_auth_security
test_cors_config
test_info_disclosure

# Generate summary
echo ""
echo "📊 Security Audit Summary"
echo "========================"

# Count test results
total_tests=$(jq '.tests | length' "$REPORT_FILE")
passed_tests=$(jq '[.tests[] | select(.status == "PASS")] | length' "$REPORT_FILE")
failed_tests=$(jq '[.tests[] | select(.status == "FAIL")] | length' "$REPORT_FILE")
warning_tests=$(jq '[.tests[] | select(.status == "WARN")] | length' "$REPORT_FILE")

echo "Total tests: $total_tests"
echo "Passed: $passed_tests"
echo "Failed: $failed_tests"
echo "Warnings: $warning_tests"

# Update summary in JSON
jq --argjson total "$total_tests" --argjson passed "$passed_tests" --argjson failed "$failed_tests" --argjson warnings "$warning_tests" \
  '.summary = {"total": $total, "passed": $passed, "failed": $failed, "warnings": $warnings}' \
  "$REPORT_FILE" > "$REPORT_FILE.tmp" && mv "$REPORT_FILE.tmp" "$REPORT_FILE"

echo ""
echo "📄 Detailed results saved to: $REPORT_FILE"

# Set exit code based on results
if [ "$failed_tests" -gt 0 ]; then
  echo "❌ Security audit completed with failures"
  exit 1
elif [ "$warning_tests" -gt 0 ]; then
  echo "⚠️  Security audit completed with warnings"
  exit 0
else
  echo "✅ Security audit completed successfully"
  exit 0
fi