[Pkg-javascript-commits] [ltx] 28/469: sasl: DIGEST-MD5 support
Jonas Smedegaard
dr at jones.dk
Wed Aug 31 13:00:54 UTC 2016
This is an automated email from the git hooks/post-receive script.
js pushed a commit to branch master
in repository ltx.
commit 33abba0a22e2c949bd25074d35fea7e7acea3abb
Author: Astro <astro at spaceboyz.net>
Date: Mon May 31 00:47:57 2010 +0200
sasl: DIGEST-MD5 support
---
lib/xmpp/client.js | 28 ++++++++----
lib/xmpp/sasl.js | 124 +++++++++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 140 insertions(+), 12 deletions(-)
diff --git a/lib/xmpp/client.js b/lib/xmpp/client.js
index 1e3e95f..a686b74 100644
--- a/lib/xmpp/client.js
+++ b/lib/xmpp/client.js
@@ -83,7 +83,16 @@ Client.prototype.onRawStanza = function(stanza) {
this.streamFeatures = stanza;
this.useFeatures();
} else if (this.state == STATE_AUTH) {
- if (stanza.is('success', NS_XMPP_SASL)) {
+ if (stanza.is('challenge', NS_XMPP_SASL)) {
+ var challengeMsg = b64.decode(stanza.getText());
+ sys.puts("challengeMsg: " + challengeMsg);
+ var responseMsg = b64.encode(
+ this.mech.challenge(challengeMsg));
+ this.send(new xml.Element('response',
+ { xmlns: NS_XMPP_SASL
+ }).t(responseMsg));
+ } else if (stanza.is('success', NS_XMPP_SASL)) {
+ this.mech = null;
this.state = STATE_AUTHED;
this.startStream();
} else {
@@ -136,19 +145,22 @@ Client.prototype.useFeatures = function() {
if (this.state == STATE_PREAUTH &&
this.streamFeatures.getChild('mechanisms', NS_XMPP_SASL)) {
this.state = STATE_AUTH;
- var mech = sasl.selectMechanism(
+ this.mech = sasl.selectMechanism(
this.streamFeatures.
getChild('mechanisms', NS_XMPP_SASL).
getChildren('mechanism', NS_XMPP_SASL).
map(function(el) { return el.getText(); }));
- if (mech) {
- mech.authzid = this.jid.bare().toString();
- mech.authcid = this.jid.user;
- mech.password = this.password;
+ if (this.mech) {
+ this.mech.authzid = this.jid.bare().toString();
+ this.mech.authcid = this.jid.user;
+ this.mech.password = this.password;
+ this.mech.realm = this.jid.domain; // anything?
+ this.mech.digest_uri = "xmpp/" + this.jid.domain;
+ var authMsg = b64.encode(this.mech.auth());
this.send(new xml.Element('auth',
{ xmlns: NS_XMPP_SASL,
- mechanism: mech.name
- }).t(b64.encode(mech.auth())));
+ mechanism: this.mech.name
+ }).t(authMsg));
} else {
this.emit('error', 'No usable SASL mechanism');
this.end();
diff --git a/lib/xmpp/sasl.js b/lib/xmpp/sasl.js
index 17bb1b4..290b541 100644
--- a/lib/xmpp/sasl.js
+++ b/lib/xmpp/sasl.js
@@ -1,12 +1,14 @@
+var crypto = require('crypto');
+
function selectMechanism(mechs) {
if (mechs.indexOf("ANONYMOUS") >= 0)
return new Anonymous();
- /*if (mechs.indexOf("DIGEST-MD5") >= 0)
- return "DIGEST-MD5";*/
+ else if (mechs.indexOf("DIGEST-MD5") >= 0)
+ return new DigestMD5();
else if (mechs.indexOf("PLAIN") >= 0)
- return new Plain();
+ return new Plain();
else
- return null;
+ return null;
}
exports.selectMechanism = selectMechanism;
@@ -25,3 +27,117 @@ function Anonymous() {
return this.authzid;
};
}
+
+function DigestMD5() {
+ this.name = "DIGEST-MD5";
+ this.auth = function() {
+ return "";
+ };
+
+ this.nonce_count = 0;
+ this.getNC = function() {
+ return rjust(this.nonce_count.toString(), 8, '0');
+ };
+ this.cnonce = generateNonce();
+ this.challenge = function(s) {
+ dict = parseDict(s);
+ if (dict.realm)
+ this.realm = dict.realm;
+ //require('sys').puts("dict: "+JSON.stringify(dict));
+
+ var response;
+ if (dict.nonce && dict.qop) {
+ this.nonce_count++;
+ var a1 = md5(this.authcid + ':' +
+ this.realm + ':' +
+ this.password) + ':' +
+ dict.nonce + ':' +
+ this.cnonce + ':' +
+ this.authzid;
+ var a2 = "AUTHENTICATE:" + this.digest_uri;
+ if (dict.qop == 'auth-int' || dict.qop == 'auth-conf')
+ a2 += ":00000000000000000000000000000000";
+ var responseValue = md5_hex(md5_hex(a1) + ':' +
+ dict.nonce + ':' +
+ this.getNC() + ':' +
+ this.cnonce + ':' +
+ dict.qop + ':' +
+ md5_hex(a2)
+ );
+ response = {
+ username: this.authcid,
+ realm: this.realm,
+ nonce: dict.nonce,
+ cnonce: this.cnonce,
+ nc: this.getNC(),
+ qop: dict.qop,
+ 'digest-uri': this.digest_uri,
+ response: responseValue,
+ authzid: this.authzid,
+ charset: 'utf-8'
+ };
+ } else if (dict.rspauth) {
+ return "";
+ }
+ //require('sys').puts('response: '+JSON.stringify(response));
+ return encodeDict(response);
+ };
+}
+
+function parseDict(s) {
+ var result = {};
+ while (s) {
+ var m;
+
+ if ((m = /^(.+?)="(.*?[^\\])",(.*)/.exec(s))) {
+ result[m[1]] = m[2];
+ s = m[3];
+ } else if ((m = /^(.+?)="(.*?[^\\])"$/.exec(s))) {
+ result[m[1]] = m[2];
+ s = m[3];
+ } else if ((m = /^(.+?)=(.+?),(.*)/.exec(s))) {
+ result[m[1]] = m[2];
+ s = m[3];
+ } else if ((m = /^(.+?)=(.+?)$/.exec(s))) {
+ result[m[1]] = m[2];
+ s = m[3];
+ } else {
+ s = null;
+ }
+ }
+ return result;
+}
+
+function encodeDict(dict) {
+ var s = "";
+ for(k in dict) {
+ var v = dict[k];
+ if (v)
+ s += ',' + k + '="' + v + '"';
+ }
+ return s.substr(1); // without first ','
+}
+
+function rjust(s, targetLen, padding) {
+ while(s.length < targetLen)
+ s = padding + s;
+ return s;
+}
+
+function md5(s, encoding) {
+ var hash = crypto.createHash('md5');
+ hash.update(s);
+ return hash.digest(encoding || 'binary');
+}
+
+function md5_hex(s) {
+ return md5(s, 'hex');
+}
+
+function generateNonce() {
+ var result = "";
+ for(var i = 0; i < 8; i++)
+ result += String.fromCharCode(48 +
+ Math.round(Math.random() * 10));
+ return result;
+}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/ltx.git
More information about the Pkg-javascript-commits
mailing list