From 2aa4a82499d4becd2284cdb482213d541b8804dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 28 Apr 2024 16:29:10 +0200 Subject: Adding upstream version 86.0.1. Signed-off-by: Daniel Baumann --- toolkit/components/extensions/NativeManifests.jsm | 182 ++++++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 toolkit/components/extensions/NativeManifests.jsm (limited to 'toolkit/components/extensions/NativeManifests.jsm') 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)); + }, +}; -- cgit v1.2.3