rittenhop-ghost/versions/5.94.2/node_modules/cookie-session/index.js

291 lines
5.4 KiB
JavaScript

/*!
* cookie-session
* Copyright(c) 2013 Jonathan Ong
* Copyright(c) 2014-2017 Douglas Christopher Wilson
* MIT Licensed
*/
'use strict'
/**
* Module dependencies.
* @private
*/
var Buffer = require('safe-buffer').Buffer
var debug = require('debug')('cookie-session')
var Cookies = require('cookies')
var onHeaders = require('on-headers')
/**
* Module exports.
* @public
*/
module.exports = cookieSession
/**
* Create a new cookie session middleware.
*
* @param {object} [options]
* @param {boolean} [options.httpOnly=true]
* @param {array} [options.keys]
* @param {string} [options.name=session] Name of the cookie to use
* @param {boolean} [options.overwrite=true]
* @param {string} [options.secret]
* @param {boolean} [options.signed=true]
* @return {function} middleware
* @public
*/
function cookieSession (options) {
var opts = options || {}
// cookie name
var name = opts.name || 'session'
// secrets
var keys = opts.keys
if (!keys && opts.secret) keys = [opts.secret]
// defaults
if (opts.overwrite == null) opts.overwrite = true
if (opts.httpOnly == null) opts.httpOnly = true
if (opts.signed == null) opts.signed = true
if (!keys && opts.signed) throw new Error('.keys required.')
debug('session options %j', opts)
return function _cookieSession (req, res, next) {
var cookies = new Cookies(req, res, {
keys: keys
})
var sess
// for overriding
req.sessionOptions = Object.create(opts)
// define req.session getter / setter
Object.defineProperty(req, 'session', {
configurable: true,
enumerable: true,
get: getSession,
set: setSession
})
function getSession () {
// already retrieved
if (sess) {
return sess
}
// unset
if (sess === false) {
return null
}
// get session
if ((sess = tryGetSession(cookies, name, req.sessionOptions))) {
return sess
}
// create session
debug('new session')
return (sess = Session.create())
}
function setSession (val) {
if (val == null) {
// unset session
sess = false
return val
}
if (typeof val === 'object') {
// create a new session
sess = Session.create(val)
return sess
}
throw new Error('req.session can only be set as null or an object.')
}
onHeaders(res, function setHeaders () {
if (sess === undefined) {
// not accessed
return
}
try {
if (sess === false) {
// remove
debug('remove %s', name)
cookies.set(name, '', req.sessionOptions)
} else if ((!sess.isNew || sess.isPopulated) && sess.isChanged) {
// save populated or non-new changed session
debug('save %s', name)
cookies.set(name, Session.serialize(sess), req.sessionOptions)
}
} catch (e) {
debug('error saving session %s', e.message)
}
})
next()
}
};
/**
* Session model.
*
* @param {Context} ctx
* @param {Object} obj
* @private
*/
function Session (ctx, obj) {
Object.defineProperty(this, '_ctx', {
value: ctx
})
if (obj) {
for (var key in obj) {
if (!(key in this)) {
this[key] = obj[key]
}
}
}
}
/**
* Create new session.
* @private
*/
Session.create = function create (obj) {
var ctx = new SessionContext()
return new Session(ctx, obj)
}
/**
* Create session from serialized form.
* @private
*/
Session.deserialize = function deserialize (str) {
var ctx = new SessionContext()
var obj = decode(str)
ctx._new = false
ctx._val = str
return new Session(ctx, obj)
}
/**
* Serialize a session to a string.
* @private
*/
Session.serialize = function serialize (sess) {
return encode(sess)
}
/**
* Return if the session is changed for this request.
*
* @return {Boolean}
* @public
*/
Object.defineProperty(Session.prototype, 'isChanged', {
get: function getIsChanged () {
return this._ctx._new || this._ctx._val !== Session.serialize(this)
}
})
/**
* Return if the session is new for this request.
*
* @return {Boolean}
* @public
*/
Object.defineProperty(Session.prototype, 'isNew', {
get: function getIsNew () {
return this._ctx._new
}
})
/**
* populated flag, which is just a boolean alias of .length.
*
* @return {Boolean}
* @public
*/
Object.defineProperty(Session.prototype, 'isPopulated', {
get: function getIsPopulated () {
return Object.keys(this).length > 0
}
})
/**
* Session context to store metadata.
*
* @private
*/
function SessionContext () {
this._new = true
this._val = undefined
}
/**
* Decode the base64 cookie value to an object.
*
* @param {String} string
* @return {Object}
* @private
*/
function decode (string) {
var body = Buffer.from(string, 'base64').toString('utf8')
return JSON.parse(body)
}
/**
* Encode an object into a base64-encoded JSON string.
*
* @param {Object} body
* @return {String}
* @private
*/
function encode (body) {
var str = JSON.stringify(body)
return Buffer.from(str).toString('base64')
}
/**
* Try getting a session from a cookie.
* @private
*/
function tryGetSession (cookies, name, opts) {
var str = cookies.get(name, opts)
if (!str) {
return undefined
}
debug('parse %s', str)
try {
return Session.deserialize(str)
} catch (err) {
return undefined
}
}