commit 269c9bd63b4c43db525158f52a8468ac7c72918c
parent 14e523cf736d0c165daa2bf4165515f224f99e3d
Author: moz-wptsync-bot <wptsync@mozilla.com>
Date: Thu, 4 Dec 2025 18:27:01 +0000
Bug 2003207 [wpt PR 56351] - Digital Credentials: add mDoc support and generic protocol selection mechanism, a=testonly
Automatic update from web-platform-tests
Digital Credentials: add mDoc support and generic protocol selection mechanism (#56351)
* Digital Credentials: add mDoc support and generic protocol selection mechanism
- Add org-iso-mdoc protocol support and mDocRequest interface
- Implement automatic protocol selection using DigitalCredential.userAgentAllowsProtocol
- Update protocol type definitions to separate OpenID and mDoc protocols
- Add DigitalCredentialStatic interface for userAgentAllowsProtocol method
- Update helper functions to use automatic protocol detection as defaults
- Tests now use makeGetOptions() and makeCreateOptions() without explicit protocols
--
wpt-commits: afce258ce1915a1a34522670d664031042e70f62
wpt-pr: 56351
Diffstat:
5 files changed, 87 insertions(+), 14 deletions(-)
diff --git a/testing/web-platform/tests/digital-credentials/create.tentative.https.html b/testing/web-platform/tests/digital-credentials/create.tentative.https.html
@@ -182,7 +182,7 @@
promise_test(async (t) => {
const abortController = new AbortController();
const { signal } = abortController;
- const options = makeCreateOptions({ protocol: "openid4vci", signal });
+ const options = makeCreateOptions({ signal });
await test_driver.bless("user activation");
const promise = promise_rejects_dom(
t,
@@ -200,7 +200,7 @@
abort: "after",
action: "create",
needsActivation: true,
- options: makeCreateOptions({protocol: "openid4vci"}),
+ options: makeCreateOptions(),
});
assert_equals(result.constructor, "DOMException");
assert_equals(result.name, "AbortError");
@@ -236,7 +236,7 @@
];
for (const badValue of throwingValues) {
- const options = makeCreateOptions({protocol: "openid4vci"});
+ const options = makeCreateOptions();
options.digital.requests[0].data = badValue;
await promise_rejects_js(
diff --git a/testing/web-platform/tests/digital-credentials/dc-types.ts b/testing/web-platform/tests/digital-credentials/dc-types.ts
@@ -1,5 +1,10 @@
-export type GetProtocol = "default" | "openid4vp-v1-unsigned" | "openid4vp-v1-signed" | "openid4vp-v1-multisigned";
-export type CreateProtocol = "default" | "openid4vci";
+export type OpenIDPresentationProtocol =
+ | "openid4vp-v1-unsigned"
+ | "openid4vp-v1-signed"
+ | "openid4vp-v1-multisigned";
+export type OpenIDIssuanceProtocol = "openid4vci";
+export type GetProtocol = OpenIDPresentationProtocol | "org-iso-mdoc";
+export type CreateProtocol = OpenIDIssuanceProtocol;
export type CredentialMediationRequirement =
| "conditional"
@@ -8,6 +13,22 @@ export type CredentialMediationRequirement =
| "silent";
/**
+ * @see https://www.iso.org/obp/ui#iso:std:iso-iec:ts:18013:-7:ed-2:v1:en
+ */
+export interface MobileDocumentRequest {
+ /**
+ * Information required for encryption, typically a base64-encoded string or JSON object as a string.
+ * The format should comply with the requirements specified in ISO/IEC TS 18013-7.
+ */
+ readonly encryptionInfo: string;
+ /**
+ * The device request payload, usually a stringified JSON object containing the request details.
+ * This should follow the structure defined in ISO/IEC TS 18013-7 for device requests.
+ */
+ readonly deviceRequest: string;
+}
+
+/**
* Configuration for makeGetOptions function
*/
export interface MakeGetOptionsConfig {
@@ -135,3 +156,17 @@ export interface SendMessageData {
action: IframeActionType;
options?: CredentialRequestOptions;
}
+
+/**
+ * The DigitalCredential interface
+ */
+export interface DigitalCredentialStatic {
+ /**
+ * Check if the user agent allows a specific protocol
+ */
+ userAgentAllowsProtocol(protocol: string): boolean;
+}
+
+declare global {
+ var DigitalCredential: DigitalCredentialStatic;
+}
diff --git a/testing/web-platform/tests/digital-credentials/get.tentative.https.html b/testing/web-platform/tests/digital-credentials/get.tentative.https.html
@@ -206,7 +206,7 @@
promise_test(async (t) => {
const abortController = new AbortController();
const { signal } = abortController;
- const options = makeGetOptions({protocol: "openid4vp-v1-unsigned", signal});
+ const options = makeGetOptions({signal});
await test_driver.bless("user activation");
const promise = promise_rejects_dom(
t,
@@ -224,7 +224,7 @@
abort: "after",
action: "get",
needsActivation: true,
- options: makeGetOptions({protocol: "openid4vp-v1-signed"}),
+ options: makeGetOptions(),
});
assert_equals(result.constructor, "DOMException");
assert_equals(result.name, "AbortError");
@@ -253,7 +253,7 @@ promise_test(async t => {
];
for (const badValue of throwingValues) {
- const options = makeGetOptions({protocol: "openid4vp-v1-multisigned"});
+ const options = makeGetOptions();
options.digital.requests[0].data = badValue;
await promise_rejects_js(
diff --git a/testing/web-platform/tests/digital-credentials/support/helper.js b/testing/web-platform/tests/digital-credentials/support/helper.js
@@ -13,8 +13,27 @@
* @typedef {import('../dc-types').MakeGetOptionsConfig} MakeGetOptionsConfig
* @typedef {import('../dc-types').MakeCreateOptionsConfig} MakeCreateOptionsConfig
* @typedef {import('../dc-types').CredentialMediationRequirement} CredentialMediationRequirement
+ * @typedef {import('../dc-types').MobileDocumentRequest} MobileDocumentRequest
*/
+/** @type {GetProtocol[]} */
+const GET_PROTOCOLS = /** @type {const} */ ([
+ "openid4vp-v1-unsigned",
+ "openid4vp-v1-signed",
+ "openid4vp-v1-multisigned",
+ "org-iso-mdoc",
+]);
+
+/** @type {CreateProtocol[]} */
+const CREATE_PROTOCOLS = /** @type {const} */ (["openid4vci"]);
+
+const SUPPORTED_GET_PROTOCOL = GET_PROTOCOLS.find(
+ (protocol) => DigitalCredential.userAgentAllowsProtocol(protocol)
+);
+const SUPPORTED_CREATE_PROTOCOL = CREATE_PROTOCOLS.find(
+ (protocol) => DigitalCredential.userAgentAllowsProtocol(protocol)
+);
+
/**
* Internal helper to build the request array from validated input.
* Assumes requestsInputArray is a non-empty array of strings.
@@ -37,6 +56,7 @@ function _makeOptionsInternal(requestsInputArray, mediation, requestMapping, sig
throw new Error(`Unknown request type within array: ${request}`);
}
}
+ /** @type {{ digital: { requests: any[] }, mediation: CredentialMediationRequirement, signal?: AbortSignal }} */
const result = { digital: { requests }, mediation };
if (signal !== undefined) {
result.signal = signal;
@@ -46,14 +66,13 @@ function _makeOptionsInternal(requestsInputArray, mediation, requestMapping, sig
const allMappings = {
get: {
+ "org-iso-mdoc": () => makeMDocRequest(),
"openid4vp-v1-unsigned": () => makeOID4VPDict("openid4vp-v1-unsigned"),
"openid4vp-v1-signed": () => makeOID4VPDict("openid4vp-v1-signed"),
"openid4vp-v1-multisigned": () => makeOID4VPDict("openid4vp-v1-multisigned"),
- "default": () => makeDigitalCredentialGetRequest(undefined, undefined),
},
create: {
"openid4vci": () => makeOID4VCIDict(),
- "default": () => makeDigitalCredentialCreateRequest(),
},
};
@@ -91,6 +110,7 @@ function _makeOptionsUnified(type, protocol, mediation, signal) {
if (Array.isArray(protocol)) {
if (protocol.length === 0) {
// Handle empty array explicitly
+ /** @type {{ digital: { requests: any[] }, mediation: CredentialMediationRequirement, signal?: AbortSignal }} */
const result = { digital: { requests: [] }, mediation };
if (signal !== undefined) {
result.signal = signal;
@@ -102,6 +122,7 @@ function _makeOptionsUnified(type, protocol, mediation, signal) {
}
// 4. Handle invalid input types (neither string nor array)
+ /** @type {{ digital: { requests: any[] }, mediation: CredentialMediationRequirement, signal?: AbortSignal }} */
const result = { digital: { requests: [] }, mediation };
if (signal !== undefined) {
result.signal = signal;
@@ -116,7 +137,10 @@ function _makeOptionsUnified(type, protocol, mediation, signal) {
* @returns {CredentialRequestOptions}
*/
export function makeGetOptions(config = {}) {
- const { protocol = "default", mediation = "required", signal } = config;
+ const { protocol = SUPPORTED_GET_PROTOCOL, mediation = "required", signal } = config;
+ if (!protocol) {
+ throw new Error("No Protocol. Can't make get options.");
+ }
return _makeOptionsUnified('get', protocol, mediation, signal);
}
@@ -127,7 +151,10 @@ export function makeGetOptions(config = {}) {
* @returns {CredentialCreationOptions}
*/
export function makeCreateOptions(config = {}) {
- const { protocol = "default", mediation = "required", signal } = config;
+ const { protocol = SUPPORTED_CREATE_PROTOCOL, mediation = "required", signal } = config;
+ if (!protocol) {
+ throw new Error("No protocol. Can't make create options.");
+ }
return _makeOptionsUnified('create', protocol, mediation, signal);
}
@@ -181,6 +208,17 @@ function makeOID4VCIDict() {
}
/**
+ * Representation of an mDoc request.
+ *
+ * @returns {DigitalCredentialGetRequest}
+ **/
+function makeMDocRequest() {
+ return makeDigitalCredentialGetRequest("org-iso-mdoc", {
+ // Canonical example of an mDoc request coming soon.
+ });
+}
+
+/**
* Sends a message to an iframe and return the response.
*
* @param {HTMLIFrameElement} iframe - The iframe element to send the message to.
diff --git a/testing/web-platform/tests/digital-credentials/user-activation.https.html b/testing/web-platform/tests/digital-credentials/user-activation.https.html
@@ -14,7 +14,7 @@
navigator.userActivation.isActive,
"User activation should not be active"
);
- const options = makeGetOptions({protocol: "openid4vp-v1-unsigned"});
+ const options = makeGetOptions();
await promise_rejects_dom(
t,
"NotAllowedError",
@@ -25,7 +25,7 @@
promise_test(async (t) => {
await test_driver.bless();
const abort = new AbortController();
- const options = makeGetOptions({protocol: "openid4vp-v1-unsigned", signal: abort.signal});
+ const options = makeGetOptions({ signal: abort.signal });
assert_true(
navigator.userActivation.isActive,
"User activation should be active after test_driver.bless()."