@originator-profile/verify 0.5.3 → 0.6.0-beta.1

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.
@@ -1,4 +1,4 @@
1
- import { ContentAttestation, Image, Target, ContentAttestationSet, OpVc, Jwk, ArticleCA, Certificate as Certificate$1, CoreProfile, WebMediaProfile, WebsiteProfile, JapaneseExistenceCertificate, OriginatorProfileSet, Jwks, SiteProfile, AllowedOrigin } from '@originator-profile/model';
1
+ import { ContentAttestation, Image, Target, ContentAttestationSet, OpVc, Jwk, ArticleCA, Certificate as Certificate$1, CoreProfile, WebMediaProfile, WebsiteProfile, JapaneseExistenceCertificate, ProfileAnnotation, JapaneseExistencePA, ProfileAnnotationIssuerRegistration, OriginatorProfileSet, Jwks, SiteProfile, AllowedOrigin } from '@originator-profile/model';
2
2
  import { JwtVcDecodingResult, UnverifiedJwtVc, JwtVcVerificationResult, VerifiedJwtVc, VcValidator } from '@originator-profile/securing-mechanism';
3
3
  import { Keys } from '@originator-profile/cryptography';
4
4
  import { DigestSriResult, ContentFetcher, ElementSelector } from '@originator-profile/sign';
@@ -344,7 +344,8 @@ declare class CertificateExpired<T extends OpVc> extends Error {
344
344
  constructor(message: string, result: VerifiedJwtVc<T>);
345
345
  }
346
346
 
347
- type Certificate = Certificate$1 | JapaneseExistenceCertificate;
347
+ /** @deprecated Profile Annotation とその派生として整理する可能性あるため "Certificate" の利用は非推奨 */
348
+ type Certificate = Certificate$1 | JapaneseExistenceCertificate | ProfileAnnotation | JapaneseExistencePA | ProfileAnnotationIssuerRegistration;
348
349
  /** Originator Profile 復号失敗 */
349
350
  type OpDecodingFailure = {
350
351
  core: JwtVcDecodingResult<CoreProfile>;
@@ -1,7 +1,7 @@
1
1
  import { JwtVcVerifier, VcValidateFailed, VcVerifyFailed, JwtVcDecoder } from '@originator-profile/securing-mechanism';
2
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 } from '@originator-profile/model';
4
+ import { ContentAttestation, JapaneseExistencePA, ProfileAnnotationIssuerRegistration, ProfileAnnotation, JapaneseExistenceCertificate, Certificate, WebMediaProfile, CoreProfile, WebsiteProfile } from '@originator-profile/model';
5
5
  import { z } from 'zod';
6
6
 
7
7
  class CaInvalid extends Error {
@@ -422,7 +422,7 @@ function verifyAllowedOrigin(origin, allowedOrigins) {
422
422
 
423
423
  async function importURLPatternPolyfill() {
424
424
  if (typeof URLPattern === "undefined") {
425
- await import('./index-CQxI_8IG.mjs');
425
+ await import('./index-CQxI_8IG.js');
426
426
  }
427
427
  }
428
428
  function ReplaceEncode(url) {
@@ -912,29 +912,48 @@ class CertificateExpired extends Error {
912
912
 
913
913
  const isEveryDecodedPa = (annotations) => annotations.every((annotation) => "doc" in annotation);
914
914
  const isEveryDecodedWmp = (media) => media.every((m) => "doc" in m);
915
- const validateDecodedOp = (core, annotations, media, resultOp) => {
915
+ const failedPaths = (items, opIndex, prefix, isFailed) => items.map(
916
+ (item, index) => isFailed(item) ? `OP[${opIndex}].${prefix}[${index}]` : null
917
+ ).filter((path) => path !== null);
918
+ const validateDecodedOp = (core, annotations, media, resultOp, opIndex) => {
916
919
  if (annotations && !isEveryDecodedPa(annotations)) {
917
- return new OpInvalid("Profile Annotation decode failed", resultOp);
920
+ const paths = failedPaths(annotations, opIndex, "PA", (a) => !("doc" in a));
921
+ return new OpInvalid(
922
+ `Profile Annotation decode failed (${paths.join(", ")})`,
923
+ resultOp
924
+ );
918
925
  }
919
926
  if (media && !isEveryDecodedWmp(media)) {
920
- return new OpInvalid("Web Media Profile decode failed", resultOp);
927
+ const paths = failedPaths(media, opIndex, "WMP", (m) => !("doc" in m));
928
+ return new OpInvalid(
929
+ `Web Media Profile decode failed (${paths.join(", ")})`,
930
+ resultOp
931
+ );
921
932
  }
933
+ const subjectMismatchErrors = [];
922
934
  if (media && media.some(
923
935
  (m) => core.doc.credentialSubject.id !== m.doc.credentialSubject.id
924
936
  )) {
925
- return new OpInvalid(
926
- "Subject mismatch between Core Profile and Web Media Profile",
927
- resultOp
937
+ const details = media.map(
938
+ (m, index) => core.doc.credentialSubject.id !== m.doc.credentialSubject.id ? `OP[${opIndex}].WMP[${index}] issuer: ${m.doc.issuer}, subject: ${m.doc.credentialSubject.id}` : null
939
+ ).filter((d) => d !== null);
940
+ subjectMismatchErrors.push(
941
+ `Subject mismatch between Core Profile and Web Media Profile (${details.join(", ")})`
928
942
  );
929
943
  }
930
944
  if (annotations && annotations.some(
931
945
  (annotation) => core.doc.credentialSubject.id !== annotation.doc.credentialSubject.id
932
946
  )) {
933
- return new OpInvalid(
934
- "Subject mismatch between Core Profile and Profile Annotation",
935
- resultOp
947
+ const details = annotations.map(
948
+ (a, index) => core.doc.credentialSubject.id !== a.doc.credentialSubject.id ? `OP[${opIndex}].PA[${index}] issuer: ${a.doc.issuer}, subject: ${a.doc.credentialSubject.id}` : null
949
+ ).filter((d) => d !== null);
950
+ subjectMismatchErrors.push(
951
+ `Subject mismatch between Core Profile and Profile Annotation (${details.join(", ")})`
936
952
  );
937
953
  }
954
+ if (subjectMismatchErrors.length > 0) {
955
+ return new OpInvalid(subjectMismatchErrors.join("\n"), resultOp);
956
+ }
938
957
  return { type: "valid", annotations, media };
939
958
  };
940
959
  const isDecodedOps = (ops) => ops.every((op) => !(op instanceof OpInvalid));
@@ -942,7 +961,7 @@ function decodeOps(ops) {
942
961
  const decodeCp = JwtVcDecoder();
943
962
  const decodePa = JwtVcDecoder();
944
963
  const decodeWmp = JwtVcDecoder();
945
- const resultOps = ops.map((op) => {
964
+ const resultOps = ops.map((op, opIndex) => {
946
965
  const core = decodeCp(op.core);
947
966
  const annotations = op.annotations ? op.annotations.map(decodePa) : void 0;
948
967
  const mediaInput = op.media;
@@ -950,9 +969,18 @@ function decodeOps(ops) {
950
969
  const media = mediaArray ? mediaArray.map(decodeWmp) : void 0;
951
970
  const resultOp = { core, annotations, media };
952
971
  if (core instanceof Error) {
953
- return new OpInvalid("Core Profile decode failed", resultOp);
972
+ return new OpInvalid(
973
+ `Core Profile decode failed (OP[${opIndex}])`,
974
+ resultOp
975
+ );
954
976
  }
955
- const validated = validateDecodedOp(core, annotations, media, resultOp);
977
+ const validated = validateDecodedOp(
978
+ core,
979
+ annotations,
980
+ media,
981
+ resultOp,
982
+ opIndex
983
+ );
956
984
  if (validated instanceof OpInvalid) {
957
985
  return validated;
958
986
  }
@@ -963,7 +991,9 @@ function decodeOps(ops) {
963
991
  };
964
992
  });
965
993
  if (!isDecodedOps(resultOps)) {
966
- return new OpsInvalid("Invalid Originator Profile Set", resultOps);
994
+ const invalidIndexes = resultOps.map((op, index) => op instanceof OpInvalid ? index : null).filter((i) => i !== null);
995
+ const msg = invalidIndexes.length > 0 ? `Invalid Originator Profile Set (${invalidIndexes.map((i) => `OP[${i}]`).join(", ")})` : "Invalid Originator Profile Set";
996
+ return new OpsInvalid(msg, resultOps);
967
997
  }
968
998
  return resultOps;
969
999
  }
@@ -977,6 +1007,7 @@ function OpVerifier(paOrWmpIssuerKeys, vc, validator) {
977
1007
  const cpKeys = LocalKeys(jwks);
978
1008
  return JwtVcVerifier(cpKeys, issuer, validator);
979
1009
  }
1010
+
980
1011
  function validateCertificateExpiry(verifiedVc) {
981
1012
  const now = /* @__PURE__ */ new Date();
982
1013
  const validFrom = verifiedVc.doc.validFrom ? new Date(verifiedVc.doc.validFrom) : null;
@@ -996,7 +1027,16 @@ async function verifyAnnotations(paIssuerKeys, annotations, validator) {
996
1027
  const verify = OpVerifier(
997
1028
  paIssuerKeys,
998
1029
  annotation,
999
- validator?.(z.union([Certificate, JapaneseExistenceCertificate]))
1030
+ validator?.(
1031
+ // TODO: Profile Annotation とその派生のスキーマとして整理
1032
+ z.union([
1033
+ JapaneseExistencePA,
1034
+ ProfileAnnotationIssuerRegistration,
1035
+ ProfileAnnotation,
1036
+ JapaneseExistenceCertificate,
1037
+ Certificate
1038
+ ])
1039
+ )
1000
1040
  );
1001
1041
  const result = await verify(annotation.source);
1002
1042
  if (result instanceof Error) {
@@ -1006,13 +1046,12 @@ async function verifyAnnotations(paIssuerKeys, annotations, validator) {
1006
1046
  if (valid instanceof CertificateExpired) {
1007
1047
  return valid;
1008
1048
  }
1009
- await verifyImageDigestSri(
1010
- valid.doc.credentialSubject.image
1011
- );
1049
+ await verifyImageDigestSri(valid.doc.credentialSubject.image);
1012
1050
  return valid;
1013
1051
  })
1014
1052
  );
1015
1053
  }
1054
+
1016
1055
  async function verifyMedia(wmpIssuerKeys, media, validator) {
1017
1056
  if (!media) return;
1018
1057
  return await Promise.all(
@@ -1031,6 +1070,16 @@ async function verifyMedia(wmpIssuerKeys, media, validator) {
1031
1070
  })
1032
1071
  );
1033
1072
  }
1073
+
1074
+ function generateErrorDetails(items, opIndex, prefix, sources) {
1075
+ if (!items) return [];
1076
+ return items.map((item, index) => {
1077
+ if (!(item instanceof Error)) return null;
1078
+ const src = sources?.[index];
1079
+ const info = src ? ` issuer: ${src.doc.issuer}, subject: ${src.doc.credentialSubject.id}` : "";
1080
+ return `OP[${opIndex}].${prefix}[${index}]${info}`;
1081
+ }).filter((d) => d !== null);
1082
+ }
1034
1083
  const isVerifiedOps = (ops) => ops.every((op) => !(op instanceof OpVerifyFailed));
1035
1084
  function OpsVerifier(ops, keys, issuer, validator) {
1036
1085
  const decoded = decodeOps(ops);
@@ -1045,7 +1094,7 @@ function OpsVerifier(ops, keys, issuer, validator) {
1045
1094
  }
1046
1095
  const paOrWmpIssuerKeys = getMappedKeys(decoded);
1047
1096
  const resultOps = await Promise.all(
1048
- decoded.map(async (op) => {
1097
+ decoded.map(async (op, opIndex) => {
1049
1098
  const core = await verifyCp(op.core.source);
1050
1099
  const annotations = await verifyAnnotations(
1051
1100
  paOrWmpIssuerKeys,
@@ -1055,17 +1104,27 @@ function OpsVerifier(ops, keys, issuer, validator) {
1055
1104
  const media = await verifyMedia(paOrWmpIssuerKeys, op.media, validator);
1056
1105
  const resultOp = { core, annotations, media };
1057
1106
  if (core instanceof Error) {
1058
- return new OpVerifyFailed("Core Profile verify failed", resultOp);
1107
+ return new OpVerifyFailed(
1108
+ `Core Profile verify failed (OP[${opIndex}])`,
1109
+ resultOp
1110
+ );
1059
1111
  }
1060
1112
  if (annotations && annotations.some((annotation) => annotation instanceof Error)) {
1113
+ const details = generateErrorDetails(
1114
+ annotations,
1115
+ opIndex,
1116
+ "PA",
1117
+ op.annotations
1118
+ );
1061
1119
  return new OpVerifyFailed(
1062
- "Profile Annotation verify failed",
1120
+ `Profile Annotation verify failed (${details.join(", ")})`,
1063
1121
  resultOp
1064
1122
  );
1065
1123
  }
1066
1124
  if (media && media.some((m) => m instanceof Error)) {
1125
+ const details = generateErrorDetails(media, opIndex, "WMP", op.media);
1067
1126
  return new OpVerifyFailed(
1068
- "Web Media Profile verify failed",
1127
+ `Web Media Profile verify failed (${details.join(", ")})`,
1069
1128
  resultOp
1070
1129
  );
1071
1130
  }
@@ -1073,10 +1132,9 @@ function OpsVerifier(ops, keys, issuer, validator) {
1073
1132
  })
1074
1133
  );
1075
1134
  if (!isVerifiedOps(resultOps)) {
1076
- return new OpsVerifyFailed(
1077
- "Originator Profile Set verify failed",
1078
- resultOps
1079
- );
1135
+ const verifyFailedIndexes = resultOps.map((op, index) => op instanceof OpVerifyFailed ? index : null).filter((i) => i !== null);
1136
+ const msg = verifyFailedIndexes.length > 0 ? `Originator Profile Set verify failed (${verifyFailedIndexes.map((i) => `OP[${i}]`).join(", ")})` : "Originator Profile Set verify failed";
1137
+ return new OpsVerifyFailed(msg, resultOps);
1080
1138
  }
1081
1139
  return resultOps;
1082
1140
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@originator-profile/verify",
3
- "version": "0.5.3",
3
+ "version": "0.6.0-beta.1",
4
4
  "license": "Apache-2.0",
5
5
  "homepage": "https://docs.originator-profile.org",
6
6
  "repository": {
@@ -13,14 +13,8 @@
13
13
  },
14
14
  "type": "module",
15
15
  "exports": {
16
- "require": {
17
- "types": "./dist/index.d.cts",
18
- "default": "./dist/index.cjs"
19
- },
20
- "import": {
21
- "types": "./dist/index.d.mts",
22
- "default": "./dist/index.mjs"
23
- }
16
+ "types": "./dist/index.d.ts",
17
+ "default": "./dist/index.js"
24
18
  },
25
19
  "files": [
26
20
  "dist",
@@ -33,31 +27,31 @@
33
27
  "jose": "^6.2.2",
34
28
  "jsonld": "^9.0.0",
35
29
  "zod": "^4.3.6",
36
- "@originator-profile/core": "0.5.3",
37
- "@originator-profile/cryptography": "0.5.3",
38
- "@originator-profile/securing-mechanism": "0.5.3",
39
- "@originator-profile/model": "0.5.3",
40
- "@originator-profile/sign": "0.5.3"
30
+ "@originator-profile/core": "0.6.0-beta.1",
31
+ "@originator-profile/model": "0.6.0-beta.1",
32
+ "@originator-profile/cryptography": "0.6.0-beta.1",
33
+ "@originator-profile/securing-mechanism": "0.6.0-beta.1",
34
+ "@originator-profile/sign": "0.6.0-beta.1"
41
35
  },
42
36
  "devDependencies": {
43
- "@playwright/test": "^1.60.0",
44
- "date-fns": "^4.1.0",
45
- "eslint": "^10.1.0",
46
- "happy-dom": "^20.8.9",
47
- "just-diff-apply": "^5.5.0",
48
- "just-typeof": "^3.2.0",
49
- "pkgroll": "^2.27.0",
50
- "playwright": "^1.60.0",
51
- "typescript": "^6.0.2",
52
- "urlpattern-polyfill": "^10.1.0",
53
- "vite": "^8.0.3",
54
- "vitest": "^4.1.2",
55
- "websri": "^1.0.1",
56
- "eslint-config-originator-profile": "0.5.3",
57
- "@originator-profile/tsconfig": "0.5.3"
37
+ "@playwright/test": "1.59.1",
38
+ "date-fns": "4.1.0",
39
+ "eslint": "10.2.0",
40
+ "happy-dom": "20.8.9",
41
+ "just-diff-apply": "5.5.0",
42
+ "just-typeof": "3.2.0",
43
+ "pkgroll": "2.27.0",
44
+ "playwright": "1.59.1",
45
+ "typescript": "6.0.2",
46
+ "urlpattern-polyfill": "10.1.0",
47
+ "vite": "8.0.8",
48
+ "vitest": "4.1.4",
49
+ "websri": "1.0.1",
50
+ "@originator-profile/tsconfig": "0.6.0-beta.1",
51
+ "eslint-config-originator-profile": "0.6.0-beta.1"
58
52
  },
59
53
  "scripts": {
60
- "build": "pkgroll --clean-dist --target=node20",
54
+ "build": "pkgroll --clean-dist",
61
55
  "test": "vitest run",
62
56
  "e2e": "playwright test",
63
57
  "e2e:update": "playwright test --update-snapshots",