diff options
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | legacy/BootstrapLoader.sys.mjs | 9 | ||||
-rw-r--r-- | legacy/LegacyFoxUtils.sys.mjs | 85 |
3 files changed, 95 insertions, 0 deletions
@@ -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 <https://gir.st/>, 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; +} |