prompt.js 6.7 KB

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