mirror of
https://github.com/Foltik/Shimapan
synced 2024-11-15 01:06:32 -05:00
87 lines
2.8 KiB
JavaScript
87 lines
2.8 KiB
JavaScript
const fs = require('fs').promises;
|
|
const config = require('config');
|
|
|
|
const ModelPath = '../models/';
|
|
const Key = require(ModelPath + 'Key.js');
|
|
const User = require(ModelPath + 'User.js');
|
|
|
|
const wrap = require('./wrap.js');
|
|
const verifyScope = require('./verifyScope.js');
|
|
const rateLimit = require('express-rate-limit');
|
|
|
|
const checkSession = (req, scope, status) => {
|
|
if (req.isAuthenticated()) {
|
|
status.authenticated = true;
|
|
if (!scope || verifyScope(req.session.passport.scope, scope)) {
|
|
req.username = req.session.passport.user;
|
|
req.displayname = req.session.passport.displayname;
|
|
req.scope = req.session.passport.scope;
|
|
req.key = null;
|
|
status.permission = true;
|
|
}
|
|
}
|
|
};
|
|
|
|
const checkKey = async (req, scope, status) => {
|
|
if (req.body.key) {
|
|
const key = await Key.findOne({key: req.body.key});
|
|
if (key) {
|
|
status.authenticated = true;
|
|
if (!scope || verifyScope(key.scope, scope)) {
|
|
req.username = key.issuer;
|
|
req.displayname = key.issuer;
|
|
req.scope = key.scope;
|
|
req.key = key.key;
|
|
status.permission = true;
|
|
}
|
|
} else {
|
|
// Log failure
|
|
await fs.appendFile('auth.log', `${new Date().toISOString()} key ${req.ip}\n`);
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
const apiLimiter = config.get('RateLimit.enable')
|
|
? rateLimit({
|
|
windowMs: config.get('RateLimit.api.window') * 1000,
|
|
max: config.get('RateLimit.api.max'),
|
|
skip: (req, res) => res.statusCode !== 401 && res.statusCode !== 403
|
|
})
|
|
: (req, res, next) => { next(); };
|
|
// Middleware that checks for authentication by either API key or session
|
|
// sets req.username, req.displayname, req.scope, and req.key if authenticated properly,
|
|
// otherwise throws an error code.
|
|
// If the user is banned, also throw an error.
|
|
const requireAuth = scope => (req, res, next) => {
|
|
apiLimiter(req, res, wrap(async () => {
|
|
|
|
const status = {
|
|
authenticated: false,
|
|
permission: false
|
|
};
|
|
|
|
// First, check the session
|
|
checkSession(req, scope, status);
|
|
// If not authenticated yet, check for a key
|
|
if (!status.authenticated)
|
|
await checkKey(req, scope, status);
|
|
|
|
if (!status.authenticated)
|
|
return res.status(401).json({message: 'Unauthorized.'});
|
|
else if (!status.permission)
|
|
return res.status(403).json({message: 'Forbidden.'});
|
|
|
|
// Check if the user is banned
|
|
const user = await User.findOne({username: req.username});
|
|
if (user && user.banned)
|
|
return res.status(403).json({message: 'Forbidden.'});
|
|
|
|
next();
|
|
}));
|
|
};
|
|
|
|
module.exports.checkSession = checkSession;
|
|
module.exports.checkKey = checkKey;
|
|
module.exports.requireAuth = requireAuth;
|