Fix jwt-token
This commit is contained in:
@@ -2,6 +2,7 @@ const express = require('express');
|
||||
const DroneDetection = require('../models/DroneDetection');
|
||||
const Device = require('../models/Device');
|
||||
const { authenticateToken } = require('../middleware/auth');
|
||||
const { getDroneTypeInfo } = require('../utils/droneTypes');
|
||||
const router = express.Router();
|
||||
|
||||
/**
|
||||
@@ -66,8 +67,17 @@ router.get('/', authenticateToken, async (req, res) => {
|
||||
const hasNextPage = parseInt(page) < totalPages;
|
||||
const hasPrevPage = parseInt(page) > 1;
|
||||
|
||||
// Enhance detections with drone type information
|
||||
const enhancedDetections = detections.map(detection => {
|
||||
const droneTypeInfo = getDroneTypeInfo(detection.drone_type);
|
||||
return {
|
||||
...detection.toJSON(),
|
||||
drone_type_info: droneTypeInfo
|
||||
};
|
||||
});
|
||||
|
||||
res.json({
|
||||
detections,
|
||||
detections: enhancedDetections,
|
||||
pagination: {
|
||||
currentPage: parseInt(page),
|
||||
totalPages,
|
||||
@@ -107,7 +117,14 @@ router.get('/:id', authenticateToken, async (req, res) => {
|
||||
return res.status(404).json({ error: 'Detection not found' });
|
||||
}
|
||||
|
||||
res.json(detection);
|
||||
// Enhance detection with drone type information
|
||||
const droneTypeInfo = getDroneTypeInfo(detection.drone_type);
|
||||
const enhancedDetection = {
|
||||
...detection.toJSON(),
|
||||
drone_type_info: droneTypeInfo
|
||||
};
|
||||
|
||||
res.json(enhancedDetection);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error fetching detection:', error);
|
||||
|
||||
@@ -5,6 +5,7 @@ const { validateRequest } = require('../middleware/validation');
|
||||
const { Heartbeat, Device, DroneDetection } = require('../models');
|
||||
const AlertService = require('../services/alertService');
|
||||
const DroneTrackingService = require('../services/droneTrackingService');
|
||||
const { getDroneTypeInfo, getDroneTypeName } = require('../utils/droneTypes');
|
||||
|
||||
// Initialize services
|
||||
const alertService = new AlertService();
|
||||
@@ -191,7 +192,11 @@ async function handleHeartbeat(req, res) {
|
||||
async function handleDetection(req, res) {
|
||||
const detectionData = req.body;
|
||||
|
||||
console.log(`🚁 Drone detection received from device ${detectionData.device_id}: drone_id=${detectionData.drone_id}, type=${detectionData.drone_type}, rssi=${detectionData.rssi}`);
|
||||
// Get drone type information
|
||||
const droneTypeInfo = getDroneTypeInfo(detectionData.drone_type);
|
||||
|
||||
console.log(`🚁 Drone detection received from device ${detectionData.device_id}: drone_id=${detectionData.drone_id}, type=${detectionData.drone_type} (${droneTypeInfo.name}), rssi=${detectionData.rssi}`);
|
||||
console.log(`🎯 Drone Type Details: ${droneTypeInfo.category} | Threat: ${droneTypeInfo.threat_level} | ${droneTypeInfo.description}`);
|
||||
console.log('🔍 Complete detection data:', JSON.stringify(detectionData, null, 2));
|
||||
|
||||
// Check if device exists and is approved
|
||||
|
||||
160
server/routes/droneTypes.js
Normal file
160
server/routes/droneTypes.js
Normal file
@@ -0,0 +1,160 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const {
|
||||
getAllDroneTypes,
|
||||
getDroneTypesByCategory,
|
||||
getDroneTypesByThreatLevel,
|
||||
getDroneTypeInfo
|
||||
} = require('../utils/droneTypes');
|
||||
|
||||
/**
|
||||
* GET /api/drone-types
|
||||
* Get all available drone types
|
||||
*/
|
||||
router.get('/', (req, res) => {
|
||||
try {
|
||||
const droneTypes = getAllDroneTypes();
|
||||
|
||||
// Convert to array format with IDs
|
||||
const droneTypesArray = Object.entries(droneTypes).map(([id, info]) => ({
|
||||
id: parseInt(id),
|
||||
...info
|
||||
}));
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: droneTypesArray,
|
||||
total: droneTypesArray.length
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error fetching drone types:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Failed to fetch drone types',
|
||||
details: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* GET /api/drone-types/:id
|
||||
* Get specific drone type by ID
|
||||
*/
|
||||
router.get('/:id', (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const droneTypeInfo = getDroneTypeInfo(parseInt(id));
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: droneTypeInfo
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error fetching drone type:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Failed to fetch drone type',
|
||||
details: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* GET /api/drone-types/category/:category
|
||||
* Get drone types by category
|
||||
*/
|
||||
router.get('/category/:category', (req, res) => {
|
||||
try {
|
||||
const { category } = req.params;
|
||||
const droneTypes = getDroneTypesByCategory(category);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: droneTypes,
|
||||
category: category,
|
||||
total: droneTypes.length
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error fetching drone types by category:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Failed to fetch drone types by category',
|
||||
details: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* GET /api/drone-types/threat/:threatLevel
|
||||
* Get drone types by threat level
|
||||
*/
|
||||
router.get('/threat/:threatLevel', (req, res) => {
|
||||
try {
|
||||
const { threatLevel } = req.params;
|
||||
const droneTypes = getDroneTypesByThreatLevel(threatLevel);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: droneTypes,
|
||||
threat_level: threatLevel,
|
||||
total: droneTypes.length
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error fetching drone types by threat level:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Failed to fetch drone types by threat level',
|
||||
details: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* GET /api/drone-types/categories
|
||||
* Get all available categories
|
||||
*/
|
||||
router.get('/meta/categories', (req, res) => {
|
||||
try {
|
||||
const droneTypes = getAllDroneTypes();
|
||||
const categories = [...new Set(Object.values(droneTypes).map(type => type.category))];
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: categories,
|
||||
total: categories.length
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error fetching drone type categories:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Failed to fetch drone type categories',
|
||||
details: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* GET /api/drone-types/threat-levels
|
||||
* Get all available threat levels
|
||||
*/
|
||||
router.get('/meta/threat-levels', (req, res) => {
|
||||
try {
|
||||
const droneTypes = getAllDroneTypes();
|
||||
const threatLevels = [...new Set(Object.values(droneTypes).map(type => type.threat_level))];
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: threatLevels,
|
||||
total: threatLevels.length
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error fetching drone type threat levels:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Failed to fetch drone type threat levels',
|
||||
details: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
@@ -10,6 +10,7 @@ const healthRoutes = require('./health');
|
||||
const debugRoutes = require('./debug');
|
||||
const detectorsRoutes = require('./detectors');
|
||||
const detectionsRoutes = require('./detections');
|
||||
const droneTypesRoutes = require('./droneTypes');
|
||||
|
||||
// API versioning
|
||||
router.use('/v1/devices', deviceRoutes);
|
||||
@@ -19,6 +20,7 @@ router.use('/v1/dashboard', dashboardRoutes);
|
||||
router.use('/v1/health', healthRoutes);
|
||||
router.use('/v1/detectors', detectorsRoutes);
|
||||
router.use('/v1/detections', detectionsRoutes);
|
||||
router.use('/v1/drone-types', droneTypesRoutes);
|
||||
|
||||
// Default routes (no version prefix for backward compatibility)
|
||||
router.use('/devices', deviceRoutes);
|
||||
@@ -29,6 +31,7 @@ router.use('/health', healthRoutes);
|
||||
router.use('/debug', debugRoutes);
|
||||
router.use('/detectors', detectorsRoutes);
|
||||
router.use('/detections', detectionsRoutes);
|
||||
router.use('/drone-types', droneTypesRoutes);
|
||||
|
||||
// API documentation endpoint
|
||||
router.get('/', (req, res) => {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const twilio = require('twilio');
|
||||
const { AlertRule, AlertLog, User, Device, DroneDetection } = require('../models');
|
||||
const { Op } = require('sequelize');
|
||||
const { getDroneTypeInfo } = require('../utils/droneTypes');
|
||||
|
||||
class AlertService {
|
||||
constructor() {
|
||||
@@ -56,33 +57,28 @@ class AlertService {
|
||||
actionRequired = false;
|
||||
}
|
||||
|
||||
// Adjust threat level based on drone type (if classified)
|
||||
const droneTypes = {
|
||||
0: 'Consumer/Hobby',
|
||||
1: 'Orlan/Military', // Orlan drones - highest threat
|
||||
2: 'Professional/Commercial',
|
||||
3: 'Racing/High-speed',
|
||||
4: 'Unknown/Custom'
|
||||
};
|
||||
// Get drone type information using our comprehensive mapping
|
||||
const droneTypeInfo = getDroneTypeInfo(droneType);
|
||||
|
||||
// CRITICAL: Orlan drones (type 1) - ALWAYS CRITICAL regardless of distance
|
||||
if (droneType === 1) {
|
||||
// Adjust threat level based on drone type and category
|
||||
if (droneTypeInfo.threat_level === 'critical' || droneTypeInfo.category.includes('Military')) {
|
||||
// Military/Combat drones - ALWAYS CRITICAL regardless of distance
|
||||
threatLevel = 'critical';
|
||||
description = 'CRITICAL THREAT: ORLAN MILITARY DRONE DETECTED - IMMEDIATE RESPONSE REQUIRED';
|
||||
description = `CRITICAL THREAT: ${droneTypeInfo.name.toUpperCase()} DETECTED - IMMEDIATE RESPONSE REQUIRED`;
|
||||
actionRequired = true;
|
||||
console.log(`🚨 ORLAN DRONE DETECTED - Force escalating to CRITICAL threat level (RSSI: ${rssi})`);
|
||||
} else if (droneType === 2) {
|
||||
// Professional/Commercial drone - escalate threat
|
||||
console.log(`🚨 MILITARY DRONE DETECTED: ${droneTypeInfo.name} - Force escalating to CRITICAL threat level (RSSI: ${rssi})`);
|
||||
} else if (droneTypeInfo.threat_level === 'high' || droneTypeInfo.category.includes('Professional')) {
|
||||
// Professional/Commercial drone - escalate threat one level
|
||||
if (threatLevel === 'low') threatLevel = 'medium';
|
||||
if (threatLevel === 'medium') threatLevel = 'high';
|
||||
if (threatLevel === 'high') threatLevel = 'critical';
|
||||
description += ' - PROFESSIONAL/COMMERCIAL DRONE DETECTED';
|
||||
description += ` - ${droneTypeInfo.name.toUpperCase()} DETECTED`;
|
||||
actionRequired = true;
|
||||
} else if (droneType === 3) {
|
||||
} else if (droneTypeInfo.category.includes('Racing')) {
|
||||
// Racing/Fast drone - escalate if close
|
||||
if (rssi >= -55 && threatLevel !== 'critical') {
|
||||
threatLevel = 'high';
|
||||
description += ' - HIGH-SPEED DRONE DETECTED';
|
||||
description += ` - HIGH-SPEED ${droneTypeInfo.name.toUpperCase()} DETECTED`;
|
||||
actionRequired = true;
|
||||
}
|
||||
}
|
||||
@@ -91,7 +87,9 @@ class AlertService {
|
||||
level: threatLevel,
|
||||
estimatedDistance: Math.round(estimatedDistance),
|
||||
rssi,
|
||||
droneType: droneTypes[droneType] || 'Unknown',
|
||||
droneType: droneTypeInfo.name,
|
||||
droneCategory: droneTypeInfo.category,
|
||||
threatLevel: droneTypeInfo.threat_level,
|
||||
description,
|
||||
requiresImmediateAction: actionRequired,
|
||||
priority: threatLevel === 'critical' ? 1 : threatLevel === 'high' ? 2 : threatLevel === 'medium' ? 3 : 4
|
||||
|
||||
217
server/utils/droneTypes.js
Normal file
217
server/utils/droneTypes.js
Normal file
@@ -0,0 +1,217 @@
|
||||
/**
|
||||
* Drone Type Mappings
|
||||
* Maps integer drone_type values to human-readable names and categories
|
||||
*/
|
||||
|
||||
const DRONE_TYPES = {
|
||||
// Military/Combat Drones
|
||||
0: {
|
||||
name: "Russian Orlan",
|
||||
category: "Military/Reconnaissance",
|
||||
threat_level: "high",
|
||||
description: "Russian military reconnaissance drone"
|
||||
},
|
||||
1: {
|
||||
name: "Bayraktar TB2",
|
||||
category: "Military/Combat",
|
||||
threat_level: "critical",
|
||||
description: "Turkish military combat drone"
|
||||
},
|
||||
2: {
|
||||
name: "MQ-9 Reaper",
|
||||
category: "Military/Combat",
|
||||
threat_level: "critical",
|
||||
description: "US military combat drone"
|
||||
},
|
||||
3: {
|
||||
name: "Iranian Shahed",
|
||||
category: "Military/Kamikaze",
|
||||
threat_level: "critical",
|
||||
description: "Iranian kamikaze/suicide drone"
|
||||
},
|
||||
4: {
|
||||
name: "Chinese Wing Loong",
|
||||
category: "Military/Combat",
|
||||
threat_level: "critical",
|
||||
description: "Chinese military combat drone"
|
||||
},
|
||||
5: {
|
||||
name: "Israeli Hermes",
|
||||
category: "Military/Reconnaissance",
|
||||
threat_level: "high",
|
||||
description: "Israeli military reconnaissance drone"
|
||||
},
|
||||
|
||||
// Commercial/Professional Drones
|
||||
10: {
|
||||
name: "DJI Mavic",
|
||||
category: "Commercial/Professional",
|
||||
threat_level: "medium",
|
||||
description: "DJI professional quadcopter"
|
||||
},
|
||||
11: {
|
||||
name: "DJI Phantom",
|
||||
category: "Commercial/Professional",
|
||||
threat_level: "medium",
|
||||
description: "DJI professional quadcopter"
|
||||
},
|
||||
12: {
|
||||
name: "DJI Inspire",
|
||||
category: "Commercial/Professional",
|
||||
threat_level: "medium",
|
||||
description: "DJI professional cinematography drone"
|
||||
},
|
||||
13: {
|
||||
name: "Autel EVO",
|
||||
category: "Commercial/Professional",
|
||||
threat_level: "medium",
|
||||
description: "Autel professional quadcopter"
|
||||
},
|
||||
14: {
|
||||
name: "Parrot Anafi",
|
||||
category: "Commercial/Professional",
|
||||
threat_level: "medium",
|
||||
description: "Parrot professional quadcopter"
|
||||
},
|
||||
|
||||
// Consumer/Hobby Drones
|
||||
20: {
|
||||
name: "DJI Mini",
|
||||
category: "Consumer/Hobby",
|
||||
threat_level: "low",
|
||||
description: "DJI consumer mini drone"
|
||||
},
|
||||
21: {
|
||||
name: "DJI Spark",
|
||||
category: "Consumer/Hobby",
|
||||
threat_level: "low",
|
||||
description: "DJI consumer compact drone"
|
||||
},
|
||||
22: {
|
||||
name: "Ryze Tello",
|
||||
category: "Consumer/Hobby",
|
||||
threat_level: "low",
|
||||
description: "Consumer toy/education drone"
|
||||
},
|
||||
23: {
|
||||
name: "Holy Stone",
|
||||
category: "Consumer/Hobby",
|
||||
threat_level: "low",
|
||||
description: "Consumer hobby quadcopter"
|
||||
},
|
||||
24: {
|
||||
name: "Syma X5C",
|
||||
category: "Consumer/Hobby",
|
||||
threat_level: "low",
|
||||
description: "Consumer toy quadcopter"
|
||||
},
|
||||
|
||||
// Racing/FPV Drones
|
||||
30: {
|
||||
name: "Racing Quadcopter",
|
||||
category: "Racing/FPV",
|
||||
threat_level: "low",
|
||||
description: "Custom racing/FPV quadcopter"
|
||||
},
|
||||
31: {
|
||||
name: "TinyHawk",
|
||||
category: "Racing/FPV",
|
||||
threat_level: "low",
|
||||
description: "Micro racing quadcopter"
|
||||
},
|
||||
|
||||
// Fixed-Wing Drones
|
||||
40: {
|
||||
name: "Fixed-Wing Surveillance",
|
||||
category: "Fixed-Wing/Surveillance",
|
||||
threat_level: "medium",
|
||||
description: "Fixed-wing surveillance aircraft"
|
||||
},
|
||||
41: {
|
||||
name: "Fixed-Wing Cargo",
|
||||
category: "Fixed-Wing/Commercial",
|
||||
threat_level: "medium",
|
||||
description: "Fixed-wing cargo/delivery aircraft"
|
||||
},
|
||||
|
||||
// Unknown/Unclassified
|
||||
99: {
|
||||
name: "Unknown Drone",
|
||||
category: "Unknown/Unclassified",
|
||||
threat_level: "medium",
|
||||
description: "Unidentified or unclassified drone"
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get drone type information by ID
|
||||
* @param {number} droneTypeId - The integer drone type ID
|
||||
* @returns {object} Drone type information or default for unknown types
|
||||
*/
|
||||
function getDroneTypeInfo(droneTypeId) {
|
||||
const typeInfo = DRONE_TYPES[droneTypeId];
|
||||
|
||||
if (typeInfo) {
|
||||
return {
|
||||
id: droneTypeId,
|
||||
...typeInfo
|
||||
};
|
||||
}
|
||||
|
||||
// Return default for unknown types
|
||||
return {
|
||||
id: droneTypeId,
|
||||
name: `Unknown Type ${droneTypeId}`,
|
||||
category: "Unknown/Unclassified",
|
||||
threat_level: "medium",
|
||||
description: `Unrecognized drone type ID: ${droneTypeId}`
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get just the drone name by ID
|
||||
* @param {number} droneTypeId - The integer drone type ID
|
||||
* @returns {string} Drone name
|
||||
*/
|
||||
function getDroneTypeName(droneTypeId) {
|
||||
return getDroneTypeInfo(droneTypeId).name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all available drone types
|
||||
* @returns {object} All drone type mappings
|
||||
*/
|
||||
function getAllDroneTypes() {
|
||||
return DRONE_TYPES;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get drone types by category
|
||||
* @param {string} category - The category to filter by
|
||||
* @returns {array} Array of drone types in the category
|
||||
*/
|
||||
function getDroneTypesByCategory(category) {
|
||||
return Object.entries(DRONE_TYPES)
|
||||
.filter(([id, info]) => info.category === category)
|
||||
.map(([id, info]) => ({ id: parseInt(id), ...info }));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get drone types by threat level
|
||||
* @param {string} threatLevel - The threat level to filter by
|
||||
* @returns {array} Array of drone types with the threat level
|
||||
*/
|
||||
function getDroneTypesByThreatLevel(threatLevel) {
|
||||
return Object.entries(DRONE_TYPES)
|
||||
.filter(([id, info]) => info.threat_level === threatLevel)
|
||||
.map(([id, info]) => ({ id: parseInt(id), ...info }));
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
DRONE_TYPES,
|
||||
getDroneTypeInfo,
|
||||
getDroneTypeName,
|
||||
getAllDroneTypes,
|
||||
getDroneTypesByCategory,
|
||||
getDroneTypesByThreatLevel
|
||||
};
|
||||
Reference in New Issue
Block a user