Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(288)

Side by Side Diff: remoting/webapp/crd/js/it2me_helpee_channel.js

Issue 973333002: Remove Hangout Remote Desktop integration code from the webapp. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase + manifest changes Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 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.
4
5 /**
6 * @fileoverview
7 *
8 * It2MeHelpeeChannel relays messages between the Hangouts web page (Hangouts)
9 * and the It2Me Native Messaging Host (It2MeHost) for the helpee (the Hangouts
10 * participant who is receiving remoting assistance).
11 *
12 * It runs in the background page. It contains a chrome.runtime.Port object,
13 * representing a connection to Hangouts, and a remoting.It2MeHostFacade object,
14 * representing a connection to the IT2Me Native Messaging Host.
15 *
16 * Hangouts It2MeHelpeeChannel It2MeHost
17 * |---------runtime.connect()-------->| |
18 * |-----------hello message---------->| |
19 * |<-----helloResponse message------->| |
20 * |----------connect message--------->| |
21 * | |-----showConfirmDialog()----->|
22 * | |----------connect()---------->|
23 * | |<-------hostStateChanged------|
24 * | | (RECEIVED_ACCESS_CODE) |
25 * |<---connect response (access code)-| |
26 * | | |
27 *
28 * Hangouts will send the access code to the web app on the helper side.
29 * The helper will then connect to the It2MeHost using the access code.
30 *
31 * Hangouts It2MeHelpeeChannel It2MeHost
32 * | |<-------hostStateChanged------|
33 * | | (CONNECTED) |
34 * |<-- hostStateChanged(CONNECTED)----| |
35 * |-------disconnect message--------->| |
36 * |<--hostStateChanged(DISCONNECTED)--| |
37 *
38 *
39 * It also handles host downloads and install status queries:
40 *
41 * Hangouts It2MeHelpeeChannel
42 * |------isHostInstalled message----->|
43 * |<-isHostInstalled response(false)--|
44 * | |
45 * |--------downloadHost message------>|
46 * | |
47 * |------isHostInstalled message----->|
48 * |<-isHostInstalled response(false)--|
49 * | |
50 * |------isHostInstalled message----->|
51 * |<-isHostInstalled response(true)---|
52 */
53
54 'use strict';
55
56 /** @suppress {duplicate} */
57 var remoting = remoting || {};
58
59 /**
60 * @param {chrome.runtime.Port} hangoutPort
61 * @param {remoting.It2MeHostFacade} host
62 * @param {remoting.HostInstaller} hostInstaller
63 * @param {function()} onDisposedCallback Callback to notify the client when
64 * the connection is torn down.
65 *
66 * @constructor
67 * @implements {base.Disposable}
68 */
69 remoting.It2MeHelpeeChannel =
70 function(hangoutPort, host, hostInstaller, onDisposedCallback) {
71 /**
72 * @type {chrome.runtime.Port}
73 * @private
74 */
75 this.hangoutPort_ = hangoutPort;
76
77 /**
78 * @type {remoting.It2MeHostFacade}
79 * @private
80 */
81 this.host_ = host;
82
83 /**
84 * @type {?remoting.HostInstaller}
85 * @private
86 */
87 this.hostInstaller_ = hostInstaller;
88
89 /**
90 * @type {remoting.HostSession.State}
91 * @private
92 */
93 this.hostState_ = remoting.HostSession.State.UNKNOWN;
94
95 /**
96 * @type {?function()}
97 * @private
98 */
99 this.onDisposedCallback_ = onDisposedCallback;
100
101 this.onHangoutMessageRef_ = this.onHangoutMessage_.bind(this);
102 this.onHangoutDisconnectRef_ = this.onHangoutDisconnect_.bind(this);
103 };
104
105 /** @enum {string} */
106 remoting.It2MeHelpeeChannel.HangoutMessageTypes = {
107 CONNECT: 'connect',
108 CONNECT_RESPONSE: 'connectResponse',
109 DISCONNECT: 'disconnect',
110 DOWNLOAD_HOST: 'downloadHost',
111 ERROR: 'error',
112 HELLO: 'hello',
113 HELLO_RESPONSE: 'helloResponse',
114 HOST_STATE_CHANGED: 'hostStateChanged',
115 IS_HOST_INSTALLED: 'isHostInstalled',
116 IS_HOST_INSTALLED_RESPONSE: 'isHostInstalledResponse'
117 };
118
119 /** @enum {string} */
120 remoting.It2MeHelpeeChannel.Features = {
121 REMOTE_ASSISTANCE: 'remoteAssistance'
122 };
123
124 remoting.It2MeHelpeeChannel.prototype.init = function() {
125 this.hangoutPort_.onMessage.addListener(this.onHangoutMessageRef_);
126 this.hangoutPort_.onDisconnect.addListener(this.onHangoutDisconnectRef_);
127 };
128
129 remoting.It2MeHelpeeChannel.prototype.dispose = function() {
130 if (this.host_ !== null) {
131 this.host_.unhookCallbacks();
132 this.host_.disconnect();
133 this.host_ = null;
134 }
135
136 if (this.hangoutPort_ !== null) {
137 this.hangoutPort_.onMessage.removeListener(this.onHangoutMessageRef_);
138 this.hangoutPort_.onDisconnect.removeListener(this.onHangoutDisconnectRef_);
139 this.hostState_ = remoting.HostSession.State.DISCONNECTED;
140
141 try {
142 var MessageTypes = remoting.It2MeHelpeeChannel.HangoutMessageTypes;
143 this.hangoutPort_.postMessage({
144 method: MessageTypes.HOST_STATE_CHANGED,
145 state: this.hostState_
146 });
147 } catch (e) {
148 // |postMessage| throws if |this.hangoutPort_| is disconnected
149 // It is safe to ignore the exception.
150 }
151 this.hangoutPort_.disconnect();
152 this.hangoutPort_ = null;
153 }
154
155 if (this.onDisposedCallback_ !== null) {
156 this.onDisposedCallback_();
157 this.onDisposedCallback_ = null;
158 }
159 };
160
161 /**
162 * Message Handler for incoming runtime messages from Hangouts.
163 *
164 * @param {{method:string, data:Object<string,*>}} message
165 * @private
166 */
167 remoting.It2MeHelpeeChannel.prototype.onHangoutMessage_ = function(message) {
168 try {
169 var MessageTypes = remoting.It2MeHelpeeChannel.HangoutMessageTypes;
170 switch (message.method) {
171 case MessageTypes.HELLO:
172 this.hangoutPort_.postMessage({
173 method: MessageTypes.HELLO_RESPONSE,
174 supportedFeatures: base.values(remoting.It2MeHelpeeChannel.Features)
175 });
176 return true;
177 case MessageTypes.IS_HOST_INSTALLED:
178 this.handleIsHostInstalled_(message);
179 return true;
180 case MessageTypes.DOWNLOAD_HOST:
181 this.handleDownloadHost_(message);
182 return true;
183 case MessageTypes.CONNECT:
184 this.handleConnect_(message);
185 return true;
186 case MessageTypes.DISCONNECT:
187 this.dispose();
188 return true;
189 }
190 throw new Error('Unsupported message method=' + message.method);
191 } catch(/** @type {Error} */ error) {
192 this.sendErrorResponse_(message, error.message);
193 }
194 return false;
195 };
196
197 /**
198 * Queries the |hostInstaller| for the installation status.
199 *
200 * @param {{method:string, data:Object<string,*>}} message
201 * @private
202 */
203 remoting.It2MeHelpeeChannel.prototype.handleIsHostInstalled_ =
204 function(message) {
205 /** @type {remoting.It2MeHelpeeChannel} */
206 var that = this;
207
208 /** @param {boolean} installed */
209 function sendResponse(installed) {
210 var MessageTypes = remoting.It2MeHelpeeChannel.HangoutMessageTypes;
211 that.hangoutPort_.postMessage({
212 method: MessageTypes.IS_HOST_INSTALLED_RESPONSE,
213 result: installed
214 });
215 }
216
217 remoting.HostInstaller.isInstalled().then(
218 sendResponse,
219 /** @type {function(*):void} */(this.sendErrorResponse_.bind(this, message))
220 );
221 };
222
223 /**
224 * @param {{method:string, data:Object<string,*>}} message
225 * @private
226 */
227 remoting.It2MeHelpeeChannel.prototype.handleDownloadHost_ = function(message) {
228 try {
229 this.hostInstaller_.download();
230 } catch (/** @type {*} */ e) {
231 var error = /** @type {Error} */ (e);
232 this.sendErrorResponse_(message, error.message);
233 }
234 };
235
236 /**
237 * Disconnect the session if the |hangoutPort| gets disconnected.
238 * @private
239 */
240 remoting.It2MeHelpeeChannel.prototype.onHangoutDisconnect_ = function() {
241 this.dispose();
242 };
243
244 /**
245 * Connects to the It2Me Native messaging Host and retrieves the access code.
246 *
247 * @param {{method:string, data:Object<string,*>}} message
248 * @private
249 */
250 remoting.It2MeHelpeeChannel.prototype.handleConnect_ =
251 function(message) {
252 var bounds =
253 /** @type {Bounds} */ (getObjectAttr(message, 'hangoutBounds', null));
254
255 if (this.hostState_ !== remoting.HostSession.State.UNKNOWN) {
256 throw new Error('An existing connection is in progress.');
257 }
258
259 var that = this;
260 this.showConfirmDialog_(bounds)
261 .then(this.initializeHost_.bind(this))
262 .then(this.fetchOAuthToken_.bind(this))
263 .then(this.fetchEmail_.bind(this))
264 /** @param {{email:string, token:string}|Promise} result */
265 .then(function(result) {
266 that.connectToHost_(result.email, result.token);
267 /** @param {*} reason */
268 }).catch(function(reason) {
269 that.sendErrorResponse_(message, /** @type {Error} */ (reason));
270 that.dispose();
271 });
272 };
273
274 /**
275 * Prompts the user before starting the It2Me Native Messaging Host. This
276 * ensures that even if Hangouts is compromised, an attacker cannot start the
277 * host without explicit user confirmation.
278 *
279 * @param {Bounds} bounds Bounds of the hangout window
280 * @return {Promise} A promise that will resolve if the user accepts remote
281 * assistance or reject otherwise.
282 * @private
283 */
284 remoting.It2MeHelpeeChannel.prototype.showConfirmDialog_ = function(bounds) {
285 if (base.isAppsV2()) {
286 return this.showConfirmDialogV2_(bounds);
287 } else {
288 return this.showConfirmDialogV1_();
289 }
290 };
291
292 /**
293 * @return {Promise} A promise that will resolve if the user accepts remote
294 * assistance or reject otherwise.
295 * @private
296 */
297 remoting.It2MeHelpeeChannel.prototype.showConfirmDialogV1_ = function() {
298 var messageHeader = l10n.getTranslationOrError(
299 /*i18n-content*/'HANGOUTS_CONFIRM_DIALOG_MESSAGE_1');
300 var message1 = l10n.getTranslationOrError(
301 /*i18n-content*/'HANGOUTS_CONFIRM_DIALOG_MESSAGE_2');
302 var message2 = l10n.getTranslationOrError(
303 /*i18n-content*/'HANGOUTS_CONFIRM_DIALOG_MESSAGE_3');
304 var message = base.escapeHTML(messageHeader) + '\n' +
305 '- ' + base.escapeHTML(message1) + '\n' +
306 '- ' + base.escapeHTML(message2) + '\n';
307
308 if(window.confirm(message)) {
309 return Promise.resolve();
310 } else {
311 return Promise.reject(new Error(remoting.Error.CANCELLED));
312 }
313 };
314
315 /**
316 * @param {Bounds} bounds the bounds of the Hangouts Window. If set, the
317 * confirm dialog will be centered within |bounds|.
318 * @return {Promise} A promise that will resolve if the user accepts remote
319 * assistance or reject otherwise.
320 * @private
321 */
322 remoting.It2MeHelpeeChannel.prototype.showConfirmDialogV2_ = function(bounds) {
323 var getToken =
324 base.Promise.as(chrome.identity.getAuthToken, [{interactive: false}]);
325
326 return getToken;
327 };
328
329 /**
330 * @return {Promise} A promise that resolves when the host is initialized.
331 * @private
332 */
333 remoting.It2MeHelpeeChannel.prototype.initializeHost_ = function() {
334 /** @type {remoting.It2MeHostFacade} */
335 var host = this.host_;
336
337 /**
338 * @param {function(*=):void} resolve
339 * @param {function(*=):void} reject
340 */
341 return new Promise(function(resolve, reject) {
342 if (host.initialized()) {
343 resolve(true);
344 } else {
345 host.initialize(/** @type {function(*=):void} */ (resolve),
346 /** @type {function(*=):void} */ (reject));
347 }
348 });
349 };
350
351 /**
352 * @return {!Promise<string>} Promise that resolves with the OAuth token as the
353 * value.
354 */
355 remoting.It2MeHelpeeChannel.prototype.fetchOAuthToken_ = function() {
356 if (base.isAppsV2()) {
357 return remoting.identity.getToken();
358 } else {
359 var onError = function(/** * */ error) {
360 if (error === remoting.Error.NOT_AUTHENTICATED) {
361 return new Promise(function(resolve, reject) {
362 remoting.oauth2.doAuthRedirect(function() {
363 remoting.identity.getToken().then(resolve);
364 });
365 });
366 }
367 throw Error(remoting.Error.NOT_AUTHENTICATED);
368 };
369 return /** @type {!Promise<string>} */ (
370 remoting.identity.getToken().catch(onError));
371 }
372 };
373
374 /**
375 * @param {string|Promise} token
376 * @return {Promise} Promise that resolves with the access token and the email
377 * of the user.
378 */
379 remoting.It2MeHelpeeChannel.prototype.fetchEmail_ = function(token) {
380 /** @param {string} email */
381 function onEmail (email) {
382 return { email: email, token: token };
383 }
384 return remoting.identity.getEmail().then(onEmail);
385 };
386
387 /**
388 * Connects to the It2Me Native Messaging Host and retrieves the access code
389 * in the |onHostStateChanged_| callback.
390 *
391 * @param {string} email
392 * @param {string} accessToken
393 * @private
394 */
395 remoting.It2MeHelpeeChannel.prototype.connectToHost_ =
396 function(email, accessToken) {
397 base.debug.assert(this.host_.initialized());
398 this.host_.connect(
399 email,
400 'oauth2:' + accessToken,
401 this.onHostStateChanged_.bind(this),
402 base.doNothing, // Ignore |onNatPolicyChanged|.
403 console.log.bind(console), // Forward logDebugInfo to console.log.
404 remoting.settings.XMPP_SERVER_FOR_IT2ME_HOST,
405 remoting.settings.XMPP_SERVER_USE_TLS,
406 remoting.settings.DIRECTORY_BOT_JID,
407 this.onHostConnectError_);
408 };
409
410 /**
411 * @param {remoting.Error} error
412 * @private
413 */
414 remoting.It2MeHelpeeChannel.prototype.onHostConnectError_ = function(error) {
415 this.sendErrorResponse_(null, error);
416 };
417
418 /**
419 * @param {remoting.HostSession.State} state
420 * @private
421 */
422 remoting.It2MeHelpeeChannel.prototype.onHostStateChanged_ = function(state) {
423 this.hostState_ = state;
424 var MessageTypes = remoting.It2MeHelpeeChannel.HangoutMessageTypes;
425 var HostState = remoting.HostSession.State;
426
427 switch (state) {
428 case HostState.RECEIVED_ACCESS_CODE:
429 var accessCode = this.host_.getAccessCode();
430 this.hangoutPort_.postMessage({
431 method: MessageTypes.CONNECT_RESPONSE,
432 accessCode: accessCode
433 });
434 break;
435 case HostState.CONNECTED:
436 case HostState.DISCONNECTED:
437 this.hangoutPort_.postMessage({
438 method: MessageTypes.HOST_STATE_CHANGED,
439 state: state
440 });
441 break;
442 case HostState.ERROR:
443 this.sendErrorResponse_(null, remoting.Error.UNEXPECTED);
444 break;
445 case HostState.INVALID_DOMAIN_ERROR:
446 this.sendErrorResponse_(null, remoting.Error.INVALID_HOST_DOMAIN);
447 break;
448 default:
449 // It is safe to ignore other state changes.
450 }
451 };
452
453 /**
454 * @param {?{method:string, data:Object<string,*>}} incomingMessage
455 * @param {string|Error} error
456 * @private
457 */
458 remoting.It2MeHelpeeChannel.prototype.sendErrorResponse_ =
459 function(incomingMessage, error) {
460 if (error instanceof Error) {
461 error = error.message;
462 }
463
464 console.error('Error responding to message method:' +
465 (incomingMessage ? incomingMessage.method : 'null') +
466 ' error:' + error);
467 this.hangoutPort_.postMessage({
468 method: remoting.It2MeHelpeeChannel.HangoutMessageTypes.ERROR,
469 message: error,
470 request: incomingMessage
471 });
472 };
OLDNEW
« no previous file with comments | « remoting/webapp/crd/js/hangout_session.js ('k') | remoting/webapp/crd/js/it2me_helper_channel.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698