[Pkg-javascript-commits] [ltx] 17/469: oops, all this c2s auth stuff belongs into client not connection

Jonas Smedegaard dr at jones.dk
Wed Aug 31 13:00:52 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 7baf775d990b227a07a939e7b7e9a289d914e7cb
Author: Astro <astro at spaceboyz.net>
Date:   Sun May 30 16:38:56 2010 +0200

    oops, all this c2s auth stuff belongs into client not connection
---
 lib/xmpp/client.js     | 143 ++++++++++++++++++++++++++++++++++++++++-
 lib/xmpp/connection.js | 168 +++++++------------------------------------------
 2 files changed, 163 insertions(+), 148 deletions(-)

diff --git a/lib/xmpp/client.js b/lib/xmpp/client.js
index 5831e02..5c71c0b 100644
--- a/lib/xmpp/client.js
+++ b/lib/xmpp/client.js
@@ -1,7 +1,23 @@
 var Connection = require('./connection').Connection;
 var JID = require('./jid').JID;
+var xml = require('./xml');
+var sasl = require('./sasl');
 var sys = require('sys');
 var dns = require('dns');
+var b64 = require('base64');
+
+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';
 
 /**
  * params:
@@ -21,6 +37,8 @@ function Client(params) {
     this.xmlns = "jabber:client";
     this.xmppVersion = "1.0";
     this.streamTo = this.jid.domain;
+    this.state = STATE_PREAUTH;
+    this.addListener('rawStanza', this.onRawStanza);
 
     if (params.host) {
 	this.connect(params.port || 5222, params.host);
@@ -41,7 +59,11 @@ function Client(params) {
 					       else
 						   return 0;
 					   });
-			       /* Design fail: */
+			       /* Epic design fail: we cannot retry
+				  with another SRV result because that
+				  will confuse the user with
+				  non-terminal 'error' & 'end' events.
+				*/
 			       self.connect(addrs[0].port, addrs[0].name);
 			   }
 		       });
@@ -50,3 +72,122 @@ function Client(params) {
 
 sys.inherits(Client, Connection);
 exports.Client = Client;
+
+Client.prototype.onRawStanza = function(stanza) {
+    /* Actually, we shouldn't wait for <stream:features/> if
+       this.streamAttrs.version is missing, but who uses pre-XMPP-1.0
+       these days anyway? */
+    if (this.state != STATE_ONLINE &&
+	stanza.name == 'stream:features') {
+	this.streamFeatures = stanza;
+	this.useFeatures();
+    } else if (this.state == STATE_AUTH) {
+	if (stanza.is('success', NS_XMPP_SASL)) {
+	    this.state = STATE_AUTHED;
+	    this.startStream();
+	} else {
+	    this.emit('authFail');
+	    this.end();
+	}
+    } else if (this.state == STATE_BIND &&
+	       stanza.is('iq') &&
+	       stanza.attrs.id == IQID_BIND) {
+	if (stanza.attrs.type == 'result') {
+	    this.state = STATE_AUTHED;
+	    this.did_bind = true;
+
+	    var bindEl = stanza.getChild('bind', NS_XMPP_BIND);
+	    if (bindEl && bindEl.getChild('jid')) {
+		this.jid = new JID(bindEl.getChild('jid').getText());
+	    }
+
+	    /* no stream restart, but next feature */
+	    this.useFeatures();
+	} else {
+	    this.emit('error', 'Cannot bind resource');
+	    this.end();
+	}
+    } else if (this.state == STATE_SESSION &&
+	       stanza.is('iq') &&
+	       stanza.attrs.id == IQID_SESSION) {
+	if (stanza.attrs.type == 'result') {
+	    this.state = STATE_AUTHED;
+	    this.did_session = true;
+
+	    /* no stream restart, but next feature (most probably
+	       we'll go online next) */
+	    this.useFeatures();
+	} else {
+	    this.emit('error', 'Cannot bind resource');
+	    this.end();
+	}
+    } else if (stanza.name == 'stream:error') {
+	this.emit('error', stanza);
+	this.end();
+    }
+};
+
+/**
+ * Either we just received <stream:features/>, or we just enabled a
+ * feature and are looking for the next.
+ */
+Connection.prototype.useFeatures = function() {
+    if (this.state == STATE_PREAUTH &&
+	       this.streamFeatures.getChild('mechanisms', NS_XMPP_SASL)) {
+	this.state = STATE_AUTH;
+	var mech = selectAuthMechanism(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;
+	    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 (this.state == STATE_AUTHED &&
+	       !this.did_bind &&
+	       this.streamFeatures.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);
+    } else if (this.state == STATE_AUTHED &&
+	       !this.did_session &&
+	       this.streamFeatures.getChild('session', NS_XMPP_SESSION)) {
+	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 if (this.state == STATE_AUTHED) {
+	/* Ok, we're authenticated and all features have been
+	   processed */
+	this.state = STATE_ONLINE;
+	this.emit('online');
+    }
+};
+
+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/connection.js b/lib/xmpp/connection.js
index e671ede..af14f8f 100644
--- a/lib/xmpp/connection.js
+++ b/lib/xmpp/connection.js
@@ -2,29 +2,16 @@ var net = require('net');
 var sys = require('sys');
 var expat = require('expat');
 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_TLS = 1,
-    STATE_AUTH = 2,
-    STATE_AUTHED = 3,
-    STATE_BIND = 4,
-    STATE_SESSION = 5,
-    STATE_ONLINE = 6;
-var IQID_SESSION = 'sess',
-    IQID_BIND = 'bind';
 
+/** A note on events: this base class will emit 'rawStanza' and leaves
+    'stanza' to Client & Component. Therefore we won't confuse the
+    user with stanzas before authentication has finished.
+*/
 function Connection() {
-    net.Stream.call(this);
+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);
@@ -108,139 +95,26 @@ Connection.prototype.onData = function(data) {
 };
 
 /**
- * This is not an event listener, but takes care of the authentication
- * before 'stanza' events are emitted to the user.
+ * This is not an event listener, but takes care of the TLS handshake
+ * before 'rawStanza' events are emitted to the derived classes.
  */
 Connection.prototype.onStanza = function(stanza) {
-    if (this.state == STATE_ONLINE) {
-	this.emit('stanza', this.element);
-    } else if (stanza.name == 'stream:features') {
-	this.streamFeatures = stanza;
-	this.useFeatures();
-    } else if (this.state == STATE_TLS) {
-	if (stanza.is('proceed', NS_XMPP_TLS)) {
-	    this.setSecure();
-	    this.addListener('secure',
-			     function() {
-				 this.state = STATE_PREAUTH;
-				 this.startStream();
-			     });
-	} else {
-	    this.emit('error', 'Cannot begin TLS handshake');
-	    this.end();
-	}
-    } else if (this.state == STATE_AUTH) {
-	if (stanza.is('success', NS_XMPP_SASL)) {
-	    this.state = STATE_AUTHED;
-	    this.startStream();
-	} else {
-	    this.emit('authFail');
-	    this.end();
-	}
-    } else if (this.state == STATE_BIND &&
-	       stanza.is('iq') &&
-	       stanza.attrs.id == IQID_BIND) {
-	if (stanza.attrs.type == 'result') {
-	    this.state = STATE_AUTHED;
-	    this.did_bind = true;
-
-	    var bindEl = stanza.getChild('bind', NS_XMPP_BIND);
-	    if (bindEl && bindEl.getChild('jid')) {
-		this.jid = new JID(bindEl.getChild('jid').getText());
-	    }
-
-	    /* no stream restart, but next feature */
-	    this.useFeatures();
-	} else {
-	    this.emit('error', 'Cannot bind resource');
-	    this.end();
-	}
-    } else if (this.state == STATE_SESSION &&
-	       stanza.is('iq') &&
-	       stanza.attrs.id == IQID_SESSION) {
-	if (stanza.attrs.type == 'result') {
-	    this.state = STATE_AUTHED;
-	    this.did_session = true;
-
-	    /* no stream restart, but next feature (most probably
-	       we'll go online next) */
-	    this.useFeatures();
-	} else {
-	    this.emit('error', 'Cannot bind resource');
-	    this.end();
-	}
-    } else if (stanza.name == 'stream:error') {
+    if (stanza.name == 'stream:error') {
+	/* TODO: extract error text */
 	this.emit('error', stanza);
-	this.end();
-    }
-};
-
-/**
- * Either onStanza just received <stream:features/>, or we just
- * enabled a feature and are looking for the next.
- */
-Connection.prototype.useFeatures = function() {
-    if (this.allowTLS &&
-	this.state == STATE_PREAUTH &&
-	this.streamFeatures.getChild('starttls', NS_XMPP_TLS)) {
-	this.state = STATE_TLS;
+    } else if (stanza.name == 'stream:features' &&
+	this.allowTLS &&
+	stanza.getChild('starttls', NS_XMPP_TLS)) {
+	/* Signal willingness to perform TLS handshake */
 	this.send(new xml.Element('starttls', { xmlns: NS_XMPP_TLS }));
-    } else if (this.state == STATE_PREAUTH &&
-	       this.streamFeatures.getChild('mechanisms', NS_XMPP_SASL)) {
-	this.state = STATE_AUTH;
-	var mech = selectAuthMechanism(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;
-	    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 (this.state == STATE_AUTHED &&
-	       !this.did_bind &&
-	       this.streamFeatures.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);
-    } else if (this.state == STATE_AUTHED &&
-	       !this.did_session &&
-	       this.streamFeatures.getChild('session', NS_XMPP_SESSION)) {
-	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 if (this.state == STATE_AUTHED) {
-	/* Ok, we're authenticated and all features have been
-	   processed */
-	this.state = STATE_ONLINE;
-	this.emit('online');
+    } else if (this.allowTLS &&
+	       stanza.is('proceed', NS_XMPP_TLS)) {
+	/* Server is waiting for TLS handshake */
+	this.setSecure();
+	this.addListener('secure', this.startStream);
+    } else {
+	this.emit('rawStanza', stanza);
     }
 };
 
-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;
-}
+

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