remoting.js revision 58537e28ecd584eab876aee8be7156509866d23a
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)'use strict';
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** @suppress {duplicate} */
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)var remoting = remoting || {};
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/** @type {remoting.HostSession} */ remoting.hostSession = null;
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
1358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch * @type {boolean} True if this is a v2 app; false if it is a legacy app.
1458e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch */
1558e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdochremoting.isAppsV2 = false;
1658e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch
1758e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch/**
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Show the authorization consent UI and register a one-shot event handler to
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * continue the authorization process.
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {function():void} authContinue Callback to invoke when the user
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *     clicks "Continue".
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)function consentRequired_(authContinue) {
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  /** @type {HTMLElement} */
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  var dialog = document.getElementById('auth-dialog');
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  /** @type {HTMLElement} */
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  var button = document.getElementById('auth-button');
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  var consentGranted = function(event) {
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    dialog.hidden = true;
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    button.removeEventListener('click', consentGranted, false);
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    authContinue();
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  };
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dialog.hidden = false;
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  button.addEventListener('click', consentGranted, false);
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Entry point for app initialization.
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)remoting.init = function() {
4258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  // Determine whether or not this is a V2 web-app. In order to keep the apps
4358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  // v2 patch as small as possible, all JS changes needed for apps v2 are done
4458e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  // at run-time. Only the manifest is patched.
4558e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  var manifest = chrome.runtime.getManifest();
4658e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  if (manifest && manifest.app && manifest.app.background) {
4758e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    remoting.isAppsV2 = true;
482385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    var htmlNode = /** @type {HTMLElement} */ (document.body.parentNode);
492385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch    htmlNode.classList.add('apps-v2');
5058e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  }
5158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch
5258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  if (!remoting.isAppsV2) {
5358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    migrateLocalToChromeStorage_();
5458e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  }
5558e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  remoting.logExtensionInfo_();
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  l10n.localize();
5858e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create global objects.
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  remoting.settings = new remoting.Settings();
6158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  if (remoting.isAppsV2) {
6258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    remoting.identity = new remoting.Identity(consentRequired_);
6358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  } else {
6458e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    remoting.oauth2 = new remoting.OAuth2();
6558e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    if (!remoting.oauth2.isAuthenticated()) {
6658e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch      document.getElementById('auth-dialog').hidden = false;
6758e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    }
6858e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    remoting.identity = remoting.oauth2;
6958e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  }
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  remoting.stats = new remoting.ConnectionStats(
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      document.getElementById('statistics'));
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  remoting.formatIq = new remoting.FormatIq();
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  remoting.hostList = new remoting.HostList(
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      document.getElementById('host-list'),
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      document.getElementById('host-list-empty'),
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      document.getElementById('host-list-error-message'),
7758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      document.getElementById('host-list-refresh-failed-button'),
7858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      document.getElementById('host-list-loading-indicator'));
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  remoting.toolbar = new remoting.Toolbar(
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      document.getElementById('session-toolbar'));
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  remoting.clipboard = new remoting.Clipboard();
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  var sandbox = /** @type {HTMLIFrameElement} */
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      document.getElementById('wcs-sandbox');
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  remoting.wcsSandbox = new remoting.WcsSandboxContainer(sandbox.contentWindow);
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
86b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  /** @param {remoting.Error} error */
87b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  var onGetEmailError = function(error) {
88b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // No need to show the error message for NOT_AUTHENTICATED
89b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    // because we will show "auth-dialog".
90b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (error != remoting.Error.NOT_AUTHENTICATED) {
91b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      remoting.showErrorMessage(error);
92b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    }
93b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  }
94b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  remoting.identity.getEmail(remoting.onEmail, onGetEmailError);
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  remoting.showOrHideIT2MeUi();
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  remoting.showOrHideMe2MeUi();
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The plugin's onFocus handler sends a paste command to |window|, because
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // it can't send one to the plugin element itself.
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  window.addEventListener('paste', pluginGotPaste_, false);
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  window.addEventListener('copy', pluginGotCopy_, false);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  remoting.initModalDialogs();
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (isHostModeSupported_()) {
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    var noShare = document.getElementById('chrome-os-no-share');
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    noShare.parentNode.removeChild(noShare);
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    var button = document.getElementById('share-button');
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    button.disabled = true;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  var onLoad = function() {
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Parse URL parameters.
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    var urlParams = getUrlParameters_();
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if ('mode' in urlParams) {
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (urlParams['mode'] == 'me2me') {
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        var hostId = urlParams['hostId'];
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        remoting.connectMe2Me(hostId);
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return;
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // No valid URL parameters, start up normally.
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    remoting.initHomeScreenUi();
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  remoting.hostList.load(onLoad);
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // For Apps v1, check the tab type to warn the user if they are not getting
1303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // the best keyboard experience.
1313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!remoting.isAppsV2 && navigator.platform.indexOf('Mac') == -1) {
1323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    /** @param {boolean} isWindowed */
1333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    var onIsWindowed = function(isWindowed) {
1343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      if (!isWindowed) {
1353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        document.getElementById('startup-mode-box-me2me').hidden = false;
1363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        document.getElementById('startup-mode-box-it2me').hidden = false;
1373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      }
1383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    };
1393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    isWindowed_(onIsWindowed);
1403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Display the user's email address and allow access to the rest of the app,
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * including parsing URL parameters.
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {string} email The user's email address.
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {void} Nothing.
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)remoting.onEmail = function(email) {
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  document.getElementById('current-email').innerText = email;
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  document.getElementById('get-started-it2me').disabled = false;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  document.getElementById('get-started-me2me').disabled = false;
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
157b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) * Returns whether or not IT2Me is supported via the host NPAPI plugin.
158b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) *
159b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) * @return {boolean}
160b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) */
161b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)function isIT2MeSupported_() {
162b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  var container = document.getElementById('host-plugin-container');
163b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  /** @type {remoting.HostPlugin} */
164b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  var plugin = remoting.HostSession.createPlugin();
165b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  container.appendChild(plugin);
166b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  var result = plugin.hasOwnProperty('REQUESTED_ACCESS_CODE');
167b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  container.removeChild(plugin);
168b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return result;
169b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
170b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
171b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)/**
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * initHomeScreenUi is called if the app is not starting up in session mode,
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * and also if the user cancels pin entry or the connection in session mode.
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)remoting.initHomeScreenUi = function() {
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  remoting.hostController = new remoting.HostController();
177b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  document.getElementById('share-button').disabled = !isIT2MeSupported_();
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  remoting.setMode(remoting.AppMode.HOME);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  remoting.hostSetupDialog =
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new remoting.HostSetupDialog(remoting.hostController);
181a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  var dialog = document.getElementById('paired-clients-list');
182a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  var message = document.getElementById('paired-client-manager-message');
183a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  var deleteAll = document.getElementById('delete-all-paired-clients');
184a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  var close = document.getElementById('close-paired-client-manager-dialog');
185a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  var working = document.getElementById('paired-client-manager-dialog-working');
186a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  var error = document.getElementById('paired-client-manager-dialog-error');
187a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  var noPairedClients = document.getElementById('no-paired-clients');
188a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  remoting.pairedClientManager =
189a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch      new remoting.PairedClientManager(remoting.hostController, dialog, message,
190a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch                                       deleteAll, close, noPairedClients,
191a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch                                       working, error);
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Display the cached host list, then asynchronously update and re-display it.
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  remoting.updateLocalHostState();
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  remoting.hostList.refresh(remoting.updateLocalHostState);
195868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  remoting.butterBar = new remoting.ButterBar();
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
199a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch * Fetches local host state and updates the DOM accordingly.
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)remoting.updateLocalHostState = function() {
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  /**
203c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)   * @param {string?} hostId Host id.
204c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)   */
205c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  var onHostId = function(hostId) {
206c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    remoting.hostController.getLocalHostState(onHostState.bind(null, hostId));
207c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  };
208c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
209c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  /**
210c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)   * @param {string?} hostId Host id.
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   * @param {remoting.HostController.State} state Host state.
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   */
213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  var onHostState = function(hostId, state) {
214c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    remoting.hostList.setLocalHostStateAndId(state, hostId);
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    remoting.hostList.display();
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  };
217c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
218a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  /**
219a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)   * @param {boolean} response True if the feature is present.
220a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch   */
221a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  var onHasFeatureResponse = function(response) {
222a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    /**
223a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)     * @param {remoting.Error} error
224a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)     */
225a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    var onError = function(error) {
226a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      console.error('Failed to get pairing status: ' + error);
227a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      remoting.pairedClientManager.setPairedClients([]);
228a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    };
229a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
230a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    if (response) {
231a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      remoting.hostController.getPairedClients(
232a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)          remoting.pairedClientManager.setPairedClients.bind(
233a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)              remoting.pairedClientManager),
234a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)          onError);
235a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    } else {
236a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      console.log('Pairing registry not supported by host.');
237a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      remoting.pairedClientManager.setPairedClients([]);
238a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    }
239a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  };
240a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
241a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  remoting.hostController.hasFeature(
242a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      remoting.HostController.Feature.PAIRING_REGISTRY, onHasFeatureResponse);
243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  remoting.hostController.getLocalHostId(onHostId);
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Log information about the current extension.
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * The extension manifest is parsed to extract this info.
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)remoting.logExtensionInfo_ = function() {
25158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  var v2OrLegacy = remoting.isAppsV2 ? " (v2)" : " (legacy)";
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  var manifest = chrome.runtime.getManifest();
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (manifest && manifest.version) {
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    var name = chrome.i18n.getMessage('PRODUCT_NAME');
25558e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    console.log(name + ' version: ' + manifest.version + v2OrLegacy);
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    console.error('Failed to get product version. Corrupt manifest?');
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * If an IT2Me client or host is active then prompt the user before closing.
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * If a Me2Me client is active then don't bother, since closing the window is
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the more intuitive way to end a Me2Me session, and re-connecting is easy.
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)remoting.promptClose = function() {
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!remoting.clientSession ||
2683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      remoting.clientSession.getMode() == remoting.ClientSession.Mode.ME2ME) {
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return null;
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (remoting.currentMode) {
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case remoting.AppMode.CLIENT_CONNECTING:
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case remoting.AppMode.HOST_WAITING_FOR_CODE:
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case remoting.AppMode.HOST_WAITING_FOR_CONNECTION:
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case remoting.AppMode.HOST_SHARED:
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case remoting.AppMode.IN_SESSION:
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return chrome.i18n.getMessage(/*i18n-content*/'CLOSE_PROMPT');
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return null;
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Sign the user out of Chromoting by clearing (and revoking, if possible) the
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * OAuth refresh token.
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Also clear all local storage, to avoid leaking information.
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)remoting.signOut = function() {
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  remoting.oauth2.clear();
2917d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  chrome.storage.local.clear();
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  remoting.setMode(remoting.AppMode.HOME);
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  document.getElementById('auth-dialog').hidden = false;
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Returns whether the app is running on ChromeOS.
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {boolean} True if the app is running on ChromeOS.
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)remoting.runningOnChromeOS = function() {
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return !!navigator.userAgent.match(/\bCrOS\b/);
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Callback function called when the browser window gets a paste operation.
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Event} eventUncast
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {void} Nothing.
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)function pluginGotPaste_(eventUncast) {
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var event = /** @type {remoting.ClipboardEvent} */ eventUncast;
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (event && event.clipboardData) {
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    remoting.clipboard.toHost(event.clipboardData);
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Callback function called when the browser window gets a copy operation.
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Event} eventUncast
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {void} Nothing.
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)function pluginGotCopy_(eventUncast) {
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var event = /** @type {remoting.ClipboardEvent} */ eventUncast;
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (event && event.clipboardData) {
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (remoting.clipboard.toOs(event.clipboardData)) {
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // The default action may overwrite items that we added to clipboardData.
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      event.preventDefault();
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Returns whether Host mode is supported on this platform.
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {boolean} True if Host mode is supported.
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)function isHostModeSupported_() {
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Currently, sharing on Chromebooks is not supported.
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return !remoting.runningOnChromeOS();
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {Object.<string, string>} The URL parameters.
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)function getUrlParameters_() {
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var result = {};
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var parts = window.location.search.substring(1).split('&');
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (var i = 0; i < parts.length; i++) {
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    var pair = parts[i].split('=');
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result[pair[0]] = decodeURIComponent(pair[1]);
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result;
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {string} jsonString A JSON-encoded string.
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {*} The decoded object, or undefined if the string cannot be parsed.
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)function jsonParseSafe(jsonString) {
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  try {
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return JSON.parse(jsonString);
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } catch (err) {
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return undefined;
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Return the current time as a formatted string suitable for logging.
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {string} The current time, formatted as [mmdd/hhmmss.xyz]
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)remoting.timestamp = function() {
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /**
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * @param {number} num A number.
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * @param {number} len The required length of the answer.
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   * @return {string} The number, formatted as a string of the specified length
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   *     by prepending zeroes as necessary.
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   */
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var pad = function(num, len) {
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    var result = num.toString();
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (result.length < len) {
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      result = new Array(len - result.length + 1).join('0') + result;
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result;
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var now = new Date();
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var timestamp = pad(now.getMonth() + 1, 2) + pad(now.getDate(), 2) + '/' +
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pad(now.getHours(), 2) + pad(now.getMinutes(), 2) +
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pad(now.getSeconds(), 2) + '.' + pad(now.getMilliseconds(), 3);
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return '[' + timestamp + ']';
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Show an error message, optionally including a short-cut for signing in to
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Chromoting again.
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {remoting.Error} error
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @return {void} Nothing.
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)remoting.showErrorMessage = function(error) {
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  l10n.localizeElementFromTag(
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      document.getElementById('token-refresh-error-message'),
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      error);
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  var auth_failed = (error == remoting.Error.AUTHENTICATION_FAILED);
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  document.getElementById('token-refresh-auth-failed').hidden = !auth_failed;
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  document.getElementById('token-refresh-other-error').hidden = auth_failed;
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  remoting.setMode(remoting.AppMode.TOKEN_REFRESH_FAILED);
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
4112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Determine whether or not the app is running in a window.
4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {function(boolean):void} callback Callback to receive whether or not
4152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *     the current tab is running in windowed mode.
4162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)function isWindowed_(callback) {
4182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  /** @param {chrome.Window} win The current window. */
4192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  var windowCallback = function(win) {
4202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    callback(win.type == 'popup');
4212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  };
4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  /** @param {chrome.Tab} tab The current tab. */
4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  var tabCallback = function(tab) {
4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (tab.pinned) {
4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      callback(false);
4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      chrome.windows.get(tab.windowId, null, windowCallback);
4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  };
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (chrome.tabs) {
4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    chrome.tabs.getCurrent(tabCallback);
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    console.error('chome.tabs is not available.');
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
436c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
437c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)/**
438c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * Migrate settings in window.localStorage to chrome.storage.local so that
439c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * users of older web-apps that used the former do not lose their settings.
440c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) */
441c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)function migrateLocalToChromeStorage_() {
442c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // The OAuth2 class still uses window.localStorage, so don't migrate any of
443c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // those settings.
444c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  var oauthSettings = [
445c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      'oauth2-refresh-token',
446c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      'oauth2-refresh-token-revokable',
447c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      'oauth2-access-token',
448c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      'oauth2-xsrf-token',
449c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      'remoting-email'
450c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ];
451c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (var setting in window.localStorage) {
452c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (oauthSettings.indexOf(setting) == -1) {
453c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      var copy = {}
454c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      copy[setting] = window.localStorage.getItem(setting);
455c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      chrome.storage.local.set(copy);
456c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      window.localStorage.removeItem(setting);
457c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
458c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
459c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
460c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
461c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)/**
462c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * Generate a nonce, to be used as an xsrf protection token.
463c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) *
464c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) * @return {string} A URL-Safe Base64-encoded 128-bit random value. */
465c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)remoting.generateXsrfToken = function() {
466c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  var random = new Uint8Array(16);
467c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  window.crypto.getRandomValues(random);
468c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  var base64Token = window.btoa(String.fromCharCode.apply(null, random));
469c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return base64Token.replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
470c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)};
471