fix: security hardening and Safari stability

- Remove hardcoded JWT_SECRET fallback (crash on boot if unset)
- Make LiveKit config optional with 503 guard on token endpoint
- Add REST rate limiting via @fastify/rate-limit (auth 10/15m, messages 5/5s, uploads 10/1m, global 60/1m)
- Add WebSocket token bucket rate limiter (30 burst, 2/sec refill)
- Add DM channel ownership (ownerId) with migration, enforce on add-member
- Require friendship to add users to group DMs
- Add silent 20Hz oscillator to prevent Safari AudioContext suspension
- Move WebSocket heartbeat to Web Worker to bypass Safari background throttling
This commit is contained in:
Jannis Braun
2026-02-24 04:34:36 +01:00
parent 36e27121da
commit 024833c470
16 changed files with 205 additions and 36 deletions
+18 -2
View File
@@ -19,7 +19,15 @@ function sanitizeUser(row: typeof schema.users.$inferSelect): User {
}
export async function authRoutes(app: FastifyInstance): Promise<void> {
app.post<{ Body: RegisterRequest }>('/api/auth/register', async (request, reply) => {
app.post<{ Body: RegisterRequest }>('/api/auth/register', {
config: {
rateLimit: {
max: 10,
timeWindow: '15 minutes',
keyGenerator: (request: any) => request.ip,
},
},
}, async (request, reply) => {
const { username, password, displayName } = request.body;
if (!username || typeof username !== 'string') {
@@ -83,7 +91,15 @@ export async function authRoutes(app: FastifyInstance): Promise<void> {
return reply.code(201).send(response);
});
app.post<{ Body: LoginRequest }>('/api/auth/login', async (request, reply) => {
app.post<{ Body: LoginRequest }>('/api/auth/login', {
config: {
rateLimit: {
max: 10,
timeWindow: '15 minutes',
keyGenerator: (request: any) => request.ip,
},
},
}, async (request, reply) => {
const { username, password } = request.body;
if (!username || typeof username !== 'string') {