mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-11-08 20:28:42 +02:00
PathUtils.filename throws if the path is not an absolute path, which was likely not the case with the OS.Path.basename call used previously. This internal change of behavior shouldn't be triggering any issue on Windows, where the hostInfo.manifest.path seems to be always normalized into an absolute path (by computing it as relative to the hostInfo.manifest if it wasn't already an absolute path), but it makes browser.pkcs11.isModuleInstalled to regress on Linux (and maybe also on MacOS if the pkcs11 manifest files include only the library name and not its full path, as it seems to be the case for the Belgium eID pkcs11 manifest packaged for Linux). The result of PathUtils.filename is expected to only include the basename of the file (without the full dir path and the file extension) and so to fix the regression being triggered on non-windows platform we could use a fake absolute url to get the expected result using PathUtils.filename as is. Differential Revision: https://phabricator.services.mozilla.com/D141097
187 lines
7.2 KiB
JavaScript
187 lines
7.2 KiB
JavaScript
/* 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";
|
|
|
|
XPCOMUtils.defineLazyModuleGetters(this, {
|
|
ctypes: "resource://gre/modules/ctypes.jsm",
|
|
NativeManifests: "resource://gre/modules/NativeManifests.jsm",
|
|
});
|
|
|
|
XPCOMUtils.defineLazyServiceGetter(
|
|
this,
|
|
"pkcs11db",
|
|
"@mozilla.org/security/pkcs11moduledb;1",
|
|
"nsIPKCS11ModuleDB"
|
|
);
|
|
|
|
// eslint-disable-next-line mozilla/reject-importGlobalProperties
|
|
Cu.importGlobalProperties(["PathUtils"]);
|
|
|
|
var { DefaultMap } = ExtensionUtils;
|
|
|
|
const findModuleByPath = function(path) {
|
|
for (let module of pkcs11db.listModules()) {
|
|
if (module && module.libName === path) {
|
|
return module;
|
|
}
|
|
}
|
|
return null;
|
|
};
|
|
|
|
this.pkcs11 = class extends ExtensionAPI {
|
|
getAPI(context) {
|
|
let manifestCache = new DefaultMap(async name => {
|
|
let hostInfo = await NativeManifests.lookupManifest(
|
|
"pkcs11",
|
|
name,
|
|
context
|
|
);
|
|
if (hostInfo) {
|
|
// We don't normalize the absolute path below because
|
|
// `Path.normalize` throws when the target file doesn't
|
|
// exist, and that might be the case on non Windows
|
|
// builds.
|
|
let absolutePath = PathUtils.isAbsolute(hostInfo.manifest.path)
|
|
? hostInfo.manifest.path
|
|
: PathUtils.joinRelative(
|
|
PathUtils.parent(hostInfo.path),
|
|
hostInfo.manifest.path
|
|
);
|
|
|
|
if (AppConstants.platform === "win") {
|
|
// On Windows, `hostInfo.manifest.path` is expected to be a normalized
|
|
// absolute path. On other platforms, this path may be relative but we
|
|
// cannot use `PathUtils.normalize()` on non-absolute paths.
|
|
absolutePath = PathUtils.normalize(absolutePath);
|
|
hostInfo.manifest.path = absolutePath;
|
|
}
|
|
|
|
// PathUtils.filename throws if the path is not an absolute path.
|
|
// The result is expected to be the basename of the file (without
|
|
// the dir path and the extension) so it is fine to use an absolute
|
|
// path that may not be normalized (non-Windows platforms).
|
|
let manifestLib = PathUtils.filename(absolutePath);
|
|
|
|
if (AppConstants.platform !== "linux") {
|
|
manifestLib = manifestLib.toLowerCase(manifestLib);
|
|
}
|
|
if (
|
|
manifestLib !== ctypes.libraryName("nssckbi") &&
|
|
manifestLib !== ctypes.libraryName("osclientcerts") &&
|
|
manifestLib !== ctypes.libraryName("ipcclientcerts")
|
|
) {
|
|
return hostInfo.manifest;
|
|
}
|
|
}
|
|
return Promise.reject({ message: `No such PKCS#11 module ${name}` });
|
|
});
|
|
return {
|
|
pkcs11: {
|
|
/**
|
|
* Verify whether a given PKCS#11 module is installed.
|
|
*
|
|
* @param {string} name The name of the module, as specified in
|
|
* the manifest file.
|
|
* @returns {Promise} A Promise that resolves to true if the package
|
|
* is installed, or false if it is not. May be
|
|
* rejected if the module could not be found.
|
|
*/
|
|
async isModuleInstalled(name) {
|
|
let manifest = await manifestCache.get(name);
|
|
return findModuleByPath(manifest.path) !== null;
|
|
},
|
|
/**
|
|
* Install a PKCS#11 module
|
|
*
|
|
* @param {string} name The name of the module, as specified in
|
|
* the manifest file.
|
|
* @param {integer} [flags = 0] Any flags to be passed on to the
|
|
* nsIPKCS11ModuleDB.addModule method
|
|
* @returns {Promise} When the Promise resolves, the module will have
|
|
* been installed. When it is rejected, the module
|
|
* either is already installed or could not be
|
|
* installed for some reason.
|
|
*/
|
|
async installModule(name, flags = 0) {
|
|
let manifest = await manifestCache.get(name);
|
|
if (!manifest.description) {
|
|
return Promise.reject({
|
|
message: `The description field in the manifest for PKCS#11 module ${name} must have a value`,
|
|
});
|
|
}
|
|
pkcs11db.addModule(manifest.description, manifest.path, flags, 0);
|
|
},
|
|
/**
|
|
* Uninstall a PKCS#11 module
|
|
*
|
|
* @param {string} name The name of the module, as specified in
|
|
* the manifest file.
|
|
* @returns {Promise}. When the Promise resolves, the module will have
|
|
* been uninstalled. When it is rejected, the
|
|
* module either was not installed or could not be
|
|
* uninstalled for some reason.
|
|
*/
|
|
async uninstallModule(name) {
|
|
let manifest = await manifestCache.get(name);
|
|
let module = findModuleByPath(manifest.path);
|
|
if (!module) {
|
|
return Promise.reject({
|
|
message: `The PKCS#11 module ${name} is not loaded`,
|
|
});
|
|
}
|
|
pkcs11db.deleteModule(module.name);
|
|
},
|
|
/**
|
|
* Get a list of slots for a given PKCS#11 module, with
|
|
* information on the token (if any) in the slot.
|
|
*
|
|
* The PKCS#11 standard defines slots as an abstract concept
|
|
* that may or may not have at most one token. In practice, when
|
|
* using PKCS#11 for smartcards (the most likely use case of
|
|
* PKCS#11 for Firefox), a slot corresponds to a cardreader, and
|
|
* a token corresponds to a card.
|
|
*
|
|
* @param {string} name The name of the PKCS#11 module, as
|
|
* specified in the manifest file.
|
|
* @returns {Promise} A promise that resolves to an array of objects
|
|
* with two properties. The `name` object contains
|
|
* the name of the slot; the `token` object is null
|
|
* if there is no token in the slot, or is an object
|
|
* describing various properties of the token if
|
|
* there is.
|
|
*/
|
|
async getModuleSlots(name) {
|
|
let manifest = await manifestCache.get(name);
|
|
let module = findModuleByPath(manifest.path);
|
|
if (!module) {
|
|
return Promise.reject({
|
|
message: `The module ${name} is not installed`,
|
|
});
|
|
}
|
|
let rv = [];
|
|
for (let slot of module.listSlots()) {
|
|
let token = slot.getToken();
|
|
let slotobj = {
|
|
name: slot.name,
|
|
token: null,
|
|
};
|
|
if (slot.status != 1 /* SLOT_NOT_PRESENT */) {
|
|
slotobj.token = {
|
|
name: token.tokenName,
|
|
manufacturer: token.tokenManID,
|
|
HWVersion: token.tokenHWVersion,
|
|
FWVersion: token.tokenFWVersion,
|
|
serial: token.tokenSerialNumber,
|
|
isLoggedIn: token.isLoggedIn(),
|
|
};
|
|
}
|
|
rv.push(slotobj);
|
|
}
|
|
return rv;
|
|
},
|
|
},
|
|
};
|
|
}
|
|
};
|