rolling session
This commit is contained in:
parent
68512ec871
commit
16016071a4
@ -17,7 +17,7 @@ import { MiddlewareFunction, Request, Response } from "../../../@types/Server.js
|
||||
import { NextFunction } from "express";
|
||||
import { User } from "../structures/index.js";
|
||||
|
||||
const OAuthLinks: {[key: string]: string} = {};
|
||||
const OAuthLinks: { [key: string]: string } = {};
|
||||
|
||||
type Cookie = {
|
||||
secure?: boolean,
|
||||
@ -45,7 +45,7 @@ class Authenticator {
|
||||
|
||||
#passport: passport.Authenticator;
|
||||
#logger: LoggerClient;
|
||||
#OAuthParams: {[key: string]: OAuthParams | null};
|
||||
#OAuthParams: { [key: string]: OAuthParams | null };
|
||||
|
||||
/**
|
||||
* Creates an instance of Authenticator.
|
||||
@ -64,19 +64,31 @@ class Authenticator {
|
||||
constructor (
|
||||
server: Server,
|
||||
users: UserDatabaseInterface,
|
||||
{ sessionStorage, secret, name, cookie = {} }: { sessionStorage: MongoStore, secret: string, name: string, cookie: Cookie }
|
||||
{
|
||||
rollingSession = true,
|
||||
sessionStorage,
|
||||
secret,
|
||||
name,
|
||||
cookie = {}
|
||||
}: {
|
||||
sessionStorage: MongoStore,
|
||||
rollingSession?: boolean,
|
||||
secret: string,
|
||||
name: string,
|
||||
cookie: Cookie
|
||||
}
|
||||
) {
|
||||
|
||||
|
||||
// if (!(users instanceof UserDatabaseInterface))
|
||||
// Util.fatal(new Error(`Expecting user database to be an instance inheriting UserDatabaseInterface`));
|
||||
this.#_userdb = users;
|
||||
|
||||
if (!sessionStorage)
|
||||
if (!sessionStorage)
|
||||
Util.fatal(new Error('Missing session storage'));
|
||||
|
||||
this.#logger = server.createLogger(this);
|
||||
this.#_cookieName = name;
|
||||
|
||||
|
||||
cookie = { maxAge: 0.5 * 24 * 60 * 60 * 1000, secure: false, ...cookie };
|
||||
cookie.secure = cookie.secure && process.env.NODE_ENV !== 'development';
|
||||
server.app.use(session({
|
||||
@ -85,7 +97,8 @@ class Authenticator {
|
||||
store: sessionStorage,
|
||||
secret,
|
||||
resave: false,
|
||||
saveUninitialized: false
|
||||
saveUninitialized: false,
|
||||
rolling: rollingSession
|
||||
}));
|
||||
|
||||
this.#passport = passport;
|
||||
@ -107,8 +120,8 @@ class Authenticator {
|
||||
this.#OAuthParams = {};
|
||||
server.OAuthProviders.forEach(provider => {
|
||||
const providerName = provider.name.toLowerCase();
|
||||
OAuthLinks[providerName] = provider.authoriseURL;
|
||||
OAuthLinks[providerName +'Token'] = provider.tokenURL;
|
||||
OAuthLinks[providerName] = provider.authoriseURL;
|
||||
OAuthLinks[providerName + 'Token'] = provider.tokenURL;
|
||||
});
|
||||
|
||||
}
|
||||
@ -121,7 +134,7 @@ class Authenticator {
|
||||
* @param {object} [{ failureRedirect = '/api/login/fail', successRedirect = '/home' }={}]
|
||||
* @memberof Authenticator
|
||||
*/
|
||||
addStrategy (name: string, strategy: passport.Strategy, { failureRedirect = '/api/login/fail', successRedirect, authParams }: {failureRedirect?: string, successRedirect?: string, authParams?: OAuthParams } = {}) {
|
||||
addStrategy (name: string, strategy: passport.Strategy, { failureRedirect = '/api/login/fail', successRedirect, authParams }: { failureRedirect?: string, successRedirect?: string, authParams?: OAuthParams } = {}) {
|
||||
this.#logger.info(`Adding ${name} authentication strategy`);
|
||||
this.#passport.use(name, strategy);
|
||||
this.#OAuthParams[name] = authParams || null;
|
||||
@ -161,31 +174,31 @@ class Authenticator {
|
||||
|
||||
// For API requests, does not redirect to a login page
|
||||
async #_auth (req: Request, res: Response, next: NextFunction) {
|
||||
if (await this.#_authenticate(req, res))
|
||||
if (await this.#_authenticate(req, res))
|
||||
return next();
|
||||
}
|
||||
|
||||
// Meant for non-api paths
|
||||
#_authenticateRedirect (req: Request, res: Response, next: NextFunction) {
|
||||
// '/login' should point towards a login page, should probably make this configurable
|
||||
if (!req.isAuthenticated())
|
||||
if (!req.isAuthenticated())
|
||||
return res.redirect('/login');
|
||||
if (req.user.temporary)
|
||||
if (req.user.temporary)
|
||||
return res.redirect('/login/finalise');
|
||||
next();
|
||||
}
|
||||
|
||||
|
||||
// Check if request is authenticated, meant for API requests
|
||||
// Takes care of responding to unauthenticated requests
|
||||
async #_authenticate (req: Request, res: Response) {
|
||||
if (req.user) {
|
||||
if (req.user.temporary) {
|
||||
res.status(403).send('Temporary accounts must be finalised before proceeding');
|
||||
res.status(403).send('Temporary accounts must be finalised before proceeding');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else if (req.get('cookie')?.includes(this.#_cookieName)) {
|
||||
res.status(401).send('Invalid session');
|
||||
res.status(401).send('Invalid session');
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -202,16 +215,16 @@ class Authenticator {
|
||||
|
||||
const application = await this.#_userdb.matchToken(key);
|
||||
if (application) {
|
||||
req.user = application;
|
||||
req.user = application;
|
||||
} else {
|
||||
res.status(401).send('Unknown identity');
|
||||
res.status(401).send('Unknown identity');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Authorisation implicitly checks for authentication
|
||||
*
|
||||
@ -221,17 +234,17 @@ class Authenticator {
|
||||
* @memberof Authenticator
|
||||
*/
|
||||
createAuthoriser (permission: string, level = 1) {
|
||||
|
||||
|
||||
PermissionManager.ensurePermission(permission);
|
||||
|
||||
const func = async (req: Request, res: Response, next: NextFunction) => {
|
||||
// Request does not have a user bound to it, response already sent from #_authenticate
|
||||
if (!await this.#_authenticate(req, res))
|
||||
if (!await this.#_authenticate(req, res))
|
||||
return;
|
||||
// If the authentication is done through a token, the user will be attached in the authentication step
|
||||
const { user } = req;
|
||||
// Has permission
|
||||
if (user.hasPermission(permission, level))
|
||||
if (user.hasPermission(permission, level))
|
||||
return next();
|
||||
return res.status(403).send('Insufficient permissions');
|
||||
};
|
||||
@ -244,7 +257,7 @@ class Authenticator {
|
||||
service = service.toLowerCase();
|
||||
const link = OAuthLinks[service];
|
||||
const _params = this.#OAuthParams[service];
|
||||
if (!_params)
|
||||
if (!_params)
|
||||
return null;
|
||||
const params = {
|
||||
response_type: 'code',
|
||||
|
Loading…
Reference in New Issue
Block a user