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;