From 953a206522866f4a9a95d86af60095e236e1c8ed Mon Sep 17 00:00:00 2001 From: Alexander Borg Date: Sun, 7 Sep 2025 12:45:59 +0200 Subject: [PATCH] Fix jwt-token --- debug_device_status.py | 60 ++++++++++- fix_stockholm_device.py | 217 ++++++++++++++++++++++++++++++++++++++++ server/routes/device.js | 13 +++ test_device_health.py | 62 +++++++++++- 4 files changed, 349 insertions(+), 3 deletions(-) create mode 100644 fix_stockholm_device.py diff --git a/debug_device_status.py b/debug_device_status.py index a09e383..7299d1a 100644 --- a/debug_device_status.py +++ b/debug_device_status.py @@ -17,10 +17,61 @@ warnings.filterwarnings('ignore', message='Unverified HTTPS request') API_BASE_URL = os.getenv('API_BASE_URL', 'http://localhost:3002/api') BASE_PATH = os.getenv('VITE_BASE_PATH', '').rstrip('/') +# Authentication configuration +USERNAME = os.getenv('TEST_USERNAME', 'admin') +PASSWORD = os.getenv('TEST_PASSWORD', 'admin123') +SKIP_AUTH = os.getenv('SKIP_AUTH', 'false').lower() == 'true' + if BASE_PATH and not API_BASE_URL.endswith('/api'): domain = API_BASE_URL.replace('/api', '').replace('/drones/api', '').replace('/uggla/api', '') API_BASE_URL = f"{domain}{BASE_PATH}/api" +# Global variable to store authentication token +AUTH_TOKEN = None + +def authenticate(): + """Authenticate with the API and get access token""" + global AUTH_TOKEN + + if SKIP_AUTH: + print("šŸ”“ Authentication skipped (SKIP_AUTH=true)") + return True + + try: + login_data = { + "username": USERNAME, + "password": PASSWORD + } + + response = requests.post(f"{API_BASE_URL}/users/login", json=login_data, verify=False, timeout=10) + + if response.status_code == 200: + data = response.json() + if data.get('success') and 'data' in data and 'token' in data['data']: + AUTH_TOKEN = data['data']['token'] + print(f"āœ… Authentication successful") + return True + else: + print(f"āŒ Invalid login response: {data}") + return False + else: + print(f"āŒ Authentication failed: HTTP {response.status_code}") + return False + except Exception as e: + print(f"āŒ Authentication error: {e}") + return False + +def get_auth_headers(): + """Get headers with authentication token""" + headers = { + 'Content-Type': 'application/json' + } + + if not SKIP_AUTH and AUTH_TOKEN: + headers['Authorization'] = f'Bearer {AUTH_TOKEN}' + + return headers + def debug_device_status(): """Debug device status calculation""" print("šŸ” DEVICE STATUS DEBUG") @@ -28,7 +79,7 @@ def debug_device_status(): try: # Get all devices - response = requests.get(f"{API_BASE_URL}/devices", verify=False, timeout=10) + response = requests.get(f"{API_BASE_URL}/devices", headers=get_auth_headers(), verify=False, timeout=10) if response.status_code == 200: data = response.json() @@ -107,6 +158,7 @@ def send_test_heartbeat(): response = requests.post( f"{API_BASE_URL}/detectors", json=payload, + headers=get_auth_headers(), verify=False, timeout=10 ) @@ -126,6 +178,12 @@ def main(): print(f"ā° Test Time: {datetime.now()}") print() + # Authenticate first + print("šŸ” Authenticating...") + if not authenticate(): + print("āŒ Authentication failed, tests may not work") + return + debug_device_status() send_test_heartbeat() diff --git a/fix_stockholm_device.py b/fix_stockholm_device.py new file mode 100644 index 0000000..7c37c05 --- /dev/null +++ b/fix_stockholm_device.py @@ -0,0 +1,217 @@ +#!/usr/bin/env python3 +""" +Fix Stockholm Device Script +Ensures the Stockholm device is properly configured for heartbeat monitoring +""" + +import requests +import json +import os +from datetime import datetime + +# Disable SSL warnings for self-signed certificates +import warnings +warnings.filterwarnings('ignore', message='Unverified HTTPS request') + +# Configuration +API_BASE_URL = os.getenv('API_BASE_URL', 'http://localhost:3002/api') +BASE_PATH = os.getenv('VITE_BASE_PATH', '').rstrip('/') + +# Authentication configuration +USERNAME = os.getenv('TEST_USERNAME', 'admin') +PASSWORD = os.getenv('TEST_PASSWORD', 'admin123') +SKIP_AUTH = os.getenv('SKIP_AUTH', 'false').lower() == 'true' + +if BASE_PATH and not API_BASE_URL.endswith('/api'): + domain = API_BASE_URL.replace('/api', '').replace('/drones/api', '').replace('/uggla/api', '') + API_BASE_URL = f"{domain}{BASE_PATH}/api" + +# Global variable to store authentication token +AUTH_TOKEN = None + +def authenticate(): + """Authenticate with the API and get access token""" + global AUTH_TOKEN + + if SKIP_AUTH: + print("šŸ”“ Authentication skipped (SKIP_AUTH=true)") + return True + + try: + login_data = { + "username": USERNAME, + "password": PASSWORD + } + + response = requests.post(f"{API_BASE_URL}/users/login", json=login_data, verify=False, timeout=10) + + if response.status_code == 200: + data = response.json() + if data.get('success') and 'data' in data and 'token' in data['data']: + AUTH_TOKEN = data['data']['token'] + print(f"āœ… Authentication successful") + return True + else: + print(f"āŒ Invalid login response: {data}") + return False + else: + print(f"āŒ Authentication failed: HTTP {response.status_code}") + return False + except Exception as e: + print(f"āŒ Authentication error: {e}") + return False + +def get_auth_headers(): + """Get headers with authentication token""" + headers = { + 'Content-Type': 'application/json' + } + + if not SKIP_AUTH and AUTH_TOKEN: + headers['Authorization'] = f'Bearer {AUTH_TOKEN}' + + return headers + +def fix_stockholm_device(): + """Check and fix Stockholm device configuration""" + print("šŸ”§ FIXING STOCKHOLM DEVICE CONFIGURATION") + print("=" * 50) + + try: + # Get all devices + response = requests.get(f"{API_BASE_URL}/devices", headers=get_auth_headers(), verify=False, timeout=10) + + if response.status_code == 200: + data = response.json() + if data.get('success') and data.get('data'): + devices = data['data'] + + # Find Stockholm device + stockholm_device = None + for device in devices: + if device.get('id') == 1001 or 'Stockholm' in device.get('name', ''): + stockholm_device = device + break + + if stockholm_device: + device_id = stockholm_device['id'] + print(f"šŸ“± Found Stockholm Device (ID: {device_id})") + print(f" Name: {stockholm_device.get('name', 'N/A')}") + print(f" Active: {stockholm_device.get('is_active', False)}") + print(f" Approved: {stockholm_device.get('is_approved', False)}") + print(f" Heartbeat Interval: {stockholm_device.get('heartbeat_interval', 'Not set')} seconds") + + # Check if device needs fixing + needs_fix = False + updates = {} + + if not stockholm_device.get('is_active'): + print("āŒ Device is not active") + updates['is_active'] = True + needs_fix = True + + if not stockholm_device.get('is_approved'): + print("āŒ Device is not approved") + updates['is_approved'] = True + needs_fix = True + + # Ensure heartbeat interval is set to 60 seconds (matching health probe simulator) + if stockholm_device.get('heartbeat_interval') != 60: + print(f"āš ļø Heartbeat interval is {stockholm_device.get('heartbeat_interval')}, should be 60 seconds") + updates['heartbeat_interval'] = 60 + needs_fix = True + + if needs_fix: + print(f"\nšŸ”§ Applying fixes: {updates}") + + # Update device + response = requests.put( + f"{API_BASE_URL}/devices/{device_id}", + json=updates, + headers=get_auth_headers(), + verify=False, + timeout=10 + ) + + if response.status_code == 200: + print("āœ… Device configuration updated successfully") + + # Get updated device info + response = requests.get(f"{API_BASE_URL}/devices", headers=get_auth_headers(), verify=False, timeout=10) + if response.status_code == 200: + data = response.json() + devices = data['data'] + for device in devices: + if device.get('id') == device_id: + print(f"\nšŸ“Š Updated device configuration:") + print(f" Active: {device.get('is_active', False)}") + print(f" Approved: {device.get('is_approved', False)}") + print(f" Heartbeat Interval: {device.get('heartbeat_interval', 'Not set')} seconds") + break + else: + print(f"āŒ Failed to update device: HTTP {response.status_code}") + print(f" Response: {response.text}") + else: + print("āœ… Device configuration is correct") + + else: + print("āŒ Stockholm device not found") + print("Available devices:") + for device in devices: + print(f" - ID {device['id']}: {device.get('name', 'Unnamed')}") + else: + print(f"āŒ No devices found") + else: + print(f"āŒ HTTP Error: {response.status_code}") + print(f" Response: {response.text}") + + except Exception as e: + print(f"āŒ Error: {e}") + +def send_test_heartbeat(): + """Send a test heartbeat after fixing the device""" + print(f"\nšŸ’“ Sending Test Heartbeat") + print("-" * 30) + + try: + payload = { + 'type': 'heartbeat', + 'key': '1001' # Stockholm device key + } + + response = requests.post( + f"{API_BASE_URL}/detectors", + json=payload, + headers=get_auth_headers(), + verify=False, + timeout=10 + ) + + print(f"šŸ“Š Response: {response.status_code}") + if response.status_code in [200, 201]: + data = response.json() + print(f"āœ… Heartbeat sent successfully: {data.get('message', 'OK')}") + else: + print(f"āŒ Error: {response.text}") + + except Exception as e: + print(f"āŒ Error sending heartbeat: {e}") + +def main(): + print(f"šŸ”— API URL: {API_BASE_URL}") + print(f"ā° Time: {datetime.now()}") + print() + + # Authenticate first + print("šŸ” Authenticating...") + if not authenticate(): + print("āŒ Authentication failed") + return + + fix_stockholm_device() + send_test_heartbeat() + + print(f"\nāœ… Stockholm device fix complete") + +if __name__ == "__main__": + main() diff --git a/server/routes/device.js b/server/routes/device.js index d7eacc0..4a4369c 100644 --- a/server/routes/device.js +++ b/server/routes/device.js @@ -89,6 +89,19 @@ router.get('/', authenticateToken, async (req, res) => { const expectedInterval = device.heartbeat_interval || 300; const isOnline = timeSinceLastHeartbeat && timeSinceLastHeartbeat < (expectedInterval * 2); + // Debug logging for device status calculation + if (device.id === 1001) { // Stockholm device + console.log(`šŸ” DEBUG Device ${device.id} status calculation:`); + console.log(` Now: ${now.toISOString()}`); + console.log(` Last heartbeat: ${device.last_heartbeat}`); + console.log(` Time since last: ${timeSinceLastHeartbeat} seconds`); + console.log(` Expected interval: ${expectedInterval} seconds`); + console.log(` Threshold: ${expectedInterval * 2} seconds`); + console.log(` Is online: ${isOnline}`); + console.log(` Is active: ${device.is_active}`); + console.log(` Final status: ${device.is_active ? (isOnline ? 'online' : 'offline') : 'inactive'}`); + } + return { ...device.toJSON(), stats: { diff --git a/test_device_health.py b/test_device_health.py index 81d22bb..5602671 100644 --- a/test_device_health.py +++ b/test_device_health.py @@ -18,11 +18,63 @@ warnings.filterwarnings('ignore', message='Unverified HTTPS request') API_BASE_URL = os.getenv('API_BASE_URL', 'http://localhost:3002/api') 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' + # If BASE_PATH is set, construct the full URL if BASE_PATH and not API_BASE_URL.endswith('/api'): domain = API_BASE_URL.replace('/api', '').replace('/drones/api', '').replace('/uggla/api', '') API_BASE_URL = f"{domain}{BASE_PATH}/api" +# Global variable to store authentication token +AUTH_TOKEN = None + +def authenticate(): + """Authenticate with the API and get access token""" + global AUTH_TOKEN + + if SKIP_AUTH: + print("šŸ”“ Authentication skipped (SKIP_AUTH=true)") + return True + + try: + login_data = { + "username": USERNAME, + "password": PASSWORD + } + + response = requests.post(f"{API_BASE_URL}/users/login", json=login_data, verify=False, timeout=10) + + if response.status_code == 200: + data = response.json() + if data.get('success') and 'data' in data and 'token' in data['data']: + AUTH_TOKEN = data['data']['token'] + print(f"āœ… Authentication successful") + return True + else: + print(f"āŒ Invalid login response: {data}") + return False + else: + print(f"āŒ Authentication failed: HTTP {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""" + headers = { + 'Content-Type': 'application/json' + } + + if not SKIP_AUTH and AUTH_TOKEN: + headers['Authorization'] = f'Bearer {AUTH_TOKEN}' + + return headers + def test_device_health_status(): """Test device health monitoring status""" print("šŸ” Testing Device Health Monitoring System") @@ -91,7 +143,7 @@ def test_device_list(): print("-" * 40) try: - response = requests.get(f"{API_BASE_URL}/devices", verify=False, timeout=10) + response = requests.get(f"{API_BASE_URL}/devices", headers=get_auth_headers(), verify=False, timeout=10) if response.status_code == 200: data = response.json() @@ -137,7 +189,7 @@ def test_alert_rules(): print("-" * 40) try: - response = requests.get(f"{API_BASE_URL}/alerts/rules", verify=False, timeout=10) + response = requests.get(f"{API_BASE_URL}/alerts/rules", headers=get_auth_headers(), verify=False, timeout=10) if response.status_code == 200: data = response.json() @@ -181,6 +233,12 @@ def main(): print(f"ā° Test Time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") print() + # Authenticate first + print("šŸ” Authenticating...") + if not authenticate(): + print("āŒ Authentication failed, some tests may not work") + print() + # Run all tests test_device_health_status() test_device_list()