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 || {};
13 * @param {remoting.Host} host
16 * @implements {remoting.Activity}
18 remoting.Me2MeActivity = function(host) {
23 new remoting.PinDialog(document.getElementById('pin-dialog'), host);
25 this.hostUpdateDialog_ = new remoting.HostNeedsUpdateDialog(
26 document.getElementById('host-needs-update-dialog'), this.host_);
29 this.retryOnHostOffline_ = true;
31 /** @private {remoting.SmartReconnector} */
32 this.reconnector_ = null;
34 /** @private {remoting.DesktopRemotingActivity} */
35 this.desktopActivity_ = null;
38 remoting.Me2MeActivity.prototype.dispose = function() {
39 base.dispose(this.desktopActivity_);
40 this.desktopActivity_ = null;
43 remoting.Me2MeActivity.prototype.start = function() {
44 var webappVersion = chrome.runtime.getManifest().version;
47 this.hostUpdateDialog_.showIfNecessary(webappVersion).then(function() {
48 return that.host_.options.load();
51 }).catch(function(/** remoting.Error */ error) {
52 if (error.hasTag(remoting.Error.Tag.CANCELLED)) {
53 remoting.setMode(remoting.AppMode.HOME);
58 remoting.Me2MeActivity.prototype.stop = function() {
59 this.desktopActivity_.stop();
62 /** @return {remoting.DesktopRemotingActivity} */
63 remoting.Me2MeActivity.prototype.getDesktopActivity = function() {
64 return this.desktopActivity_;
68 * @param {boolean} suppressHostOfflineError
71 remoting.Me2MeActivity.prototype.connect_ = function(suppressHostOfflineError) {
72 remoting.setMode(remoting.AppMode.CLIENT_CONNECTING);
73 base.dispose(this.desktopActivity_);
74 this.desktopActivity_ = new remoting.DesktopRemotingActivity(this);
75 var connector = remoting.SessionConnector.factory.createConnector(
76 document.getElementById('client-container'),
77 remoting.app_capabilities(),
78 this.desktopActivity_);
81 remoting.Application.Mode.ME2ME,
82 this.host_, this.createCredentialsProvider_(), suppressHostOfflineError);
86 * @return {remoting.CredentialsProvider}
89 remoting.Me2MeActivity.prototype.createCredentialsProvider_ = function() {
90 var host = this.host_;
94 * @param {string} tokenUrl Token-issue URL received from the host.
95 * @param {string} hostPublicKey Host public key (DER and Base64 encoded).
96 * @param {string} scope OAuth scope to request the token for.
97 * @param {function(string, string):void} onThirdPartyTokenFetched Callback.
99 var fetchThirdPartyToken = function(
100 tokenUrl, hostPublicKey, scope, onThirdPartyTokenFetched) {
101 var thirdPartyTokenFetcher = new remoting.ThirdPartyTokenFetcher(
102 tokenUrl, hostPublicKey, scope, host.tokenUrlPatterns,
103 onThirdPartyTokenFetched);
104 thirdPartyTokenFetcher.fetchToken();
108 * @param {boolean} supportsPairing
109 * @param {function(string):void} onPinFetched
111 var requestPin = function(supportsPairing, onPinFetched) {
112 that.pinDialog_.show(supportsPairing).then(function(/** string */ pin) {
113 remoting.setMode(remoting.AppMode.CLIENT_CONNECTING);
115 }).catch(function(/** remoting.Error */ error) {
116 base.debug.assert(error.hasTag(remoting.Error.Tag.CANCELLED));
117 remoting.setMode(remoting.AppMode.HOME);
121 return new remoting.CredentialsProvider({
122 fetchPin: requestPin,
123 pairingInfo: /** @type{remoting.PairingInfo} */ (
124 base.deepCopy(host.options.pairingInfo)),
125 fetchThirdPartyToken: fetchThirdPartyToken
130 * @param {!remoting.Error} error
132 remoting.Me2MeActivity.prototype.onConnectionFailed = function(error) {
133 if (error.hasTag(remoting.Error.Tag.HOST_IS_OFFLINE) &&
134 this.retryOnHostOffline_) {
136 var onHostListRefresh = function(/** boolean */ success) {
138 // Get the host from the hostList for the refreshed JID.
139 that.host_ = remoting.hostList.getHostForId(that.host_.hostId);
140 that.connect_(false);
145 this.retryOnHostOffline_ = false;
147 // The plugin will be re-created when the host finished refreshing
148 remoting.hostList.refresh(onHostListRefresh);
155 * @param {!remoting.ConnectionInfo} connectionInfo
157 remoting.Me2MeActivity.prototype.onConnected = function(connectionInfo) {
158 // Reset the refresh flag so that the next connection will retry if needed.
159 this.retryOnHostOffline_ = true;
161 var plugin = connectionInfo.plugin();
162 if (plugin.hasCapability(remoting.ClientSession.Capability.CAST)) {
163 plugin.extensions().register(new remoting.CastExtensionHandler());
165 plugin.extensions().register(new remoting.GnubbyAuthHandler());
166 this.pinDialog_.requestPairingIfNecessary(connectionInfo.plugin());
168 base.dispose(this.reconnector_);
169 this.reconnector_ = new remoting.SmartReconnector(
170 this.connect_.bind(this, false),
171 this.stop.bind(this),
172 connectionInfo.session());
175 remoting.Me2MeActivity.prototype.onDisconnected = function() {
176 this.showFinishDialog_(remoting.AppMode.CLIENT_SESSION_FINISHED_ME2ME);
180 * @param {!remoting.Error} error
182 remoting.Me2MeActivity.prototype.onError = function(error) {
183 var errorDiv = document.getElementById('connect-error-message');
184 l10n.localizeElementFromTag(errorDiv, error.getTag());
185 this.showFinishDialog_(remoting.AppMode.CLIENT_CONNECT_FAILED_ME2ME);
189 * @param {remoting.AppMode} mode
192 remoting.Me2MeActivity.prototype.showFinishDialog_ = function(mode) {
193 var dialog = new remoting.MessageDialog(
195 document.getElementById('client-finished-me2me-button'),
196 document.getElementById('client-reconnect-button'));
198 /** @typedef {remoting.MessageDialog.Result} */
199 var Result = remoting.MessageDialog.Result;
202 dialog.show().then(function(/** Result */result) {
203 if (result === Result.PRIMARY) {
204 remoting.setMode(remoting.AppMode.HOME);
212 * @param {HTMLElement} rootElement
213 * @param {remoting.Host} host
216 remoting.HostNeedsUpdateDialog = function(rootElement, host) {
220 this.dialog_ = new remoting.MessageDialog(
221 remoting.AppMode.CLIENT_HOST_NEEDS_UPGRADE,
222 rootElement.querySelector('.connect-button'),
223 rootElement.querySelector('.cancel-button'));
225 l10n.localizeElementFromTag(
226 rootElement.querySelector('.host-needs-update-message'),
227 /*i18n-content*/'HOST_NEEDS_UPDATE_TITLE', host.hostName);
231 * Shows the HostNeedsUpdateDialog if the user is trying to connect to a legacy
234 * @param {string} webappVersion
235 * @return {Promise} Promise that resolves when no update is required or
236 * when the user ignores the update warning. Rejects with
237 * |remoting.Error.CANCELLED| if the user cancels the connection.
239 remoting.HostNeedsUpdateDialog.prototype.showIfNecessary =
240 function(webappVersion) {
241 if (!remoting.Host.needsUpdate(this.host_, webappVersion)) {
242 return Promise.resolve();
244 /** @typedef {remoting.MessageDialog.Result} */
245 var Result = remoting.MessageDialog.Result;
246 return this.dialog_.show().then(function(/** Result */ result) {
247 if (result === Result.SECONDARY) {
248 return Promise.reject(new remoting.Error(remoting.Error.Tag.CANCELLED));
254 * @param {HTMLElement} rootElement
255 * @param {remoting.Host} host
258 remoting.PinDialog = function(rootElement, host) {
260 this.rootElement_ = rootElement;
262 this.pairingCheckbox_ = rootElement.querySelector('.pairing-checkbox');
264 this.pinInput_ = rootElement.querySelector('.pin-inputField');
268 this.dialog_ = new remoting.InputDialog(
269 remoting.AppMode.CLIENT_PIN_PROMPT,
270 this.rootElement_.querySelector('form'),
272 this.rootElement_.querySelector('.cancel-button'));
277 * @param {boolean} supportsPairing
278 * @return {Promise<string>} Promise that resolves with the PIN or rejects with
279 * |remoting.Error.CANCELLED| if the user cancels the connection.
281 remoting.PinDialog.prototype.show = function(supportsPairing) {
283 this.pairingCheckbox_.checked = false;
284 this.rootElement_.querySelector('.pairing-section').hidden = !supportsPairing;
285 var message = this.rootElement_.querySelector('.pin-message');
286 l10n.localizeElement(message, this.host_.hostName);
287 this.pinInput_.value = '';
288 return this.dialog_.show();
292 * @param {remoting.ClientPlugin} plugin
294 remoting.PinDialog.prototype.requestPairingIfNecessary = function(plugin) {
295 if (this.pairingCheckbox_.checked) {
298 * @param {string} clientId
299 * @param {string} sharedSecret
301 var onPairingComplete = function(clientId, sharedSecret) {
302 that.host_.options.pairingInfo.clientId = clientId;
303 that.host_.options.pairingInfo.sharedSecret = sharedSecret;
304 that.host_.options.save();
307 // Use the platform name as a proxy for the local computer name.
308 // TODO(jamiewalch): Use a descriptive name for the local computer, for
309 // example, its Chrome Sync name.
311 if (remoting.platformIsMac()) {
313 } else if (remoting.platformIsWindows()) {
314 clientName = 'Windows';
315 } else if (remoting.platformIsChromeOS()) {
316 clientName = 'ChromeOS';
317 } else if (remoting.platformIsLinux()) {
318 clientName = 'Linux';
320 console.log('Unrecognized client platform. Using navigator.platform.');
321 clientName = navigator.platform;
323 plugin.requestPairing(clientName, onPairingComplete);