import * as core from './core.js'; import * as form from './form.js'; const kRefreshInterval = 1 * 7 * 24 * 60 * 60 * 1000; /** * Makes a Base64 value URL safe * @param {string} value * @returns TODOC */ function b64url(value) { value = value.replaceAll('+', '-').replaceAll('/', '_'); let equals = value.indexOf('='); if (equals !== -1) { return value.substring(0, equals); } else { return value; } } /** * TODOC * @param {string} value * @returns */ function unb64url(value) { value = value.replaceAll('-', '+').replaceAll('_', '/'); let remainder = value.length % 4; if (remainder == 3) { return value + '='; } else if (remainder == 2) { return value + '=='; } else { return value; } } /** * Creates a JSON Web Token * @param {object} payload Object: {"name": "username"} * @returns the JWT */ function makeJwt(payload) { const ids = ssb.getIdentities(':auth'); let id; if (ids?.length) { id = ids[0]; } else { id = ssb.createIdentity(':auth'); } const final_payload = b64url( base64Encode( JSON.stringify( Object.assign({}, payload, { exp: new Date().valueOf() + kRefreshInterval, }) ) ) ); const jwt = [ b64url(base64Encode(JSON.stringify({alg: 'HS256', typ: 'JWT'}))), final_payload, b64url(ssb.hmacsha256sign(final_payload, ':auth', id)), ].join('.'); return jwt; } /** * Validates a JWT ? * @param {*} session TODOC * @returns */ function readSession(session) { let jwt_parts = session?.split('.'); if (jwt_parts?.length === 3) { let [header, payload, signature] = jwt_parts; header = JSON.parse(utf8Decode(base64Decode(unb64url(header)))); if (header.typ === 'JWT' && header.alg === 'HS256') { signature = unb64url(signature); let id = ssb.getIdentities(':auth'); if (id?.length && ssb.hmacsha256verify(id[0], payload, signature)) { const result = JSON.parse(utf8Decode(base64Decode(unb64url(payload)))); const now = new Date().valueOf(); if (now < result.exp) { print(`JWT valid for another ${(result.exp - now) / 1000} seconds.`); return result; } else { print(`JWT expired by ${(now - result.exp) / 1000} seconds.`); } } else { print('JWT verification failed.'); } } else { print('Invalid JWT header.'); } } } /** * TODOC * @param {*} headers most likely an object * @returns */ function getCookies(headers) { let cookies = {}; if (headers.cookie) { let parts = headers.cookie.split(/,|;/); for (let i in parts) { let equals = parts[i].indexOf('='); let name = parts[i].substring(0, equals).trim(); let value = parts[i].substring(equals + 1).trim(); cookies[name] = value; } } return cookies; } /** * Gets a user's permissions based on it's session ? * @param {*} session TODOC * @returns */ function getPermissions(session) { let permissions; let entry = readSession(session); if (entry) { permissions = getPermissionsForUser(entry.name); permissions.authenticated = entry.name !== 'guest'; } return permissions || {}; } /** * Get a user's permissions ? * @param {string} userName TODOC * @returns */ function getPermissionsForUser(userName) { let permissions = {}; if ( core.globalSettings && core.globalSettings.permissions && core.globalSettings.permissions[userName] ) { for (let i in core.globalSettings.permissions[userName]) { permissions[core.globalSettings.permissions[userName][i]] = true; } } return permissions; } /** * TODOC * @param {*} headers * @returns */ function query(headers) { let session = getCookies(headers).session; let entry; let autologin = tildefriends.args.autologin; if ((entry = autologin ? {name: autologin} : readSession(session))) { return { session: entry, permissions: autologin ? getPermissionsForUser(autologin) : getPermissions(session), }; } } /** * Refreshes a JWT ? * @param {*} credentials TODOC * @returns */ function makeRefresh(credentials) { if (credentials?.session?.name) { return { token: makeJwt({name: credentials.session.name}), interval: kRefreshInterval, }; } } export {query, makeRefresh};