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

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
14 *
15 * @param {string} username Username.
16 * @param {string} authToken OAuth2 token.
17 * @param {function(string):void} sendMessageCallback Callback call to send
18 * a message.
19 * @param {function():void} startTlsCallback Callback to call to start TLS on
20 * the underlying socket.
21 * @param {function(string):void} onHandshakeDoneCallback Callback to call
22 * after authentication is completed successfully
23 * @param {function(Element):void} onStanzaCallback Callback to call for each
24 * incoming stanza (when authenticated).
25 * @param {function(remoting.Error, string):void} onErrorCallback Callback to
26 * call on error. Can be called at any point during lifetime of connection.
27 * @constructor
28 */
29 remoting.XmppLoginHandler = function(username,
30 authToken,
31 sendMessageCallback,
32 startTlsCallback,
33 onHandshakeDoneCallback,
34 onStanzaCallback,
35 onErrorCallback) {
36 this.username_ = username;
37 this.authToken_ = authToken;
38 this.sendMessageCallback_ = sendMessageCallback;
39 this.startTlsCallback_ = startTlsCallback;
40 this.onHandshakeDoneCallback_ = onHandshakeDoneCallback;
41 this.onStanzaCallback_ = onStanzaCallback;
42 this.onErrorCallback_ = onErrorCallback;
43
44 this.state_ = remoting.XmppLoginHandler.State.INIT;
45 this.jid_ = '';
46
47 /** @type {remoting.XmppStreamParser} */
48 this.streamParser_ = null;
49 }
50
51 /**
52 * @enum {number}
53 */
54 remoting.XmppLoginHandler.State = {
55 INIT: 0,
56 START_SENT: 1,
57 STARTTLS_SENT: 2,
58 STARTING_TLS: 3,
59 START_SENT_AFTER_TLS: 4,
60 AUTH_SENT: 5,
61 AUTH_ACCEPTED: 6,
62 BIND_SENT: 7,
63 SESSION_IQ_SENT: 8,
64 SESSION_ACTIVE: 9,
65 ERROR: 10
66 };
67
68 remoting.XmppLoginHandler.prototype.start = function() {
69 this.state_ = remoting.XmppLoginHandler.State.START_SENT;
70 this.startStream_();
71 }
72
73 /** @param {ArrayBuffer} data */
74 remoting.XmppLoginHandler.prototype.onDataReceived = function(data) {
75 switch (this.state_) {
76 case remoting.XmppLoginHandler.State.INIT:
77 this.onError_(remoting.Error.UNEXPECTED,
78 'Data was received before the stream was started.');
79 break;
80
81 case remoting.XmppLoginHandler.State.ERROR:
82 // Ignore data received in the error state.
83 break;
84
85 default:
86 this.streamParser_.appendData(data);
87 break;
88 }
89 }
90
91 /** @param {Element} stanza */
92 remoting.XmppLoginHandler.prototype.onStanza_ = function(stanza) {
93 switch (this.state_) {
94 case remoting.XmppLoginHandler.State.START_SENT:
95 if (stanza.querySelector('features>starttls')) {
96 this.sendMessageCallback_(
97 '<starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>');
98 this.state_ = remoting.XmppLoginHandler.State.STARTTLS_SENT;
99 } else {
100 this.onError_(remoting.Error.UNEXPECTED, "Server doesn't support TLS.");
101 }
102 break;
103
104 case remoting.XmppLoginHandler.State.STARTTLS_SENT:
105 if (stanza.localName == "proceed") {
106 this.state_ = remoting.XmppLoginHandler.State.STARTING_TLS;
107 this.startTlsCallback_();
108 } else {
109 this.onError_(remoting.Error.UNEXPECTED,
110 "Failed to start TLS: " +
111 (new XMLSerializer().serializeToString(stanza)));
112 }
113 break;
114
115 case remoting.XmppLoginHandler.State.START_SENT_AFTER_TLS:
116 var mechanisms = Array.prototype.map.call(
117 stanza.querySelectorAll('features>mechanisms>mechanism'),
118 /** @param {Element} m */
119 function(m) { return m.textContent; });
120 if (mechanisms.indexOf("X-OAUTH2")) {
121 this.onError_(remoting.Error.UNEXPECTED,
122 "OAuth2 is not supported by the server.");
123 return;
124 }
125
126 var cookie = window.btoa("\0" + this.username_ + "\0" + this.authToken_);
127
128 this.state_ = remoting.XmppLoginHandler.State.AUTH_SENT;
129 this.sendMessageCallback_(
130 '<auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" ' +
131 'mechanism="X-OAUTH2" auth:service="oauth2" ' +
132 'auth:allow-generated-jid="true" ' +
133 'auth:client-uses-full-bind-result="true" ' +
134 'auth:allow-non-google-login="true" ' +
135 'xmlns:auth="http://www.google.com/talk/protocol/auth">' +
136 cookie + '</auth>');
137 break;
138
139 case remoting.XmppLoginHandler.State.AUTH_SENT:
140 if (stanza.localName == 'success') {
141 this.state_ = remoting.XmppLoginHandler.State.AUTH_ACCEPTED;
142 this.startStream_();
143 } else {
144 this.onError_(remoting.Error.AUTHENTICATION_FAILED,
145 'Failed to authenticate: ' +
146 (new XMLSerializer().serializeToString(stanza)));
147 }
148 break;
149
150 case remoting.XmppLoginHandler.State.AUTH_ACCEPTED:
151 if (stanza.querySelector('features>bind')) {
152 this.sendMessageCallback_(
153 '<iq type="set" id="0">' +
154 '<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind">' +
155 '<resource>chromoting</resource></bind></iq>');
156 this.state_ = remoting.XmppLoginHandler.State.BIND_SENT;
157 } else {
158 this.onError_(remoting.Error.UNEXPECTED,
159 'Server doesn\'t support bind after authentication.');
160 }
161 break;
162
163 case remoting.XmppLoginHandler.State.BIND_SENT:
164 var jidElement = stanza.querySelector('iq>bind>jid');
165 if (!jidElement)
166 if (stanza.getAttribute('id') != '0' ||
167 stanza.getAttribute('type') != 'result' || !jidElement) {
168 this.onError_(remoting.Error.UNEXPECTED,
169 'Received unexpected response to bind: ' +
170 (new XMLSerializer().serializeToString(stanza)));
171 return;
172 }
173 this.jid_ = jidElement.textContent;
174 this.sendMessageCallback_(
175 '<iq type="set" id="1">' +
176 '<session xmlns="urn:ietf:params:xml:ns:xmpp-session"/></iq>');
177 this.state_ = remoting.XmppLoginHandler.State.SESSION_IQ_SENT;
178 break;
179
180 case remoting.XmppLoginHandler.State.SESSION_IQ_SENT:
181 if (stanza.getAttribute('id') != '1' ||
182 stanza.getAttribute('type') != 'result') {
183 this.onError_(remoting.Error.UNEXPECTED,
184 'Failed to start session: ' +
185 (new XMLSerializer().serializeToString(stanza)));
186 return;
187 }
188 this.state_ = remoting.XmppLoginHandler.State.SESSION_ACTIVE;
189 this.onHandshakeDoneCallback_(this.jid_);
190 break;
191
192 case remoting.XmppLoginHandler.State.SESSION_ACTIVE:
193 this.onStanzaCallback_(stanza);
194 break;
195 }
196 }
197
198 /** @param {string} text */
199 remoting.XmppLoginHandler.prototype.onParserError_ = function(text) {
200 this.onError_(remoting.Error.UNEXPECTED, text);
201 }
202
203 remoting.XmppLoginHandler.prototype.onTlsStarted = function() {
204 base.debug.assert(this.state_ ==
205 remoting.XmppLoginHandler.State.STARTING_TLS);
206 this.state_ = remoting.XmppLoginHandler.State.START_SENT_AFTER_TLS;
207 this.startStream_();
208 };
209
210 remoting.XmppLoginHandler.prototype.startStream_ = function() {
211 var server = this.username_.split('@', 2)[1];
212 this.sendMessageCallback_('<stream:stream to="' + server +
213 '" version="1.0" xmlns="jabber:client" ' +
214 'xmlns:stream="http://etherx.jabber.org/streams">');
215 this.streamParser_ =
216 new remoting.XmppStreamParser(this.onStanza_.bind(this),
217 this.onParserError_.bind(this));
218 }
219
220 /**
221 * @param {remoting.Error} error
222 * @param {string} text
223 */
224 remoting.XmppLoginHandler.prototype.onError_ = function(error, text) {
225 if (this.state_ != remoting.XmppLoginHandler.State.ERROR) {
226 this.onErrorCallback_(error, text);
227 this.state_ = remoting.XmppLoginHandler.State.ERROR;
228 } else {
229 console.error(text);
230 }
231 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698