mirror of
https://gitlab.com/wgp/dougal/software.git
synced 2025-12-06 10:17:07 +00:00
114 lines
2.8 KiB
JavaScript
114 lines
2.8 KiB
JavaScript
const dns = require('dns');
|
|
const { Netmask } = require('netmask');
|
|
const cfg = require('../../../lib/config');
|
|
const jwt = require('../../../lib/jwt');
|
|
const user = require('../../../lib/db/user');
|
|
const ServerUser = require('../../../lib/db/user/User');
|
|
|
|
async function authorisedIP (req, res) {
|
|
const validIPs = await user.ip({active: true}); // Get all active IP logins
|
|
validIPs.forEach( i => i.$block = new Netmask(i.ip) );
|
|
validIPs.sort( (a, b) => b.$block.bitmask - a.$block.netmask ); // More specific IPs have precedence
|
|
for (const ip of validIPs) {
|
|
const block = ip.$block;
|
|
if (block.contains(req.ip)) {
|
|
const payload = {
|
|
...ip,
|
|
ip: req.ip,
|
|
autologin: true
|
|
};
|
|
delete payload.$block;
|
|
delete payload.hash;
|
|
delete payload.active;
|
|
jwt.issue(payload, req, res);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
async function authorisedHost (req, res) {
|
|
const validHosts = await user.host({active: true}); // Get all active host logins
|
|
for (const key in validHosts) {
|
|
try {
|
|
const ip = await dns.promises.resolve(key);
|
|
if (ip == req.ip) {
|
|
const payload = {
|
|
...validHosts[key],
|
|
ip: req.ip,
|
|
autologin: true
|
|
};
|
|
delete payload.$block;
|
|
delete payload.hash;
|
|
delete payload.active;
|
|
jwt.issue(payload, req, res);
|
|
return true;
|
|
}
|
|
} catch (err) {
|
|
if (err.code != "ENODATA") {
|
|
console.error(err);
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// TODO: Check client TLS certificates
|
|
// Probably will do this via Nginx with
|
|
// ssl_verify_client optional;
|
|
// and then putting either of the
|
|
// $ssl_client_s_dn or $ssl_client_escaped_cert
|
|
// variables into an HTTP header for Node
|
|
// to check (naturally, it must be ensured
|
|
// that a user cannot just insert the header
|
|
// in a request).
|
|
|
|
|
|
async function auth (req, res, next) {
|
|
|
|
if (res.headersSent) {
|
|
// Nothing to do, this request must have been
|
|
// handled already by another middleware.
|
|
return;
|
|
}
|
|
|
|
// Check for a valid JWT (already decoded by a previous
|
|
// middleware).
|
|
if (req.user) {
|
|
if (!req.user.autologin) {
|
|
// If this is not an automatic login, check if the token is in the
|
|
// second half of its lifetime. If so, reissue a new one, valid for
|
|
// another cfg.jwt.options.expiresIn seconds.
|
|
if (req.user.exp) {
|
|
const ttl = req.user.exp - Date.now()/1000;
|
|
if (ttl < cfg.jwt.options.expiresIn/2) {
|
|
const credentials = await ServerUser.fromSQL(null, req.user.id);
|
|
if (credentials) {
|
|
// Refresh token
|
|
payload = Object.assign({}, credentials.toJSON());
|
|
jwt.issue(Object.assign({}, credentials.toJSON()), req, res);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
next();
|
|
return;
|
|
}
|
|
|
|
// Check if the IP is known to us
|
|
if (await authorisedIP(req, res)) {
|
|
next();
|
|
return;
|
|
}
|
|
|
|
// Check if the hostname is known to us
|
|
if (await authorisedHost(req, res)) {
|
|
next();
|
|
return;
|
|
}
|
|
|
|
next({status: 401, message: "Not authorised"});
|
|
}
|
|
|
|
module.exports = auth;
|