Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(48)

Side by Side Diff: remoting/webapp/xmpp_login_handler.js

Issue 514343002: XMPP implementation in JavaScript. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 'use strict';
6
7 /** @suppress {duplicate} */
8 var remoting = remoting || {};
9
10 /**
11 * XmppLoginHandler handles authentication handshake for XmppConnection. It
12 * receives incoming data using onDataReceived() calls |sendMessageCallback|
13 * to send outgoing messages and
Jamie 2014/08/29 02:14:09 Incomplete comment. I think an overview of the pr
Sergey Ulanov 2014/08/29 23:40:30 Added reference to RFC and State description lists
14 *
15 * @param {string} server Domain name of the server we are connecting to.
16 * @param {string} username Username.
17 * @param {string} authToken OAuth2 token.
18 * @param {function(string):void} sendMessageCallback Callback call to send
Jamie 2014/08/29 02:14:09 s/call/to call/
Sergey Ulanov 2014/08/29 23:40:30 Done.
19 * a message.
20 * @param {function():void} startTlsCallback Callback to call to start TLS on
21 * the underlying socket.
Jamie 2014/08/29 02:14:09 Why does this need to be a callback? There's only
Sergey Ulanov 2014/08/29 23:40:30 This class doesn't know anything about the socket.
22 * @param {function(string):void} onHandshakeDoneCallback Callback to call
23 * after authentication is completed successfully
24 * @param {function(Element):void} onStanzaCallback Callback to call for each
25 * incoming stanza (when authenticated).
26 * @param {function(remoting.Error, string):void} onErrorCallback Callback to
27 * call on error. Can be called at any point during lifetime of connection.
28 * @constructor
29 */
30 remoting.XmppLoginHandler = function(server,
31 username,
32 authToken,
33 sendMessageCallback,
34 startTlsCallback,
35 onHandshakeDoneCallback,
36 onStanzaCallback,
37 onErrorCallback) {
38 this.server_ = server;
Jamie 2014/08/29 02:14:09 @private
Sergey Ulanov 2014/08/29 23:40:30 Done.
39 this.username_ = username;
40 this.authToken_ = authToken;
41 this.sendMessageCallback_ = sendMessageCallback;
42 this.startTlsCallback_ = startTlsCallback;
43 this.onHandshakeDoneCallback_ = onHandshakeDoneCallback;
44 this.onStanzaCallback_ = onStanzaCallback;
45 this.onErrorCallback_ = onErrorCallback;
46
47 this.state_ = remoting.XmppLoginHandler.State.INIT;
48 this.jid_ = '';
49
50 /** @type {remoting.XmppStreamParser} */
51 this.streamParser_ = null;
52 }
53
54 /**
55 * @enum {number}
56 */
57 remoting.XmppLoginHandler.State = {
58 INIT: 0,
59 START_SENT: 1,
60 STARTTLS_SENT: 2,
61 STARTING_TLS: 3,
62 START_SENT_AFTER_TLS: 4,
63 AUTH_SENT: 5,
64 AUTH_ACCEPTED: 6,
65 BIND_SENT: 7,
66 SESSION_IQ_SENT: 8,
67 SESSION_ACTIVE: 9,
68 ERROR: 10
69 };
70
71 remoting.XmppLoginHandler.prototype.start = function() {
72 this.state_ = remoting.XmppLoginHandler.State.START_SENT;
73 this.startStream_();
74 }
75
76 /** @param {ArrayBuffer} data */
77 remoting.XmppLoginHandler.prototype.onDataReceived = function(data) {
78 switch (this.state_) {
79 case remoting.XmppLoginHandler.State.INIT:
80 this.onError_(remoting.Error.UNEXPECTED,
81 'Data was received before the stream was started.');
82 break;
83
84 case remoting.XmppLoginHandler.State.ERROR:
85 // Ignore data received in the error state.
86 break;
87
88 default:
89 this.streamParser_.appendData(data);
kelvinp 2014/08/29 01:37:10 Have you consider moving streamParser to XMPPConne
Sergey Ulanov 2014/08/29 23:40:30 The issue here is that streamParser needs to be re
90 break;
91 }
92 }
93
94 /** @param {Element} stanza */
95 remoting.XmppLoginHandler.prototype.onStanza_ = function(stanza) {
96 switch (this.state_) {
97 case remoting.XmppLoginHandler.State.START_SENT:
98 if (stanza.querySelector('features>starttls')) {
99 this.sendMessageCallback_(
100 '<starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>');
101 this.state_ = remoting.XmppLoginHandler.State.STARTTLS_SENT;
102 } else {
103 this.onError_(remoting.Error.UNEXPECTED, "Server doesn't support TLS.");
104 }
105 break;
106
107 case remoting.XmppLoginHandler.State.STARTTLS_SENT:
108 if (stanza.localName == "proceed") {
109 this.state_ = remoting.XmppLoginHandler.State.STARTING_TLS;
110 this.startTlsCallback_();
111 } else {
112 this.onError_(remoting.Error.UNEXPECTED,
113 "Failed to start TLS: " +
114 (new XMLSerializer().serializeToString(stanza)));
115 }
116 break;
117
118 case remoting.XmppLoginHandler.State.START_SENT_AFTER_TLS:
119 var mechanisms = Array.prototype.map.call(
120 stanza.querySelectorAll('features>mechanisms>mechanism'),
121 /** @param {Element} m */
122 function(m) { return m.textContent; });
123 if (mechanisms.indexOf("X-OAUTH2")) {
124 this.onError_(remoting.Error.UNEXPECTED,
125 "OAuth2 is not supported by the server.");
126 return;
127 }
128
129 var cookie = window.btoa("\0" + this.username_ + "\0" + this.authToken_);
130
131 this.state_ = remoting.XmppLoginHandler.State.AUTH_SENT;
132 this.sendMessageCallback_(
133 '<auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" ' +
Jamie 2014/08/29 02:14:09 When constructing XML hierarchies from string lite
Sergey Ulanov 2014/08/29 23:40:30 Done.
134 'mechanism="X-OAUTH2" auth:service="oauth2" ' +
135 'auth:allow-generated-jid="true" ' +
136 'auth:client-uses-full-bind-result="true" ' +
137 'auth:allow-non-google-login="true" ' +
138 'xmlns:auth="http://www.google.com/talk/protocol/auth">' +
139 cookie + '</auth>');
140 break;
141
142 case remoting.XmppLoginHandler.State.AUTH_SENT:
143 if (stanza.localName == 'success') {
144 this.state_ = remoting.XmppLoginHandler.State.AUTH_ACCEPTED;
145 this.startStream_();
146 } else {
147 this.onError_(remoting.Error.AUTHENTICATION_FAILED,
148 'Failed to authenticate: ' +
149 (new XMLSerializer().serializeToString(stanza)));
150 }
151 break;
152
153 case remoting.XmppLoginHandler.State.AUTH_ACCEPTED:
154 if (stanza.querySelector('features>bind')) {
155 this.sendMessageCallback_(
156 '<iq type="set" id="0">' +
157 '<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind">' +
158 '<resource>chromoting</resource></bind></iq>');
159 this.state_ = remoting.XmppLoginHandler.State.BIND_SENT;
160 } else {
161 this.onError_(remoting.Error.UNEXPECTED,
162 'Server doesn\'t support bind after authentication.');
Jamie 2014/08/29 02:14:09 You can use double-quotes if the string has an apo
Sergey Ulanov 2014/08/29 23:40:30 Done.
163 }
164 break;
165
166 case remoting.XmppLoginHandler.State.BIND_SENT:
167 var jidElement = stanza.querySelector('iq>bind>jid');
168 if (!jidElement)
Jamie 2014/08/29 02:14:09 This is indented badly, and very confusing without
Sergey Ulanov 2014/08/29 23:40:30 Actually this |if| doesn't even need to be here.
169 if (stanza.getAttribute('id') != '0' ||
170 stanza.getAttribute('type') != 'result' || !jidElement) {
171 this.onError_(remoting.Error.UNEXPECTED,
172 'Received unexpected response to bind: ' +
173 (new XMLSerializer().serializeToString(stanza)));
174 return;
175 }
176 this.jid_ = jidElement.textContent;
177 this.sendMessageCallback_(
178 '<iq type="set" id="1">' +
179 '<session xmlns="urn:ietf:params:xml:ns:xmpp-session"/></iq>');
180 this.state_ = remoting.XmppLoginHandler.State.SESSION_IQ_SENT;
181 break;
182
183 case remoting.XmppLoginHandler.State.SESSION_IQ_SENT:
184 if (stanza.getAttribute('id') != '1' ||
185 stanza.getAttribute('type') != 'result') {
186 this.onError_(remoting.Error.UNEXPECTED,
187 'Failed to start session: ' +
188 (new XMLSerializer().serializeToString(stanza)));
189 return;
190 }
191 this.state_ = remoting.XmppLoginHandler.State.SESSION_ACTIVE;
192 this.onHandshakeDoneCallback_(this.jid_);
193 break;
194
195 case remoting.XmppLoginHandler.State.SESSION_ACTIVE:
196 this.onStanzaCallback_(stanza);
197 break;
198 }
199 }
200
201 /** @param {string} text */
202 remoting.XmppLoginHandler.prototype.onParserError_ = function(text) {
203 this.onError_(remoting.Error.UNEXPECTED, text);
204 }
205
206 remoting.XmppLoginHandler.prototype.onTlsStarted = function() {
207 base.debug.assert(this.state_ ==
208 remoting.XmppLoginHandler.State.STARTING_TLS);
209 this.state_ = remoting.XmppLoginHandler.State.START_SENT_AFTER_TLS;
210 this.startStream_();
211 };
212
213 remoting.XmppLoginHandler.prototype.startStream_ = function() {
214 this.sendMessageCallback_('<stream:stream to="' + this.server_ +
215 '" version="1.0" xmlns="jabber:client" ' +
216 'xmlns:stream="http://etherx.jabber.org/streams">');
217 this.streamParser_ =
218 new remoting.XmppStreamParser(this.onStanza_.bind(this),
219 this.onParserError_.bind(this));
220 }
221
222 /**
223 * @param {remoting.Error} error
224 * @param {string} text
225 */
226 remoting.XmppLoginHandler.prototype.onError_ = function(error, text) {
227 if (this.state_ != remoting.XmppLoginHandler.State.ERROR) {
228 this.onErrorCallback_(error, text);
229 this.state_ = remoting.XmppLoginHandler.State.ERROR;
230 } else {
231 console.error(text);
232 }
233 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698