auth.js (6401B)
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 loader.lazyRequireGetter( 8 this, 9 "prompt", 10 "resource://devtools/shared/security/prompt.js" 11 ); 12 13 /** 14 * A simple enum-like object with keys mirrored to values. 15 * This makes comparison to a specfic value simpler without having to repeat and 16 * mis-type the value. 17 */ 18 function createEnum(obj) { 19 for (const key in obj) { 20 obj[key] = key; 21 } 22 return obj; 23 } 24 25 /** 26 * |allowConnection| implementations can return various values as their |result| 27 * field to indicate what action to take. By specifying these, we can 28 * centralize the common actions available, while still allowing embedders to 29 * present their UI in whatever way they choose. 30 */ 31 var AuthenticationResult = (exports.AuthenticationResult = createEnum({ 32 /** 33 * Close all listening sockets, and disable them from opening again. 34 */ 35 DISABLE_ALL: null, 36 37 /** 38 * Deny the current connection. 39 */ 40 DENY: null, 41 42 /** 43 * Additional data needs to be exchanged before a result can be determined. 44 */ 45 PENDING: null, 46 47 /** 48 * Allow the current connection. 49 */ 50 ALLOW: null, 51 52 /** 53 * Allow the current connection, and persist this choice for future 54 * connections from the same client. This requires a trustable mechanism to 55 * identify the client in the future. 56 */ 57 ALLOW_PERSIST: null, 58 })); 59 60 /** 61 * An |Authenticator| implements an authentication mechanism via various hooks 62 * in the client and server debugger socket connection path (see socket.js). 63 * 64 * |Authenticator|s are stateless objects. Each hook method is passed the state 65 * it needs by the client / server code in socket.js. 66 * 67 * Separate instances of the |Authenticator| are created for each use (client 68 * connection, server listener) in case some methods are customized by the 69 * embedder for a given use case. 70 */ 71 var Authenticators = {}; 72 73 /** 74 * The Prompt authenticator displays a server-side user prompt that includes 75 * connection details, and asks the user to verify the connection. There are 76 * no cryptographic properties at work here, so it is up to the user to be sure 77 * that the client can be trusted. 78 */ 79 var Prompt = (Authenticators.Prompt = {}); 80 81 Prompt.mode = "PROMPT"; 82 83 Prompt.Client = class { 84 mode = Prompt.mode; 85 86 /** 87 * When client is about to make a new connection, verify that the connection settings 88 * are compatible with this authenticator. 89 * 90 * @throws if validation requirements are not met 91 */ 92 validateSettings() {} 93 94 /** 95 * When client has just made a new socket connection, validate the connection 96 * to ensure it meets the authenticator's policies. 97 * 98 * @param host string 99 * The host name or IP address of the devtools server. 100 * @param port number 101 * The port number of the devtools server. 102 * @param encryption boolean (optional) 103 * Whether the server requires encryption. Defaults to false. 104 * @param s nsISocketTransport 105 * Underlying socket transport, in case more details are needed. 106 * @return boolean 107 * Whether the connection is valid. 108 */ 109 validateConnection() { 110 return true; 111 } 112 113 /** 114 * Work with the server to complete any additional steps required by this 115 * authenticator's policies. 116 * 117 * Debugging commences after this hook completes successfully. 118 * 119 * @param host string 120 * The host name or IP address of the devtools server. 121 * @param port number 122 * The port number of the devtools server. 123 * @param encryption boolean (optional) 124 * Whether the server requires encryption. Defaults to false. 125 * @param transport DebuggerTransport 126 * A transport that can be used to communicate with the server. 127 * @return A promise can be used if there is async behavior. 128 */ 129 authenticate() {} 130 }; 131 132 Prompt.Server = class { 133 mode = Prompt.mode; 134 135 /** 136 * Augment the service discovery advertisement with any additional data needed 137 * to support this authentication mode. 138 * 139 * @param listener SocketListener 140 * The socket listener that was just opened. 141 * @param advertisement object 142 * The advertisement being built. 143 */ 144 augmentAdvertisement(listener, advertisement) { 145 advertisement.authentication = Prompt.mode; 146 } 147 148 /** 149 * Determine whether a connection the server should be allowed or not based on 150 * this authenticator's policies. 151 * 152 * @param session object 153 * In PROMPT mode, the |session| includes: 154 * { 155 * client: { 156 * host, 157 * port 158 * }, 159 * server: { 160 * host, 161 * port 162 * }, 163 * transport 164 * } 165 * @return An AuthenticationResult value. 166 * A promise that will be resolved to the above is also allowed. 167 */ 168 authenticate({ client, server }) { 169 if (!Services.prefs.getBoolPref("devtools.debugger.prompt-connection")) { 170 return AuthenticationResult.ALLOW; 171 } 172 return this.allowConnection({ 173 authentication: this.mode, 174 client, 175 server, 176 }); 177 } 178 179 /** 180 * Prompt the user to accept or decline the incoming connection. The default 181 * implementation is used unless this is overridden on a particular 182 * authenticator instance. 183 * 184 * It is expected that the implementation of |allowConnection| will show a 185 * prompt to the user so that they can allow or deny the connection. 186 * 187 * @param session object 188 * In PROMPT mode, the |session| includes: 189 * { 190 * authentication: "PROMPT", 191 * client: { 192 * host, 193 * port 194 * }, 195 * server: { 196 * host, 197 * port 198 * } 199 * } 200 * @return An AuthenticationResult value. 201 * A promise that will be resolved to the above is also allowed. 202 */ 203 allowConnection = prompt.Server.defaultAllowConnection; 204 }; 205 206 exports.Authenticators = { 207 get(mode) { 208 if (!mode) { 209 mode = Prompt.mode; 210 } 211 for (const key in Authenticators) { 212 const auth = Authenticators[key]; 213 if (auth.mode === mode) { 214 return auth; 215 } 216 } 217 throw new Error("Unknown authenticator mode: " + mode); 218 }, 219 };