// Any copyright is dedicated to the Public Domain. // http://creativecommons.org/publicdomain/zero/1.0/ "use strict"; // Tests that the UI for setting the password on a to be exported PKCS #12 file: // 1. Correctly requires the password to be typed in twice as confirmation. // 2. Calculates and displays the strength of said password. /** * @typedef TestCase * @type {object} * @property {string} name * The name of the test case for display purposes. * @property {string} password1 * The password to enter into the first password textbox. * @property {string} password2 * The password to enter into the second password textbox. * @property {string} strength * The expected strength of the password in the range [0, 100]. */ /** * A list of test cases representing various inputs to the password textboxes. * * @type {TestCase[]} */ const TEST_CASES = [ { name: "empty", password1: "", password2: "", strength: "0" }, { name: "match-weak", password1: "foo", password2: "foo", strength: "10" }, { name: "match-medium", password1: "foo123", password2: "foo123", strength: "60", }, { name: "match-strong", password1: "fooBARBAZ 1234567890`~!@#$%^&*()-_=+{[}]|\\:;'\",<.>/?一二三", password2: "fooBARBAZ 1234567890`~!@#$%^&*()-_=+{[}]|\\:;'\",<.>/?一二三", strength: "100", }, { name: "mismatch-weak", password1: "foo", password2: "bar", strength: "10" }, { name: "mismatch-medium", password1: "foo123", password2: "bar", strength: "60", }, { name: "mismatch-strong", password1: "fooBARBAZ 1234567890`~!@#$%^&*()-_=+{[}]|\\:;'\",<.>/?一二三", password2: "bar", strength: "100", }, ]; /** * Opens the dialog shown to set the password on a PKCS #12 file being exported. * * @returns {Promise} * A promise that resolves when the dialog has finished loading, with * an array consisting of: * 1. The window of the opened dialog. * 2. The return value nsIWritablePropertyBag2 passed to the dialog. */ function openSetP12PasswordDialog() { let returnVals = Cc["@mozilla.org/hash-property-bag;1"].createInstance( Ci.nsIWritablePropertyBag2 ); let win = window.openDialog( "chrome://pippki/content/setp12password.xhtml", "", "", returnVals ); return new Promise((resolve, reject) => { win.addEventListener( "load", function () { executeSoon(() => resolve([win, returnVals])); }, { once: true } ); }); } // Tests that the first password textbox is the element that is initially // focused. add_task(async function testFocus() { let [win] = await openSetP12PasswordDialog(); Assert.equal( win.document.activeElement, win.document.getElementById("pw1"), "First password textbox should have focus" ); await BrowserTestUtils.closeWindow(win); }); // Tests that the password strength algorithm used is reasonable, and that the // Accept button is only enabled if the two passwords match. add_task(async function testPasswordStrengthAndEquality() { let [win] = await openSetP12PasswordDialog(); let password1Textbox = win.document.getElementById("pw1"); let password2Textbox = win.document.getElementById("pw2"); let strengthProgressBar = win.document.getElementById("pwmeter"); for (let testCase of TEST_CASES) { password1Textbox.value = testCase.password1; password2Textbox.value = testCase.password2; // Setting the value of the password textboxes via |.value| apparently // doesn't cause the oninput handlers to be called, so we do it here. password1Textbox.oninput(); password2Textbox.oninput(); Assert.equal( win.document.getElementById("setp12password").getButton("accept") .disabled, password1Textbox.value != password2Textbox.value, "Actual and expected accept button disable state should " + `match for ${testCase.name}` ); Assert.equal( strengthProgressBar.value, testCase.strength, `Actual and expected strength value should match for ${testCase.name}` ); } await BrowserTestUtils.closeWindow(win); }); // Test that the right values are returned when the dialog is accepted. add_task(async function testAcceptDialogReturnValues() { let [win, retVals] = await openSetP12PasswordDialog(); const password = "fooBAR 1234567890`~!@#$%^&*()-_=+{[}]|\\:;'\",<.>/?一二三"; win.document.getElementById("pw1").value = password; win.document.getElementById("pw2").value = password; info("Accepting dialog"); win.document.getElementById("setp12password").acceptDialog(); await BrowserTestUtils.windowClosed(win); Assert.ok( retVals.get("confirmedPassword"), "Return value should signal user confirmed a password" ); Assert.equal( retVals.get("password"), password, "Actual and expected password should match" ); }); // Test that the right values are returned when the dialog is canceled. add_task(async function testCancelDialogReturnValues() { let [win, retVals] = await openSetP12PasswordDialog(); info("Canceling dialog"); win.document.getElementById("setp12password").cancelDialog(); await BrowserTestUtils.windowClosed(win); Assert.ok( !retVals.get("confirmedPassword"), "Return value should signal user didn't confirm a password" ); });