1 /* Any copyright is dedicated to the Public Domain.
2 http://creativecommons.org/publicdomain/zero/1.0/ */
6 const { FirefoxBridgeExtensionUtils } = ChromeUtils.importESModule(
7 "resource:///modules/FirefoxBridgeExtensionUtils.sys.mjs"
10 const FIREFOX_SHELL_OPEN_COMMAND_PATH = "firefox\\shell\\open\\command";
11 const FIREFOX_PRIVATE_SHELL_OPEN_COMMAND_PATH =
12 "firefox-private\\shell\\open\\command";
14 class StubbedRegistryKey {
22 constructor(children, values) {
23 this.#children = children;
24 this.#values = values;
25 this.#originalChildren = new Map(children);
27 this.#closeCalled = false;
28 this.#openedForRead = false;
29 this.#deletedChildren = new Set([]);
37 this.#closeCalled = false;
38 this.#deletedChildren = new Set([]);
39 this.#children = new Map(this.#originalChildren);
43 this.#openedForRead = true;
46 get wasOpenedForRead() {
47 return this.#openedForRead;
50 openChild(path, accessLevel) {
51 const result = this.#children.get(path);
52 result?.open(accessLevel);
57 return this.#children.has(path);
61 this.#closeCalled = true;
65 this.#deletedChildren.add(path);
67 // delete the actual child if it's in there
68 this.#children.delete(path);
71 isChildDeleted(path) {
72 return this.#deletedChildren.has(path);
77 for (const [key] of this.#children) {
87 readStringValue(name) {
88 return this.#values.get(name);
92 return this.#children.size;
95 getValueType(entryName) {
96 if (typeof this.readStringValue(entryName) == "string") {
97 return Ci.nsIWindowsRegKey.TYPE_STRING;
100 throw new Error(`${entryName} not found in registry`);
103 get wasCloseCalled() {
104 return this.#closeCalled;
107 getValueName(index) {
109 for (const [key] of this.#values) {
120 return this.#values.size;
124 class StubbedDeleteBridgeProtocolRegistryEntryHelper {
128 constructor({ applicationPath, registryRootKey }) {
129 this.#applicationPath = applicationPath;
130 this.#registryRootKey = registryRootKey;
133 getApplicationPath() {
134 return this.#applicationPath;
138 return this.#registryRootKey;
141 deleteRegistryTree(root, toDeletePath) {
142 // simplify this for tests
143 root.removeChild(toDeletePath);
147 add_task(async function test_DeleteWhenSameFirefoxInstall() {
148 const applicationPath = "testPath";
150 const firefoxEntries = new Map();
151 firefoxEntries.set("", `\"${applicationPath}\" -osint -url \"%1\"`);
153 const firefoxProtocolRegKey = new StubbedRegistryKey(
158 const firefoxPrivateEntries = new Map();
159 firefoxPrivateEntries.set(
161 `\"${applicationPath}\" -osint -private-window \"%1\"`
163 const firefoxPrivateProtocolRegKey = new StubbedRegistryKey(
165 firefoxPrivateEntries
168 const children = new Map();
169 children.set(FIREFOX_SHELL_OPEN_COMMAND_PATH, firefoxProtocolRegKey);
171 FIREFOX_PRIVATE_SHELL_OPEN_COMMAND_PATH,
172 firefoxPrivateProtocolRegKey
175 const registryRootKey = new StubbedRegistryKey(children, new Map());
177 const stubbedDeleteBridgeProtocolRegistryHelper =
178 new StubbedDeleteBridgeProtocolRegistryEntryHelper({
183 FirefoxBridgeExtensionUtils.maybeDeleteBridgeProtocolRegistryEntries(
184 stubbedDeleteBridgeProtocolRegistryHelper
187 ok(registryRootKey.wasCloseCalled, "Root key closed");
189 ok(firefoxProtocolRegKey.wasOpenedForRead, "Firefox key opened");
190 ok(firefoxProtocolRegKey.wasCloseCalled, "Firefox key closed");
192 registryRootKey.isChildDeleted("firefox"),
193 "Firefox protocol registry entry deleted"
197 firefoxPrivateProtocolRegKey.wasOpenedForRead,
198 "Firefox private key opened"
200 ok(firefoxPrivateProtocolRegKey.wasCloseCalled, "Firefox private key closed");
202 registryRootKey.isChildDeleted("firefox-private"),
203 "Firefox private protocol registry entry deleted"
207 add_task(async function test_DeleteWhenDifferentFirefoxInstall() {
208 const applicationPath = "testPath";
209 const badApplicationPath = "testPath2";
211 const firefoxEntries = new Map();
212 firefoxEntries.set("", `\"${badApplicationPath}\" -osint -url \"%1\"`);
214 const firefoxProtocolRegKey = new StubbedRegistryKey(
219 const firefoxPrivateEntries = new Map();
220 firefoxPrivateEntries.set(
222 `\"${badApplicationPath}\" -osint -private-window \"%1\"`
224 const firefoxPrivateProtocolRegKey = new StubbedRegistryKey(
226 firefoxPrivateEntries
229 const children = new Map();
230 children.set(FIREFOX_SHELL_OPEN_COMMAND_PATH, firefoxProtocolRegKey);
232 FIREFOX_PRIVATE_SHELL_OPEN_COMMAND_PATH,
233 firefoxPrivateProtocolRegKey
236 const registryRootKey = new StubbedRegistryKey(children, new Map());
238 const stubbedDeleteBridgeProtocolRegistryHelper =
239 new StubbedDeleteBridgeProtocolRegistryEntryHelper({
244 FirefoxBridgeExtensionUtils.maybeDeleteBridgeProtocolRegistryEntries(
245 stubbedDeleteBridgeProtocolRegistryHelper
248 ok(registryRootKey.wasCloseCalled, "Root key closed");
250 ok(firefoxProtocolRegKey.wasOpenedForRead, "Firefox key opened");
251 ok(firefoxProtocolRegKey.wasCloseCalled, "Firefox key closed");
253 !registryRootKey.isChildDeleted("firefox"),
254 "Firefox protocol registry entry not deleted"
258 firefoxPrivateProtocolRegKey.wasOpenedForRead,
259 "Firefox private key opened"
261 ok(firefoxPrivateProtocolRegKey.wasCloseCalled, "Firefox private key closed");
263 !registryRootKey.isChildDeleted("firefox-private"),
264 "Firefox private protocol registry entry not deleted"
268 add_task(async function test_DeleteWhenNoRegistryEntries() {
269 const applicationPath = "testPath";
271 const firefoxPrivateEntries = new Map();
272 const firefoxPrivateProtocolRegKey = new StubbedRegistryKey(
274 firefoxPrivateEntries
277 const children = new Map();
279 FIREFOX_PRIVATE_SHELL_OPEN_COMMAND_PATH,
280 firefoxPrivateProtocolRegKey
283 const registryRootKey = new StubbedRegistryKey(children, new Map());
285 const stubbedDeleteBridgeProtocolRegistryHelper =
286 new StubbedDeleteBridgeProtocolRegistryEntryHelper({
291 FirefoxBridgeExtensionUtils.maybeDeleteBridgeProtocolRegistryEntries(
292 stubbedDeleteBridgeProtocolRegistryHelper
295 ok(registryRootKey.wasCloseCalled, "Root key closed");
298 firefoxPrivateProtocolRegKey.wasOpenedForRead,
299 "Firefox private key opened"
301 ok(firefoxPrivateProtocolRegKey.wasCloseCalled, "Firefox private key closed");
303 !registryRootKey.isChildDeleted("firefox"),
304 "Firefox protocol registry entry deleted when it shouldn't be"
307 !registryRootKey.isChildDeleted("firefox-private"),
308 "Firefox private protocol registry deleted when it shouldn't be"
312 add_task(async function test_DeleteWhenUnexpectedRegistryEntries() {
313 const applicationPath = "testPath";
315 const firefoxEntries = new Map();
316 firefoxEntries.set("", `\"${applicationPath}\" -osint -url \"%1\"`);
317 firefoxEntries.set("extraEntry", "extraValue");
318 const firefoxProtocolRegKey = new StubbedRegistryKey(
323 const children = new Map();
324 children.set(FIREFOX_SHELL_OPEN_COMMAND_PATH, firefoxProtocolRegKey);
326 const registryRootKey = new StubbedRegistryKey(children, new Map());
328 const stubbedDeleteBridgeProtocolRegistryHelper =
329 new StubbedDeleteBridgeProtocolRegistryEntryHelper({
334 FirefoxBridgeExtensionUtils.maybeDeleteBridgeProtocolRegistryEntries(
335 stubbedDeleteBridgeProtocolRegistryHelper
338 ok(registryRootKey.wasCloseCalled, "Root key closed");
340 ok(firefoxProtocolRegKey.wasOpenedForRead, "Firefox key opened");
341 ok(firefoxProtocolRegKey.wasCloseCalled, "Firefox key closed");
343 !registryRootKey.isChildDeleted("firefox"),
344 "Firefox protocol registry entry deleted when it shouldn't be"
347 !registryRootKey.isChildDeleted("firefox-private"),
348 "Firefox private protocol registry deleted when it shouldn't be"