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 };