[Pkg-javascript-commits] [ltx] 02/469: SASL PLAIN, bind & session

Jonas Smedegaard dr at jones.dk
Wed Aug 31 13:00:49 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 29612d1a34c5ac676178809528231692bd62ef3c
Author: Astro <astro at spaceboyz.net>
Date:   Wed May 26 03:26:56 2010 +0200

    SASL PLAIN, bind & session
---
 lib/xmpp/connection.js | 117 ++++++++++++++++++++++++++++++++++++++++++++++---
 lib/xmpp/jid.js        |  18 +++++++-
 lib/xmpp/sasl.js       |  16 +++++++
 3 files changed, 144 insertions(+), 7 deletions(-)

diff --git a/lib/xmpp/connection.js b/lib/xmpp/connection.js
index 245bb3a..cc0371a 100644
--- a/lib/xmpp/connection.js
+++ b/lib/xmpp/connection.js
@@ -3,13 +3,30 @@ var sys = require('sys');
 var expat = require('expat');
 var puts = require('sys').puts;
 var xml = require('./xml');
+var sasl = require('./sasl');
+var JID = require('./jid').JID;
+var b64 = require('base64');
 
 var NS_XMPP_TLS = 'urn:ietf:params:xml:ns:xmpp-tls';
+var NS_XMPP_SASL = 'urn:ietf:params:xml:ns:xmpp-sasl';
+var NS_XMPP_BIND = 'urn:ietf:params:xml:ns:xmpp-bind';
+var NS_XMPP_SESSION = 'urn:ietf:params:xml:ns:xmpp-session';
+
+var STATE_PREAUTH = 0,
+    STATE_AUTH = 1,
+    STATE_AUTHED = 2,
+    STATE_BIND = 3,
+    STATE_SESSION = 4,
+    STATE_ONLINE = 5;
+var IQID_SESSION = 'sess',
+    IQID_BIND = 'bind';
 
 function Connection() {
     net.Stream.call(this);
 
+    this.state = STATE_PREAUTH;
     this.charset = 'UTF-8';
+    this.allowTLS = true;  /* can be set by user */
     this.addListener('connect', this.startStream);
     this.addListener('data', this.onData);
 //    this.addListener('end', this.onEnd);
@@ -20,6 +37,7 @@ sys.inherits(Connection, net.Stream);
 exports.Connection = Connection;
 
 Connection.prototype.send = function(stanza) {
+    puts("SEND " + stanza);
     var self = this;
     if (stanza.root)
 	stanza.root().write(function(s) {
@@ -49,7 +67,7 @@ Connection.prototype.startParser = function() {
     });
     self.parser.addListener('endElement', function(name, attrs) {
 	if (!self.element && name == 'stream:stream') {
-	    self.close();
+	    self.end();
 	} else if (self.element && name == self.element.name) {
 	    if (self.element.parent)
 		self.element = self.element.parent;
@@ -97,14 +115,101 @@ Connection.prototype.onData = function(data) {
 Connection.prototype.onStanza = function(stanza) {
     puts('Stanza: ' + stanza.toString());
 
-    if (stanza.name == 'stream:features') {
-	if (stanza.getChild('starttls', NS_XMPP_TLS)) {
+    if (this.state == STATE_ONLINE) {
+	this.emit('stanza', this.element);
+    } else if (this.state == STATE_PREAUTH &&
+	       stanza.name == 'stream:features') {
+	if (this.allowTLS &&
+	    stanza.getChild('starttls', NS_XMPP_TLS)) {
 	    this.send(new xml.Element('starttls', { xmlns: NS_XMPP_TLS }));
+	} else if (stanza.getChild('mechanisms', NS_XMPP_SASL)) {
+	    this.state = STATE_AUTH;
+	    var mechs = stanza.getChild('mechanisms', NS_XMPP_SASL).
+			    getChildren('mechanism', NS_XMPP_SASL).
+			    map(function(el) { return el.getText(); });
+	    var mech = selectAuthMechanism(mechs);
+	    if (mech) {
+		mech.authzid = this.jid.bare().toString();
+		mech.authcid = this.jid.user;
+		mech.password = this.password;
+		this.send(new xml.Element('auth',
+					  { xmlns: NS_XMPP_SASL,
+					    mechanism: mech.name
+					  }).t(b64.encode(mech.auth())));
+	    } else {
+		this.emit('authFail');
+		this.end();
+	    }
 	}
-    } else if (stanza.name == 'proceed' && stanza.getNS() == NS_XMPP_TLS) {
+    } else if (stanza.name == 'proceed' &&
+	       stanza.getNS() == NS_XMPP_TLS) {
 	this.setSecure();
 	this.addListener('secure', this.startStream);
-    }
+    } else if (this.state == STATE_AUTH &&
+	       stanza.getNS() == NS_XMPP_SASL) {
+	if (stanza.name == 'success') {
+	    this.state = STATE_AUTHED;
+	    this.startStream();
+	} else {
+	    this.emit('authFail');
+	    this.end();
+	}
+    } else if (this.state == STATE_AUTHED &&
+	       stanza.name == 'stream:features' &&
+	       stanza.getChild('bind', NS_XMPP_BIND)) {
+	this.state = STATE_BIND;
+	var bindEl = new xml.Element('iq',
+				     { type: 'set',
+				       id: IQID_BIND
+				     }).c('bind',
+					  { xmlns: NS_XMPP_BIND
+					  });
+	if (this.jid.resource)
+	    bindEl.c('resource').t(this.jid.resource);
+	this.send(bindEl.root());
+    } else if (this.state == STATE_BIND &&
+	       stanza.name == 'iq' &&
+	       stanza.attrs.id == IQID_BIND) {
+	if (stanza.attrs.type == 'result') {
+	    this.state = STATE_AUTHED;
+	    var bindEl = stanza.getChild('bind', NS_XMPP_BIND);
+	    if (bindEl && bindEl.getChild('jid')) {
+		this.jid = new JID(bindEl.getChild('jid').getText());
+	    }
 
-    this.emit('stanza', this.element);
+	    // FIXME: move this to check stream:features again
+	    this.state = STATE_SESSION;
+	    this.send(new xml.Element('iq',
+				      { type: 'set',
+					to: this.jid.domain,
+					id: IQID_SESSION
+				      }).c('session',
+					   { xmlns: NS_XMPP_SESSION
+					   }));
+	} else {
+	    this.emit('error', "Cannot bind resource");
+	    this.end();
+	}
+    } else if (this.state == STATE_SESSION &&
+	       stanza.name == 'iq' &&
+	       stanza.attrs.id == IQID_SESSION) {
+	if (stanza.attrs.type == 'result') {
+	    this.state = STATE_AUTHED;
+	} else {
+	    this.emit('error', "Cannot establish session");
+	    this.end();
+	}
+    } else if (stanza.name == 'stream:error') {
+	this.emit('error', stanza);
+	this.end();
+    }
 };
+
+function selectAuthMechanism(mechs) {
+    /*if (mechs.indexOf("DIGEST-MD5") >= 0)
+	return "DIGEST-MD5";
+    else*/ if (mechs.indexOf("PLAIN") >= 0)
+	return new sasl.Mechanism("PLAIN");
+    else
+	return null;
+}
diff --git a/lib/xmpp/jid.js b/lib/xmpp/jid.js
index b5e43d3..d2bcf95 100644
--- a/lib/xmpp/jid.js
+++ b/lib/xmpp/jid.js
@@ -18,6 +18,22 @@ JID.prototype.parseJID = function(s) {
 	s = s.substr(0, s.indexOf('/'));
     }
     this.domain = s;
-}
+};
+
+JID.prototype.toString = function() {
+    var s = this.domain;
+    if (this.user)
+	s = this.user + '@' + s;
+    if (this.resource)
+	s = s + '/' + this.resource;
+    return s;
+};
+
+JID.prototype.bare = function() {
+    if (this.resource)
+	return new JID(this.user, this.domain, null);
+    else
+	return this;
+};
 
 exports.JID = JID;
diff --git a/lib/xmpp/sasl.js b/lib/xmpp/sasl.js
new file mode 100644
index 0000000..d215cc4
--- /dev/null
+++ b/lib/xmpp/sasl.js
@@ -0,0 +1,16 @@
+function Mechanism(name) {
+    this.name = name;
+    if (name == "PLAIN")
+	Plain.call(this);
+    else
+	throw("Unsupported mechanism: " + name);
+}
+exports.Mechanism = Mechanism;
+
+function Plain() {
+    this.auth = function() {
+	return this.authzid + "\0" +
+	    this.authcid + "\0" +
+	    this.password;
+    };
+}

-- 
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