Use PUBLIC_URL for the passkey origin; warn on weak cookie secrets
build-container / build (push) Successful in 2m39s

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
nmemmertandClaude Sonnet 5.5 committed 2026-10-20 14:00:44 -04:00
1 parent 1b49ee6cb4
commit 943f510ec4
1 file changed
+7 -1
+7 -1
View File
@@ -16,6 +16,8 @@ const writeJson = (f, v) => fs.writeFileSync(path.join(DATA_DIR, f), JSON.string
// Signing secret for cookies: env wins, otherwise generated once and kept so sessions survive restarts.
let secret = process.env.COOKIE_SECRET;
if (secret && secret.length < 24) console.warn('[auth] COOKIE_SECRET is short; use at least 32 random characters (openssl rand -hex 32).');
if (secret && process.env.HUB_SETUP_CODE && secret === process.env.HUB_SETUP_CODE) console.warn('[auth] COOKIE_SECRET equals HUB_SETUP_CODE. Anyone who knows the setup code could forge sessions. Use different random values.');
if (!secret) {
secret = readJson('secret.json', {}).secret;
if (!secret) { secret = crypto.randomBytes(32).toString('hex'); writeJson('secret.json', { secret }); }
@@ -30,7 +32,7 @@ if (!store.creds.length) console.log(`[auth] No passkeys yet. Setup code: ${SETU
const SESSION_DAYS = 30;
const mac = v => crypto.createHmac('sha256', secret).update(v).digest('base64url');
const cookies = req => Object.fromEntries((req.headers.cookie || '').split(/; */).filter(Boolean).map(c => { const i = c.indexOf('='); return [c.slice(0, i), decodeURIComponent(c.slice(i + 1))]; }));
const isHttps = req => (req.headers['x-forwarded-proto'] || '') === 'https';
const isHttps = req => (req.headers['x-forwarded-proto'] || '') === 'https' || (process.env.PUBLIC_URL || '').startsWith('https://');
function isAuthed(req) {
const [exp, sig] = String(cookies(req).hub_session || '').split('.');
@@ -64,7 +66,11 @@ const throttled = req => {
return h.n > 10;
};
// When PUBLIC_URL is set it is the source of truth for the passkey origin, so a reverse proxy that
// forgets Host / X-Forwarded-Proto cannot break passkeys. Otherwise derive it from the request.
const PUBLIC = (process.env.PUBLIC_URL || '').replace(/\/$/, '');
const rp = req => {
if (PUBLIC) { const u = new URL(PUBLIC); return { rpID: u.hostname, origin: u.origin }; }
const host = req.headers['x-forwarded-host'] || req.headers.host || 'localhost';
const proto = req.headers['x-forwarded-proto'] || 'http';
return { rpID: host.split(':')[0], origin: `${proto}://${host}` };