107 lines
2.9 KiB
JavaScript
107 lines
2.9 KiB
JavaScript
|
|
var crypto = require('crypto')
|
|
var cookie = require('cookie')
|
|
var signature = require('cookie-signature')
|
|
|
|
|
|
module.exports = ({name, secret, cookie:options, store}) => {
|
|
name = name || 'grant'
|
|
options = options || {path: '/', httpOnly: true, secure: false, maxAge: null}
|
|
|
|
if (!secret) {
|
|
throw new Error('Grant: cookie secret is required')
|
|
}
|
|
|
|
var embed = !store
|
|
|
|
return (req) => {
|
|
var headers = Object.keys(req.headers)
|
|
.filter((key) => /(?:set-)?cookie/i.test(key))
|
|
.reduce((all, key) => (all[key.toLowerCase()] = req.headers[key], all), {})
|
|
|
|
headers['set-cookie'] =
|
|
headers['set-cookie'] ||
|
|
(req.multiValueHeaders && req.multiValueHeaders['Set-Cookie']) ||
|
|
[]
|
|
|
|
var cookies = {
|
|
input:
|
|
// vercel - parsed object
|
|
typeof req.cookies === 'object' && !(req.cookies instanceof Array) ? req.cookies :
|
|
cookie.parse(
|
|
headers.cookie ? headers.cookie :
|
|
// aws v2 event - array of key=value pairs
|
|
req.cookies ? req.cookies.join('; ') :
|
|
''
|
|
),
|
|
output: headers['set-cookie'].reduce((all, str) =>
|
|
(all[str.split(';')[0].split('=')[0]] = str, all), {})
|
|
}
|
|
|
|
var encode = (payload, opt = {}) => {
|
|
var data = embed
|
|
? Buffer.from(JSON.stringify(payload)).toString('base64')
|
|
: payload
|
|
var value = signature.sign(data, secret)
|
|
var output = cookie.serialize(name, value, {...options, ...opt})
|
|
cookies.output[name] = output
|
|
headers['set-cookie'] = Object.keys(cookies.output)
|
|
.map((name) => cookies.output[name])
|
|
}
|
|
|
|
var cookieStore = () => {
|
|
var session = (() => {
|
|
var payload = signature.unsign(cookies.input[name] || '', secret)
|
|
try {
|
|
return JSON.parse(Buffer.from(payload, 'base64').toString())
|
|
}
|
|
catch (err) {
|
|
return {grant: {}}
|
|
}
|
|
})()
|
|
var store = {
|
|
get: async (sid) => session,
|
|
set: async (sid, value) => session = value,
|
|
remove: async (sid) => session = {}
|
|
}
|
|
return {
|
|
get: async () => {
|
|
return store.get()
|
|
},
|
|
set: async (value) => {
|
|
encode(value)
|
|
return store.set(null, value)
|
|
},
|
|
remove: async () => {
|
|
encode('', {maxAge: 0})
|
|
await store.remove()
|
|
},
|
|
cookies,
|
|
headers,
|
|
}
|
|
}
|
|
|
|
var sessionStore = () => {
|
|
var sid = signature.unsign(cookies.input[name] || '', secret)
|
|
|| crypto.randomBytes(20).toString('hex')
|
|
return {
|
|
get: async () => {
|
|
return await store.get(sid) || {grant: {}}
|
|
},
|
|
set: async (value) => {
|
|
encode(sid)
|
|
return store.set(sid, value)
|
|
},
|
|
remove: async () => {
|
|
encode(sid, {maxAge: 0})
|
|
await store.remove(sid)
|
|
},
|
|
cookies,
|
|
headers,
|
|
}
|
|
}
|
|
|
|
return embed ? cookieStore() : sessionStore()
|
|
}
|
|
}
|