summaryrefslogtreecommitdiffstats
path: root/toolkit/components/passwordmgr/test/browser/browser_doorhanger_crossframe.js
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
commit6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch)
treea68f146d7fa01f0134297619fbe7e33db084e0aa /toolkit/components/passwordmgr/test/browser/browser_doorhanger_crossframe.js
parentInitial commit. (diff)
downloadthunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.tar.xz
thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.zip
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/components/passwordmgr/test/browser/browser_doorhanger_crossframe.js')
-rw-r--r--toolkit/components/passwordmgr/test/browser/browser_doorhanger_crossframe.js236
1 files changed, 236 insertions, 0 deletions
diff --git a/toolkit/components/passwordmgr/test/browser/browser_doorhanger_crossframe.js b/toolkit/components/passwordmgr/test/browser/browser_doorhanger_crossframe.js
new file mode 100644
index 0000000000..8c4770d510
--- /dev/null
+++ b/toolkit/components/passwordmgr/test/browser/browser_doorhanger_crossframe.js
@@ -0,0 +1,236 @@
+const OUTER_URL =
+ "https://test1.example.com:443" + DIRECTORY_PATH + "form_crossframe.html";
+
+requestLongerTimeout(2);
+
+async function acceptPasswordSave() {
+ let notif = await getCaptureDoorhangerThatMayOpen("password-save");
+ let promiseNewSavedPassword = TestUtils.topicObserved(
+ "LoginStats:NewSavedPassword",
+ (subject, data) => subject == gBrowser.selectedBrowser
+ );
+ clickDoorhangerButton(notif, REMEMBER_BUTTON);
+ await promiseNewSavedPassword;
+}
+
+function checkFormFields(browsingContext, prefix, username, password) {
+ return SpecialPowers.spawn(
+ browsingContext,
+ [prefix, username, password],
+ (formPrefix, expectedUsername, expectedPassword) => {
+ let doc = content.document;
+ Assert.equal(
+ doc.getElementById(formPrefix + "-username").value,
+ expectedUsername,
+ "username matches"
+ );
+ Assert.equal(
+ doc.getElementById(formPrefix + "-password").value,
+ expectedPassword,
+ "password matches"
+ );
+ }
+ );
+}
+
+function listenForNotifications(count, expectedFormOrigin) {
+ return new Promise(resolve => {
+ let notifications = [];
+ LoginManagerParent.setListenerForTests((msg, data) => {
+ if (msg == "FormProcessed") {
+ notifications.push("FormProcessed: " + data.browsingContext.id);
+ } else if (msg == "ShowDoorhanger") {
+ Assert.equal(
+ data.origin,
+ expectedFormOrigin,
+ "Message origin should match expected"
+ );
+ notifications.push("FormSubmit: " + data.data.usernameField.name);
+ }
+ if (notifications.length == count) {
+ resolve(notifications);
+ }
+ });
+ });
+}
+
+async function verifyNotifications(notifyPromise, expected) {
+ let actual = await notifyPromise;
+
+ Assert.equal(actual.length, expected.length, "Extra notification(s) sent");
+ let expectedItem;
+ while ((expectedItem = expected.pop())) {
+ let index = actual.indexOf(expectedItem);
+ if (index >= 0) {
+ actual.splice(index, 1);
+ } else {
+ Assert.ok(false, "Expected notification '" + expectedItem + "' not sent");
+ }
+ }
+}
+
+// Make sure there is an autocomplete result for the frame's saved login and select it.
+async function autocompleteLoginInIFrame(
+ browser,
+ iframeBrowsingContext,
+ selector
+) {
+ let popup = document.getElementById("PopupAutoComplete");
+ Assert.ok(popup, "Got popup");
+
+ await openACPopup(popup, browser, selector, iframeBrowsingContext);
+
+ let autocompleteLoginResult = popup.querySelector(
+ `[originaltype="loginWithOrigin"]`
+ );
+ Assert.ok(autocompleteLoginResult, "Got login richlistitem");
+
+ let promiseHidden = BrowserTestUtils.waitForEvent(popup, "popuphidden");
+
+ await EventUtils.synthesizeKey("KEY_ArrowDown");
+ await EventUtils.synthesizeKey("KEY_Enter");
+
+ await promiseHidden;
+}
+
+/*
+ * In this test, a frame is loaded with a document that contains a username
+ * and password field. This frame also contains another child iframe that
+ * itself contains a username and password field. This inner frame is loaded
+ * from a different domain than the first.
+ *
+ * locationMode should be false to submit forms, or true to click a button
+ * which changes the location instead. The latter should still save the
+ * username and password.
+ */
+async function submitSomeCrossSiteFrames(locationMode) {
+ info("Check with location mode " + locationMode);
+ let notifyPromise = listenForNotifications(2);
+
+ let firsttab = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ OUTER_URL
+ );
+
+ let outerFrameBC = firsttab.linkedBrowser.browsingContext;
+ let innerFrameBC = outerFrameBC.children[0];
+
+ await verifyNotifications(notifyPromise, [
+ "FormProcessed: " + outerFrameBC.id,
+ "FormProcessed: " + innerFrameBC.id,
+ ]);
+
+ // Fill in the username and password for both the outer and inner frame
+ // and submit the inner frame.
+ notifyPromise = listenForNotifications(1, "https://test2.example.org");
+ info("submit page after changing inner form");
+
+ await SpecialPowers.spawn(outerFrameBC, [], () => {
+ let doc = content.document;
+ doc.getElementById("outer-username").setUserInput("outer");
+ doc.getElementById("outer-password").setUserInput("outerpass");
+ });
+
+ await SpecialPowers.spawn(innerFrameBC, [locationMode], doClick => {
+ let doc = content.document;
+ doc.getElementById("inner-username").setUserInput("inner");
+ doc.getElementById("inner-password").setUserInput("innerpass");
+ if (doClick) {
+ doc.getElementById("inner-gobutton").click();
+ } else {
+ doc.getElementById("inner-form").submit();
+ }
+ });
+
+ await acceptPasswordSave();
+
+ await verifyNotifications(notifyPromise, ["FormSubmit: username"]);
+
+ // Next, open a second tab with the same page in it to verify that the data gets filled properly.
+ notifyPromise = listenForNotifications(2);
+ let secondtab = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ OUTER_URL
+ );
+
+ let outerFrameBC2 = secondtab.linkedBrowser.browsingContext;
+ let innerFrameBC2 = outerFrameBC2.children[0];
+ await verifyNotifications(notifyPromise, [
+ "FormProcessed: " + outerFrameBC2.id,
+ "FormProcessed: " + innerFrameBC2.id,
+ ]);
+
+ // We don't expect the innerFrame to be autofilled with the saved login, since
+ // it is cross-origin with the top level frame, so we autocomplete instead.
+ info("Autocompleting saved login into inner form");
+ await autocompleteLoginInIFrame(
+ secondtab.linkedBrowser,
+ innerFrameBC2,
+ "#inner-username"
+ );
+
+ await checkFormFields(outerFrameBC2, "outer", "", "");
+ await checkFormFields(innerFrameBC2, "inner", "inner", "innerpass");
+
+ // Next, change the username and password fields in the outer frame and submit.
+ notifyPromise = listenForNotifications(1, "https://test1.example.com");
+ info("submit page after changing outer form");
+
+ await SpecialPowers.spawn(outerFrameBC2, [locationMode], doClick => {
+ let doc = content.document;
+ doc.getElementById("outer-username").setUserInput("outer2");
+ doc.getElementById("outer-password").setUserInput("outerpass2");
+ if (doClick) {
+ doc.getElementById("outer-gobutton").click();
+ } else {
+ doc.getElementById("outer-form").submit();
+ }
+
+ doc.getElementById("outer-form").submit();
+ });
+
+ await acceptPasswordSave();
+ await verifyNotifications(notifyPromise, ["FormSubmit: outer-username"]);
+
+ // Finally, open a third tab with the same page in it to verify that the data gets filled properly.
+ notifyPromise = listenForNotifications(2);
+ let thirdtab = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ OUTER_URL
+ );
+
+ let outerFrameBC3 = thirdtab.linkedBrowser.browsingContext;
+ let innerFrameBC3 = outerFrameBC3.children[0];
+ await verifyNotifications(notifyPromise, [
+ "FormProcessed: " + outerFrameBC3.id,
+ "FormProcessed: " + innerFrameBC3.id,
+ ]);
+
+ // We don't expect the innerFrame to be autofilled with the saved login, since
+ // it is cross-origin with the top level frame, so we autocomplete instead.
+ info("Autocompleting saved login into inner form");
+ await autocompleteLoginInIFrame(
+ thirdtab.linkedBrowser,
+ innerFrameBC3,
+ "#inner-username"
+ );
+
+ await checkFormFields(outerFrameBC3, "outer", "outer2", "outerpass2");
+ await checkFormFields(innerFrameBC3, "inner", "inner", "innerpass");
+
+ LoginManagerParent.setListenerForTests(null);
+
+ await BrowserTestUtils.removeTab(firsttab);
+ await BrowserTestUtils.removeTab(secondtab);
+ await BrowserTestUtils.removeTab(thirdtab);
+
+ LoginTestUtils.clearData();
+}
+
+add_task(async function cross_site_frames_submit() {
+ await submitSomeCrossSiteFrames(false);
+});
+
+add_task(async function cross_site_frames_changelocation() {
+ await submitSomeCrossSiteFrames(true);
+});