diff options
Diffstat (limited to 'toolkit/components/passwordmgr/test/test_master_password.html')
-rw-r--r-- | toolkit/components/passwordmgr/test/test_master_password.html | 308 |
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> + |