diff --git a/server/routes/debug.js b/server/routes/debug.js index b4ead64..f08d3db 100644 --- a/server/routes/debug.js +++ b/server/routes/debug.js @@ -87,29 +87,21 @@ router.get('/heartbeat-payloads', authenticateToken, MultiTenantAuth, async (req const { limit = 50, offset = 0, device_id } = req.query; const whereClause = { - raw_payload: { [Op.ne]: null } + raw_payload: { [Op.ne]: null }, + tenant_id: req.user.tenant_id // 🔒 SECURITY: Filter by user's tenant }; if (device_id) { whereClause.device_id = device_id; } - // 🔒 SECURITY: Filter heartbeats by user's tenant using device relationship const heartbeats = await Heartbeat.findAll({ where: whereClause, - include: [{ - model: Device, - as: 'device', - where: { - tenant_id: req.user.tenant_id - }, - attributes: ['id', 'name', 'tenant_id'] - }], order: [['received_at', 'DESC']], limit: parseInt(limit), offset: parseInt(offset), attributes: [ - 'id', 'device_id', 'device_key', 'received_at', 'raw_payload' + 'id', 'device_id', 'device_key', 'received_at', 'raw_payload', 'tenant_id' ] }); diff --git a/server/routes/detections.js b/server/routes/detections.js index 2dccc8e..d3f9451 100644 --- a/server/routes/detections.js +++ b/server/routes/detections.js @@ -226,6 +226,9 @@ router.get('/debug', authenticateToken, async (req, res) => { include: [{ model: Device, as: 'device', + where: { + tenant_id: req.user.tenant_id // 🔒 SECURITY: Filter by user's tenant + }, attributes: ['id', 'name', 'location_description', 'geo_lat', 'geo_lon', 'tenant_id'] }], limit: parseInt(limit), @@ -243,6 +246,8 @@ router.get('/debug', authenticateToken, async (req, res) => { }; }); + console.log(`🔒 Admin debug: Retrieved ${detections.count} detections for tenant ${req.user.tenant_id}`); + res.json({ success: true, data: enhancedDetections, diff --git a/server/routes/detectors.js b/server/routes/detectors.js index e79ad5c..8e2c708 100644 --- a/server/routes/detectors.js +++ b/server/routes/detectors.js @@ -155,13 +155,15 @@ async function handleHeartbeat(req, res) { if (!device.is_approved) { console.log(`🚫 Heartbeat rejected from unapproved device ${deviceId}`); - // Emit reminder notification - req.io.emit('device_approval_reminder', { - device_id: deviceId, - device_key: key, - timestamp: new Date().toISOString(), - message: `Device ${deviceId} (${key}) still awaiting approval` - }); + // Emit reminder notification to tenant room only + if (device.tenant_id) { + req.io.to(`tenant_${device.tenant_id}`).emit('device_approval_reminder', { + device_id: deviceId, + device_key: key, + timestamp: new Date().toISOString(), + message: `Device ${deviceId} (${key}) still awaiting approval` + }); + } return res.status(403).json({ success: false, @@ -195,14 +197,16 @@ async function handleHeartbeat(req, res) { const heartbeat = await Heartbeat.create(heartbeatRecord); - // Emit real-time update via Socket.IO (from original heartbeat route) - req.io.emit('device_heartbeat', { - device_id: deviceId, - device_key: key, - timestamp: heartbeat.received_at, - status: 'online', - ...heartbeatData - }); + // Emit real-time update via Socket.IO to tenant room only + if (device.tenant_id) { + req.io.to(`tenant_${device.tenant_id}`).emit('device_heartbeat', { + device_id: deviceId, + device_key: key, + timestamp: heartbeat.received_at, + status: 'online', + ...heartbeatData + }); + } console.log(`✅ Heartbeat recorded for device ${deviceId}`); @@ -261,12 +265,14 @@ async function handleDetection(req, res) { if (!device.is_approved) { console.log(`🚫 Detection rejected from unapproved device ${detectionData.device_id}`); - // Emit reminder notification - req.io.emit('device_approval_reminder', { - device_id: detectionData.device_id, - timestamp: new Date().toISOString(), - message: `Device ${detectionData.device_id} still awaiting approval` - }); + // Emit reminder notification to tenant room only + if (device.tenant_id) { + req.io.to(`tenant_${device.tenant_id}`).emit('device_approval_reminder', { + device_id: detectionData.device_id, + timestamp: new Date().toISOString(), + message: `Device ${detectionData.device_id} still awaiting approval` + }); + } return res.status(403).json({ success: false, diff --git a/server/routes/device.js b/server/routes/device.js index 3e3065d..993a652 100644 --- a/server/routes/device.js +++ b/server/routes/device.js @@ -433,9 +433,9 @@ router.put('/:id', authenticateToken, validateRequest(updateDeviceSchema), async await device.update(req.body); - // Emit real-time update (only if io is available) - if (req.io) { - req.io.emit('device_updated', device); + // Emit real-time update to tenant room only + if (req.io && device.tenant_id) { + req.io.to(`tenant_${device.tenant_id}`).emit('device_updated', device); } console.log(`✅ Device ${req.params.id} updated successfully`); @@ -564,10 +564,10 @@ router.post('/:id/approve', async (req, res) => { is_active: approved // Set device as active when approved, inactive when unapproved }); - // Emit real-time notification + // Emit real-time notification to tenant room only const { io } = require('../index'); - if (io) { - io.emit('device_approval_updated', { + if (io && device.tenant_id) { + io.to(`tenant_${device.tenant_id}`).emit('device_approval_updated', { device_id: deviceId, approved: approved, timestamp: new Date().toISOString(),