summaryrefslogtreecommitdiffstats
path: root/toolkit/components/passwordmgr/test/test_master_password.html
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/passwordmgr/test/test_master_password.html')
-rw-r--r--toolkit/components/passwordmgr/test/test_master_password.html308
1 files changed, 308 insertions, 0 deletions
diff --git a/toolkit/components/passwordmgr/test/test_master_password.html b/toolkit/components/passwordmgr/test/test_master_password.html
new file mode 100644
index 000000000..c8884811f
--- /dev/null
+++ b/toolkit/components/passwordmgr/test/test_master_password.html
@@ -0,0 +1,308 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test for master password</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="pwmgr_common.js"></script>
+ <script type="text/javascript" src="prompt_common.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+Login Manager test: master password.
+<script>
+"use strict";
+
+commonInit();
+SimpleTest.waitForExplicitFinish();
+SimpleTest.requestFlakyTimeout("untriaged");
+
+var pwmgr = SpecialPowers.Cc["@mozilla.org/login-manager;1"]
+ .getService(SpecialPowers.Ci.nsILoginManager);
+var pwcrypt = SpecialPowers.Cc["@mozilla.org/login-manager/crypto/SDR;1"]
+ .getService(Ci.nsILoginManagerCrypto);
+
+var nsLoginInfo = new SpecialPowers.wrap(SpecialPowers.Components).Constructor("@mozilla.org/login-manager/loginInfo;1", Ci.nsILoginInfo);
+
+var exampleCom = "http://example.com/tests/toolkit/components/passwordmgr/test/";
+var exampleOrg = "http://example.org/tests/toolkit/components/passwordmgr/test/";
+
+var login1 = new nsLoginInfo();
+var login2 = new nsLoginInfo();
+
+login1.init("http://example.com", "http://example.com", null,
+ "user1", "pass1", "uname", "pword");
+login2.init("http://example.org", "http://example.org", null,
+ "user2", "pass2", "uname", "pword");
+
+pwmgr.addLogin(login1);
+pwmgr.addLogin(login2);
+</script>
+
+<p id="display"></p>
+
+<div id="content" style="display: none">
+<iframe id="iframe1"></iframe>
+<iframe id="iframe2"></iframe>
+</div>
+
+<pre id="test">
+<script class="testbody" type="text/javascript">
+var testNum = 1;
+var iframe1 = document.getElementById("iframe1");
+var iframe2 = document.getElementById("iframe2");
+
+// A couple of tests have to wait until the password manager gets around to
+// filling in the password in the subtest (after we dismiss the master
+// password dialog). In order to accomplish this, the test waits for an event
+// and then posts a message back up to us telling us to continue.
+var continuation = null;
+addEventListener("message", () => {
+ if (continuation) {
+ var c = continuation;
+ continuation = null;
+ c();
+ }
+});
+
+/*
+ * handleDialog
+ *
+ * Invoked a short period of time after calling startCallbackTimer(), and
+ * allows testing the actual auth dialog while it's being displayed. Tests
+ * should call startCallbackTimer() each time the auth dialog is expected (the
+ * timer is a one-shot).
+ */
+function handleDialog(doc, testNumber) {
+ ok(true, "handleDialog running for test " + testNumber);
+
+ var clickOK = true;
+ var doNothing = false;
+ var passfield = doc.getElementById("password1Textbox");
+ var dialog = doc.getElementById("commonDialog");
+
+ switch (testNumber) {
+ case 1:
+ is(passfield.getAttribute("value"), "", "Checking empty prompt");
+ passfield.setAttribute("value", masterPassword);
+ is(passfield.getAttribute("value"), masterPassword, "Checking filled prompt");
+ break;
+
+ case 2:
+ clickOK = false;
+ break;
+
+ case 3:
+ is(passfield.getAttribute("value"), "", "Checking empty prompt");
+ passfield.setAttribute("value", masterPassword);
+ break;
+
+ case 4:
+ doNothing = true;
+ break;
+
+ case 5:
+ is(passfield.getAttribute("value"), "", "Checking empty prompt");
+ passfield.setAttribute("value", masterPassword);
+ break;
+
+ default:
+ ok(false, "Uhh, unhandled switch for testNum #" + testNumber);
+ break;
+ }
+
+ didDialog = true;
+
+ if (!doNothing) {
+ SpecialPowers.addObserver(outerWindowObserver, "outer-window-destroyed", false);
+ if (clickOK)
+ dialog.acceptDialog();
+ else
+ dialog.cancelDialog();
+ }
+
+ ok(true, "handleDialog done for test " + testNumber);
+
+ if (testNumber == 4)
+ checkTest4A();
+}
+
+var outerWindowObserver = {
+ observe: function(id) {
+ SpecialPowers.removeObserver(outerWindowObserver, "outer-window-destroyed");
+ var func;
+ if (testNum == 1)
+ func = startTest2;
+ else if (testNum == 2)
+ func = startTest3;
+
+ // For tests 3 and 4C, we use the 'continuation' mechanism, described
+ // above.
+ if (func)
+ setTimeout(func, 300);
+ }
+};
+
+
+function startTest1() {
+ ok(pwcrypt.isLoggedIn, "should be initially logged in (no MP)");
+ enableMasterPassword();
+ ok(!pwcrypt.isLoggedIn, "should be logged out after setting MP");
+
+ // --- Test 1 ---
+ // Trigger a MP prompt via the API
+ startCallbackTimer();
+ var logins = pwmgr.getAllLogins();
+ ok(didDialog, "handleDialog was invoked");
+ is(logins.length, 3, "expected number of logins");
+
+ ok(pwcrypt.isLoggedIn, "should be logged in after MP prompt");
+ logoutMasterPassword();
+ ok(!pwcrypt.isLoggedIn, "should be logged out");
+}
+
+function startTest2() {
+ // Try again but click cancel.
+ testNum++;
+ startCallbackTimer();
+ var failedAsExpected = false;
+ logins = null;
+ try {
+ logins = pwmgr.getAllLogins();
+ } catch (e) { failedAsExpected = true; }
+ ok(didDialog, "handleDialog was invoked");
+ ok(failedAsExpected, "getAllLogins should have thrown");
+ is(logins, null, "shouldn't have gotten logins");
+ ok(!pwcrypt.isLoggedIn, "should still be logged out");
+}
+
+function startTest3() {
+ // Load a single iframe to trigger a MP
+ testNum++;
+ iframe1.src = exampleCom + "subtst_master_pass.html";
+ continuation = checkTest3;
+ startCallbackTimer();
+}
+
+function checkTest3() {
+ ok(true, "checkTest3 starting");
+ ok(didDialog, "handleDialog was invoked");
+
+ // check contents of iframe1 fields
+ var u = SpecialPowers.wrap(iframe1).contentDocument.getElementById("userfield");
+ var p = SpecialPowers.wrap(iframe1).contentDocument.getElementById("passfield");
+ is(u.value, "user1", "checking expected user to have been filled in");
+ is(p.value, "pass1", "checking expected pass to have been filled in");
+
+ ok(pwcrypt.isLoggedIn, "should be logged in");
+ logoutMasterPassword();
+ ok(!pwcrypt.isLoggedIn, "should be logged out");
+
+
+ // --- Test 4 ---
+ // first part of loading 2 MP-triggering iframes
+ testNum++;
+ iframe1.src = exampleOrg + "subtst_master_pass.html";
+ // start the callback, but we'll not enter the MP, just call checkTest4A
+ startCallbackTimer();
+}
+
+function checkTest4A() {
+ ok(true, "checkTest4A starting");
+ ok(didDialog, "handleDialog was invoked");
+
+ // check contents of iframe1 fields
+ var u = SpecialPowers.wrap(iframe1).contentDocument.getElementById("userfield");
+ var p = SpecialPowers.wrap(iframe1).contentDocument.getElementById("passfield");
+ is(u.value, "", "checking expected empty user");
+ is(p.value, "", "checking expected empty pass");
+
+
+ ok(!pwcrypt.isLoggedIn, "should be logged out");
+
+ // XXX check that there's 1 MP window open
+
+ // Load another iframe with a login form
+ // This should detect that there's already a pending MP prompt, and not
+ // put up a second one. The load event will fire (note that when pwmgr is
+ // driven from DOMContentLoaded, if that blocks due to prompting for a MP,
+ // the load even will also be blocked until the prompt is dismissed).
+ iframe2.onload = checkTest4B_delay;
+ iframe2.src = exampleCom + "subtst_master_pass.html";
+}
+
+function checkTest4B_delay() {
+ // Testing a negative, wait a little to give the login manager a chance to
+ // (incorrectly) fill in the form. Note, we cannot use setTimeout()
+ // here because the modal window suspends all window timers. Instead we
+ // must use a chrome script to use nsITimer directly.
+ let chromeURL = SimpleTest.getTestFileURL("chrome_timeout.js");
+ let script = SpecialPowers.loadChromeScript(chromeURL);
+ script.addMessageListener('ready', _ => {
+ script.sendAsyncMessage('setTimeout', { delay: 500 });
+ });
+ script.addMessageListener('timeout', checkTest4B);
+}
+
+function checkTest4B() {
+ ok(true, "checkTest4B starting");
+ // iframe2 should load without having triggered a MP prompt (because one
+ // is already waiting)
+
+ // check contents of iframe2 fields
+ var u = SpecialPowers.wrap(iframe2).contentDocument.getElementById("userfield");
+ var p = SpecialPowers.wrap(iframe2).contentDocument.getElementById("passfield");
+ is(u.value, "", "checking expected empty user");
+ is(p.value, "", "checking expected empty pass");
+
+ // XXX check that there's 1 MP window open
+ ok(!pwcrypt.isLoggedIn, "should be logged out");
+
+ continuation = checkTest4C;
+
+ // Ok, now enter the MP. The MP prompt is already up, but we'll just reuse startCallBackTimer.
+ // --- Test 5 ---
+ testNum++;
+ startCallbackTimer();
+}
+
+function checkTest4C() {
+ ok(true, "checkTest4C starting");
+ ok(didDialog, "handleDialog was invoked");
+
+ // We shouldn't have to worry about iframe1's load event racing with
+ // filling of iframe2's data. We notify observers synchronously, so
+ // iframe2's observer will process iframe2 before iframe1 even finishes
+ // processing the form (which is blocking its load event).
+ ok(pwcrypt.isLoggedIn, "should be logged in");
+
+ // check contents of iframe1 fields
+ var u = SpecialPowers.wrap(iframe1).contentDocument.getElementById("userfield");
+ var p = SpecialPowers.wrap(iframe1).contentDocument.getElementById("passfield");
+ is(u.value, "user2", "checking expected user to have been filled in");
+ is(p.value, "pass2", "checking expected pass to have been filled in");
+
+ // check contents of iframe2 fields
+ u = SpecialPowers.wrap(iframe2).contentDocument.getElementById("userfield");
+ p = SpecialPowers.wrap(iframe2).contentDocument.getElementById("passfield");
+ is(u.value, "user1", "checking expected user to have been filled in");
+ is(p.value, "pass1", "checking expected pass to have been filled in");
+
+ SimpleTest.finish();
+}
+
+// XXX do a test5ABC with clicking cancel?
+
+SimpleTest.registerCleanupFunction(function finishTest() {
+ disableMasterPassword();
+
+ pwmgr.removeLogin(login1);
+ pwmgr.removeLogin(login2);
+});
+
+window.addEventListener("runTests", startTest1);
+</script>
+</pre>
+</body>
+</html>
+