@peac/protocol 0.15.3 → 0.16.0

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.d.ts CHANGED
@@ -17,5 +17,6 @@ export * from './verification-report';
17
17
  export * from './ssrf-safe-fetch';
18
18
  export * from './transport-profiles';
19
19
  export * from './pointer-fetch';
20
+ export * from './replay-guard';
20
21
  export { base64urlDecode, base64urlEncode, computeJwkThumbprint, generateKeypair, jwkToPublicKeyBytes, sha256Bytes, sha256Hex, verify, } from '@peac/crypto';
21
22
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,YAAY,EACV,GAAG,EACH,IAAI,EACJ,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,cAAc,EACd,gBAAgB,EAChB,WAAW,GACZ,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAK9E,OAAO,EACL,4BAA4B,EAC5B,6BAA6B,EAC7B,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,oBAAoB,CAAC;AAG5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAGhC,OAAO,EACL,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,eAAe,EACf,mBAAmB,EACnB,WAAW,EACX,SAAS,EACT,MAAM,GACP,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,YAAY,EACV,GAAG,EACH,IAAI,EACJ,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,cAAc,EACd,gBAAgB,EAChB,WAAW,GACZ,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAK9E,OAAO,EACL,4BAA4B,EAC5B,6BAA6B,EAC7B,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,oBAAoB,CAAC;AAG5B,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAIhC,cAAc,gBAAgB,CAAC;AAG/B,OAAO,EACL,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,eAAe,EACf,mBAAmB,EACnB,WAAW,EACX,SAAS,EACT,MAAM,GACP,MAAM,cAAc,CAAC"}
package/dist/index.mjs CHANGED
@@ -2405,7 +2405,14 @@ var JOSE_CODE_MAP = {
2405
2405
  CRYPTO_JWS_CRIT_REJECTED: "E_JWS_CRIT_REJECTED",
2406
2406
  CRYPTO_JWS_MISSING_KID: "E_JWS_MISSING_KID",
2407
2407
  CRYPTO_JWS_B64_REJECTED: "E_JWS_B64_REJECTED",
2408
- CRYPTO_JWS_ZIP_REJECTED: "E_JWS_ZIP_REJECTED"
2408
+ CRYPTO_JWS_ZIP_REJECTED: "E_JWS_ZIP_REJECTED",
2409
+ // Raw-input I-JSON gate (RFC 7493): specific E_IJSON_* codes so callers can
2410
+ // distinguish duplicate member names, out-of-range numbers, and invalid
2411
+ // strings from ordinary format errors. (Generic JSON syntax errors from the
2412
+ // gate use CRYPTO_INVALID_JWS_FORMAT -> E_INVALID_FORMAT via FORMAT_ERROR_CODES.)
2413
+ CRYPTO_IJSON_DUPLICATE_MEMBER_NAME: "E_IJSON_DUPLICATE_MEMBER_NAME",
2414
+ CRYPTO_IJSON_NUMBER_OUT_OF_RANGE: "E_IJSON_NUMBER_OUT_OF_RANGE",
2415
+ CRYPTO_IJSON_INVALID_STRING: "E_IJSON_INVALID_STRING"
2409
2416
  };
2410
2417
  var MAX_PARSE_ISSUES = 25;
2411
2418
  function sanitizeParseIssues(issues) {
@@ -2429,10 +2436,12 @@ async function verifyLocal(jws, publicKey, options = {}) {
2429
2436
  try {
2430
2437
  const result = await defaultCodec.decode(jws, publicKey);
2431
2438
  if (!result.valid) {
2439
+ const signatureBytes = ed25519SignatureByteLength(jws);
2440
+ const invalidLength = signatureBytes !== null && signatureBytes !== ED25519_SIGNATURE_BYTES;
2432
2441
  return {
2433
2442
  valid: false,
2434
2443
  code: "E_INVALID_SIGNATURE",
2435
- message: "Ed25519 signature verification failed"
2444
+ message: invalidLength ? "Ed25519 signature has invalid length" : "Ed25519 signature verification failed"
2436
2445
  };
2437
2446
  }
2438
2447
  const accumulatedWarnings = [];
@@ -4071,6 +4080,80 @@ async function verifyAndFetchPointer(pointerHeader, fetchOptions) {
4071
4080
  });
4072
4081
  }
4073
4082
 
4074
- export { CHECK_IDS, DEFAULT_NETWORK_SECURITY, DEFAULT_VERIFIER_LIMITS, IssueError, NON_DETERMINISTIC_ARTIFACT_KEYS, VerificationReportBuilder, buildFailureReport, buildSuccessReport, checkDocumentBinding, checkPolicyBinding, clearJWKSCache, clearKidThumbprints, computeDocumentDigest, computeJsonDocumentDigestJcs, computePolicyDigestJcs, computeReceiptDigest, computeTextDocumentDigestUtf8, createDefaultPolicy, createDigest, createEmptyReport, createReportBuilder, fetchDiscovery, fetchIssuerConfig, fetchJWKSSafe, fetchPointerSafe, fetchPointerWithDigest, fetchPolicyManifest, getJWKSCacheSize, getKidThumbprintSize, getPurposeHeader, getReceiptHeader, getSSRFCapabilities, isAttestationResult, isBlockedIP, isCommerceResult, isWire02Result, issue, issueJws, issueWire01, issueWire02, parseBodyProfile, parseDiscovery, parseHeaderProfile, parseIssuerConfig, parsePointerProfile, parsePolicyManifest, parseTransportProfile, reasonCodeToErrorCode, reasonCodeToSeverity, resetSSRFCapabilitiesCache, resolveJWKS, setPurposeAppliedHeader, setPurposeReasonHeader, setReceiptHeader, setVaryHeader, setVaryPurposeHeader, ssrfErrorToReasonCode, ssrfSafeFetch, verifyAndFetchPointer, verifyLocal, verifyReceipt, verifyReceiptCore };
4083
+ // src/replay-guard.ts
4084
+ var DEFAULT_MAX_CLOCK_SKEW_SECONDS = 300;
4085
+ var DEFAULT_MAX_ENTRIES = 1e5;
4086
+ function safeInteger(value, name) {
4087
+ if (!Number.isSafeInteger(value)) {
4088
+ throw new Error(`createReplayGuard: ${name} must be a safe integer`);
4089
+ }
4090
+ return value;
4091
+ }
4092
+ function positiveInt(value, name) {
4093
+ safeInteger(value, name);
4094
+ if (value <= 0) {
4095
+ throw new Error(`createReplayGuard: ${name} must be a positive integer`);
4096
+ }
4097
+ return value;
4098
+ }
4099
+ function nonNegativeInt(value, name) {
4100
+ safeInteger(value, name);
4101
+ if (value < 0) {
4102
+ throw new Error(`createReplayGuard: ${name} must be a non-negative integer`);
4103
+ }
4104
+ return value;
4105
+ }
4106
+ function nonEmptyString(value, name) {
4107
+ if (typeof value !== "string" || value.length === 0) {
4108
+ throw new Error(`createReplayGuard: ${name} must be a non-empty string`);
4109
+ }
4110
+ return value;
4111
+ }
4112
+ function createReplayGuard(options) {
4113
+ const windowSeconds = positiveInt(options.windowSeconds, "windowSeconds");
4114
+ const maxClockSkewSeconds = options.maxClockSkewSeconds === void 0 ? DEFAULT_MAX_CLOCK_SKEW_SECONDS : nonNegativeInt(options.maxClockSkewSeconds, "maxClockSkewSeconds");
4115
+ const maxEntries = options.maxEntries === void 0 ? DEFAULT_MAX_ENTRIES : positiveInt(options.maxEntries, "maxEntries");
4116
+ const now = options.now ?? (() => Math.floor(Date.now() / 1e3));
4117
+ let lastNow = Number.NEGATIVE_INFINITY;
4118
+ const currentNow = () => {
4119
+ const raw = safeInteger(now(), "now()");
4120
+ if (raw < lastNow) return lastNow;
4121
+ lastNow = raw;
4122
+ return raw;
4123
+ };
4124
+ const seen = /* @__PURE__ */ new Map();
4125
+ const keyOf = (iss, jti) => `${iss.length}:${iss}${jti.length}:${jti}`;
4126
+ const purgeExpired = (nowSeconds) => {
4127
+ for (const [key, entry] of seen) {
4128
+ if (entry.expiresAt > nowSeconds) break;
4129
+ seen.delete(key);
4130
+ }
4131
+ };
4132
+ return {
4133
+ check(record) {
4134
+ const iat = safeInteger(record.iat, "record.iat");
4135
+ const iss = nonEmptyString(record.iss, "record.iss");
4136
+ const jti = nonEmptyString(record.jti, "record.jti");
4137
+ const t = currentNow();
4138
+ purgeExpired(t);
4139
+ if (iat < t - windowSeconds || iat > t + maxClockSkewSeconds) {
4140
+ return "outside-window";
4141
+ }
4142
+ const key = keyOf(iss, jti);
4143
+ if (seen.has(key)) {
4144
+ return "replayed";
4145
+ }
4146
+ const expiresAt = safeInteger(t + windowSeconds + maxClockSkewSeconds, "entry expiry");
4147
+ if (seen.size >= maxEntries) {
4148
+ const oldest = seen.keys().next().value;
4149
+ if (oldest !== void 0) seen.delete(oldest);
4150
+ }
4151
+ seen.set(key, { expiresAt });
4152
+ return "fresh";
4153
+ }
4154
+ };
4155
+ }
4156
+
4157
+ export { CHECK_IDS, DEFAULT_NETWORK_SECURITY, DEFAULT_VERIFIER_LIMITS, IssueError, NON_DETERMINISTIC_ARTIFACT_KEYS, VerificationReportBuilder, buildFailureReport, buildSuccessReport, checkDocumentBinding, checkPolicyBinding, clearJWKSCache, clearKidThumbprints, computeDocumentDigest, computeJsonDocumentDigestJcs, computePolicyDigestJcs, computeReceiptDigest, computeTextDocumentDigestUtf8, createDefaultPolicy, createDigest, createEmptyReport, createReplayGuard, createReportBuilder, fetchDiscovery, fetchIssuerConfig, fetchJWKSSafe, fetchPointerSafe, fetchPointerWithDigest, fetchPolicyManifest, getJWKSCacheSize, getKidThumbprintSize, getPurposeHeader, getReceiptHeader, getSSRFCapabilities, isAttestationResult, isBlockedIP, isCommerceResult, isWire02Result, issue, issueJws, issueWire01, issueWire02, parseBodyProfile, parseDiscovery, parseHeaderProfile, parseIssuerConfig, parsePointerProfile, parsePolicyManifest, parseTransportProfile, reasonCodeToErrorCode, reasonCodeToSeverity, resetSSRFCapabilitiesCache, resolveJWKS, setPurposeAppliedHeader, setPurposeReasonHeader, setReceiptHeader, setVaryHeader, setVaryPurposeHeader, ssrfErrorToReasonCode, ssrfSafeFetch, verifyAndFetchPointer, verifyLocal, verifyReceipt, verifyReceiptCore };
4075
4158
  //# sourceMappingURL=index.mjs.map
4076
4159
  //# sourceMappingURL=index.mjs.map