Fix jwt-token

This commit is contained in:
2025-09-22 07:20:09 +02:00
parent 84ee9b3bc0
commit 223ae8980c

View File

@@ -1,25 +1,14 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
""" """
Orlan Detection Test Script Simplified Orlan Detection Test Script
Tests the critical alert system for Orlan military drones by simulating Tests the drone detection system by sending drone detections directly to the API
a long-distance approach from undetectable range to directly overhead. without authentication. This simulates drone sensor devices sending detections.
Test Scenario: Test Scenarios:
- Starts 50km away (beyond detection range) - Tests different drone types (Orlan, Zala, DJI, etc.)
- Slowly approaches target device - Tests different distances/RSSI values
- Triggers critical alerts as print(f"🛫 {drone_name} Starting Distance: {float(start_distance):.1f}km from device") - Tests critical vs normal threat levels
print(f"📍 Device Location: {target_lat:.6f}, {target_lon:.6f}") - Tests system response to detections
# Verify starting position is undetectable
if is_detectable(start_distance):
print("⚠️ WARNING: Starting position is within detection range!")
else:
print("✅ Starting position confirmed undetectable")
print("\n" + "=" * 70)
print(f"STARTING {drone_name.upper()} APPROACH SIMULATION")
print("=" * 70)etection range
- Ends with drone hovering directly above target
""" """
import requests import requests
@@ -34,73 +23,16 @@ import warnings
warnings.filterwarnings('ignore', message='Unverified HTTPS request') warnings.filterwarnings('ignore', message='Unverified HTTPS request')
# Configuration from environment variables # Configuration from environment variables
# Tests default to localhost:3002 for local development
API_BASE_URL = os.getenv('API_BASE_URL', 'http://localhost:3002/api') API_BASE_URL = os.getenv('API_BASE_URL', 'http://localhost:3002/api')
BASE_PATH = os.getenv('VITE_BASE_PATH', '').rstrip('/') BASE_PATH = os.getenv('VITE_BASE_PATH', '').rstrip('/')
# Authentication configuration - Optional for local testing
USERNAME = os.getenv('TEST_USERNAME', 'admin')
PASSWORD = os.getenv('TEST_PASSWORD', 'admin123')
SKIP_AUTH = os.getenv('SKIP_AUTH', 'false').lower() == 'true' # Set to 'true' to skip authentication
# If BASE_PATH is set, construct the full URL # If BASE_PATH is set, construct the full URL
if BASE_PATH and not API_BASE_URL.endswith('/api'): if BASE_PATH and not API_BASE_URL.endswith('/api'):
# Extract domain from API_BASE_URL and add base path
domain = API_BASE_URL.replace('/api', '').replace('/drones/api', '').replace('/uggla/api', '') domain = API_BASE_URL.replace('/api', '').replace('/drones/api', '').replace('/uggla/api', '')
API_BASE_URL = f"{domain}{BASE_PATH}/api" API_BASE_URL = f"{domain}{BASE_PATH}/api"
print(f"🔗 Using API Base URL: {API_BASE_URL}") print(f"🔗 Using API Base URL: {API_BASE_URL}")
# Global variable to store authentication token
AUTH_TOKEN = None
def authenticate():
"""Authenticate with the API and get access token"""
global AUTH_TOKEN
login_data = {
"username": USERNAME,
"password": PASSWORD
}
try:
print(f"🔐 Authenticating as user: {USERNAME}")
response = requests.post(f"{API_BASE_URL}/users/login", json=login_data, verify=False)
if response.status_code == 200:
data = response.json()
AUTH_TOKEN = data.get('data', {}).get('token')
if AUTH_TOKEN:
print("✅ Authentication successful")
return True
else:
print("❌ No token received in response")
print(f"Response data: {data}")
return False
else:
print(f"❌ Authentication failed: {response.status_code}")
print(f"Response: {response.text}")
return False
except Exception as e:
print(f"❌ Authentication error: {e}")
return False
def get_auth_headers():
"""Get headers with authentication token"""
if SKIP_AUTH:
return {"Content-Type": "application/json"}
if AUTH_TOKEN:
return {
"Authorization": f"Bearer {AUTH_TOKEN}",
"Content-Type": "application/json"
}
return {"Content-Type": "application/json"}
# Detection range parameters (approximate)
MAX_DETECTION_RANGE_KM = 25.0 # Maximum range for drone detection
MIN_RSSI_THRESHOLD = -95 # Minimum RSSI for detection
# Drone types mapping (matches GuessedDroneType enum) # Drone types mapping (matches GuessedDroneType enum)
DRONE_TYPES = { DRONE_TYPES = {
0: "None", 0: "None",
@@ -124,311 +56,249 @@ DRONE_TYPES = {
18: "DJIe" 18: "DJIe"
} }
def select_drone_type(): # Detection range parameters
"""Allow user to select drone type for simulation""" MAX_DETECTION_RANGE_KM = 25.0 # Maximum range for drone detection
print("\n" + "=" * 50) MIN_RSSI_THRESHOLD = -95 # Minimum RSSI for detection
print("🚁 DRONE TYPE SELECTION")
print("=" * 50)
print("Available drone types:")
# Group by category for better display
military_types = [(k, v) for k, v in DRONE_TYPES.items() if v in ["Orlan", "Zala", "Eleron", "ZalaLancet", "Lancet", "CryptoOrlan"]]
maybe_types = [(k, v) for k, v in DRONE_TYPES.items() if v.startswith("Maybe")]
fpv_types = [(k, v) for k, v in DRONE_TYPES.items() if v.startswith("FPV_")]
commercial_types = [(k, v) for k, v in DRONE_TYPES.items() if v in ["DJI", "DJIe", "Supercam", "MaybeSupercam"]]
other_types = [(k, v) for k, v in DRONE_TYPES.items() if v in ["None", "Unknown", "REB"]]
print("\n🎖️ MILITARY DRONES:")
for drone_id, name in military_types:
print(f" {drone_id:2d}: {name}")
print("\n🏢 COMMERCIAL DRONES:")
for drone_id, name in commercial_types:
print(f" {drone_id:2d}: {name}")
print("\n🎮 FPV DRONES:")
for drone_id, name in fpv_types:
print(f" {drone_id:2d}: {name}")
print("\n❓ UNCERTAIN TYPES:")
for drone_id, name in maybe_types:
print(f" {drone_id:2d}: {name}")
print("\n🔧 OTHER:")
for drone_id, name in other_types:
print(f" {drone_id:2d}: {name}")
print("\n" + "=" * 50)
while True:
try:
choice = input(f"Select drone type (0-{max(DRONE_TYPES.keys())}) [default: 2-Orlan]: ").strip()
if choice == "":
return 2 # Default to Orlan
drone_type = int(choice)
if drone_type in DRONE_TYPES:
print(f"✅ Selected: {DRONE_TYPES[drone_type]} (Type {drone_type})")
return drone_type
else:
print(f"❌ Invalid choice. Please select 0-{max(DRONE_TYPES.keys())}")
except ValueError:
print("❌ Please enter a valid number")
except KeyboardInterrupt:
print("\n⚠️ Using default: Orlan (Type 2)")
return 2
def haversine_distance(lat1, lon1, lat2, lon2):
"""Calculate distance between two points in kilometers"""
R = 6371 # Earth's radius in kilometers
dlat = math.radians(lat2 - lat1)
dlon = math.radians(lon2 - lon1)
a = (math.sin(dlat/2) * math.sin(dlat/2) +
math.cos(math.radians(lat1)) * math.cos(math.radians(lat2)) *
math.sin(dlon/2) * math.sin(dlon/2))
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))
return R * c
def rssi_from_distance(distance_km): def rssi_from_distance(distance_km):
"""Calculate RSSI based on distance for Orlan drone""" """Calculate RSSI based on distance for drone detection"""
# Ensure distance_km is a float
distance_km = float(distance_km) distance_km = float(distance_km)
# Orlan drones have powerful military-grade transmission systems # If beyond detection range, return very weak signal
# Base RSSI at 1km = -55 dBm (stronger than civilian drones) if distance_km > MAX_DETECTION_RANGE_KM:
base_rssi = -55 return MIN_RSSI_THRESHOLD - 10 # Undetectable
path_loss_exponent = 2.3 # Lower path loss due to military equipment
if distance_km < 0.001: # Less than 1 meter # RSSI calculation based on free space path loss
return -25 # Closer distance = stronger signal (higher RSSI)
# Formula: RSSI = -40 - 20*log10(distance_km)
rssi = -40 - (20 * math.log10(max(distance_km, 0.1))) # Avoid log(0)
rssi = base_rssi - (20 * path_loss_exponent * math.log10(distance_km)) # Clamp to realistic range (-30 to -100 dBm)
return max(rssi, -100) # Cap at -100 dBm return max(-100, min(-30, rssi))
def is_detectable(distance_km): def is_detectable(distance_km):
"""Check if drone is within detectable range""" """Check if drone is within detectable range"""
rssi = rssi_from_distance(distance_km) return distance_km <= MAX_DETECTION_RANGE_KM and rssi_from_distance(distance_km) >= MIN_RSSI_THRESHOLD
return distance_km <= MAX_DETECTION_RANGE_KM and rssi >= MIN_RSSI_THRESHOLD
def fetch_devices(): def get_threat_level(distance_km, drone_type):
"""Fetch devices from API""" """Determine threat level based on distance and drone type"""
try: if distance_km <= 1:
if SKIP_AUTH: return "critical"
# Try without authentication first for local testing elif distance_km <= 5:
response = requests.get(f"{API_BASE_URL}/devices/map", verify=False) return "high"
else: elif distance_km <= 15:
response = requests.get(f"{API_BASE_URL}/devices", headers=get_auth_headers(), verify=False) return "medium"
else:
if response.status_code == 200: return "low"
data = response.json()
return data.get('data', [])
else:
print(f"Failed to fetch devices: {response.status_code}")
print(f"Response: {response.text}")
except Exception as e:
print(f"Error fetching devices: {e}")
return []
def send_detection(device, distance_km, step, total_steps, drone_type=2): def send_drone_detection(device_id, drone_type, distance_km, drone_id=2000):
"""Send a detection to the API using EXACT standard payload format""" """Send a drone detection to the API"""
# Ensure distance_km is a float
distance_km = float(distance_km) distance_km = float(distance_km)
rssi = rssi_from_distance(distance_km) rssi = rssi_from_distance(distance_km)
# Use the device's coordinates as the detection location # Sample device coordinates (Stockholm Central)
# The RSSI indicates how close/far the drone is from this device device_lat = 59.3293
device_lon = 18.0686
detection_data = { detection_data = {
"device_id": device["id"], "device_id": device_id,
"geo_lat": float(device["geo_lat"]), # Device location "geo_lat": device_lat,
"geo_lon": float(device["geo_lon"]), # Device location "geo_lon": device_lon,
"device_timestamp": int(time.time() * 1000), # Current timestamp in milliseconds "device_timestamp": int(time.time()), # Unix timestamp in seconds
"drone_type": drone_type, # Selected drone type "drone_type": drone_type,
"rssi": int(rssi), # RSSI indicates distance from device "rssi": int(rssi),
"freq": 24, # Most drones operate on 2.4 GHz (24 = 2400 MHz) "freq": 24, # 2.4 GHz frequency
"drone_id": 2000 # Consistent drone ID to track the same drone "drone_id": drone_id
} }
try: try:
response = requests.post(f"{API_BASE_URL}/detectors", json=detection_data, verify=False) print(f"📡 Sending detection: Device={device_id}, Drone={DRONE_TYPES.get(drone_type, 'Unknown')}, Distance={distance_km:.1f}km, RSSI={rssi:.0f}dBm")
response = requests.post(
f"{API_BASE_URL}/detectors",
json=detection_data,
headers={"Content-Type": "application/json"},
verify=False
)
if response.status_code == 201: if response.status_code == 201:
status = "🚨 CRITICAL ALERT" if distance_km <= 5 else "⚠️ DETECTED" if is_detectable(distance_km) else "📡 MONITORING" threat = get_threat_level(distance_km, drone_type)
print(f"{status} - Step {step}/{total_steps}: Distance={float(distance_km):.1f}km, RSSI={float(rssi):.0f}dBm") status_icon = "🚨" if threat in ["critical", "high"] else "⚠️" if threat == "medium" else "📡"
print(f"{status_icon} SUCCESS: Detection sent successfully - Threat Level: {threat.upper()}")
return True return True
else: else:
print(f"❌ Failed to send detection: {response.status_code}") print(f"❌ FAILED: {response.status_code} - {response.text}")
print(f"Response: {response.text}")
return False return False
except Exception as e: except Exception as e:
print(f"❌ Error sending detection: {e}") print(f"❌ ERROR: {e}")
return False return False
def run_orlan_detection_test(): def test_drone_approach_scenario(device_id, drone_type=2):
"""Run the comprehensive drone detection test""" """Test a drone approaching from distance to overhead"""
print("=" * 70) print(f"\n{'='*70}")
print("<EFBFBD> DRONE DETECTION SIMULATION TEST") print(f"🚁 DRONE APPROACH SIMULATION")
print("=" * 70) print(f"Device ID: {device_id}")
print("Test Scenario:") print(f"Drone Type: {DRONE_TYPES.get(drone_type, 'Unknown')} (Type {drone_type})")
print("• Starting position: 50km away (undetectable)") print(f"{'='*70}")
print("• Approach pattern: Gradual approach to device")
print("• Detection threshold: ~25km range")
print("• Critical alerts: <5km from device")
print("• End position: Directly overhead (0m)")
print("=" * 70)
print(f"🔗 API Endpoint: {API_BASE_URL}")
if SKIP_AUTH:
print("⚠️ AUTHENTICATION DISABLED - Running in local test mode")
print()
# Select drone type for simulation # Test distances: 30km -> 20km -> 10km -> 5km -> 1km -> 0.1km
selected_drone_type = select_drone_type() test_distances = [30.0, 20.0, 10.0, 5.0, 1.0, 0.1]
drone_name = DRONE_TYPES[selected_drone_type] drone_id = 2000 + drone_type # Unique drone ID per type
# Authenticate first (unless skipped) successful_detections = 0
if not SKIP_AUTH and not authenticate():
print("❌ Authentication failed. Cannot proceed with test.")
print("Please check:")
print("1. Is the server running?")
print("2. Are the credentials correct?")
print(f" Username: {USERNAME}")
print("3. Set TEST_USERNAME and TEST_PASSWORD environment variables if needed")
print("4. Or set SKIP_AUTH=true to skip authentication for local testing")
return
# Test API connectivity first for i, distance in enumerate(test_distances, 1):
print("🔍 Testing API connectivity...") print(f"\n📍 Step {i}/{len(test_distances)}: Testing {distance}km distance")
try:
response = requests.get(f"{API_BASE_URL}/health") if is_detectable(distance):
if response.status_code == 200: success = send_drone_detection(device_id, drone_type, distance, drone_id)
print("✅ API is accessible") if success:
successful_detections += 1
time.sleep(1) # Small delay between detections
else: else:
print(f"❌ API health check failed: {response.status_code}") print(f"📡 Distance {distance}km is beyond detection range ({MAX_DETECTION_RANGE_KM}km)")
return
except Exception as e:
print(f"❌ Cannot connect to API: {e}")
print("Please check:")
print("1. Is the server running?")
print("2. Is the API_BASE_URL correct?")
print(f" Current: {API_BASE_URL}")
return
# Fetch devices print(f"\n✅ Approach simulation complete: {successful_detections} successful detections")
print("📡 Fetching devices...") return successful_detections
devices = fetch_devices()
if not devices: def test_multiple_drone_types(device_id):
print("❌ No devices found!") """Test different drone types at critical distance"""
print("Make sure at least one device is registered in the system.") print(f"\n{'='*70}")
return print(f"🛩️ MULTIPLE DRONE TYPES TEST")
print(f"Device ID: {device_id}")
print(f"Testing at critical distance: 2km")
print(f"{'='*70}")
print(f"✅ Found {len(devices)} device(s)") # Test important drone types
test_types = [2, 3, 6, 13, 17] # Orlan, Zala, Lancet, DJI, CryptoOrlan
distance = 2.0 # Critical distance
# Use the first device as target successful_detections = 0
target_device = devices[0]
print(f"🎯 Target Device: {target_device['name']}")
# Ensure coordinates are floats for drone_type in test_types:
target_lat = float(target_device['geo_lat']) drone_name = DRONE_TYPES.get(drone_type, 'Unknown')
target_lon = float(target_device['geo_lon']) print(f"\n🚁 Testing {drone_name} (Type {drone_type})")
drone_id = 3000 + drone_type # Unique drone ID per type
success = send_drone_detection(device_id, drone_type, distance, drone_id)
if success:
successful_detections += 1
time.sleep(1)
print(f"📍 Target Location: {target_lat:.6f}, {target_lon:.6f}") print(f"\n✅ Multi-drone test complete: {successful_detections}/{len(test_types)} successful detections")
return successful_detections
def test_rapid_detections(device_id, drone_type=2):
"""Test rapid successive detections (like drone hovering)"""
print(f"\n{'='*70}")
print(f"⚡ RAPID DETECTION TEST")
print(f"Device ID: {device_id}")
print(f"Drone Type: {DRONE_TYPES.get(drone_type, 'Unknown')} (Type {drone_type})")
print(f"Simulating drone hovering at 0.5km distance")
print(f"{'='*70}")
# Calculate starting position 50km away for distance simulation distance = 0.5 # Very close - critical threat
start_distance = 50.0 # km drone_id = 4000 # Unique drone ID
detection_count = 5
successful_detections = 0
print(f"🛫 Orlan Starting Distance: {float(start_distance):.1f}km from device") for i in range(1, detection_count + 1):
print(f"<EFBFBD> Device Location: {target_lat:.6f}, {target_lon:.6f}") print(f"\n🔄 Rapid detection {i}/{detection_count}")
success = send_drone_detection(device_id, drone_type, distance, drone_id)
if success:
successful_detections += 1
time.sleep(0.5) # Rapid fire
# Verify starting position is undetectable print(f"\n✅ Rapid detection test complete: {successful_detections}/{detection_count} successful detections")
if is_detectable(start_distance): return successful_detections
print("⚠️ WARNING: Starting position is within detection range!")
def run_detection_tests():
"""Run comprehensive drone detection tests"""
print("🚀 DRONE DETECTION SYSTEM TEST")
print("="*70)
print("This script tests drone detection by sending detection data directly")
print("to the API without authentication (simulating sensor devices).")
print("="*70)
# Use known device IDs from the setup database
# These should exist if setup-database.js ran successfully
test_device_ids = [
"device-alpha-001",
"device-beta-002",
"device-gamma-003"
]
# Try each device until we find one that works
working_device = None
for device_id in test_device_ids:
print(f"\n🔍 Testing device: {device_id}")
success = send_drone_detection(device_id, 2, 5.0, 9999) # Test detection
if success:
working_device = device_id
print(f"✅ Device {device_id} is working and approved")
break
else:
print(f"❌ Device {device_id} failed (not found or not approved)")
if not working_device:
print("\n❌ No working devices found!")
print("Make sure the database setup script has run and devices are approved.")
return False
print(f"\n🎯 Using device: {working_device}")
# Run test scenarios
total_tests = 0
total_successful = 0
print(f"\n{'='*70}")
print("STARTING TEST SCENARIOS")
print(f"{'='*70}")
# Test 1: Drone approach scenario
successful = test_drone_approach_scenario(working_device, 2) # Orlan
total_tests += 6 # Number of distance steps
total_successful += successful
# Test 2: Multiple drone types
successful = test_multiple_drone_types(working_device)
total_tests += 5 # Number of drone types
total_successful += successful
# Test 3: Rapid detections
successful = test_rapid_detections(working_device, 6) # Lancet
total_tests += 5 # Number of rapid detections
total_successful += successful
# Summary
print(f"\n{'='*70}")
print("TEST SUMMARY")
print(f"{'='*70}")
print(f"Total Tests: {total_tests}")
print(f"Successful: {total_successful}")
print(f"Failed: {total_tests - total_successful}")
print(f"Success Rate: {(total_successful/total_tests)*100:.1f}%")
if total_successful == total_tests:
print("🎉 ALL TESTS PASSED! Detection system is working correctly.")
elif total_successful > 0:
print("⚠️ PARTIAL SUCCESS - Some detections failed.")
else: else:
print("✅ Starting position confirmed undetectable") print("❌ ALL TESTS FAILED - Detection system has issues.")
print("\n" + "=" * 70) print(f"\n💡 Check the backend logs for detailed processing information.")
print("STARTING ORLAN APPROACH SIMULATION") print(f"💡 Check the dashboard to see if detections appear in real-time.")
print("=" * 70)
# Simulation parameters return total_successful == total_tests
total_steps = 50 # More steps for gradual approach
final_distance = 0.0 # Directly overhead
detection_started = False
critical_alerts_started = False
for step in range(1, total_steps + 1):
# Calculate current distance using exponential approach for realistic acceleration
progress = step / total_steps
# Use exponential curve for realistic approach - slower at distance, faster when close
distance_km = start_distance * (1 - progress) ** 1.8 + final_distance * progress ** 1.8
# Check detection status
detectable = is_detectable(distance_km)
# Send detection only if within detectable range
if detectable:
if not detection_started:
print(f"\n🔍 FIRST DETECTION at {float(distance_km):.1f}km - {drone_name} has entered detection range!")
detection_started = True
success = send_detection(target_device, distance_km, step, total_steps, selected_drone_type)
if not success:
print(f"❌ Failed to send detection at step {step}")
continue
# Show escalation messages
if distance_km <= 5 and not critical_alerts_started:
print(f"🚨 CRITICAL ALERT THRESHOLD REACHED at {float(distance_km):.1f}km!")
critical_alerts_started = True
elif distance_km <= 1:
print(f"🔥 IMMEDIATE THREAT: {drone_name} within {float(distance_km):.1f}km!")
elif distance_km <= 0.1:
print(f"💥 DIRECTLY OVERHEAD: {drone_name} at {float(distance_km)*1000:.0f}m altitude!")
else:
# Outside detection range
print(f"📡 Step {step}/{total_steps}: Distance={float(distance_km):.1f}km (undetectable, RSSI={float(rssi_from_distance(distance_km)):.0f}dBm)")
# Variable delay based on distance
if distance_km > 30:
delay = 2.0 # 2 seconds for very long range
elif distance_km > 15:
delay = 1.5 # 1.5 seconds for long range
elif distance_km > 5:
delay = 1.0 # 1 second for medium range
else:
delay = 0.8 # Faster updates for critical proximity
time.sleep(delay)
print("\n" + "=" * 70)
print(f"<EFBFBD> {drone_name.upper()} DETECTION TEST COMPLETED")
print("=" * 70)
print("Test Summary:")
print(f"• Starting distance: {float(start_distance):.1f}km (undetectable)")
print(f"• Detection range entered: ~{float(MAX_DETECTION_RANGE_KM):.1f}km")
print(f"• Critical alerts triggered: <5km")
print(f"• Final position: Directly overhead")
print(f"• Target device: {target_device['name']}")
print(f"• Drone type tested: {drone_name} (Type {selected_drone_type})")
print(f"• Total simulation steps: {total_steps}")
print("")
print("Expected Results:")
print("✅ No detections sent while >25km away")
print("✅ First detection when entering ~25km range")
print(f"✅ Critical alerts triggered for {drone_name} type (drone_type={selected_drone_type})")
print("✅ All alerts escalated regardless of distance/RSSI")
print("✅ Real-time tracking visible on dashboard")
print("=" * 70)
if __name__ == "__main__": if __name__ == "__main__":
try: try:
run_orlan_detection_test() success = run_detection_tests()
exit(0 if success else 1)
except KeyboardInterrupt: except KeyboardInterrupt:
print("\n\n⚠️ Drone detection test interrupted by user") print("\n⚠️ Test interrupted by user")
exit(1)
except Exception as e: except Exception as e:
print(f"\nError during drone detection test: {e}") print(f"\nTest failed with error: {e}")
exit(1)