From fed438c6ed6df1dcb3e0bd75d787e2e0883c0c21 Mon Sep 17 00:00:00 2001 From: Nicole Ebken Date: Thu, 5 Mar 2026 13:01:02 +0100 Subject: [PATCH 1/5] chore: process token with verifiable presentation content --- .../app-runtime/src/AppStringProcessor.ts | 7 ++++ .../src/extensibility/ui/IUIBridge.ts | 3 +- packages/app-runtime/test/lib/FakeUIBridge.ts | 4 +++ .../test/lib/MockUIBridge.matchers.ts | 34 +++++++++++++++++++ packages/app-runtime/test/lib/MockUIBridge.ts | 9 ++++- .../test/runtime/AppStringProcessor.test.ts | 20 ++++++++++- 6 files changed, 74 insertions(+), 3 deletions(-) diff --git a/packages/app-runtime/src/AppStringProcessor.ts b/packages/app-runtime/src/AppStringProcessor.ts index 554899baa..bb0dd4699 100644 --- a/packages/app-runtime/src/AppStringProcessor.ts +++ b/packages/app-runtime/src/AppStringProcessor.ts @@ -2,6 +2,7 @@ import { OpenId4VciResolvedCredentialOffer } from "@credo-ts/openid4vc"; import { ILogger, ILoggerFactory } from "@js-soft/logging-abstractions"; import { Serializable } from "@js-soft/ts-serval"; import { EventBus, Result } from "@js-soft/ts-utils"; +import { VerifiablePresentation } from "@nmshd/content"; import { ICoreAddress, Reference } from "@nmshd/core-types"; import { AnonymousServices, DeviceMapper, RuntimeServices } from "@nmshd/runtime"; import { BackboneIds, TokenContentDeviceSharedSecret } from "@nmshd/transport"; @@ -289,6 +290,12 @@ export class AppStringProcessor { // RelationshipTemplates are processed by the RequestModule break; case "Token": + const tokenContent = this.parseTokenContent(result.value.value.content); + + if (tokenContent instanceof VerifiablePresentation) { + await uiBridge.showVerifiablePresentation(account, result.value.value); + break; + } return Result.fail(AppRuntimeErrors.appStringProcessor.notSupportedTokenContent()); case "DeviceOnboardingInfo": return Result.fail(AppRuntimeErrors.appStringProcessor.deviceOnboardingNotAllowed()); diff --git a/packages/app-runtime/src/extensibility/ui/IUIBridge.ts b/packages/app-runtime/src/extensibility/ui/IUIBridge.ts index 56ec32ec9..02d56a319 100644 --- a/packages/app-runtime/src/extensibility/ui/IUIBridge.ts +++ b/packages/app-runtime/src/extensibility/ui/IUIBridge.ts @@ -1,12 +1,13 @@ import { ApplicationError, Result } from "@js-soft/ts-utils"; import { OpenId4VciCredentialResponseJSON } from "@nmshd/consumption"; -import { DeviceOnboardingInfoDTO, FileDVO, IdentityDVO, LocalRequestDVO, MailDVO, MessageDVO, RequestMessageDVO, ResolveAuthorizationRequestResponse } from "@nmshd/runtime"; +import { DeviceOnboardingInfoDTO, FileDVO, IdentityDVO, LocalRequestDVO, MailDVO, MessageDVO, RequestMessageDVO, ResolveAuthorizationRequestResponse, TokenDTO } from "@nmshd/runtime"; import { LocalAccountDTO } from "../../multiAccount"; export interface IUIBridge { showMessage(account: LocalAccountDTO, relationship: IdentityDVO, message: MessageDVO | MailDVO | RequestMessageDVO): Promise>; showRelationship(account: LocalAccountDTO, relationship: IdentityDVO): Promise>; showFile(account: LocalAccountDTO, file: FileDVO): Promise>; + showVerifiablePresentation(account: LocalAccountDTO, token: TokenDTO): Promise>; showDeviceOnboarding(deviceOnboardingInfo: DeviceOnboardingInfoDTO): Promise>; showRequest(account: LocalAccountDTO, request: LocalRequestDVO): Promise>; showResolvedAuthorizationRequest(account: LocalAccountDTO, response: ResolveAuthorizationRequestResponse): Promise>; diff --git a/packages/app-runtime/test/lib/FakeUIBridge.ts b/packages/app-runtime/test/lib/FakeUIBridge.ts index cdb74c689..5c3057665 100644 --- a/packages/app-runtime/test/lib/FakeUIBridge.ts +++ b/packages/app-runtime/test/lib/FakeUIBridge.ts @@ -14,6 +14,10 @@ export class FakeUIBridge implements IUIBridge { return Promise.resolve(Result.ok(undefined)); } + public showVerifiablePresentation(): Promise> { + return Promise.resolve(Result.ok(undefined)); + } + public showDeviceOnboarding(): Promise> { return Promise.resolve(Result.ok(undefined)); } diff --git a/packages/app-runtime/test/lib/MockUIBridge.matchers.ts b/packages/app-runtime/test/lib/MockUIBridge.matchers.ts index 0a9a5a877..59ed3d222 100644 --- a/packages/app-runtime/test/lib/MockUIBridge.matchers.ts +++ b/packages/app-runtime/test/lib/MockUIBridge.matchers.ts @@ -214,6 +214,38 @@ expect.extend({ return { pass: true, message: () => "" }; }, + showVerifiablePresentationCalled(mockUIBridge: unknown, id: string) { + if (!(mockUIBridge instanceof MockUIBridge)) { + throw new Error("This method can only be used with expect(MockUIBridge)."); + } + + const calls = mockUIBridge.calls.filter((x) => x.method === "showVerifiablePresentation"); + if (calls.length === 0) { + return { pass: false, message: () => "The method showVerifiablePresentation was not called." }; + } + + const matchingCalls = calls.filter((x) => x.token.id === id); + if (matchingCalls.length === 0) { + return { + pass: false, + message: () => `The method showVerifiablePresentation was called, but not with the specified token id '${id}', instead with ids '${calls.map((e) => e.token.id).join(", ")}'.` + }; + } + + return { pass: true, message: () => "" }; + }, + showVerifiablePresentationNotCalled(mockUIBridge: unknown) { + if (!(mockUIBridge instanceof MockUIBridge)) { + throw new Error("This method can only be used with expect(MockUIBridge)."); + } + + const calls = mockUIBridge.calls.filter((x) => x.method === "showVerifiablePresentation"); + if (calls.length > 0) { + return { pass: false, message: () => `The method showVerifiablePresentation called: ${calls.map((c) => `'account id: ${c.account.id} - tokenId: ${c.token.id}'`)}` }; + } + + return { pass: true, message: () => "" }; + }, showErrorCalled(mockUIBridge: unknown, code: string) { if (!(mockUIBridge instanceof MockUIBridge)) { throw new Error("This method can only be used with expect(MockUIBridge)."); @@ -253,6 +285,8 @@ declare global { showResolvedCredentialOfferNotCalled(): R; showFileCalled(id: string): R; showFileNotCalled(): R; + showVerifiablePresentationCalled(id: string): R; + showVerifiablePresentationNotCalled(): R; showErrorCalled(code: string): R; } } diff --git a/packages/app-runtime/test/lib/MockUIBridge.ts b/packages/app-runtime/test/lib/MockUIBridge.ts index 97ca2655b..801ec95e0 100644 --- a/packages/app-runtime/test/lib/MockUIBridge.ts +++ b/packages/app-runtime/test/lib/MockUIBridge.ts @@ -1,12 +1,13 @@ import { ApplicationError, Result } from "@js-soft/ts-utils"; import { OpenId4VciCredentialResponseJSON } from "@nmshd/consumption"; -import { DeviceOnboardingInfoDTO, FileDVO, IdentityDVO, LocalRequestDVO, MailDVO, MessageDVO, RequestMessageDVO, ResolveAuthorizationRequestResponse } from "@nmshd/runtime"; +import { DeviceOnboardingInfoDTO, FileDVO, IdentityDVO, LocalRequestDVO, MailDVO, MessageDVO, RequestMessageDVO, ResolveAuthorizationRequestResponse, TokenDTO } from "@nmshd/runtime"; import { IUIBridge, LocalAccountDTO } from "../../src"; export type MockUIBridgeCall = | { method: "showMessage"; account: LocalAccountDTO; relationship: IdentityDVO; message: MessageDVO | MailDVO | RequestMessageDVO } | { method: "showRelationship"; account: LocalAccountDTO; relationship: IdentityDVO } | { method: "showFile"; account: LocalAccountDTO; file: FileDVO } + | { method: "showVerifiablePresentation"; account: LocalAccountDTO; token: TokenDTO } | { method: "showDeviceOnboarding"; deviceOnboardingInfo: DeviceOnboardingInfoDTO } | { method: "showRequest"; account: LocalAccountDTO; request: LocalRequestDVO } | { method: "showResolvedAuthorizationRequest"; account: LocalAccountDTO; response: ResolveAuthorizationRequestResponse } @@ -57,6 +58,12 @@ export class MockUIBridge implements IUIBridge { return Promise.resolve(Result.ok(undefined)); } + public showVerifiablePresentation(account: LocalAccountDTO, token: TokenDTO): Promise> { + this._calls.push({ method: "showVerifiablePresentation", account, token }); + + return Promise.resolve(Result.ok(undefined)); + } + public showDeviceOnboarding(deviceOnboardingInfo: DeviceOnboardingInfoDTO): Promise> { this._calls.push({ method: "showDeviceOnboarding", deviceOnboardingInfo }); diff --git a/packages/app-runtime/test/runtime/AppStringProcessor.test.ts b/packages/app-runtime/test/runtime/AppStringProcessor.test.ts index 66ba74f08..fde72e1fe 100644 --- a/packages/app-runtime/test/runtime/AppStringProcessor.test.ts +++ b/packages/app-runtime/test/runtime/AppStringProcessor.test.ts @@ -1,4 +1,4 @@ -import { ArbitraryRelationshipTemplateContentJSON, AuthenticationRequestItem, RelationshipTemplateContent } from "@nmshd/content"; +import { ArbitraryRelationshipTemplateContentJSON, AuthenticationRequestItem, RelationshipTemplateContent, VerifiablePresentation } from "@nmshd/content"; import { CoreDate, PasswordLocationIndicatorOptions } from "@nmshd/core-types"; import { DeviceOnboardingInfoDTO, PeerRelationshipTemplateLoadedEvent } from "@nmshd/runtime"; import assert from "assert"; @@ -377,6 +377,24 @@ describe("AppStringProcessor", function () { expect(runtime4MockUiBridge).showFileCalled(file.id); }); + test("get a token with verifiable presentation content using a url", async function () { + const tokenResult = await runtime1Session.transportServices.tokens.createOwnToken({ + content: VerifiablePresentation.from({ + value: { tokenContent: "test" }, + type: "VerifiablePresentation" + }).toJSON(), + expiresAt: CoreDate.utc().add({ days: 1 }).toISOString(), + ephemeral: true + }); + const token = tokenResult.value; + + const result = await runtime4.stringProcessor.processURL(token.reference.url, runtime4Session.account); + expect(result).toBeSuccessful(); + expect(result.value).toBeUndefined(); + + expect(runtime4MockUiBridge).showVerifiablePresentationCalled(token.id); + }); + test("get a template using a url", async function () { const templateResult = await runtime1Session.transportServices.relationshipTemplates.createOwnRelationshipTemplate({ content: RelationshipTemplateContent.from({ From 3cb884dd2fc8a35412cec8a3d93702290a75e318 Mon Sep 17 00:00:00 2001 From: Nicole Ebken Date: Thu, 5 Mar 2026 13:12:29 +0100 Subject: [PATCH 2/5] chore: run prettier --- .../app-runtime/src/extensibility/ui/IUIBridge.ts | 12 +++++++++++- .../app-runtime/test/lib/MockUIBridge.matchers.ts | 3 ++- packages/app-runtime/test/lib/MockUIBridge.ts | 12 +++++++++++- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/packages/app-runtime/src/extensibility/ui/IUIBridge.ts b/packages/app-runtime/src/extensibility/ui/IUIBridge.ts index 02d56a319..6a38084ef 100644 --- a/packages/app-runtime/src/extensibility/ui/IUIBridge.ts +++ b/packages/app-runtime/src/extensibility/ui/IUIBridge.ts @@ -1,6 +1,16 @@ import { ApplicationError, Result } from "@js-soft/ts-utils"; import { OpenId4VciCredentialResponseJSON } from "@nmshd/consumption"; -import { DeviceOnboardingInfoDTO, FileDVO, IdentityDVO, LocalRequestDVO, MailDVO, MessageDVO, RequestMessageDVO, ResolveAuthorizationRequestResponse, TokenDTO } from "@nmshd/runtime"; +import { + DeviceOnboardingInfoDTO, + FileDVO, + IdentityDVO, + LocalRequestDVO, + MailDVO, + MessageDVO, + RequestMessageDVO, + ResolveAuthorizationRequestResponse, + TokenDTO +} from "@nmshd/runtime"; import { LocalAccountDTO } from "../../multiAccount"; export interface IUIBridge { diff --git a/packages/app-runtime/test/lib/MockUIBridge.matchers.ts b/packages/app-runtime/test/lib/MockUIBridge.matchers.ts index 59ed3d222..590719ab1 100644 --- a/packages/app-runtime/test/lib/MockUIBridge.matchers.ts +++ b/packages/app-runtime/test/lib/MockUIBridge.matchers.ts @@ -228,7 +228,8 @@ expect.extend({ if (matchingCalls.length === 0) { return { pass: false, - message: () => `The method showVerifiablePresentation was called, but not with the specified token id '${id}', instead with ids '${calls.map((e) => e.token.id).join(", ")}'.` + message: () => + `The method showVerifiablePresentation was called, but not with the specified token id '${id}', instead with ids '${calls.map((e) => e.token.id).join(", ")}'.` }; } diff --git a/packages/app-runtime/test/lib/MockUIBridge.ts b/packages/app-runtime/test/lib/MockUIBridge.ts index 801ec95e0..d2e63a6c9 100644 --- a/packages/app-runtime/test/lib/MockUIBridge.ts +++ b/packages/app-runtime/test/lib/MockUIBridge.ts @@ -1,6 +1,16 @@ import { ApplicationError, Result } from "@js-soft/ts-utils"; import { OpenId4VciCredentialResponseJSON } from "@nmshd/consumption"; -import { DeviceOnboardingInfoDTO, FileDVO, IdentityDVO, LocalRequestDVO, MailDVO, MessageDVO, RequestMessageDVO, ResolveAuthorizationRequestResponse, TokenDTO } from "@nmshd/runtime"; +import { + DeviceOnboardingInfoDTO, + FileDVO, + IdentityDVO, + LocalRequestDVO, + MailDVO, + MessageDVO, + RequestMessageDVO, + ResolveAuthorizationRequestResponse, + TokenDTO +} from "@nmshd/runtime"; import { IUIBridge, LocalAccountDTO } from "../../src"; export type MockUIBridgeCall = From 2cb2d12281de72bfd89a3809433dbea5b802b015 Mon Sep 17 00:00:00 2001 From: Nicole Ebken Date: Thu, 5 Mar 2026 14:14:31 +0100 Subject: [PATCH 3/5] chore: add isTechnicallyValid param --- packages/app-runtime/src/AppStringProcessor.ts | 3 ++- packages/app-runtime/src/extensibility/ui/IUIBridge.ts | 2 +- packages/app-runtime/test/lib/MockUIBridge.matchers.ts | 9 +++++---- packages/app-runtime/test/lib/MockUIBridge.ts | 6 +++--- .../app-runtime/test/runtime/AppStringProcessor.test.ts | 2 +- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/packages/app-runtime/src/AppStringProcessor.ts b/packages/app-runtime/src/AppStringProcessor.ts index bb0dd4699..1081fdff7 100644 --- a/packages/app-runtime/src/AppStringProcessor.ts +++ b/packages/app-runtime/src/AppStringProcessor.ts @@ -293,7 +293,8 @@ export class AppStringProcessor { const tokenContent = this.parseTokenContent(result.value.value.content); if (tokenContent instanceof VerifiablePresentation) { - await uiBridge.showVerifiablePresentation(account, result.value.value); + // TODO: replace with real validation once implemented + await uiBridge.showVerifiablePresentation(account, result.value.value, true); break; } return Result.fail(AppRuntimeErrors.appStringProcessor.notSupportedTokenContent()); diff --git a/packages/app-runtime/src/extensibility/ui/IUIBridge.ts b/packages/app-runtime/src/extensibility/ui/IUIBridge.ts index 6a38084ef..3830da868 100644 --- a/packages/app-runtime/src/extensibility/ui/IUIBridge.ts +++ b/packages/app-runtime/src/extensibility/ui/IUIBridge.ts @@ -17,7 +17,7 @@ export interface IUIBridge { showMessage(account: LocalAccountDTO, relationship: IdentityDVO, message: MessageDVO | MailDVO | RequestMessageDVO): Promise>; showRelationship(account: LocalAccountDTO, relationship: IdentityDVO): Promise>; showFile(account: LocalAccountDTO, file: FileDVO): Promise>; - showVerifiablePresentation(account: LocalAccountDTO, token: TokenDTO): Promise>; + showVerifiablePresentation(account: LocalAccountDTO, token: TokenDTO, isTechnicallyValid: boolean): Promise>; showDeviceOnboarding(deviceOnboardingInfo: DeviceOnboardingInfoDTO): Promise>; showRequest(account: LocalAccountDTO, request: LocalRequestDVO): Promise>; showResolvedAuthorizationRequest(account: LocalAccountDTO, response: ResolveAuthorizationRequestResponse): Promise>; diff --git a/packages/app-runtime/test/lib/MockUIBridge.matchers.ts b/packages/app-runtime/test/lib/MockUIBridge.matchers.ts index 590719ab1..93300c453 100644 --- a/packages/app-runtime/test/lib/MockUIBridge.matchers.ts +++ b/packages/app-runtime/test/lib/MockUIBridge.matchers.ts @@ -214,7 +214,7 @@ expect.extend({ return { pass: true, message: () => "" }; }, - showVerifiablePresentationCalled(mockUIBridge: unknown, id: string) { + showVerifiablePresentationCalled(mockUIBridge: unknown, id: string, isTechnicallyValid?: boolean) { if (!(mockUIBridge instanceof MockUIBridge)) { throw new Error("This method can only be used with expect(MockUIBridge)."); } @@ -224,12 +224,13 @@ expect.extend({ return { pass: false, message: () => "The method showVerifiablePresentation was not called." }; } - const matchingCalls = calls.filter((x) => x.token.id === id); + const matchingCalls = calls.filter((x) => x.token.id === id && (isTechnicallyValid === undefined || x.isTechnicallyValid === isTechnicallyValid)); if (matchingCalls.length === 0) { + const callsWithData = calls.map((e) => `'${e.token.id}' (isTechnicallyValid: ${e.isTechnicallyValid})`).join(", "); return { pass: false, message: () => - `The method showVerifiablePresentation was called, but not with the specified token id '${id}', instead with ids '${calls.map((e) => e.token.id).join(", ")}'.` + `The method showVerifiablePresentation was called, but not with token id '${id}' and isTechnicallyValid '${isTechnicallyValid}', instead with calls ${callsWithData}.` }; } @@ -286,7 +287,7 @@ declare global { showResolvedCredentialOfferNotCalled(): R; showFileCalled(id: string): R; showFileNotCalled(): R; - showVerifiablePresentationCalled(id: string): R; + showVerifiablePresentationCalled(id: string, isTechnicallyValid?: boolean): R; showVerifiablePresentationNotCalled(): R; showErrorCalled(code: string): R; } diff --git a/packages/app-runtime/test/lib/MockUIBridge.ts b/packages/app-runtime/test/lib/MockUIBridge.ts index d2e63a6c9..2c433ab3a 100644 --- a/packages/app-runtime/test/lib/MockUIBridge.ts +++ b/packages/app-runtime/test/lib/MockUIBridge.ts @@ -17,7 +17,7 @@ export type MockUIBridgeCall = | { method: "showMessage"; account: LocalAccountDTO; relationship: IdentityDVO; message: MessageDVO | MailDVO | RequestMessageDVO } | { method: "showRelationship"; account: LocalAccountDTO; relationship: IdentityDVO } | { method: "showFile"; account: LocalAccountDTO; file: FileDVO } - | { method: "showVerifiablePresentation"; account: LocalAccountDTO; token: TokenDTO } + | { method: "showVerifiablePresentation"; account: LocalAccountDTO; token: TokenDTO; isTechnicallyValid: boolean } | { method: "showDeviceOnboarding"; deviceOnboardingInfo: DeviceOnboardingInfoDTO } | { method: "showRequest"; account: LocalAccountDTO; request: LocalRequestDVO } | { method: "showResolvedAuthorizationRequest"; account: LocalAccountDTO; response: ResolveAuthorizationRequestResponse } @@ -68,8 +68,8 @@ export class MockUIBridge implements IUIBridge { return Promise.resolve(Result.ok(undefined)); } - public showVerifiablePresentation(account: LocalAccountDTO, token: TokenDTO): Promise> { - this._calls.push({ method: "showVerifiablePresentation", account, token }); + public showVerifiablePresentation(account: LocalAccountDTO, token: TokenDTO, isTechnicallyValid: boolean): Promise> { + this._calls.push({ method: "showVerifiablePresentation", account, token, isTechnicallyValid }); return Promise.resolve(Result.ok(undefined)); } diff --git a/packages/app-runtime/test/runtime/AppStringProcessor.test.ts b/packages/app-runtime/test/runtime/AppStringProcessor.test.ts index fde72e1fe..1d3c826a1 100644 --- a/packages/app-runtime/test/runtime/AppStringProcessor.test.ts +++ b/packages/app-runtime/test/runtime/AppStringProcessor.test.ts @@ -392,7 +392,7 @@ describe("AppStringProcessor", function () { expect(result).toBeSuccessful(); expect(result.value).toBeUndefined(); - expect(runtime4MockUiBridge).showVerifiablePresentationCalled(token.id); + expect(runtime4MockUiBridge).showVerifiablePresentationCalled(token.id, true); }); test("get a template using a url", async function () { From 43f3ba65a413988327217385759e3645dc72d0ec Mon Sep 17 00:00:00 2001 From: Nicole Ebken Date: Thu, 5 Mar 2026 15:22:04 +0100 Subject: [PATCH 4/5] chore: run audit fix --- package-lock.json | 100 +++++++++++++++++----------------------------- 1 file changed, 37 insertions(+), 63 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0ac7b1756..930950aa9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3778,9 +3778,9 @@ } }, "node_modules/@npmcli/package-json/node_modules/minimatch": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.2.tgz", - "integrity": "sha512-+G4CpNBxa5MprY+04MbgOw1v7So6n5JY166pFi9KfYwT78fxScCeSNQSNzp6dpPSW2rONOps6Ocam1wFhCgoVw==", + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -4755,9 +4755,9 @@ } }, "node_modules/@tufjs/models/node_modules/minimatch": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.2.tgz", - "integrity": "sha512-+G4CpNBxa5MprY+04MbgOw1v7So6n5JY166pFi9KfYwT78fxScCeSNQSNzp6dpPSW2rONOps6Ocam1wFhCgoVw==", + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -5324,37 +5324,24 @@ "typescript": ">=4.8.4 <6.0.0" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", - "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" + "balanced-match": "^1.0.0" } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.6.tgz", - "integrity": "sha512-kQAVowdR33euIqeA0+VZTDqU+qo1IeVY+hrKYtZMio3Pg0P0vuh/kwRylLUddJhB6pf3q/botcOvRtx4IN1wqQ==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^5.0.2" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -6831,9 +6818,9 @@ } }, "node_modules/cacache/node_modules/minimatch": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.2.tgz", - "integrity": "sha512-+G4CpNBxa5MprY+04MbgOw1v7So6n5JY166pFi9KfYwT78fxScCeSNQSNzp6dpPSW2rONOps6Ocam1wFhCgoVw==", + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -9150,37 +9137,24 @@ "node": ">=10.13.0" } }, - "node_modules/glob/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, "node_modules/glob/node_modules/brace-expansion": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", - "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" + "balanced-match": "^1.0.0" } }, "node_modules/glob/node_modules/minimatch": { - "version": "9.0.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.6.tgz", - "integrity": "sha512-kQAVowdR33euIqeA0+VZTDqU+qo1IeVY+hrKYtZMio3Pg0P0vuh/kwRylLUddJhB6pf3q/botcOvRtx4IN1wqQ==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^5.0.2" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -9523,9 +9497,9 @@ } }, "node_modules/ignore-walk/node_modules/minimatch": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.2.tgz", - "integrity": "sha512-+G4CpNBxa5MprY+04MbgOw1v7So6n5JY166pFi9KfYwT78fxScCeSNQSNzp6dpPSW2rONOps6Ocam1wFhCgoVw==", + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -11401,9 +11375,9 @@ "license": "MIT" }, "node_modules/minimatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.3.tgz", - "integrity": "sha512-M2GCs7Vk83NxkUyQV1bkABc4yxgz9kILhHImZiBPAZ9ybuvCb0/H7lEl5XvIg3g+9d4eNotkZA5IWwYl0tibaA==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -13325,9 +13299,9 @@ } }, "node_modules/readdir-glob/node_modules/minimatch": { - "version": "5.1.7", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.7.tgz", - "integrity": "sha512-FjiwU9HaHW6YB3H4a1sFudnv93lvydNjz2lmyUXR6IwKhGI+bgL3SOZrBGn6kvvX2pJvhEkGSGjyTHN47O4rqA==", + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", "dev": true, "license": "ISC", "dependencies": { @@ -14637,9 +14611,9 @@ } }, "node_modules/tar": { - "version": "7.5.9", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.9.tgz", - "integrity": "sha512-BTLcK0xsDh2+PUe9F6c2TlRp4zOOBMTkoQHQIWSIzI0R7KG46uEwq4OPk2W7bZcprBMsuaeFsqwYr7pjh6CuHg==", + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.10.tgz", + "integrity": "sha512-8mOPs1//5q/rlkNSPcCegA6hiHJYDmSLEI8aMH/CdSQJNWztHC9WHNam5zdQlfpTwB9Xp7IBEsHfV5LKMJGVAw==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { From d23214fad3e126a84fe06dba4346e1b5f87299ac Mon Sep 17 00:00:00 2001 From: Nicole Ebken Date: Fri, 6 Mar 2026 13:51:13 +0100 Subject: [PATCH 5/5] chore: pr comments --- packages/app-runtime/src/AppStringProcessor.ts | 2 +- .../app-runtime/test/lib/MockUIBridge.matchers.ts | 12 ++++++++---- .../test/runtime/AppStringProcessor.test.ts | 4 ++-- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/packages/app-runtime/src/AppStringProcessor.ts b/packages/app-runtime/src/AppStringProcessor.ts index 1081fdff7..167d13381 100644 --- a/packages/app-runtime/src/AppStringProcessor.ts +++ b/packages/app-runtime/src/AppStringProcessor.ts @@ -293,7 +293,7 @@ export class AppStringProcessor { const tokenContent = this.parseTokenContent(result.value.value.content); if (tokenContent instanceof VerifiablePresentation) { - // TODO: replace with real validation once implemented + // TODO: add technical validation await uiBridge.showVerifiablePresentation(account, result.value.value, true); break; } diff --git a/packages/app-runtime/test/lib/MockUIBridge.matchers.ts b/packages/app-runtime/test/lib/MockUIBridge.matchers.ts index 93300c453..cd2be3394 100644 --- a/packages/app-runtime/test/lib/MockUIBridge.matchers.ts +++ b/packages/app-runtime/test/lib/MockUIBridge.matchers.ts @@ -214,7 +214,7 @@ expect.extend({ return { pass: true, message: () => "" }; }, - showVerifiablePresentationCalled(mockUIBridge: unknown, id: string, isTechnicallyValid?: boolean) { + showVerifiablePresentationCalled(mockUIBridge: unknown, id: string, isTechnicallyValid: boolean) { if (!(mockUIBridge instanceof MockUIBridge)) { throw new Error("This method can only be used with expect(MockUIBridge)."); } @@ -224,7 +224,7 @@ expect.extend({ return { pass: false, message: () => "The method showVerifiablePresentation was not called." }; } - const matchingCalls = calls.filter((x) => x.token.id === id && (isTechnicallyValid === undefined || x.isTechnicallyValid === isTechnicallyValid)); + const matchingCalls = calls.filter((x) => x.token.id === id && x.isTechnicallyValid === isTechnicallyValid); if (matchingCalls.length === 0) { const callsWithData = calls.map((e) => `'${e.token.id}' (isTechnicallyValid: ${e.isTechnicallyValid})`).join(", "); return { @@ -243,7 +243,11 @@ expect.extend({ const calls = mockUIBridge.calls.filter((x) => x.method === "showVerifiablePresentation"); if (calls.length > 0) { - return { pass: false, message: () => `The method showVerifiablePresentation called: ${calls.map((c) => `'account id: ${c.account.id} - tokenId: ${c.token.id}'`)}` }; + return { + pass: false, + message: () => + `The method showVerifiablePresentation called: ${calls.map((c) => `'account id: ${c.account.id} - tokenId: ${c.token.id} - isTechnicallyValid: ${c.isTechnicallyValid}'`)}` + }; } return { pass: true, message: () => "" }; @@ -287,7 +291,7 @@ declare global { showResolvedCredentialOfferNotCalled(): R; showFileCalled(id: string): R; showFileNotCalled(): R; - showVerifiablePresentationCalled(id: string, isTechnicallyValid?: boolean): R; + showVerifiablePresentationCalled(id: string, isTechnicallyValid: boolean): R; showVerifiablePresentationNotCalled(): R; showErrorCalled(code: string): R; } diff --git a/packages/app-runtime/test/runtime/AppStringProcessor.test.ts b/packages/app-runtime/test/runtime/AppStringProcessor.test.ts index 1d3c826a1..a9d005554 100644 --- a/packages/app-runtime/test/runtime/AppStringProcessor.test.ts +++ b/packages/app-runtime/test/runtime/AppStringProcessor.test.ts @@ -380,8 +380,8 @@ describe("AppStringProcessor", function () { test("get a token with verifiable presentation content using a url", async function () { const tokenResult = await runtime1Session.transportServices.tokens.createOwnToken({ content: VerifiablePresentation.from({ - value: { tokenContent: "test" }, - type: "VerifiablePresentation" + value: { claim: "test" }, + type: "dc+sd-jwt" }).toJSON(), expiresAt: CoreDate.utc().add({ days: 1 }).toISOString(), ephemeral: true