authenticator
This commit is contained in:
parent
52bd21434b
commit
dcec17599a
123
src/server/middleware/Authenticator.js
Normal file
123
src/server/middleware/Authenticator.js
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
const { AbstractUserDatabase } = require('../interfaces');
|
||||||
|
const { Util } = require('../../util');
|
||||||
|
|
||||||
|
const session = require('express-session');
|
||||||
|
const MongoStore = require('connect-mongo');
|
||||||
|
const Strategy = require('@navy.gif/passport-discord');
|
||||||
|
const Passport = require('passport');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes care of sessions and authentication
|
||||||
|
*
|
||||||
|
* @class Authenticator
|
||||||
|
*/
|
||||||
|
class Authenticator {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of Authenticator.
|
||||||
|
* @param {Object} express
|
||||||
|
* @param {AbstractUserDatabase} users
|
||||||
|
* @param {Object} sessionOptions {
|
||||||
|
* mongo,
|
||||||
|
* cookie: {
|
||||||
|
* maxAge = 0.5 * 24 * 60 * 60 * 1000,
|
||||||
|
* secure = false
|
||||||
|
* },
|
||||||
|
* secret
|
||||||
|
* }
|
||||||
|
* @memberof Authenticator
|
||||||
|
*/
|
||||||
|
constructor (server, express, users, {
|
||||||
|
mongo, secret, discordID, discordSecret, callbackURL, discordScope, discordVersion,
|
||||||
|
cookie = { }
|
||||||
|
}) {
|
||||||
|
|
||||||
|
if (!(users instanceof AbstractUserDatabase)) Util.fatal(new Error(`Expecting user database to be an instance inheriting AbstractUserDatabase`));
|
||||||
|
this.userdb = users;
|
||||||
|
|
||||||
|
if (!mongo) Util.fatal(new Error('Missing mongo client for '));
|
||||||
|
|
||||||
|
this.logger = server.createLogger(this);
|
||||||
|
|
||||||
|
cookie = { maxAge: 0.5 * 24 * 60 * 60 * 1000, secure: false, ...cookie };
|
||||||
|
cookie.secure = cookie.secure && process.env.NODE_ENV !== 'development';
|
||||||
|
express.use(session({
|
||||||
|
cookie,
|
||||||
|
store: MongoStore.create({ client: mongo, dbName: 'sessions' }),
|
||||||
|
secret,
|
||||||
|
resave: false,
|
||||||
|
saveUninitialized: false
|
||||||
|
}));
|
||||||
|
|
||||||
|
express.use(Passport.initialize());
|
||||||
|
express.use(Passport.session());
|
||||||
|
|
||||||
|
Passport.serializeUser((user, callback) => {
|
||||||
|
callback(null, user.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
Passport.deserializeUser(async (id, callback) => {
|
||||||
|
const user = await this.userdb.fetchUser(id);
|
||||||
|
callback(null, user);
|
||||||
|
});
|
||||||
|
|
||||||
|
Passport.use(new Strategy({
|
||||||
|
clientID: discordID, clientSecret: discordSecret, callbackURL, scope: discordScope, version: discordVersion
|
||||||
|
}, async (accessToken, refreshToken, profile, callback) => {
|
||||||
|
this.logger.info(`${profile.username} (${profile.id}) is logging in.`);
|
||||||
|
const user = await this.userdb.userFromDiscord(profile);
|
||||||
|
callback(null, user);
|
||||||
|
}));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async authenticate (req, res, next) {
|
||||||
|
|
||||||
|
if (this._authenticate(req, res)) return next();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async _authenticate (req, res) {
|
||||||
|
|
||||||
|
if (req.isAuthenticated()) return true;
|
||||||
|
|
||||||
|
// Sometimes the authorisation key automatically has a token type prepended to the header value,
|
||||||
|
// we don't care about that, we just want the key, which will always be the last element
|
||||||
|
const authHeader = req.get('Authorization') || req.get('Authorisation');
|
||||||
|
const segments = authHeader.split(' ');
|
||||||
|
const key = segments[segments.length - 1];
|
||||||
|
|
||||||
|
const user = await this.userdb.matchToken(key);
|
||||||
|
if (user) req.user = user;
|
||||||
|
else {
|
||||||
|
res.status(401).send('Unknown identity');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authorisation implicitly checks for authentication
|
||||||
|
*
|
||||||
|
* @param {*} permission
|
||||||
|
* @return {*}
|
||||||
|
* @memberof Authenticator
|
||||||
|
*/
|
||||||
|
createAuthoriser (permission) {
|
||||||
|
|
||||||
|
const func = (req, res, next) => {
|
||||||
|
const { user } = req;
|
||||||
|
if (!this._authenticate(req, res)) return;
|
||||||
|
if (user.hasPermission(permission)) return next();
|
||||||
|
return res.status(403).send('Access denied');
|
||||||
|
};
|
||||||
|
|
||||||
|
return func;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Authenticator;
|
3
src/server/middleware/index.js
Normal file
3
src/server/middleware/index.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
module.exports = {
|
||||||
|
Authenticator: require('./Authenticator')
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user