summaryrefslogtreecommitdiffstats
path: root/toolkit/components/extensions/NativeManifests.jsm
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /toolkit/components/extensions/NativeManifests.jsm
parentInitial commit. (diff)
downloadfirefox-upstream.tar.xz
firefox-upstream.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/components/extensions/NativeManifests.jsm')
-rw-r--r--toolkit/components/extensions/NativeManifests.jsm182
1 files changed, 182 insertions, 0 deletions
diff --git a/toolkit/components/extensions/NativeManifests.jsm b/toolkit/components/extensions/NativeManifests.jsm
new file mode 100644
index 0000000000..5e8e0dc510
--- /dev/null
+++ b/toolkit/components/extensions/NativeManifests.jsm
@@ -0,0 +1,182 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+/* 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";
+
+var EXPORTED_SYMBOLS = ["NativeManifests"];
+
+const { XPCOMUtils } = ChromeUtils.import(
+ "resource://gre/modules/XPCOMUtils.jsm"
+);
+
+XPCOMUtils.defineLazyModuleGetters(this, {
+ AppConstants: "resource://gre/modules/AppConstants.jsm",
+ OS: "resource://gre/modules/osfile.jsm",
+ Schemas: "resource://gre/modules/Schemas.jsm",
+ Services: "resource://gre/modules/Services.jsm",
+ WindowsRegistry: "resource://gre/modules/WindowsRegistry.jsm",
+});
+
+const DASHED = AppConstants.platform === "linux";
+
+// Supported native manifest types, with platform-specific slugs.
+const TYPES = {
+ stdio: DASHED ? "native-messaging-hosts" : "NativeMessagingHosts",
+ storage: DASHED ? "managed-storage" : "ManagedStorage",
+ pkcs11: DASHED ? "pkcs11-modules" : "PKCS11Modules",
+};
+
+const NATIVE_MANIFEST_SCHEMA =
+ "chrome://extensions/content/schemas/native_manifest.json";
+
+const REGPATH = "Software\\Mozilla";
+
+var NativeManifests = {
+ _initializePromise: null,
+ _lookup: null,
+
+ init() {
+ if (!this._initializePromise) {
+ let platform = AppConstants.platform;
+ if (platform == "win") {
+ this._lookup = this._winLookup;
+ } else if (platform == "macosx" || platform == "linux") {
+ let dirs = [
+ Services.dirsvc.get("XREUserNativeManifests", Ci.nsIFile).path,
+ Services.dirsvc.get("XRESysNativeManifests", Ci.nsIFile).path,
+ ];
+ this._lookup = (type, name, context) =>
+ this._tryPaths(type, name, dirs, context);
+ } else {
+ throw new Error(
+ `Native manifests are not supported on ${AppConstants.platform}`
+ );
+ }
+ this._initializePromise = Schemas.load(NATIVE_MANIFEST_SCHEMA);
+ }
+ return this._initializePromise;
+ },
+
+ async _winLookup(type, name, context) {
+ const REGISTRY = Ci.nsIWindowsRegKey;
+ let regPath = `${REGPATH}\\${TYPES[type]}\\${name}`;
+ let path = WindowsRegistry.readRegKey(
+ REGISTRY.ROOT_KEY_CURRENT_USER,
+ regPath,
+ "",
+ REGISTRY.WOW64_64
+ );
+ if (!path) {
+ path = WindowsRegistry.readRegKey(
+ REGISTRY.ROOT_KEY_LOCAL_MACHINE,
+ regPath,
+ "",
+ REGISTRY.WOW64_32
+ );
+ }
+ if (!path) {
+ path = WindowsRegistry.readRegKey(
+ REGISTRY.ROOT_KEY_LOCAL_MACHINE,
+ regPath,
+ "",
+ REGISTRY.WOW64_64
+ );
+ }
+ if (!path) {
+ return null;
+ }
+
+ let manifest = await this._tryPath(type, path, name, context, true);
+ return manifest ? { path, manifest } : null;
+ },
+
+ _tryPath(type, path, name, context, logIfNotFound) {
+ return Promise.resolve()
+ .then(() => OS.File.read(path, { encoding: "utf-8" }))
+ .then(data => {
+ let manifest;
+ try {
+ manifest = JSON.parse(data);
+ } catch (ex) {
+ Cu.reportError(
+ `Error parsing native manifest ${path}: ${ex.message}`
+ );
+ return null;
+ }
+
+ let normalized = Schemas.normalize(
+ manifest,
+ "manifest.NativeManifest",
+ context
+ );
+ if (normalized.error) {
+ Cu.reportError(normalized.error);
+ return null;
+ }
+ manifest = normalized.value;
+
+ if (manifest.type !== type) {
+ Cu.reportError(
+ `Native manifest ${path} has type property ${manifest.type} (expected ${type})`
+ );
+ return null;
+ }
+ if (manifest.name !== name) {
+ Cu.reportError(
+ `Native manifest ${path} has name property ${manifest.name} (expected ${name})`
+ );
+ return null;
+ }
+ if (
+ manifest.allowed_extensions &&
+ !manifest.allowed_extensions.includes(context.extension.id)
+ ) {
+ Cu.reportError(
+ `This extension does not have permission to use native manifest ${path}`
+ );
+ return null;
+ }
+
+ return manifest;
+ })
+ .catch(ex => {
+ if (ex instanceof OS.File.Error && ex.becauseNoSuchFile) {
+ if (logIfNotFound) {
+ Cu.reportError(
+ `Error reading native manifest file ${path}: file is referenced in the registry but does not exist`
+ );
+ }
+ return null;
+ }
+ throw ex;
+ });
+ },
+
+ async _tryPaths(type, name, dirs, context) {
+ for (let dir of dirs) {
+ let path = OS.Path.join(dir, TYPES[type], `${name}.json`);
+ let manifest = await this._tryPath(type, path, name, context, false);
+ if (manifest) {
+ return { path, manifest };
+ }
+ }
+ return null;
+ },
+
+ /**
+ * Search for a valid native manifest of the given type and name.
+ * The directories searched and rules for manifest validation are all
+ * detailed in the Native Manifests documentation.
+ *
+ * @param {string} type The type, one of: "pkcs11", "stdio" or "storage".
+ * @param {string} name The name of the manifest to search for.
+ * @param {object} context A context object as expected by Schemas.normalize.
+ * @returns {object} The contents of the validated manifest, or null if
+ * no valid manifest can be found for this type and name.
+ */
+ lookupManifest(type, name, context) {
+ return this.init().then(() => this._lookup(type, name, context));
+ },
+};