Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

<!DOCTYPE html>
<meta charset="utf-8">
<title>Digital Credential API: org-iso-mdoc origin binding scenarios</title>
<script src="/common/get-host-info.sub.js"></script>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<body>
<iframe id="cross-origin" allow="digital-credentials-get"></iframe>
<iframe id="sandboxed" sandbox="allow-scripts" allow="digital-credentials-get"></iframe>
<iframe id="same-origin"></iframe>
</body>
<script type="module">
import { makeGetOptions, sendMessage, loadIframe } from "../support/helper.js";
// Tests for origin binding behavior with org-iso-mdoc.
//
// ISO 18013-7 C.5 specifies:
// dcapiInfo = [Base64EncryptionInfo, SerializedOrigin]
// The mdoc shall use the origin received from the API.
// If the mdoc does not receive the origin, it shall abort.
//
// The browser passes the TOP-LEVEL origin to the framework.
// These tests verify that origin handling is correct across
// iframe, cross-origin, and sandbox scenarios.
const iframeCrossOrigin = document.querySelector("#cross-origin");
const iframeSandboxed = document.querySelector("#sandboxed");
const iframeSameOrigin = document.querySelector("#same-origin");
promise_setup(async () => {
const hostInfo = get_host_info();
await Promise.all([
loadIframe(
iframeCrossOrigin,
`${hostInfo.HTTPS_REMOTE_ORIGIN}/digital-credentials/support/iframe.html`
),
loadIframe(
iframeSandboxed,
"/digital-credentials/support/iframe.html"
),
loadIframe(
iframeSameOrigin,
"/digital-credentials/support/iframe.html"
),
]);
});
// --- Sandboxed iframe with opaque origin ---
promise_test(async (t) => {
// A sandboxed iframe has an opaque origin.
// The DC API should either reject (no valid origin to pass to wallet)
// or the wallet should abort (origin is "null").
const options = makeGetOptions({ protocol: "org-iso-mdoc" });
const result = await sendMessage(iframeSandboxed, {
action: "get",
needsActivation: true,
options,
});
// Expect rejection: either NotAllowedError (permissions policy blocks it
// because sandboxed iframe without allow-same-origin can't use the feature)
// or TypeError (opaque origin)
assert_true(
result.constructor === "DOMException" || result.constructor === "TypeError",
`Sandboxed iframe should fail, got: ${result.constructor} ${result.name || ''}`
);
}, "org-iso-mdoc request from sandboxed iframe (opaque origin) is rejected.");
// --- Cross-origin iframe (allowed via permissions policy) ---
promise_test(async (t) => {
// Cross-origin iframe with digital-credentials-get permission.
// The request should proceed, using the TOP-LEVEL origin for the
// SessionTranscript (not the iframe's origin).
const options = makeGetOptions({ protocol: "org-iso-mdoc" });
const result = await sendMessage(iframeCrossOrigin, {
abort: "after",
action: "get",
needsActivation: true,
options,
});
// Should get AbortError (meaning the request was accepted and was pending
// before we aborted). NotAllowedError would mean it was rejected outright.
assert_equals(result.constructor, "DOMException");
assert_equals(result.name, "AbortError",
"Cross-origin iframe request should proceed (then abort), not be rejected");
}, "org-iso-mdoc request from cross-origin iframe (with permission) proceeds with top-level origin.");
// --- Same-origin iframe ---
promise_test(async (t) => {
// Same-origin iframe: origin should match top-level (they're the same).
const options = makeGetOptions({ protocol: "org-iso-mdoc" });
const result = await sendMessage(iframeSameOrigin, {
abort: "after",
action: "get",
needsActivation: true,
options,
});
assert_equals(result.constructor, "DOMException");
assert_equals(result.name, "AbortError",
"Same-origin iframe request should proceed (then abort)");
}, "org-iso-mdoc request from same-origin iframe proceeds normally.");
// --- Cross-origin iframe WITHOUT permission policy ---
promise_test(async (t) => {
// Create a cross-origin iframe without the allow attribute
const hostInfo = get_host_info();
const iframe = document.createElement("iframe");
// No allow="digital-credentials-get"
document.body.appendChild(iframe);
t.add_cleanup(() => iframe.remove());
await loadIframe(iframe, `${hostInfo.HTTPS_REMOTE_ORIGIN}/digital-credentials/support/iframe.html`);
const options = makeGetOptions({ protocol: "org-iso-mdoc" });
const result = await sendMessage(iframe, {
action: "get",
needsActivation: true,
options,
});
assert_equals(result.constructor, "DOMException");
assert_equals(result.name, "NotAllowedError",
"Cross-origin iframe without permission policy should be rejected with NotAllowedError");
}, "org-iso-mdoc request from cross-origin iframe WITHOUT permission is rejected.");
</script>