OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * @fileoverview | 6 * @fileoverview |
7 * Connect set-up state machine for Me2Me and IT2Me | 7 * Connect set-up state machine for Me2Me and IT2Me |
8 */ | 8 */ |
9 | 9 |
10 'use strict'; | 10 'use strict'; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
48 | 48 |
49 /** @private {function(remoting.Error):void} */ | 49 /** @private {function(remoting.Error):void} */ |
50 this.onConnectionFailed_ = onConnectionFailed; | 50 this.onConnectionFailed_ = onConnectionFailed; |
51 | 51 |
52 /** @private {Array<string>} */ | 52 /** @private {Array<string>} */ |
53 this.requiredCapabilities_ = requiredCapabilities; | 53 this.requiredCapabilities_ = requiredCapabilities; |
54 | 54 |
55 /** @private {string} */ | 55 /** @private {string} */ |
56 this.defaultRemapKeys_ = defaultRemapKeys; | 56 this.defaultRemapKeys_ = defaultRemapKeys; |
57 | 57 |
58 /** @private {string} */ | |
59 this.clientJid_ = ''; | |
60 | |
61 /** @private {remoting.DesktopConnectedView.Mode} */ | 58 /** @private {remoting.DesktopConnectedView.Mode} */ |
62 this.connectionMode_ = remoting.DesktopConnectedView.Mode.ME2ME; | 59 this.connectionMode_ = remoting.DesktopConnectedView.Mode.ME2ME; |
63 | 60 |
64 /** @private {remoting.SignalStrategy} */ | 61 /** @private {remoting.SignalStrategy} */ |
65 this.signalStrategy_ = null; | 62 this.signalStrategy_ = null; |
66 | 63 |
67 /** @private {remoting.SmartReconnector} */ | 64 /** @private {remoting.SmartReconnector} */ |
68 this.reconnector_ = null; | 65 this.reconnector_ = null; |
69 | 66 |
70 /** @private */ | 67 /** @private */ |
(...skipping 12 matching lines...) Expand all Loading... |
83 remoting.SessionConnectorImpl.prototype.reset = function() { | 80 remoting.SessionConnectorImpl.prototype.reset = function() { |
84 /** @private {remoting.Host} */ | 81 /** @private {remoting.Host} */ |
85 this.host_ = null; | 82 this.host_ = null; |
86 | 83 |
87 /** @private {boolean} */ | 84 /** @private {boolean} */ |
88 this.logHostOfflineErrors_ = false; | 85 this.logHostOfflineErrors_ = false; |
89 | 86 |
90 /** @private {remoting.ClientSession} */ | 87 /** @private {remoting.ClientSession} */ |
91 this.clientSession_ = null; | 88 this.clientSession_ = null; |
92 | 89 |
93 /** @private {XMLHttpRequest} */ | 90 /** @private {remoting.CredentialsProvider} */ |
94 this.pendingXhr_ = null; | |
95 | |
96 /** @type {remoting.CredentialsProvider} */ | |
97 this.credentialsProvider_ = null; | 91 this.credentialsProvider_ = null; |
98 }; | 92 }; |
99 | 93 |
100 /** | 94 /** |
101 * Initiate a Me2Me connection. | 95 * Initiate a Me2Me connection. |
102 * | 96 * |
103 * This doesn't report host-offline errors because the connection will | 97 * This doesn't report host-offline errors because the connection will |
104 * be retried and retryConnectMe2Me is responsible for reporting these errors. | 98 * be retried and retryConnectMe2Me is responsible for reporting these errors. |
105 * | 99 * |
106 * @param {remoting.Host} host The Me2Me host to which to connect. | 100 * @param {remoting.Host} host The Me2Me host to which to connect. |
107 * @param {function(boolean, function(string):void):void} fetchPin Function to | 101 * @param {function(boolean, function(string):void):void} fetchPin Function to |
108 * interactively obtain the PIN from the user. | 102 * interactively obtain the PIN from the user. |
109 * @param {string} clientPairingId The client id issued by the host when | 103 * @param {string} clientPairingId The client id issued by the host when |
110 * this device was paired, if it is already paired. | 104 * this device was paired, if it is already paired. |
111 * @param {string} clientPairedSecret The shared secret issued by the host when | 105 * @param {string} clientPairedSecret The shared secret issued by the host when |
112 * this device was paired, if it is already paired. | 106 * this device was paired, if it is already paired. |
113 * @return {void} Nothing. | 107 * @return {void} Nothing. |
114 */ | 108 */ |
115 remoting.SessionConnectorImpl.prototype.connectMe2Me = | 109 remoting.SessionConnectorImpl.prototype.connectMe2Me = |
116 function(host, fetchPin, fetchThirdPartyToken, | 110 function(host, fetchPin, fetchThirdPartyToken, |
117 clientPairingId, clientPairedSecret) { | 111 clientPairingId, clientPairedSecret) { |
118 this.connectionMode_ = remoting.DesktopConnectedView.Mode.ME2ME; | |
119 this.logHostOfflineErrors_ = false; | 112 this.logHostOfflineErrors_ = false; |
120 var credentialsProvider = new remoting.CredentialsProvider({ | 113 var credentialsProvider = new remoting.CredentialsProvider({ |
121 fetchPin: fetchPin, | 114 fetchPin: fetchPin, |
122 pairingInfo: { id: clientPairingId, secret: clientPairedSecret }, | 115 pairingInfo: { id: clientPairingId, secret: clientPairedSecret }, |
123 fetchThirdPartyToken: fetchThirdPartyToken | 116 fetchThirdPartyToken: fetchThirdPartyToken |
124 }); | 117 }); |
125 this.connectInternal_(host, credentialsProvider); | 118 this.connect( |
| 119 remoting.DesktopConnectedView.Mode.ME2ME, host, credentialsProvider); |
126 }; | 120 }; |
127 | 121 |
128 /** | 122 /** |
129 * Retry connecting to a Me2Me host after a connection failure. | 123 * Retry connecting to a Me2Me host after a connection failure. |
130 * | 124 * |
131 * This is the same as connectMe2Me except that is will log errors if the | 125 * This is the same as connectMe2Me except that is will log errors if the |
132 * host is offline. | 126 * host is offline. |
133 * | 127 * |
134 * @param {remoting.Host} host The Me2Me host to refresh. | 128 * @param {remoting.Host} host The Me2Me host to refresh. |
135 * @return {void} Nothing. | 129 * @return {void} Nothing. |
136 */ | 130 */ |
137 remoting.SessionConnectorImpl.prototype.retryConnectMe2Me = function(host) { | 131 remoting.SessionConnectorImpl.prototype.retryConnectMe2Me = function(host) { |
138 this.connectionMode_ = remoting.DesktopConnectedView.Mode.ME2ME; | |
139 this.logHostOfflineErrors_ = true; | 132 this.logHostOfflineErrors_ = true; |
140 this.connectInternal_(host, this.credentialsProvider_); | 133 this.connect(remoting.DesktopConnectedView.Mode.ME2ME, host, |
| 134 this.credentialsProvider_); |
141 }; | 135 }; |
142 | 136 |
143 /** | 137 /** |
144 * Initiate a Me2App connection. | 138 * Initiate a Me2App connection. |
145 * | 139 * |
146 * @param {remoting.Host} host The Me2Me host to which to connect. | 140 * @param {remoting.Host} host The Me2Me host to which to connect. |
147 * @param {function(string, string, string, | 141 * @param {function(string, string, string, |
148 * function(string, string): void): void} | 142 * function(string, string): void): void} |
149 * fetchThirdPartyToken Function to obtain a token from a third party | 143 * fetchThirdPartyToken Function to obtain a token from a third party |
150 * authenticaiton server. | 144 * authenticaiton server. |
151 * @return {void} Nothing. | 145 * @return {void} Nothing. |
152 */ | 146 */ |
153 remoting.SessionConnectorImpl.prototype.connectMe2App = | 147 remoting.SessionConnectorImpl.prototype.connectMe2App = |
154 function(host, fetchThirdPartyToken) { | 148 function(host, fetchThirdPartyToken) { |
155 this.connectionMode_ = remoting.DesktopConnectedView.Mode.APP_REMOTING; | 149 this.connectionMode_ = remoting.DesktopConnectedView.Mode.APP_REMOTING; |
156 this.logHostOfflineErrors_ = true; | 150 this.logHostOfflineErrors_ = true; |
157 var credentialsProvider = new remoting.CredentialsProvider({ | 151 var credentialsProvider = new remoting.CredentialsProvider({ |
158 fetchThirdPartyToken : fetchThirdPartyToken | 152 fetchThirdPartyToken : fetchThirdPartyToken |
159 }); | 153 }); |
160 this.connectInternal_(host, credentialsProvider); | 154 this.connect( |
| 155 remoting.DesktopConnectedView.Mode.APP_REMOTING, host, |
| 156 credentialsProvider); |
161 }; | 157 }; |
162 | 158 |
163 /** | 159 /** |
164 * Update the pairing info so that the reconnect function will work correctly. | 160 * Update the pairing info so that the reconnect function will work correctly. |
165 * | 161 * |
166 * @param {string} clientId The paired client id. | 162 * @param {string} clientId The paired client id. |
167 * @param {string} sharedSecret The shared secret. | 163 * @param {string} sharedSecret The shared secret. |
168 */ | 164 */ |
169 remoting.SessionConnectorImpl.prototype.updatePairingInfo = | 165 remoting.SessionConnectorImpl.prototype.updatePairingInfo = |
170 function(clientId, sharedSecret) { | 166 function(clientId, sharedSecret) { |
171 var pairingInfo = this.credentialsProvider_.getPairingInfo(); | 167 var pairingInfo = this.credentialsProvider_.getPairingInfo(); |
172 pairingInfo.id = clientId; | 168 pairingInfo.id = clientId; |
173 pairingInfo.secret = sharedSecret; | 169 pairingInfo.secret = sharedSecret; |
174 }; | 170 }; |
175 | 171 |
176 /** | 172 /** |
177 * Initiates a connection. | 173 * Initiates a connection. |
178 * | 174 * |
| 175 * @param {remoting.DesktopConnectedView.Mode} mode |
179 * @param {remoting.Host} host the Host to connect to. | 176 * @param {remoting.Host} host the Host to connect to. |
180 * @param {remoting.CredentialsProvider} credentialsProvider | 177 * @param {remoting.CredentialsProvider} credentialsProvider |
181 * @return {void} Nothing. | 178 * @return {void} Nothing. |
182 * @private | 179 * @private |
183 */ | 180 */ |
184 remoting.SessionConnectorImpl.prototype.connectInternal_ = | 181 remoting.SessionConnectorImpl.prototype.connect = |
185 function(host, credentialsProvider) { | 182 function(mode, host, credentialsProvider) { |
186 // Cancel any existing connect operation. | 183 // Cancel any existing connect operation. |
187 this.cancel(); | 184 this.cancel(); |
188 | 185 this.connectionMode_ = mode; |
189 this.host_ = host; | 186 this.host_ = host; |
190 this.credentialsProvider_ = credentialsProvider; | 187 this.credentialsProvider_ = credentialsProvider; |
191 this.connectSignaling_(); | 188 this.connectSignaling_(); |
192 }; | 189 }; |
193 | 190 |
194 /** | 191 /** |
195 * Initiate an IT2Me connection. | |
196 * | |
197 * @param {string} accessCode The access code as entered by the user. | |
198 * @return {void} Nothing. | |
199 */ | |
200 remoting.SessionConnectorImpl.prototype.connectIT2Me = function(accessCode) { | |
201 var kSupportIdLen = 7; | |
202 var kHostSecretLen = 5; | |
203 var kAccessCodeLen = kSupportIdLen + kHostSecretLen; | |
204 | |
205 // Cancel any existing connect operation. | |
206 this.cancel(); | |
207 | |
208 var normalizedAccessCode = this.normalizeAccessCode_(accessCode); | |
209 if (normalizedAccessCode.length != kAccessCodeLen) { | |
210 this.onError_(remoting.Error.INVALID_ACCESS_CODE); | |
211 return; | |
212 } | |
213 var hostId = normalizedAccessCode.substring(0, kSupportIdLen); | |
214 this.credentialsProvider_ = new remoting.CredentialsProvider({ | |
215 accessCode: normalizedAccessCode | |
216 }); | |
217 this.connectionMode_ = remoting.DesktopConnectedView.Mode.IT2ME; | |
218 remoting.identity.getToken().then( | |
219 this.connectIT2MeWithToken_.bind(this, hostId), | |
220 remoting.Error.handler(this.onError_)); | |
221 }; | |
222 | |
223 /** | |
224 * Reconnect a closed connection. | 192 * Reconnect a closed connection. |
225 * | 193 * |
226 * @return {void} Nothing. | 194 * @return {void} Nothing. |
227 */ | 195 */ |
228 remoting.SessionConnectorImpl.prototype.reconnect = function() { | 196 remoting.SessionConnectorImpl.prototype.reconnect = function() { |
229 if (this.connectionMode_ == remoting.DesktopConnectedView.Mode.IT2ME) { | 197 if (this.connectionMode_ == remoting.DesktopConnectedView.Mode.IT2ME) { |
230 console.error('reconnect not supported for IT2Me.'); | 198 console.error('reconnect not supported for IT2Me.'); |
231 return; | 199 return; |
232 } | 200 } |
233 this.logHostOfflineErrors_ = false; | 201 this.logHostOfflineErrors_ = false; |
234 this.connectInternal_(this.host_, this.credentialsProvider_); | 202 this.connect(this.connectionMode_, this.host_, this.credentialsProvider_); |
235 }; | 203 }; |
236 | 204 |
237 /** | 205 /** |
238 * Cancel a connection-in-progress. | 206 * Cancel a connection-in-progress. |
239 */ | 207 */ |
240 remoting.SessionConnectorImpl.prototype.cancel = function() { | 208 remoting.SessionConnectorImpl.prototype.cancel = function() { |
241 if (this.clientSession_) { | 209 if (this.clientSession_) { |
242 this.clientSession_.removePlugin(); | 210 this.clientSession_.removePlugin(); |
243 this.clientSession_ = null; | 211 this.clientSession_ = null; |
244 } | 212 } |
245 if (this.pendingXhr_) { | |
246 this.pendingXhr_.abort(); | |
247 this.pendingXhr_ = null; | |
248 } | |
249 this.reset(); | 213 this.reset(); |
250 }; | 214 }; |
251 | 215 |
252 /** | 216 /** |
253 * Get the connection mode (Me2Me or IT2Me) | 217 * Get the connection mode (Me2Me or IT2Me) |
254 * | 218 * |
255 * @return {remoting.DesktopConnectedView.Mode} | 219 * @return {remoting.DesktopConnectedView.Mode} |
256 */ | 220 */ |
257 remoting.SessionConnectorImpl.prototype.getConnectionMode = function() { | 221 remoting.SessionConnectorImpl.prototype.getConnectionMode = function() { |
258 return this.connectionMode_; | 222 return this.connectionMode_; |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
320 } | 284 } |
321 break; | 285 break; |
322 | 286 |
323 case remoting.SignalStrategy.State.FAILED: | 287 case remoting.SignalStrategy.State.FAILED: |
324 this.onError_(this.signalStrategy_.getError()); | 288 this.onError_(this.signalStrategy_.getError()); |
325 break; | 289 break; |
326 } | 290 } |
327 }; | 291 }; |
328 | 292 |
329 /** | 293 /** |
330 * Continue an IT2Me connection once an access token has been obtained. | |
331 * | |
332 * @param {string} hostId | |
333 * @param {string} token An OAuth2 access token. | |
334 * @return {void} Nothing. | |
335 * @private | |
336 */ | |
337 remoting.SessionConnectorImpl.prototype.connectIT2MeWithToken_ = | |
338 function(hostId, token) { | |
339 // Resolve the host id to get the host JID. | |
340 this.pendingXhr_ = remoting.xhr.start({ | |
341 method: 'GET', | |
342 url: remoting.settings.DIRECTORY_API_BASE_URL + '/support-hosts/' + | |
343 encodeURIComponent(hostId), | |
344 onDone: this.onIT2MeHostInfo_.bind(this, hostId), | |
345 oauthToken: token | |
346 }); | |
347 }; | |
348 | |
349 /** | |
350 * Continue an IT2Me connection once the host JID has been looked up. | |
351 * | |
352 * @param {string} hostId | |
353 * @param {XMLHttpRequest} xhr The server response to the support-hosts query. | |
354 * @return {void} Nothing. | |
355 * @private | |
356 */ | |
357 remoting.SessionConnectorImpl.prototype.onIT2MeHostInfo_ = | |
358 function(hostId, xhr) { | |
359 this.pendingXhr_ = null; | |
360 if (xhr.status == 200) { | |
361 var host = /** @type {{data: {jabberId: string, publicKey: string}}} */ | |
362 (base.jsonParseSafe(xhr.responseText)); | |
363 if (host && host.data && host.data.jabberId && host.data.publicKey) { | |
364 this.host_ = new remoting.Host(); | |
365 this.host_.hostId = hostId; | |
366 this.host_.jabberId = host.data.jabberId; | |
367 this.host_.publicKey = host.data.publicKey; | |
368 this.host_.hostName = host.data.jabberId.split('/')[0]; | |
369 this.connectSignaling_(); | |
370 return; | |
371 } else { | |
372 console.error('Invalid "support-hosts" response from server.'); | |
373 } | |
374 } else { | |
375 this.onError_(this.translateSupportHostsError_(xhr.status)); | |
376 } | |
377 }; | |
378 | |
379 /** | |
380 * Creates ClientSession object. | 294 * Creates ClientSession object. |
381 */ | 295 */ |
382 remoting.SessionConnectorImpl.prototype.createSession_ = function() { | 296 remoting.SessionConnectorImpl.prototype.createSession_ = function() { |
383 // In some circumstances, the WCS <iframe> can get reloaded, which results | 297 // In some circumstances, the WCS <iframe> can get reloaded, which results |
384 // in a new clientJid and a new callback. In this case, remove the old | 298 // in a new clientJid and a new callback. In this case, remove the old |
385 // client plugin before instantiating a new one. | 299 // client plugin before instantiating a new one. |
386 if (this.clientSession_) { | 300 if (this.clientSession_) { |
387 this.clientSession_.removePlugin(); | 301 this.clientSession_.removePlugin(); |
388 this.clientSession_ = null; | 302 this.clientSession_ = null; |
389 } | 303 } |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
465 | 379 |
466 default: | 380 default: |
467 console.error('Unexpected client plugin state: ' + event.current); | 381 console.error('Unexpected client plugin state: ' + event.current); |
468 // This should only happen if the web-app and client plugin get out of | 382 // This should only happen if the web-app and client plugin get out of |
469 // sync, and even then the version check should ensure compatibility. | 383 // sync, and even then the version check should ensure compatibility. |
470 this.onError_(remoting.Error.MISSING_PLUGIN); | 384 this.onError_(remoting.Error.MISSING_PLUGIN); |
471 } | 385 } |
472 }; | 386 }; |
473 | 387 |
474 /** | 388 /** |
475 * @param {number} error An HTTP error code returned by the support-hosts | |
476 * endpoint. | |
477 * @return {remoting.Error} The equivalent remoting.Error code. | |
478 * @private | |
479 */ | |
480 remoting.SessionConnectorImpl.prototype.translateSupportHostsError_ = | |
481 function(error) { | |
482 switch (error) { | |
483 case 0: return remoting.Error.NETWORK_FAILURE; | |
484 case 404: return remoting.Error.INVALID_ACCESS_CODE; | |
485 case 502: // No break | |
486 case 503: return remoting.Error.SERVICE_UNAVAILABLE; | |
487 default: return remoting.Error.UNEXPECTED; | |
488 } | |
489 }; | |
490 | |
491 /** | |
492 * Normalize the access code entered by the user. | |
493 * | |
494 * @param {string} accessCode The access code, as entered by the user. | |
495 * @return {string} The normalized form of the code (whitespace removed). | |
496 * @private | |
497 */ | |
498 remoting.SessionConnectorImpl.prototype.normalizeAccessCode_ = | |
499 function(accessCode) { | |
500 // Trim whitespace. | |
501 return accessCode.replace(/\s/g, ''); | |
502 }; | |
503 | |
504 | |
505 /** | |
506 * @constructor | 389 * @constructor |
507 * @implements {remoting.SessionConnectorFactory} | 390 * @implements {remoting.SessionConnectorFactory} |
508 */ | 391 */ |
509 remoting.DefaultSessionConnectorFactory = function() { | 392 remoting.DefaultSessionConnectorFactory = function() {}; |
510 }; | |
511 | 393 |
512 /** | 394 /** |
513 * @param {HTMLElement} clientContainer Container element for the client view. | 395 * @param {HTMLElement} clientContainer Container element for the client view. |
514 * @param {function(remoting.ClientSession):void} onConnected Callback on | 396 * @param {function(remoting.ClientSession):void} onConnected Callback on |
515 * success. | 397 * success. |
516 * @param {function(remoting.Error):void} onError Callback on error. | 398 * @param {function(remoting.Error):void} onError Callback on error. |
517 * @param {function(string, string):boolean} onExtensionMessage The handler for | 399 * @param {function(string, string):boolean} onExtensionMessage The handler for |
518 * protocol extension messages. Returns true if a message is recognized; | 400 * protocol extension messages. Returns true if a message is recognized; |
519 * false otherwise. | 401 * false otherwise. |
520 * @param {function(remoting.Error):void} onConnectionFailed Callback for when | 402 * @param {function(remoting.Error):void} onConnectionFailed Callback for when |
521 * the connection fails. | 403 * the connection fails. |
522 * @param {Array<string>} requiredCapabilities Connector capabilities | 404 * @param {Array<string>} requiredCapabilities Connector capabilities |
523 * required by this application. | 405 * required by this application. |
524 * @param {string} defaultRemapKeys The default set of key mappings to use | 406 * @param {string} defaultRemapKeys The default set of key mappings to use |
525 * in the client session. | 407 * in the client session. |
526 * @return {remoting.SessionConnector} | 408 * @return {remoting.SessionConnector} |
527 */ | 409 */ |
528 remoting.DefaultSessionConnectorFactory.prototype.createConnector = | 410 remoting.DefaultSessionConnectorFactory.prototype.createConnector = |
529 function(clientContainer, onConnected, onError, onExtensionMessage, | 411 function(clientContainer, onConnected, onError, onExtensionMessage, |
530 onConnectionFailed, requiredCapabilities, defaultRemapKeys) { | 412 onConnectionFailed, requiredCapabilities, defaultRemapKeys) { |
531 return new remoting.SessionConnectorImpl(clientContainer, onConnected, | 413 return new remoting.SessionConnectorImpl(clientContainer, onConnected, |
532 onError, onExtensionMessage, | 414 onError, onExtensionMessage, |
533 onConnectionFailed, | 415 onConnectionFailed, |
534 requiredCapabilities, | 416 requiredCapabilities, |
535 defaultRemapKeys); | 417 defaultRemapKeys); |
536 }; | 418 }; |
OLD | NEW |