| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 * Class that wraps low-level details of interacting with the client plugin. | 7 * Class that wraps low-level details of interacting with the client plugin. |
| 8 * | 8 * |
| 9 * This abstracts a <embed> element and controls the plugin which does | 9 * This abstracts a <embed> element and controls the plugin which does |
| 10 * the actual remoting work. It also handles differences between | 10 * the actual remoting work. It also handles differences between |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 70 * @param {string} connectionType The connection type. | 70 * @param {string} connectionType The connection type. |
| 71 * @private | 71 * @private |
| 72 */ | 72 */ |
| 73 this.onRouteChangedHandler_ = function(channel, connectionType) {}; | 73 this.onRouteChangedHandler_ = function(channel, connectionType) {}; |
| 74 | 74 |
| 75 /** | 75 /** |
| 76 * @param {boolean} ready Connection ready state. | 76 * @param {boolean} ready Connection ready state. |
| 77 * @private | 77 * @private |
| 78 */ | 78 */ |
| 79 this.onConnectionReadyHandler_ = function(ready) {}; | 79 this.onConnectionReadyHandler_ = function(ready) {}; |
| 80 | |
| 81 /** | |
| 82 * @param {string} tokenUrl Token-request URL, received from the host. | |
| 83 * @param {string} hostPublicKey Public key for the host. | |
| 84 * @param {string} scope OAuth scope to request the token for. | |
| 85 * @private | |
| 86 */ | |
| 87 this.fetchThirdPartyTokenHandler_ = function( | |
| 88 tokenUrl, hostPublicKey, scope) {}; | |
| 89 /** | 80 /** |
| 90 * @param {!Array<string>} capabilities The negotiated capabilities. | 81 * @param {!Array<string>} capabilities The negotiated capabilities. |
| 91 * @private | 82 * @private |
| 92 */ | 83 */ |
| 93 this.onSetCapabilitiesHandler_ = function (capabilities) {}; | 84 this.onSetCapabilitiesHandler_ = function (capabilities) {}; |
| 94 /** @private */ | |
| 95 this.fetchPinHandler_ = function (supportsPairing) {}; | |
| 96 /** | 85 /** |
| 97 * @param {string} data Remote gnubbyd data. | 86 * @param {string} data Remote gnubbyd data. |
| 98 * @private | 87 * @private |
| 99 */ | 88 */ |
| 100 this.onGnubbyAuthHandler_ = function(data) {}; | 89 this.onGnubbyAuthHandler_ = function(data) {}; |
| 101 /** | 90 /** |
| 102 * @param {string} url | 91 * @param {string} url |
| 103 * @param {number} hotspotX | 92 * @param {number} hotspotX |
| 104 * @param {number} hotspotY | 93 * @param {number} hotspotY |
| 105 * @private | 94 * @private |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 161 that.handleMessage_( | 150 that.handleMessage_( |
| 162 /** @type {remoting.ClientPluginMessage} */ (event.data)); | 151 /** @type {remoting.ClientPluginMessage} */ (event.data)); |
| 163 }, false); | 152 }, false); |
| 164 | 153 |
| 165 if (remoting.settings.CLIENT_PLUGIN_TYPE == 'native') { | 154 if (remoting.settings.CLIENT_PLUGIN_TYPE == 'native') { |
| 166 window.setTimeout(this.showPluginForClickToPlay_.bind(this), 500); | 155 window.setTimeout(this.showPluginForClickToPlay_.bind(this), 500); |
| 167 } | 156 } |
| 168 | 157 |
| 169 this.hostDesktop_ = new remoting.ClientPlugin.HostDesktopImpl( | 158 this.hostDesktop_ = new remoting.ClientPlugin.HostDesktopImpl( |
| 170 this, this.postMessage_.bind(this)); | 159 this, this.postMessage_.bind(this)); |
| 160 |
| 161 /** @private {remoting.CredentialsProvider} */ |
| 162 this.credentials_ = null; |
| 171 }; | 163 }; |
| 172 | 164 |
| 173 /** | 165 /** |
| 174 * Creates plugin element without adding it to a container. | 166 * Creates plugin element without adding it to a container. |
| 175 * | 167 * |
| 176 * @return {HTMLEmbedElement} Plugin element | 168 * @return {HTMLEmbedElement} Plugin element |
| 177 */ | 169 */ |
| 178 remoting.ClientPluginImpl.createPluginElement_ = function() { | 170 remoting.ClientPluginImpl.createPluginElement_ = function() { |
| 179 var plugin = | 171 var plugin = |
| 180 /** @type {HTMLEmbedElement} */ (document.createElement('embed')); | 172 /** @type {HTMLEmbedElement} */ (document.createElement('embed')); |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 275 }; | 267 }; |
| 276 | 268 |
| 277 /** | 269 /** |
| 278 * @param {function(string, number, number):void} handler | 270 * @param {function(string, number, number):void} handler |
| 279 */ | 271 */ |
| 280 remoting.ClientPluginImpl.prototype.setMouseCursorHandler = function(handler) { | 272 remoting.ClientPluginImpl.prototype.setMouseCursorHandler = function(handler) { |
| 281 this.updateMouseCursorImage_ = handler; | 273 this.updateMouseCursorImage_ = handler; |
| 282 }; | 274 }; |
| 283 | 275 |
| 284 /** | 276 /** |
| 285 * @param {function(string, string, string):void} handler | |
| 286 */ | |
| 287 remoting.ClientPluginImpl.prototype.setFetchThirdPartyTokenHandler = | |
| 288 function(handler) { | |
| 289 this.fetchThirdPartyTokenHandler_ = handler; | |
| 290 }; | |
| 291 | |
| 292 /** | |
| 293 * @param {function(boolean):void} handler | |
| 294 */ | |
| 295 remoting.ClientPluginImpl.prototype.setFetchPinHandler = function(handler) { | |
| 296 this.fetchPinHandler_ = handler; | |
| 297 }; | |
| 298 | |
| 299 /** | |
| 300 * @param {?function({rects:Array<Array<number>>}):void} handler | 277 * @param {?function({rects:Array<Array<number>>}):void} handler |
| 301 */ | 278 */ |
| 302 remoting.ClientPluginImpl.prototype.setDebugDirtyRegionHandler = | 279 remoting.ClientPluginImpl.prototype.setDebugDirtyRegionHandler = |
| 303 function(handler) { | 280 function(handler) { |
| 304 this.debugRegionHandler_ = handler; | 281 this.debugRegionHandler_ = handler; |
| 305 this.plugin_.postMessage(JSON.stringify( | 282 this.plugin_.postMessage(JSON.stringify( |
| 306 { method: 'enableDebugRegion', data: { enable: handler != null } })); | 283 { method: 'enableDebugRegion', data: { enable: handler != null } })); |
| 307 }; | 284 }; |
| 308 | 285 |
| 309 /** | 286 /** |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 429 | 406 |
| 430 } else if (message.method == 'onConnectionReady') { | 407 } else if (message.method == 'onConnectionReady') { |
| 431 var ready = getBooleanAttr(message.data, 'ready'); | 408 var ready = getBooleanAttr(message.data, 'ready'); |
| 432 this.onConnectionReadyHandler_(ready); | 409 this.onConnectionReadyHandler_(ready); |
| 433 | 410 |
| 434 } else if (message.method == 'fetchPin') { | 411 } else if (message.method == 'fetchPin') { |
| 435 // The pairingSupported value in the dictionary indicates whether both | 412 // The pairingSupported value in the dictionary indicates whether both |
| 436 // client and host support pairing. If the client doesn't support pairing, | 413 // client and host support pairing. If the client doesn't support pairing, |
| 437 // then the value won't be there at all, so give it a default of false. | 414 // then the value won't be there at all, so give it a default of false. |
| 438 var pairingSupported = getBooleanAttr(message.data, 'pairingSupported', | 415 var pairingSupported = getBooleanAttr(message.data, 'pairingSupported', |
| 439 false) | 416 false); |
| 440 this.fetchPinHandler_(pairingSupported); | 417 this.credentials_.getPIN(pairingSupported).then( |
| 441 | 418 this.onPinFetched_.bind(this) |
| 419 ); |
| 442 } else if (message.method == 'setCapabilities') { | 420 } else if (message.method == 'setCapabilities') { |
| 443 /** @type {!Array<string>} */ | 421 /** @type {!Array<string>} */ |
| 444 var capabilities = tokenize(getStringAttr(message.data, 'capabilities')); | 422 var capabilities = tokenize(getStringAttr(message.data, 'capabilities')); |
| 445 this.onSetCapabilitiesHandler_(capabilities); | 423 this.onSetCapabilitiesHandler_(capabilities); |
| 446 | 424 |
| 447 } else if (message.method == 'fetchThirdPartyToken') { | 425 } else if (message.method == 'fetchThirdPartyToken') { |
| 448 var tokenUrl = getStringAttr(message.data, 'tokenUrl'); | 426 var tokenUrl = getStringAttr(message.data, 'tokenUrl'); |
| 449 var hostPublicKey = getStringAttr(message.data, 'hostPublicKey'); | 427 var hostPublicKey = getStringAttr(message.data, 'hostPublicKey'); |
| 450 var scope = getStringAttr(message.data, 'scope'); | 428 var scope = getStringAttr(message.data, 'scope'); |
| 451 this.fetchThirdPartyTokenHandler_(tokenUrl, hostPublicKey, scope); | 429 this.credentials_.getThirdPartyToken(tokenUrl, hostPublicKey, scope).then( |
| 452 | 430 this.onThirdPartyTokenFetched_.bind(this) |
| 431 ); |
| 453 } else if (message.method == 'pairingResponse') { | 432 } else if (message.method == 'pairingResponse') { |
| 454 var clientId = getStringAttr(message.data, 'clientId'); | 433 var clientId = getStringAttr(message.data, 'clientId'); |
| 455 var sharedSecret = getStringAttr(message.data, 'sharedSecret'); | 434 var sharedSecret = getStringAttr(message.data, 'sharedSecret'); |
| 456 this.onPairingComplete_(clientId, sharedSecret); | 435 this.onPairingComplete_(clientId, sharedSecret); |
| 457 | 436 |
| 458 } else if (message.method == 'extensionMessage') { | 437 } else if (message.method == 'extensionMessage') { |
| 459 var extMsgType = getStringAttr(message.data, 'type'); | 438 var extMsgType = getStringAttr(message.data, 'type'); |
| 460 var extMsgData = getStringAttr(message.data, 'data'); | 439 var extMsgData = getStringAttr(message.data, 'data'); |
| 461 switch (extMsgType) { | 440 switch (extMsgType) { |
| 462 case 'gnubby-auth': | 441 case 'gnubby-auth': |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 583 { method: 'incomingIq', data: { iq: iq } })); | 562 { method: 'incomingIq', data: { iq: iq } })); |
| 584 } else { | 563 } else { |
| 585 // plugin.onIq may not be set after the plugin has been shut | 564 // plugin.onIq may not be set after the plugin has been shut |
| 586 // down. Particularly this happens when we receive response to | 565 // down. Particularly this happens when we receive response to |
| 587 // session-terminate stanza. | 566 // session-terminate stanza. |
| 588 console.warn('plugin.onIq is not set so dropping incoming message.'); | 567 console.warn('plugin.onIq is not set so dropping incoming message.'); |
| 589 } | 568 } |
| 590 }; | 569 }; |
| 591 | 570 |
| 592 /** | 571 /** |
| 593 * @param {string} hostJid The jid of the host to connect to. | 572 * @param {remoting.Host} host The host to connect to. |
| 594 * @param {string} hostPublicKey The base64 encoded version of the host's | |
| 595 * public key. | |
| 596 * @param {string} localJid Local jid. | 573 * @param {string} localJid Local jid. |
| 597 * @param {string} sharedSecret The access code for IT2Me or the PIN | 574 * @param {remoting.CredentialsProvider} credentialsProvider |
| 598 * for Me2Me. | |
| 599 * @param {string} authenticationMethods Comma-separated list of | |
| 600 * authentication methods the client should attempt to use. | |
| 601 * @param {string} authenticationTag A host-specific tag to mix into | |
| 602 * authentication hashes. | |
| 603 * @param {string} clientPairingId For paired Me2Me connections, the | |
| 604 * pairing id for this client, as issued by the host. | |
| 605 * @param {string} clientPairedSecret For paired Me2Me connections, the | |
| 606 * paired secret for this client, as issued by the host. | |
| 607 */ | 575 */ |
| 608 remoting.ClientPluginImpl.prototype.connect = function( | 576 remoting.ClientPluginImpl.prototype.connect = |
| 609 hostJid, hostPublicKey, localJid, sharedSecret, | 577 function(host, localJid, credentialsProvider) { |
| 610 authenticationMethods, authenticationTag, | |
| 611 clientPairingId, clientPairedSecret) { | |
| 612 var keyFilter = ''; | 578 var keyFilter = ''; |
| 613 if (remoting.platformIsMac()) { | 579 if (remoting.platformIsMac()) { |
| 614 keyFilter = 'mac'; | 580 keyFilter = 'mac'; |
| 615 } else if (remoting.platformIsChromeOS()) { | 581 } else if (remoting.platformIsChromeOS()) { |
| 616 keyFilter = 'cros'; | 582 keyFilter = 'cros'; |
| 617 } | 583 } |
| 618 // Use PPB_VideoDecoder API only in Chrome 42 and above. It is broken in | 584 // Use PPB_VideoDecoder API only in Chrome 42 and above. It is broken in |
| 619 // previous versions of Chrome, see http://crbug.com/447403 . | 585 // previous versions of Chrome, see http://crbug.com/447403 . |
| 620 // Currently PPAPI doesn't provide a way for plugins to check the Chrome | 586 // Currently PPAPI doesn't provide a way for plugins to check the Chrome |
| 621 // version, so this check needs to be in the webapp. | 587 // version, so this check needs to be in the webapp. |
| 622 var enableVideoDecodeRenderer = | 588 var enableVideoDecodeRenderer = |
| 623 parseInt((remoting.getChromeVersion() || '0').split('.')[0], 10) >= 42; | 589 parseInt((remoting.getChromeVersion() || '0').split('.')[0], 10) >= 42; |
| 624 this.plugin_.postMessage(JSON.stringify( | 590 this.plugin_.postMessage(JSON.stringify( |
| 625 { method: 'delegateLargeCursors', data: {} })); | 591 { method: 'delegateLargeCursors', data: {} })); |
| 592 var methods = 'third_party,spake2_pair,spake2_hmac,spake2_plain'; |
| 593 this.credentials_ = credentialsProvider; |
| 594 this.useAsyncPinDialog_(); |
| 626 this.plugin_.postMessage(JSON.stringify( | 595 this.plugin_.postMessage(JSON.stringify( |
| 627 { method: 'connect', data: { | 596 { method: 'connect', data: { |
| 628 hostJid: hostJid, | 597 hostJid: host.jabberId, |
| 629 hostPublicKey: hostPublicKey, | 598 hostPublicKey: host.publicKey, |
| 630 localJid: localJid, | 599 localJid: localJid, |
| 631 sharedSecret: sharedSecret, | 600 sharedSecret: '', |
| 632 authenticationMethods: authenticationMethods, | 601 authenticationMethods: methods, |
| 633 authenticationTag: authenticationTag, | 602 authenticationTag: host.hostId, |
| 634 capabilities: this.capabilities_.join(" "), | 603 capabilities: this.capabilities_.join(" "), |
| 635 clientPairingId: clientPairingId, | 604 clientPairingId: credentialsProvider.getPairingInfo().id, |
| 636 clientPairedSecret: clientPairedSecret, | 605 clientPairedSecret: credentialsProvider.getPairingInfo().secret, |
| 637 keyFilter: keyFilter, | 606 keyFilter: keyFilter, |
| 638 enableVideoDecodeRenderer: enableVideoDecodeRenderer | 607 enableVideoDecodeRenderer: enableVideoDecodeRenderer |
| 639 } | 608 } |
| 640 })); | 609 })); |
| 641 }; | 610 }; |
| 642 | 611 |
| 643 /** | 612 /** |
| 644 * Release all currently pressed keys. | 613 * Release all currently pressed keys. |
| 645 */ | 614 */ |
| 646 remoting.ClientPluginImpl.prototype.releaseAllKeys = function() { | 615 remoting.ClientPluginImpl.prototype.releaseAllKeys = function() { |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 783 return; | 752 return; |
| 784 } | 753 } |
| 785 this.plugin_.postMessage(JSON.stringify( | 754 this.plugin_.postMessage(JSON.stringify( |
| 786 { method: 'videoControl', data: { losslessColor: wantLossless }})); | 755 { method: 'videoControl', data: { losslessColor: wantLossless }})); |
| 787 }; | 756 }; |
| 788 | 757 |
| 789 /** | 758 /** |
| 790 * Called when a PIN is obtained from the user. | 759 * Called when a PIN is obtained from the user. |
| 791 * | 760 * |
| 792 * @param {string} pin The PIN. | 761 * @param {string} pin The PIN. |
| 762 * @private |
| 793 */ | 763 */ |
| 794 remoting.ClientPluginImpl.prototype.onPinFetched = | 764 remoting.ClientPluginImpl.prototype.onPinFetched_ = |
| 795 function(pin) { | 765 function(pin) { |
| 796 if (!this.hasFeature(remoting.ClientPlugin.Feature.ASYNC_PIN)) { | 766 if (!this.hasFeature(remoting.ClientPlugin.Feature.ASYNC_PIN)) { |
| 797 return; | 767 return; |
| 798 } | 768 } |
| 799 this.plugin_.postMessage(JSON.stringify( | 769 this.plugin_.postMessage(JSON.stringify( |
| 800 { method: 'onPinFetched', data: { pin: pin }})); | 770 { method: 'onPinFetched', data: { pin: pin }})); |
| 801 }; | 771 }; |
| 802 | 772 |
| 803 /** | 773 /** |
| 804 * Tells the plugin to ask for the PIN asynchronously. | 774 * Tells the plugin to ask for the PIN asynchronously. |
| 775 * @private |
| 805 */ | 776 */ |
| 806 remoting.ClientPluginImpl.prototype.useAsyncPinDialog = | 777 remoting.ClientPluginImpl.prototype.useAsyncPinDialog_ = |
| 807 function() { | 778 function() { |
| 808 if (!this.hasFeature(remoting.ClientPlugin.Feature.ASYNC_PIN)) { | 779 if (!this.hasFeature(remoting.ClientPlugin.Feature.ASYNC_PIN)) { |
| 809 return; | 780 return; |
| 810 } | 781 } |
| 811 this.plugin_.postMessage(JSON.stringify( | 782 this.plugin_.postMessage(JSON.stringify( |
| 812 { method: 'useAsyncPinDialog', data: {} })); | 783 { method: 'useAsyncPinDialog', data: {} })); |
| 813 }; | 784 }; |
| 814 | 785 |
| 815 /** | 786 /** |
| 816 * Allows automatic mouse-lock. | 787 * Allows automatic mouse-lock. |
| 817 */ | 788 */ |
| 818 remoting.ClientPluginImpl.prototype.allowMouseLock = function() { | 789 remoting.ClientPluginImpl.prototype.allowMouseLock = function() { |
| 819 this.plugin_.postMessage(JSON.stringify( | 790 this.plugin_.postMessage(JSON.stringify( |
| 820 { method: 'allowMouseLock', data: {} })); | 791 { method: 'allowMouseLock', data: {} })); |
| 821 }; | 792 }; |
| 822 | 793 |
| 823 /** | 794 /** |
| 824 * Sets the third party authentication token and shared secret. | 795 * Sets the third party authentication token and shared secret. |
| 825 * | 796 * |
| 826 * @param {string} token The token received from the token URL. | 797 * @param {remoting.ThirdPartyToken} token |
| 827 * @param {string} sharedSecret Shared secret received from the token URL. | 798 * @private |
| 828 */ | 799 */ |
| 829 remoting.ClientPluginImpl.prototype.onThirdPartyTokenFetched = function( | 800 remoting.ClientPluginImpl.prototype.onThirdPartyTokenFetched_ = function( |
| 830 token, sharedSecret) { | 801 token) { |
| 831 this.plugin_.postMessage(JSON.stringify( | 802 this.plugin_.postMessage(JSON.stringify( |
| 832 { method: 'onThirdPartyTokenFetched', | 803 { method: 'onThirdPartyTokenFetched', |
| 833 data: { token: token, sharedSecret: sharedSecret}})); | 804 data: { token: token.token, sharedSecret: token.secret}})); |
| 834 }; | 805 }; |
| 835 | 806 |
| 836 /** | 807 /** |
| 837 * Request pairing with the host for PIN-less authentication. | 808 * Request pairing with the host for PIN-less authentication. |
| 838 * | 809 * |
| 839 * @param {string} clientName The human-readable name of the client. | 810 * @param {string} clientName The human-readable name of the client. |
| 840 * @param {function(string, string):void} onDone, Callback to receive the | 811 * @param {function(string, string):void} onDone, Callback to receive the |
| 841 * client id and shared secret when they are available. | 812 * client id and shared secret when they are available. |
| 842 */ | 813 */ |
| 843 remoting.ClientPluginImpl.prototype.requestPairing = | 814 remoting.ClientPluginImpl.prototype.requestPairing = |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 937 remoting.DefaultClientPluginFactory.prototype.preloadPlugin = function() { | 908 remoting.DefaultClientPluginFactory.prototype.preloadPlugin = function() { |
| 938 if (remoting.settings.CLIENT_PLUGIN_TYPE != 'pnacl') { | 909 if (remoting.settings.CLIENT_PLUGIN_TYPE != 'pnacl') { |
| 939 return; | 910 return; |
| 940 } | 911 } |
| 941 | 912 |
| 942 var plugin = remoting.ClientPluginImpl.createPluginElement_(); | 913 var plugin = remoting.ClientPluginImpl.createPluginElement_(); |
| 943 plugin.addEventListener( | 914 plugin.addEventListener( |
| 944 'loadend', function() { document.body.removeChild(plugin); }, false); | 915 'loadend', function() { document.body.removeChild(plugin); }, false); |
| 945 document.body.appendChild(plugin); | 916 document.body.appendChild(plugin); |
| 946 }; | 917 }; |
| OLD | NEW |