@peac/protocol 0.15.2 → 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.cjs +86 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +86 -3
- package/dist/index.mjs.map +1 -1
- package/dist/replay-guard.d.ts +55 -0
- package/dist/replay-guard.d.ts.map +1 -0
- package/dist/verify-local-wire01.d.ts.map +1 -1
- package/dist/verify-local.cjs +11 -2
- package/dist/verify-local.cjs.map +1 -1
- package/dist/verify-local.d.ts +1 -1
- package/dist/verify-local.d.ts.map +1 -1
- package/dist/verify-local.mjs +11 -2
- package/dist/verify-local.mjs.map +1 -1
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -2406,7 +2406,14 @@ var JOSE_CODE_MAP = {
|
|
|
2406
2406
|
CRYPTO_JWS_CRIT_REJECTED: "E_JWS_CRIT_REJECTED",
|
|
2407
2407
|
CRYPTO_JWS_MISSING_KID: "E_JWS_MISSING_KID",
|
|
2408
2408
|
CRYPTO_JWS_B64_REJECTED: "E_JWS_B64_REJECTED",
|
|
2409
|
-
CRYPTO_JWS_ZIP_REJECTED: "E_JWS_ZIP_REJECTED"
|
|
2409
|
+
CRYPTO_JWS_ZIP_REJECTED: "E_JWS_ZIP_REJECTED",
|
|
2410
|
+
// Raw-input I-JSON gate (RFC 7493): specific E_IJSON_* codes so callers can
|
|
2411
|
+
// distinguish duplicate member names, out-of-range numbers, and invalid
|
|
2412
|
+
// strings from ordinary format errors. (Generic JSON syntax errors from the
|
|
2413
|
+
// gate use CRYPTO_INVALID_JWS_FORMAT -> E_INVALID_FORMAT via FORMAT_ERROR_CODES.)
|
|
2414
|
+
CRYPTO_IJSON_DUPLICATE_MEMBER_NAME: "E_IJSON_DUPLICATE_MEMBER_NAME",
|
|
2415
|
+
CRYPTO_IJSON_NUMBER_OUT_OF_RANGE: "E_IJSON_NUMBER_OUT_OF_RANGE",
|
|
2416
|
+
CRYPTO_IJSON_INVALID_STRING: "E_IJSON_INVALID_STRING"
|
|
2410
2417
|
};
|
|
2411
2418
|
var MAX_PARSE_ISSUES = 25;
|
|
2412
2419
|
function sanitizeParseIssues(issues) {
|
|
@@ -2430,10 +2437,12 @@ async function verifyLocal(jws, publicKey, options = {}) {
|
|
|
2430
2437
|
try {
|
|
2431
2438
|
const result = await defaultCodec.decode(jws, publicKey);
|
|
2432
2439
|
if (!result.valid) {
|
|
2440
|
+
const signatureBytes = ed25519SignatureByteLength(jws);
|
|
2441
|
+
const invalidLength = signatureBytes !== null && signatureBytes !== ED25519_SIGNATURE_BYTES;
|
|
2433
2442
|
return {
|
|
2434
2443
|
valid: false,
|
|
2435
2444
|
code: "E_INVALID_SIGNATURE",
|
|
2436
|
-
message: "Ed25519 signature verification failed"
|
|
2445
|
+
message: invalidLength ? "Ed25519 signature has invalid length" : "Ed25519 signature verification failed"
|
|
2437
2446
|
};
|
|
2438
2447
|
}
|
|
2439
2448
|
const accumulatedWarnings = [];
|
|
@@ -4072,6 +4081,80 @@ async function verifyAndFetchPointer(pointerHeader, fetchOptions) {
|
|
|
4072
4081
|
});
|
|
4073
4082
|
}
|
|
4074
4083
|
|
|
4084
|
+
// src/replay-guard.ts
|
|
4085
|
+
var DEFAULT_MAX_CLOCK_SKEW_SECONDS = 300;
|
|
4086
|
+
var DEFAULT_MAX_ENTRIES = 1e5;
|
|
4087
|
+
function safeInteger(value, name) {
|
|
4088
|
+
if (!Number.isSafeInteger(value)) {
|
|
4089
|
+
throw new Error(`createReplayGuard: ${name} must be a safe integer`);
|
|
4090
|
+
}
|
|
4091
|
+
return value;
|
|
4092
|
+
}
|
|
4093
|
+
function positiveInt(value, name) {
|
|
4094
|
+
safeInteger(value, name);
|
|
4095
|
+
if (value <= 0) {
|
|
4096
|
+
throw new Error(`createReplayGuard: ${name} must be a positive integer`);
|
|
4097
|
+
}
|
|
4098
|
+
return value;
|
|
4099
|
+
}
|
|
4100
|
+
function nonNegativeInt(value, name) {
|
|
4101
|
+
safeInteger(value, name);
|
|
4102
|
+
if (value < 0) {
|
|
4103
|
+
throw new Error(`createReplayGuard: ${name} must be a non-negative integer`);
|
|
4104
|
+
}
|
|
4105
|
+
return value;
|
|
4106
|
+
}
|
|
4107
|
+
function nonEmptyString(value, name) {
|
|
4108
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
4109
|
+
throw new Error(`createReplayGuard: ${name} must be a non-empty string`);
|
|
4110
|
+
}
|
|
4111
|
+
return value;
|
|
4112
|
+
}
|
|
4113
|
+
function createReplayGuard(options) {
|
|
4114
|
+
const windowSeconds = positiveInt(options.windowSeconds, "windowSeconds");
|
|
4115
|
+
const maxClockSkewSeconds = options.maxClockSkewSeconds === void 0 ? DEFAULT_MAX_CLOCK_SKEW_SECONDS : nonNegativeInt(options.maxClockSkewSeconds, "maxClockSkewSeconds");
|
|
4116
|
+
const maxEntries = options.maxEntries === void 0 ? DEFAULT_MAX_ENTRIES : positiveInt(options.maxEntries, "maxEntries");
|
|
4117
|
+
const now = options.now ?? (() => Math.floor(Date.now() / 1e3));
|
|
4118
|
+
let lastNow = Number.NEGATIVE_INFINITY;
|
|
4119
|
+
const currentNow = () => {
|
|
4120
|
+
const raw = safeInteger(now(), "now()");
|
|
4121
|
+
if (raw < lastNow) return lastNow;
|
|
4122
|
+
lastNow = raw;
|
|
4123
|
+
return raw;
|
|
4124
|
+
};
|
|
4125
|
+
const seen = /* @__PURE__ */ new Map();
|
|
4126
|
+
const keyOf = (iss, jti) => `${iss.length}:${iss}${jti.length}:${jti}`;
|
|
4127
|
+
const purgeExpired = (nowSeconds) => {
|
|
4128
|
+
for (const [key, entry] of seen) {
|
|
4129
|
+
if (entry.expiresAt > nowSeconds) break;
|
|
4130
|
+
seen.delete(key);
|
|
4131
|
+
}
|
|
4132
|
+
};
|
|
4133
|
+
return {
|
|
4134
|
+
check(record) {
|
|
4135
|
+
const iat = safeInteger(record.iat, "record.iat");
|
|
4136
|
+
const iss = nonEmptyString(record.iss, "record.iss");
|
|
4137
|
+
const jti = nonEmptyString(record.jti, "record.jti");
|
|
4138
|
+
const t = currentNow();
|
|
4139
|
+
purgeExpired(t);
|
|
4140
|
+
if (iat < t - windowSeconds || iat > t + maxClockSkewSeconds) {
|
|
4141
|
+
return "outside-window";
|
|
4142
|
+
}
|
|
4143
|
+
const key = keyOf(iss, jti);
|
|
4144
|
+
if (seen.has(key)) {
|
|
4145
|
+
return "replayed";
|
|
4146
|
+
}
|
|
4147
|
+
const expiresAt = safeInteger(t + windowSeconds + maxClockSkewSeconds, "entry expiry");
|
|
4148
|
+
if (seen.size >= maxEntries) {
|
|
4149
|
+
const oldest = seen.keys().next().value;
|
|
4150
|
+
if (oldest !== void 0) seen.delete(oldest);
|
|
4151
|
+
}
|
|
4152
|
+
seen.set(key, { expiresAt });
|
|
4153
|
+
return "fresh";
|
|
4154
|
+
}
|
|
4155
|
+
};
|
|
4156
|
+
}
|
|
4157
|
+
|
|
4075
4158
|
Object.defineProperty(exports, "base64urlDecode", {
|
|
4076
4159
|
enumerable: true,
|
|
4077
4160
|
get: function () { return crypto$1.base64urlDecode; }
|
|
@@ -4124,6 +4207,7 @@ exports.computeTextDocumentDigestUtf8 = computeTextDocumentDigestUtf8;
|
|
|
4124
4207
|
exports.createDefaultPolicy = createDefaultPolicy;
|
|
4125
4208
|
exports.createDigest = createDigest;
|
|
4126
4209
|
exports.createEmptyReport = createEmptyReport;
|
|
4210
|
+
exports.createReplayGuard = createReplayGuard;
|
|
4127
4211
|
exports.createReportBuilder = createReportBuilder;
|
|
4128
4212
|
exports.fetchDiscovery = fetchDiscovery;
|
|
4129
4213
|
exports.fetchIssuerConfig = fetchIssuerConfig;
|