Fix jwt-token
This commit is contained in:
@@ -116,6 +116,17 @@ async function startServer() {
|
||||
console.log('📱 SMS Alerts: ⚠️ Disabled (no Twilio credentials)');
|
||||
}
|
||||
|
||||
// Start periodic clear alert checking (every 2 minutes)
|
||||
setInterval(async () => {
|
||||
try {
|
||||
await alertService.checkClearedAlerts();
|
||||
} catch (error) {
|
||||
console.error('Error checking cleared alerts:', error);
|
||||
}
|
||||
}, 2 * 60 * 1000); // Check every 2 minutes
|
||||
|
||||
console.log('🔄 Clear alert monitoring: ✅ Started');
|
||||
|
||||
console.log(`📊 Health check: http://localhost:${PORT}/health`);
|
||||
console.log(`🌐 API endpoint: http://localhost:${PORT}/api`);
|
||||
console.log('================================================\n');
|
||||
|
||||
@@ -74,6 +74,11 @@ module.exports = (sequelize) => {
|
||||
defaultValue: ['sms'],
|
||||
comment: 'Array of alert channels: sms, email, webhook'
|
||||
},
|
||||
sms_phone_number: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: true,
|
||||
comment: 'Phone number for SMS alerts'
|
||||
},
|
||||
webhook_url: {
|
||||
type: DataTypes.STRING,
|
||||
allowNull: true,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const bcrypt = require('bcryptjs');
|
||||
const { User, Device } = require('./models');
|
||||
const bcrypt = require('bcrypt');
|
||||
const { User, Device, AlertRule } = require('./models');
|
||||
|
||||
async function seedDatabase() {
|
||||
try {
|
||||
@@ -74,6 +74,65 @@ async function seedDatabase() {
|
||||
console.log('✅ Devices already exist');
|
||||
}
|
||||
|
||||
// Get admin user for alert rules
|
||||
const adminUser = await User.findOne({ where: { username: 'admin' } });
|
||||
|
||||
// Create location-specific alert rules
|
||||
const alertRuleCount = await AlertRule.count();
|
||||
if (alertRuleCount === 0) {
|
||||
await AlertRule.bulkCreate([
|
||||
{
|
||||
user_id: adminUser.id,
|
||||
name: 'Arlanda Airport Security Alert',
|
||||
description: 'High-priority drone detection alert for Arlanda Airport',
|
||||
is_active: true,
|
||||
device_ids: [1], // Arlanda detector only
|
||||
min_rssi: -85, // Alert on any detection
|
||||
priority: 'critical',
|
||||
alert_channels: ['sms'],
|
||||
sms_phone_number: '0736419592',
|
||||
cooldown_period: 300, // 5 minutes between alerts
|
||||
min_detections: 1,
|
||||
time_window: 60 // 1 minute window
|
||||
},
|
||||
{
|
||||
user_id: adminUser.id,
|
||||
name: 'Muskö Naval Base Security Alert',
|
||||
description: 'High-priority drone detection alert for Muskö Naval Base',
|
||||
is_active: true,
|
||||
device_ids: [2], // Muskö detector only
|
||||
min_rssi: -85, // Alert on any detection
|
||||
priority: 'critical',
|
||||
alert_channels: ['sms'],
|
||||
sms_phone_number: '0739999999',
|
||||
cooldown_period: 300, // 5 minutes between alerts
|
||||
min_detections: 1,
|
||||
time_window: 60 // 1 minute window
|
||||
},
|
||||
{
|
||||
user_id: adminUser.id,
|
||||
name: 'Royal Castle Security Alert',
|
||||
description: 'High-priority drone detection alert for Royal Castle',
|
||||
is_active: true,
|
||||
device_ids: [3], // Royal Castle detector only
|
||||
min_rssi: -85, // Alert on any detection
|
||||
priority: 'critical',
|
||||
alert_channels: ['sms'],
|
||||
sms_phone_number: '0739999999',
|
||||
cooldown_period: 300, // 5 minutes between alerts
|
||||
min_detections: 1,
|
||||
time_window: 60 // 1 minute window
|
||||
}
|
||||
]);
|
||||
|
||||
console.log('✅ Location-specific alert rules created:');
|
||||
console.log(' - Arlanda Airport → 0736419592');
|
||||
console.log(' - Muskö Naval Base → 073999999');
|
||||
console.log(' - Royal Castle → 073999999');
|
||||
} else {
|
||||
console.log('✅ Alert rules already exist');
|
||||
}
|
||||
|
||||
console.log('🌱 Database seeding completed');
|
||||
} catch (error) {
|
||||
console.error('❌ Database seeding failed:', error);
|
||||
|
||||
@@ -7,6 +7,7 @@ class AlertService {
|
||||
this.twilioClient = null;
|
||||
this.twilioPhone = null;
|
||||
this.twilioEnabled = false;
|
||||
this.activeAlerts = new Map(); // Track active alerts for clear notifications
|
||||
this.initializeTwilio();
|
||||
}
|
||||
|
||||
@@ -156,6 +157,15 @@ class AlertService {
|
||||
for (const rule of alertRules) {
|
||||
if (await this.shouldTriggerAlert(rule, detection, threatAssessment)) {
|
||||
await this.triggerAlert(rule, detection, threatAssessment);
|
||||
|
||||
// Track active alert for potential clear notification
|
||||
const alertKey = `${rule.id}-${detection.device_id}`;
|
||||
this.activeAlerts.set(alertKey, {
|
||||
rule,
|
||||
detection,
|
||||
threatAssessment,
|
||||
alertTime: new Date()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,7 +323,7 @@ class AlertService {
|
||||
// SECURITY ENHANCEMENT: For critical threats, send to all available channels
|
||||
const channels = threatAssessment.level === 'critical'
|
||||
? ['sms', 'email', 'webhook'] // Force all channels for critical threats
|
||||
: rule.actions.channels || ['sms'];
|
||||
: rule.alert_channels || ['sms'];
|
||||
|
||||
// Send alerts through configured channels
|
||||
for (const channel of channels) {
|
||||
@@ -322,8 +332,8 @@ class AlertService {
|
||||
try {
|
||||
switch (channel) {
|
||||
case 'sms':
|
||||
if (rule.actions.sms && rule.actions.phone_number) {
|
||||
alertLog = await this.sendSMSAlert(rule.actions.phone_number, message, rule, detection, threatAssessment);
|
||||
if (rule.alert_channels.includes('sms') && rule.sms_phone_number) {
|
||||
alertLog = await this.sendSMSAlert(rule.sms_phone_number, message, rule, detection, threatAssessment);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -375,7 +385,8 @@ class AlertService {
|
||||
// Check if Twilio is enabled
|
||||
if (!this.twilioEnabled || !this.twilioClient) {
|
||||
console.log('📱 SMS alert skipped - Twilio not configured');
|
||||
console.log(`📱 Would have sent to ${phoneNumber}: ${message}`);
|
||||
console.log(`📱 Would have sent to ${phoneNumber}:`);
|
||||
console.log(`📱 Message: ${message}`);
|
||||
|
||||
return await AlertLog.create({
|
||||
alert_rule_id: rule.id,
|
||||
@@ -392,7 +403,8 @@ class AlertService {
|
||||
}
|
||||
|
||||
try {
|
||||
console.log(`📱 Sending SMS alert to ${phoneNumber}`);
|
||||
console.log(`📱 Sending SMS alert to ${phoneNumber} for rule: ${rule.name}`);
|
||||
console.log(`📱 Message: ${message}`);
|
||||
|
||||
const twilioMessage = await this.twilioClient.messages.create({
|
||||
body: message,
|
||||
@@ -400,7 +412,7 @@ class AlertService {
|
||||
to: phoneNumber
|
||||
});
|
||||
|
||||
console.log(`✅ SMS sent successfully: ${twilioMessage.sid}`);
|
||||
console.log(`✅ SMS sent successfully to ${phoneNumber}: ${twilioMessage.sid}`);
|
||||
|
||||
return await AlertLog.create({
|
||||
alert_rule_id: rule.id,
|
||||
@@ -414,7 +426,7 @@ class AlertService {
|
||||
priority: rule.priority
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to send SMS:', error.message);
|
||||
console.error(`❌ Failed to send SMS to ${phoneNumber}:`, error.message);
|
||||
|
||||
return await AlertLog.create({
|
||||
alert_rule_id: rule.id,
|
||||
@@ -553,6 +565,59 @@ class AlertService {
|
||||
|
||||
return hours * 60 + minutes;
|
||||
}
|
||||
|
||||
// Check for cleared alerts (call this periodically)
|
||||
async checkClearedAlerts() {
|
||||
try {
|
||||
const now = new Date();
|
||||
const clearThreshold = 5 * 60 * 1000; // 5 minutes without detection = cleared
|
||||
|
||||
for (const [alertKey, alertData] of this.activeAlerts.entries()) {
|
||||
const timeSinceAlert = now - alertData.alertTime;
|
||||
|
||||
if (timeSinceAlert > clearThreshold) {
|
||||
// Check if there are any recent detections from this device
|
||||
const recentDetections = await DroneDetection.count({
|
||||
where: {
|
||||
device_id: alertData.detection.device_id,
|
||||
device_timestamp: {
|
||||
[Op.gte]: new Date(now - clearThreshold)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (recentDetections === 0) {
|
||||
await this.sendClearAlert(alertData);
|
||||
this.activeAlerts.delete(alertKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error checking cleared alerts:', error);
|
||||
}
|
||||
}
|
||||
|
||||
async sendClearAlert(alertData) {
|
||||
const { rule, detection } = alertData;
|
||||
|
||||
if (rule.alert_channels.includes('sms') && rule.sms_phone_number) {
|
||||
const device = await Device.findByPk(detection.device_id);
|
||||
const clearMessage = this.generateClearMessage(device, rule);
|
||||
|
||||
console.log(`🟢 ALERT CLEARED - Sending clear notification for ${device.name} to ${rule.sms_phone_number}`);
|
||||
|
||||
await this.sendSMSAlert(rule.sms_phone_number, clearMessage, rule, detection, null);
|
||||
}
|
||||
}
|
||||
|
||||
generateClearMessage(device, rule) {
|
||||
return `🟢 ALL CLEAR 🟢\n\n` +
|
||||
`📍 LOCATION: ${device.location_description || device.name}\n` +
|
||||
`🔧 DEVICE: ${device.name}\n` +
|
||||
`⏰ TIME: ${new Date().toLocaleString('sv-SE')}\n\n` +
|
||||
`✅ No drone activity detected for 5+ minutes.\n` +
|
||||
`🛡️ Area is secure.`;
|
||||
}
|
||||
}
|
||||
|
||||
// Export the class directly (not a singleton instance)
|
||||
|
||||
Reference in New Issue
Block a user