summaryrefslogtreecommitdiffstats
path: root/devtools/shared/security/prompt.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/shared/security/prompt.js')
-rw-r--r--devtools/shared/security/prompt.js179
1 files changed, 179 insertions, 0 deletions
diff --git a/devtools/shared/security/prompt.js b/devtools/shared/security/prompt.js
new file mode 100644
index 000000000..aad9b7211
--- /dev/null
+++ b/devtools/shared/security/prompt.js
@@ -0,0 +1,179 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+* License, v. 2.0. If a copy of the MPL was not distributed with this
+* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+var { Ci } = require("chrome");
+var Services = require("Services");
+var DevToolsUtils = require("devtools/shared/DevToolsUtils");
+loader.lazyRequireGetter(this, "DebuggerSocket",
+ "devtools/shared/security/socket", true);
+loader.lazyRequireGetter(this, "AuthenticationResult",
+ "devtools/shared/security/auth", true);
+
+const {LocalizationHelper} = require("devtools/shared/l10n");
+const L10N = new LocalizationHelper("devtools/shared/locales/debugger.properties");
+
+var Client = exports.Client = {};
+var Server = exports.Server = {};
+
+/**
+ * During OOB_CERT authentication, a notification dialog like this is used to
+ * to display a token which the user must transfer through some mechanism to the
+ * server to authenticate the devices.
+ *
+ * This implementation presents the token as text for the user to transfer
+ * manually. For a mobile device, you should override this implementation with
+ * something more convenient, such as displaying a QR code.
+ *
+ * @param host string
+ * The host name or IP address of the debugger server.
+ * @param port number
+ * The port number of the debugger server.
+ * @param cert object (optional)
+ * The server's cert details.
+ * @param authResult AuthenticationResult
+ * Authentication result sent from the server.
+ * @param oob object (optional)
+ * The token data to be transferred during OOB_CERT step 8:
+ * * sha256: hash(ClientCert)
+ * * k : K(random 128-bit number)
+ * @return object containing:
+ * * close: Function to hide the notification
+ */
+Client.defaultSendOOB = ({ authResult, oob }) => {
+ // Only show in the PENDING state
+ if (authResult != AuthenticationResult.PENDING) {
+ throw new Error("Expected PENDING result, got " + authResult);
+ }
+ let title = L10N.getStr("clientSendOOBTitle");
+ let header = L10N.getStr("clientSendOOBHeader");
+ let hashMsg = L10N.getFormatStr("clientSendOOBHash", oob.sha256);
+ let token = oob.sha256.replace(/:/g, "").toLowerCase() + oob.k;
+ let tokenMsg = L10N.getFormatStr("clientSendOOBToken", token);
+ let msg = `${header}\n\n${hashMsg}\n${tokenMsg}`;
+ let prompt = Services.prompt;
+ let flags = prompt.BUTTON_POS_0 * prompt.BUTTON_TITLE_CANCEL;
+
+ // Listen for the window our prompt opens, so we can close it programatically
+ let promptWindow;
+ let windowListener = {
+ onOpenWindow(xulWindow) {
+ let win = xulWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindow);
+ win.addEventListener("load", function listener() {
+ win.removeEventListener("load", listener, false);
+ if (win.document.documentElement.getAttribute("id") != "commonDialog") {
+ return;
+ }
+ // Found the window
+ promptWindow = win;
+ Services.wm.removeListener(windowListener);
+ }, false);
+ },
+ onCloseWindow() {},
+ onWindowTitleChange() {}
+ };
+ Services.wm.addListener(windowListener);
+
+ // nsIPrompt is typically a blocking API, so |executeSoon| to get around this
+ DevToolsUtils.executeSoon(() => {
+ prompt.confirmEx(null, title, msg, flags, null, null, null, null,
+ { value: false });
+ });
+
+ return {
+ close() {
+ if (!promptWindow) {
+ return;
+ }
+ promptWindow.document.documentElement.acceptDialog();
+ promptWindow = null;
+ }
+ };
+};
+
+/**
+ * Prompt the user to accept or decline the incoming connection. This is the
+ * default implementation that products embedding the debugger server may
+ * choose to override. This can be overridden via |allowConnection| on the
+ * socket's authenticator instance.
+ *
+ * @param session object
+ * The session object will contain at least the following fields:
+ * {
+ * authentication,
+ * client: {
+ * host,
+ * port
+ * },
+ * server: {
+ * host,
+ * port
+ * }
+ * }
+ * Specific authentication modes may include additional fields. Check
+ * the different |allowConnection| methods in ./auth.js.
+ * @return An AuthenticationResult value.
+ * A promise that will be resolved to the above is also allowed.
+ */
+Server.defaultAllowConnection = ({ client, server }) => {
+ let title = L10N.getStr("remoteIncomingPromptTitle");
+ let header = L10N.getStr("remoteIncomingPromptHeader");
+ let clientEndpoint = `${client.host}:${client.port}`;
+ let clientMsg = L10N.getFormatStr("remoteIncomingPromptClientEndpoint", clientEndpoint);
+ let serverEndpoint = `${server.host}:${server.port}`;
+ let serverMsg = L10N.getFormatStr("remoteIncomingPromptServerEndpoint", serverEndpoint);
+ let footer = L10N.getStr("remoteIncomingPromptFooter");
+ let msg = `${header}\n\n${clientMsg}\n${serverMsg}\n\n${footer}`;
+ let disableButton = L10N.getStr("remoteIncomingPromptDisable");
+ let prompt = Services.prompt;
+ let flags = prompt.BUTTON_POS_0 * prompt.BUTTON_TITLE_OK +
+ prompt.BUTTON_POS_1 * prompt.BUTTON_TITLE_CANCEL +
+ prompt.BUTTON_POS_2 * prompt.BUTTON_TITLE_IS_STRING +
+ prompt.BUTTON_POS_1_DEFAULT;
+ let result = prompt.confirmEx(null, title, msg, flags, null, null,
+ disableButton, null, { value: false });
+ if (result === 0) {
+ return AuthenticationResult.ALLOW;
+ }
+ if (result === 2) {
+ return AuthenticationResult.DISABLE_ALL;
+ }
+ return AuthenticationResult.DENY;
+};
+
+/**
+ * During OOB_CERT authentication, the user must transfer some data through some
+ * out of band mechanism from the client to the server to authenticate the
+ * devices.
+ *
+ * This implementation prompts the user for a token as constructed by
+ * |Client.defaultSendOOB| that the user needs to transfer manually. For a
+ * mobile device, you should override this implementation with something more
+ * convenient, such as reading a QR code.
+ *
+ * @return An object containing:
+ * * sha256: hash(ClientCert)
+ * * k : K(random 128-bit number)
+ * A promise that will be resolved to the above is also allowed.
+ */
+Server.defaultReceiveOOB = () => {
+ let title = L10N.getStr("serverReceiveOOBTitle");
+ let msg = L10N.getStr("serverReceiveOOBBody");
+ let input = { value: null };
+ let prompt = Services.prompt;
+ let result = prompt.prompt(null, title, msg, input, null, { value: false });
+ if (!result) {
+ return null;
+ }
+ // Re-create original object from token
+ input = input.value.trim();
+ let sha256 = input.substring(0, 64);
+ sha256 = sha256.replace(/\w{2}/g, "$&:").slice(0, -1).toUpperCase();
+ let k = input.substring(64);
+ return { sha256, k };
+};