'use strict'; //////////////////////////////////////////////////////////////////////////////// /// DISCLAIMER /// /// Copyright 2015-2016 ArangoDB GmbH, Cologne, Germany /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. /// You may obtain a copy of the License at /// /// http://www.apache.org/licenses/LICENSE-2.0 /// /// Unless required by applicable law or agreed to in writing, software /// distributed under the License is distributed on an "AS IS" BASIS, /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. /// See the License for the specific language governing permissions and /// limitations under the License. /// /// Copyright holder is ArangoDB GmbH, Cologne, Germany /// /// @author Alan Plum //////////////////////////////////////////////////////////////////////////////// const assert = require('assert'); const il = require('@arangodb/util').inline; const cookieTransport = require('@arangodb/foxx/sessions/transports/cookie'); const headerTransport = require('@arangodb/foxx/sessions/transports/header'); const collectionStorage = require('@arangodb/foxx/sessions/storages/collection'); module.exports = function sessionMiddleware(cfg) { if (!cfg) { cfg = {}; } let storage = cfg.storage; if (cfg.storages) { console.warn(il` Found unexpected "storages" option in session middleware. Did you mean "storage"? `); } assert(storage, 'No session storage specified'); if (typeof storage === 'string' || storage.isArangoCollection) { storage = collectionStorage(storage); } else if (typeof storage === 'function') { storage = storage(); } if (storage.toClient) { console.warn(il` Found unexpected "toClient" method on session storage. Did you mean "forClient"? `); } assert( storage.forClient && storage.fromClient, 'Session storage must have a forClient and fromClient method' ); if (cfg.transports) { console.warn(il` Found unexpected "transports" option in session middleware. Did you mean "transport"? `); } let transports = cfg.transport || []; if (!Array.isArray(transports)) { transports = [transports]; } transports = transports.map((transport) => { if (transport === 'cookie') { return cookieTransport(); } if (transport === 'header') { return headerTransport(); } if (typeof transport === 'function') { transport = transport(); } assert( transport.get || transport.set, 'Session transport must have a get and/or set method' ); return transport; }); assert(transports.length > 0, 'Must specify at least one session transport'); const autoCreate = cfg.autoCreate !== false; return { config: {storage, transport: transports}, register() { return (req, res, next) => { let sid = null; for (const transport of transports) { if (typeof transport.get === 'function') { sid = transport.get(req) || null; } if (sid) { break; } } let payload = sid && storage.fromClient(sid); if (!payload) { if (!autoCreate) { payload = null; } else if (typeof storage.new === 'function') { payload = storage.new(); } else { payload = {}; } } req.session = payload; next(); if (req.session) { sid = storage.forClient(req.session); for (const transport of transports.reverse()) { if (typeof transport.set === 'function') { transport.set(res, sid); } } } else if (payload) { for (const transport of transports.reverse()) { if (typeof transport.clear === 'function') { transport.clear(req); } } } }; } }; };