diff --git a/server.js b/server.js index c2f2acb..f685697 100644 --- a/server.js +++ b/server.js @@ -817,10 +817,50 @@ function linkSitePage(host, page) { } // ---- server ---- +// ---- the curtain ---------------------------------------------------------- +// Work in progress is not for passers-by. CURTAIN= puts a contentless holding page +// in front of every request; ?k= sets a cookie that lifts it for that browser. +const CURTAIN = String(process.env.CURTAIN || '').trim(); +const CURTAIN_PAGE = ` + +Coming soon

Coming soon

This site is still being built.

`; + +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);