diff --git a/README.md b/README.md index 813ab97..1f45848 100644 --- a/README.md +++ b/README.md @@ -19,12 +19,18 @@ It just needs to sit there with no more action required. declare global { namespace Express { interface Request { + // fetch user info (needs AuthProxy and some headers) getUserInfo(): Promise; - noLogging: boolean|undefined; - permissionDetails?: import('role-acl').Permission; + // fetch user info (needed for HttpLogger) + noHttpLogging: boolean|undefined; + // permission details (after a Permission route) + permissionDetails: import('role-acl').Permission; + // switch session to another user;does not close old session (after Session router) + setSessionById(sessionId: string): Promise; } interface Response { + // initialize a logout (needs AuthProxy and some headers) initLogout(): boolean; } } diff --git a/out/auto-reload.js b/out/auto-reload.js index 1fdbfc9..d51d8fa 100644 --- a/out/auto-reload.js +++ b/out/auto-reload.js @@ -52,7 +52,7 @@ if (!_1.DefaultConfig.isProduction) { `.replace(/\t/g, "")); }); router.get("/auto-reload", (req, res) => { - req.noLogging = true; + req.noHttpLogging = true; res.json({ uuid }); }); } diff --git a/out/config.js b/out/config.js index da27833..94d6137 100644 --- a/out/config.js +++ b/out/config.js @@ -23,9 +23,9 @@ const envs = { USERINFO_HEADER: env.get('USERINFO_HEADER').default("X-Userinfo-Token").asString(), // base url to init a logout or request user info AUTH_PROXY_URL: env.get('AUTH_PROXY_URL').asString() || undefined, - // override base url to request user info + // override AUTH_PROXY_URL to request user info AUTH_PROXY_USERINFO_URL: env.get('AUTH_PROXY_USERINFO_URL').asString() || undefined, - // override base url to init a logout + // override AUTH_PROXY_URL to init a logout AUTH_PROXY_INIT_LOGOUT_URL: env.get('AUTH_PROXY_INIT_LOGOUT_URL').asString() || undefined, }; function requireEnv(name, onlyInProduction = false) { diff --git a/out/logging.js b/out/logging.js index edd98dc..9079cb3 100644 --- a/out/logging.js +++ b/out/logging.js @@ -39,7 +39,7 @@ exports.HttpLogger = (req, res, next) => { const status = colorFunction(res.statusCode.toString(10)); const method = req.method.toUpperCase().padEnd(6, " "); const responseTime = (Date.now() - start).toString(10).padStart(3, " "); - if (!req.noLogging) + if (!req.noHttpLogging) exports.Logger.http(`${status} ${method} ${responseTime}ms ${path}`); end.apply(res, args); }; diff --git a/out/session.js b/out/session.js index e7f5889..1094ae5 100644 --- a/out/session.js +++ b/out/session.js @@ -1,9 +1,20 @@ "use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; Object.defineProperty(exports, "__esModule", { value: true }); exports.Session = void 0; const session = require("express-session"); const _1 = require("."); const redisStore = require("connect-redis"); +const express_1 = require("express"); +const util_1 = require("util"); let sessionStore = undefined; function getRouter(options) { _1.DefaultConfig.requireEnv('SESSION_SECRET', true); @@ -11,7 +22,30 @@ function getRouter(options) { const RedisStore = redisStore(session); sessionStore = new RedisStore({ client: _1.Redis.client }); } - return session(Object.assign({ store: sessionStore, secret: _1.DefaultConfig.SESSION_SECRET || 'keyboard cat', resave: false, saveUninitialized: true, cookie: { secure: false } }, options)); + const router = express_1.Router(); + router.use(session(Object.assign({ store: sessionStore, secret: _1.DefaultConfig.SESSION_SECRET || 'keyboard cat', resave: false, saveUninitialized: true, cookie: { secure: false } }, options))); + router.use((req, res, next) => { + // throws if error occurred + req.setSessionById = (sessionId) => __awaiter(this, void 0, void 0, function* () { + const sessionStore = req.sessionStore; + if (sessionStore) { + const getSession = util_1.promisify(sessionStore.get); + const session = yield getSession(sessionId); + if (session) { + sessionStore.createSession(req, session); + return true; // success + } + else { + return false; // session id not found + } + } + else { + return false; // no session store present + } + }); + next(); + }); + return router; } exports.Session = { getRouter, diff --git a/src/auto-reload.ts b/src/auto-reload.ts index c3d014e..5ec6b12 100644 --- a/src/auto-reload.ts +++ b/src/auto-reload.ts @@ -52,7 +52,7 @@ if (!DefaultConfig.isProduction) { }); router.get("/auto-reload", (req, res) => { - req.noLogging = true; + req.noHttpLogging = true; res.json({uuid}); }); } diff --git a/src/config.ts b/src/config.ts index 9f903c8..0be75cc 100644 --- a/src/config.ts +++ b/src/config.ts @@ -24,9 +24,9 @@ const envs = { USERINFO_HEADER: env.get('USERINFO_HEADER').default("X-Userinfo-Token").asString(), // base url to init a logout or request user info AUTH_PROXY_URL: env.get('AUTH_PROXY_URL').asString() || undefined, - // override base url to request user info + // override AUTH_PROXY_URL to request user info AUTH_PROXY_USERINFO_URL: env.get('AUTH_PROXY_USERINFO_URL').asString() || undefined, - // override base url to init a logout + // override AUTH_PROXY_URL to init a logout AUTH_PROXY_INIT_LOGOUT_URL: env.get('AUTH_PROXY_INIT_LOGOUT_URL').asString() || undefined, }; diff --git a/src/logging.ts b/src/logging.ts index 8e5e059..953211f 100644 --- a/src/logging.ts +++ b/src/logging.ts @@ -47,7 +47,7 @@ export const HttpLogger: RequestHandler = (req, res, next) => { const status = colorFunction(res.statusCode.toString(10)); const method = req.method.toUpperCase().padEnd(6, " "); const responseTime = (Date.now()-start).toString(10).padStart(3, " "); - if (!req.noLogging) + if (!req.noHttpLogging) Logger.http(`${status} ${method} ${responseTime}ms ${path}`); end.apply(res, args); }; diff --git a/src/session.ts b/src/session.ts index 7e93aee..a4e075a 100644 --- a/src/session.ts +++ b/src/session.ts @@ -2,7 +2,8 @@ import * as session from 'express-session'; import {Store} from 'express-session'; import {DefaultConfig, Redis} from '.'; import * as redisStore from "connect-redis"; -import {RequestHandler} from 'express'; +import {RequestHandler, Router} from 'express'; +import {promisify} from "util"; let sessionStore: Store|undefined = undefined; @@ -13,14 +14,35 @@ function getRouter(options?: Partial): RequestHandler { const RedisStore = redisStore(session); sessionStore = new RedisStore({client: Redis.client}); } - return session({ + const router = Router(); + router.use(session({ store: sessionStore, secret: DefaultConfig.SESSION_SECRET || 'keyboard cat', resave: false, saveUninitialized: true, cookie: {secure: false}, ...options, + })); + router.use((req, res, next) => { + // throws if error occurred + req.setSessionById = async sessionId => { + const sessionStore = (req as { sessionStore?: session.Store }).sessionStore; + if (sessionStore) { + const getSession = promisify(sessionStore.get); + const session = await getSession(sessionId); + if (session) { + sessionStore.createSession(req, session); + return true; // success + } else { + return false; // session id not found + } + } else { + return false; // no session store present + } + }; + next(); }); + return router; } export const Session = { diff --git a/src/types/extend-request.d.ts b/src/types/extend-request.d.ts index 0111bd5..4ee3c47 100644 --- a/src/types/extend-request.d.ts +++ b/src/types/extend-request.d.ts @@ -3,12 +3,18 @@ declare global { namespace Express { interface Request { + // fetch user info (needs AuthProxy and some headers) getUserInfo(): Promise; - noLogging: boolean|undefined; - permissionDetails?: import('role-acl').Permission; + // fetch user info (needed for HttpLogger) + noHttpLogging: boolean|undefined; + // permission details (after a Permission route) + permissionDetails: import('role-acl').Permission; + // switch session to another user;does not close old session (after Session router) + setSessionById(sessionId: string): Promise; } interface Response { + // initialize a logout (needs AuthProxy and some headers) initLogout(): boolean; } }