http-auth
Version:
Node.js package for HTTP basic and digest access authentication.
167 lines (149 loc) • 5.2 kB
JavaScript
// Generated by CoffeeScript 1.8.0
(function() {
var Base, Digest, utils, uuid,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
Base = require('./base');
utils = require('./utils');
uuid = require('node-uuid');
Digest = (function(_super) {
__extends(Digest, _super);
function Digest(options, checker) {
this.options = options;
this.checker = checker;
Digest.__super__.constructor.call(this, this.options, this.checker);
this.nonces = [];
this.options.algorithm = this.options.algorithm === 'MD5-sess' ? 'MD5-sess' : 'MD5';
this.options.qop = this.options.qop === 'none' ? '' : 'auth';
}
Digest.prototype.processLine = function(line) {
var hash, realm, username, _ref;
_ref = line.split(":"), username = _ref[0], realm = _ref[1], hash = _ref[2];
if (realm === this.options.realm) {
return this.options.users.push({
username: username,
hash: hash
});
}
};
Digest.prototype.parseAuthorization = function(header) {
var i, len, opts, param, params, parts, tokens;
opts = {};
parts = header.split(' ');
params = parts.slice(1).join(' ');
tokens = params.split(/,(?=(?:[^"]|"[^"]*")*$)/);
if ((parts[0].substr(0, 6)) === "Digest") {
i = 0;
len = tokens.length;
while (i < len) {
param = /(\w+)=["]?([^"]*)["]?$/.exec(tokens[i]);
if (param) {
opts[param[1]] = param[2];
}
i++;
}
}
return opts;
};
Digest.prototype.validate = function(ha2, co, hash) {
var ha1, response;
ha1 = hash;
if (co.algorithm === 'MD5-sess') {
ha1 = utils.md5("" + ha1 + ":" + co.nonce + ":" + co.cnonce);
}
if (co.qop) {
response = utils.md5("" + ha1 + ":" + co.nonce + ":" + co.nc + ":" + co.cnonce + ":" + co.qop + ":" + ha2);
} else {
response = utils.md5("" + ha1 + ":" + co.nonce + ":" + ha2);
}
return response === co.response;
};
Digest.prototype.findUser = function(req, co, callback) {
var found, ha2, user, _i, _len, _ref;
if (this.validateNonce(co.nonce)) {
ha2 = utils.md5("" + req.method + ":" + co.uri);
if (this.checker) {
return this.checker.apply(this, [
co.username, (function(_this) {
return function(hash) {
return callback.apply(_this, [
{
user: _this.validate(ha2, co, hash) ? co.username : void 0
}
]);
};
})(this)
]);
} else {
_ref = this.options.users;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
user = _ref[_i];
if (user.username === co.username && this.validate(ha2, co, user.hash)) {
found = true;
break;
}
}
return callback.apply(this, [
{
user: found ? co.username : void 0
}
]);
}
} else {
return callback.apply(this, [
{
stale: true
}
]);
}
};
Digest.prototype.removeNonces = function(noncesToRemove) {
var index, nonce, _i, _len, _results;
_results = [];
for (_i = 0, _len = noncesToRemove.length; _i < _len; _i++) {
nonce = noncesToRemove[_i];
index = this.nonces.indexOf(nonce);
if (index !== -1) {
_results.push(this.nonces.splice(index, 1));
} else {
_results.push(void 0);
}
}
return _results;
};
Digest.prototype.validateNonce = function(nonce) {
var found, noncesToRemove, now, serverNonce, _i, _len, _ref;
now = Date.now();
noncesToRemove = [];
_ref = this.nonces;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
serverNonce = _ref[_i];
if ((serverNonce[1] + 3600000) > now) {
if (serverNonce[0] === nonce) {
found = true;
}
} else {
noncesToRemove.push(serverNonce);
}
}
this.removeNonces(noncesToRemove);
return found;
};
Digest.prototype.askNonce = function() {
var nonce;
nonce = utils.md5(uuid.v4());
this.nonces.push([nonce, Date.now()]);
return nonce;
};
Digest.prototype.generateHeader = function(result) {
var nonce, stale;
nonce = this.askNonce();
stale = result.stale ? true : false;
return "Digest realm=\"" + this.options.realm + "\", qop=\"" + this.options.qop + "\", nonce=\"" + nonce + "\", algorithm=\"" + this.options.algorithm + "\", stale=\"" + stale + "\"";
};
return Digest;
})(Base);
module.exports = function(options, checker) {
return new Digest(options, checker);
};
}).call(this);