Fix jwt-token

This commit is contained in:
2025-09-17 18:40:40 +02:00
parent b96a06f48c
commit 4a62aa8960
3 changed files with 290 additions and 2 deletions

View File

@@ -0,0 +1,65 @@
const { Device, Tenant } = require('./models');
async function createStockholmDevice() {
try {
// Find the uamils-ab tenant
const tenant = await Tenant.findOne({ where: { slug: 'uamils-ab' } });
if (!tenant) {
console.log('❌ Tenant uamils-ab not found');
return;
}
// Check if device "1" already exists
const existingDevice = await Device.findOne({ where: { id: '1' } });
if (existingDevice) {
console.log('✅ Stockholm Castle device already exists');
console.log(` ID: ${existingDevice.id}`);
console.log(` Name: ${existingDevice.name}`);
console.log(` Approved: ${existingDevice.is_approved}`);
console.log(` Active: ${existingDevice.is_active}`);
console.log(` Tenant: ${existingDevice.tenant_id}`);
return;
}
// Create Stockholm Castle device
const stockholmDevice = await Device.create({
id: '1',
name: 'Stockholm Castle',
type: 'drone_detector',
location: 'Stockholm Castle, Sweden',
description: 'Drone detector at Stockholm Castle monitoring royal grounds',
is_approved: true,
is_active: true,
tenant_id: tenant.id,
coordinates: JSON.stringify({
latitude: 59.3251,
longitude: 18.0719
}),
config: JSON.stringify({
detection_range: 25000, // 25km range
alert_threshold: 5000, // Alert when within 5km
frequency_bands: ['2.4GHz', '5.8GHz'],
sensitivity: 'high'
})
});
console.log('✅ Stockholm Castle device created successfully');
console.log(` ID: ${stockholmDevice.id}`);
console.log(` Name: ${stockholmDevice.name}`);
console.log(` Tenant: ${stockholmDevice.tenant_id}`);
console.log(` Approved: ${stockholmDevice.is_approved}`);
} catch (error) {
console.error('❌ Error creating Stockholm device:', error.message);
}
}
createStockholmDevice()
.then(() => {
console.log('✅ Stockholm device setup completed');
process.exit(0);
})
.catch(error => {
console.error('❌ Setup failed:', error);
process.exit(1);
});

View File

@@ -55,7 +55,10 @@ const detectorSchema = Joi.alternatives().try(
type: Joi.string().valid('heartbeat').required(), type: Joi.string().valid('heartbeat').required(),
key: Joi.string().required(), key: Joi.string().required(),
// Optional heartbeat fields // Optional heartbeat fields
device_id: Joi.number().integer().optional(), device_id: Joi.alternatives().try(
Joi.number().integer(),
Joi.string()
).optional(),
geo_lat: Joi.number().min(-90).max(90).optional(), geo_lat: Joi.number().min(-90).max(90).optional(),
geo_lon: Joi.number().min(-180).max(180).optional(), geo_lon: Joi.number().min(-180).max(180).optional(),
location_description: Joi.string().optional(), location_description: Joi.string().optional(),
@@ -65,7 +68,10 @@ const detectorSchema = Joi.alternatives().try(
}), }),
// Detection schema // Detection schema
Joi.object({ Joi.object({
device_id: Joi.number().integer().required(), device_id: Joi.alternatives().try(
Joi.number().integer(),
Joi.string()
).required(),
geo_lat: Joi.number().min(-90).max(90).required(), geo_lat: Joi.number().min(-90).max(90).required(),
geo_lon: Joi.number().min(-180).max(180).required(), geo_lon: Joi.number().min(-180).max(180).required(),
device_timestamp: Joi.number().integer().min(0).required(), device_timestamp: Joi.number().integer().min(0).required(),

217
test_device_api.py Normal file
View File

@@ -0,0 +1,217 @@
#!/usr/bin/env python3
"""
Test script for device API authentication and detection submission
Simulates Stockholm Castle device sending drone detection data
"""
import requests
import json
import sys
import os
from datetime import datetime, timezone
# Configuration
API_BASE_URL = os.getenv('API_BASE_URL', 'http://localhost:3001/api')
TENANT_ID = os.getenv('TENANT_ID', 'uamils-ab')
DEVICE_ID = os.getenv('DEVICE_ID', '1') # Stockholm Castle device
USERNAME = os.getenv('TEST_USERNAME', 'admin')
PASSWORD = os.getenv('TEST_PASSWORD', 'admin123')
# Headers for multi-tenant API
HEADERS = {
'Content-Type': 'application/json',
'x-tenant-id': TENANT_ID,
'User-Agent': 'Stockholm-Castle-Device/1.0'
}
class DeviceAPITester:
def __init__(self):
self.session = requests.Session()
self.session.headers.update(HEADERS)
self.jwt_token = None
def authenticate(self):
"""Authenticate with the backend and get JWT token"""
print(f"🔐 Authenticating as user: {USERNAME} for tenant: {TENANT_ID}")
auth_data = {
'username': USERNAME,
'password': PASSWORD
}
try:
response = self.session.post(f"{API_BASE_URL}/auth/local", json=auth_data)
if response.status_code == 200:
data = response.json()
if data.get('success') and data.get('token'):
self.jwt_token = data['token']
self.session.headers['Authorization'] = f'Bearer {self.jwt_token}'
print(f"✅ Authentication successful")
print(f" User: {data.get('user', {}).get('username', 'N/A')}")
print(f" Role: {data.get('user', {}).get('role', 'N/A')}")
print(f" Tenant: {data.get('user', {}).get('tenant_id', 'N/A')}")
return True
else:
print(f"❌ Authentication failed: Invalid response format")
print(f"Response: {response.text}")
return False
else:
print(f"❌ Authentication failed: {response.status_code}")
print(f"Response: {response.text}")
return False
except requests.exceptions.RequestException as e:
print(f"❌ Authentication error: {e}")
return False
def check_health(self):
"""Check if API is healthy"""
try:
response = self.session.get(f"{API_BASE_URL}/health")
if response.status_code == 200:
print("✅ API health check passed")
return True
else:
print(f"❌ API health check failed: {response.status_code}")
return False
except requests.exceptions.RequestException as e:
print(f"❌ API health check error: {e}")
return False
def send_detection(self, drone_type="Orlan", distance=1000, confidence=0.85):
"""Send a drone detection to the API"""
detection_data = {
'device_id': DEVICE_ID,
'drone_type': drone_type,
'confidence': confidence,
'distance': distance,
'signal_strength': -45.2,
'frequency': 2400,
'coordinates': {
'latitude': 59.3251, # Stockholm Castle
'longitude': 18.0719
},
'raw_data': {
'rssi': -45.2,
'snr': 12.5,
'frequency_mhz': 2400,
'bandwidth': '20MHz',
'detected_at': datetime.now(timezone.utc).isoformat()
},
'metadata': {
'device_location': 'Stockholm Castle',
'weather': 'Clear',
'temperature': 15.2
}
}
print(f"📡 Sending detection: {drone_type} at {distance}m distance")
try:
response = self.session.post(f"{API_BASE_URL}/detections", json=detection_data)
if response.status_code == 201:
data = response.json()
print(f"✅ Detection sent successfully")
print(f" Detection ID: {data.get('id', 'N/A')}")
print(f" Timestamp: {data.get('timestamp', 'N/A')}")
return True
else:
print(f"❌ Detection failed: {response.status_code}")
print(f"Response: {response.text}")
return False
except requests.exceptions.RequestException as e:
print(f"❌ Detection error: {e}")
return False
def send_heartbeat(self):
"""Send a heartbeat to show device is online"""
heartbeat_data = {
'device_id': DEVICE_ID,
'status': 'online',
'battery_level': 95,
'signal_quality': 85,
'last_detection': datetime.now(timezone.utc).isoformat(),
'location': {
'latitude': 59.3251,
'longitude': 18.0719
},
'system_info': {
'firmware_version': '1.2.3',
'uptime': 3600,
'cpu_usage': 25.5,
'memory_usage': 45.2
}
}
print(f"💓 Sending heartbeat for device {DEVICE_ID}")
try:
response = self.session.post(f"{API_BASE_URL}/heartbeat", json=heartbeat_data)
if response.status_code in [200, 201]:
print(f"✅ Heartbeat sent successfully")
return True
else:
print(f"❌ Heartbeat failed: {response.status_code}")
print(f"Response: {response.text}")
return False
except requests.exceptions.RequestException as e:
print(f"❌ Heartbeat error: {e}")
return False
def main():
print("=" * 70)
print("🎯 STOCKHOLM CASTLE DEVICE API TEST")
print("=" * 70)
print(f"API URL: {API_BASE_URL}")
print(f"Tenant: {TENANT_ID}")
print(f"Device ID: {DEVICE_ID}")
print(f"Username: {USERNAME}")
print("=" * 70)
tester = DeviceAPITester()
# Step 1: Health check
if not tester.check_health():
print("❌ API not healthy. Please check if server is running.")
sys.exit(1)
# Step 2: Authenticate
if not tester.authenticate():
print("❌ Authentication failed. Please check credentials and tenant.")
print("\n💡 Troubleshooting:")
print("1. Ensure backend is running on correct port")
print("2. Check username/password are correct")
print("3. Verify tenant 'uamils-ab' exists")
print("4. Check database seeding completed successfully")
sys.exit(1)
# Step 3: Send heartbeat
print("\n" + "=" * 50)
print("Testing Device Heartbeat")
print("=" * 50)
tester.send_heartbeat()
# Step 4: Send detection
print("\n" + "=" * 50)
print("Testing Drone Detection")
print("=" * 50)
tester.send_detection(drone_type="Orlan", distance=1500, confidence=0.92)
# Step 5: Send another detection (closer)
print("\n" + "=" * 50)
print("Testing Critical Alert (Close Drone)")
print("=" * 50)
tester.send_detection(drone_type="Orlan", distance=500, confidence=0.98)
print("\n" + "=" * 70)
print("✅ TEST COMPLETED")
print("=" * 70)
print("Check the web interface to see the detections and device status")
if __name__ == "__main__":
main()