You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
39 lines
1.2 KiB
39 lines
1.2 KiB
const crypto = require('crypto')
|
|
const { env } = require('../config/env')
|
|
|
|
function sign(value) {
|
|
return crypto
|
|
.createHmac('sha256', env.auth.sessionSecret)
|
|
.update(value)
|
|
.digest('base64url')
|
|
}
|
|
|
|
function createSessionToken(accountId) {
|
|
const issuedAt = Math.floor(Date.now() / 1000)
|
|
const payload = Buffer.from(JSON.stringify({
|
|
sub: accountId,
|
|
iat: issuedAt,
|
|
exp: issuedAt + Math.max(1, Number(env.auth.sessionTtlHours || 168)) * 60 * 60,
|
|
})).toString('base64url')
|
|
return `${payload}.${sign(payload)}`
|
|
}
|
|
|
|
function verifySessionToken(token) {
|
|
const [payload, signature, extra] = String(token || '').trim().split('.')
|
|
if (!payload || !signature || extra) return null
|
|
const expected = sign(payload)
|
|
const actualBuffer = Buffer.from(signature)
|
|
const expectedBuffer = Buffer.from(expected)
|
|
if (actualBuffer.length !== expectedBuffer.length || !crypto.timingSafeEqual(actualBuffer, expectedBuffer)) return null
|
|
|
|
try {
|
|
const data = JSON.parse(Buffer.from(payload, 'base64url').toString('utf8'))
|
|
if (!data.sub || !data.exp || Number(data.exp) <= Math.floor(Date.now() / 1000)) return null
|
|
return data
|
|
} catch (error) {
|
|
return null
|
|
}
|
|
}
|
|
|
|
module.exports = { createSessionToken, verifySessionToken }
|