feat(security): add phase8 hardening with rate limits, audit logs, and auth-first simulator flow

This commit is contained in:
2026-01-24 18:45:00 +00:00
parent 6d6c77f77e
commit f6d66c3650
11 changed files with 355 additions and 5 deletions

View File

@@ -5,6 +5,7 @@ import { z } from 'zod';
import { db } from '../db/client';
import { recordings, streamSessions } from '../db/schema';
import { requireDeviceAuth } from '../middleware/device-auth';
import { writeAuditLog } from '../services/audit';
import { minioBucket, minioClient, minioPresignedExpirySeconds } from '../utils/minio';
const router = Router();
@@ -105,6 +106,16 @@ router.post('/:recordingId/finalize', requireDeviceAuth, async (req, res) => {
.returning();
res.json({ message: 'Recording finalized', recording: updated });
await writeAuditLog({
ownerUserId: recording.ownerUserId,
actorDeviceId: recording.cameraDeviceId,
action: 'recording.finalized',
targetType: 'recording',
targetId: recording.id,
metadata: { objectKey: parsed.data.objectKey, bucket: parsed.data.bucket },
ipAddress: req.ip,
});
});
router.get('/:recordingId/download-url', requireDeviceAuth, async (req, res) => {
@@ -156,6 +167,16 @@ router.get('/:recordingId/download-url', requireDeviceAuth, async (req, res) =>
downloadUrl,
expiresInSeconds: minioPresignedExpirySeconds,
});
await writeAuditLog({
ownerUserId: recording.ownerUserId,
actorDeviceId: deviceAuth.deviceId,
action: 'recording.download_url_issued',
targetType: 'recording',
targetId: recording.id,
metadata: { objectKey: recording.objectKey, bucket: recording.bucket },
ipAddress: req.ip,
});
});
// Internal helper used by stream lifecycle to create recording placeholder rows.