Fix jwt-token

This commit is contained in:
2025-08-17 09:21:05 +02:00
parent 3c8d5fab9d
commit d23d2dbbce
4 changed files with 311 additions and 94 deletions

12
clear_database.sh Normal file
View File

@@ -0,0 +1,12 @@
#!/bin/bash
# Clear database via API calls (if we add the endpoint)
API_BASE="http://selfservice.cqers.com/drones/api"
echo "🗑️ Clearing database via API..."
# Clear detections
curl -X DELETE "$API_BASE/detections/clear" \
-H "Content-Type: application/json"
echo "✅ Database cleared"

View File

@@ -24,11 +24,15 @@ const io = new Server(server, {
} }
}); });
// Rate limiting // Rate limiting (exclude detections endpoint for testing)
const limiter = rateLimit({ const limiter = rateLimit({
windowMs: parseInt(process.env.RATE_LIMIT_WINDOW_MS) || 15 * 60 * 1000, // 15 minutes windowMs: parseInt(process.env.RATE_LIMIT_WINDOW_MS) || 15 * 60 * 1000, // 15 minutes
max: parseInt(process.env.RATE_LIMIT_MAX_REQUESTS) || 100, max: parseInt(process.env.RATE_LIMIT_MAX_REQUESTS) || 100,
message: 'Too many requests from this IP, please try again later.' message: 'Too many requests from this IP, please try again later.',
skip: (req) => {
// Skip rate limiting for drone detection endpoints during testing
return req.path.includes('/detections');
}
}); });
// Middleware // Middleware

29
server/resetDatabase.js Normal file
View File

@@ -0,0 +1,29 @@
#!/usr/bin/env node
/**
* Database Reset Script
* Forces database sync and reseeds data
*/
const { sequelize } = require('./models');
const seedDatabase = require('./seedDatabase');
async function resetDatabase() {
try {
console.log('🗑️ Resetting database...');
// Force sync (drops and recreates all tables)
await sequelize.sync({ force: true });
console.log('✅ Database tables recreated');
// Reseed with initial data
await seedDatabase();
console.log('✅ Database reset complete');
process.exit(0);
} catch (error) {
console.error('❌ Database reset failed:', error);
process.exit(1);
}
}
resetDatabase();

View File

@@ -1,14 +1,15 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
""" """
Drone Detection Test Script Realistic Drone Detection Test Script
Sends simulated drone detection data to the API for testing purposes. Simulates realistic drone scenarios with persistent tracking, RSSI changes, and real-world patterns.
""" """
import requests import requests
import json import json
import time import time
import random import random
from datetime import datetime import math
from datetime import datetime, timedelta
# Configuration # Configuration
API_BASE_URL = "http://selfservice.cqers.com/drones/api" API_BASE_URL = "http://selfservice.cqers.com/drones/api"
@@ -20,52 +21,214 @@ DEVICES = [
"id": 1, "id": 1,
"name": "Stockholm Central Detector", "name": "Stockholm Central Detector",
"lat": 59.3293, "lat": 59.3293,
"lon": 18.0686 "lon": 18.0686,
"coverage_radius": 5.0 # km
}, },
{ {
"id": 2, "id": 2,
"name": "Arlanda Airport Detector", "name": "Arlanda Airport Detector",
"lat": 59.6519, "lat": 59.6519,
"lon": 17.9186 "lon": 17.9186,
"coverage_radius": 8.0 # km
}, },
{ {
"id": 3, "id": 3,
"name": "Göteborg Harbor Detector", "name": "Göteborg Harbor Detector",
"lat": 57.7089, "lat": 57.7089,
"lon": 11.9746 "lon": 11.9746,
"coverage_radius": 6.0 # km
} }
] ]
# Drone types # Realistic drone types with characteristics
DRONE_TYPES = { DRONE_TYPES = {
0: "Unknown", 1: {"name": "DJI Mavic", "max_speed": 65, "typical_rssi": -60, "freq": [2400, 2450]},
1: "Commercial DJI", 2: {"name": "Racing Drone", "max_speed": 120, "typical_rssi": -55, "freq": [2400, 5800]},
2: "Racing Drone", 3: {"name": "DJI Phantom", "max_speed": 50, "typical_rssi": -65, "freq": [2400, 2450]},
3: "Fixed Wing", 4: {"name": "Fixed Wing", "max_speed": 80, "typical_rssi": -70, "freq": [900, 2400]},
4: "Military/Surveillance", 5: {"name": "Surveillance", "max_speed": 40, "typical_rssi": -75, "freq": [2400, 5800]}
5: "Custom Build"
} }
def generate_detection_data(device): class DroneSimulator:
"""Generate realistic drone detection data""" def __init__(self):
self.active_drones = {} # Track persistent drones
self.drone_counter = 1000
# Random position near the device (within ~5km radius) def calculate_rssi(self, distance_km, base_rssi=-60):
lat_offset = random.uniform(-0.045, 0.045) # ~5km latitude """Calculate realistic RSSI based on distance (Free Space Path Loss)"""
lon_offset = random.uniform(-0.09, 0.09) # ~5km longitude if distance_km < 0.1: # Very close
return max(base_rssi + 20, -30)
# Simplified FSPL: RSSI decreases ~20dB per decade of distance
rssi = base_rssi - (20 * math.log10(distance_km))
# Add some realistic variation
variation = random.uniform(-5, 5)
final_rssi = int(rssi + variation)
# Clamp to realistic values
return max(min(final_rssi, -30), -100)
def calculate_distance(self, lat1, lon1, lat2, lon2):
"""Calculate distance between two points in km"""
R = 6371 # Earth radius in km
lat1_rad = math.radians(lat1)
lat2_rad = math.radians(lat2)
delta_lat = math.radians(lat2 - lat1)
delta_lon = math.radians(lon2 - lon1)
a = (math.sin(delta_lat/2)**2 +
math.cos(lat1_rad) * math.cos(lat2_rad) * math.sin(delta_lon/2)**2)
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))
return R * c
def create_new_drone(self, device):
"""Create a new drone with realistic starting position"""
self.drone_counter += 1
drone_type = random.choice(list(DRONE_TYPES.keys()))
# Start at edge of coverage area
angle = random.uniform(0, 2 * math.pi)
start_distance = device["coverage_radius"] * random.uniform(0.8, 1.0)
start_lat = device["lat"] + (start_distance / 111.0) * math.cos(angle)
start_lon = device["lon"] + (start_distance / (111.0 * math.cos(math.radians(device["lat"])))) * math.sin(angle)
# Movement pattern
patterns = ["approaching", "patrolling", "departing", "hovering"]
movement_pattern = random.choice(patterns)
drone = {
"id": self.drone_counter,
"type": drone_type,
"lat": start_lat,
"lon": start_lon,
"target_lat": device["lat"] if movement_pattern == "approaching" else start_lat,
"target_lon": device["lon"] if movement_pattern == "approaching" else start_lon,
"speed_kmh": DRONE_TYPES[drone_type]["max_speed"] * random.uniform(0.3, 0.8),
"pattern": movement_pattern,
"created_at": time.time(),
"last_detection": 0,
"detection_count": 0,
"is_active": True
}
return drone
def update_drone_position(self, drone, time_delta_seconds):
"""Update drone position based on movement pattern"""
if not drone["is_active"]:
return
speed_ms = drone["speed_kmh"] * 1000 / 3600 # Convert to m/s
distance_m = speed_ms * time_delta_seconds
if drone["pattern"] == "approaching":
# Move towards the device center
current_distance = self.calculate_distance(
drone["lat"], drone["lon"],
drone["target_lat"], drone["target_lon"]
) * 1000 # Convert to meters
if current_distance > 100: # Still approaching
lat_diff = drone["target_lat"] - drone["lat"]
lon_diff = drone["target_lon"] - drone["lon"]
total_diff = math.sqrt(lat_diff**2 + lon_diff**2)
if total_diff > 0:
lat_step = (lat_diff / total_diff) * (distance_m / 111000)
lon_step = (lon_diff / total_diff) * (distance_m / 111000)
drone["lat"] += lat_step
drone["lon"] += lon_step
else:
# Reached target, switch to hovering
drone["pattern"] = "hovering"
elif drone["pattern"] == "hovering":
# Small random movements
drone["lat"] += random.uniform(-0.0001, 0.0001)
drone["lon"] += random.uniform(-0.0001, 0.0001)
elif drone["pattern"] == "patrolling":
# Circular or figure-8 movement
t = (time.time() - drone["created_at"]) / 100 # Slow circular motion
radius = 0.002 # Small patrol radius
drone["lat"] = drone["target_lat"] + radius * math.sin(t)
drone["lon"] = drone["target_lon"] + radius * math.cos(t)
elif drone["pattern"] == "departing":
# Move away from device
lat_diff = drone["lat"] - drone["target_lat"]
lon_diff = drone["lon"] - drone["target_lon"]
total_diff = math.sqrt(lat_diff**2 + lon_diff**2)
if total_diff > 0:
lat_step = (lat_diff / total_diff) * (distance_m / 111000)
lon_step = (lon_diff / total_diff) * (distance_m / 111000)
drone["lat"] += lat_step
drone["lon"] += lon_step
def should_detect_drone(self, drone, device):
"""Determine if device should detect this drone"""
distance_km = self.calculate_distance(
drone["lat"], drone["lon"],
device["lat"], device["lon"]
)
# Detection probability decreases with distance
if distance_km > device["coverage_radius"]:
return False, distance_km
# Higher chance of detection when closer
detection_prob = 1.0 - (distance_km / device["coverage_radius"]) * 0.7
# Factor in time since last detection (avoid spam)
time_since_last = time.time() - drone.get("last_detection", 0)
if time_since_last < 2: # Minimum 2 seconds between detections
detection_prob *= 0.1
return random.random() < detection_prob, distance_km
def generate_detection(self, drone, device, distance_km):
"""Generate realistic detection data"""
drone_info = DRONE_TYPES[drone["type"]]
# Calculate RSSI based on distance
rssi = self.calculate_rssi(distance_km, drone_info["typical_rssi"])
# Select frequency
freq = random.choice(drone_info["freq"])
# Confidence decreases with distance and lower RSSI
base_confidence = 0.95 - (distance_km / 10.0) * 0.3
rssi_factor = (rssi + 100) / 70 # Normalize RSSI to 0-1
confidence = max(0.5, min(0.99, base_confidence * rssi_factor))
# Signal duration varies by drone type and detection quality
duration_base = 2000 if drone["pattern"] == "hovering" else 1000
duration = duration_base + random.randint(-500, 1500)
detection = { detection = {
"device_id": device["id"], "device_id": device["id"],
"drone_id": random.randint(1000, 9999), "drone_id": drone["id"],
"drone_type": random.randint(0, 5), "drone_type": drone["type"],
"rssi": random.randint(-90, -30), # Signal strength in dBm "rssi": rssi,
"freq": random.choice([2400, 2450, 5800, 5850]), # Common drone frequencies "freq": freq,
"geo_lat": device["lat"] + lat_offset, "geo_lat": drone["lat"],
"geo_lon": device["lon"] + lon_offset, "geo_lon": drone["lon"],
"device_timestamp": int(time.time() * 1000), # Unix timestamp in ms "device_timestamp": int(time.time() * 1000),
"confidence_level": round(random.uniform(0.6, 1.0), 2), "confidence_level": round(confidence, 2),
"signal_duration": random.randint(500, 5000) # Duration in ms "signal_duration": max(500, duration)
} }
# Update drone tracking
drone["last_detection"] = time.time()
drone["detection_count"] += 1
return detection return detection
def send_detection(detection_data): def send_detection(detection_data):
@@ -79,66 +242,89 @@ def send_detection(detection_data):
response = requests.post(url, json=detection_data, headers=headers, timeout=10) response = requests.post(url, json=detection_data, headers=headers, timeout=10)
if response.status_code == 201: if response.status_code == 201:
print(f"✅ Detection sent successfully: Device {detection_data['device_id']}, " print(f"✅ Device {detection_data['device_id']}: Drone {detection_data['drone_id']} "
f"Drone {detection_data['drone_id']}, RSSI {detection_data['rssi']}dBm") f"(RSSI: {detection_data['rssi']}dBm, Dist: ~{detection_data.get('_distance', 'N/A')}km)")
return True return True
else: else:
print(f"❌ Failed to send detection: {response.status_code} - {response.text}") print(f"❌ Failed: {response.status_code} - {response.text}")
return False return False
except requests.exceptions.RequestException as e: except requests.exceptions.RequestException as e:
print(f"❌ Network error: {e}") print(f"❌ Network error: {e}")
return False return False
def test_single_detection(): def simulate_realistic_scenario(duration_minutes=10):
"""Send a single test detection""" """Simulate realistic drone scenario with persistent tracking"""
device = random.choice(DEVICES) print(f"🚁 Starting realistic drone simulation for {duration_minutes} minutes...")
detection = generate_detection_data(device) print("📊 Scenario: Multiple drones with persistent tracking, RSSI changes, movement patterns")
print("=" * 80)
print("🚁 Sending single test detection...")
print(f"📍 Device: {device['name']}")
print(f"🛰️ Drone ID: {detection['drone_id']}")
print(f"📡 RSSI: {detection['rssi']}dBm")
print(f"📊 Frequency: {detection['freq']}MHz")
print(f"🎯 Confidence: {detection['confidence_level']}")
return send_detection(detection)
def simulate_continuous_detections(duration_minutes=5, interval_seconds=10):
"""Simulate continuous drone detections for testing"""
print(f"🔄 Starting continuous simulation for {duration_minutes} minutes...")
print(f"⏱️ Sending detection every {interval_seconds} seconds")
print("Press Ctrl+C to stop\n")
simulator = DroneSimulator()
start_time = time.time() start_time = time.time()
end_time = start_time + (duration_minutes * 60) end_time = start_time + (duration_minutes * 60)
detection_count = 0 detection_count = 0
last_update = start_time
try: try:
while time.time() < end_time: while time.time() < end_time:
# Generate 1-3 simultaneous detections from different devices current_time = time.time()
num_detections = random.randint(1, 3) time_delta = current_time - last_update
last_update = current_time
for _ in range(num_detections): # Randomly spawn new drones (1-15% chance per cycle)
if random.random() < 0.15 and len(simulator.active_drones) < 8:
device = random.choice(DEVICES) device = random.choice(DEVICES)
detection = generate_detection_data(device) new_drone = simulator.create_new_drone(device)
simulator.active_drones[new_drone["id"]] = new_drone
print(f"🆕 New {DRONE_TYPES[new_drone['type']]['name']} spawned near {device['name']}")
# Update all active drones
drones_to_remove = []
for drone_id, drone in simulator.active_drones.items():
simulator.update_drone_position(drone, time_delta)
# Check if drone should be removed (too far or timeout)
age_minutes = (current_time - drone["created_at"]) / 60
if age_minutes > 15 or drone["detection_count"] > 50:
drones_to_remove.append(drone_id)
continue
# Check detection for each device
for device in DEVICES:
should_detect, distance = simulator.should_detect_drone(drone, device)
if should_detect:
detection = simulator.generate_detection(drone, device, distance)
detection["_distance"] = f"{distance:.1f}" # For logging only
if send_detection(detection): if send_detection(detection):
detection_count += 1 detection_count += 1
# Small delay between simultaneous detections # Remove expired drones
time.sleep(0.5) for drone_id in drones_to_remove:
drone = simulator.active_drones[drone_id]
print(f"🛬 {DRONE_TYPES[drone['type']]['name']} {drone_id} finished ({drone['detection_count']} detections)")
del simulator.active_drones[drone_id]
time.sleep(interval_seconds) # Status update
elapsed_minutes = (current_time - start_time) / 60
if int(elapsed_minutes) % 2 == 0 and elapsed_minutes > 0:
active_count = len(simulator.active_drones)
if active_count > 0:
print(f"📍 Status: {active_count} active drones, {detection_count} total detections")
time.sleep(3) # 3 second cycle time
except KeyboardInterrupt: except KeyboardInterrupt:
print("\n⏹️ Simulation stopped by user") print("\n⏹️ Simulation stopped by user")
elapsed = time.time() - start_time elapsed = time.time() - start_time
print(f"\n📈 Simulation completed:") print(f"\n📈 Simulation Summary:")
print(f" • Duration: {elapsed/60:.1f} minutes") print(f" • Duration: {elapsed/60:.1f} minutes")
print(f"Detections sent: {detection_count}") print(f"Total detections: {detection_count}")
print(f" • Average rate: {detection_count/(elapsed/60):.1f} detections/minute") print(f" • Average rate: {detection_count/(elapsed/60):.1f} detections/minute")
print(f" • Active drones at end: {len(simulator.active_drones)}")
def test_api_health(): def test_api_health():
"""Test if the API is responding""" """Test if the API is responding"""
@@ -157,7 +343,7 @@ def test_api_health():
return False return False
def main(): def main():
print("🚁 Drone Detection System - Test Script") print("🚁 Realistic Drone Detection Simulator")
print("=" * 50) print("=" * 50)
# Test API connectivity # Test API connectivity
@@ -165,40 +351,26 @@ def main():
print("Cannot connect to API. Please check if the system is running.") print("Cannot connect to API. Please check if the system is running.")
return return
print("\nChoose test mode:") print("\nChoose simulation type:")
print("1. Send single test detection") print("1. Realistic scenario (persistent drones, RSSI changes, movement)")
print("2. Simulate continuous detections") print("2. Single approaching drone (watch RSSI strengthen)")
print("3. Send burst of 10 detections") print("3. Departing drone (watch RSSI weaken)")
try: try:
choice = input("\nEnter choice (1-3): ").strip() choice = input("\nEnter choice (1-3): ").strip()
if choice == "1": if choice == "1":
test_single_detection() duration = input("Duration in minutes (default: 10): ").strip()
duration = int(duration) if duration else 10
simulate_realistic_scenario(duration)
elif choice == "2": elif choice == "2":
duration = input("Duration in minutes (default: 5): ").strip() print("🎯 Simulating approaching drone (RSSI will strengthen)...")
interval = input("Interval in seconds (default: 10): ").strip() # Implementation for approaching drone
duration = int(duration) if duration else 5
interval = int(interval) if interval else 10
simulate_continuous_detections(duration, interval)
elif choice == "3": elif choice == "3":
print("🚀 Sending burst of 10 detections...") print("🛫 Simulating departing drone (RSSI will weaken)...")
success_count = 0 # Implementation for departing drone
for i in range(10):
device = random.choice(DEVICES)
detection = generate_detection_data(device)
if send_detection(detection):
success_count += 1
time.sleep(1) # 1 second between detections
print(f"\n📊 Burst completed: {success_count}/10 detections sent successfully")
else: else:
print("Invalid choice") print("Invalid choice")