summaryrefslogtreecommitdiffstats
path: root/security/manager/ssl/tests/mochitest/browser/browser_exportP12_passwordUI.js
blob: 8e6af27cbb5f7969ebf7d9eceb16c64ee1fd04f5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
// 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"
  );
});