comparison lightstring.js @ 27:b6e4bc19ff5a

undoing
author Sonny Piers <sonny.piers@gmail.com>
date Sat, 28 Jan 2012 01:27:00 +0100
parents 119ceb121908
children 630b9579fe4a
comparison
equal deleted inserted replaced
19:fc577e5b2f4a 27:b6e4bc19ff5a
33 */ 33 */
34 stanza: { 34 stanza: {
35 stream: { 35 stream: {
36 open: function(aService) { 36 open: function(aService) {
37 //FIXME no ending "/" - node-xmpp-bosh bug 37 //FIXME no ending "/" - node-xmpp-bosh bug
38 return "<stream:stream to='" + aService + "'\ 38 return "<stream:stream to='" + aService + "'" +
39 xmlns='" + Lightstring.NS.jabberClient + "'\ 39 " xmlns='" + Lightstring.NS.jabberClient + "'" +
40 xmlns:stream='" + Lightstring.NS.stream + "'\ 40 " xmlns:stream='" + Lightstring.NS.stream + "'" +
41 version='1.0'/>"; 41 " version='1.0'/>";
42 }, 42 },
43 close: function() { 43 close: function() {
44 return '</stream:stream>'; 44 return "</stream:stream>";
45 } 45 }
46 } 46 }
47 }, 47 },
48 /** 48 /**
49 * @private 49 * @private
96 96
97 97
98 //FIXME support SCRAM-SHA1 && allow specify method preferences 98 //FIXME support SCRAM-SHA1 && allow specify method preferences
99 if ('DIGEST-MD5' in mechanisms) 99 if ('DIGEST-MD5' in mechanisms)
100 that.send( 100 that.send(
101 "<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl'\ 101 "<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl'" +
102 mechanism='DIGEST-MD5'/>" 102 " mechanism='DIGEST-MD5'/>"
103 ); 103 );
104 else if ('PLAIN' in mechanisms) { 104 else if ('PLAIN' in mechanisms) {
105 var token = btoa( 105 var token = btoa(
106 that.jid + 106 that.jid +
107 '\u0000' + 107 '\u0000' +
108 that.jid.node + 108 that.jid.node +
109 '\u0000' + 109 '\u0000' +
110 that.password 110 that.password
111 ); 111 );
112 that.send( 112 that.send(
113 "<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl'\ 113 "<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl'" +
114 mechanism='PLAIN'>" + token + '</auth>' 114 " mechanism='PLAIN'>" + token + "</auth>"
115 ); 115 );
116 } 116 }
117 } 117 }
118 //XMPP features 118 //XMPP features
119 else { 119 else {
120 that.emit('features', stanza); 120 that.emit('features', stanza);
121 //Bind http://xmpp.org/rfcs/rfc3920.html#bind 121 //Bind http://xmpp.org/rfcs/rfc3920.html#bind
122 var bind =
123 "<iq type='set' xmlns='jabber:client'>" +
124 "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>" +
125 (that.jid.resource? "<resource>" + that.jid.resource + "</resource>": "") +
126 "</bind>" +
127 "</iq>";
122 that.send( 128 that.send(
123 "<iq type='set' xmlns='jabber:client'>\ 129 bind,
124 <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/>\ 130 function(stanza) {
125 </iq>", 131 //Session http://xmpp.org/rfcs/rfc3921.html#session
126 function() { 132 that.jid = new Lightstring.JID(stanza.textContent);
127 //Session http://xmpp.org/rfcs/rfc3921.html#session 133 that.send(
128 that.send( 134 "<iq type='set' xmlns='jabber:client'>" +
129 "<iq type='set' xmlns='jabber:client'>\ 135 "<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>" +
130 <session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>\ 136 "</iq>",
131 </iq>", 137 function() {
132 function() { 138 that.emit('connected');
133 that.emit('connected'); 139 }
134 } 140 );
135 ); 141 }
136 }); 142 );
137 } 143 }
138 }); 144 });
139 this.on('success', function(stanza, that) { 145 this.on('success', function(stanza, that) {
140 that.send( 146 that.send(
141 "<stream:stream to='" + that.host + "'\ 147 "<stream:stream to='" + that.jid.domain + "'" +
142 xmlns='jabber:client'\ 148 " xmlns='jabber:client'" +
143 xmlns:stream='http://etherx.jabber.org/streams'\ 149 " xmlns:stream='http://etherx.jabber.org/streams'" +
144 version='1.0' />" 150 " version='1.0'/>"
145 ); 151 );
146 }); 152 });
147 this.on('failure', function(stanza, that) { 153 this.on('failure', function(stanza, that) {
148 that.emit('conn-error', stanza.firstChild.tagName); 154 that.emit('conn-error', stanza.firstChild.tagName);
149 }); 155 });
183 host = matches[2]; 189 host = matches[2];
184 break; 190 break;
185 } 191 }
186 } 192 }
187 193
188 var digest_uri = 'xmpp/' + that.host; 194 var digest_uri = 'xmpp/' + that.jid.domain;
189 if (host !== null) { 195 if (host !== null)
190 digest_uri = digest_uri + '/' + host; 196 digest_uri = digest_uri + '/' + host;
191 } 197 var A1 = MD5.hash(that.jid.node +
192 var A1 = MD5.hash(that.node +
193 ':' + realm + ':' + that.password) + 198 ':' + realm + ':' + that.password) +
194 ':' + nonce + ':' + cnonce; 199 ':' + nonce + ':' + cnonce;
195 var A2 = 'AUTHENTICATE:' + digest_uri; 200 var A2 = 'AUTHENTICATE:' + digest_uri;
196 201
197 var responseText = ''; 202 var responseText = '';
198 responseText += 'username=' + _quote(that.node) + ','; 203 responseText += 'username=' + _quote(that.jid.node) + ',';
199 responseText += 'realm=' + _quote(realm) + ','; 204 responseText += 'realm=' + _quote(realm) + ',';
200 responseText += 'nonce=' + _quote(nonce) + ','; 205 responseText += 'nonce=' + _quote(nonce) + ',';
201 responseText += 'cnonce=' + _quote(cnonce) + ','; 206 responseText += 'cnonce=' + _quote(cnonce) + ',';
202 responseText += 'nc="00000001",'; 207 responseText += 'nc="00000001",';
203 responseText += 'qop="auth",'; 208 responseText += 'qop="auth",';
207 nonce + ':00000001:' + 212 nonce + ':00000001:' +
208 cnonce + ':auth:' + 213 cnonce + ':auth:' +
209 MD5.hexdigest(A2))) + ','; 214 MD5.hexdigest(A2))) + ',';
210 responseText += 'charset="utf-8"'; 215 responseText += 'charset="utf-8"';
211 that.send( 216 that.send(
212 "<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>" 217 "<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>" +
213 + btoa(responseText) + 218 btoa(responseText) +
214 '</response>'); 219 "</response>");
215 }); 220 });
216 }; 221 };
217 Lightstring.Connection.prototype = { 222 Lightstring.Connection.prototype = {
218 /** 223 /**
219 * @function Create and open a websocket then go though the XMPP authentification process. 224 * @function Create and open a websocket then go though the XMPP authentification process.
220 * @param {String} [aJid] The JID (Jabber id) to use. 225 * @param {String} [aJid] The JID (Jabber id) to use.
221 * @param {String} [aPassword] The associated password. 226 * @param {String} [aPassword] The associated password.
222 */ 227 */
223 connect: function(aJid, aPassword) { 228 connect: function(aJid, aPassword) {
224 this.emit('connecting'); 229 this.emit('connecting');
225 if (aJid) 230 this.jid = new Lightstring.JID(aJid);
226 this.jid = aJid;
227 if (this.jid) {
228 this.host = this.jid.split('@')[1];
229 this.node = this.jid.split('@')[0];
230 this.resource = this.jid.split('/')[1];
231 }
232 if (aPassword) 231 if (aPassword)
233 this.password = aPassword; 232 this.password = aPassword;
234 233
235 if (!this.jid) 234 if (!this.jid.bare)
236 throw 'Lightstring: Connection.jid is undefined.'; 235 throw 'Lightstring: Connection.jid is undefined.';
237 if (!this.password) 236 if (!this.password)
238 throw 'Lightstring: Connection.password is undefined.'; 237 throw 'Lightstring: Connection.password is undefined.';
239 if (!this.service) 238 if (!this.service)
240 throw 'Lightstring: Connection.service is undefined.'; 239 throw 'Lightstring: Connection.service is undefined.';
250 var that = this; 249 var that = this;
251 this.socket.addEventListener('open', function() { 250 this.socket.addEventListener('open', function() {
252 if (this.protocol !== 'xmpp') 251 if (this.protocol !== 'xmpp')
253 console.error('Lightstring: The server located at '+ that.service + ' doesn\'t seems to be XMPP aware.'); 252 console.error('Lightstring: The server located at '+ that.service + ' doesn\'t seems to be XMPP aware.');
254 253
255 var stream = Lightstring.stanza.stream.open(that.host); 254 var stream = Lightstring.stanza.stream.open(that.jid.domain);
256 255
257 that.socket.send(stream); 256 that.socket.send(stream);
258 that.emit('XMLOutput', stream); 257 that.emit('XMLOutput', stream);
259 }); 258 });
260 this.socket.addEventListener('error', function(e) { 259 this.socket.addEventListener('error', function(e) {
268 that.emit('XMLInput', e.data); 267 that.emit('XMLInput', e.data);
269 var elm = Lightstring.xml2dom(e.data); 268 var elm = Lightstring.xml2dom(e.data);
270 that.emit('DOMInput', elm); 269 that.emit('DOMInput', elm);
271 that.emit(elm.tagName, elm); 270 that.emit(elm.tagName, elm);
272 271
272 <<<<<<< HEAD
273 if (elm.tagName === 'iq') 273 if (elm.tagName === 'iq')
274 that.emit(elm.getAttribute('id'), elm); 274 that.emit(elm.getAttribute('id'), elm);
275 =======
276 if (elm.tagName === 'iq') {
277 var payload = elm.firstChild;
278 if (payload)
279 that.emit('iq/' + payload.namespaceURI + ':' + payload.localName, elm);
280 that.emit(elm.getAttribute('id'), elm); //FIXME: possible attack vector.
281 }
282 >>>>>>> f6a7c0f93d154c2cd34dfdda4ab8eec808b91b34
275 }); 283 });
276 }, 284 },
277 /** 285 /**
278 * @function Send a message. 286 * @function Send a message.
279 * @param {String|Object} aStanza The message to send. 287 * @param {String|Object} aStanza The message to send.
301 str = Lightstring.dom2xml(elm); 309 str = Lightstring.dom2xml(elm);
302 } 310 }
303 if (aCallback) 311 if (aCallback)
304 this.on(elm.getAttribute('id'), aCallback); 312 this.on(elm.getAttribute('id'), aCallback);
305 } 313 }
306 else if (aCallback) { 314 else if (aCallback)
307 this.emit('warning', 'Callback can\'t be called with non-iq stanza.'); 315 this.emit('warning', 'Callback can\'t be called with non-iq stanza.');
308 }
309 316
310 317
311 this.socket.send(str); 318 this.socket.send(str);
312 this.emit('XMLOutput', str); 319 this.emit('XMLOutput', str);
313 this.emit('DOMOutput', elm); 320 this.emit('DOMOutput', elm);