Updating XTBs based on .GRDs from branch master
[chromium-blink-merge.git] / remoting / webapp / crd / js / me2me_activity.js
blob7d1f29ae2a489946da42390388415eeb28e7a54f
1 // Copyright 2015 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.
5 /** @suppress {duplicate} */
6 var remoting = remoting || {};
8 (function() {
10 'use strict';
12 /**
13  * @param {remoting.Host} host
14  * @param {remoting.HostList} hostList
15  *
16  * @constructor
17  * @implements {remoting.Activity}
18  */
19 remoting.Me2MeActivity = function(host, hostList) {
20   /** @private */
21   this.host_ = host;
22   /** @private */
23   this.hostList_ = hostList;
24   /** @private */
25   this.pinDialog_ =
26       new remoting.PinDialog(document.getElementById('pin-dialog'), host);
27   /** @private */
28   this.hostUpdateDialog_ = new remoting.HostNeedsUpdateDialog(
29       document.getElementById('host-needs-update-dialog'), this.host_);
31   /** @private */
32   this.retryOnHostOffline_ = true;
34   /** @private {remoting.SmartReconnector} */
35   this.reconnector_ = null;
37   /** @private {remoting.DesktopRemotingActivity} */
38   this.desktopActivity_ = null;
41 remoting.Me2MeActivity.prototype.dispose = function() {
42   base.dispose(this.desktopActivity_);
43   this.desktopActivity_ = null;
46 remoting.Me2MeActivity.prototype.start = function() {
47   var webappVersion = chrome.runtime.getManifest().version;
48   var that = this;
50   this.hostUpdateDialog_.showIfNecessary(webappVersion).then(function() {
51     return that.host_.options.load();
52   }).then(function() {
53     that.connect_(true);
54   }).catch(remoting.Error.handler(function(/** remoting.Error */ error) {
55     if (error.hasTag(remoting.Error.Tag.CANCELLED)) {
56       remoting.setMode(remoting.AppMode.HOME);
57     }
58   }));
61 remoting.Me2MeActivity.prototype.stop = function() {
62   if (this.desktopActivity_) {
63     this.desktopActivity_.stop();
64   }
67 /** @return {remoting.DesktopRemotingActivity} */
68 remoting.Me2MeActivity.prototype.getDesktopActivity = function() {
69   return this.desktopActivity_;
72 /**
73  * @param {boolean} suppressHostOfflineError
74  * @private
75  */
76 remoting.Me2MeActivity.prototype.connect_ = function(suppressHostOfflineError) {
77   base.dispose(this.desktopActivity_);
78   this.desktopActivity_ = new remoting.DesktopRemotingActivity(this);
79   this.desktopActivity_.getConnectingDialog().show();
80   this.desktopActivity_.start(this.host_, this.createCredentialsProvider_(),
81                               suppressHostOfflineError);
84 /**
85  * @return {remoting.CredentialsProvider}
86  * @private
87  */
88 remoting.Me2MeActivity.prototype.createCredentialsProvider_ = function() {
89   var host = this.host_;
90   var that = this;
92   /**
93    * @param {string} tokenUrl Token-issue URL received from the host.
94    * @param {string} hostPublicKey Host public key (DER and Base64 encoded).
95    * @param {string} scope OAuth scope to request the token for.
96    * @param {function(string, string):void} onThirdPartyTokenFetched Callback.
97    */
98   var fetchThirdPartyToken = function(
99       tokenUrl, hostPublicKey, scope, onThirdPartyTokenFetched) {
100     var thirdPartyTokenFetcher = new remoting.ThirdPartyTokenFetcher(
101         tokenUrl, hostPublicKey, scope, host.tokenUrlPatterns,
102         onThirdPartyTokenFetched);
103     thirdPartyTokenFetcher.fetchToken();
104   };
106   /**
107    * @param {boolean} supportsPairing
108    * @param {function(string):void} onPinFetched
109    */
110   var requestPin = function(supportsPairing, onPinFetched) {
111     // Set time when PIN was requested.
112     var authStartTime = new Date().getTime();
113     that.desktopActivity_.getConnectingDialog().hide();
114     that.pinDialog_.show(supportsPairing).then(function(/** string */ pin) {
115       remoting.setMode(remoting.AppMode.CLIENT_CONNECTING);
116       // Done obtaining PIN information. Log time taken for PIN entry.
117       var logToServer = that.desktopActivity_.getSession().getLogger();
118       logToServer.setAuthTotalTime(new Date().getTime() - authStartTime);
119       onPinFetched(pin);
120     }).catch(remoting.Error.handler(function(/** remoting.Error */ error) {
121       console.assert(error.hasTag(remoting.Error.Tag.CANCELLED),
122                     'Unexpected error: ' + error.getTag() + '.');
123       remoting.setMode(remoting.AppMode.HOME);
124       that.stop();
125     }));
126   };
128   return new remoting.CredentialsProvider({
129     fetchPin: requestPin,
130     pairingInfo: /** @type{remoting.PairingInfo} */ (
131         base.deepCopy(host.options.pairingInfo)),
132     fetchThirdPartyToken: fetchThirdPartyToken
133   });
137  * @param {!remoting.Error} error
138  */
139 remoting.Me2MeActivity.prototype.onConnectionFailed = function(error) {
140   if (error.hasTag(remoting.Error.Tag.HOST_IS_OFFLINE) &&
141       this.retryOnHostOffline_) {
142     var that = this;
143     var onHostListRefresh = function(/** boolean */ success) {
144       if (success) {
145         // Get the host from the hostList for the refreshed JID.
146         that.host_ = that.hostList_.getHostForId(that.host_.hostId);
147         that.connect_(false);
148         return;
149       }
150       that.showErrorMessage_(error);
151     };
152     this.retryOnHostOffline_ = false;
154     // The plugin will be re-created when the host finished refreshing
155     this.hostList_.refresh(onHostListRefresh);
156   } else if (!error.isNone()) {
157     this.showErrorMessage_(error);
158   }
160   base.dispose(this.desktopActivity_);
161   this.desktopActivity_ = null;
165  * @param {!remoting.ConnectionInfo} connectionInfo
166  */
167 remoting.Me2MeActivity.prototype.onConnected = function(connectionInfo) {
168   // Reset the refresh flag so that the next connection will retry if needed.
169   this.retryOnHostOffline_ = true;
171   var plugin = connectionInfo.plugin();
172   if (plugin.hasCapability(remoting.ClientSession.Capability.CAST)) {
173     plugin.extensions().register(new remoting.CastExtensionHandler());
174   }
175   plugin.extensions().register(new remoting.GnubbyAuthHandler());
176   this.pinDialog_.requestPairingIfNecessary(connectionInfo.plugin());
178   base.dispose(this.reconnector_);
179   this.reconnector_ = new remoting.SmartReconnector(
180       this.desktopActivity_.getConnectingDialog(),
181       this.connect_.bind(this, false),
182       this.stop.bind(this),
183       connectionInfo.session());
186 remoting.Me2MeActivity.prototype.onDisconnected = function(error) {
187   if (error.isNone()) {
188     this.showFinishDialog_(remoting.AppMode.CLIENT_SESSION_FINISHED_ME2ME);
189   } else {
190     this.reconnector_.onConnectionDropped(error);
191     this.showErrorMessage_(error);
192   }
194   base.dispose(this.desktopActivity_);
195   this.desktopActivity_ = null;
199  * @param {!remoting.Error} error
200  * @private
201  */
202 remoting.Me2MeActivity.prototype.showErrorMessage_ = function(error) {
203   var errorDiv = document.getElementById('connect-error-message');
204   l10n.localizeElementFromTag(errorDiv, error.getTag());
205   this.showFinishDialog_(remoting.AppMode.CLIENT_CONNECT_FAILED_ME2ME);
209  * @param {remoting.AppMode} mode
210  * @private
211  */
212 remoting.Me2MeActivity.prototype.showFinishDialog_ = function(mode) {
213   var dialog = new remoting.MessageDialog(
214       mode,
215       document.getElementById('client-finished-me2me-button'),
216       document.getElementById('client-reconnect-button'));
218   /** @typedef {remoting.MessageDialog.Result} */
219   var Result = remoting.MessageDialog.Result;
220   var that = this;
222   dialog.show().then(function(/** Result */result) {
223     if (result === Result.PRIMARY) {
224       remoting.setMode(remoting.AppMode.HOME);
225     } else {
226       that.connect_(true);
227     }
228   });
232  * @param {HTMLElement} rootElement
233  * @param {remoting.Host} host
234  * @constructor
235  */
236 remoting.HostNeedsUpdateDialog = function(rootElement, host) {
237   /** @private */
238   this.host_ = host;
239   /** @private */
240   this.dialog_ = new remoting.MessageDialog(
241       remoting.AppMode.CLIENT_HOST_NEEDS_UPGRADE,
242       rootElement.querySelector('.connect-button'),
243       rootElement.querySelector('.cancel-button'));
245   l10n.localizeElementFromTag(
246       rootElement.querySelector('.host-needs-update-message'),
247       /*i18n-content*/'HOST_NEEDS_UPDATE_TITLE', host.hostName);
251  * Shows the HostNeedsUpdateDialog if the user is trying to connect to a legacy
252  * host.
254  * @param {string} webappVersion
255  * @return {Promise}  Promise that resolves when no update is required or
256  *    when the user ignores the update warning.  Rejects with
257  *    |remoting.Error.CANCELLED| if the user cancels the connection.
258  */
259 remoting.HostNeedsUpdateDialog.prototype.showIfNecessary =
260     function(webappVersion) {
261   if (!remoting.Host.needsUpdate(this.host_, webappVersion)) {
262     return Promise.resolve();
263   }
264   /** @typedef {remoting.MessageDialog.Result} */
265   var Result = remoting.MessageDialog.Result;
266   return this.dialog_.show().then(function(/** Result */ result) {
267     if (result === Result.SECONDARY) {
268       return Promise.reject(new remoting.Error(remoting.Error.Tag.CANCELLED));
269     }
270   });
274  * @param {HTMLElement} rootElement
275  * @param {remoting.Host} host
276  * @constructor
277  */
278 remoting.PinDialog = function(rootElement, host) {
279   /** @private */
280   this.rootElement_ = rootElement;
281   /** @private */
282   this.pairingCheckbox_ = rootElement.querySelector('.pairing-checkbox');
283   /** @private */
284   this.pinInput_ = rootElement.querySelector('.pin-inputField');
285   /** @private */
286   this.host_ = host;
287   /** @private */
288   this.dialog_ = new remoting.InputDialog(
289     remoting.AppMode.CLIENT_PIN_PROMPT,
290     this.rootElement_.querySelector('form'),
291     this.pinInput_,
292     this.rootElement_.querySelector('.cancel-button'));
297  * @param {boolean} supportsPairing
298  * @return {Promise<string>}  Promise that resolves with the PIN or rejects with
299  *    |remoting.Error.CANCELLED| if the user cancels the connection.
300  */
301 remoting.PinDialog.prototype.show = function(supportsPairing) {
302   // Reset the UI.
303   this.pairingCheckbox_.checked = false;
304   this.rootElement_.querySelector('.pairing-section').hidden = !supportsPairing;
305   var message = this.rootElement_.querySelector('.pin-message');
306   l10n.localizeElement(message, this.host_.hostName);
307   this.pinInput_.value = '';
308   return this.dialog_.show();
312  * @param {remoting.ClientPlugin} plugin
313  */
314 remoting.PinDialog.prototype.requestPairingIfNecessary = function(plugin) {
315   if (this.pairingCheckbox_.checked) {
316     var that = this;
317     /**
318      * @param {string} clientId
319      * @param {string} sharedSecret
320      */
321     var onPairingComplete = function(clientId, sharedSecret) {
322       that.host_.options.pairingInfo.clientId = clientId;
323       that.host_.options.pairingInfo.sharedSecret = sharedSecret;
324       that.host_.options.save();
325     };
327     // Use the platform name as a proxy for the local computer name.
328     // TODO(jamiewalch): Use a descriptive name for the local computer, for
329     // example, its Chrome Sync name.
330     var clientName = '';
331     if (remoting.platformIsMac()) {
332       clientName = 'Mac';
333     } else if (remoting.platformIsWindows()) {
334       clientName = 'Windows';
335     } else if (remoting.platformIsChromeOS()) {
336       clientName = 'ChromeOS';
337     } else if (remoting.platformIsLinux()) {
338       clientName = 'Linux';
339     } else {
340       console.log('Unrecognized client platform. Using navigator.platform.');
341       clientName = navigator.platform;
342     }
343     plugin.requestPairing(clientName, onPairingComplete);
344   }
347 })();