From fd3ca18334ca895abef89c0386cbe4328dd88b8b Mon Sep 17 00:00:00 2001 From: girst Date: Tue, 5 Aug 2025 20:24:31 +0200 Subject: fix 'make diff' hg.mozilla.org now redirects to hg-edge.mozilla.org. --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 9824f6c..8d78afe 100644 --- a/Makefile +++ b/Makefile @@ -23,6 +23,6 @@ uninstall: cd "$(DESTDIR)" && rm -rf -- $(files) diff: - @curl -s https://hg.mozilla.org/comm-central/raw-file/8a37a90aab4ec643fce1e1ab33984613ce0b492d/common/src/BootstrapLoader.jsm | diff --color -u - legacy/BootstrapLoader.sys.mjs ||: - @curl -s https://hg.mozilla.org/comm-central/raw-file/8a37a90aab4ec643fce1e1ab33984613ce0b492d/common/src/RDFDataSource.jsm | diff --color -u - legacy/RDFDataSource.sys.mjs ||: - @curl -s https://hg.mozilla.org/comm-central/raw-file/8a37a90aab4ec643fce1e1ab33984613ce0b492d/common/src/RDFManifestConverter.jsm | diff --color -u - legacy/RDFManifestConverter.sys.mjs ||: + @curl -sL https://hg.mozilla.org/comm-central/raw-file/8a37a90aab4ec643fce1e1ab33984613ce0b492d/common/src/BootstrapLoader.jsm | diff --color -u - legacy/BootstrapLoader.sys.mjs ||: + @curl -sL https://hg.mozilla.org/comm-central/raw-file/8a37a90aab4ec643fce1e1ab33984613ce0b492d/common/src/RDFDataSource.jsm | diff --color -u - legacy/RDFDataSource.sys.mjs ||: + @curl -sL https://hg.mozilla.org/comm-central/raw-file/8a37a90aab4ec643fce1e1ab33984613ce0b492d/common/src/RDFManifestConverter.jsm | diff --color -u - legacy/RDFManifestConverter.sys.mjs ||: -- cgit v1.2.3 From f6ad068eefefd2f081423278d8b0bbb763a6656f Mon Sep 17 00:00:00 2001 From: girst Date: Tue, 5 Aug 2025 19:21:23 +0200 Subject: make compatible with mozilla142 and above the general idea came from onemen and 117649 in the discussion in https://github.com/xiaoxiaoflood/firefox-scripts/issues/363 but the code has been written from scratch (as I wasn't convinced of some of their design decisions). in the end, the overall approach taken looks somewhat similar, because there seems to be only one way to do that from JS code. we only rewrite a subset of specified manifest instructions, that are needed for VimFx. others are passed-through and might make other addons work. the full list of manifest instructions is documented here: https://www.devdoc.net/web/developer.mozilla.org/en-US/Chrome_Registration.html Further notes on the implementation: use of constants from (and hence import of) FileUtils has been avoided by 1) specifying unix file/dir permissions directly instead of using FileUtils.PERMS_FILE and 2) by relying on default open(2) modes in FileOutputStream, which are the one we want anyways. its documented at https://searchfox.org/mozilla-central/rev/4fd0d5e4669bfa2d0888b730684d8adea061fd30/netwerk/base/nsIFileStreams.idl#96-97 during uninstall(), it does not suffice to re-call .autoRegister() to remove the chrome.manifest. .checkForNewChrome() has precedence in mozilla-central: https://searchfox.org/mozilla-central/rev/4fd0d5e4669bfa2d0888b730684d8adea061fd30/toolkit/mozapps/extensions/AddonManagerStartup.cpp#770 the file doesn't need to exist in uninstall() at all, and only the parent directory must exist for install(), but creating it in both cases simplified the logic a bit. an empty directory will stay behind in the profile directory after uninstallation - oh, well; too bad. nsIFile.remove() takes a boolean argument; it determines recursion. https://searchfox.org/mozilla-central/rev/820596a140570007ce22a6c137ce2520676cfffe/xpcom/io/nsIFile.idl#272 AddonManagerStartup exposes a method .registerChrome(), which takes a parsed manifest instead of a file path. This one doesn't support 'skin' entries (workaround-able with overrides) and does not expose 'content' entries to the content processes - the latter kills this idea. https://searchfox.org/mozilla-central/rev/820596a140570007ce22a6c137ce2520676cfffe/toolkit/mozapps/extensions/AddonManagerStartup.cpp#782 https://searchfox.org/mozilla-central/rev/820596a140570007ce22a6c137ce2520676cfffe/browser/extensions/formautofill/api.js#124 zipReader code was cribbed from here, with Cc[].createInstance() replaced by the nicer Components.Constructor call: https://searchfox.org/mozilla-central/rev/820596a140570007ce22a6c137ce2520676cfffe/modules/libjar/zipwriter/test/unit/test_alignment.js#73 regressed-by: https://bugzilla.mozilla.org/show_bug.cgi?id=1953136 --- Makefile | 1 + legacy/BootstrapLoader.sys.mjs | 9 +++++ legacy/LegacyFoxUtils.sys.mjs | 85 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+) create mode 100644 legacy/LegacyFoxUtils.sys.mjs diff --git a/Makefile b/Makefile index 8d78afe..507f807 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,7 @@ files := config.js files += defaults/pref/config-prefs.js files += legacy.manifest files += legacy/BootstrapLoader.sys.mjs +files += legacy/LegacyFoxUtils.sys.mjs files += legacy/RDFDataSource.sys.mjs files += legacy/RDFManifestConverter.sys.mjs archive = legacyfox.tar.gz diff --git a/legacy/BootstrapLoader.sys.mjs b/legacy/BootstrapLoader.sys.mjs index 80fc61d..7285ca5 100644 --- a/legacy/BootstrapLoader.sys.mjs +++ b/legacy/BootstrapLoader.sys.mjs @@ -10,6 +10,7 @@ import {AddonManager} from "resource://gre/modules/AddonManager.sys.mjs"; import {AddonInternal} from "resource://gre/modules/addons/XPIDatabase.sys.mjs"; import {InstallRDF} from "resource://legacy/RDFManifestConverter.sys.mjs"; import {XPIProvider} from "resource://gre/modules/addons/XPIProvider.sys.mjs"; +import {LegacyFoxUtils} from "resource://legacy/LegacyFoxUtils.sys.mjs"; const BOOTSTRAP_REASONS = XPIProvider.BOOTSTRAP_REASONS; @@ -339,7 +340,11 @@ export var BootstrapLoader = { startup(...args) { if (addon.type == "extension") { logger.debug(`Registering manifest for ${file.path}\n`); + try { Components.manager.addBootstrappedManifestLocation(file); + } catch (e) { // mozilla142+ + LegacyFoxUtils.addBootstrappedManifestLocation(file, addon, getURIForResourceInFile); + } } return startup(...args); }, @@ -352,7 +357,11 @@ export var BootstrapLoader = { } finally { if (reason != BOOTSTRAP_REASONS.APP_SHUTDOWN) { logger.debug(`Removing manifest for ${file.path}\n`); + try { Components.manager.removeBootstrappedManifestLocation(file); + } catch (e) { // mozilla142+ + LegacyFoxUtils.removeBootstrappedManifestLocation(addon); + } } } }, diff --git a/legacy/LegacyFoxUtils.sys.mjs b/legacy/LegacyFoxUtils.sys.mjs new file mode 100644 index 0000000..099f996 --- /dev/null +++ b/legacy/LegacyFoxUtils.sys.mjs @@ -0,0 +1,85 @@ +/** + * Replacements for Components.manager.addBootstrappedManifestLocation and + * Components.manager.removeBootstrappedManifestLocation, which have been nixed + * in mozilla142. Copyright 2025 Tobias Girstmair , MPLv2. + */ + +const ZipReader = Components.Constructor( + "@mozilla.org/libjar/zip-reader;1", + "nsIZipReader", + "open" +); + +const ScriptableInputStream = Components.Constructor( + "@mozilla.org/scriptableinputstream;1", + "nsIScriptableInputStream", + "init" +); + +const FileOutputStream = Components.Constructor( + "@mozilla.org/network/file-output-stream;1", + "nsIFileOutputStream", + "init" +); + +export class LegacyFoxUtils { + static addBootstrappedManifestLocation(file, addon, uriMaker) { + // read chrome.manifest from .jar (or unpacked addon) + let zipReader = new ZipReader(file); + let istream = new ScriptableInputStream(zipReader.getInputStream("chrome.manifest")); + let manifestContents = istream.read(zipReader.getEntry("chrome.manifest").realSize); + + // replace chrome:// and resource:// URIs with absolute paths to JAR + manifestContents = manifestContents + .split("\n") + .map(absolutizePaths.bind(null, uriMaker, file)) + .join("\n"); + + // write modified chrome.manifest to profile directory + let manifest = constructManifestPath(addon); + let ostream = new FileOutputStream(manifest, -1, -1, 0); + ostream.write(manifestContents, manifestContents.length); + ostream.close(); + + // let Firefox read and parse it + Components.manager.QueryInterface(Ci.nsIComponentRegistrar).autoRegister(manifest); + } + + static removeBootstrappedManifestLocation(addon) { + let manifest = constructManifestPath(addon); + manifest.fileSize = 0; // truncate the manifest + Cc['@mozilla.org/chrome/chrome-registry;1'] + .getService(Ci.nsIXULChromeRegistry).checkForNewChrome(); + manifest.remove(false); + } +} + +function absolutizePaths(uriMaker, file, line) { + const manifestMethodPathLocation = { + content: 2, // content packagename uri/to/files/ [flags] + locale: 3, // locale packagename localename uri/to/files/ [flags] + skin: 3, // skin packagename skinname uri/to/files/ [flags] + resource: 2 // resource aliasname uri/to/files/ [flags] + }; + + let words = line.trim().split(/\s+/); + const index = manifestMethodPathLocation[words[0]]; + + if (index) { + words[index] = uriMaker(file, words[index]).spec; + line = words.join(" "); + } + + return line; +} + +function constructManifestPath(addon) { + let manifest = Services.dirsvc.get('ProfD', Ci.nsIFile) + manifest.append('legacy-extension-data'); + manifest.append(addon.id); + manifest.append('chrome.manifest'); + + manifest.exists() || manifest.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o644); + + return manifest; +} -- cgit v1.2.3 From 836dadeb9ed2ad00465720301a21060ff48f7e11 Mon Sep 17 00:00:00 2001 From: girst Date: Tue, 5 Aug 2025 20:22:55 +0200 Subject: optimize legacy-extension-data file operations for reference: https://searchfox.org/mozilla-central/source/xpcom/io/nsIFile.idl --- legacy/LegacyFoxUtils.sys.mjs | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/legacy/LegacyFoxUtils.sys.mjs b/legacy/LegacyFoxUtils.sys.mjs index 099f996..8e101d0 100644 --- a/legacy/LegacyFoxUtils.sys.mjs +++ b/legacy/LegacyFoxUtils.sys.mjs @@ -35,8 +35,15 @@ export class LegacyFoxUtils { .map(absolutizePaths.bind(null, uriMaker, file)) .join("\n"); + // we store the temporary file in the user's profile, in a subdirectory + // analogous to webExtension's "browser-extension-data". + let manifest = Services.dirsvc.get('ProfD', Ci.nsIFile) + manifest.append('legacy-extension-data'); + manifest.append(addon.id); + manifest.exists() || manifest.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755); + manifest.append('chrome.manifest'); /* created or truncated by ostream */ + // write modified chrome.manifest to profile directory - let manifest = constructManifestPath(addon); let ostream = new FileOutputStream(manifest, -1, -1, 0); ostream.write(manifestContents, manifestContents.length); ostream.close(); @@ -46,11 +53,12 @@ export class LegacyFoxUtils { } static removeBootstrappedManifestLocation(addon) { - let manifest = constructManifestPath(addon); - manifest.fileSize = 0; // truncate the manifest + let manifestDir = Services.dirsvc.get('ProfD', Ci.nsIFile) + manifestDir.append('legacy-extension-data'); + manifestDir.append(addon.id); + manifestDir.exists() && manifestDir.remove(/*recursive=*/true); Cc['@mozilla.org/chrome/chrome-registry;1'] .getService(Ci.nsIXULChromeRegistry).checkForNewChrome(); - manifest.remove(false); } } @@ -72,14 +80,3 @@ function absolutizePaths(uriMaker, file, line) { return line; } - -function constructManifestPath(addon) { - let manifest = Services.dirsvc.get('ProfD', Ci.nsIFile) - manifest.append('legacy-extension-data'); - manifest.append(addon.id); - manifest.append('chrome.manifest'); - - manifest.exists() || manifest.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o644); - - return manifest; -} -- cgit v1.2.3