http-auth
Version:
Node.js package for HTTP basic and digest access authentication.
118 lines (97 loc) • 2.94 kB
JavaScript
// 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);
};
;