| 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'; |
| 11 | 11 |
| 12 /** @suppress {duplicate} */ | 12 /** @suppress {duplicate} */ |
| 13 var remoting = remoting || {}; | 13 var remoting = remoting || {}; |
| 14 | 14 |
| 15 /** | 15 /** |
| 16 * @param {HTMLElement} clientContainer Container element for the client view. | 16 * @param {HTMLElement} clientContainer Container element for the client view. |
| 17 * @param {function(remoting.ClientSession):void} onConnected Callback on | 17 * @param {remoting.Application} app The main remoting application. |
| 18 * success. | |
| 19 * @param {function(remoting.Error):void} onError Callback on error. | |
| 20 * @param {function(string, string):boolean} onExtensionMessage The handler for | |
| 21 * protocol extension messages. Returns true if a message is recognized; | |
| 22 * false otherwise. | |
| 23 * @constructor | 18 * @constructor |
| 24 * @implements {remoting.SessionConnector} | 19 * @implements {remoting.SessionConnector} |
| 25 */ | 20 */ |
| 26 remoting.SessionConnectorImpl = function(clientContainer, onConnected, onError, | 21 remoting.SessionConnectorImpl = function(clientContainer, app) { |
| 27 onExtensionMessage) { | |
| 28 /** | 22 /** |
| 29 * @type {HTMLElement} | 23 * @type {HTMLElement} |
| 30 * @private | 24 * @private |
| 31 */ | 25 */ |
| 32 this.clientContainer_ = clientContainer; | 26 this.clientContainer_ = clientContainer; |
| 33 | 27 |
| 34 /** | 28 /** |
| 35 * @type {function(remoting.ClientSession):void} | 29 * @type {remoting.Application} |
| 36 * @private | 30 * @private |
| 37 */ | 31 */ |
| 38 this.onConnected_ = onConnected; | 32 this.app_ = app; |
| 39 | |
| 40 /** | |
| 41 * @type {function(remoting.Error):void} | |
| 42 * @private | |
| 43 */ | |
| 44 this.onError_ = onError; | |
| 45 | |
| 46 /** | |
| 47 * @type {function(string, string):boolean} | |
| 48 * @private | |
| 49 */ | |
| 50 this.onExtensionMessage_ = onExtensionMessage; | |
| 51 | 33 |
| 52 /** | 34 /** |
| 53 * @type {string} | 35 * @type {string} |
| 54 * @private | 36 * @private |
| 55 */ | 37 */ |
| 56 this.clientJid_ = ''; | 38 this.clientJid_ = ''; |
| 57 | 39 |
| 58 /** | 40 /** |
| 59 * @type {remoting.ClientSession.Mode} | 41 * @type {remoting.ClientSession.Mode} |
| 60 * @private | 42 * @private |
| (...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 269 remoting.SessionConnectorImpl.prototype.connectIT2Me = function(accessCode) { | 251 remoting.SessionConnectorImpl.prototype.connectIT2Me = function(accessCode) { |
| 270 var kSupportIdLen = 7; | 252 var kSupportIdLen = 7; |
| 271 var kHostSecretLen = 5; | 253 var kHostSecretLen = 5; |
| 272 var kAccessCodeLen = kSupportIdLen + kHostSecretLen; | 254 var kAccessCodeLen = kSupportIdLen + kHostSecretLen; |
| 273 | 255 |
| 274 // Cancel any existing connect operation. | 256 // Cancel any existing connect operation. |
| 275 this.cancel(); | 257 this.cancel(); |
| 276 | 258 |
| 277 var normalizedAccessCode = this.normalizeAccessCode_(accessCode); | 259 var normalizedAccessCode = this.normalizeAccessCode_(accessCode); |
| 278 if (normalizedAccessCode.length != kAccessCodeLen) { | 260 if (normalizedAccessCode.length != kAccessCodeLen) { |
| 279 this.onError_(remoting.Error.INVALID_ACCESS_CODE); | 261 this.app_.onError(remoting.Error.INVALID_ACCESS_CODE); |
| 280 return; | 262 return; |
| 281 } | 263 } |
| 282 | 264 |
| 283 this.hostId_ = normalizedAccessCode.substring(0, kSupportIdLen); | 265 this.hostId_ = normalizedAccessCode.substring(0, kSupportIdLen); |
| 284 this.passPhrase_ = normalizedAccessCode; | 266 this.passPhrase_ = normalizedAccessCode; |
| 285 this.connectionMode_ = remoting.ClientSession.Mode.IT2ME; | 267 this.connectionMode_ = remoting.ClientSession.Mode.IT2ME; |
| 286 remoting.identity.callWithToken(this.connectIT2MeWithToken_.bind(this), | 268 remoting.identity.callWithToken(this.connectIT2MeWithToken_.bind(this), |
| 287 this.onError_); | 269 this.app_.onError); |
| 288 }; | 270 }; |
| 289 | 271 |
| 290 /** | 272 /** |
| 291 * Reconnect a closed connection. | 273 * Reconnect a closed connection. |
| 292 * | 274 * |
| 293 * @return {void} Nothing. | 275 * @return {void} Nothing. |
| 294 */ | 276 */ |
| 295 remoting.SessionConnectorImpl.prototype.reconnect = function() { | 277 remoting.SessionConnectorImpl.prototype.reconnect = function() { |
| 296 if (this.connectionMode_ == remoting.ClientSession.Mode.IT2ME) { | 278 if (this.connectionMode_ == remoting.ClientSession.Mode.IT2ME) { |
| 297 console.error('reconnect not supported for IT2Me.'); | 279 console.error('reconnect not supported for IT2Me.'); |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 342 remoting.SessionConnectorImpl.prototype.connectSignaling_ = function() { | 324 remoting.SessionConnectorImpl.prototype.connectSignaling_ = function() { |
| 343 base.dispose(this.signalStrategy_); | 325 base.dispose(this.signalStrategy_); |
| 344 this.signalStrategy_ = null; | 326 this.signalStrategy_ = null; |
| 345 | 327 |
| 346 /** @type {remoting.SessionConnectorImpl} */ | 328 /** @type {remoting.SessionConnectorImpl} */ |
| 347 var that = this; | 329 var that = this; |
| 348 | 330 |
| 349 /** @param {string} token */ | 331 /** @param {string} token */ |
| 350 function connectSignalingWithToken(token) { | 332 function connectSignalingWithToken(token) { |
| 351 remoting.identity.getEmail( | 333 remoting.identity.getEmail( |
| 352 connectSignalingWithTokenAndEmail.bind(null, token), that.onError_); | 334 connectSignalingWithTokenAndEmail.bind(null, token), that.app_.onError); |
| 353 } | 335 } |
| 354 | 336 |
| 355 /** | 337 /** |
| 356 * @param {string} token | 338 * @param {string} token |
| 357 * @param {string} email | 339 * @param {string} email |
| 358 */ | 340 */ |
| 359 function connectSignalingWithTokenAndEmail(token, email) { | 341 function connectSignalingWithTokenAndEmail(token, email) { |
| 360 that.signalStrategy_.connect( | 342 that.signalStrategy_.connect( |
| 361 remoting.settings.XMPP_SERVER_ADDRESS, email, token); | 343 remoting.settings.XMPP_SERVER_ADDRESS, email, token); |
| 362 } | 344 } |
| 363 | 345 |
| 364 this.signalStrategy_ = | 346 this.signalStrategy_ = |
| 365 remoting.SignalStrategy.create(this.onSignalingState_.bind(this)); | 347 remoting.SignalStrategy.create(this.onSignalingState_.bind(this)); |
| 366 | 348 |
| 367 remoting.identity.callWithToken(connectSignalingWithToken, this.onError_); | 349 remoting.identity.callWithToken(connectSignalingWithToken, this.app_.onError); |
| 368 }; | 350 }; |
| 369 | 351 |
| 370 /** | 352 /** |
| 371 * @private | 353 * @private |
| 372 * @param {remoting.SignalStrategy.State} state | 354 * @param {remoting.SignalStrategy.State} state |
| 373 */ | 355 */ |
| 374 remoting.SessionConnectorImpl.prototype.onSignalingState_ = function(state) { | 356 remoting.SessionConnectorImpl.prototype.onSignalingState_ = function(state) { |
| 375 switch (state) { | 357 switch (state) { |
| 376 case remoting.SignalStrategy.State.CONNECTED: | 358 case remoting.SignalStrategy.State.CONNECTED: |
| 377 // Proceed only if the connection hasn't been canceled. | 359 // Proceed only if the connection hasn't been canceled. |
| 378 if (this.hostJid_) { | 360 if (this.hostJid_) { |
| 379 this.createSession_(); | 361 this.createSession_(); |
| 380 } | 362 } |
| 381 break; | 363 break; |
| 382 | 364 |
| 383 case remoting.SignalStrategy.State.FAILED: | 365 case remoting.SignalStrategy.State.FAILED: |
| 384 this.onError_(this.signalStrategy_.getError()); | 366 this.app_.onError(this.signalStrategy_.getError()); |
| 385 break; | 367 break; |
| 386 } | 368 } |
| 387 }; | 369 }; |
| 388 | 370 |
| 389 /** | 371 /** |
| 390 * Continue an IT2Me connection once an access token has been obtained. | 372 * Continue an IT2Me connection once an access token has been obtained. |
| 391 * | 373 * |
| 392 * @param {string} token An OAuth2 access token. | 374 * @param {string} token An OAuth2 access token. |
| 393 * @return {void} Nothing. | 375 * @return {void} Nothing. |
| 394 * @private | 376 * @private |
| (...skipping 24 matching lines...) Expand all Loading... |
| 419 if (host && host.data && host.data.jabberId && host.data.publicKey) { | 401 if (host && host.data && host.data.jabberId && host.data.publicKey) { |
| 420 this.hostJid_ = host.data.jabberId; | 402 this.hostJid_ = host.data.jabberId; |
| 421 this.hostPublicKey_ = host.data.publicKey; | 403 this.hostPublicKey_ = host.data.publicKey; |
| 422 this.hostDisplayName_ = this.hostJid_.split('/')[0]; | 404 this.hostDisplayName_ = this.hostJid_.split('/')[0]; |
| 423 this.connectSignaling_(); | 405 this.connectSignaling_(); |
| 424 return; | 406 return; |
| 425 } else { | 407 } else { |
| 426 console.error('Invalid "support-hosts" response from server.'); | 408 console.error('Invalid "support-hosts" response from server.'); |
| 427 } | 409 } |
| 428 } else { | 410 } else { |
| 429 this.onError_(this.translateSupportHostsError_(xhr.status)); | 411 this.app_.onError(this.translateSupportHostsError_(xhr.status)); |
| 430 } | 412 } |
| 431 }; | 413 }; |
| 432 | 414 |
| 433 /** | 415 /** |
| 434 * Creates ClientSession object. | 416 * Creates ClientSession object. |
| 435 */ | 417 */ |
| 436 remoting.SessionConnectorImpl.prototype.createSession_ = function() { | 418 remoting.SessionConnectorImpl.prototype.createSession_ = function() { |
| 437 // In some circumstances, the WCS <iframe> can get reloaded, which results | 419 // In some circumstances, the WCS <iframe> can get reloaded, which results |
| 438 // in a new clientJid and a new callback. In this case, remove the old | 420 // in a new clientJid and a new callback. In this case, remove the old |
| 439 // client plugin before instantiating a new one. | 421 // client plugin before instantiating a new one. |
| 440 if (this.clientSession_) { | 422 if (this.clientSession_) { |
| 441 this.clientSession_.removePlugin(); | 423 this.clientSession_.removePlugin(); |
| 442 this.clientSession_ = null; | 424 this.clientSession_ = null; |
| 443 } | 425 } |
| 444 | 426 |
| 445 var authenticationMethods = | 427 var authenticationMethods = |
| 446 'third_party,spake2_pair,spake2_hmac,spake2_plain'; | 428 'third_party,spake2_pair,spake2_hmac,spake2_plain'; |
| 447 this.clientSession_ = new remoting.ClientSession( | 429 this.clientSession_ = new remoting.ClientSession( |
| 448 this.signalStrategy_, this.clientContainer_, this.hostDisplayName_, | 430 this.signalStrategy_, this.clientContainer_, this.hostDisplayName_, |
| 449 this.passPhrase_, this.fetchPin_, this.fetchThirdPartyToken_, | 431 this.passPhrase_, this.fetchPin_, this.fetchThirdPartyToken_, |
| 450 authenticationMethods, this.hostId_, this.hostJid_, this.hostPublicKey_, | 432 authenticationMethods, this.hostId_, this.hostJid_, this.hostPublicKey_, |
| 451 this.connectionMode_, this.clientPairingId_, this.clientPairedSecret_); | 433 this.connectionMode_, this.clientPairingId_, this.clientPairedSecret_); |
| 452 this.clientSession_.logHostOfflineErrors(!this.refreshHostJidIfOffline_); | 434 this.clientSession_.logHostOfflineErrors(!this.refreshHostJidIfOffline_); |
| 453 this.clientSession_.addEventListener( | 435 this.clientSession_.addEventListener( |
| 454 remoting.ClientSession.Events.stateChanged, | 436 remoting.ClientSession.Events.stateChanged, |
| 455 this.bound_.onStateChange); | 437 this.bound_.onStateChange); |
| 456 this.clientSession_.createPluginAndConnect(this.onExtensionMessage_); | 438 this.clientSession_.createPluginAndConnect(this.app_.onExtensionMessage); |
| 457 }; | 439 }; |
| 458 | 440 |
| 459 /** | 441 /** |
| 460 * Handle a change in the state of the client session prior to successful | 442 * Handle a change in the state of the client session prior to successful |
| 461 * connection (after connection, this class no longer handles state change | 443 * connection (after connection, this class no longer handles state change |
| 462 * events). Errors that occur while connecting either trigger a reconnect | 444 * events). Errors that occur while connecting either trigger a reconnect |
| 463 * or notify the onError handler. | 445 * or notify the onError handler. |
| 464 * | 446 * |
| 465 * @param {remoting.ClientSession.StateEvent} event | 447 * @param {remoting.ClientSession.StateEvent} event |
| 466 * @return {void} Nothing. | 448 * @return {void} Nothing. |
| 467 * @private | 449 * @private |
| 468 */ | 450 */ |
| 469 remoting.SessionConnectorImpl.prototype.onStateChange_ = function(event) { | 451 remoting.SessionConnectorImpl.prototype.onStateChange_ = function(event) { |
| 470 switch (event.current) { | 452 switch (event.current) { |
| 471 case remoting.ClientSession.State.CONNECTED: | 453 case remoting.ClientSession.State.CONNECTED: |
| 472 // When the connection succeeds, deregister for state-change callbacks | 454 // When the connection succeeds, deregister for state-change callbacks |
| 473 // and pass the session to the onConnected callback. It is expected that | 455 // and pass the session to the onConnected callback. It is expected that |
| 474 // it will register a new state-change callback to handle disconnect | 456 // it will register a new state-change callback to handle disconnect |
| 475 // or error conditions. | 457 // or error conditions. |
| 476 this.clientSession_.removeEventListener( | 458 this.clientSession_.removeEventListener( |
| 477 remoting.ClientSession.Events.stateChanged, | 459 remoting.ClientSession.Events.stateChanged, |
| 478 this.bound_.onStateChange); | 460 this.bound_.onStateChange); |
| 479 | 461 |
| 480 base.dispose(this.reconnector_); | 462 base.dispose(this.reconnector_); |
| 481 if (this.connectionMode_ != remoting.ClientSession.Mode.IT2ME) { | 463 if (this.connectionMode_ != remoting.ClientSession.Mode.IT2ME) { |
| 482 this.reconnector_ = | 464 this.reconnector_ = |
| 483 new remoting.SmartReconnector(this, this.clientSession_); | 465 new remoting.SmartReconnector(this, this.clientSession_); |
| 484 } | 466 } |
| 485 this.onConnected_(this.clientSession_); | 467 this.app_.onConnected(this.clientSession_); |
| 486 break; | 468 break; |
| 487 | 469 |
| 488 case remoting.ClientSession.State.CREATED: | 470 case remoting.ClientSession.State.CREATED: |
| 489 console.log('Created plugin'); | 471 console.log('Created plugin'); |
| 490 break; | 472 break; |
| 491 | 473 |
| 492 case remoting.ClientSession.State.CONNECTING: | 474 case remoting.ClientSession.State.CONNECTING: |
| 493 console.log('Connecting as ' + remoting.identity.getCachedEmail()); | 475 console.log('Connecting as ' + remoting.identity.getCachedEmail()); |
| 494 break; | 476 break; |
| 495 | 477 |
| 496 case remoting.ClientSession.State.INITIALIZING: | 478 case remoting.ClientSession.State.INITIALIZING: |
| 497 console.log('Initializing connection'); | 479 console.log('Initializing connection'); |
| 498 break; | 480 break; |
| 499 | 481 |
| 500 case remoting.ClientSession.State.CLOSED: | 482 case remoting.ClientSession.State.CLOSED: |
| 501 // This class deregisters for state-change callbacks when the CONNECTED | 483 // This class deregisters for state-change callbacks when the CONNECTED |
| 502 // state is reached, so it only sees the CLOSED state in exceptional | 484 // state is reached, so it only sees the CLOSED state in exceptional |
| 503 // circumstances. For example, a CONNECTING -> CLOSED transition happens | 485 // circumstances. For example, a CONNECTING -> CLOSED transition happens |
| 504 // if the host closes the connection without an error message instead of | 486 // if the host closes the connection without an error message instead of |
| 505 // accepting it. Since there's no way of knowing exactly what went wrong, | 487 // accepting it. Since there's no way of knowing exactly what went wrong, |
| 506 // we rely on server-side logs in this case and report a generic error | 488 // we rely on server-side logs in this case and report a generic error |
| 507 // message. | 489 // message. |
| 508 this.onError_(remoting.Error.UNEXPECTED); | 490 this.app_.onError(remoting.Error.UNEXPECTED); |
| 509 break; | 491 break; |
| 510 | 492 |
| 511 case remoting.ClientSession.State.FAILED: | 493 case remoting.ClientSession.State.FAILED: |
| 512 var error = this.clientSession_.getError(); | 494 var error = this.clientSession_.getError(); |
| 513 console.error('Client plugin reported connection failed: ' + error); | 495 console.error('Client plugin reported connection failed: ' + error); |
| 514 if (error == null) { | 496 if (error == null) { |
| 515 error = remoting.Error.UNEXPECTED; | 497 error = remoting.Error.UNEXPECTED; |
| 516 } | 498 } |
| 517 if (error == remoting.Error.HOST_IS_OFFLINE && | 499 if (error == remoting.Error.HOST_IS_OFFLINE && |
| 518 this.refreshHostJidIfOffline_) { | 500 this.refreshHostJidIfOffline_) { |
| 519 // The plugin will be re-created when the host finished refreshing | 501 // The plugin will be re-created when the host finished refreshing |
| 520 remoting.hostList.refresh(this.onHostListRefresh_.bind(this)); | 502 remoting.hostList.refresh(this.onHostListRefresh_.bind(this)); |
| 521 } else { | 503 } else { |
| 522 this.onError_(error); | 504 this.app_.onError(error); |
| 523 } | 505 } |
| 524 break; | 506 break; |
| 525 | 507 |
| 526 default: | 508 default: |
| 527 console.error('Unexpected client plugin state: ' + event.current); | 509 console.error('Unexpected client plugin state: ' + event.current); |
| 528 // This should only happen if the web-app and client plugin get out of | 510 // This should only happen if the web-app and client plugin get out of |
| 529 // sync, and even then the version check should ensure compatibility. | 511 // sync, and even then the version check should ensure compatibility. |
| 530 this.onError_(remoting.Error.MISSING_PLUGIN); | 512 this.app_.onError(remoting.Error.MISSING_PLUGIN); |
| 531 } | 513 } |
| 532 }; | 514 }; |
| 533 | 515 |
| 534 /** | 516 /** |
| 535 * @param {boolean} success True if the host list was successfully refreshed; | 517 * @param {boolean} success True if the host list was successfully refreshed; |
| 536 * false if an error occurred. | 518 * false if an error occurred. |
| 537 * @private | 519 * @private |
| 538 */ | 520 */ |
| 539 remoting.SessionConnectorImpl.prototype.onHostListRefresh_ = function(success) { | 521 remoting.SessionConnectorImpl.prototype.onHostListRefresh_ = function(success) { |
| 540 if (success) { | 522 if (success) { |
| 541 var host = remoting.hostList.getHostForId(this.hostId_); | 523 var host = remoting.hostList.getHostForId(this.hostId_); |
| 542 if (host) { | 524 if (host) { |
| 543 this.connectMe2MeInternal_( | 525 this.connectMe2MeInternal_( |
| 544 host.hostId, host.jabberId, host.publicKey, host.hostName, | 526 host.hostId, host.jabberId, host.publicKey, host.hostName, |
| 545 this.fetchPin_, this.fetchThirdPartyToken_, | 527 this.fetchPin_, this.fetchThirdPartyToken_, |
| 546 this.clientPairingId_, this.clientPairedSecret_, false); | 528 this.clientPairingId_, this.clientPairedSecret_, false); |
| 547 return; | 529 return; |
| 548 } | 530 } |
| 549 } | 531 } |
| 550 this.onError_(remoting.Error.HOST_IS_OFFLINE); | 532 this.app_.onError(remoting.Error.HOST_IS_OFFLINE); |
| 551 }; | 533 }; |
| 552 | 534 |
| 553 /** | 535 /** |
| 554 * @param {number} error An HTTP error code returned by the support-hosts | 536 * @param {number} error An HTTP error code returned by the support-hosts |
| 555 * endpoint. | 537 * endpoint. |
| 556 * @return {remoting.Error} The equivalent remoting.Error code. | 538 * @return {remoting.Error} The equivalent remoting.Error code. |
| 557 * @private | 539 * @private |
| 558 */ | 540 */ |
| 559 remoting.SessionConnectorImpl.prototype.translateSupportHostsError_ = | 541 remoting.SessionConnectorImpl.prototype.translateSupportHostsError_ = |
| 560 function(error) { | 542 function(error) { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 583 | 565 |
| 584 /** | 566 /** |
| 585 * @constructor | 567 * @constructor |
| 586 * @implements {remoting.SessionConnectorFactory} | 568 * @implements {remoting.SessionConnectorFactory} |
| 587 */ | 569 */ |
| 588 remoting.DefaultSessionConnectorFactory = function() { | 570 remoting.DefaultSessionConnectorFactory = function() { |
| 589 }; | 571 }; |
| 590 | 572 |
| 591 /** | 573 /** |
| 592 * @param {HTMLElement} clientContainer Container element for the client view. | 574 * @param {HTMLElement} clientContainer Container element for the client view. |
| 593 * @param {function(remoting.ClientSession):void} onConnected Callback on | 575 * @param {remoting.Application} app The main application. |
| 594 * success. | |
| 595 * @param {function(remoting.Error):void} onError Callback on error. | |
| 596 * @param {function(string, string):boolean} onExtensionMessage The handler for | |
| 597 * protocol extension messages. Returns true if a message is recognized; | |
| 598 * false otherwise. | |
| 599 */ | 576 */ |
| 600 remoting.DefaultSessionConnectorFactory.prototype.createConnector = | 577 remoting.DefaultSessionConnectorFactory.prototype.createConnector = |
| 601 function(clientContainer, onConnected, onError, onExtensionMessage) { | 578 function(clientContainer, app) { |
| 602 return new remoting.SessionConnectorImpl( | 579 return new remoting.SessionConnectorImpl(clientContainer, app); |
| 603 clientContainer, onConnected, onError, onExtensionMessage); | |
| 604 }; | 580 }; |
| OLD | NEW |