Skip to content

Commit

Permalink
Merge pull request #186 from TimoGlastra/feature/mdoc-parsing-mulitple
Browse files Browse the repository at this point in the history
feat: support multi-document mdoc device response
  • Loading branch information
sanderPostma authored Nov 1, 2024
2 parents 0b9c601 + b40cbc5 commit 4cabdd3
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 7 deletions.
24 changes: 23 additions & 1 deletion lib/evaluation/evaluationClientWrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
IVerifiablePresentation,
OriginalVerifiableCredential,
SdJwtDecodedVerifiableCredential,
WrappedMdocCredential,
WrappedVerifiableCredential,
WrappedVerifiablePresentation,
} from '@sphereon/ssi-types';
Expand Down Expand Up @@ -416,6 +417,8 @@ export class EvaluationClientWrapper {
warnings: [],
};

// Reset and configure the evaluation client on each iteration
this._client = new EvaluationClient();
this._client.evaluate(pd, allWvcs, opts);
result.warnings = this.formatNotInfo(Status.WARN);
result.errors = this.formatNotInfo(Status.ERROR);
Expand Down Expand Up @@ -645,7 +648,7 @@ export class EvaluationClientWrapper {

vc = extractionResult.wvc;
vcPath += ` with nested credential ${descriptor.path_nested.path}`;
} else if (descriptor.format === 'vc+sd-jwt' || descriptor.format === 'mso_mdoc') {
} else if (descriptor.format === 'vc+sd-jwt') {
if (!matchingVp.vcs || !matchingVp.vcs.length) {
result.areRequiredCredentialsPresent = Status.ERROR;
result.errors?.push({
Expand All @@ -656,6 +659,25 @@ export class EvaluationClientWrapper {
continue;
}
vc = matchingVp.vcs[0];
} else if (descriptor.format === 'mso_mdoc') {
// We already know the format is mso_mdoc so this cast is safe
const vcs = matchingVp.vcs as WrappedMdocCredential[];
vcPath += ` with nested mdoc with doctype ${descriptor.id}`;

const matchingVc = vcs.find((vc) => descriptor.id === vc.credential.docType.asStr);

if (!matchingVc) {
const allDoctypes = vcs.map((vc) => `'${vc.credential.docType.asStr}'`).join(', ');
result.areRequiredCredentialsPresent = Status.ERROR;

Check warning on line 671 in lib/evaluation/evaluationClientWrapper.ts

View check run for this annotation

Codecov / codecov/patch

lib/evaluation/evaluationClientWrapper.ts#L670-L671

Added lines #L670 - L671 were not covered by tests
result.errors?.push({
status: Status.ERROR,
tag: 'NoCredentialsFound',
message: `No mdoc credential with doctype '${descriptor.id}' found in mdoc vp. Available documents are ${allDoctypes}`,
});
continue;

Check warning on line 677 in lib/evaluation/evaluationClientWrapper.ts

View check run for this annotation

Codecov / codecov/patch

lib/evaluation/evaluationClientWrapper.ts#L677

Added line #L677 was not covered by tests
}

vc = matchingVc;
} else {
result.areRequiredCredentialsPresent = Status.ERROR;
result.errors?.push({
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"@sd-jwt/present": "^0.7.2",
"@sd-jwt/types": "^0.7.2",
"@sphereon/pex-models": "^2.3.1",
"@sphereon/ssi-types": "0.30.2-next.129",
"@sphereon/ssi-types": "0.30.2-next.135",
"ajv": "^8.12.0",
"ajv-formats": "^2.1.1",
"jwt-decode": "^3.1.2",
Expand Down
10 changes: 5 additions & 5 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

50 changes: 50 additions & 0 deletions test/Mdoc.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import { SubmissionRequirementMatchType } from '../lib/evaluation/core';

export const hasher = (data: string) => createHash('sha256').update(data).digest();

const mdocBase64UrlMultipleDocumentsPresentation =
'uQADZ3ZlcnNpb25jMS4waWRvY3VtZW50c4KjZ2RvY1R5cGV1b3JnLmlzby4xODAxMy41LjEubURMbGlzc3VlclNpZ25lZLkAAmpuYW1lU3BhY2VzoXFvcmcuaXNvLjE4MDEzLjUuMYHYGFhipGhkaWdlc3RJRAFxZWxlbWVudElkZW50aWZpZXJqZ2l2ZW5fbmFtZWxlbGVtZW50VmFsdWVjQXZhZnJhbmRvbVggKtvEv2_zGjeiQxMF6Qr_ubn_R7oUADdffjsLaAleH_VqaXNzdWVyQXV0aIRDoQEmogRYMXpEbmFlcnR6VllXOFJFenplZzl0QUVEN3E1UFhTV2lpUFZkQnFodVZpRVdUdW84TGEYIYFZAi4wggIqMIIB0KADAgECAhRXxszTCL3kPso3RPKocTjau7iE6DAKBggqhkjOPQQDAjBTMQswCQYDVQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxDzANBgNVBAcMBkFsYmFueTEPMA0GA1UECgwGTlkgRE1WMQ8wDQYDVQQLDAZOWSBETVYwHhcNMjMwOTE0MTQ1NTE4WhcNMzMwOTExMTQ1NTE4WjBTMQswCQYDVQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxDzANBgNVBAcMBkFsYmFueTEPMA0GA1UECgwGTlkgRE1WMQ8wDQYDVQQLDAZOWSBETVYwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASJPC2DR5Btxs1pt_Y2r0v9Uz-WGE8KrazRCDDaRHHb22CsFw0c_FNPri2dzUiPd0f9-XjZJeox6ekIPDgrqe1To4GBMH8wHQYDVR0OBBYEFKttLgO5HUkiQDOPvMre_ZMz6vbHMB8GA1UdIwQYMBaAFKttLgO5HUkiQDOPvMre_ZMz6vbHMA8GA1UdEwEB_wQFMAMBAf8wLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMAoGCCqGSM49BAMCA0gAMEUCIAn9DKuXsD549k5019zuiGaMR2oK_Fqizr_-B9O-dy6pAiEA2jiryYoID0nyT_7OH__Ips3VssC12o_Ht2esOpXcuD5ZBJjYGFkEk7kABmd2ZXJzaW9uYzEuMG9kaWdlc3RBbGdvcml0aG1nU0hBLTI1Nmx2YWx1ZURpZ2VzdHOhcW9yZy5pc28uMTgwMTMuNS4xuBgAWCCbhqm6X1E0NzApTQbm806eplorHKwV1j97TVuIvlHcIgFYIDVFLRh8V5cYmighiiOv6deYv_L8TsUBru1rL75aNJd7AlggD2Z1ozETPthnxZgrNEmQ_v9KWeeNDIduTp5uLnjVGIwDWCDp1Ll490dE-v3H_UbC5lN9Cg71m3awpdc_x2YGPuR1nQRYIHJ2yhtpIJWWdRUdV9oI6thFN2Whfld5Gxxe540WmFgrBVgg62E26LqOHli6OXczPaQEt44_jRFNksmt9j_OXnHlp2wGWCA1C_FRU_BFvHnKPWnDrswG-CjzW9pSe-XVfN40gYSBFQdYIAFk-KqrP_fpvMNhGtReBkf0ag9AzMQCqtUgF4ADsoOzCFggUGLIURDcD_MFlVPsukIX58xzxfwnmc7WmpTNlQIhJ74JWCC-R-QqQyqc6tFDepghyhm3j_wSCARrAa6o0DDJg-2evQpYIAY-QMinqw69wWEISG0bcYGiLx5AOadHoV0bKyN2Dks6C1gg_71wnC-37xSXHLVtgY-vAmRiEjUa8d3EzdiZFCEHG4EMWCA-TAbVFGvwy5AXWS6FHEX3RIys3q6F9Z372ei0UN0JRw1YIEOi-MwtUJ2l_ixrk2cy3O1mRTBcAIM5uIJx2eUUWx89Dlggd-ab0Cuj2yC_k6Fur3_1Ihw692ETl1ZAkaB35LXd1qoPWCCIUclY01QUZkGAFsAnhvpomj41LToq5VEAhi3EP17maBBYIJuBcjlWhR5hUzjMsPeR3gveLqJAMfpVwjBvuGXIZE8CEVgg97JhkE0VdgjaeJRMdGRgLZkUkafO0La7go_4SY3TKZASWCDBeESPPAwGCecC2NO5fOK9EKHmLb0qwo1xtHgR8OgH3RNYIMc3W8dbiJfha69dWm13wqGPViKcGGKX8pMn0KEw5FseFFggJnQlhJ5hQMKE2LWtXUhc3RlB1Q-CXx4nURpUQQWac1UVWCDzG025GiQJK11hBSbVvJqaWYYHCDcbIczVuvGk6JH55hZYIGHapaMrTh5UV5vq0YKWgm4Yn3Sa_g4Sk1WAZMa9LGOdF1ggAAU91pJ-GWSAPAftY-gyIjQdUdI4qIEwslpm4yXkU4ltZGV2aWNlS2V5SW5mb7kAAWlkZXZpY2VLZXmkAQIgASFYIIgYecp6I4sZvw9MH4wA6aLhm6em9z6ukrhR1N4bUIVZIlggoxS1OAORJ7XNUHNfVFGeM8E0RQVFxWA62fJj-sxW03dnZG9jVHlwZXVvcmcuaXNvLjE4MDEzLjUuMS5tRExsdmFsaWRpdHlJbmZvuQAEZnNpZ25lZMB0MjAyMy0xMC0yNFQwMDowMDowMFppdmFsaWRGcm9twHQyMDIzLTEwLTI0VDAwOjAwOjAwWmp2YWxpZFVudGlswHQyMDUwLTEwLTI0VDAwOjAwOjAwWm5leHBlY3RlZFVwZGF0ZfdYQCuk_3TNOL-d7XCpcWK62Xd7j7nBVKettDLfYovq0UGxJmmiLcbGESoHNK_t7Eem1NM5nbxVby6e97wC-vOa9QpsZGV2aWNlU2lnbmVkuQACam5hbWVTcGFjZXPYGFgguQABcWNvbS5mb29iYXItZGV2aWNluQABZHRlc3QZBNJqZGV2aWNlQXV0aLkAAm9kZXZpY2VTaWduYXR1cmWEQ6EBJqD3WED1J2uMcDM9U4ueL9jHIDYeOlKWfWo2hcnTCBMbd4K5gsc9WoeefXiD-m_kOg_Z1HQr2J6S2Rkq6tLj8Vt0hFlUaWRldmljZU1hY_ejZ2RvY1R5cGV2b3JnLmlzby4xODAxMy41LjEubURMMmxpc3N1ZXJTaWduZWS5AAJqbmFtZVNwYWNlc6Fxb3JnLmlzby4xODAxMy41LjGB2BhYZaRoZGlnZXN0SUQAcWVsZW1lbnRJZGVudGlmaWVya2ZhbWlseV9uYW1lbGVsZW1lbnRWYWx1ZWVKb25lc2ZyYW5kb21YICjmHbyr5i-QHqN7DrJ_a7n13KdAoXcSMry4Eg4w5fgzamlzc3VlckF1dGiEQ6EBJqIEWDF6RG5hZXJ0elZZVzhSRXp6ZWc5dEFFRDdxNVBYU1dpaVBWZEJxaHVWaUVXVHVvOExhGCGBWQIuMIICKjCCAdCgAwIBAgIUV8bM0wi95D7KN0TyqHE42ru4hOgwCgYIKoZIzj0EAwIwUzELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE5ldyBZb3JrMQ8wDQYDVQQHDAZBbGJhbnkxDzANBgNVBAoMBk5ZIERNVjEPMA0GA1UECwwGTlkgRE1WMB4XDTIzMDkxNDE0NTUxOFoXDTMzMDkxMTE0NTUxOFowUzELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE5ldyBZb3JrMQ8wDQYDVQQHDAZBbGJhbnkxDzANBgNVBAoMBk5ZIERNVjEPMA0GA1UECwwGTlkgRE1WMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEiTwtg0eQbcbNabf2Nq9L_VM_lhhPCq2s0Qgw2kRx29tgrBcNHPxTT64tnc1Ij3dH_fl42SXqMenpCDw4K6ntU6OBgTB_MB0GA1UdDgQWBBSrbS4DuR1JIkAzj7zK3v2TM-r2xzAfBgNVHSMEGDAWgBSrbS4DuR1JIkAzj7zK3v2TM-r2xzAPBgNVHRMBAf8EBTADAQH_MCwGCWCGSAGG-EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAKBggqhkjOPQQDAgNIADBFAiAJ_Qyrl7A-ePZOdNfc7ohmjEdqCvxaos6__gfTvncuqQIhANo4q8mKCA9J8k_-zh__yKbN1bLAtdqPx7dnrDqV3Lg-WQRS2BhZBE25AAZndmVyc2lvbmMxLjBvZGlnZXN0QWxnb3JpdGhtZ1NIQS0yNTZsdmFsdWVEaWdlc3RzoXFvcmcuaXNvLjE4MDEzLjUuMbYAWCBspl7DfYDOvpurPt2i7bECpR_CxWkc0ftjJb3IWQKizAFYINJd2OxXubpYtP1fQuq_m5qj1WZfggyxQJB176PKesjZAlgg2fpl2GcK-NiHunbydaPffpIEBsk0azuhsCMDtF0sGUMDWCB7dncdX3bhyUgGEH-Nt_0XDdxnTDhm7MD1LN3N_9UG2gRYIPD0bJr8et4oN_yE-v4OVgLmQXBncX2h74iwKfQwwnjmBVggO91tvX3RnpbOKiK2uWxG0afEarBFyuokHfLpZHQNRXEGWCA7R0deBjGLG6gDIXiLiluD9QAyX-kU3ZivuE3CHMc-jQdYIJicukNkihAFdmr2hkU_Yn-1IybmkSGG4fRkV5fbtOEjCFgg65A7sq2OzMZkOwLx3G2wRrWvLXvAN-aqgFGkblUiGOEJWCDtuAgjFwjiC5uqQNVX5oPWBCi0Su_rKRaElw3I7MyKZQpYIIwZrXczzPMQx4qWLY5gaj7k6FG62XUCO-HbXDyI-P9VC1ggJQGFWrCOV4UoXa-djAkWtMKfb4qyvcWSuwx87VtgCpMMWCCXDoaqc3ujqRNNxt-57hKXe5XnCV5MxKXGDyay8ld8_g1YIPr06swH7rUA6RJn9xqQz8zsg1ZVL8qljqAqx7XqmJ9XDlggjOyvASBPEZ9rowf-9Do8JCD17tDJH7i-PkhikRRyCwMPWCBmxeurMT_vkKplQN4wXHXnJ_Qt4My1-gQHstZ3ZLJuuBBYIJ-V_3fPcn4YEGlWBHorbYplnLHOudZj86bh-nAQ2NjREVggYI5T0DZ5D6F2pk5vBPQYA1FFCKqrYfZYTFUqdjH3aG4SWCDZZ61yZ36JdMPOzfxTYc37jZRXEUWCX62s6U6RGOjXuRNYIDNsxIZpiBHzPLpOHZ5BWPfB1SNbOWuEkpNwmE1BCHoBFFggFiDdelk38QU9OYNQc6-runF9lQ6SMWXa_mpDezO3OpYVWCCGzVNBY_K1t1Z5jMRhCkBF0M1F_KlYCpFe8-FiCtTvf21kZXZpY2VLZXlJbmZvuQABaWRldmljZUtleaQBAiABIVggiBh5ynojixm_D0wfjADpouGbp6b3Pq6SuFHU3htQhVkiWCCjFLU4A5Entc1Qc19UUZ4zwTRFBUXFYDrZ8mP6zFbTd2dkb2NUeXBldm9yZy5pc28uMTgwMTMuNS4xLm1ETDJsdmFsaWRpdHlJbmZvuQAEZnNpZ25lZMB0MjAyMy0xMC0yNFQwMDowMDowMFppdmFsaWRGcm9twHQyMDIzLTEwLTI0VDAwOjAwOjAwWmp2YWxpZFVudGlswHQyMDUwLTEwLTI0VDAwOjAwOjAwWm5leHBlY3RlZFVwZGF0ZfdYQDCYDNssyMNy_WCG58n1hWFNMWvVFbDxBkKmyroaku2P6Esbgc2tAq2--QdqQD1719lO_8a_Ksy_rNQimT_x2ZNsZGV2aWNlU2lnbmVkuQACam5hbWVTcGFjZXPYGFgguQABcWNvbS5mb29iYXItZGV2aWNluQABZHRlc3QZBNJqZGV2aWNlQXV0aLkAAm9kZXZpY2VTaWduYXR1cmWEQ6EBJqD3WEDNmpI321UjyotZjGVsv4NUNVdXGVVxfgyjLiMqp4ukNWJ53psdhfY3LlP4CIJcmo8vAu9Voko0-VcU1Z-PcBCNaWRldmljZU1hY_dmc3RhdHVzAA';

const mdocBase64UrlUniversityCustomNamespace =
'uQACam5hbWVTcGFjZXOhanVuaXZlcnNpdHmE2BhYZqRoZGlnZXN0SUQAcWVsZW1lbnRJZGVudGlmaWVyaGxvY2F0aW9ubGVsZW1lbnRWYWx1ZWlpbm5zYnJ1Y2tmcmFuZG9tWCAw6CXtd4ubXAr6uLB1GnfRyHVqhjH1_73iDASmcZefQtgYWGOkaGRpZ2VzdElEAXFlbGVtZW50SWRlbnRpZmllcmZkZWdyZWVsZWxlbWVudFZhbHVlaGJhY2hlbG9yZnJhbmRvbVgglzuY8jgQd7y_wuH47AYfzlEfzz827RRjo4k845nK5DLYGFhhpGhkaWdlc3RJRAJxZWxlbWVudElkZW50aWZpZXJkbmFtZWxlbGVtZW50VmFsdWVoSm9obiBEb2VmcmFuZG9tWCDtU0gwjxNPz1q2AjgYWkAGWSHDq7BsXzns_aMMNeVkE9gYWGGkaGRpZ2VzdElEA3FlbGVtZW50SWRlbnRpZmllcmNub3RsZWxlbWVudFZhbHVlaWRpc2Nsb3NlZGZyYW5kb21YICSQ7u_6OBRr8V3c5hmIeL-NKBPEaUGWPxkv8TwTPdTbamlzc3VlckF1dGiEQ6EBJqIEWDF6RG5hZWRydmd5bXpvZnhvYTRWb1VDOFJRemdwMVJnZnBCTkw1SFZuV1NKb1oyeXJhGCGBWPwwgfkwgaCgAwIBAgIQTWQTeD9zo_1knyJtFXU2hzAKBggqhkjOPQQDAjANMQswCQYDVQQGEwJERTAeFw0yNDEwMzAxNDA5MDRaFw0yNTEwMzAxNDA5MDRaMA0xCzAJBgNVBAYTAkRFMDkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDIgACx4zJR4xIci9iFJPsMUX-mu4Khh63a_hjQKef7NyM2cOjAjAAMAoGCCqGSM49BAMCA0gAMEUCIQCRXFKtPshVsgBYMjH1-VA2sU2bphzWRLYrYvALfGTBdQIgLHF1n5J7KAiDhPTjmx3xxBlCVMYan_SKqXKxZVuO1M1ZAdDYGFkBy7kABmd2ZXJzaW9uYzEuMG9kaWdlc3RBbGdvcml0aG1nU0hBLTI1Nmx2YWx1ZURpZ2VzdHOhanVuaXZlcnNpdHmkAFggkN_ol8cnR2iCh3YLAYSt_-gt_hUT9ZIlm1LCS2kHW3gBWCAz2zbutIrJdbeAGi1T64jyst4PtE9WwjJK2-py9dyafQJYIHoRBZqOeV9IhNcbYsK46RaA95WyT7mq6-yqoh6j6Ds-A1ggwzOqmOGhsmiCMaEugAowlgUkzNxl0tD4CgbIx5u1Xx9tZGV2aWNlS2V5SW5mb7kAAWlkZXZpY2VLZXmkAQIgASFYIHhQ3snZrFRdtxGAB4HPsgmtZXHpzztrXjQXPRurqHtwIlggG9V2VQ1XAa9BRwxpgguzfhtP0gz8M52TWYDLwbe0P4ZnZG9jVHlwZXFvcmcuZXUudW5pdmVyc2l0eWx2YWxpZGl0eUluZm-5AARmc2lnbmVkwHQyMDI0LTEwLTMwVDE0OjA5OjA0Wml2YWxpZEZyb23AdDIwMjQtMTAtMzBUMTQ6MDk6MDRaanZhbGlkVW50aWzAdDIwMjUtMTAtMzBUMTQ6MDk6MDRabmV4cGVjdGVkVXBkYXRl91hAjkeOGOUm0CToTYOf0x3mtHFIzwT_LTHUYvcWaWrksmBOuUgZekkHAo9Bl9UTI0NKhEBIbKv9mGWHwJUgQ_1AIw';

Expand Down Expand Up @@ -159,6 +162,53 @@ describe('evaluate mdoc', () => {
});
});

it('evaluatePresentation with mso_mdoc format where mdoc device response contains multiple documents', async () => {
const definition: PresentationDefinitionV2 = {
id: 'mDL-sample-req',
input_descriptors: [
{
id: 'org.iso.18013.5.1.mDL2',
format: {
mso_mdoc: {
alg: ['ES256', 'ES384', 'ES512', 'EdDSA', 'ESB256', 'ESB320', 'ESB384', 'ESB512'],
},
},
constraints: {
fields: [
{
path: ["$['org.iso.18013.5.1']['family_name']"],
intent_to_retain: false,
},
],
limit_disclosure: 'required',
},
},
],
};
const submission = {
definition_id: definition.id,
descriptor_map: [
{
format: 'mso_mdoc',
id: 'org.iso.18013.5.1.mDL2',
path: '$[0]',
},
],
id: '2d0b0be7-9d91-4760-ad58-f204f9f39de7',
};
const evaluateResults = pex.evaluatePresentation(definition, [mdocBase64UrlMultipleDocumentsPresentation], {
presentationSubmission: submission,
});

expect(evaluateResults).toEqual({
presentations: [mdocBase64UrlMultipleDocumentsPresentation],
areRequiredCredentialsPresent: Status.INFO,
warnings: [],
errors: [],
value: submission,
});
});

it('evaluatePresentation with mso_mdoc format generating a submission', async () => {
const presentationDefinition = getPresentationDefinitionV2();
const evaluateResults = pex.evaluatePresentation(presentationDefinition, [mdocBase64UrlUniversityPresentation], {
Expand Down

0 comments on commit 4cabdd3

Please sign in to comment.