diff options
| author | Akshay Nair <phenax5@gmail.com> | 2026-06-06 18:50:40 +0530 |
|---|---|---|
| committer | Akshay Nair <phenax5@gmail.com> | 2026-06-06 18:50:40 +0530 |
| commit | a7214b76e3f3a01f8ec6a6f8a9fe49e67765a3c5 (patch) | |
| tree | f6f26a429d8a27b5623024963fbebdcc8d0881f6 /modules/firefox.home/chrome/utils/BootstrapLoader.js | |
| parent | 210d4bf063d10a723f66029c2a12610e479d172c (diff) | |
| download | nixos-config-main.tar.gz nixos-config-main.zip | |
Diffstat (limited to 'modules/firefox.home/chrome/utils/BootstrapLoader.js')
| -rw-r--r-- | modules/firefox.home/chrome/utils/BootstrapLoader.js | 520 |
1 files changed, 0 insertions, 520 deletions
diff --git a/modules/firefox.home/chrome/utils/BootstrapLoader.js b/modules/firefox.home/chrome/utils/BootstrapLoader.js deleted file mode 100644 index 69631ab..0000000 --- a/modules/firefox.home/chrome/utils/BootstrapLoader.js +++ /dev/null @@ -1,520 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -'use strict'; - -const Services = globalThis.Services; - -ChromeUtils.defineESModuleGetters(globalThis, { - Blocklist: 'resource://gre/modules/Blocklist.sys.mjs', - ConsoleAPI: 'resource://gre/modules/Console.sys.mjs', - InstallRDF: 'chrome://userchromejs/content/RDFManifestConverter.sys.mjs', - ChromeManifest: 'chrome://userchromejs/content/ChromeManifest.sys.mjs', -}); - -Services.obs.addObserver(doc => { - if (doc.location.protocol + doc.location.pathname === 'about:addons' || - doc.location.protocol + doc.location.pathname === 'chrome:/content/extensions/aboutaddons.html') { - const win = doc.defaultView; - let handleEvent_orig = win.customElements.get('addon-card').prototype.handleEvent; - win.customElements.get('addon-card').prototype.handleEvent = function (e) { - if (e.type === 'click' && - e.target.getAttribute('action') === 'preferences' && - this.addon.__AddonInternal__.optionsType == 1/*AddonManager.OPTIONS_TYPE_DIALOG*/ && !!this.addon.optionsURL) { - var windows = Services.wm.getEnumerator(null); - while (windows.hasMoreElements()) { - var win2 = windows.getNext(); - if (win2.closed) { - continue; - } - if (win2.document.documentURI == this.addon.optionsURL) { - win2.focus(); - return; - } - } - var features = 'chrome,titlebar,toolbar,centerscreen'; - win.docShell.rootTreeItem.domWindow.openDialog(this.addon.optionsURL, this.addon.id, features); - } else { - handleEvent_orig.apply(this, arguments); - } - } - let update_orig = win.customElements.get('addon-options').prototype.update; - win.customElements.get('addon-options').prototype.update = function (card, addon) { - update_orig.apply(this, arguments); - if (addon.__AddonInternal__?.optionsType == 1/*AddonManager.OPTIONS_TYPE_DIALOG*/ && !!addon.optionsURL) - this.querySelector('panel-item[data-l10n-id="preferences-addon-button"]').hidden = false; - } - } -}, 'chrome-document-loaded'); - -const {AddonManager} = ChromeUtils.importESModule('resource://gre/modules/AddonManager.sys.mjs'); -const {XPIDatabase, AddonInternal} = ChromeUtils.importESModule('resource://gre/modules/addons/XPIDatabase.sys.mjs'); -const {XPIExports} = ChromeUtils.importESModule('resource://gre/modules/addons/XPIExports.sys.mjs') - -XPIDatabase.isDisabledLegacy = () => false; - -var orig_verifyBundleSignedState = XPIExports.verifyBundleSignedState; -XPIExports.verifyBundleSignedState = async (aBundle, aAddon) => { - if(!aAddon.isWebExtension && aAddon.type === 'extension' || aAddon.id.includes('_N_SIGN_')) - return { signedState: undefined, signedTypes: [] }; - return orig_verifyBundleSignedState(aBundle, aAddon); -} - -ChromeUtils.defineLazyGetter(this, 'BOOTSTRAP_REASONS', () => { - const {XPIProvider} = ChromeUtils.importESModule('resource://gre/modules/addons/XPIProvider.sys.mjs'); - return XPIProvider.BOOTSTRAP_REASONS; -}); - -ChromeUtils.defineLazyGetter(this, "logger", () => { - let { ConsoleAPI } = ChromeUtils.importESModule( - "resource://gre/modules/Console.sys.mjs" - ); - let consoleOptions = { - maxLogLevel: "all", - prefix: "BootstrapLoader", - }; - return new ConsoleAPI(consoleOptions); -}); - -/** - * Valid IDs fit this pattern. - */ -var gIDTest = /^(\{[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\}|[a-z0-9-\._]*\@[a-z0-9-\._]+)$/i; - -// Properties that exist in the install manifest -const PROP_METADATA = ['id', 'version', 'type', 'internalName', 'updateURL', - 'optionsURL', 'optionsType', 'aboutURL', 'iconURL']; -const PROP_LOCALE_SINGLE = ['name', 'description', 'creator', 'homepageURL']; -const PROP_LOCALE_MULTI = ['developers', 'translators', 'contributors']; - -// Map new string type identifiers to old style nsIUpdateItem types. -// Retired values: -// 32 = multipackage xpi file -// 8 = locale -// 256 = apiextension -// 128 = experiment -// theme = 4 -const TYPES = { - extension: 2, - dictionary: 64, -}; - -const COMPATIBLE_BY_DEFAULT_TYPES = { - extension: true, - dictionary: true, -}; - -const hasOwnProperty = Function.call.bind(Object.prototype.hasOwnProperty); - -function isXPI(filename) { - let ext = filename.slice(-4).toLowerCase(); - return ext === '.xpi' || ext === '.zip'; -} - -/** - * Gets an nsIURI for a file within another file, either a directory or an XPI - * file. If aFile is a directory then this will return a file: URI, if it is an - * XPI file then it will return a jar: URI. - * - * @param {nsIFile} aFile - * The file containing the resources, must be either a directory or an - * XPI file - * @param {string} aPath - * The path to find the resource at, '/' separated. If aPath is empty - * then the uri to the root of the contained files will be returned - * @returns {nsIURI} - * An nsIURI pointing at the resource - */ -function getURIForResourceInFile(aFile, aPath) { - if (!isXPI(aFile.leafName)) { - let resource = aFile.clone(); - if (aPath) - aPath.split('/').forEach(part => resource.append(part)); - - return Services.io.newFileURI(resource); - } - - return buildJarURI(aFile, aPath); -} - -/** - * Creates a jar: URI for a file inside a ZIP file. - * - * @param {nsIFile} aJarfile - * The ZIP file as an nsIFile - * @param {string} aPath - * The path inside the ZIP file - * @returns {nsIURI} - * An nsIURI for the file - */ -function buildJarURI(aJarfile, aPath) { - let uri = Services.io.newFileURI(aJarfile); - uri = 'jar:' + uri.spec + '!/' + aPath; - return Services.io.newURI(uri); -} - -var BootstrapLoader = { - name: 'bootstrap', - manifestFile: 'install.rdf', - async loadManifest(pkg) { - /** - * Reads locale properties from either the main install manifest root or - * an em:localized section in the install manifest. - * - * @param {Object} aSource - * The resource to read the properties from. - * @param {boolean} isDefault - * True if the locale is to be read from the main install manifest - * root - * @param {string[]} aSeenLocales - * An array of locale names already seen for this install manifest. - * Any locale names seen as a part of this function will be added to - * this array - * @returns {Object} - * an object containing the locale properties - */ - function readLocale(aSource, isDefault, aSeenLocales) { - let locale = {}; - if (!isDefault) { - locale.locales = []; - for (let localeName of aSource.locales || []) { - if (!localeName) { - logger.warn('Ignoring empty locale in localized properties'); - continue; - } - if (aSeenLocales.includes(localeName)) { - logger.warn('Ignoring duplicate locale in localized properties'); - continue; - } - aSeenLocales.push(localeName); - locale.locales.push(localeName); - } - - if (locale.locales.length == 0) { - logger.warn('Ignoring localized properties with no listed locales'); - return null; - } - } - - for (let prop of [...PROP_LOCALE_SINGLE, ...PROP_LOCALE_MULTI]) { - if (hasOwnProperty(aSource, prop)) { - locale[prop] = aSource[prop]; - } - } - - return locale; - } - - let manifestData = await pkg.readString('install.rdf'); - let manifest = InstallRDF.loadFromString(manifestData).decode(); - - let addon = new AddonInternal(); - for (let prop of PROP_METADATA) { - if (hasOwnProperty(manifest, prop)) { - addon[prop] = manifest[prop]; - } - } - - if (!addon.type) { - addon.type = 'extension'; - } else { - let type = addon.type; - addon.type = null; - for (let name in TYPES) { - if (TYPES[name] == type) { - addon.type = name; - break; - } - } - } - - if (!(addon.type in TYPES)) - throw new Error('Install manifest specifies unknown type: ' + addon.type); - - if (!addon.id) - throw new Error('No ID in install manifest'); - if (!gIDTest.test(addon.id)) - throw new Error('Illegal add-on ID ' + addon.id); - if (!addon.version) - throw new Error('No version in install manifest'); - - addon.strictCompatibility = (!(addon.type in COMPATIBLE_BY_DEFAULT_TYPES) || - manifest.strictCompatibility == 'true'); - - // Only read these properties for extensions. - if (addon.type == 'extension') { - if (manifest.bootstrap != 'true') { - throw new Error('Non-restartless extensions no longer supported'); - } - - if (addon.optionsType && - addon.optionsType != 1/*AddonManager.OPTIONS_TYPE_DIALOG*/ && - addon.optionsType != AddonManager.OPTIONS_TYPE_INLINE_BROWSER && - addon.optionsType != AddonManager.OPTIONS_TYPE_TAB) { - throw new Error('Install manifest specifies unknown optionsType: ' + addon.optionsType); - } - - if (addon.optionsType) - addon.optionsType = parseInt(addon.optionsType); - } - - addon.defaultLocale = readLocale(manifest, true); - - let seenLocales = []; - addon.locales = []; - for (let localeData of manifest.localized || []) { - let locale = readLocale(localeData, false, seenLocales); - if (locale) - addon.locales.push(locale); - } - - let dependencies = new Set(manifest.dependencies); - addon.dependencies = Object.freeze(Array.from(dependencies)); - - let seenApplications = []; - addon.targetApplications = []; - for (let targetApp of manifest.targetApplications || []) { - if (!targetApp.id || !targetApp.minVersion || - !targetApp.maxVersion) { - logger.warn('Ignoring invalid targetApplication entry in install manifest'); - continue; - } - if (seenApplications.includes(targetApp.id)) { - logger.warn('Ignoring duplicate targetApplication entry for ' + targetApp.id + - ' in install manifest'); - continue; - } - seenApplications.push(targetApp.id); - addon.targetApplications.push(targetApp); - } - - // Note that we don't need to check for duplicate targetPlatform entries since - // the RDF service coalesces them for us. - addon.targetPlatforms = []; - for (let targetPlatform of manifest.targetPlatforms || []) { - let platform = { - os: null, - abi: null, - }; - - let pos = targetPlatform.indexOf('_'); - if (pos != -1) { - platform.os = targetPlatform.substring(0, pos); - platform.abi = targetPlatform.substring(pos + 1); - } else { - platform.os = targetPlatform; - } - - addon.targetPlatforms.push(platform); - } - - addon.userDisabled = false; - addon.softDisabled = addon.blocklistState == Blocklist.STATE_SOFTBLOCKED; - addon.applyBackgroundUpdates = AddonManager.AUTOUPDATE_DEFAULT; - - addon.userPermissions = null; - - addon.icons = {}; - if (await pkg.hasResource('icon.png')) { - addon.icons[32] = 'icon.png'; - addon.icons[48] = 'icon.png'; - } - - if (await pkg.hasResource('icon64.png')) { - addon.icons[64] = 'icon64.png'; - } - - Object.defineProperty(addon, 'appDisabled', { - set: _ => {}, - get: _ => false - }); - - Object.defineProperty(addon, 'signedState', { - set: _ => {}, - get: _ => AddonManager.SIGNEDSTATE_NOT_REQUIRED - }); - - return addon; - }, - - loadScope(addon) { - let file = addon.file || addon._sourceBundle; - let uri = getURIForResourceInFile(file, 'bootstrap.js').spec; - let principal = Services.scriptSecurityManager.getSystemPrincipal(); - - let sandbox = new Cu.Sandbox(principal, { - sandboxName: uri, - addonId: addon.id, - wantGlobalProperties: ['ChromeUtils'], - metadata: { addonID: addon.id, URI: uri }, - }); - - try { - Object.assign(sandbox, BOOTSTRAP_REASONS); - - ChromeUtils.defineLazyGetter(sandbox, 'console', () => - new ConsoleAPI({ consoleID: `addon/${addon.id}` })); - - Services.scriptloader.loadSubScript(uri, sandbox); - } catch (e) { - logger.warn(`Error loading bootstrap.js for ${addon.id}`, e); - } - - function findMethod(name) { - if (sandbox[name]) { - return sandbox[name]; - } - - try { - let method = Cu.evalInSandbox(name, sandbox); - return method; - } catch (err) { } - - return () => { - logger.warn(`Add-on ${addon.id} is missing bootstrap method ${name}`); - }; - } - - let install = findMethod('install'); - let uninstall = findMethod('uninstall'); - let startup = findMethod('startup'); - let shutdown = findMethod('shutdown'); - - /** - * Reads content from a jar: URI - * - * @param {nsIURI} jarURI - The jar: URI to read from - * @returns {Promise<string>} The content of the file inside the JAR - */ - async function readFromJarURI(jarURI) { - return new Promise((resolve, reject) => { - try { - const channel = Services.io.newChannelFromURI( - jarURI, - null, - Services.scriptSecurityManager.getSystemPrincipal(), - null, - Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL, - Ci.nsIContentPolicy.TYPE_OTHER - ); - - const inputStream = channel.open(); - const scriptableStream = Cc[ - '@mozilla.org/scriptableinputstream;1' - ].createInstance(Ci.nsIScriptableInputStream); - scriptableStream.init(inputStream); - - let data = ''; - let available = 0; - while ((available = scriptableStream.available()) > 0) { - data += scriptableStream.read(available); - } - - scriptableStream.close(); - inputStream.close(); - resolve(data); - } catch (e) { - reject(e); - } - }); - } - - // Register a chrome manifest temporarily and return a function which un-does - // the registrarion when no longer needed. - function createManifestTemporarily(manifestText) { - let tempDir = Services.dirsvc.get('ProfD', Ci.nsIFile) - tempDir.append('browser-extension-data'); - tempDir.append(addon.id); - tempDir.append('manifests'); - if (tempDir.exists()) { - // Clean any leftover temp.manifest - tempDir.remove(true); - } - tempDir.append('temp.manifest.' + Date.now()); - - let foStream = Cc[ - '@mozilla.org/network/file-output-stream;1' - ].createInstance(Ci.nsIFileOutputStream); - foStream.init(tempDir, 0x02 | 0x08 | 0x20, 0o664, 0); // write, create, truncate - foStream.write(manifestText, manifestText.length); - foStream.close(); - - Components.manager - .QueryInterface(Ci.nsIComponentRegistrar) - .autoRegister(tempDir); - - Cc['@mozilla.org/uriloader/external-helper-app-service;1'] - .getService(Ci.nsPIExternalAppLauncher) - .deleteTemporaryFileOnExit(tempDir); - - return function () { - tempDir.fileSize = 0; // truncate the manifest - Cc['@mozilla.org/chrome/chrome-registry;1'] - .getService(Ci.nsIXULChromeRegistry) - .checkForNewChrome(); - }; - } - - return { - install(...args) { - install(...args); - // Forget any cached files we might've had from this extension. - Services.obs.notifyObservers(null, 'startupcache-invalidate'); - }, - - uninstall(...args) { - uninstall(...args); - // Forget any cached files we might've had from this extension. - Services.obs.notifyObservers(null, 'startupcache-invalidate'); - }, - - async startup(...args) { - if (addon.type == 'extension') { - logger.debug(`Registering manifest for ${file.path}\n`); - const manifestURI = getURIForResourceInFile(file, 'chrome.manifest'); - let manifestData = await readFromJarURI(manifestURI); - let chromeManifest = new ChromeManifest(() => { - return manifestData; - }, { - application: Services.appinfo.ID, - appversion: Services.appinfo.version, - platformversion: Services.appinfo.platformVersion, - os: Services.appinfo.OS, - osversion: Services.sysinfo.getProperty('version'), - abi: Services.appinfo.XPCOMABI - }); - await chromeManifest.parse() - this._clearManifest = createManifestTemporarily(chromeManifest.toString(getURIForResourceInFile(file, '').spec)); - } - return startup(...args); - }, - - shutdown(data, reason) { - try { - return shutdown(data, reason); - } catch (err) { - throw err; - } finally { - if (reason != BOOTSTRAP_REASONS.APP_SHUTDOWN) { - logger.debug(`Removing manifest for ${file.path}\n`); - this._clearManifest(); - this._clearManifest = null; - } - } - }, - }; - }, -}; - -AddonManager.addExternalExtensionLoader(BootstrapLoader); - -if (AddonManager.isReady) { - AddonManager.getAllAddons().then(addons => { - addons.forEach(addon => { - if (addon.type == 'extension' && !addon.isWebExtension && !addon.userDisabled) { - addon.reload(); - }; - }); - }); -} |
