Fix jwt-token

This commit is contained in:
2025-09-17 21:57:00 +02:00
parent 0aacbd9a16
commit a691f7d4a6

View File

@@ -292,9 +292,14 @@ router.get('/devices', async (req, res) => {
const deviceDetails = [];
for (const device of devices) {
const lastHeartbeat = device.heartbeats && device.heartbeats[0];
const isOnline = lastHeartbeat &&
(Date.now() - new Date(lastHeartbeat.timestamp).getTime()) < 300000; // 5 minutes
// Get latest heartbeat metrics for this device
const latestHeartbeat = await Heartbeat.findOne({
where: { device_id: device.id },
order: [['timestamp', 'DESC']]
});
const isOnline = latestHeartbeat &&
(Date.now() - new Date(latestHeartbeat.timestamp).getTime()) < 300000; // 5 minutes
if (isOnline) {
onlineDevices++;
@@ -302,12 +307,29 @@ router.get('/devices', async (req, res) => {
offlineDevices++;
}
// Calculate uptime (time since first heartbeat)
const firstHeartbeat = await Heartbeat.findOne({
where: { device_id: device.id },
order: [['timestamp', 'ASC']]
});
let uptime = null;
if (firstHeartbeat && latestHeartbeat) {
uptime = Math.floor((new Date(latestHeartbeat.timestamp).getTime() - new Date(firstHeartbeat.timestamp).getTime()) / 1000);
}
deviceDetails.push({
id: device.id,
name: device.name,
status: isOnline ? 'online' : 'offline',
lastSeen: lastHeartbeat ? lastHeartbeat.timestamp : null,
uptime: lastHeartbeat ? Math.floor(Date.now() / 1000) - Math.floor(new Date(lastHeartbeat.timestamp).getTime() / 1000) : null
lastSeen: latestHeartbeat ? latestHeartbeat.timestamp : null,
uptime: uptime,
metrics: latestHeartbeat ? {
cpu_usage: latestHeartbeat.cpu_usage,
memory_usage: latestHeartbeat.memory_usage,
disk_usage: latestHeartbeat.disk_usage,
uptime: latestHeartbeat.uptime
} : null
});
}
@@ -350,17 +372,58 @@ router.post('/devices/:id/heartbeat', async (req, res) => {
if (!device.is_approved) {
return res.status(403).json({
status: 'error',
message: 'Device not approved for heartbeat reporting'
message: 'Device not approved for heartbeat reporting',
approval_required: true
});
}
// Validate heartbeat data format
const { status, cpu_usage, memory_usage, disk_usage } = req.body;
const { timestamp, status, cpu_usage, memory_usage, disk_usage } = req.body;
if (!status || typeof status !== 'string') {
return res.status(400).json({
status: 'error',
message: 'Invalid heartbeat data format - status is required'
message: 'Invalid heartbeat data format - status is required and must be a string'
});
}
// Validate status values
const validStatuses = ['online', 'offline', 'error', 'maintenance'];
if (!validStatuses.includes(status)) {
return res.status(400).json({
status: 'error',
message: `Invalid status value. Must be one of: ${validStatuses.join(', ')}`
});
}
// Validate timestamp if provided
if (timestamp && isNaN(new Date(timestamp).getTime())) {
return res.status(400).json({
status: 'error',
message: 'Invalid timestamp format'
});
}
// Validate percentage fields
const percentageFields = { cpu_usage, memory_usage, disk_usage };
for (const [field, value] of Object.entries(percentageFields)) {
if (value !== undefined && value !== null && (typeof value !== 'number' || value < 0 || value > 100)) {
return res.status(400).json({
status: 'error',
message: `Invalid ${field} value. Must be a number between 0 and 100`
});
}
}
// Check for unexpected fields
const allowedFields = ['timestamp', 'status', 'cpu_usage', 'memory_usage', 'disk_usage', 'uptime'];
const receivedFields = Object.keys(req.body);
const invalidFields = receivedFields.filter(field => !allowedFields.includes(field));
if (invalidFields.length > 0) {
return res.status(400).json({
status: 'error',
message: `Invalid fields in heartbeat data: ${invalidFields.join(', ')}`
});
}
@@ -431,18 +494,51 @@ router.get('/metrics', async (req, res) => {
await sequelize.authenticate();
const dbResponseTime = Date.now() - startTime;
// Get CPU usage
const cpuUsage = process.cpuUsage();
// Get database statistics
const [deviceCount] = await sequelize.query(
'SELECT COUNT(*) as count FROM "Devices" WHERE tenant_id = :tenantId',
{
replacements: { tenantId: req.user.tenant_id },
type: sequelize.QueryTypes.SELECT
}
);
const [detectionCount] = await sequelize.query(
'SELECT COUNT(*) as count FROM "DroneDetections" WHERE tenant_id = :tenantId',
{
replacements: { tenantId: req.user.tenant_id },
type: sequelize.QueryTypes.SELECT
}
);
res.status(200).json({
status: 'ok',
metrics: {
system: {
memory: {
heapUsed: Math.round((memUsage.heapUsed / 1024 / 1024) * 100) / 100,
heapTotal: Math.round((memUsage.heapTotal / 1024 / 1024) * 100) / 100,
external: Math.round((memUsage.external / 1024 / 1024) * 100) / 100
},
database: {
responseTime: dbResponseTime
cpu: {
user: cpuUsage.user,
system: cpuUsage.system
},
uptime: process.uptime()
},
database: {
responseTime: dbResponseTime,
connection_pool: {
active: sequelize.connectionManager.pool._count || 0,
idle: sequelize.connectionManager.pool._idle?.length || 0,
total: sequelize.connectionManager.pool.options.max || 10
}
},
statistics: {
total_devices: parseInt(deviceCount.count),
total_detections: parseInt(detectionCount.count)
}
});