OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 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 * | 7 * |
8 * It2MeHelpeeChannel relays messages between the Hangouts web page (Hangouts) | 8 * It2MeHelpeeChannel relays messages between the Hangouts web page (Hangouts) |
9 * and the It2Me Native Messaging Host (It2MeHost) for the helpee (the Hangouts | 9 * and the It2Me Native Messaging Host (It2MeHost) for the helpee (the Hangouts |
10 * participant who is receiving remoting assistance). | 10 * participant who is receiving remoting assistance). |
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
243 | 243 |
244 /** | 244 /** |
245 * Connects to the It2Me Native messaging Host and retrieves the access code. | 245 * Connects to the It2Me Native messaging Host and retrieves the access code. |
246 * | 246 * |
247 * @param {{method:string, data:Object.<string,*>}} message | 247 * @param {{method:string, data:Object.<string,*>}} message |
248 * @private | 248 * @private |
249 */ | 249 */ |
250 remoting.It2MeHelpeeChannel.prototype.handleConnect_ = | 250 remoting.It2MeHelpeeChannel.prototype.handleConnect_ = |
251 function(message) { | 251 function(message) { |
252 var email = getStringAttr(message, 'email'); | 252 var email = getStringAttr(message, 'email'); |
| 253 var bounds = |
| 254 /** @type {Bounds} */ (getObjectAttr(message, 'hangoutBounds', null)); |
253 | 255 |
254 if (!email) { | 256 if (!email) { |
255 throw new Error('Missing required parameter: email'); | 257 throw new Error('Missing required parameter: email'); |
256 } | 258 } |
257 | 259 |
258 if (this.hostState_ !== remoting.HostSession.State.UNKNOWN) { | 260 if (this.hostState_ !== remoting.HostSession.State.UNKNOWN) { |
259 throw new Error('An existing connection is in progress.'); | 261 throw new Error('An existing connection is in progress.'); |
260 } | 262 } |
261 | 263 |
262 this.showConfirmDialog_().then( | 264 var that = this; |
| 265 this.showConfirmDialog_(bounds).then( |
263 this.initializeHost_.bind(this) | 266 this.initializeHost_.bind(this) |
264 ).then( | 267 ).then( |
265 this.fetchOAuthToken_.bind(this) | 268 this.fetchOAuthToken_.bind(this) |
266 ).then( | 269 ).then( |
267 /** @type {function(*):void} */(this.connectToHost_.bind(this, email)), | 270 /** @type {function(*):void} */(this.connectToHost_.bind(this, email)) |
268 /** @type {function(*):void} */(this.sendErrorResponse_.bind(this, message)) | 271 ).catch( |
| 272 /** @param {*} reason */ |
| 273 function(reason) { |
| 274 var error = /** @type {Error} */ (reason); |
| 275 that.sendErrorResponse_(message, error); |
| 276 that.dispose(); |
| 277 } |
269 ); | 278 ); |
270 }; | 279 }; |
271 | 280 |
272 /** | 281 /** |
273 * Prompts the user before starting the It2Me Native Messaging Host. This | 282 * Prompts the user before starting the It2Me Native Messaging Host. This |
274 * ensures that even if Hangouts is compromised, an attacker cannot start the | 283 * ensures that even if Hangouts is compromised, an attacker cannot start the |
275 * host without explicit user confirmation. | 284 * host without explicit user confirmation. |
276 * | 285 * |
277 * @return {Promise} A promise that resolves to a boolean value, indicating | 286 * @param {Bounds} bounds Bounds of the hangout window |
278 * whether the user accepts the remote assistance or not. | 287 * @return {Promise} A promise that will resolve if the user accepts remote |
| 288 * assistance or reject otherwise. |
279 * @private | 289 * @private |
280 */ | 290 */ |
281 remoting.It2MeHelpeeChannel.prototype.showConfirmDialog_ = function() { | 291 remoting.It2MeHelpeeChannel.prototype.showConfirmDialog_ = function(bounds) { |
282 if (base.isAppsV2()) { | 292 if (base.isAppsV2()) { |
283 return this.showConfirmDialogV2_(); | 293 return this.showConfirmDialogV2_(bounds); |
284 } else { | 294 } else { |
285 return this.showConfirmDialogV1_(); | 295 return this.showConfirmDialogV1_(); |
286 } | 296 } |
287 }; | 297 }; |
288 | 298 |
289 /** | 299 /** |
290 * @return {Promise} A promise that resolves to a boolean value, indicating | 300 * @return {Promise} A promise that will resolve if the user accepts remote |
291 * whether the user accepts the remote assistance or not. | 301 * assistance or reject otherwise. |
292 * @private | 302 * @private |
293 */ | 303 */ |
294 remoting.It2MeHelpeeChannel.prototype.showConfirmDialogV1_ = function() { | 304 remoting.It2MeHelpeeChannel.prototype.showConfirmDialogV1_ = function() { |
295 var messageHeader = l10n.getTranslationOrError( | 305 var messageHeader = l10n.getTranslationOrError( |
296 /*i18n-content*/'HANGOUTS_CONFIRM_DIALOG_MESSAGE_1'); | 306 /*i18n-content*/'HANGOUTS_CONFIRM_DIALOG_MESSAGE_1'); |
297 var message1 = l10n.getTranslationOrError( | 307 var message1 = l10n.getTranslationOrError( |
298 /*i18n-content*/'HANGOUTS_CONFIRM_DIALOG_MESSAGE_2'); | 308 /*i18n-content*/'HANGOUTS_CONFIRM_DIALOG_MESSAGE_2'); |
299 var message2 = l10n.getTranslationOrError( | 309 var message2 = l10n.getTranslationOrError( |
300 /*i18n-content*/'HANGOUTS_CONFIRM_DIALOG_MESSAGE_3'); | 310 /*i18n-content*/'HANGOUTS_CONFIRM_DIALOG_MESSAGE_3'); |
301 var message = base.escapeHTML(messageHeader) + '\n' + | 311 var message = base.escapeHTML(messageHeader) + '\n' + |
302 '- ' + base.escapeHTML(message1) + '\n' + | 312 '- ' + base.escapeHTML(message1) + '\n' + |
303 '- ' + base.escapeHTML(message2) + '\n'; | 313 '- ' + base.escapeHTML(message2) + '\n'; |
304 | 314 |
305 if(window.confirm(message)) { | 315 if(window.confirm(message)) { |
306 return Promise.resolve(); | 316 return Promise.resolve(); |
307 } else { | 317 } else { |
308 return Promise.reject(new Error(remoting.Error.CANCELLED)); | 318 return Promise.reject(new Error(remoting.Error.CANCELLED)); |
309 } | 319 } |
310 }; | 320 }; |
311 | 321 |
312 /** | 322 /** |
313 * @return {Promise} A promise that resolves to a boolean value, indicating | 323 * @param {Bounds} bounds the bounds of the Hangouts Window. If set, the |
314 * whether the user accepts the remote assistance or not. | 324 * confirm dialog will be centered within |bounds|. |
| 325 * @return {Promise} A promise that will resolve if the user accepts remote |
| 326 * assistance or reject otherwise. |
315 * @private | 327 * @private |
316 */ | 328 */ |
317 remoting.It2MeHelpeeChannel.prototype.showConfirmDialogV2_ = function() { | 329 remoting.It2MeHelpeeChannel.prototype.showConfirmDialogV2_ = function(bounds) { |
318 var messageHeader = l10n.getTranslationOrError( | 330 var getToken = |
319 /*i18n-content*/'HANGOUTS_CONFIRM_DIALOG_MESSAGE_1'); | 331 base.Promise.as(chrome.identity.getAuthToken, [{interactive: false}]); |
320 var message1 = l10n.getTranslationOrError( | 332 |
321 /*i18n-content*/'HANGOUTS_CONFIRM_DIALOG_MESSAGE_2'); | 333 return getToken.then( |
322 var message2 = l10n.getTranslationOrError( | 334 /** @param {string} token */ |
323 /*i18n-content*/'HANGOUTS_CONFIRM_DIALOG_MESSAGE_3'); | 335 function(token) { |
324 var message = '<div>' + base.escapeHTML(messageHeader) + '</div>' + | 336 return remoting.HangoutConsentDialog.getInstance().show(Boolean(token), |
325 '<ul class="insetList">' + | 337 bounds); |
326 '<li>' + base.escapeHTML(message1) + '</li>' + | 338 }); |
327 '<li>' + base.escapeHTML(message2) + '</li>' + | |
328 '</ul>'; | |
329 /** | |
330 * @param {function(*=):void} resolve | |
331 * @param {function(*=):void} reject | |
332 */ | |
333 return new Promise(function(resolve, reject) { | |
334 /** @param {number} result */ | |
335 function confirmDialogCallback(result) { | |
336 if (result === 1) { | |
337 resolve(true); | |
338 } else { | |
339 reject(new Error(remoting.Error.CANCELLED)); | |
340 } | |
341 } | |
342 remoting.MessageWindow.showConfirmWindow( | |
343 '', // Empty string to use the package name as the dialog title. | |
344 message, | |
345 l10n.getTranslationOrError( | |
346 /*i18n-content*/'HANGOUTS_CONFIRM_DIALOG_ACCEPT'), | |
347 l10n.getTranslationOrError( | |
348 /*i18n-content*/'HANGOUTS_CONFIRM_DIALOG_DECLINE'), | |
349 confirmDialogCallback | |
350 ); | |
351 }); | |
352 }; | 339 }; |
353 | 340 |
354 /** | 341 /** |
355 * @return {Promise} A promise that resolves when the host is initialized. | 342 * @return {Promise} A promise that resolves when the host is initialized. |
356 * @private | 343 * @private |
357 */ | 344 */ |
358 remoting.It2MeHelpeeChannel.prototype.initializeHost_ = function() { | 345 remoting.It2MeHelpeeChannel.prototype.initializeHost_ = function() { |
359 /** @type {remoting.It2MeHostFacade} */ | 346 /** @type {remoting.It2MeHostFacade} */ |
360 var host = this.host_; | 347 var host = this.host_; |
361 | 348 |
362 /** | 349 /** |
363 * @param {function(*=):void} resolve | 350 * @param {function(*=):void} resolve |
364 * @param {function(*=):void} reject | 351 * @param {function(*=):void} reject |
365 */ | 352 */ |
366 return new Promise(function(resolve, reject) { | 353 return new Promise(function(resolve, reject) { |
367 if (host.initialized()) { | 354 if (host.initialized()) { |
368 resolve(true); | 355 resolve(true); |
369 } else { | 356 } else { |
370 host.initialize(/** @type {function(*=):void} */ (resolve), | 357 host.initialize(/** @type {function(*=):void} */ (resolve), |
371 /** @type {function(*=):void} */ (reject)); | 358 /** @type {function(*=):void} */ (reject)); |
372 } | 359 } |
373 }); | 360 }); |
374 }; | 361 }; |
375 | 362 |
376 /** | 363 /** |
377 * @return {Promise} Promise that resolves with the OAuth token as the value. | 364 * @return {Promise<string>} Promise that resolves with the OAuth token as the |
| 365 * value. |
378 */ | 366 */ |
379 remoting.It2MeHelpeeChannel.prototype.fetchOAuthToken_ = function() { | 367 remoting.It2MeHelpeeChannel.prototype.fetchOAuthToken_ = function() { |
380 if (base.isAppsV2()) { | 368 if (base.isAppsV2()) { |
381 /** | 369 /** |
382 * @param {function(*=):void} resolve | 370 * @param {function(*=):void} resolve |
383 */ | 371 */ |
384 return new Promise(function(resolve){ | 372 return new Promise(function(resolve){ |
385 // TODO(jamiewalch): Make this work with {interactive: true} as well. | 373 chrome.identity.getAuthToken({'interactive': true}, resolve); |
386 chrome.identity.getAuthToken({ 'interactive': false }, resolve); | |
387 }); | 374 }); |
388 } else { | 375 } else { |
389 /** | 376 /** |
390 * @param {function(*=):void} resolve | 377 * @param {function(*=):void} resolve |
| 378 * @param {function(*=):void} reject |
391 */ | 379 */ |
392 return new Promise(function(resolve) { | 380 return new Promise(function(resolve, reject) { |
393 /** @type {remoting.OAuth2} */ | 381 /** @type {remoting.OAuth2} */ |
394 var oauth2 = new remoting.OAuth2(); | 382 var oauth2 = new remoting.OAuth2(); |
395 var onAuthenticated = function() { | |
396 oauth2.callWithToken( | |
397 resolve, | |
398 function() { throw new Error('Authentication failed.'); }); | |
399 }; | |
400 /** @param {remoting.Error} error */ | 383 /** @param {remoting.Error} error */ |
401 var onError = function(error) { | 384 var onError = function(error) { |
402 if (error != remoting.Error.NOT_AUTHENTICATED) { | 385 if (error === remoting.Error.NOT_AUTHENTICATED) { |
403 throw new Error('Unexpected error fetch auth token: ' + error); | 386 oauth2.doAuthRedirect(function() { |
| 387 oauth2.callWithToken(resolve, reject); |
| 388 }); |
| 389 return; |
404 } | 390 } |
405 oauth2.removeCachedAuthToken(); | 391 reject(new Error(remoting.Error.NOT_AUTHENTICATED)); |
406 }; | 392 }; |
407 oauth2.callWithToken(resolve, onError); | 393 oauth2.callWithToken(resolve, onError); |
408 }); | 394 }); |
409 } | 395 } |
410 }; | 396 }; |
411 | 397 |
412 /** | 398 /** |
413 * Connects to the It2Me Native Messaging Host and retrieves the access code | 399 * Connects to the It2Me Native Messaging Host and retrieves the access code |
414 * in the |onHostStateChanged_| callback. | 400 * in the |onHostStateChanged_| callback. |
415 * | 401 * |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
488 | 474 |
489 console.error('Error responding to message method:' + | 475 console.error('Error responding to message method:' + |
490 (incomingMessage ? incomingMessage.method : 'null') + | 476 (incomingMessage ? incomingMessage.method : 'null') + |
491 ' error:' + error); | 477 ' error:' + error); |
492 this.hangoutPort_.postMessage({ | 478 this.hangoutPort_.postMessage({ |
493 method: remoting.It2MeHelpeeChannel.HangoutMessageTypes.ERROR, | 479 method: remoting.It2MeHelpeeChannel.HangoutMessageTypes.ERROR, |
494 message: error, | 480 message: error, |
495 request: incomingMessage | 481 request: incomingMessage |
496 }); | 482 }); |
497 }; | 483 }; |
OLD | NEW |