@originator-profile/verify 0.4.0 → 0.5.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,7 +1,8 @@
1
1
  import { JwtVcVerifier, VcValidateFailed, VcVerifyFailed, JwtVcDecoder } from '@originator-profile/securing-mechanism';
2
- import { createDigestSri, selectByIntegrity, fetchExternalResource, selectByCss, fetchVisibleTextContent, fetchTextContent, fetchHtmlContent } from '@originator-profile/sign';
2
+ import { createDigestSri, selectByIntegrity, fetchExternalResource, selectByCss, fetchVisibleTextContent, fetchTextContent, fetchHtmlContent, FetchFailed } from '@originator-profile/sign';
3
3
  import { LocalKeys } from '@originator-profile/cryptography';
4
- import { ContentAttestation, CoreProfile, Certificate, JapaneseExistenceCertificate, WebMediaProfile, WebsiteProfile, CertificationSystem } from '@originator-profile/model';
4
+ import { ContentAttestation, CoreProfile, Certificate, JapaneseExistenceCertificate, WebMediaProfile, WebsiteProfile } from '@originator-profile/model';
5
+ import { z } from 'zod';
5
6
 
6
7
  class CaInvalid extends Error {
7
8
  constructor(message, result) {
@@ -24,34 +25,6 @@ class CaVerifyFailed extends Error {
24
25
  code = CaVerifyFailed.code;
25
26
  }
26
27
 
27
- function verifyAllowedOrigin(origin, allowedOrigins) {
28
- if (origin === "null") {
29
- return false;
30
- }
31
- return [allowedOrigins].flat().includes(origin);
32
- }
33
-
34
- async function importURLPatternPolyfill() {
35
- if (typeof URLPattern === "undefined") {
36
- await import('./index-CQxI_8IG.mjs');
37
- }
38
- }
39
- function ReplaceEncode(url) {
40
- return url.replace(/(%[0-9a-f]{2}?)+/g, function(match) {
41
- return match.toUpperCase();
42
- });
43
- }
44
- async function verifyAllowedUrl(url, allowedUrl) {
45
- await importURLPatternPolyfill();
46
- return [allowedUrl].flat().some((value) => {
47
- if (!value) {
48
- return false;
49
- }
50
- const pattern = new URLPattern(ReplaceEncode(value));
51
- return pattern.test(ReplaceEncode(url));
52
- });
53
- }
54
-
55
28
  const supportedHashAlgorithms = {
56
29
  /** SHA-256 hash algorithm */
57
30
  sha256: "SHA-256",
@@ -326,12 +299,62 @@ async function createIntegrityMetadataSet(hashAlgorithms, data, options = {
326
299
  return new IntegrityMetadataSet(set, options);
327
300
  }
328
301
 
302
+ const WARN_SUFFIX = `This will become an error after 2027. See: https://docs.originator-profile.org/en/opb/context/#the-image-datatype`;
329
303
  async function verifyDigestSri(content, fetcher = fetch) {
330
304
  const integrity = new IntegrityMetadataSet(content.digestSRI);
331
305
  const alg = integrity.strongestHashAlgorithms.filter(Boolean);
332
306
  if (alg.length === 0) return false;
333
- const { digestSRI } = await createDigestSri(alg[0], content, fetcher);
334
- return integrity.match(digestSRI);
307
+ try {
308
+ const result = await createDigestSri(alg[0], content, fetcher);
309
+ return "digestSRI" in result && integrity.match(result.digestSRI);
310
+ } catch (error) {
311
+ console.error(
312
+ "Failed to access content for digestSRI verification:",
313
+ error
314
+ );
315
+ return false;
316
+ }
317
+ }
318
+ async function verifyImageDigestSri(value, fetcher = fetch) {
319
+ if (!value) return;
320
+ if (!value.digestSRI) {
321
+ console.warn(`digestSRI is missing. ${WARN_SUFFIX}`);
322
+ return;
323
+ }
324
+ const valid = await verifyDigestSri(
325
+ { id: value.id, digestSRI: value.digestSRI },
326
+ fetcher
327
+ );
328
+ if (!valid) {
329
+ console.warn(`digestSRI verification failed. ${WARN_SUFFIX}`);
330
+ }
331
+ }
332
+
333
+ class IntegrityFetchFailed extends Error {
334
+ static get code() {
335
+ return "ERR_INTEGRITY_FETCH_FAILED";
336
+ }
337
+ code = IntegrityFetchFailed.code;
338
+ ok = false;
339
+ /** 取得結果 */
340
+ result;
341
+ constructor(message, result) {
342
+ super(message);
343
+ this.result = result;
344
+ }
345
+ }
346
+ class IntegrityVerificationFailed extends Error {
347
+ static get code() {
348
+ return "ERR_INTEGRITY_VERIFICATION_FAILED";
349
+ }
350
+ code = IntegrityVerificationFailed.code;
351
+ ok = false;
352
+ /** 取得結果 */
353
+ result;
354
+ constructor(message, result) {
355
+ super(message);
356
+ this.result = result;
357
+ }
335
358
  }
336
359
 
337
360
  class IntegrityVerifier {
@@ -380,7 +403,47 @@ async function verifyIntegrity(content, doc = document, fetcher = fetch) {
380
403
  (content2) => contentFetcher(content2, fetcher),
381
404
  elementSelector
382
405
  );
383
- return await integrityVerifier.verify(content, doc);
406
+ try {
407
+ return await integrityVerifier.verify(content, doc);
408
+ } catch (e) {
409
+ if (e instanceof FetchFailed) {
410
+ return new IntegrityFetchFailed("Verify integrity failed", e.error);
411
+ }
412
+ return new IntegrityVerificationFailed("Verify integrity failed", e);
413
+ }
414
+ }
415
+
416
+ function verifyAllowedOrigin(origin, allowedOrigins) {
417
+ if (origin === "null") {
418
+ return false;
419
+ }
420
+ return [allowedOrigins].flat().includes(origin);
421
+ }
422
+
423
+ async function importURLPatternPolyfill() {
424
+ if (typeof URLPattern === "undefined") {
425
+ await import('./index-CQxI_8IG.mjs');
426
+ }
427
+ }
428
+ function ReplaceEncode(url) {
429
+ return url.replace(/(%[0-9a-f]{2}?)+/g, function(match) {
430
+ return match.toUpperCase();
431
+ });
432
+ }
433
+ async function verifyAllowedUrl(url, allowedUrl) {
434
+ await importURLPatternPolyfill();
435
+ return [allowedUrl].flat().some((value) => {
436
+ if (!value) {
437
+ return false;
438
+ }
439
+ try {
440
+ const pattern = new URLPattern(ReplaceEncode(value));
441
+ return pattern.test(ReplaceEncode(url));
442
+ } catch (e) {
443
+ console.error(`Invalid URLPattern: ${value} (url: ${url})`);
444
+ }
445
+ return false;
446
+ });
384
447
  }
385
448
 
386
449
  async function checkUrlAndOrigin(result, url) {
@@ -406,6 +469,32 @@ async function checkUrlAndOrigin(result, url) {
406
469
  }
407
470
  return result;
408
471
  }
472
+ function checkIntegrityResults(integrityResults, urlResult) {
473
+ const fetchFailedResults = integrityResults.filter(
474
+ (r) => r.verifyResult instanceof Error && r.verifyResult.code === IntegrityFetchFailed.code
475
+ );
476
+ if (fetchFailedResults.length > 0) {
477
+ const failedIntegritiesMessage = fetchFailedResults.map((result) => {
478
+ return `target[${result.index}] Expected: ${result.expectedIntegrity}`;
479
+ }).join(", ");
480
+ return new CaVerifyFailed(
481
+ `Content Attestation Target integrity fetch failed for element(s): ${failedIntegritiesMessage}`,
482
+ urlResult
483
+ );
484
+ }
485
+ const verificationFailedResults = integrityResults.filter(
486
+ (r) => r.verifyResult instanceof Error && r.verifyResult.code === IntegrityVerificationFailed.code
487
+ );
488
+ if (verificationFailedResults.length > 0) {
489
+ const failedIntegritiesMessage = verificationFailedResults.map((result) => {
490
+ return `target[${result.index}] Expected: ${result.expectedIntegrity}`;
491
+ }).join(", ");
492
+ return new CaVerifyFailed(
493
+ `Content Attestation Target integrity verification failed for element(s): ${failedIntegritiesMessage}`,
494
+ urlResult
495
+ );
496
+ }
497
+ }
409
498
  function CaVerifier(ca, keys, issuer, url, verifyIntegrity$1 = verifyIntegrity, validator) {
410
499
  const verifyCa = JwtVcVerifier(keys, issuer, validator);
411
500
  return async () => {
@@ -420,6 +509,9 @@ function CaVerifier(ca, keys, issuer, url, verifyIntegrity$1 = verifyIntegrity,
420
509
  if (urlResult instanceof Error) {
421
510
  return urlResult;
422
511
  }
512
+ await verifyImageDigestSri(
513
+ urlResult.doc.credentialSubject.image
514
+ );
423
515
  if (urlResult.doc.target) {
424
516
  if (urlResult.doc.target.length === 0) {
425
517
  return new CaInvalid("Target is empty", urlResult);
@@ -431,12 +523,19 @@ function CaVerifier(ca, keys, issuer, url, verifyIntegrity$1 = verifyIntegrity,
431
523
  expectedIntegrity: t.integrity
432
524
  }))
433
525
  );
434
- const failedIndices = integrityResults.filter((result2) => !result2.verifyResult.valid).map((result2) => result2.index);
526
+ const error = checkIntegrityResults(integrityResults, urlResult);
527
+ if (error) {
528
+ return error;
529
+ }
530
+ const failedIndices = integrityResults.filter(
531
+ (result2) => !(result2.verifyResult instanceof Error) && !result2.verifyResult.valid
532
+ ).map((result2) => result2.index);
435
533
  if (failedIndices.length > 0) {
436
534
  const failedIntegritiesMessage = failedIndices.map((integrityResultIndex) => {
437
535
  const integrityResult = integrityResults[integrityResultIndex];
438
536
  if (integrityResult) {
439
- const calculatedIntegrities = integrityResult.verifyResult.failedIntegrities.join();
537
+ const verifyResult = integrityResult.verifyResult;
538
+ const calculatedIntegrities = verifyResult.failedIntegrities.join();
440
539
  return `target[${integrityResultIndex}] Expected: ${integrityResult.expectedIntegrity}, Calculated: ${calculatedIntegrities}`;
441
540
  }
442
541
  return void 0;
@@ -512,91 +611,6 @@ async function verifyCas(cas, verifiedOps, url, verifyIntegrity, validator) {
512
611
  return resultCas;
513
612
  }
514
613
 
515
- class ProfileGenericError extends Error {
516
- static get code() {
517
- return "ERR_PROFILE_GENERIC";
518
- }
519
- code = ProfileGenericError.code;
520
- }
521
- class ProfileClaimsValidationFailed extends ProfileGenericError {
522
- static get code() {
523
- return "ERR_PROFILE_CLAIMS_VALIDATION_FAILED";
524
- }
525
- code = ProfileClaimsValidationFailed.code;
526
- /** 復号結果 */
527
- result;
528
- constructor(message, result) {
529
- super(message);
530
- this.result = result;
531
- }
532
- }
533
- class ProfileTokenVerifyFailed extends ProfileGenericError {
534
- static get code() {
535
- return "ERR_PROFILE_TOKEN_VERIFY_FAILED";
536
- }
537
- code = ProfileTokenVerifyFailed.code;
538
- /** 検証結果 */
539
- result;
540
- constructor(message, result) {
541
- super(message);
542
- this.result = result;
543
- }
544
- }
545
- class ProfileBodyExtractFailed extends ProfileGenericError {
546
- static get code() {
547
- return "ERR_PROFILE_BODY_EXTRACT_FAILED";
548
- }
549
- code = ProfileBodyExtractFailed.code;
550
- }
551
- class ProfileBodyVerifyFailed extends ProfileGenericError {
552
- static get code() {
553
- return "ERR_PROFILE_BODY_VERIFY_FAILED";
554
- }
555
- code = ProfileBodyVerifyFailed.code;
556
- /** 検証結果 */
557
- result;
558
- constructor(message, result) {
559
- super(message);
560
- this.result = result;
561
- }
562
- }
563
- class ProfilesResolveFailed extends ProfileGenericError {
564
- static get code() {
565
- return "ERR_PROFILES_RESOLVE_FAILED";
566
- }
567
- code = ProfilesResolveFailed.code;
568
- /** 検証結果 */
569
- result;
570
- constructor(message, result) {
571
- super(message);
572
- this.result = result;
573
- }
574
- }
575
- class ProfilesVerifyFailed extends ProfileGenericError {
576
- static get code() {
577
- return "ERR_PROFILES_VERIFY_FAILED";
578
- }
579
- code = ProfilesVerifyFailed.code;
580
- /** 検証結果 */
581
- result;
582
- constructor(message, result) {
583
- super(message);
584
- this.result = result;
585
- }
586
- }
587
- class CertificationSystemValidationFailed extends ProfileGenericError {
588
- static get code() {
589
- return "ERR_CERTIFICATION_SYSTEM_VALIDATION_FAILED";
590
- }
591
- code = CertificationSystemValidationFailed.code;
592
- /** 検証結果 */
593
- result;
594
- constructor(message, result) {
595
- super(message);
596
- this.result = result;
597
- }
598
- }
599
-
600
614
  var REMOVE = "remove";
601
615
  var REPLACE = "replace";
602
616
  var ADD = "add";
@@ -885,8 +899,44 @@ class OpVerifyFailed extends Error {
885
899
  }
886
900
  code = OpVerifyFailed.code;
887
901
  }
902
+ class CertificateExpired extends Error {
903
+ constructor(message, result) {
904
+ super(message);
905
+ this.result = result;
906
+ }
907
+ static get code() {
908
+ return "ERR_CERTIFICATE_EXPIRED";
909
+ }
910
+ code = CertificateExpired.code;
911
+ }
888
912
 
889
913
  const isEveryDecodedPa = (annotations) => annotations.every((annotation) => "doc" in annotation);
914
+ const isEveryDecodedWmp = (media) => media.every((m) => "doc" in m);
915
+ const validateDecodedOp = (core, annotations, media, resultOp) => {
916
+ if (annotations && !isEveryDecodedPa(annotations)) {
917
+ return new OpInvalid("Profile Annotation decode failed", resultOp);
918
+ }
919
+ if (media && !isEveryDecodedWmp(media)) {
920
+ return new OpInvalid("Web Media Profile decode failed", resultOp);
921
+ }
922
+ if (media && media.some(
923
+ (m) => core.doc.credentialSubject.id !== m.doc.credentialSubject.id
924
+ )) {
925
+ return new OpInvalid(
926
+ "Subject mismatch between Core Profile and Web Media Profile",
927
+ resultOp
928
+ );
929
+ }
930
+ if (annotations && annotations.some(
931
+ (annotation) => core.doc.credentialSubject.id !== annotation.doc.credentialSubject.id
932
+ )) {
933
+ return new OpInvalid(
934
+ "Subject mismatch between Core Profile and Profile Annotation",
935
+ resultOp
936
+ );
937
+ }
938
+ return { type: "valid", annotations, media };
939
+ };
890
940
  const isDecodedOps = (ops) => ops.every((op) => !(op instanceof OpInvalid));
891
941
  function decodeOps(ops) {
892
942
  const decodeCp = JwtVcDecoder();
@@ -895,32 +945,22 @@ function decodeOps(ops) {
895
945
  const resultOps = ops.map((op) => {
896
946
  const core = decodeCp(op.core);
897
947
  const annotations = op.annotations ? op.annotations.map(decodePa) : void 0;
898
- const media = op.media ? decodeWmp(op.media) : void 0;
948
+ const mediaInput = op.media;
949
+ const mediaArray = mediaInput ? Array.isArray(mediaInput) ? mediaInput : [mediaInput] : void 0;
950
+ const media = mediaArray ? mediaArray.map(decodeWmp) : void 0;
899
951
  const resultOp = { core, annotations, media };
900
952
  if (core instanceof Error) {
901
953
  return new OpInvalid("Core Profile decode failed", resultOp);
902
954
  }
903
- if (annotations && !isEveryDecodedPa(annotations)) {
904
- return new OpInvalid("Profile Annotation decode failed", resultOp);
905
- }
906
- if (media instanceof Error) {
907
- return new OpInvalid("Web Media Profile decode failed", resultOp);
908
- }
909
- if (media && core.doc.credentialSubject.id !== media.doc.credentialSubject.id) {
910
- return new OpInvalid(
911
- "Subject mismatch between Core Profile and Web Media Profile",
912
- resultOp
913
- );
914
- }
915
- if (annotations && annotations.some(
916
- (annotation) => core.doc.credentialSubject.id !== annotation.doc.credentialSubject.id
917
- )) {
918
- return new OpInvalid(
919
- "Subject mismatch between Core Profile and Profile Annotation",
920
- resultOp
921
- );
955
+ const validated = validateDecodedOp(core, annotations, media, resultOp);
956
+ if (validated instanceof OpInvalid) {
957
+ return validated;
922
958
  }
923
- return resultOp;
959
+ return {
960
+ core,
961
+ annotations: validated.annotations,
962
+ media: validated.media
963
+ };
924
964
  });
925
965
  if (!isDecodedOps(resultOps)) {
926
966
  return new OpsInvalid("Invalid Originator Profile Set", resultOps);
@@ -937,29 +977,59 @@ function OpVerifier(paOrWmpIssuerKeys, vc, validator) {
937
977
  const cpKeys = LocalKeys(jwks);
938
978
  return JwtVcVerifier(cpKeys, issuer, validator);
939
979
  }
980
+ function validateCertificateExpiry(verifiedVc) {
981
+ const now = /* @__PURE__ */ new Date();
982
+ const validFrom = verifiedVc.doc.validFrom ? new Date(verifiedVc.doc.validFrom) : null;
983
+ const validUntil = verifiedVc.doc.validUntil ? new Date(verifiedVc.doc.validUntil) : null;
984
+ if (validFrom && now < validFrom) {
985
+ return new CertificateExpired("Certificate not yet valid", verifiedVc);
986
+ }
987
+ if (validUntil && now > validUntil) {
988
+ return new CertificateExpired("Certificate expired", verifiedVc);
989
+ }
990
+ return verifiedVc;
991
+ }
940
992
  async function verifyAnnotations(paIssuerKeys, annotations, validator) {
941
993
  if (!annotations) return;
942
994
  return await Promise.all(
943
- annotations.map((annotation) => {
995
+ annotations.map(async (annotation) => {
944
996
  const verify = OpVerifier(
945
997
  paIssuerKeys,
946
998
  annotation,
947
- validator?.({
948
- oneOf: [Certificate, JapaneseExistenceCertificate]
949
- })
999
+ validator?.(z.union([Certificate, JapaneseExistenceCertificate]))
1000
+ );
1001
+ const result = await verify(annotation.source);
1002
+ if (result instanceof Error) {
1003
+ return result;
1004
+ }
1005
+ const valid = validateCertificateExpiry(result);
1006
+ if (valid instanceof CertificateExpired) {
1007
+ return valid;
1008
+ }
1009
+ await verifyImageDigestSri(
1010
+ valid.doc.credentialSubject.image
950
1011
  );
951
- return verify(annotation.source);
1012
+ return valid;
952
1013
  })
953
1014
  );
954
1015
  }
955
1016
  async function verifyMedia(wmpIssuerKeys, media, validator) {
956
1017
  if (!media) return;
957
- const verify = OpVerifier(
958
- wmpIssuerKeys,
959
- media,
960
- validator?.(WebMediaProfile)
1018
+ return await Promise.all(
1019
+ media.map(async (m) => {
1020
+ const verify = OpVerifier(
1021
+ wmpIssuerKeys,
1022
+ m,
1023
+ validator?.(WebMediaProfile)
1024
+ );
1025
+ const result = await verify(m.source);
1026
+ if (result instanceof Error) {
1027
+ return result;
1028
+ }
1029
+ await verifyImageDigestSri(result.doc.credentialSubject.logo);
1030
+ return result;
1031
+ })
961
1032
  );
962
- return await verify(media.source);
963
1033
  }
964
1034
  const isVerifiedOps = (ops) => ops.every((op) => !(op instanceof OpVerifyFailed));
965
1035
  function OpsVerifier(ops, keys, issuer, validator) {
@@ -993,7 +1063,7 @@ function OpsVerifier(ops, keys, issuer, validator) {
993
1063
  resultOp
994
1064
  );
995
1065
  }
996
- if (media instanceof Error) {
1066
+ if (media && media.some((m) => m instanceof Error)) {
997
1067
  return new OpVerifyFailed(
998
1068
  "Web Media Profile verify failed",
999
1069
  resultOp
@@ -1034,125 +1104,105 @@ class SiteProfileVerifyFailed extends Error {
1034
1104
  code = SiteProfileVerifyFailed.code;
1035
1105
  }
1036
1106
 
1107
+ const decodeWebsiteProfiles = (sp, opsVerified) => {
1108
+ const wspSources = sp.sites || (sp.credential ? [sp.credential] : []);
1109
+ if (wspSources.length === 0) {
1110
+ return new SiteProfileInvalid("No Website Profile found", {
1111
+ originators: opsVerified,
1112
+ sites: []
1113
+ });
1114
+ }
1115
+ const decodeWsp = JwtVcDecoder();
1116
+ const decodedWsps = wspSources.map(decodeWsp);
1117
+ const decodeErrors = decodedWsps.filter((wsp) => wsp instanceof Error);
1118
+ if (decodeErrors.length > 0) {
1119
+ return new SiteProfileInvalid("Website Profile invalid", {
1120
+ originators: opsVerified,
1121
+ sites: decodeErrors
1122
+ });
1123
+ }
1124
+ return {
1125
+ decodedWsps,
1126
+ wspSources
1127
+ };
1128
+ };
1037
1129
  function SpVerifier(sp, keys, issuer, origin, verifyOrigin = true, validator) {
1038
1130
  async function verify() {
1039
1131
  const verifyOps = OpsVerifier(sp.originators, keys, issuer, validator);
1040
1132
  const opsVerified = await verifyOps();
1041
1133
  if (opsVerified instanceof OpsInvalid) {
1042
1134
  return new SiteProfileInvalid("Originator Profile Set invalid", {
1043
- originators: opsVerified
1135
+ originators: opsVerified,
1136
+ sites: []
1044
1137
  });
1045
1138
  }
1046
1139
  if (opsVerified instanceof OpsVerifyFailed) {
1047
1140
  return new SiteProfileVerifyFailed(
1048
1141
  "Originator Profile Set verify failed",
1049
- { originators: opsVerified }
1142
+ { originators: opsVerified, sites: [] }
1050
1143
  );
1051
1144
  }
1052
- const decodeWsp = JwtVcDecoder();
1053
- const decodedWsp = decodeWsp(sp.credential);
1054
- if (decodedWsp instanceof Error) {
1055
- return new SiteProfileInvalid("Website Profile invalid", {
1056
- originators: opsVerified,
1057
- credential: decodedWsp
1058
- });
1145
+ const decoded = decodeWebsiteProfiles(sp, opsVerified);
1146
+ if (decoded instanceof SiteProfileInvalid) {
1147
+ return decoded;
1059
1148
  }
1060
- const wspIssuer = decodedWsp.doc.issuer;
1061
- const cp = opsVerified.find(
1062
- (op) => op.core.doc.credentialSubject.id === wspIssuer
1149
+ const { decodedWsps, wspSources } = decoded;
1150
+ const verifiedWsps = await Promise.all(
1151
+ decodedWsps.map(async (decodedWsp, index) => {
1152
+ if (decodedWsp instanceof Error) {
1153
+ return decodedWsp;
1154
+ }
1155
+ const wspIssuer = decodedWsp.doc.issuer;
1156
+ const cp = opsVerified.find(
1157
+ (op) => op.core.doc.credentialSubject.id === wspIssuer
1158
+ );
1159
+ if (!cp) {
1160
+ return new CoreProfileNotFound(
1161
+ `Missing Core Profile (${wspIssuer})`,
1162
+ decodedWsp
1163
+ );
1164
+ }
1165
+ const verifyWsp = JwtVcVerifier(
1166
+ LocalKeys(cp.core.doc.credentialSubject.jwks),
1167
+ cp.core.doc.credentialSubject.id,
1168
+ validator?.(WebsiteProfile)
1169
+ );
1170
+ const verified = await verifyWsp(wspSources[index]);
1171
+ if (verified instanceof Error) {
1172
+ return verified;
1173
+ }
1174
+ if (verifyOrigin) {
1175
+ const allowedOrigin = "allowedOrigin" in verified.doc.credentialSubject ? verified.doc.credentialSubject.allowedOrigin : verified.doc.credentialSubject.url;
1176
+ if (!verifyAllowedOrigin(origin, allowedOrigin)) {
1177
+ return new Error("Origin not allowed");
1178
+ }
1179
+ }
1180
+ await verifyImageDigestSri(verified.doc.credentialSubject.image);
1181
+ return verified;
1182
+ })
1063
1183
  );
1064
- if (!cp) {
1184
+ const hasCoreProfileNotFound = verifiedWsps.some(
1185
+ (wsp) => wsp instanceof CoreProfileNotFound
1186
+ );
1187
+ if (hasCoreProfileNotFound) {
1065
1188
  return new SiteProfileInvalid("Appropriate Core Profile not found", {
1066
1189
  originators: opsVerified,
1067
- credential: new CoreProfileNotFound(
1068
- `Missing Core Profile (${wspIssuer})`,
1069
- decodedWsp
1070
- )
1190
+ sites: verifiedWsps
1071
1191
  });
1072
1192
  }
1073
- const verifyWsp = JwtVcVerifier(
1074
- LocalKeys(cp.core.doc.credentialSubject.jwks),
1075
- cp.core.doc.credentialSubject.id,
1076
- validator?.(WebsiteProfile)
1077
- );
1078
- const credential = await verifyWsp(sp.credential);
1079
- if (credential instanceof Error) {
1193
+ const hasError = verifiedWsps.some((wsp) => wsp instanceof Error);
1194
+ if (hasError) {
1080
1195
  return new SiteProfileVerifyFailed("Website Profile verify failed", {
1081
1196
  originators: opsVerified,
1082
- credential
1197
+ sites: verifiedWsps
1083
1198
  });
1084
1199
  }
1085
- if (verifyOrigin) {
1086
- const allowedOrigin = "allowedOrigin" in decodedWsp.doc.credentialSubject ? decodedWsp.doc.credentialSubject.allowedOrigin : decodedWsp.doc.credentialSubject.url;
1087
- if (!verifyAllowedOrigin(origin, allowedOrigin)) {
1088
- return new SiteProfileVerifyFailed("Origin not allowed", {
1089
- originators: opsVerified,
1090
- credential
1091
- });
1092
- }
1093
- }
1094
- return { originators: opsVerified, credential };
1200
+ return {
1201
+ originators: opsVerified,
1202
+ sites: verifiedWsps
1203
+ };
1095
1204
  }
1096
1205
  return verify;
1097
1206
  }
1098
1207
 
1099
- var objectTypeof = typeOf;
1100
- function typeOf(obj) {
1101
- if (obj === null) {
1102
- return "null";
1103
- }
1104
- if (obj !== Object(obj)) {
1105
- return typeof obj;
1106
- }
1107
- var result = {}.toString.call(obj).slice(8, -1).toLowerCase();
1108
- return result.indexOf("function") > -1 ? "function" : result;
1109
- }
1110
-
1111
- function CertificationSystemValidator() {
1112
- return function validate(payload) {
1113
- if (objectTypeof(payload) !== "object") {
1114
- return new CertificationSystemValidationFailed("should be an object", {
1115
- payload
1116
- });
1117
- }
1118
- const keys = Object.keys(payload);
1119
- const entries = Object.entries(payload);
1120
- if (!CertificationSystem.required.every((k) => keys.includes(k))) {
1121
- return new CertificationSystemValidationFailed(
1122
- "should be contain required properties",
1123
- { payload }
1124
- );
1125
- }
1126
- for (const entry of entries) {
1127
- const [key, value] = entry;
1128
- const propertySchema = CertificationSystem.properties[key];
1129
- if (objectTypeof(propertySchema) !== "object") {
1130
- return new CertificationSystemValidationFailed(
1131
- "should not contain additional properties",
1132
- { payload }
1133
- );
1134
- }
1135
- if ("const" in propertySchema && value !== propertySchema.const)
1136
- return new CertificationSystemValidationFailed(
1137
- `should be contain value of '${value}' in '${key}' property`,
1138
- { payload }
1139
- );
1140
- if ("type" in propertySchema && typeof value !== propertySchema.type)
1141
- return new CertificationSystemValidationFailed(
1142
- `should be contain ${propertySchema.type} value in '${key}' property`,
1143
- { payload }
1144
- );
1145
- }
1146
- return true;
1147
- };
1148
- }
1149
- function validateCertificationSystem(payload) {
1150
- const validator = CertificationSystemValidator();
1151
- const result = validator(payload);
1152
- if (result !== true) {
1153
- return result;
1154
- }
1155
- return payload;
1156
- }
1157
-
1158
- export { CaInvalid, CaVerifier, CaVerifyFailed, CasVerifyFailed, CertificationSystemValidationFailed, CertificationSystemValidator, CoreProfileNotFound, OpInvalid, OpVerifyFailed, OpsInvalid, OpsVerifier, OpsVerifyFailed, ProfileBodyExtractFailed, ProfileBodyVerifyFailed, ProfileClaimsValidationFailed, ProfileGenericError, ProfileTokenVerifyFailed, ProfilesResolveFailed, ProfilesVerifyFailed, SiteProfileInvalid, SiteProfileVerifyFailed, SpVerifier, TargetIntegrityAlgorithm, VerifyResultFactory, article, caId, caUrl, certificate, cp, decodeOps, getMappedKeys, getTupledKeys, normalizeCasItem, opId, patch, validateCertificationSystem, verifyAllowedOrigin, verifyCas, verifyDigestSri, verifyIntegrity, wmp, wsp };
1208
+ export { CaInvalid, CaVerifier, CaVerifyFailed, CasVerifyFailed, CertificateExpired, CoreProfileNotFound, IntegrityFetchFailed, IntegrityVerificationFailed, OpInvalid, OpVerifyFailed, OpsInvalid, OpsVerifier, OpsVerifyFailed, SiteProfileInvalid, SiteProfileVerifyFailed, SpVerifier, TargetIntegrityAlgorithm, VerifyResultFactory, article, caId, caUrl, certificate, cp, decodeOps, getMappedKeys, getTupledKeys, normalizeCasItem, opId, patch, verifyAllowedOrigin, verifyCas, verifyDigestSri, verifyImageDigestSri, verifyIntegrity, wmp, wsp };