From 1a007528dd9319ccda1bfd14d7ceaf04bd410bd8 Mon Sep 17 00:00:00 2001 From: Mark Paxton Date: Thu, 22 May 2014 09:14:36 +0100 Subject: [PATCH 1/8] Starting to replace http with request library - bump version and add new contributor --- http-digest-client.js | 9 +++------ package.json | 28 ++++++++++++++++++++++------ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/http-digest-client.js b/http-digest-client.js index 12d0d16..a1248af 100644 --- a/http-digest-client.js +++ b/http-digest-client.js @@ -7,15 +7,12 @@ var HTTPDigest = function () { var crypto = require('crypto'); - var http = require('http'); + var request = require('request'); - var HTTPDigest = function (username, password, https) { + var HTTPDigest = function (username, password) { this.nc = 0; this.username = username; this.password = password; - if(https === true) { - http = require('https'); - } }; // @@ -25,7 +22,7 @@ var HTTPDigest = function () { // HTTPDigest.prototype.request = function (options, callback) { var self = this; - http.request(options, function (res) { + request.get(options, function(err, res, body) { self._handleResponse(options, res, callback); }).end(); }; diff --git a/package.json b/package.json index 553fa33..20f16e2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "http-digest-client", - "version": "0.0.3", + "version": "0.0.4", "description": "Perform request agains digest authenticated servers.", "main": "http-digest-client.js", "scripts": { @@ -8,14 +8,30 @@ }, "repository": { "type": "git", - "url": "https://github.com/simme/node-http-digest-client" + "url": "https://github.com/MarkPaxton/node-http-digest-client" + }, + "author": { + "name": "Simon Ljungberg", + "email": "hi@iamsim.me" }, - "author": "Simon Ljungberg ", "contributors": [ { "name": "Paul Gration", "email": "pmgration@gmail.com" - } - ] + }, + { + "name": "Mark Paxton", + "email": "markpaxton3@gmail.com" + } + ], + "readme": "# HTTP Digest Client\n\nHacked together snippet for talking to HTTP servers that employ digest\nauthentication.\n\n## Disclaimer\n\nOnly tested against one server and spec is not followed fully. It works for me\nand for what I am doing.\n\n## Usage\n\n var digest = require('http-digest-client').createDigestClient('username', 'password');\n digest.request({\n host: 'hostname.com',\n path: '/path.json',\n port: 80,\n method: 'GET',\n headers: { \"User-Agent\": \"Simon Ljungberg\" } // Set any headers you want\n }, function (res) {\n res.on('data', function (data) {\n console.log(data.toString());\n });\n res.on('error', function (err) {\n console.log('oh noes');\n });\n });\n\nThe digest client will make one reques to the server, authentication response\nis calculated and then the request is made again. Hopefully you will then\nbe authorized.\n\n## Writing to `req`\n\nI haven't yet figured out a way to write data to the final `req` object.\nMainly because I haven't really needed it. Feel free to suggest solutions! :)\n\n# License\n\nSee LICENSE.\n\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/simme/node-http-digest-client/issues" + }, + "homepage": "https://github.com/MarkPaxton/node-http-digest-client", + "_id": "http-digest-client@0.0.3", + "_shasum": "78e018f5c0756bc74d9a3ea4fe20ad6fdbc6af24", + "_from": "http-digest-client@~0.0.3", + "_resolved": "https://registry.npmjs.org/http-digest-client/-/http-digest-client-0.0.3.tgz" } - From 2672e894fa2b607524608fe3898ad0a20376429b Mon Sep 17 00:00:00 2001 From: Mark Paxton Date: Thu, 22 May 2014 09:14:36 +0100 Subject: [PATCH 2/8] Starting to replace http with request library - bump version and add new contributor --- .gitignore | 1 + .project | 18 ++++++ Gruntfile.js | 53 ++++++++++++++++ .../http-digest-client.js | 21 ++++--- package.json | 49 +++++++++++---- test/digest_test.js | 60 +++++++++++++++++++ 6 files changed, 179 insertions(+), 23 deletions(-) create mode 100644 .gitignore create mode 100644 .project create mode 100644 Gruntfile.js rename http-digest-client.js => lib/http-digest-client.js (88%) create mode 100644 test/digest_test.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b512c09 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/.project b/.project new file mode 100644 index 0000000..5e11fbf --- /dev/null +++ b/.project @@ -0,0 +1,18 @@ + + + node-http-digest-client + + + + + + com.eclipsesource.jshint.ui.builder + + + + + + org.nodeclipse.ui.NodeNature + org.eclipse.wst.jsdt.core.jsNature + + diff --git a/Gruntfile.js b/Gruntfile.js new file mode 100644 index 0000000..ba137c0 --- /dev/null +++ b/Gruntfile.js @@ -0,0 +1,53 @@ +'use strict'; + +module.exports = function(grunt) { + + // Project configuration. + grunt.initConfig({ + nodeunit: { + files: ['test/**/*_test.js'] + }, + + jshint: { + options: { + jshintrc: '.jshintrc' + }, + gruntfile: { + src: 'Gruntfile.js' + }, + lib: { + src: ['lib/**/*.js'] + }, + test: { + src: ['test/**/*.js'] + }, + }, + watch: { + gruntfile: { + files: '<%= jshint.gruntfile.src %>', + tasks: ['jshint:gruntfile'] + }, + lib: { + files: '<%= jshint.lib.src %>', + tasks: ['jshint:lib', 'nodeunit'] + }, + test: { + files: '<%= jshint.test.src %>', + tasks: ['jshint:test', 'nodeunit'] + }, + work: { + files: ['<%= jshint.lib.src %>', '<%= jshint.test.src %>', 'node_modules/**/*.js'], + tasks: ['nodeunit'] + } + }, + }); + + // These plugins provide necessary tasks. + grunt.loadNpmTasks('grunt-contrib-nodeunit'); + grunt.loadNpmTasks('grunt-contrib-jshint'); + grunt.loadNpmTasks('grunt-contrib-watch'); + + // Default task. + grunt.registerTask('default', ['jshint', 'nodeunit' ]); + +}; diff --git a/http-digest-client.js b/lib/http-digest-client.js similarity index 88% rename from http-digest-client.js rename to lib/http-digest-client.js index 12d0d16..15d8722 100644 --- a/http-digest-client.js +++ b/lib/http-digest-client.js @@ -7,15 +7,12 @@ var HTTPDigest = function () { var crypto = require('crypto'); - var http = require('http'); + var request = require('request'); - var HTTPDigest = function (username, password, https) { + var HTTPDigest = function (username, password) { this.nc = 0; this.username = username; this.password = password; - if(https === true) { - http = require('https'); - } }; // @@ -25,8 +22,8 @@ var HTTPDigest = function () { // HTTPDigest.prototype.request = function (options, callback) { var self = this; - http.request(options, function (res) { - self._handleResponse(options, res, callback); + request(options, function(err, res, body) { + self._handleResponse(options, err, res, body, callback); }).end(); }; @@ -35,8 +32,9 @@ var HTTPDigest = function () { // // Parse authentication headers and set response. // - HTTPDigest.prototype._handleResponse = function handleResponse(options, res, callback) { - var challenge = this._parseChallenge(res.headers['www-authenticate']); + HTTPDigest.prototype._handleResponse = function handleResponse(options, err, res, body, callback) { + console.log(res); + var challenge = this._parseChallenge(res.headers['www-authenticate']); var ha1 = crypto.createHash('md5'); ha1.update([this.username, challenge.realm, this.password].join(':')); var ha2 = crypto.createHash('md5'); @@ -87,7 +85,7 @@ var HTTPDigest = function () { headers.Authorization = this._compileParams(authParams); options.headers = headers; - http.request(options, function (res) { + request(options, function (res) { callback(res); }).end(); }; @@ -96,7 +94,8 @@ var HTTPDigest = function () { // ## Parse challenge digest // HTTPDigest.prototype._parseChallenge = function parseChallenge(digest) { - var prefix = "Digest "; + console.log("parse challenge:" + digest); + var prefix = "Digest "; var challenge = digest.substr(digest.indexOf(prefix) + prefix.length); var parts = challenge.split(','); var length = parts.length; diff --git a/package.json b/package.json index 553fa33..976539c 100644 --- a/package.json +++ b/package.json @@ -1,21 +1,46 @@ { "name": "http-digest-client", - "version": "0.0.3", + "version": "0.0.4", "description": "Perform request agains digest authenticated servers.", - "main": "http-digest-client.js", + "author": { + "name": "Simon Ljungberg", + "email": "hi@iamsim.me" + }, + "contributors": [ + { + "name": "Paul Gration", + "email": "pmgration@gmail.com" + }, + { + "name": "Mark Paxton", + "email": "markpaxton3@gmail.com" + } + ], + "readme": "# HTTP Digest Client\n\nHacked together snippet for talking to HTTP servers that employ digest\nauthentication.\n\n## Disclaimer\n\nOnly tested against one server and spec is not followed fully. It works for me\nand for what I am doing.\n\n## Usage\n\n var digest = require('http-digest-client').createDigestClient('username', 'password');\n digest.request({\n host: 'hostname.com',\n path: '/path.json',\n port: 80,\n method: 'GET',\n headers: { \"User-Agent\": \"Simon Ljungberg\" } // Set any headers you want\n }, function (res) {\n res.on('data', function (data) {\n console.log(data.toString());\n });\n res.on('error', function (err) {\n console.log('oh noes');\n });\n });\n\nThe digest client will make one reques to the server, authentication response\nis calculated and then the request is made again. Hopefully you will then\nbe authorized.\n\n## Writing to `req`\n\nI haven't yet figured out a way to write data to the final `req` object.\nMainly because I haven't really needed it. Feel free to suggest solutions! :)\n\n# License\n\nSee LICENSE.\n\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/simme/node-http-digest-client/issues" + }, + "main": "lib/http-digest-client.js", + "engines": { + "node": ">= 0.8.0" + }, "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "grunt nodeunit" + }, + "devDependencies": { + "grunt": "0.4.x", + "grunt-cli": "^0.1.13", + "grunt-contrib-jshint": "0.10.x", + "grunt-contrib-nodeunit": "0.3.x", + "grunt-contrib-watch": "0.6.x" }, "repository": { "type": "git", - "url": "https://github.com/simme/node-http-digest-client" + "url": "https://github.com/MarkPaxton/node-http-digest-client" + }, + "dependencies": { + "request": "~2.34.0" }, - "author": "Simon Ljungberg ", - "contributors": [ - { - "name": "Paul Gration", - "email": "pmgration@gmail.com" - } - ] + "homepage": "https://github.com/MarkPaxton/node-http-digest-client" } - diff --git a/test/digest_test.js b/test/digest_test.js new file mode 100644 index 0000000..933b9b6 --- /dev/null +++ b/test/digest_test.js @@ -0,0 +1,60 @@ +'use strict'; +var DigestClient = require('../lib/http-digest-client.js'); +/* + * ======== A Handy Little Nodeunit Reference ======== + * https://github.com/caolan/nodeunit + * + * Test methods: + * test.expect(numAssertions) + * test.done() + * Test assertions: + * test.ok(value, [message]) + * test.equal(actual, expected, [message]) + * test.notEqual(actual, expected, [message]) + * test.deepEqual(actual, expected, [message]) + * test.notDeepEqual(actual, expected, [message]) + * test.strictEqual(actual, expected, [message]) + * test.notStrictEqual(actual, expected, [message]) + * test.throws(block, [error], [message]) + * test.doesNotThrow(block, [error], [message]) + * test.ifError(value) + */ + +exports.DigestTest = { + setUp : function(done) { + // setup here + done(); + }, + 'constructs' : function(test) { + test.expect(1); + test.done(); + }, + 'doing a digest auth works' : function(test) { + test.expect(1); + // tests here + var auth = { + user: 'admin', + pass: '******' + }, + digest = DigestClient(auth.user, auth.pass, false), options = { + url : 'http://*****/rest/workspaces/CreateMe', + method: 'post', + auth: auth, + json:true, + headers: { + "Accept" : "application/json" + } + }; + digest.request(options, function(err, res, body) { + + console.log(res.message.headers); + if (err !== null) + endError("Can't access " + url + ": " + err); + if (res.statusCode >= 400) + endError("(" + res.statusCode + ") Can't open " + url + "\r\n" + + body); + callback(body); + }); + + } +}; From 5cbaa8deefc6b07e9def1db8d194247ef1a6c472 Mon Sep 17 00:00:00 2001 From: Mark Paxton Date: Mon, 2 Jun 2014 10:36:43 +0100 Subject: [PATCH 3/8] Update to use node request module to handle digest requests properly and call callbacks compatible with request modile. Add grunt test setup. --- lib/http-digest-client.js | 265 +++++++++++++++++++------------------- test/digest_test.js | 155 +++++++++++++++------- 2 files changed, 242 insertions(+), 178 deletions(-) diff --git a/lib/http-digest-client.js b/lib/http-digest-client.js index 15d8722..329c00e 100644 --- a/lib/http-digest-client.js +++ b/lib/http-digest-client.js @@ -5,141 +5,146 @@ // by digest authentication. // -var HTTPDigest = function () { - var crypto = require('crypto'); - var request = require('request'); - - var HTTPDigest = function (username, password) { - this.nc = 0; - this.username = username; - this.password = password; - }; - - // - // ## Make request - // - // Wraps the http.request function to apply digest authorization. - // - HTTPDigest.prototype.request = function (options, callback) { - var self = this; - request(options, function(err, res, body) { - self._handleResponse(options, err, res, body, callback); - }).end(); - }; - - // - // ## Handle authentication - // - // Parse authentication headers and set response. - // - HTTPDigest.prototype._handleResponse = function handleResponse(options, err, res, body, callback) { - console.log(res); - var challenge = this._parseChallenge(res.headers['www-authenticate']); - var ha1 = crypto.createHash('md5'); - ha1.update([this.username, challenge.realm, this.password].join(':')); - var ha2 = crypto.createHash('md5'); - ha2.update([options.method, options.path].join(':')); - - // Generate cnonce - var cnonce = false; - var nc = false; - if (typeof challenge.qop === 'string') { - var cnonceHash = crypto.createHash('md5'); - cnonceHash.update(Math.random().toString(36)); - cnonce = cnonceHash.digest('hex').substr(0, 8); - nc = this.updateNC(); - } - - // Generate response hash - var response = crypto.createHash('md5'); - var responseParams = [ - ha1.digest('hex'), - challenge.nonce - ]; - - if (cnonce) { - responseParams.push(nc); - responseParams.push(cnonce); - } - - responseParams.push(challenge.qop); - responseParams.push(ha2.digest('hex')); - response.update(responseParams.join(':')); - - // Setup response parameters - var authParams = { - username: this.username, - realm: challenge.realm, - nonce: challenge.nonce, - uri: options.path, - qop: challenge.qop, - response: response.digest('hex'), - opaque: challenge.opaque - }; - if (cnonce) { - authParams.nc = nc; - authParams.cnonce = cnonce; - } - - var headers = options.headers || {}; - headers.Authorization = this._compileParams(authParams); - options.headers = headers; - - request(options, function (res) { - callback(res); - }).end(); - }; - - // - // ## Parse challenge digest - // - HTTPDigest.prototype._parseChallenge = function parseChallenge(digest) { - console.log("parse challenge:" + digest); - var prefix = "Digest "; - var challenge = digest.substr(digest.indexOf(prefix) + prefix.length); - var parts = challenge.split(','); - var length = parts.length; - var params = {}; - for (var i = 0; i < length; i++) { - var part = parts[i].match(/^\s*?([a-zA-Z0-0]+)="(.*)"\s*?$/); - if (part.length > 2) { - params[part[1]] = part[2]; +var HTTPDigest = function() { + var crypto = require('crypto'); + var request = require('request'); + + var HTTPDigest = function(username, password) { + this.nc = 0; + this.username = username; + this.password = password; + }; + + // + // ## Make request + // + // Wraps the http.request function to apply digest authorization. + // + HTTPDigest.prototype.request = function(options, callback) { + var self = this; + request(options, function(err, res, body) { + self._handleResponse(options, err, res, body, callback); + }).end(); + }; + + // + // ## Handle authentication + // + // Parse authentication headers and set response. + // + HTTPDigest.prototype._handleResponse = function handleResponse(options, err, res, body, callback) { + // First check if there is an error condition + if(err != null && typeof res=='undefined') + callback(err, res, body); + if(res.statusCode != "401") + callback(err, res, body); + // If not check if callback is required + else if(typeof res.headers['www-authenticate'] === 'undefined') { + callback(err, res, body); + } + else { + var challenge = this._parseChallenge(res.headers['www-authenticate']); + var ha1 = crypto.createHash('md5'); + ha1.update([ this.username, challenge.realm, this.password ].join(':')); + var ha2 = crypto.createHash('md5'); + ha2.update([ options.method, options.path ].join(':')); + + // Generate cnonce + var cnonce = false; + var nc = false; + if (typeof challenge.qop === 'string') { + var cnonceHash = crypto.createHash('md5'); + cnonceHash.update(Math.random().toString(36)); + cnonce = cnonceHash.digest('hex').substr(0, 8); + nc = this.updateNC(); + } + + // Generate response hash + var response = crypto.createHash('md5'); + var responseParams = [ ha1.digest('hex'), challenge.nonce ]; + + if (cnonce) { + responseParams.push(nc); + responseParams.push(cnonce); + } + + responseParams.push(challenge.qop); + responseParams.push(ha2.digest('hex')); + response.update(responseParams.join(':')); + + // Setup response parameters + var authParams = { + username : this.username, + realm : challenge.realm, + nonce : challenge.nonce, + uri : options.path, + qop : challenge.qop, + response : response.digest('hex'), + opaque : challenge.opaque + }; + if (cnonce) { + authParams.nc = nc; + authParams.cnonce = cnonce; + } + + var headers = options.headers || {}; + headers.Authorization = this._compileParams(authParams); + options.headers = headers; + + request(options, function(err, res, body) { + callback(err, res, body); + }); + } + }; + + // + // ## Parse challenge digest + // + HTTPDigest.prototype._parseChallenge = function parseChallenge(digest) { + var prefix = "Digest "; + var challenge = digest.substr(digest.indexOf(prefix) + prefix.length); + var parts = challenge.split(','); + var length = parts.length; + var params = {}; + for (var i = 0; i < length; i++) { + var part = parts[i].match(/^\s*?([a-zA-Z0-0]+)="(.*)"\s*?$/); + if (part.length > 2) { + params[part[1]] = part[2]; + } } - } - - return params; - }; - // - // ## Compose authorization header - // - HTTPDigest.prototype._compileParams = function compileParams(params) { - var parts = []; - for (var i in params) { - parts.push(i + '="' + params[i] + '"'); - } - return 'Digest ' + parts.join(','); - }; + return params; + }; - // - // ## Update and zero pad nc - // - HTTPDigest.prototype.updateNC = function updateNC() { - var max = 99999999; - this.nc++; - if (this.nc > max) { - this.nc = 1; - } - var padding = new Array(8).join('0') + ""; - var nc = this.nc + ""; - return padding.substr(0, 8 - nc.length) + nc; - }; + // + // ## Compose authorization header + // + HTTPDigest.prototype._compileParams = function compileParams(params) { + var parts = []; + for ( var i in params) { + parts.push(i + '="' + params[i] + '"'); + } + return 'Digest ' + parts.join(','); + }; + + // + // ## Update and zero pad nc + // + HTTPDigest.prototype.updateNC = function updateNC() { + var max = 99999999; + this.nc++; + if (this.nc > max) { + this.nc = 1; + } + var padding = new Array(8).join('0') + ""; + var nc = this.nc + ""; + return padding.substr(0, 8 - nc.length) + nc; + }; - // Return response handler - return HTTPDigest; + // Return response handler + return HTTPDigest; }(); module.exports = function createDigestClient(username, password, https) { - return new HTTPDigest(username, password, https); + return new HTTPDigest(username, password, https); }; - diff --git a/test/digest_test.js b/test/digest_test.js index 933b9b6..4b04828 100644 --- a/test/digest_test.js +++ b/test/digest_test.js @@ -4,57 +4,116 @@ var DigestClient = require('../lib/http-digest-client.js'); * ======== A Handy Little Nodeunit Reference ======== * https://github.com/caolan/nodeunit * - * Test methods: - * test.expect(numAssertions) - * test.done() + * Test methods: test.expect(numAssertions) + * test.done() * Test assertions: - * test.ok(value, [message]) - * test.equal(actual, expected, [message]) - * test.notEqual(actual, expected, [message]) - * test.deepEqual(actual, expected, [message]) - * test.notDeepEqual(actual, expected, [message]) - * test.strictEqual(actual, expected, [message]) - * test.notStrictEqual(actual, expected, [message]) - * test.throws(block, [error], [message]) - * test.doesNotThrow(block, [error], [message]) - * test.ifError(value) + * test.ok(value, [message]) + * test.equal(actual, expected, [message]) + * test.notEqual(actual, expected, [message]) + * test.deepEqual(actual, expected, [message]) + * test.notDeepEqual(actual, expected, [message]) + * test.strictEqual(actual, expected, [message]) + * test.notStrictEqual(actual, expected, [message]) + * test.throws(block, [error], [message]) + * test.doesNotThrow(block, [error], [message]) + * test.ifError(value) */ + exports.DigestTest = { - setUp : function(done) { - // setup here - done(); - }, - 'constructs' : function(test) { - test.expect(1); - test.done(); - }, - 'doing a digest auth works' : function(test) { - test.expect(1); - // tests here - var auth = { - user: 'admin', - pass: '******' - }, - digest = DigestClient(auth.user, auth.pass, false), options = { - url : 'http://*****/rest/workspaces/CreateMe', - method: 'post', - auth: auth, - json:true, - headers: { - "Accept" : "application/json" - } - }; - digest.request(options, function(err, res, body) { - - console.log(res.message.headers); - if (err !== null) - endError("Can't access " + url + ": " + err); - if (res.statusCode >= 400) - endError("(" + res.statusCode + ") Can't open " + url + "\r\n" - + body); - callback(body); - }); + setUp : function(done) { + // setup here + done(); + }, + 'doing a digest auth works' : function(test) { + test.expect(1); + // tests here + var auth = { + user : 'yyyy', + pass : 'xxxx' + }, digest = DigestClient(auth.user, auth.pass, false), options = { + url : 'http://xxxx/rest/workspaces', + method : 'post', + auth : auth, + json : true, + body : { + workspace : { + name : 'DeleteMe' + (new Date()).getTime() + } + }, + headers : { + "Accept" : "application/json" + } + }; + digest.request(options, function(err, res, body) { + if (err !== null) + console.log("Can't access " + res.req.url + ": " + err); + if (res.statusCode >= 400) + console.log("(" + res.statusCode + ") Can't open " + res.req.url + "\r\n" + body); + test.ok(res.statusCode < 400, "HTTP Error Code Received: " + res.statusCode); + test.done(); + }); + }, + 'doing an invalid digest auth fails' : function(test) { + test.expect(1); + // tests here + var auth = { + user : 'aaaa', + pass : 'xxxx' + }, digest = DigestClient(auth.user, auth.pass, false), options = { + url : 'http://xxxxx/rest/workspaces', + method : 'post', + auth : auth, + json : true, + body : { + workspace : { + name : 'DeleteMe' + (new Date()).getTime() + } + }, + headers : { + "Accept" : "application/json" + } + }; + digest.request(options, function(err, res, body) { + if (err !== null) + console.log("Can't access " + res.req.url + ": " + err); + if (res.statusCode > 401) + console.log("(" + res.statusCode + ") Can't open " + res.req.url + "\r\n" + body); + test.equals(res.statusCode, 401, "HTTP Error Code Received: " + res.statusCode); + + test.done(); + }); + }, + 'error 404 fails gracefully' : function(test) { + test.expect(2); + // tests here + var testUrl = 'http://xxxx/rest/workspaces/' + (new Date()).getTime(), + auth = { + user : 'aaaa', + pass : 'xxxx' + }, digest = DigestClient(auth.user, auth.pass, false), options = { + url : testUrl, + method : 'get', + auth : auth, + json : true, + body : { + workspace : { + name : 'DeleteMe' + (new Date()).getTime() + } + }, + headers : { + "Accept" : "application/json" + } + }; + digest.request(options, function(err, res, body) { + test.equal(err, null, "Error is not null"); +/* if (err !== null) + console.log("Can't access location: " + err); + if (res.statusCode >= 400) + console.log("(" + res.statusCode + ") Can't open " + testUrl + "\r\n" + body);*/ + test.equals(res.statusCode, 404, "HTTP Error Code Received: " + res.statusCode); + test.done(); + }); + } - } }; From 1009a4b459e660ae25b3dac3ab25bd5180077b06 Mon Sep 17 00:00:00 2001 From: Mark Paxton Date: Mon, 2 Jun 2014 10:49:20 +0100 Subject: [PATCH 4/8] Merge with github version --- package.json.bak | 46 ---------------------------------------------- 1 file changed, 46 deletions(-) delete mode 100644 package.json.bak diff --git a/package.json.bak b/package.json.bak deleted file mode 100644 index 976539c..0000000 --- a/package.json.bak +++ /dev/null @@ -1,46 +0,0 @@ -{ - "name": "http-digest-client", - "version": "0.0.4", - "description": "Perform request agains digest authenticated servers.", - "author": { - "name": "Simon Ljungberg", - "email": "hi@iamsim.me" - }, - "contributors": [ - { - "name": "Paul Gration", - "email": "pmgration@gmail.com" - }, - { - "name": "Mark Paxton", - "email": "markpaxton3@gmail.com" - } - ], - "readme": "# HTTP Digest Client\n\nHacked together snippet for talking to HTTP servers that employ digest\nauthentication.\n\n## Disclaimer\n\nOnly tested against one server and spec is not followed fully. It works for me\nand for what I am doing.\n\n## Usage\n\n var digest = require('http-digest-client').createDigestClient('username', 'password');\n digest.request({\n host: 'hostname.com',\n path: '/path.json',\n port: 80,\n method: 'GET',\n headers: { \"User-Agent\": \"Simon Ljungberg\" } // Set any headers you want\n }, function (res) {\n res.on('data', function (data) {\n console.log(data.toString());\n });\n res.on('error', function (err) {\n console.log('oh noes');\n });\n });\n\nThe digest client will make one reques to the server, authentication response\nis calculated and then the request is made again. Hopefully you will then\nbe authorized.\n\n## Writing to `req`\n\nI haven't yet figured out a way to write data to the final `req` object.\nMainly because I haven't really needed it. Feel free to suggest solutions! :)\n\n# License\n\nSee LICENSE.\n\n", - "readmeFilename": "README.md", - "bugs": { - "url": "https://github.com/simme/node-http-digest-client/issues" - }, - "main": "lib/http-digest-client.js", - "engines": { - "node": ">= 0.8.0" - }, - "scripts": { - "test": "grunt nodeunit" - }, - "devDependencies": { - "grunt": "0.4.x", - "grunt-cli": "^0.1.13", - "grunt-contrib-jshint": "0.10.x", - "grunt-contrib-nodeunit": "0.3.x", - "grunt-contrib-watch": "0.6.x" - }, - "repository": { - "type": "git", - "url": "https://github.com/MarkPaxton/node-http-digest-client" - }, - "dependencies": { - "request": "~2.34.0" - }, - "homepage": "https://github.com/MarkPaxton/node-http-digest-client" -} From 772835d55b88ef8c47e86ceb3a5c8b097dd0fc63 Mon Sep 17 00:00:00 2001 From: Karsten Redmer Date: Sat, 21 Jun 2014 18:32:21 +0200 Subject: [PATCH 5/8] added path parsing from given url --- lib/http-digest-client.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/http-digest-client.js b/lib/http-digest-client.js index 329c00e..9faa36d 100644 --- a/lib/http-digest-client.js +++ b/lib/http-digest-client.js @@ -4,6 +4,7 @@ // Use together with HTTP Client to perform requests to servers protected // by digest authentication. // +var url=require('url'); var HTTPDigest = function() { var crypto = require('crypto'); @@ -43,11 +44,12 @@ var HTTPDigest = function() { callback(err, res, body); } else { + var path=url.parse('options.url').path; // get path from url var challenge = this._parseChallenge(res.headers['www-authenticate']); var ha1 = crypto.createHash('md5'); ha1.update([ this.username, challenge.realm, this.password ].join(':')); var ha2 = crypto.createHash('md5'); - ha2.update([ options.method, options.path ].join(':')); + ha2.update([ options.method, path ].join(':')); // Generate cnonce var cnonce = false; @@ -77,7 +79,7 @@ var HTTPDigest = function() { username : this.username, realm : challenge.realm, nonce : challenge.nonce, - uri : options.path, + uri : path, qop : challenge.qop, response : response.digest('hex'), opaque : challenge.opaque From e946b98018c8d296e806291b4be429f04254725d Mon Sep 17 00:00:00 2001 From: Karsten Redmer Date: Sat, 21 Jun 2014 18:40:24 +0200 Subject: [PATCH 6/8] path parsing bugfix --- lib/http-digest-client.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/http-digest-client.js b/lib/http-digest-client.js index 9faa36d..2ae8c1d 100644 --- a/lib/http-digest-client.js +++ b/lib/http-digest-client.js @@ -44,7 +44,7 @@ var HTTPDigest = function() { callback(err, res, body); } else { - var path=url.parse('options.url').path; // get path from url + var path=url.parse(options.url).path; // get path from url var challenge = this._parseChallenge(res.headers['www-authenticate']); var ha1 = crypto.createHash('md5'); ha1.update([ this.username, challenge.realm, this.password ].join(':')); From 89eb3ae2582976a619d9ca92bd9a23df0024e6d8 Mon Sep 17 00:00:00 2001 From: Karsten Redmer Date: Sat, 21 Jun 2014 18:46:38 +0200 Subject: [PATCH 7/8] ensure no basic auth with request module --- lib/http-digest-client.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/http-digest-client.js b/lib/http-digest-client.js index 2ae8c1d..2768d60 100644 --- a/lib/http-digest-client.js +++ b/lib/http-digest-client.js @@ -23,6 +23,7 @@ var HTTPDigest = function() { // HTTPDigest.prototype.request = function(options, callback) { var self = this; + options.auth.sendImmediately=false; // ensure no basic auth request(options, function(err, res, body) { self._handleResponse(options, err, res, body, callback); }).end(); From 946835a2ca6ce8c2899d7c36cccaa2f85274db16 Mon Sep 17 00:00:00 2001 From: Mark Paxton Date: Thu, 16 Jul 2015 10:57:52 +0100 Subject: [PATCH 8/8] Added newline to .gitignore, removed and ignored .project file --- .gitignore | 3 ++- .project | 18 ------------------ 2 files changed, 2 insertions(+), 19 deletions(-) delete mode 100644 .project diff --git a/.gitignore b/.gitignore index b512c09..4d227a8 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -node_modules \ No newline at end of file +node_modules +.project \ No newline at end of file diff --git a/.project b/.project deleted file mode 100644 index 5e11fbf..0000000 --- a/.project +++ /dev/null @@ -1,18 +0,0 @@ - - - node-http-digest-client - - - - - - com.eclipsesource.jshint.ui.builder - - - - - - org.nodeclipse.ui.NodeNature - org.eclipse.wst.jsdt.core.jsNature - -