aboutsummaryrefslogtreecommitdiff
path: root/modules/firefox.home/chrome/utils
diff options
context:
space:
mode:
Diffstat (limited to 'modules/firefox.home/chrome/utils')
-rw-r--r--modules/firefox.home/chrome/utils/BootstrapLoader.js520
-rw-r--r--modules/firefox.home/chrome/utils/ChromeManifest.sys.mjs415
-rw-r--r--modules/firefox.home/chrome/utils/RDFDataSource.sys.mjs434
-rw-r--r--modules/firefox.home/chrome/utils/RDFManifestConverter.sys.mjs99
-rw-r--r--modules/firefox.home/chrome/utils/chrome.manifest2
-rw-r--r--modules/firefox.home/chrome/utils/userChrome.js272
-rw-r--r--modules/firefox.home/chrome/utils/xPref.sys.mjs92
7 files changed, 0 insertions, 1834 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();
- };
- });
- });
-}
diff --git a/modules/firefox.home/chrome/utils/ChromeManifest.sys.mjs b/modules/firefox.home/chrome/utils/ChromeManifest.sys.mjs
deleted file mode 100644
index f2ebc18..0000000
--- a/modules/firefox.home/chrome/utils/ChromeManifest.sys.mjs
+++ /dev/null
@@ -1,415 +0,0 @@
-/* exported ChromeManifest */
-"use strict";
-
-/**
- * A default map, which assumes a default value on get() if the key doesn't exist
- */
-class DefaultMap extends Map {
- /**
- * Constructs the default map
- *
- * @param {Function} _default A function that returns the default value for this map
- * @param {*} iterable An iterable to initialize the map with
- */
- constructor(_default, iterable) {
- super(iterable);
- this._default = _default;
- }
-
- /**
- * Get the given key, creating if necessary
- *
- * @param {String} key The key of the map to get
- * @param {Boolean} create True, if the key should be created in case it doesn't exist.
- */
- get(key, create = true) {
- if (this.has(key)) {
- return super.get(key);
- } else if (create) {
- this.set(key, this._default());
- return super.get(key);
- }
-
- return this._default();
- }
-}
-
-/**
- * A parser for chrome.manifest files. Implements a subset of
- * https://developer.mozilla.org/en-US/docs/Mozilla/Chrome_Registration
- */
-export class ChromeManifest {
- /**
- * Constucts the chrome.manifest parser
- *
- * @param {Function} loader An asynchronous function that will load further files, e.g.
- * those included via the |manifest| instruction. The
- * function will take the file as an argument and should
- * resolve with the string contents of that file
- * @param {Object} options Object describing the current system. The keys are manifest
- * instructions
- */
- constructor(loader, options) {
- this.loader = loader;
- this.options = options;
-
- this.overlay = new DefaultMap(() => []);
- this.locales = new DefaultMap(() => new Map());
- this.style = new DefaultMap(() => new Set());
- this.category = new DefaultMap(() => new Map());
-
- this.component = new Map();
- this.contract = new Map();
-
- this.content = new Map();
- this.skin = new DefaultMap(() => new Map());
- this.resource = new Map();
- this.override = new Map();
- }
-
- /**
- * Parse the given file.
- *
- * @param {String} filename The filename to load
- * @param {String} base The relative directory this file is expected to be in.
- * @return {Promise} Resolved when loading completes
- */
- async parse(filename = "chrome.manifest", base = "") {
- await this.parseString(await this.loader(filename), base);
- }
-
- /**
- * Parse the given string.
- *
- * @param {String} data The file data to load
- * @param {String} base The relative directory this file is expected to be in.
- * @return {Promise} Resolved when loading completes
- */
- async parseString(data, base = "") {
- const lines = data.split("\n");
- const extraManifests = [];
- for (const line of lines) {
- const parts = line.split(/\s+/);
- const directive = parts.shift();
- switch (directive) {
- case "manifest":
- extraManifests.push(this._parseManifest(base, ...parts));
- break;
- case "component": this._parseComponent(...parts);
- break;
- case "contract": this._parseContract(...parts);
- break;
- case "category": this._parseCategory(...parts);
- break;
- case "content": this._parseContent(...parts);
- break;
- case "locale": this._parseLocale(...parts);
- break;
- case "skin": this._parseSkin(...parts);
- break;
- case "resource": this._parseResource(...parts);
- break;
- case "overlay": this._parseOverlay(...parts);
- break;
- case "style": this._parseStyle(...parts);
- break;
- case "override": this._parseOverride(...parts);
- break;
- }
- }
-
- await Promise.all(extraManifests);
- }
-
- /**
- * Ensure the flags provided for the instruction match our options
- *
- * @param {String[]} flags An array of raw flag values in the form key=value.
- * @return {Boolean} True, if the flags match the options provided in the constructor
- */
- _parseFlags(flags) {
- const matchString = (a, sign, b) => {
- if (sign != "=") {
- console.warn(`Invalid sign ${sign} in ${a}${sign}${b}, dropping manifest instruction`);
- return false;
- }
- return a == b;
- };
-
- const matchVersion = (a, sign, b) => {
- switch (sign) {
- case "=": return Services.vc.compare(a, b) == 0;
- case ">": return Services.vc.compare(a, b) > 0;
- case "<": return Services.vc.compare(a, b) < 0;
- case ">=": return Services.vc.compare(a, b) >= 0;
- case "<=": return Services.vc.compare(a, b) <= 0;
- default:
- console.warn(`Invalid sign ${sign} in ${a}${sign}${b}, dropping manifest instruction`);
- return false;
- }
- };
-
- const flagdata = new DefaultMap(() => []);
-
- const flagMatches = (key, typeMatch) => {
- return !flagdata.has(key) || flagdata.get(key).some(val => typeMatch(this.options[key], ...val));
- };
-
- for (const flag of flags) {
- const match = flag.match(/(\w+)(>=|<=|<|>|=)(.*)/);
- if (match) {
- flagdata.get(match[1]).push([match[2], match[3]]);
- } else {
- console.warn(`Invalid flag ${flag}, dropping manifest instruction`);
- }
- }
-
- return flagMatches("application", matchString) &&
- flagMatches("appversion", matchVersion) &&
- flagMatches("platformversion", matchVersion) &&
- flagMatches("os", matchString) &&
- flagMatches("osversion", matchVersion) &&
- flagMatches("abi", matchString);
- }
-
- /**
- * Parse the manifest instruction, to load other files
- *
- * @param {String} base The base directory the manifest file is in
- * @param {String} filename The file and path to load
- * @param {...String} flags The flags for this instruction
- * @return {Promise} Promise resolved when the manifest is loaded
- */
- async _parseManifest(base, filename, ...flags) {
- if (this._parseFlags(flags)) {
- const dirparts = filename.split("/");
- dirparts.pop();
-
- try {
- await this.parse(filename, base + "/" + dirparts.join("/"));
- } catch (e) {
- console.log(`Could not read manifest '${base}/${filename}'.`);
- }
- }
- return null;
- }
-
- /**
- * Parse the component instruction, to load xpcom components
- *
- * @param {String} classid The xpcom class id to load
- * @param {String} loction The file location of this component
- * @param {...String} flags The flags for this instruction
- */
- _parseComponent(classid, location, ...flags) {
- if (this._parseFlags(flags)) {
- this.component.set(classid, location);
- }
- }
-
- /**
- * Parse the contract instruction, to load xpcom contract ids
- *
- * @param {String} contractid The xpcom contract id to load
- * @param {String} location The file location of this component
- * @param {...String} flags The flags for this instruction
- */
- _parseContract(contractid, location, ...flags) {
- if (this._parseFlags(flags)) {
- this.contract.set(contractid, location);
- }
- }
-
- /**
- * Parse the category instruction, to set up xpcom categories
- *
- * @param {String} category The name of the category
- * @param {String} entryName The category entry name
- * @param {String} value The category entry value
- * @param {...String} flags The flags for this instruction
- */
- _parseCategory(category, entryName, value, ...flags) {
- if (this._parseFlags(flags)) {
- this.category.get(category).set(entryName, value);
- }
- }
-
- /**
- * Parse the content instruction, to set chrome content locations
- *
- * @param {String} shortname The content short name, e.g. chrome://shortname/content/
- * @param {String} location The location for this content registration
- * @param {...String} flags The flags for this instruction
- */
- _parseContent(shortname, location, ...flags) {
- if (this._parseFlags(flags)) {
- this.content.set(shortname, location);
- }
- }
-
- /**
- * Parse the locale instruction, to set chrome locale locations
- *
- * @param {String} shortname The locale short name, e.g. chrome://shortname/locale/
- * @param {String} location The location for this locale registration
- * @param {...String} flags The flags for this instruction
- */
- _parseLocale(shortname, locale, location, ...flags) {
- if (this._parseFlags(flags)) {
- this.locales.get(shortname).set(locale, location);
- }
- }
-
- /**
- * Parse the skin instruction, to set chrome skin locations
- *
- * @param {String} shortname The skin short name, e.g. chrome://shortname/skin/
- * @param {String} location The location for this skin registration
- * @param {...String} flags The flags for this instruction
- */
- _parseSkin(packagename, skinname, location, ...flags) {
- if (this._parseFlags(flags)) {
- this.skin.get(packagename).set(skinname, location);
- }
- }
-
- /**
- * Parse the resource instruction, to set up resource uri subtitutions
- *
- * @param {String} packagename The resource package name, e.g. resource://packagename/
- * @param {String} url The location for this content registration
- * @param {...String} flags The flags for this instruction
- */
- _parseResource(packagename, location, ...flags) {
- if (this._parseFlags(flags)) {
- this.resource.set(packagename, location);
- }
- }
-
- /**
- * Parse the overlay instruction, to set up xul overlays
- *
- * @param {String} targetUrl The chrome target url
- * @param {String} overlayUrl The url of the xul overlay
- * @param {...String} flags The flags for this instruction
- */
- _parseOverlay(targetUrl, overlayUrl, ...flags) {
- if (this._parseFlags(flags)) {
- this.overlay.get(targetUrl).push(overlayUrl);
- }
- }
-
- /**
- * Parse the style instruction, to add stylesheets into chrome windows
- *
- * @param {String} uri The uri of the chrome window
- * @param {String} sheet The uri of the css sheet
- * @param {...String} flags The flags for this instruction
- */
- _parseStyle(uri, sheet, ...flags) {
- if (this._parseFlags(flags)) {
- this.style.get(uri).add(sheet);
- }
- }
-
- /**
- * Parse the override instruction, to set chrome uri overrides
- *
- * @param {String} uri The uri being overridden
- * @param {String} newuri The replacement uri for the original location
- * @param {...String} flags The flags for this instruction
- */
- _parseOverride(uri, newuri, ...flags) {
- if (this._parseFlags(flags)) {
- this.override.set(uri, newuri);
- }
- }
-
- /**
- * Output the manifest data as a string in chrome.manifest format
- * If root is provided, convert all relative locations to absolute paths.
- *
- * @param {String} [root] The absolute path root to resolve relative locations
- * @return {String} The manifest contents as a string
- */
- toString(root = "") {
- const lines = [];
- const isRelative = loc => {
- // Not absolute if doesn't start with /, \, or protocol (chrome://, resource://, etc)
- return (
- typeof loc === "string" &&
- !loc.match(/^(?:[a-zA-Z]+:|\\|\/)/)
- );
- };
- const absolutize = loc => {
- if (!root) return loc;
- if (loc === "/") return root;
- if (isRelative(loc)) {
- return root.replace(/[\\/]$/, "") + "/" + loc.replace(/^([\\\/])/, "");
- }
- return loc;
- };
-
- // Output components
- for (const [classid, location] of this.component) {
- lines.push(`component ${classid} ${absolutize(location)}`);
- }
-
- // Output contracts
- for (const [contractid, location] of this.contract) {
- lines.push(`contract ${contractid} ${absolutize(location)}`);
- }
-
- // Output categories
- for (const [category, entries] of this.category) {
- for (const [entryName, value] of entries) {
- lines.push(`category ${category} ${entryName} ${value}`);
- }
- }
-
- // Output content
- for (const [shortname, location] of this.content) {
- lines.push(`content ${shortname} ${absolutize(location)}`);
- }
-
- // Output locales
- for (const [shortname, locales] of this.locales) {
- for (const [locale, location] of locales) {
- lines.push(`locale ${shortname} ${locale} ${absolutize(location)}`);
- }
- }
-
- // Output skins
- for (const [packagename, skins] of this.skin) {
- for (const [skinname, location] of skins) {
- lines.push(`skin ${packagename} ${skinname} ${absolutize(location)}`);
- }
- }
-
- // Output resources
- for (const [packagename, location] of this.resource) {
- lines.push(`resource ${packagename} ${absolutize(location)}`);
- }
-
- // Output overlays
- for (const [targetUrl, overlays] of this.overlay) {
- for (const overlayUrl of overlays) {
- lines.push(`overlay ${targetUrl} ${absolutize(overlayUrl)}`);
- }
- }
-
- // Output styles
- for (const [uri, sheets] of this.style) {
- for (const sheet of sheets) {
- lines.push(`style ${uri} ${absolutize(sheet)}`);
- }
- }
-
- // Output overrides
- for (const [uri, newuri] of this.override) {
- lines.push(`override ${uri} ${newuri}`);
- }
-
- return lines.join("\n");
- }
-}
diff --git a/modules/firefox.home/chrome/utils/RDFDataSource.sys.mjs b/modules/firefox.home/chrome/utils/RDFDataSource.sys.mjs
deleted file mode 100644
index c6380c1..0000000
--- a/modules/firefox.home/chrome/utils/RDFDataSource.sys.mjs
+++ /dev/null
@@ -1,434 +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/. */
-
-/**
- * This module creates a new API for accessing and modifying RDF graphs. The
- * goal is to be able to serialise the graph in a human readable form. Also
- * if the graph was originally loaded from an RDF/XML the serialisation should
- * closely match the original with any new data closely following the existing
- * layout. The output should always be compatible with Mozilla's RDF parser.
- *
- * This is all achieved by using a DOM Document to hold the current state of the
- * graph in XML form. This can be initially loaded and parsed from disk or
- * a blank document used for an empty graph. As assertions are added to the
- * graph, appropriate DOM nodes are added to the document to represent them
- * along with any necessary whitespace to properly layout the XML.
- *
- * In general the order of adding assertions to the graph will impact the form
- * the serialisation takes. If a resource is first added as the object of an
- * assertion then it will eventually be serialised inside the assertion's
- * property element. If a resource is first added as the subject of an assertion
- * then it will be serialised at the top level of the XML.
- */
-
-const NS_XML = "http://www.w3.org/XML/1998/namespace";
-const NS_XMLNS = "http://www.w3.org/2000/xmlns/";
-const NS_RDF = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
-const NS_NC = "http://home.netscape.com/NC-rdf#";
-
-/* eslint prefer-template: 1 */
-
-function isElement(obj) {
- return Element.isInstance(obj);
-}
-function isText(obj) {
- return obj && typeof obj == "object" && ChromeUtils.getClassName(obj) == "Text";
-}
-
-/**
- * Returns either an rdf namespaced attribute or an un-namespaced attribute
- * value. Returns null if neither exists,
- */
-function getRDFAttribute(element, name) {
- if (element.hasAttributeNS(NS_RDF, name))
- return element.getAttributeNS(NS_RDF, name);
- if (element.hasAttribute(name))
- return element.getAttribute(name);
- return undefined;
-}
-
-/**
- * Represents an assertion in the datasource
- */
-class RDFAssertion {
- constructor(subject, predicate, object) {
- // The subject on this assertion, an RDFSubject
- this._subject = subject;
- // The predicate, a string
- this._predicate = predicate;
- // The object, an RDFNode
- this._object = object;
- // The datasource this assertion exists in
- this._ds = this._subject._ds;
- // Marks that _DOMnode is the subject's element
- this._isSubjectElement = false;
- // The DOM node that represents this assertion. Could be a property element,
- // a property attribute or the subject's element for rdf:type
- this._DOMNode = null;
- }
-
- getPredicate() {
- return this._predicate;
- }
-
- getObject() {
- return this._object;
- }
-}
-
-class RDFNode {
- equals(rdfnode) {
- return (rdfnode.constructor === this.constructor &&
- rdfnode._value == this._value);
- }
-}
-
-/**
- * A simple literal value
- */
-export class RDFLiteral extends RDFNode {
- constructor(value) {
- super();
- this._value = value;
- }
-
- getValue() {
- return this._value;
- }
-}
-
-/**
- * This is an RDF node that can be a subject so a resource or a blank node
- */
-class RDFSubject extends RDFNode {
- constructor(ds) {
- super();
- // A lookup of the assertions with this as the subject. Keyed on predicate
- this._assertions = {};
- // A lookup of the assertions with this as the object. Keyed on predicate
- this._backwards = {};
- // The datasource this subject belongs to
- this._ds = ds;
- // The DOM elements in the document that represent this subject. Array of Element
- this._elements = [];
- }
-
- /**
- * Parses the given Element from the DOM document
- */
- /* eslint-disable complexity */
- _parseElement(element) {
- this._elements.push(element);
-
- // There might be an inferred rdf:type assertion in the element name
- if (element.namespaceURI != NS_RDF ||
- element.localName != "Description") {
- var assertion = new RDFAssertion(this, RDF_R("type"),
- this._ds.getResource(element.namespaceURI + element.localName));
- assertion._DOMnode = element;
- assertion._isSubjectElement = true;
- this._addAssertion(assertion);
- }
-
- // Certain attributes can be literal properties
- for (let attr of element.attributes) {
- if (attr.namespaceURI == NS_XML || attr.namespaceURI == NS_XMLNS ||
- attr.nodeName == "xmlns")
- continue;
- if ((attr.namespaceURI == NS_RDF || !attr.namespaceURI) &&
- (["nodeID", "about", "resource", "ID", "parseType"].includes(attr.localName)))
- continue;
- var object = null;
- if (attr.namespaceURI == NS_RDF) {
- if (attr.localName == "type")
- object = this._ds.getResource(attr.nodeValue);
- }
- if (!object)
- object = new RDFLiteral(attr.nodeValue);
- assertion = new RDFAssertion(this, attr.namespaceURI + attr.localName, object);
- assertion._DOMnode = attr;
- this._addAssertion(assertion);
- }
-
- var child = element.firstChild;
- element.listCounter = 1;
- while (child) {
- if (isElement(child)) {
- object = null;
- var predicate = child.namespaceURI + child.localName;
- if (child.namespaceURI == NS_RDF) {
- if (child.localName == "li") {
- predicate = RDF_R(`_${element.listCounter}`);
- element.listCounter++;
- }
- }
-
- // Check for and bail out on unknown attributes on the property element
- for (let attr of child.attributes) {
- // Ignore XML namespaced attributes
- if (attr.namespaceURI == NS_XML)
- continue;
- // These are reserved by XML for future use
- if (attr.localName.substring(0, 3).toLowerCase() == "xml")
- continue;
- // We can handle these RDF attributes
- if ((!attr.namespaceURI || attr.namespaceURI == NS_RDF) &&
- ["resource", "nodeID"].includes(attr.localName))
- continue;
- // This is a special attribute we handle for compatibility with Mozilla RDF
- if (attr.namespaceURI == NS_NC &&
- attr.localName == "parseType")
- continue;
- }
-
- var parseType = child.getAttributeNS(NS_NC, "parseType");
-
- var resource = getRDFAttribute(child, "resource");
- var nodeID = getRDFAttribute(child, "nodeID");
-
- if (resource !== undefined) {
- var base = Services.io.newURI(element.baseURI);
- object = this._ds.getResource(base.resolve(resource));
- } else if (nodeID !== undefined) {
- object = this._ds.getBlankNode(nodeID);
- } else {
- var hasText = false;
- var childElement = null;
- var subchild = child.firstChild;
- while (subchild) {
- if (isText(subchild) && /\S/.test(subchild.nodeValue)) {
- hasText = true;
- } else if (isElement(subchild)) {
- childElement = subchild;
- }
- subchild = subchild.nextSibling;
- }
-
- if (childElement) {
- object = this._ds._getSubjectForElement(childElement);
- object._parseElement(childElement);
- } else
- object = new RDFLiteral(child.textContent);
- }
-
- assertion = new RDFAssertion(this, predicate, object);
- this._addAssertion(assertion);
- assertion._DOMnode = child;
- }
- child = child.nextSibling;
- }
- }
- /* eslint-enable complexity */
-
- /**
- * Adds a new assertion to the internal hashes. Should be called for every
- * new assertion parsed or created programmatically.
- */
- _addAssertion(assertion) {
- var predicate = assertion.getPredicate();
- if (predicate in this._assertions)
- this._assertions[predicate].push(assertion);
- else
- this._assertions[predicate] = [ assertion ];
-
- var object = assertion.getObject();
- if (object instanceof RDFSubject) {
- // Create reverse assertion
- if (predicate in object._backwards)
- object._backwards[predicate].push(assertion);
- else
- object._backwards[predicate] = [ assertion ];
- }
- }
-
- /**
- * Returns all objects in assertions with this subject and the given predicate.
- */
- getObjects(predicate) {
- if (predicate in this._assertions)
- return Array.from(this._assertions[predicate],
- i => i.getObject());
-
- return [];
- }
-
- /**
- * Retrieves the first property value for the given predicate.
- */
- getProperty(predicate) {
- if (predicate in this._assertions)
- return this._assertions[predicate][0].getObject();
- return null;
- }
-}
-
-/**
- * Creates a new RDFResource for the datasource. Private.
- */
-export class RDFResource extends RDFSubject {
- constructor(ds, uri) {
- super(ds);
- // This is the uri that the resource represents.
- this._uri = uri;
- }
-}
-
-/**
- * Creates a new blank node. Private.
- */
-export class RDFBlankNode extends RDFSubject {
- constructor(ds, nodeID) {
- super(ds);
- // The nodeID of this node. May be null if there is no ID.
- this._nodeID = nodeID;
- }
-
- /**
- * Sets attributes on the DOM element to mark it as representing this node
- */
- _applyToElement(element) {
- if (!this._nodeID)
- return;
- if (USE_RDFNS_ATTR) {
- var prefix = this._ds._resolvePrefix(element, RDF_R("nodeID"));
- element.setAttributeNS(prefix.namespaceURI, prefix.qname, this._nodeID);
- } else {
- element.setAttribute("nodeID", this._nodeID);
- }
- }
-
- /**
- * Creates a new Element in the document for holding assertions about this
- * subject. The URI controls what tagname to use.
- */
- _createNewElement(uri) {
- // If there are already nodes representing this in the document then we need
- // a nodeID to match them
- if (!this._nodeID && this._elements.length > 0) {
- this._ds._createNodeID(this);
- for (let element of this._elements)
- this._applyToElement(element);
- }
-
- return super._createNewElement.call(uri);
- }
-
- /**
- * Adds a reference to this node to the given property Element.
- */
- _addReferenceToElement(element) {
- if (this._elements.length > 0 && !this._nodeID) {
- // In document elsewhere already
- // Create a node ID and update the other nodes referencing
- this._ds._createNodeID(this);
- for (let element of this._elements)
- this._applyToElement(element);
- }
-
- if (this._nodeID) {
- if (USE_RDFNS_ATTR) {
- let prefix = this._ds._resolvePrefix(element, RDF_R("nodeID"));
- element.setAttributeNS(prefix.namespaceURI, prefix.qname, this._nodeID);
- } else {
- element.setAttribute("nodeID", this._nodeID);
- }
- } else {
- // Add the empty blank node, this is generally right since further
- // assertions will be added to fill this out
- var newelement = this._ds._addElement(element, RDF_R("Description"));
- newelement.listCounter = 1;
- this._elements.push(newelement);
- }
- }
-
- /**
- * Removes any reference to this node from the given property Element.
- */
- _removeReferenceFromElement(element) {
- if (element.hasAttributeNS(NS_RDF, "nodeID"))
- element.removeAttributeNS(NS_RDF, "nodeID");
- if (element.hasAttribute("nodeID"))
- element.removeAttribute("nodeID");
- }
-
- getNodeID() {
- return this._nodeID;
- }
-}
-
-/**
- * Creates a new RDFDataSource from the given document. The document will be
- * changed as assertions are added and removed to the RDF. Pass a null document
- * to start with an empty graph.
- */
-export class RDFDataSource {
- constructor(document) {
- // All known resources, indexed on URI
- this._resources = {};
- // All blank nodes
- this._allBlankNodes = [];
-
- // The underlying DOM document for this datasource
- this._document = document;
- this._parseDocument();
- }
-
- static loadFromString(text) {
- let parser = new DOMParser();
- let document = parser.parseFromString(text, "application/xml");
-
- return new this(document);
- }
-
- /**
- * Returns an rdf subject for the given DOM Element. If the subject has not
- * been seen before a new one is created.
- */
- _getSubjectForElement(element) {
- var about = getRDFAttribute(element, "about");
-
- if (about !== undefined) {
- let base = Services.io.newURI(element.baseURI);
- return this.getResource(base.resolve(about));
- }
- return this.getBlankNode(null);
- }
-
- /**
- * Parses the document for subjects at the top level.
- */
- _parseDocument() {
- var domnode = this._document.documentElement.firstChild;
- while (domnode) {
- if (isElement(domnode)) {
- var subject = this._getSubjectForElement(domnode);
- subject._parseElement(domnode);
- }
- domnode = domnode.nextSibling;
- }
- }
-
- /**
- * Gets a blank node. nodeID may be null and if so a new blank node is created.
- * If a nodeID is given then the blank node with that ID is returned or created.
- */
- getBlankNode(nodeID) {
- var rdfnode = new RDFBlankNode(this, nodeID);
- this._allBlankNodes.push(rdfnode);
- return rdfnode;
- }
-
- /**
- * Gets the resource for the URI. The resource is created if it has not been
- * used already.
- */
- getResource(uri) {
- if (uri in this._resources)
- return this._resources[uri];
-
- var resource = new RDFResource(this, uri);
- this._resources[uri] = resource;
- return resource;
- }
-} \ No newline at end of file
diff --git a/modules/firefox.home/chrome/utils/RDFManifestConverter.sys.mjs b/modules/firefox.home/chrome/utils/RDFManifestConverter.sys.mjs
deleted file mode 100644
index 25cae7e..0000000
--- a/modules/firefox.home/chrome/utils/RDFManifestConverter.sys.mjs
+++ /dev/null
@@ -1,99 +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";
-
-import { RDFDataSource } from "chrome://userchromejs/content/RDFDataSource.sys.mjs";
-
-const RDFURI_INSTALL_MANIFEST_ROOT = "urn:mozilla:install-manifest";
-
-function EM_R(aProperty) {
- return `http://www.mozilla.org/2004/em-rdf#${aProperty}`;
-}
-
-function getValue(literal) {
- return literal && literal.getValue();
-}
-
-function getProperty(resource, property) {
- return getValue(resource.getProperty(EM_R(property)));
-}
-
-class Manifest {
- constructor(ds) {
- this.ds = ds;
- }
-
- static loadFromString(text) {
- return new this(RDFDataSource.loadFromString(text));
- }
-}
-
-export class InstallRDF extends Manifest {
- _readProps(source, obj, props) {
- for (let prop of props) {
- let val = getProperty(source, prop);
- if (val != null) {
- obj[prop] = val;
- }
- }
- }
-
- _readArrayProp(source, obj, prop, target, decode = getValue) {
- let result = Array.from(source.getObjects(EM_R(prop)),
- target => decode(target));
- if (result.length) {
- obj[target] = result;
- }
- }
-
- _readArrayProps(source, obj, props, decode = getValue) {
- for (let [prop, target] of Object.entries(props)) {
- this._readArrayProp(source, obj, prop, target, decode);
- }
- }
-
- _readLocaleStrings(source, obj) {
- this._readProps(source, obj, ["name", "description", "creator", "homepageURL"]);
- this._readArrayProps(source, obj, {
- locale: "locales",
- developer: "developers",
- translator: "translators",
- contributor: "contributors",
- });
- }
-
- decode() {
- let root = this.ds.getResource(RDFURI_INSTALL_MANIFEST_ROOT);
- let result = {};
-
- let props = ["id", "version", "type", "updateURL", "optionsURL",
- "optionsType", "aboutURL", "iconURL",
- "bootstrap", "unpack", "strictCompatibility"];
- this._readProps(root, result, props);
-
- let decodeTargetApplication = source => {
- let app = {};
- this._readProps(source, app, ["id", "minVersion", "maxVersion"]);
- return app;
- };
-
- let decodeLocale = source => {
- let localized = {};
- this._readLocaleStrings(source, localized);
- return localized;
- };
-
- this._readLocaleStrings(root, result);
-
- this._readArrayProps(root, result, {"targetPlatform": "targetPlatforms"});
- this._readArrayProps(root, result, {"targetApplication": "targetApplications"},
- decodeTargetApplication);
- this._readArrayProps(root, result, {"localized": "localized"},
- decodeLocale);
- this._readArrayProps(root, result, {"dependency": "dependencies"},
- source => getProperty(source, "id"));
-
- return result;
- }
-} \ No newline at end of file
diff --git a/modules/firefox.home/chrome/utils/chrome.manifest b/modules/firefox.home/chrome/utils/chrome.manifest
deleted file mode 100644
index d9076b2..0000000
--- a/modules/firefox.home/chrome/utils/chrome.manifest
+++ /dev/null
@@ -1,2 +0,0 @@
-content userchromejs ./
-resource userchromejs ../
diff --git a/modules/firefox.home/chrome/utils/userChrome.js b/modules/firefox.home/chrome/utils/userChrome.js
deleted file mode 100644
index 1870bee..0000000
--- a/modules/firefox.home/chrome/utils/userChrome.js
+++ /dev/null
@@ -1,272 +0,0 @@
-'use strict';
-
-(() => {
- ChromeUtils.defineESModuleGetters(globalThis, {
- xPref: 'chrome://userchromejs/content/xPref.sys.mjs',
- Management: 'resource://gre/modules/Extension.sys.mjs',
- AppConstants: 'resource://gre/modules/AppConstants.sys.mjs',
- });
-
- let UC = {
- webExts: new Map(),
- sidebar: new Map(),
- sandboxes: new WeakMap()
- };
-
- let _uc = {
- ALWAYSEXECUTE: 'rebuild_userChrome.uc.js',
- BROWSERCHROME: AppConstants.MOZ_APP_NAME == 'thunderbird' ? 'chrome://messenger/content/messenger.xhtml' : 'chrome://browser/content/browser.xhtml',
- BROWSERTYPE: AppConstants.MOZ_APP_NAME == 'thunderbird' ? 'mail:3pane' : 'navigator:browser',
- BROWSERNAME: AppConstants.MOZ_APP_NAME.charAt(0).toUpperCase() + AppConstants.MOZ_APP_NAME.slice(1),
- PREF_ENABLED: 'userChromeJS.enabled',
- PREF_SCRIPTSDISABLED: 'userChromeJS.scriptsDisabled',
-
- chromedir: Services.dirsvc.get('UChrm', Ci.nsIFile),
- scriptsDir: '',
-
- sss: Cc["@mozilla.org/content/style-sheet-service;1"].getService(Ci.nsIStyleSheetService),
-
- getScripts: function () {
- this.scripts = {};
- let files = this.chromedir.directoryEntries.QueryInterface(Ci.nsISimpleEnumerator);
- while (files.hasMoreElements()) {
- let file = files.getNext().QueryInterface(Ci.nsIFile);
- if (/\.uc\.js$/i.test(file.leafName)) {
- _uc.getScriptData(file);
- }
- }
- },
-
- getScriptData: function (aFile) {
- let aContent = this.readFile(aFile);
- let header = (aContent.match(/^\/\/ ==UserScript==\s*\n(?:.*\n)*?\/\/ ==\/UserScript==\s*\n/m) || [''])[0];
- let match, rex = {
- include: [],
- exclude: []
- };
- let findNextRe = /^\/\/ @(include|exclude)\s+(.+)\s*$/gm;
- while ((match = findNextRe.exec(header))) {
- rex[match[1]].push(match[2].replace(/^main$/i, _uc.BROWSERCHROME).replace(/\*/g, '.*?'));
- }
- if (!rex.include.length) {
- rex.include.push(_uc.BROWSERCHROME);
- }
- let exclude = rex.exclude.length ? '(?!' + rex.exclude.join('$|') + '$)' : '';
-
- let def = ['', ''];
- let author = (header.match(/\/\/ @author\s+(.+)\s*$/im) || def)[1];
- let filename = aFile.leafName || '';
-
- return this.scripts[filename] = {
- filename: filename,
- file: aFile,
- url: Services.io.getProtocolHandler('file').QueryInterface(Ci.nsIFileProtocolHandler).getURLSpecFromDir(this.chromedir) + filename,
- name: (header.match(/\/\/ @name\s+(.+)\s*$/im) || def)[1],
- description: (header.match(/\/\/ @description\s+(.+)\s*$/im) || def)[1],
- version: (header.match(/\/\/ @version\s+(.+)\s*$/im) || def)[1],
- author: (header.match(/\/\/ @author\s+(.+)\s*$/im) || def)[1],
- regex: new RegExp('^' + exclude + '(' + (rex.include.join('|') || '.*') + ')$', 'i'),
- id: (header.match(/\/\/ @id\s+(.+)\s*$/im) || ['', filename.split('.uc.js')[0] + '@' + (author || 'userChromeJS')])[1],
- homepageURL: (header.match(/\/\/ @homepageURL\s+(.+)\s*$/im) || def)[1],
- downloadURL: (header.match(/\/\/ @downloadURL\s+(.+)\s*$/im) || def)[1],
- updateURL: (header.match(/\/\/ @updateURL\s+(.+)\s*$/im) || def)[1],
- optionsURL: (header.match(/\/\/ @optionsURL\s+(.+)\s*$/im) || def)[1],
- startup: (header.match(/\/\/ @startup\s+(.+)\s*$/im) || def)[1],
- shutdown: (header.match(/\/\/ @shutdown\s+(.+)\s*$/im) || def)[1],
- onlyonce: /\/\/ @onlyonce\b/.test(header),
- isRunning: false,
- get isEnabled() {
- return (xPref.get(_uc.PREF_SCRIPTSDISABLED) || '').split(',').indexOf(this.filename) == -1;
- }
- }
- },
-
- readFile: function (aFile, metaOnly = false) {
- let stream = Cc['@mozilla.org/network/file-input-stream;1'].createInstance(Ci.nsIFileInputStream);
- stream.init(aFile, 0x01, 0, 0);
- let cvstream = Cc['@mozilla.org/intl/converter-input-stream;1'].createInstance(Ci.nsIConverterInputStream);
- cvstream.init(stream, 'UTF-8', 1024, Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
- let content = '',
- data = {};
- while (cvstream.readString(4096, data)) {
- content += data.value;
- if (metaOnly && content.indexOf('// ==/UserScript==') > 0) {
- break;
- }
- }
- cvstream.close();
- return content.replace(/\r\n?/g, '\n');
- },
-
- everLoaded: [],
-
- loadScript: function (script, win) {
- if (!script.regex.test(win.location.href) || (script.filename != this.ALWAYSEXECUTE && !script.isEnabled)) {
- return;
- }
-
- if (script.onlyonce && script.isRunning) {
- if (script.startup) {
- Cu.evalInSandbox(`(function(script, win){${script.startup}})`, this.getSandbox(win))(script, win);
- }
- return;
- }
-
- try {
- Services.scriptloader.loadSubScript(script.url + '?' + script.file.lastModifiedTime,
- script.onlyonce ? { window: win } : win);
- script.isRunning = true;
- if (script.startup) {
- Cu.evalInSandbox(`(function(script, win){${script.startup}})`, this.getSandbox(win))(script, win);
- }
- if (!script.shutdown) {
- this.everLoaded.push(script.id);
- }
- } catch (ex) {
- Cu.reportError(ex);
- }
- },
-
- getSandbox: function (doc) {
- if (!UC.sandboxes) UC.sandboxes = new WeakMap();
- let global = Cu.getGlobalForObject(doc);
- if (UC.sandboxes.has(global))
- return UC.sandboxes.get(global);
- let sb = Cu.Sandbox(Services.scriptSecurityManager.getSystemPrincipal(), {
- sandboxPrototype: global,
- sameZoneAs: global,
- wantXrays: false,
- sandboxName: 'UCJS:Sandbox'
- });
- UC.sandboxes.set(global, sb);
- global.addEventListener('unload', () => {
- UC.sandboxes.delete(global);
- Cu.nukeSandbox(sb);
- });
- return sb;
- },
-
- windows: function (fun, onlyBrowsers = true) {
- let windows = Services.wm.getEnumerator(onlyBrowsers ? this.BROWSERTYPE : null);
- while (windows.hasMoreElements()) {
- let win = windows.getNext();
- if (!win._uc)
- continue;
- if (!onlyBrowsers) {
- let frames = win.docShell.getAllDocShellsInSubtree(Ci.nsIDocShellTreeItem.typeAll, Ci.nsIDocShell.ENUMERATE_FORWARDS);
- let res = frames.some(frame => {
- let fWin = frame.domWindow;
- let {document, location} = fWin;
- if (fun(document, fWin, location))
- return true;
- });
- if (res)
- break;
- } else {
- let {document, location} = win;
- if (fun(document, win, location))
- break;
- }
- }
- },
-
- createElement: function (doc, tag, atts, XUL = true) {
- let el = XUL ? doc.createXULElement(tag) : doc.createElement(tag);
- for (let att in atts) {
- if (att.startsWith('on'))
- el.addEventListener(att.slice(2), typeof atts[att] == "string" ?
- Cu.evalInSandbox(`(function(event){${atts[att]}})`, this.getSandbox(doc)) : atts[att]);
- else
- el.setAttribute(att, atts[att]);
- }
- return el
- }
- };
-
- if (xPref.get(_uc.PREF_ENABLED) === undefined) {
- xPref.set(_uc.PREF_ENABLED, true, true);
- }
-
- if (xPref.get(_uc.PREF_SCRIPTSDISABLED) === undefined) {
- xPref.set(_uc.PREF_SCRIPTSDISABLED, '', true);
- }
-
- let UserChrome_js = {
- observe: function (aSubject) {
- if (
- AppConstants.MOZ_APP_NAME == "thunderbird" &&
- aSubject?.location?.href.startsWith("chrome://messenger/content")
- ) {
- aSubject.addEventListener("DOMContentLoaded", () => {
- this.load(aSubject);
- }, {once: true})
- } else {
- aSubject.addEventListener('DOMContentLoaded', this, {once: true});
- }
- },
-
- handleEvent: function (aEvent) {
- let document = aEvent.originalTarget;
- let window = document.defaultView;
- if (window.document.isInitialDocument) {
- this.load(window.parent);
- } else {
- this.load(window);
- }
- },
-
- load: function (window) {
- let location = window.location;
-
- if (!this.sharedWindowOpened && location.href == 'chrome://extensions/content/dummy.xhtml') {
- this.sharedWindowOpened = true;
-
- Management.on('extension-browser-inserted', function (topic, browser) {
- browser.messageManager.addMessageListener('Extension:BackgroundViewLoaded', this.messageListener.bind(this));
- }.bind(this));
- } else if (/^(chrome:(?!\/\/global\/content\/commonDialog\.x?html)|about:(?!blank))/i.test(location.href)) {
- window.UC = UC;
- window._uc = _uc;
- window.xPref = xPref;
- if (window._gBrowser) // bug 1443849
- window.gBrowser = window._gBrowser;
-
- if (xPref.get(_uc.PREF_ENABLED)) {
- Object.values(_uc.scripts).forEach(script => {
- _uc.loadScript(script, window);
- });
- } else if (!UC.rebuild) {
- _uc.loadScript(_uc.scripts[_uc.ALWAYSEXECUTE], window);
- }
- }
- },
-
- messageListener: function (msg) {
- const browser = msg.target;
- const { addonId } = browser._contentPrincipal;
-
- browser.messageManager.removeMessageListener('Extension:BackgroundViewLoaded', this.messageListener);
-
- if (browser.ownerGlobal.location.href == 'chrome://extensions/content/dummy.xhtml') {
- UC.webExts.set(addonId, browser);
- Services.obs.notifyObservers(null, 'UCJS:WebExtLoaded', addonId);
- } else {
- let win = browser.ownerGlobal.windowRoot.ownerGlobal;
- UC.sidebar.get(addonId)?.set(win, browser) || UC.sidebar.set(addonId, new Map([[win, browser]]));
- Services.obs.notifyObservers(win, 'UCJS:SidebarLoaded', addonId);
- }
- }
- };
-
- if (!Services.appinfo.inSafeMode) {
- _uc.chromedir.append(_uc.scriptsDir);
- _uc.getScripts();
- let windows = Services.wm.getEnumerator(null);
- while (windows.hasMoreElements()) {
- let win = windows.getNext();
- if (!('UC' in win))
- UserChrome_js.load(win)
- }
- Services.obs.addObserver(UserChrome_js, 'chrome-document-global-created', false);
- }
-})();
diff --git a/modules/firefox.home/chrome/utils/xPref.sys.mjs b/modules/firefox.home/chrome/utils/xPref.sys.mjs
deleted file mode 100644
index aba56db..0000000
--- a/modules/firefox.home/chrome/utils/xPref.sys.mjs
+++ /dev/null
@@ -1,92 +0,0 @@
-'use strict';
-
-export const xPref = {
- // Retorna o valor da preferência, seja qual for o tipo, mas não
- // testei com tipos complexos como nsIFile, não sei como detectar
- // uma preferência assim, na verdade nunca vi uma
- get: function (prefPath, def = false, valueIfUndefined, setDefault = true) {
- let sPrefs = def ?
- Services.prefs.getDefaultBranch(null) :
- Services.prefs;
-
- try {
- switch (sPrefs.getPrefType(prefPath)) {
- case 0:
- if (valueIfUndefined != undefined)
- return this.set(prefPath, valueIfUndefined, setDefault);
- else
- return undefined;
- case 32:
- return sPrefs.getStringPref(prefPath);
- case 64:
- return sPrefs.getIntPref(prefPath);
- case 128:
- return sPrefs.getBoolPref(prefPath);
- }
- } catch (ex) {
- return undefined;
- }
- return;
- },
-
- set: function (prefPath, value, def = false) {
- let sPrefs = def ?
- Services.prefs.getDefaultBranch(null) :
- Services.prefs;
-
- switch (typeof value) {
- case 'string':
- return sPrefs.setStringPref(prefPath, value) || value;
- case 'number':
- return sPrefs.setIntPref(prefPath, value) || value;
- case 'boolean':
- return sPrefs.setBoolPref(prefPath, value) || value;
- }
- return;
- },
-
- lock: function (prefPath, value) {
- let sPrefs = Services.prefs;
- this.lockedBackupDef[prefPath] = this.get(prefPath, true);
- if (sPrefs.prefIsLocked(prefPath))
- sPrefs.unlockPref(prefPath);
-
- this.set(prefPath, value, true);
- sPrefs.lockPref(prefPath);
- },
-
- lockedBackupDef: {},
-
- unlock: function (prefPath) {
- Services.prefs.unlockPref(prefPath);
- let bkp = this.lockedBackupDef[prefPath];
- if (bkp == undefined)
- Services.prefs.deleteBranch(prefPath);
- else
- this.set(prefPath, bkp, true);
- },
-
- clear: Services.prefs.clearUserPref,
-
- // Detecta mudanças na preferência e retorna:
- // return[0]: valor da preferência alterada
- // return[1]: nome da preferência alterada
- // Guardar chamada numa var se quiser interrompê-la depois
- addListener: function (prefPath, trat) {
- this.observer = function (aSubject, aTopic, prefPath) {
- return trat(xPref.get(prefPath), prefPath);
- }
-
- Services.prefs.addObserver(prefPath, this.observer);
- return {
- prefPath,
- observer: this.observer
- };
- },
-
- // Encerra pref observer
- // Só precisa passar a var definida quando adicionou
- removeListener: function (obs) {
- Services.prefs.removeObserver(obs.prefPath, obs.observer);
- }
-}