diff options
Diffstat (limited to '')
-rw-r--r-- | security/manager/pki/resources/content/device_manager.js | 433 |
1 files changed, 433 insertions, 0 deletions
diff --git a/security/manager/pki/resources/content/device_manager.js b/security/manager/pki/resources/content/device_manager.js new file mode 100644 index 0000000000..deb58d2ff3 --- /dev/null +++ b/security/manager/pki/resources/content/device_manager.js @@ -0,0 +1,433 @@ +/* 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 { XPCOMUtils } = ChromeUtils.importESModule( + "resource://gre/modules/XPCOMUtils.sys.mjs" +); + +var secmoddb; +var skip_enable_buttons = false; + +/* Do the initial load of all PKCS# modules and list them. */ +function LoadModules() { + secmoddb = Cc["@mozilla.org/security/pkcs11moduledb;1"].getService( + Ci.nsIPKCS11ModuleDB + ); + RefreshDeviceList(); +} + +async function doPrompt(l10n_id) { + let [msg] = await document.l10n.formatValues([{ id: l10n_id }]); + Services.prompt.alert(window, null, msg); +} + +async function doConfirm(l10n_id) { + let [msg] = await document.l10n.formatValues([{ id: l10n_id }]); + return Services.prompt.confirm(window, null, msg); +} + +function RefreshDeviceList() { + for (let module of secmoddb.listModules()) { + let slots = module.listSlots(); + AddModule(module, slots); + } + + // Set the text on the FIPS button. + SetFIPSButton(); +} + +function SetFIPSButton() { + var fipsButton = document.getElementById("fipsbutton"); + if (secmoddb.isFIPSEnabled) { + document.l10n.setAttributes(fipsButton, "devmgr-button-disable-fips"); + } else { + document.l10n.setAttributes(fipsButton, "devmgr-button-enable-fips"); + } + + var can_toggle = secmoddb.canToggleFIPS; + if (can_toggle) { + fipsButton.removeAttribute("disabled"); + } else { + fipsButton.setAttribute("disabled", "true"); + } +} + +/* Add a module to the tree. slots is the array of slots in the module, + * to be represented as children. + */ +function AddModule(module, slots) { + var tree = document.getElementById("device_list"); + var item = document.createXULElement("treeitem"); + var row = document.createXULElement("treerow"); + var cell = document.createXULElement("treecell"); + cell.setAttribute("label", module.name); + row.appendChild(cell); + item.appendChild(row); + var parent = document.createXULElement("treechildren"); + for (let slot of slots) { + var child_item = document.createXULElement("treeitem"); + var child_row = document.createXULElement("treerow"); + var child_cell = document.createXULElement("treecell"); + child_cell.setAttribute("label", slot.name); + child_row.appendChild(child_cell); + child_item.appendChild(child_row); + child_item.setAttribute("pk11kind", "slot"); + // 'slot' is an attribute on any HTML element, hence 'slotObject' instead. + child_item.slotObject = slot; + parent.appendChild(child_item); + } + item.appendChild(parent); + item.setAttribute("pk11kind", "module"); + item.module = module; + item.setAttribute("open", "true"); + item.setAttribute("container", "true"); + tree.appendChild(item); +} + +var selected_slot; +var selected_module; + +/* get the slot selected by the user (can only be one-at-a-time) */ +function getSelectedItem() { + let tree = document.getElementById("device_tree"); + if (tree.currentIndex < 0) { + return; + } + let item = tree.view.getItemAtIndex(tree.currentIndex); + selected_slot = null; + selected_module = null; + if (item) { + let kind = item.getAttribute("pk11kind"); + if (kind == "slot") { + selected_slot = item.slotObject; + } else { + // (kind == "module") + selected_module = item.module; + } + } +} + +function enableButtons() { + if (skip_enable_buttons) { + return; + } + + var login_toggle = "true"; + var logout_toggle = "true"; + var pw_toggle = "true"; + var unload_toggle = "true"; + getSelectedItem(); + if (selected_module) { + unload_toggle = "false"; + showModuleInfo(); + } else if (selected_slot) { + // here's the workaround - login functions are all with token, + // so grab the token type + var selected_token = selected_slot.getToken(); + if (selected_token != null) { + if (selected_token.needsLogin() || !selected_token.needsUserInit) { + pw_toggle = "false"; + if (selected_token.needsLogin()) { + if (selected_token.isLoggedIn()) { + logout_toggle = "false"; + } else { + login_toggle = "false"; + } + } + } + + if ( + !Services.policies.isAllowed("createMasterPassword") && + selected_token.isInternalKeyToken && + !selected_token.hasPassword + ) { + pw_toggle = "true"; + } + } + showSlotInfo(); + } + document + .getElementById("login_button") + .setAttribute("disabled", login_toggle); + document + .getElementById("logout_button") + .setAttribute("disabled", logout_toggle); + document + .getElementById("change_pw_button") + .setAttribute("disabled", pw_toggle); + document + .getElementById("unload_button") + .setAttribute("disabled", unload_toggle); +} + +// clear the display of information for the slot +function ClearInfoList() { + let infoList = document.getElementById("info_list"); + while (infoList.hasChildNodes()) { + infoList.firstChild.remove(); + } +} + +function ClearDeviceList() { + ClearInfoList(); + + skip_enable_buttons = true; + var tree = document.getElementById("device_tree"); + tree.view.selection.clearSelection(); + skip_enable_buttons = false; + + // Remove the existing listed modules so that a refresh doesn't display the + // module that just changed. + let deviceList = document.getElementById("device_list"); + while (deviceList.hasChildNodes()) { + deviceList.firstChild.remove(); + } +} + +// show a list of info about a slot +function showSlotInfo() { + var present = true; + ClearInfoList(); + switch (selected_slot.status) { + case Ci.nsIPKCS11Slot.SLOT_DISABLED: + AddInfoRow( + "devinfo-status", + { l10nID: "devinfo-status-disabled" }, + "tok_status" + ); + present = false; + break; + case Ci.nsIPKCS11Slot.SLOT_NOT_PRESENT: + AddInfoRow( + "devinfo-status", + { l10nID: "devinfo-status-not-present" }, + "tok_status" + ); + present = false; + break; + case Ci.nsIPKCS11Slot.SLOT_UNINITIALIZED: + AddInfoRow( + "devinfo-status", + { l10nID: "devinfo-status-uninitialized" }, + "tok_status" + ); + break; + case Ci.nsIPKCS11Slot.SLOT_NOT_LOGGED_IN: + AddInfoRow( + "devinfo-status", + { l10nID: "devinfo-status-not-logged-in" }, + "tok_status" + ); + break; + case Ci.nsIPKCS11Slot.SLOT_LOGGED_IN: + AddInfoRow( + "devinfo-status", + { l10nID: "devinfo-status-logged-in" }, + "tok_status" + ); + break; + case Ci.nsIPKCS11Slot.SLOT_READY: + AddInfoRow( + "devinfo-status", + { l10nID: "devinfo-status-ready" }, + "tok_status" + ); + break; + default: + return; + } + AddInfoRow("devinfo-desc", { label: selected_slot.desc }, "slot_desc"); + AddInfoRow("devinfo-man-id", { label: selected_slot.manID }, "slot_manID"); + AddInfoRow( + "devinfo-hwversion", + { label: selected_slot.HWVersion }, + "slot_hwv" + ); + AddInfoRow( + "devinfo-fwversion", + { label: selected_slot.FWVersion }, + "slot_fwv" + ); + if (present) { + showTokenInfo(); + } +} + +function showModuleInfo() { + ClearInfoList(); + AddInfoRow("devinfo-modname", { label: selected_module.name }, "module_name"); + AddInfoRow( + "devinfo-modpath", + { label: selected_module.libName }, + "module_path" + ); +} + +// add a row to the info list, as [col1 col2] (ex.: ["status" "logged in"]) +function AddInfoRow(l10nID, col2, cell_id) { + var tree = document.getElementById("info_list"); + var item = document.createXULElement("treeitem"); + var row = document.createXULElement("treerow"); + var cell1 = document.createXULElement("treecell"); + document.l10n.setAttributes(cell1, l10nID); + cell1.setAttribute("crop", "never"); + row.appendChild(cell1); + var cell2 = document.createXULElement("treecell"); + if (col2.l10nID) { + document.l10n.setAttributes(cell2, col2.l10nID); + } else { + cell2.setAttribute("label", col2.label); + } + cell2.setAttribute("crop", "never"); + cell2.setAttribute("id", cell_id); + row.appendChild(cell2); + item.appendChild(row); + tree.appendChild(item); +} + +// log in to a slot +function doLogin() { + getSelectedItem(); + // here's the workaround - login functions are with token + var selected_token = selected_slot.getToken(); + try { + selected_token.login(false); + var tok_status = document.getElementById("tok_status"); + if (selected_token.isLoggedIn()) { + document.l10n.setAttributes(tok_status, "devinfo-status-logged-in"); + } else { + document.l10n.setAttributes(tok_status, "devinfo-status-not-logged-in"); + } + } catch (e) { + doPrompt("login-failed"); + } + enableButtons(); +} + +// log out of a slot +function doLogout() { + getSelectedItem(); + // here's the workaround - login functions are with token + var selected_token = selected_slot.getToken(); + try { + selected_token.logoutAndDropAuthenticatedResources(); + var tok_status = document.getElementById("tok_status"); + if (selected_token.isLoggedIn()) { + document.l10n.setAttributes(tok_status, "devinfo-status-logged-in"); + } else { + document.l10n.setAttributes(tok_status, "devinfo-status-not-logged-in"); + } + } catch (e) {} + enableButtons(); +} + +// load a new device +function doLoad() { + window.browsingContext.topChromeWindow.open( + "load_device.xhtml", + "loaddevice", + "chrome,centerscreen,modal" + ); + ClearDeviceList(); + RefreshDeviceList(); +} + +async function deleteSelected() { + getSelectedItem(); + if (selected_module && (await doConfirm("del-module-warning"))) { + try { + secmoddb.deleteModule(selected_module.name); + } catch (e) { + doPrompt("del-module-error"); + return false; + } + selected_module = null; + return true; + } + return false; +} + +async function doUnload() { + if (await deleteSelected()) { + ClearDeviceList(); + RefreshDeviceList(); + } +} + +function changePassword() { + getSelectedItem(); + let params = Cc["@mozilla.org/embedcomp/dialogparam;1"].createInstance( + Ci.nsIDialogParamBlock + ); + let objects = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray); + objects.appendElement(selected_slot.getToken()); + params.objects = objects; + window.browsingContext.topChromeWindow.openDialog( + "changepassword.xhtml", + "", + "chrome,centerscreen,modal", + params + ); + showSlotInfo(); + enableButtons(); +} + +// ------------------------------------- Old code + +function showTokenInfo() { + var selected_token = selected_slot.getToken(); + AddInfoRow("devinfo-label", { label: selected_token.tokenName }, "tok_label"); + AddInfoRow( + "devinfo-man-id", + { label: selected_token.tokenManID }, + "tok_manID" + ); + AddInfoRow( + "devinfo-serialnum", + { label: selected_token.tokenSerialNumber }, + "tok_sNum" + ); + AddInfoRow( + "devinfo-hwversion", + { label: selected_token.tokenHWVersion }, + "tok_hwv" + ); + AddInfoRow( + "devinfo-fwversion", + { label: selected_token.tokenFWVersion }, + "tok_fwv" + ); +} + +function toggleFIPS() { + if (!secmoddb.isFIPSEnabled) { + // A restriction of FIPS mode is, the password must be set + // In FIPS mode the password must be non-empty. + // This is different from what we allow in NON-Fips mode. + + var tokendb = Cc["@mozilla.org/security/pk11tokendb;1"].getService( + Ci.nsIPK11TokenDB + ); + var internal_token = tokendb.getInternalKeyToken(); // nsIPK11Token + if (!internal_token.hasPassword) { + // Token has either no or an empty password. + doPrompt("fips-nonempty-primary-password-required"); + return; + } + } + + try { + secmoddb.toggleFIPSMode(); + } catch (e) { + doPrompt("unable-to-toggle-fips"); + return; + } + + // Remove the existing listed modules so that a refresh doesn't display the + // module that just changed. + ClearDeviceList(); + + RefreshDeviceList(); +} |