65 lines
1.8 KiB
TypeScript
65 lines
1.8 KiB
TypeScript
import { Router } from 'express';
|
|
import type { Request, Response } from 'express';
|
|
import { getDb } from '../../db/index';
|
|
import { buildDisplayJson } from '../../modules/display/display-builder';
|
|
|
|
const router = Router();
|
|
|
|
/**
|
|
* GET /api/display/:id
|
|
* ESP32 endpoint — returns display JSON.
|
|
* Optional token auth via ?token=... or Authorization: Bearer ...
|
|
* If the display has an api_token set, the token MUST match.
|
|
*/
|
|
router.get('/:id', (req: Request, res: Response): void => {
|
|
try {
|
|
const db = getDb();
|
|
const displayId = parseInt(req.params.id);
|
|
|
|
const display = db
|
|
.prepare('SELECT id, api_token FROM displays WHERE id = ?')
|
|
.get(displayId) as { id: number; api_token: string | null } | undefined;
|
|
|
|
if (!display) {
|
|
res.status(404).json({ error: 'Display not found' });
|
|
return;
|
|
}
|
|
|
|
// Check token if display has one configured
|
|
if (display.api_token) {
|
|
const authHeader = req.headers.authorization;
|
|
const queryToken = req.query.token as string | undefined;
|
|
|
|
let provided: string | null = null;
|
|
if (authHeader && authHeader.startsWith('Bearer ')) {
|
|
provided = authHeader.slice(7);
|
|
} else if (queryToken) {
|
|
provided = queryToken;
|
|
}
|
|
|
|
if (!provided || provided !== display.api_token) {
|
|
res.status(401).json({ error: 'Invalid or missing token' });
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Update last_seen
|
|
db.run(
|
|
`UPDATE displays SET last_seen = datetime('now') WHERE id = ?`,
|
|
[displayId]
|
|
);
|
|
|
|
const json = buildDisplayJson(displayId);
|
|
if (!json) {
|
|
res.status(404).json({ error: 'Display configuration not found' });
|
|
return;
|
|
}
|
|
|
|
res.json(json);
|
|
} catch (err) {
|
|
res.status(500).json({ error: (err as Error).message });
|
|
}
|
|
});
|
|
|
|
export default router;
|