Files
meb-server/stream/src/routes/connect.js

44 lines
1.5 KiB
JavaScript

import { Router } from 'express';
import crypto from 'crypto';
import { querySensors as sensors } from '../data/db.js';
import { redis } from '../data/redis.js';
import { verify } from '../core/securitycore.js';
const router = Router();
const rateLimiter = 10;
const rateLimitWindow = 60;
router.post('/connect', async (req, res) => {
const { sensorID, code } = req.body;
const ip = (req.headers['x-forwarded-for']?.split(',')[0]?.trim()) || req.socket.remoteAddress || 'unknown';
const tryKey = `streamconnect:fail:${ip}`;
const fails = Number(await redis.get(tryKey).catch(() => 0));
if (fails >= rateLimiter) {
return res.status(429).json({ error: 'Too many failed attempts' });
}
if (!sensorID || !code) {
await redis.multi().incr(tryKey).expire(tryKey, rateLimitWindow).exec().catch(() => { });
return res.status(400).json({ error: 'sensor and code are required' });
}
const { rows } = await sensors('select id, name, code_hash from sensors where id = $1', [sensorID]);
if (rows.length === 0) {
return res.status(404).json({ error: 'sensor not found' });
}
if (!rows[0] || !verify(code, rows[0].code_hash)) {
await redis.multi().incr(tryKey).expire(tryKey, rateLimitWindow).exec().catch(() => { });
return res.status(401).json({ error: 'invalid code' });
}
const token = crypto.randomUUID();
await redis.set(`sensor:pending:${token}`, rows[0].id, 'EX', 5);
res.json({
token,
expiresIn: 5
})
})
export { router as connectsAPI }