browser_exportP12_passwordUI.js (5479B)
1 // Any copyright is dedicated to the Public Domain. 2 // http://creativecommons.org/publicdomain/zero/1.0/ 3 "use strict"; 4 5 // Tests that the UI for setting the password on a to be exported PKCS #12 file: 6 // 1. Correctly requires the password to be typed in twice as confirmation. 7 // 2. Calculates and displays the strength of said password. 8 9 /** 10 * @typedef TestCase 11 * @type {object} 12 * @property {string} name 13 * The name of the test case for display purposes. 14 * @property {string} password1 15 * The password to enter into the first password textbox. 16 * @property {string} password2 17 * The password to enter into the second password textbox. 18 * @property {string} strength 19 * The expected strength of the password in the range [0, 100]. 20 */ 21 22 /** 23 * A list of test cases representing various inputs to the password textboxes. 24 * 25 * @type {TestCase[]} 26 */ 27 const TEST_CASES = [ 28 { name: "empty", password1: "", password2: "", strength: "0" }, 29 { name: "match-weak", password1: "foo", password2: "foo", strength: "10" }, 30 { 31 name: "match-medium", 32 password1: "foo123", 33 password2: "foo123", 34 strength: "60", 35 }, 36 { 37 name: "match-strong", 38 password1: "fooBARBAZ 1234567890`~!@#$%^&*()-_=+{[}]|\\:;'\",<.>/?一二三", 39 password2: "fooBARBAZ 1234567890`~!@#$%^&*()-_=+{[}]|\\:;'\",<.>/?一二三", 40 strength: "100", 41 }, 42 { name: "mismatch-weak", password1: "foo", password2: "bar", strength: "10" }, 43 { 44 name: "mismatch-medium", 45 password1: "foo123", 46 password2: "bar", 47 strength: "60", 48 }, 49 { 50 name: "mismatch-strong", 51 password1: "fooBARBAZ 1234567890`~!@#$%^&*()-_=+{[}]|\\:;'\",<.>/?一二三", 52 password2: "bar", 53 strength: "100", 54 }, 55 ]; 56 57 /** 58 * Opens the dialog shown to set the password on a PKCS #12 file being exported. 59 * 60 * @returns {Promise} 61 * A promise that resolves when the dialog has finished loading, with 62 * an array consisting of: 63 * 1. The window of the opened dialog. 64 * 2. The return value nsIWritablePropertyBag2 passed to the dialog. 65 */ 66 function openSetP12PasswordDialog() { 67 let returnVals = Cc["@mozilla.org/hash-property-bag;1"].createInstance( 68 Ci.nsIWritablePropertyBag2 69 ); 70 let win = window.openDialog( 71 "chrome://pippki/content/setp12password.xhtml", 72 "", 73 "", 74 returnVals 75 ); 76 return new Promise(resolve => { 77 win.addEventListener( 78 "load", 79 function () { 80 executeSoon(() => resolve([win, returnVals])); 81 }, 82 { once: true } 83 ); 84 }); 85 } 86 87 // Tests that the first password textbox is the element that is initially 88 // focused. 89 add_task(async function testFocus() { 90 let [win] = await openSetP12PasswordDialog(); 91 Assert.equal( 92 win.document.activeElement, 93 win.document.getElementById("pw1"), 94 "First password textbox should have focus" 95 ); 96 await BrowserTestUtils.closeWindow(win); 97 }); 98 99 // Tests that the password strength algorithm used is reasonable, and that the 100 // Accept button is only enabled if the two passwords match. 101 add_task(async function testPasswordStrengthAndEquality() { 102 let [win] = await openSetP12PasswordDialog(); 103 let password1Textbox = win.document.getElementById("pw1"); 104 let password2Textbox = win.document.getElementById("pw2"); 105 let strengthProgressBar = win.document.getElementById("pwmeter"); 106 107 for (let testCase of TEST_CASES) { 108 password1Textbox.value = testCase.password1; 109 password2Textbox.value = testCase.password2; 110 // Setting the value of the password textboxes via |.value| apparently 111 // doesn't cause the oninput handlers to be called, so we do it here. 112 password1Textbox.dispatchEvent(new Event("input", { bubbles: true })); 113 password2Textbox.dispatchEvent(new Event("input", { bubbles: true })); 114 115 Assert.equal( 116 win.document.getElementById("setp12password").getButton("accept") 117 .disabled, 118 password1Textbox.value != password2Textbox.value, 119 "Actual and expected accept button disable state should " + 120 `match for ${testCase.name}` 121 ); 122 Assert.equal( 123 strengthProgressBar.value, 124 testCase.strength, 125 `Actual and expected strength value should match for ${testCase.name}` 126 ); 127 } 128 129 await BrowserTestUtils.closeWindow(win); 130 }); 131 132 // Test that the right values are returned when the dialog is accepted. 133 add_task(async function testAcceptDialogReturnValues() { 134 let [win, retVals] = await openSetP12PasswordDialog(); 135 const password = "fooBAR 1234567890`~!@#$%^&*()-_=+{[}]|\\:;'\",<.>/?一二三"; 136 win.document.getElementById("pw1").value = password; 137 win.document.getElementById("pw2").value = password; 138 info("Accepting dialog"); 139 win.document.getElementById("setp12password").acceptDialog(); 140 await BrowserTestUtils.windowClosed(win); 141 142 Assert.ok( 143 retVals.get("confirmedPassword"), 144 "Return value should signal user confirmed a password" 145 ); 146 Assert.equal( 147 retVals.get("password"), 148 password, 149 "Actual and expected password should match" 150 ); 151 }); 152 153 // Test that the right values are returned when the dialog is canceled. 154 add_task(async function testCancelDialogReturnValues() { 155 let [win, retVals] = await openSetP12PasswordDialog(); 156 info("Canceling dialog"); 157 win.document.getElementById("setp12password").cancelDialog(); 158 await BrowserTestUtils.windowClosed(win); 159 160 Assert.ok( 161 !retVals.get("confirmedPassword"), 162 "Return value should signal user didn't confirm a password" 163 ); 164 });