diff --git a/core/app.js b/core/app.js index 2a8389b8..1d41ce7e 100644 --- a/core/app.js +++ b/core/app.js @@ -61,6 +61,8 @@ function socket(request, response, client) { let process; let options = {}; let credentials = auth.query(request.headers); + let refresh_token = credentials?.refresh?.token; + let refresh_interval = credentials?.refresh?.interval; response.onClose = async function() { if (process && process.task) { @@ -190,6 +192,12 @@ function socket(request, response, client) { process.lastActive = Date.now(); } } + + if (refresh_token) { + return { + 'Set-Cookie': `session=${refresh_token}; path=/; Max-Age=${refresh_interval}; Secure; SameSite=Strict`, + }; + } } export { socket, App }; diff --git a/core/auth.js b/core/auth.js index c890c02e..3502f242 100644 --- a/core/auth.js +++ b/core/auth.js @@ -5,13 +5,7 @@ import * as form from './form.js'; var gTokens = {}; var gDatabase = new Database("auth"); -const kRefreshInterval = - 1 /* w */ * - 7 /* d */ * - 24 /* h */ * - 60 /* m */ * - 60 /* s */ * - 1000 /* ms */; +const kRefreshInterval = 1 * 7 * 24 * 60 * 60 * 1000; function b64url(value) { value = value.replaceAll('+', '-').replaceAll('/', '_'); @@ -59,10 +53,12 @@ function readSession(session) { let id = ssb.getIdentities(':auth'); if (id?.length && ssb.hmacsha256verify(id[0], payload, signature)) { let result = JSON.parse(base64Decode(unb64url(payload))); - if ((new Date()).valueOf() < result.exp) { + let now = new Date().valueOf() + if (now < result.exp) { + print(`JWT valid for another ${(result.exp - now) / 1000} seconds.`); return result; } else { - print('JWT expired.'); + print(`JWT expired by ${(now - result.exp) / 1000} seconds.`); } } else { print('JWT verification failed.'); @@ -70,6 +66,8 @@ function readSession(session) { } else { print('Invalid JWT header.'); } + } else { + print('No session JWT.'); } } @@ -174,7 +172,7 @@ function handler(request, response) { } } - var cookie = "session=" + session + "; path=/; Max-Age=604800; Secure; SameSite=Strict"; + var cookie = `session=${session}; path=/; Max-Age=${kRefreshInterval}; Secure; SameSite=Strict`; var entry = readSession(session); if (entry && formData.return) { response.writeHead(303, {"Location": formData.return, "Set-Cookie": cookie}); @@ -257,7 +255,14 @@ function query(headers) { var entry; var autologin = tildefriends.args.autologin; if (entry = autologin ? {name: autologin} : readSession(session)) { - return {session: entry, permissions: autologin ? getPermissionsForUser(autologin) : getPermissions(session)}; + return { + session: entry, + permissions: autologin ? getPermissionsForUser(autologin) : getPermissions(session), + refresh: { + token: makeJwt({name: entry.name}), + interval: kRefreshInterval, + }, + }; } } diff --git a/core/httpd.js b/core/httpd.js index 5ff91847..ed54c256 100644 --- a/core/httpd.js +++ b/core/httpd.js @@ -246,7 +246,7 @@ function handleWebSocketRequest(request, response, client) { } response.onMessage = null; - handler.invoke(request, response); + let extra_headers = handler.invoke(request, response); client.read(function(data) { if (data) { @@ -333,7 +333,7 @@ function handleWebSocketRequest(request, response, client) { if (request.headers["sec-websocket-version"] != "13") { headers["Sec-WebSocket-Version"] = "13"; } - response.writeHead(101, headers); + response.writeHead(101, Object.assign({}, headers, extra_headers)); } function webSocketAcceptResponse(key) {