UNPKG

bot18

Version:

A high-frequency cryptocurrency trading bot by Zenbot creator @carlos8f

153 lines (139 loc) 5 kB
var cookie = require('cookie') , sosa_mem = require('sosa_mem') , idgen = require('idgen') , sig = require('sig') , href = require('href') function PlainObject() {} PlainObject.prototype = Object.create(null); function shallowCopy (obj) { var ret = new PlainObject(); Object.keys(obj || {}).forEach(function (k) { ret[k] = obj[k]; }); return ret; } function deepCopy (obj) { return JSON.parse(JSON.stringify(obj)) } module.exports = function (_opts) { _opts || (_opts = {}); var coll = _opts.sessions || sosa_mem({prefix: _opts.key || 'sosa_session'})('sessions', _opts); var options = shallowCopy(_opts); options.cookie = shallowCopy(_opts.cookie || {}); if (typeof options.cookie.httpOnly === 'undefined') options.cookie.httpOnly = true; options.cookie.name || (options.cookie.name = options.key || 'sosa_session'); options.cookie.path || (options.cookie.path = '/'); return function sosa_session (req, res, next) { href(req, res, function (err) { if (err) return next(err); var touch = false, hash; if (!req.headers['cookie']) return create(); var cookies = cookie.parse(req.headers['cookie']); if (!cookies || !cookies[options.cookie.name]) return create(); // attempt to load based on cookie's id coll.load(cookies[options.cookie.name], function (err, session) { if (err) return next(err); if (!session) return create(); set(session); doNext(); }); function create () { generate(); doNext(); } function generate (id) { var session = {id: id, rev: 0}; if (!id) session.id = idgen(32); set(session); } function set (session) { req.session = session; req.sessionID = req.session.id; hash = sig(req.session); // expose some stuff on session, also some connect compatibility req.session.__proto__ = { req: req, res: res, save: function (cb) { // check signature for changes if ((!options.cookie.secure || req.href.protocol === 'https:') && sig(req.session) !== hash) { req.session.rev++; coll.save(deepCopy(req.session), options.save, function (err) { // if another request saved the session first, defer if (err && err.code === 'REV_CONFLICT') return cb && cb(); if (err && !cb) return res.emit('error', err); cb && cb(err); }); } // no changes, just return else cb && cb(); return this; }, destroy: function (cb) { coll.destroy(req.session.id, function (err) { if (err && !cb) return res.emit('error', err); if (!err) { delete req.session; delete req.sessionID; } cb && cb(err); }); return this; }, touch: function () { // set-cookie again touch = true; return this; }, reload: function (cb) { coll.load(req.session.id, function (err, session) { if (err && !cb) return res.emit('error', err); if (!err) { if (session) set(session); // create an empty session with the same id else generate(req.session.id); } cb && cb(err); }); return this; }, regenerate: function (cb) { req.session.destroy(function (err) { if (err && !cb) return res.emit('error', err); if (!err) generate(); cb && cb(err); }); return this; } }; } function doNext () { // proxy res.writeHead() to set cookie var _writeHead = res.writeHead; res.writeHead = function () { res.writeHead = _writeHead; // session was just saved for the first time? // account for writeHead() called before end() if (req.session && ((sig(req.session) !== hash && req.session.rev < 2) || touch || options.cookie.alwaysSet)) { if (!options.cookie.secure || req.href.protocol === 'https:') { res.setHeader('Set-Cookie', cookie.serialize(options.cookie.name, req.session.id, options.cookie)); } } res.writeHead.apply(res, [].slice.call(arguments)); }; // proxy res.end() to save session var _end = res.end; res.end = function () { res.end = _end; var args = [].slice.call(arguments); if (!req.session) return res.end.apply(res, args); req.session.save(function (err) { if (err) return res.emit('error', err); res.end.apply(res, args); }); }; next(); } }); }; };