A curtain in front of the whole app
Work in progress should not be readable by anyone who wanders in. CURTAIN=<secret> puts a contentless "Coming soon" card in front of every request — pages, APIs, the rotator, the link domains — with noindex headers and nothing that names the product or what it does. Opening the site once with ?k=<secret> drops a cookie that lifts it for that browser. Unsetting CURTAIN opens the site again, so this never has to be picked back out of the code. It sits at the very top of the request handler, ahead of the rotator and the link-domain sites, so there is no path around it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -817,10 +817,50 @@ function linkSitePage(host, page) {
|
||||
}
|
||||
|
||||
// ---- server ----
|
||||
// ---- the curtain ----------------------------------------------------------
|
||||
// Work in progress is not for passers-by. CURTAIN=<secret> puts a contentless holding page
|
||||
// in front of every request; ?k=<secret> sets a cookie that lifts it for that browser.
|
||||
const CURTAIN = String(process.env.CURTAIN || '').trim();
|
||||
const CURTAIN_PAGE = `<!doctype html><html lang="en"><head><meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1"><meta name="robots" content="noindex,nofollow">
|
||||
<title>Coming soon</title><style>
|
||||
*{margin:0;padding:0;box-sizing:border-box}
|
||||
html,body{height:100%}
|
||||
body{display:flex;align-items:center;justify-content:center;padding:24px;
|
||||
background:#0d1117;color:#e6edf3;font:16px/1.6 system-ui,-apple-system,"Segoe UI",sans-serif}
|
||||
.card{max-width:420px;text-align:center}
|
||||
h1{font-size:clamp(28px,7vw,44px);font-weight:700;letter-spacing:-.5px;margin-bottom:14px}
|
||||
p{color:#8b949e}
|
||||
</style></head><body><div class="card"><h1>Coming soon</h1><p>This site is still being built.</p></div></body></html>`;
|
||||
|
||||
function curtained(req, res, u) {
|
||||
if (!CURTAIN) return false;
|
||||
if (u.searchParams.get('k') === CURTAIN) {
|
||||
u.searchParams.delete('k');
|
||||
res.writeHead(302, {
|
||||
'Set-Cookie': 'ls.pass=' + encodeURIComponent(CURTAIN) + '; Path=/; Max-Age=2592000; HttpOnly; SameSite=Lax; Secure',
|
||||
Location: u.pathname + (u.searchParams.toString() ? '?' + u.searchParams : ''),
|
||||
'Cache-Control': 'no-store'
|
||||
});
|
||||
res.end();
|
||||
return true;
|
||||
}
|
||||
const pass = /(?:^|;\s*)ls\.pass=([^;]*)/.exec(req.headers.cookie || '');
|
||||
if (pass && decodeURIComponent(pass[1]) === CURTAIN) return false;
|
||||
res.writeHead(503, {
|
||||
'Content-Type': 'text/html; charset=utf-8',
|
||||
'Cache-Control': 'no-store',
|
||||
'X-Robots-Tag': 'noindex, nofollow'
|
||||
});
|
||||
res.end(req.method === 'HEAD' ? '' : CURTAIN_PAGE);
|
||||
return true;
|
||||
}
|
||||
|
||||
const server = http.createServer(async (req, res) => {
|
||||
try {
|
||||
const u = new URL(req.url, 'http://x');
|
||||
const p = u.pathname;
|
||||
if (curtained(req, res, u)) return; // nothing below this line runs for an uninvited visitor
|
||||
|
||||
// -- the rotator redirect: one hop, recorded, on any host (LinkSpin)
|
||||
let rm = /^\/r\/([a-z0-9]{4,12})$/i.exec(p);
|
||||
|
||||
Reference in New Issue
Block a user