Jonatan Nilsson
71b1725655
Some checks failed
continuous-integration/appveyor/branch AppVeyor build failed
70 lines
2 KiB
JavaScript
70 lines
2 KiB
JavaScript
import crypto from 'crypto'
|
|
import { HttpError } from 'flaska'
|
|
import { decode, encode } from '../util.mjs'
|
|
import config from '../config.mjs'
|
|
|
|
export const RankLevels = {
|
|
Normal: 1,
|
|
Manager: 10,
|
|
Admin: 100,
|
|
}
|
|
|
|
const issuer = config.get('mssql:connectionUser')
|
|
const secret = config.get('jwtsecret')
|
|
|
|
export function verifyValidToken(parts, minLevel) {
|
|
if (parts.length !== 4) {
|
|
throw new HttpError(401, 'Authentication token invalid')
|
|
}
|
|
|
|
const hmac = crypto.createHmac('sha256', secret)
|
|
hmac.update([parts[0], parts[1], parts[2]].join('.'))
|
|
let apiSignature = encode(hmac.digest())
|
|
|
|
if (apiSignature !== parts[3]) {
|
|
throw new HttpError(401, 'Authentication token invalid signature')
|
|
}
|
|
|
|
let header
|
|
let body
|
|
try {
|
|
header = JSON.parse(decode(parts[0]).toString('utf8'))
|
|
body = JSON.parse(decode(parts[1]).toString('utf8'))
|
|
} catch (err) {
|
|
throw new HttpError(401, 'Authentication token invalid json')
|
|
}
|
|
|
|
if (header.alg !== 'HS256') {
|
|
throw new HttpError(401, 'Authentication token invalid alg')
|
|
}
|
|
|
|
let unixNow = Math.floor(Date.now() / 1000)
|
|
|
|
// Validate token, add a little skew support for issued_at
|
|
if (body.iss !== issuer || !body.iat || !body.exp
|
|
|| body.iat > unixNow + 300 || body.exp <= unixNow) {
|
|
throw new HttpError(403, 'Authentication token expired or invalid')
|
|
}
|
|
|
|
if (body.rank < minLevel) {
|
|
throw new HttpError(401, 'User does not have access to this resource')
|
|
}
|
|
|
|
return body
|
|
}
|
|
|
|
export function authenticate(minLevel = RankLevels.Manager) {
|
|
return function(ctx) {
|
|
if (!ctx.req.headers.authorization) {
|
|
throw new HttpError(401, 'Authentication token missing')
|
|
}
|
|
if (!ctx.req.headers.authorization.startsWith('Bearer ')) {
|
|
throw new HttpError(401, 'Authentication token invalid')
|
|
}
|
|
|
|
let parts = ctx.req.headers.authorization.slice(7).split('.')
|
|
|
|
ctx.state.auth_user = verifyValidToken(parts, minLevel)
|
|
ctx.state.auth_token = [parts[0], parts[1], parts[2]].join('.')
|
|
}
|
|
}
|