tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

prompt.js (6635B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 "use strict";
      6 
      7 var DevToolsUtils = require("resource://devtools/shared/DevToolsUtils.js");
      8 loader.lazyRequireGetter(
      9  this,
     10  "AuthenticationResult",
     11  "resource://devtools/shared/security/auth.js",
     12  true
     13 );
     14 
     15 const { LocalizationHelper } = require("resource://devtools/shared/l10n.js");
     16 const L10N = new LocalizationHelper(
     17  "devtools/shared/locales/debugger.properties"
     18 );
     19 
     20 var Client = (exports.Client = {});
     21 var Server = (exports.Server = {});
     22 
     23 /**
     24 * During OOB_CERT authentication, a notification dialog like this is used to
     25 * to display a token which the user must transfer through some mechanism to the
     26 * server to authenticate the devices.
     27 *
     28 * This implementation presents the token as text for the user to transfer
     29 * manually.  For a mobile device, you should override this implementation with
     30 * something more convenient, such as displaying a QR code.
     31 *
     32 * @param host string
     33 *        The host name or IP address of the devtools server.
     34 * @param port number
     35 *        The port number of the devtools server.
     36 * @param authResult AuthenticationResult
     37 *        Authentication result sent from the server.
     38 * @param oob object (optional)
     39 *        The token data to be transferred during OOB_CERT step 8:
     40 *        * sha256: hash(ClientCert)
     41 *        * k     : K(random 128-bit number)
     42 * @return object containing:
     43 *         * close: Function to hide the notification
     44 */
     45 Client.defaultSendOOB = ({ authResult, oob }) => {
     46  // Only show in the PENDING state
     47  if (authResult != AuthenticationResult.PENDING) {
     48    throw new Error("Expected PENDING result, got " + authResult);
     49  }
     50  const title = L10N.getStr("clientSendOOBTitle");
     51  const header = L10N.getStr("clientSendOOBHeader");
     52  const hashMsg = L10N.getFormatStr("clientSendOOBHash", oob.sha256);
     53  const token = oob.sha256.replace(/:/g, "").toLowerCase() + oob.k;
     54  const tokenMsg = L10N.getFormatStr("clientSendOOBToken", token);
     55  const msg = `${header}\n\n${hashMsg}\n${tokenMsg}`;
     56  const prompt = Services.prompt;
     57  const flags = prompt.BUTTON_POS_0 * prompt.BUTTON_TITLE_CANCEL;
     58 
     59  // Listen for the window our prompt opens, so we can close it programatically
     60  let promptWindow;
     61  const windowListener = {
     62    onOpenWindow(xulWindow) {
     63      const win = xulWindow.docShell.domWindow;
     64      win.addEventListener(
     65        "load",
     66        function () {
     67          if (
     68            win.document.documentElement.getAttribute("id") != "commonDialog"
     69          ) {
     70            return;
     71          }
     72          // Found the window
     73          promptWindow = win;
     74          Services.wm.removeListener(windowListener);
     75        },
     76        { once: true }
     77      );
     78    },
     79    onCloseWindow() {},
     80  };
     81  Services.wm.addListener(windowListener);
     82 
     83  // nsIPrompt is typically a blocking API, so |executeSoon| to get around this
     84  DevToolsUtils.executeSoon(() => {
     85    prompt.confirmEx(null, title, msg, flags, null, null, null, null, {
     86      value: false,
     87    });
     88  });
     89 
     90  return {
     91    close() {
     92      if (!promptWindow) {
     93        return;
     94      }
     95      promptWindow.document.documentElement.acceptDialog();
     96      promptWindow = null;
     97    },
     98  };
     99 };
    100 
    101 /**
    102 * Prompt the user to accept or decline the incoming connection.  This is the
    103 * default implementation that products embedding the devtools server may
    104 * choose to override.  This can be overridden via |allowConnection| on the
    105 * socket's authenticator instance.
    106 *
    107 * @param session object
    108 *        The session object will contain at least the following fields:
    109 *        {
    110 *          authentication,
    111 *          client: {
    112 *            host,
    113 *            port
    114 *          },
    115 *          server: {
    116 *            host,
    117 *            port
    118 *          }
    119 *        }
    120 *        Specific authentication modes may include additional fields.  Check
    121 *        the different |allowConnection| methods in ./auth.js.
    122 * @return An AuthenticationResult value.
    123 *         A promise that will be resolved to the above is also allowed.
    124 */
    125 Server.defaultAllowConnection = ({ client, server }) => {
    126  const title = L10N.getStr("remoteIncomingPromptTitle");
    127  const header = L10N.getStr("remoteIncomingPromptHeader");
    128  const clientEndpoint = `${client.host}:${client.port}`;
    129  const clientMsg = L10N.getFormatStr(
    130    "remoteIncomingPromptClientEndpoint",
    131    clientEndpoint
    132  );
    133  const serverEndpoint = `${server.host}:${server.port}`;
    134  const serverMsg = L10N.getFormatStr(
    135    "remoteIncomingPromptServerEndpoint",
    136    serverEndpoint
    137  );
    138  const footer = L10N.getStr("remoteIncomingPromptFooter");
    139  const msg = `${header}\n\n${clientMsg}\n${serverMsg}\n\n${footer}`;
    140  const disableButton = L10N.getStr("remoteIncomingPromptDisable");
    141  const prompt = Services.prompt;
    142  const flags =
    143    prompt.BUTTON_POS_0 * prompt.BUTTON_TITLE_OK +
    144    prompt.BUTTON_POS_1 * prompt.BUTTON_TITLE_CANCEL +
    145    prompt.BUTTON_POS_2 * prompt.BUTTON_TITLE_IS_STRING +
    146    prompt.BUTTON_POS_1_DEFAULT;
    147  const result = prompt.confirmEx(
    148    null,
    149    title,
    150    msg,
    151    flags,
    152    null,
    153    null,
    154    disableButton,
    155    null,
    156    { value: false }
    157  );
    158  if (result === 0) {
    159    return AuthenticationResult.ALLOW;
    160  }
    161  if (result === 2) {
    162    return AuthenticationResult.DISABLE_ALL;
    163  }
    164  return AuthenticationResult.DENY;
    165 };
    166 
    167 /**
    168 * During OOB_CERT authentication, the user must transfer some data through some
    169 * out of band mechanism from the client to the server to authenticate the
    170 * devices.
    171 *
    172 * This implementation prompts the user for a token as constructed by
    173 * |Client.defaultSendOOB| that the user needs to transfer manually.  For a
    174 * mobile device, you should override this implementation with something more
    175 * convenient, such as reading a QR code.
    176 *
    177 * @return An object containing:
    178 *         * sha256: hash(ClientCert)
    179 *         * k     : K(random 128-bit number)
    180 *         A promise that will be resolved to the above is also allowed.
    181 */
    182 Server.defaultReceiveOOB = () => {
    183  const title = L10N.getStr("serverReceiveOOBTitle");
    184  const msg = L10N.getStr("serverReceiveOOBBody");
    185  let input = { value: null };
    186  const prompt = Services.prompt;
    187  const result = prompt.prompt(null, title, msg, input, null, { value: false });
    188  if (!result) {
    189    return null;
    190  }
    191  // Re-create original object from token
    192  input = input.value.trim();
    193  let sha256 = input.substring(0, 64);
    194  sha256 = sha256.replace(/\w{2}/g, "$&:").slice(0, -1).toUpperCase();
    195  const k = input.substring(64);
    196  return { sha256, k };
    197 };