Use PUBLIC_URL for the passkey origin; warn on weak cookie secrets
build-container / build (push) Successful in 2m39s
build-container / build (push) Successful in 2m39s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
1b49ee6cb4
commit
943f510ec4
1 file changed
+7
-1
@@ -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}` };
|
||||
|
||||
Reference in new issue
Block a user