openvibers/openvibe.live Commits

Ban screen: 'Please leave me alone' as the headline; the ban sticks to the browser via cookie so every visit (signed in or not) lands on it

OP OpenVibers committed 11 Sept 2026 · 0f398bcde4 · 2 files, +25 −9

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CMxJm1dB8rdsaMSgNjVa82

Changes

ddiff --git a/public/banned.html b/public/banned.html
iindex da2c1a43..2930344a 100644
---- a/public/banned.html
++++ b/public/banned.html
@@@ -11,11 +11,14 @@
* { box-sizing: border-box; }
body { margin: 0; min-height: 100vh; display: grid; place-items: center; padding: 24px 16px; font-family: 'Segoe UI', system-ui, -apple-system, sans-serif; color: #e8e6e3;
background: radial-gradient(120% 90% at 50% 110%, #3b0a0a 0%, #0d0d0f 60%); }
-- .card { max-width: 640px; width: 100%; text-align: center; padding: 36px 28px; border-radius: 20px; background: rgba(20,12,14,0.85); border: 1px solid rgba(231,76,60,0.45);
++ .card { max-width: 820px; width: 100%; text-align: center; padding: 36px 28px; border-radius: 20px; background: rgba(20,12,14,0.85); border: 1px solid rgba(231,76,60,0.45);
box-shadow: 0 30px 80px rgba(0,0,0,0.6), 0 0 0 1px rgba(231,76,60,0.2), 0 0 60px rgba(231,76,60,0.15); }
.stamp { display: inline-block; padding: 8px 22px; border: 4px solid #e74c3c; color: #e74c3c; border-radius: 10px; font-weight: 900; font-size: clamp(2rem, 8vw, 3.4rem); letter-spacing: 0.18em;
transform: rotate(-4deg); text-shadow: 0 0 20px rgba(231,76,60,0.5); }
h1 { margin: 22px 0 8px; font-size: clamp(1.3rem, 3.6vw, 1.9rem); }
++ .plea { margin: 26px 0 10px; font-size: clamp(2.2rem, 8.5vw, 4.6rem); line-height: 1.02; font-weight: 900; letter-spacing: -0.02em; color: #fff; text-shadow: 0 6px 30px rgba(0,0,0,0.6); }
++ .plea-body { font-size: clamp(1.25rem, 3.6vw, 1.9rem); line-height: 1.35; color: #fff; font-weight: 600; margin: 0 0 18px; }
++ .who { font-size: 1.05rem; color: #cfc9c4; margin: 0 0 6px; }
p { margin: 0 0 12px; font-size: 1.02rem; line-height: 1.55; color: #cfc9c4; }
p b { color: #fff; }
.reason { margin: 18px 0; padding: 12px 14px; border-radius: 12px; background: rgba(231,76,60,0.1); border-left: 3px solid #e74c3c; text-align: left; color: #f5d5d0; }
@@@ -27,11 +30,12 @@
<body>
<div class="card">
<div class="stamp">BANNED</div>
-- <h1>{{HEADLINE}}</h1>
-- <p>{{BODY}}</p>
++ <h1 class="plea">Please leave me alone.</h1>
++ <p class="plea-body">I'm trying to move forward with my life, and you have been nothing but disrespectful to me.</p>
++ <p class="who">{{HEADLINE}}</p>
<div class="reason"><small>Reason on record</small>{{REASON}}</div>
<p><b>This ban is permanent.</b> Don't put any effort into coming back — there is nothing here for you, and this decision won't change.</p>
-- <p class="fine"><span class="logo">OpenVibe.Live</span> · this page is shown to you every time you open the site.</p>
++ <p class="fine"><span class="logo">OpenVibe.Live</span> · you will see this page every time you open the site.</p>
</div>
</body>
</html>
ddiff --git a/server/index.js b/server/index.js
iindex d693e608..73b32d7d 100644
---- a/server/index.js
++++ b/server/index.js
@@@ -361,6 +361,12 @@ app.use((req, res, next) => {
return res.status(404).send('<!DOCTYPE html><html><head><title>404</title></head><body><h1>404 Not Found</h1></body></html>');
}
} catch (e) { /* DB error — let request through rather than block everyone */ }
++ // A browser that has been shown the ban screen keeps seeing it (cookie set by GET /banned),
++ // signed in or not. Assets still load so the page itself can render.
++ if (req.cookies && req.cookies.ov_banned === '1' && !req.path.startsWith('/banned') && !req.path.startsWith('/assets/') && req.path !== '/api/health') {
++ if (req.path.startsWith('/api/') || req.path.startsWith('/ws/')) return res.status(403).json({ error: 'Account is banned' });
++ return res.redirect(302, '/banned');
++ }
next();
});
@@@ -735,14 +741,20 @@ app.get('/banned', (req, res) => {
const token = extractToken(req);
if (token) { user = authenticateApiToken(token) || (() => { const d = verifyToken(token); return d ? resolveNetworkUser(d) : null; })(); }
} catch { user = null; }
-- if (user && !user.is_banned) return res.redirect('/');
-- const name = user ? (user.display_name || user.username) : null;
-- const reason = (user && user.ban_reason) || 'Banned by the site owner.';
++ if (user && !user.is_banned) { res.clearCookie('ov_banned'); res.clearCookie('ov_banned_name'); return res.redirect('/'); }
++ // Make the ban stick to this browser: from now on every visit — signed in or not — lands here.
++ const isSecure = String(config.baseUrl || '').startsWith('https');
++ const tenYears = 10 * 365 * 24 * 3600 * 1000;
++ if (user && user.is_banned) {
++ res.cookie('ov_banned', '1', { httpOnly: true, maxAge: tenYears, sameSite: 'Lax', secure: isSecure });
++ res.cookie('ov_banned_name', String(user.display_name || user.username).slice(0, 60), { httpOnly: true, maxAge: tenYears, sameSite: 'Lax', secure: isSecure });
++ }
++ const name = user ? (user.display_name || user.username) : (req.cookies && req.cookies.ov_banned_name ? String(req.cookies.ov_banned_name) : null);
++ const reason = (user && user.ban_reason) || 'Repeated disrespect toward the owner of this site. Permanent.';
let html = '';
try { html = require('fs').readFileSync(path.join(__dirname, '../public/banned.html'), 'utf8'); } catch { html = '<h1>Banned</h1>'; }
html = html
-- .replace('{{HEADLINE}}', name ? `${escHtml(name)}, you are banned from OpenVibe.Live.` : 'This account is banned from OpenVibe.Live.')
-- .replace('{{BODY}}', name ? `You were disrespectful to the person who built and runs this site, and you hurt him. That's the whole story, and it's enough.` : 'The account you signed in with has been banned by the site owner.')
++ .replace('{{HEADLINE}}', name ? `${escHtml(name)}, you are banned from OpenVibe.Live.` : 'You are banned from OpenVibe.Live.')
.replace('{{REASON}}', escHtml(reason));
res.status(403).set('Cache-Control', 'no-store').type('html').send(html);
});