summaryrefslogtreecommitdiffstats
path: root/dom/credentialmanagement/tests
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--dom/credentialmanagement/tests/browser/browser.toml3
-rw-r--r--dom/credentialmanagement/tests/browser/browser_active_document.js139
-rw-r--r--dom/credentialmanagement/tests/crashtests/bug1691963.html28
-rw-r--r--dom/credentialmanagement/tests/crashtests/crashtests.list1
-rw-r--r--dom/credentialmanagement/tests/mochitest/frame_credman_iframes.html105
-rw-r--r--dom/credentialmanagement/tests/mochitest/mochitest.toml14
-rw-r--r--dom/credentialmanagement/tests/mochitest/test_credman_empty_option.html40
-rw-r--r--dom/credentialmanagement/tests/mochitest/test_credman_iframes.html88
8 files changed, 418 insertions, 0 deletions
diff --git a/dom/credentialmanagement/tests/browser/browser.toml b/dom/credentialmanagement/tests/browser/browser.toml
new file mode 100644
index 0000000000..be685270ac
--- /dev/null
+++ b/dom/credentialmanagement/tests/browser/browser.toml
@@ -0,0 +1,3 @@
+[DEFAULT]
+
+["browser_active_document.js"]
diff --git a/dom/credentialmanagement/tests/browser/browser_active_document.js b/dom/credentialmanagement/tests/browser/browser_active_document.js
new file mode 100644
index 0000000000..eced461630
--- /dev/null
+++ b/dom/credentialmanagement/tests/browser/browser_active_document.js
@@ -0,0 +1,139 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const TEST_URL = "https://example.com/";
+
+function arrivingHereIsBad(aResult) {
+ ok(false, "Bad result! Received a: " + aResult);
+}
+
+function expectNotAllowedError(aResult) {
+ let expected = "NotAllowedError";
+ is(aResult.slice(0, expected.length), expected, `Expecting a ${expected}`);
+}
+
+function promiseMakeCredential(tab) {
+ return ContentTask.spawn(tab.linkedBrowser, null, async function () {
+ const cose_alg_ECDSA_w_SHA256 = -7;
+
+ let publicKey = {
+ rp: { id: content.document.domain, name: "none", icon: "none" },
+ user: {
+ id: new Uint8Array(),
+ name: "none",
+ icon: "none",
+ displayName: "none",
+ },
+ challenge: content.crypto.getRandomValues(new Uint8Array(16)),
+ timeout: 5000, // the minimum timeout is actually 15 seconds
+ pubKeyCredParams: [{ type: "public-key", alg: cose_alg_ECDSA_w_SHA256 }],
+ };
+
+ return content.navigator.credentials.create({ publicKey });
+ });
+}
+
+function promiseGetAssertion(tab) {
+ return ContentTask.spawn(tab.linkedBrowser, null, async function () {
+ let newCredential = {
+ type: "public-key",
+ id: content.crypto.getRandomValues(new Uint8Array(16)),
+ transports: ["usb"],
+ };
+
+ let publicKey = {
+ challenge: content.crypto.getRandomValues(new Uint8Array(16)),
+ timeout: 5000, // the minimum timeout is actually 15 seconds
+ rpId: content.document.domain,
+ allowCredentials: [newCredential],
+ };
+
+ return content.navigator.credentials.get({ publicKey });
+ });
+}
+
+add_task(async function test_setup() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["security.webauth.webauthn", true],
+ ["security.webauth.webauthn_enable_softtoken", true],
+ ["security.webauth.webauthn_enable_usbtoken", false],
+ ],
+ });
+});
+
+add_task(async function test_background_tab() {
+ // Open two tabs, the last one will selected.
+ let tab_bg = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
+ let tab_fg = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
+
+ // Requests from background tabs must fail.
+ await promiseMakeCredential(tab_bg)
+ .then(arrivingHereIsBad)
+ .catch(expectNotAllowedError);
+
+ // Requests from background tabs must fail.
+ await promiseGetAssertion(tab_bg)
+ .then(arrivingHereIsBad)
+ .catch(expectNotAllowedError);
+
+ // Close tabs.
+ await BrowserTestUtils.removeTab(tab_bg);
+ await BrowserTestUtils.removeTab(tab_fg);
+});
+
+add_task(async function test_background_window() {
+ // Open a tab, then a new window.
+ let tab_bg = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
+ let win = await BrowserTestUtils.openNewBrowserWindow();
+
+ // Wait until the new window is really focused.
+ await new Promise(resolve => SimpleTest.waitForFocus(resolve, win));
+
+ // Requests from selected tabs not in the active window must fail.
+ await promiseMakeCredential(tab_bg)
+ .then(arrivingHereIsBad)
+ .catch(expectNotAllowedError);
+
+ // Requests from selected tabs not in the active window must fail.
+ await promiseGetAssertion(tab_bg)
+ .then(arrivingHereIsBad)
+ .catch(expectNotAllowedError);
+
+ // Close tab and window.
+ await BrowserTestUtils.closeWindow(win);
+ await BrowserTestUtils.removeTab(tab_bg);
+});
+
+add_task(async function test_minimized() {
+ // Minimizing windows doesn't supported in headless mode.
+ if (Services.env.get("MOZ_HEADLESS")) {
+ return;
+ }
+
+ // Open a window with a tab.
+ let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL);
+
+ // Minimize the window.
+ window.minimize();
+ await TestUtils.waitForCondition(() => !tab.linkedBrowser.docShellIsActive);
+
+ // Requests from minimized windows must fail.
+ await promiseMakeCredential(tab)
+ .then(arrivingHereIsBad)
+ .catch(expectNotAllowedError);
+
+ // Requests from minimized windows must fail.
+ await promiseGetAssertion(tab)
+ .then(arrivingHereIsBad)
+ .catch(expectNotAllowedError);
+
+ // Restore the window.
+ await new Promise(resolve => SimpleTest.waitForFocus(resolve, window));
+
+ // Close tab.
+ await BrowserTestUtils.removeTab(tab);
+});
diff --git a/dom/credentialmanagement/tests/crashtests/bug1691963.html b/dom/credentialmanagement/tests/crashtests/bug1691963.html
new file mode 100644
index 0000000000..f7ef34622f
--- /dev/null
+++ b/dom/credentialmanagement/tests/crashtests/bug1691963.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+ <script>
+ document.addEventListener("DOMContentLoaded", () => {
+ const frame = document.createElement("frame");
+ document.body.appendChild(frame);
+ const { credentials } = frame.contentWindow.navigator;
+
+ let i = 0;
+ setInterval(async () => {
+ if (i++ > 3) {
+ document.documentElement.removeAttribute("class");
+ }
+ try {
+ await credentials.get({
+ publicKey: {
+ challenge: new Uint8Array(128),
+ allowCredentials: [{ type: 'public-key', id: new TextEncoder().encode('FOOBAR'), }],
+ },
+ });
+ } catch (e) {}
+ frame.remove();
+ }, 1000);
+ }, { once: true });
+ </script>
+</head>
+</html>
diff --git a/dom/credentialmanagement/tests/crashtests/crashtests.list b/dom/credentialmanagement/tests/crashtests/crashtests.list
new file mode 100644
index 0000000000..dcd014d6ec
--- /dev/null
+++ b/dom/credentialmanagement/tests/crashtests/crashtests.list
@@ -0,0 +1 @@
+load bug1691963.html
diff --git a/dom/credentialmanagement/tests/mochitest/frame_credman_iframes.html b/dom/credentialmanagement/tests/mochitest/frame_credman_iframes.html
new file mode 100644
index 0000000000..e7dbd40b34
--- /dev/null
+++ b/dom/credentialmanagement/tests/mochitest/frame_credman_iframes.html
@@ -0,0 +1,105 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Embedded Frame for Credential Management: Prohibit use in cross-origin iframes</title>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <meta charset=utf-8>
+</head>
+<body>
+
+<script class="testbody" type="text/javascript">
+"use strict";
+
+const cose_alg_ECDSA_w_SHA256 = -7;
+var _parentOrigin = "https://example.com/";
+
+function log(msg) {
+ console.log(msg);
+ let logBox = document.getElementById("log");
+ if (logBox) {
+ logBox.textContent += "\n" + msg;
+ }
+}
+
+function local_finished() {
+ parent.postMessage({"done": true}, _parentOrigin);
+ log("Done.");
+}
+
+function local_ok(expression, message) {
+ let body = {"test": expression, "status": expression, "msg": message};
+ parent.postMessage(body, _parentOrigin);
+ log(expression + ": " + message);
+}
+
+function testSameOrigin() {
+ log("Same origin: " + document.domain);
+
+ navigator.credentials.create({publicKey: makeCredentialOptions})
+ .then(function sameOriginCreateThen(aResult) {
+ local_ok(aResult != undefined, "Create worked " + aResult);
+ })
+ .catch(function sameOriginCatch(aResult) {
+ local_ok(false, "Should not have failed " + aResult);
+ })
+ .then(function sameOriginPreventSilentAccess() {
+ return navigator.credentials.preventSilentAccess();
+ })
+ .then(function sameOriginPreventSilentAccessThen(aResult) {
+ local_ok(aResult == undefined, "PreventSilentAccess worked " + aResult);
+ })
+ .catch(function sameOriginPreventSilentAccessCatch(aResult) {
+ local_ok(false, "Should not have failed " + aResult);
+ })
+ .then(function() {
+ local_finished();
+ });
+}
+
+function testCrossOrigin() {
+ log("Cross-origin: " + document.domain);
+
+ navigator.credentials.create({publicKey: makeCredentialOptions})
+ .then(function crossOriginThen(aBad) {
+ local_ok(false, "Should not have succeeded " + aBad);
+ })
+ .catch(function crossOriginCatch(aResult) {
+ local_ok(aResult.toString().startsWith("NotAllowedError"),
+ "Expecting a NotAllowedError, received " + aResult);
+ })
+ .then(function crossOriginPreventSilentAccess() {
+ return navigator.credentials.preventSilentAccess();
+ })
+ .then(function crossOriginPreventSilentAccessThen(aResult) {
+ local_ok(aResult == undefined, "PreventSilentAccess worked " + aResult);
+ })
+ .catch(function crossOriginPreventSilentAccessCatch(aResult) {
+ local_ok(false, "Should not have failed " + aResult);
+ })
+ .then(function() {
+ local_finished();
+ });
+}
+
+let rp = {id: document.domain, name: "none", icon: "none"};
+let user = {
+ id: crypto.getRandomValues(new Uint8Array(16)),
+ name: "none", icon: "none", displayName: "none",
+};
+let param = {type: "public-key", alg: cose_alg_ECDSA_w_SHA256};
+let makeCredentialOptions = {
+ rp, user, challenge: new Uint8Array(), pubKeyCredParams: [param],
+};
+
+if (document.domain == "example.com") {
+ testSameOrigin();
+} else {
+ testCrossOrigin();
+}
+
+</script>
+
+<div id="log"></div>
+
+</body>
+</html>
diff --git a/dom/credentialmanagement/tests/mochitest/mochitest.toml b/dom/credentialmanagement/tests/mochitest/mochitest.toml
new file mode 100644
index 0000000000..d8d142d9d8
--- /dev/null
+++ b/dom/credentialmanagement/tests/mochitest/mochitest.toml
@@ -0,0 +1,14 @@
+[DEFAULT]
+support-files = ["frame_credman_iframes.html"]
+scheme = "https"
+
+["test_credman_empty_option.html"]
+
+["test_credman_iframes.html"]
+skip-if = [
+ "xorigin", # Application time out
+ "win10_2009", # Bug 1718296
+ "win11_2009", # Bug 1718296
+ "http3",
+ "http2",
+]
diff --git a/dom/credentialmanagement/tests/mochitest/test_credman_empty_option.html b/dom/credentialmanagement/tests/mochitest/test_credman_empty_option.html
new file mode 100644
index 0000000000..4e582a9f8e
--- /dev/null
+++ b/dom/credentialmanagement/tests/mochitest/test_credman_empty_option.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<head>
+ <title>Credential Management: Handle requests with empty options</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <meta charset=utf-8>
+</head>
+<body>
+<h1>Credential Management: Handle requests with empty options</h1>
+
+<script class="testbody" type="text/javascript">
+"use strict";
+
+SimpleTest.waitForExplicitFinish();
+
+SpecialPowers.pushPrefEnv({"set": [["security.webauth.webauthn", true],
+ ["dom.security.credentialmanagement.enabled", true]
+ ]},
+async function() {
+ info("testing create({}).")
+ try {
+ await navigator.credentials.create({});
+ ok(false, "Credential creation with no options should be an error.");
+ }
+ catch (err) {
+ is(err.name, "NotSupportedError", "Credential creation with no options is a NotSupportedError");
+ }
+ info("testing get({}).")
+ try {
+ await navigator.credentials.get({});
+ ok(false, "Credential get with no options should be an error.");
+ }
+ catch (err) {
+ is(err.name, "NotSupportedError", "Credential get with no options is a NotSupportedError");
+ }
+ SimpleTest.finish();
+});
+</script>
+</body>
+</html>
diff --git a/dom/credentialmanagement/tests/mochitest/test_credman_iframes.html b/dom/credentialmanagement/tests/mochitest/test_credman_iframes.html
new file mode 100644
index 0000000000..b77a868392
--- /dev/null
+++ b/dom/credentialmanagement/tests/mochitest/test_credman_iframes.html
@@ -0,0 +1,88 @@
+<!DOCTYPE html>
+<head>
+ <title>Credential Management: Prohibit use in cross-origin iframes</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+ <meta charset=utf-8>
+</head>
+<body>
+<h1>Credential Management: Prohibit use in cross-origin iframes</h1>
+<ul>
+ <li><a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1407789">Mozilla Bug 1407789</a></li>
+</ul>
+
+<div id="framediv">
+ <h2>Same Origin Test</h2>
+ <iframe id="frame_top"></iframe>
+
+ <h2>Cross-Origin Test</h2>
+ <iframe id="frame_bottom"></iframe>
+</div>
+
+<script class="testbody" type="text/javascript">
+"use strict";
+
+var _countCompletes = 0;
+var _expectedCompletes = 2; // 2 iframes
+
+var _done = new Promise((resolve) => {
+ function handleEventMessage(event) {
+ if ("test" in event.data) {
+ let summary = event.data.test + ": " + event.data.msg;
+ ok(event.data.status, summary);
+ } else if ("done" in event.data) {
+ _countCompletes += 1;
+ if (_countCompletes == _expectedCompletes) {
+ console.log("Test compeleted. Finished.");
+ resolve();
+ }
+ } else {
+ ok(false, "Unexpected message in the test harness: " + event.data);
+ }
+ }
+
+ window.addEventListener("message", handleEventMessage);
+});
+
+async function addVirtualAuthenticator() {
+ let id = await SpecialPowers.spawnChrome([], () => {
+ let webauthnService = Cc["@mozilla.org/webauthn/service;1"].getService(
+ Ci.nsIWebAuthnService
+ );
+ return webauthnService.addVirtualAuthenticator(
+ "ctap2",
+ "internal",
+ true,
+ true,
+ true,
+ true
+ );
+ });
+
+ SimpleTest.registerCleanupFunction(async () => {
+ await SpecialPowers.spawnChrome([id], (authenticatorId) => {
+ let webauthnService = Cc["@mozilla.org/webauthn/service;1"].getService(
+ Ci.nsIWebAuthnService
+ );
+ webauthnService.removeVirtualAuthenticator(authenticatorId);
+ });
+ });
+}
+
+add_task(async () => {
+ await SpecialPowers.pushPrefEnv({"set": [["security.webauth.webauthn", true],
+ ["security.webauth.webauthn_enable_softtoken", true],
+ ["security.webauth.webauthn_enable_usbtoken", false]]});
+ await addVirtualAuthenticator();
+});
+
+add_task(async () => {
+ document.getElementById("frame_top").src = "https://example.com/tests/dom/credentialmanagement/tests/mochitest/frame_credman_iframes.html";
+
+ document.getElementById("frame_bottom").src = "https://test1.example.com/tests/dom/credentialmanagement/tests/mochitest/frame_credman_iframes.html";
+
+ await _done;
+});
+</script>
+</body>
+</html>