UNPKG

http-auth

Version:

Node.js package for HTTP basic and digest access authentication.

118 lines (97 loc) 2.94 kB
"use strict"; // Base class. const Base = require("./base"); // Utility module. const utils = require("./utils"); // Importing apache-md5 module. const md5 = require("apache-md5"); // Importing apache-crypt module. const crypt = require("apache-crypt"); // Bcrypt. const bcrypt = require("bcryptjs"); // Crypto. const crypto = require("crypto"); // Reuse. const basicSchemeRegExp = /^basic\s/i; // Define basic auth. class Basic extends Base { // Constructor. constructor(options, checker) { super(options, checker); } // Verifies if password is correct. validate(hash, password) { if (hash.substr(0, 5) === "{SHA}") { hash = hash.substr(5); return hash === utils.sha1(password); } else if (hash.substr(0, 6) === "$apr1$" || hash.substr(0, 3) === "$1$") { return hash === md5(password, hash); } else if (hash.substr(0, 4) === "$2y$" || hash.substr(0, 4) === "$2a$") { return bcrypt.compareSync(password, hash); } else if (hash === crypt(password, hash)) { return true; } else if (hash.length === password.length) { return crypto.timingSafeEqual ? crypto.timingSafeEqual(Buffer.from(hash), Buffer.from(password)) : hash === password; } } // Processes line from authentication file. processLine(userLine) { let lineSplit = userLine.split(":"); let username = lineSplit.shift(); let hash = lineSplit.join(":"); // Push user. this.options.users.push({ username: username, hash: hash }); } // Generates request header. generateHeader() { return `Basic realm="${this.options.realm}"`; } // Parsing authorization header. parseAuthorization(header) { if (basicSchemeRegExp.test(header)) { let tokens = header.split(" "); return tokens[1]; } } // Searching for user. findUser(req, hash, callback) { // Decode base64. let splitHash = utils.decodeBase64(hash).split(":"); let username = splitHash.shift(); let password = splitHash.join(":"); if (this.checker) { // Custom auth. this.checker.apply(this, [ username, password, (result, customUser) => { let params = undefined; if (result instanceof Error) { params = [result]; } else { params = [{ user: customUser || username, pass: !!result }]; } callback.apply(this, params); }, req ]); } else { // File based auth. let pass = false; // Loop users to find the matching one. this.options.users.forEach(user => { if (user.username === username && this.validate(user.hash, password)) { pass = true; } }); // Call final callback. callback.apply(this, [{ user: username, pass: pass }]); } } } // Export basic auth. module.exports = (options, checker) => { return new Basic(options, checker); };