Changeset 8f2f97c in Klonkt for src/server.js


Ignore:
Timestamp:
06/23/2026 02:24:46 PM (3 months ago)
Author:
Robin Genis <roboburr@…>
Branches:
main
Children:
cb01666
Parents:
24cdcc6
Message:

Prutter (DM feature) fully removed

Reason: redundant feature + unnecessary attack surface (real-time WebSocket +
storing private messages = privacy/abuse risk). Removed: routes/prutter.js,
PrutterService, the WebSocket server in server.js, both DM views, all nav links
(topnav/bottom-tab), the DM button on profiles, the per-site enable_prutter
toggle and column. Existing (empty) DM tables in old DBs remain untouched but
are no longer referenced anywhere. No WebSocket left in the app.

Co-Authored-By: Claude <noreply@…>

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/server.js

    r24cdcc6 r8f2f97c  
    1919import { SqliteSessionStore } from './services/SqliteSessionStore.js';
    2020import { ensurePrimarySite } from './services/ensurePrimarySite.js';
    21 import PrutterService from './services/PrutterService.js';
    22 import { WebSocketServer } from 'ws';
    23 
    2421import { resolveSite, loadAudioTracks, loadTheme } from './middleware/site.js';
    2522import { isViewer } from './middleware/auth.js';
     
    3633import adminSettingsRoutes from './routes/admin-settings.js';
    3734import adminSeoRoutes from './routes/admin-seo.js';
    38 import prutterRoutes from './routes/prutter.js';
    3935import audioRoutes from './routes/audio.js';
    4036import searchRoutes from './routes/search.js';
     
    206202})();
    207203
    208 // Singleton PrutterService — routes get it via req.app.locals.prutter.
    209 const prutter = new PrutterService(db);
    210 app.locals.prutter = prutter;
    211 
    212204// Cirkels-federatie: publieke, site-agnostische endpoints (/.klonkt/*).
    213205// Vóór resolveSite/theme — ze hebben geen site-context nodig.
     
    274266app.use('/admin/epk', adminEpkRoutes);
    275267app.use('/admin', adminRoutes);
    276 app.use('/prutter', prutterRoutes);
    277268app.use('/audio', audioRoutes);
    278269app.use('/search', searchRoutes);
     
    422413});
    423414
    424 // ==================== WebSocket: Prutter real-time ====================
    425 // Authenticate via the existing session cookie. We reuse sessionMiddleware
    426 // during the HTTP upgrade so req.session is populated; if no user, abort.
    427 const wss = new WebSocketServer({ noServer: true });
    428 
    429 server.on('upgrade', (req, socket, head) => {
    430   if (req.url !== '/ws/prutter') {
    431     socket.destroy();
    432     return;
    433   }
    434   // Run session middleware on the upgrade request.
    435   // (Express's middleware accepts (req, res, next); we pass a stub res.)
    436   const stubRes = { setHeader: () => {}, getHeader: () => undefined, on: () => {}, end: () => {} };
    437   sessionMiddleware(req, stubRes, () => {
    438     if (!req.session?.user) {
    439       socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');
    440       socket.destroy();
    441       return;
    442     }
    443     // Kijker-accounts zijn alleen-lezen: weiger de WS-upgrade. De HTTP-guard
    444     // dekt geen WS, dus dit is de plek om schrijven via een (toekomstige)
    445     // message-handler te voorkomen.
    446     if (isViewer(req.session.user)) {
    447       socket.write('HTTP/1.1 403 Forbidden\r\n\r\n');
    448       socket.destroy();
    449       return;
    450     }
    451     wss.handleUpgrade(req, socket, head, (ws) => {
    452       ws.userId = req.session.user.id;
    453       wss.emit('connection', ws, req);
    454     });
    455   });
    456 });
    457 
    458 wss.on('connection', (ws) => {
    459   prutter.addConnection(ws.userId, ws);
    460   ws.on('close', () => prutter.removeConnection(ws.userId, ws));
    461   ws.on('error', () => prutter.removeConnection(ws.userId, ws));
    462   // Optional: ping every 30s to keep connections alive through proxies
    463   ws.isAlive = true;
    464   ws.on('pong', () => { ws.isAlive = true; });
    465 });
    466 const wsPing = setInterval(() => {
    467   for (const ws of wss.clients) {
    468     if (ws.isAlive === false) { ws.terminate(); continue; }
    469     ws.isAlive = false;
    470     try { ws.ping(); } catch {}
    471   }
    472 }, 30000);
    473 if (wsPing.unref) wsPing.unref();
    474 
    475415server.listen(PORT, () => {
    476416  console.log('');
     
    483423  console.log(`   ✓ Auth:     wachtwoord (beheer) + Google (luisteraars) / logout`);
    484424  console.log(`   ✓ Posts:    create / edit / view / archive`);
    485   console.log(`   ✓ Realtime: WebSocket server ready (Prutter)`);
    486425  console.log('');
    487426  console.log(`   Mode: ${isDev ? 'development' : 'PRODUCTION'}`);
Note: See TracChangeset for help on using the changeset viewer.