fune/browser/components/extensions/parent/ext-pkcs11.js

166 lines
6.1 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",
OS: "resource://gre/modules/osfile.jsm",
});
XPCOMUtils.defineLazyServiceGetter(
this,
"pkcs11db",
"@mozilla.org/security/pkcs11moduledb;1",
"nsIPKCS11ModuleDB"
);
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) {
if (AppConstants.platform === "win") {
hostInfo.manifest.path = OS.Path.join(
OS.Path.dirname(hostInfo.path),
hostInfo.manifest.path
);
}
let manifestLib = OS.Path.basename(hostInfo.manifest.path);
if (AppConstants.platform !== "linux") {
manifestLib = manifestLib.toLowerCase(manifestLib);
}
if (
manifestLib !== ctypes.libraryName("nssckbi") &&
manifestLib !== ctypes.libraryName("osclientcerts")
) {
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;
},
},
};
}
};