@ponharu/pkgflare 0.0.0 → 1.1.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/README.md +45 -2
- package/dist/cli.js +173 -9
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +16 -2
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/worker.js +1206 -61
- package/dist/worker.js.map +1 -1
- package/docs/architecture.md +6 -1
- package/docs/operations.md +60 -4
- package/docs/specification.md +17 -3
- package/package.json +3 -2
package/dist/worker.js
CHANGED
|
@@ -7,6 +7,10 @@ var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
|
7
7
|
var __commonJS = (cb, mod) => function __require() {
|
|
8
8
|
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
9
9
|
};
|
|
10
|
+
var __export = (target, all) => {
|
|
11
|
+
for (var name in all)
|
|
12
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
13
|
+
};
|
|
10
14
|
var __copyProps = (to, from, except, desc) => {
|
|
11
15
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
16
|
for (let key of __getOwnPropNames(from))
|
|
@@ -1021,9 +1025,9 @@ var require_range = __commonJS({
|
|
|
1021
1025
|
range = range.replace(BUILDSTRIPRE, "");
|
|
1022
1026
|
const memoOpts = (this.options.includePrerelease && FLAG_INCLUDE_PRERELEASE) | (this.options.loose && FLAG_LOOSE);
|
|
1023
1027
|
const memoKey = memoOpts + ":" + range;
|
|
1024
|
-
const
|
|
1025
|
-
if (
|
|
1026
|
-
return
|
|
1028
|
+
const cached2 = cache2.get(memoKey);
|
|
1029
|
+
if (cached2) {
|
|
1030
|
+
return cached2;
|
|
1027
1031
|
}
|
|
1028
1032
|
const loose = this.options.loose;
|
|
1029
1033
|
const hr = loose ? re[t.HYPHENRANGELOOSE] : re[t.HYPHENRANGE];
|
|
@@ -1055,7 +1059,7 @@ var require_range = __commonJS({
|
|
|
1055
1059
|
rangeMap.delete("");
|
|
1056
1060
|
}
|
|
1057
1061
|
const result = [...rangeMap.values()];
|
|
1058
|
-
|
|
1062
|
+
cache2.set(memoKey, result);
|
|
1059
1063
|
return result;
|
|
1060
1064
|
}
|
|
1061
1065
|
intersects(range, options) {
|
|
@@ -1094,7 +1098,7 @@ var require_range = __commonJS({
|
|
|
1094
1098
|
};
|
|
1095
1099
|
module.exports = Range;
|
|
1096
1100
|
var LRU = require_lrucache();
|
|
1097
|
-
var
|
|
1101
|
+
var cache2 = new LRU();
|
|
1098
1102
|
var parseOptions = require_parse_options();
|
|
1099
1103
|
var Comparator = require_comparator();
|
|
1100
1104
|
var debug = require_debug();
|
|
@@ -2025,9 +2029,88 @@ var scopePattern = /^@[a-z0-9](?:[a-z0-9._-]*[a-z0-9])?$/;
|
|
|
2025
2029
|
var bindingPattern = /^[A-Z][A-Z0-9_]*$/;
|
|
2026
2030
|
var hostnamePattern = /^(?=.{1,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
|
|
2027
2031
|
var reservedBindings = /* @__PURE__ */ new Set(["PKGFLARE_DB", "PKGFLARE_BUCKET", "PKGFLARE_CONFIG"]);
|
|
2032
|
+
var githubIdPattern = /^[1-9][0-9]{0,19}$/;
|
|
2033
|
+
var audiencePattern = /^[\x21-\x7e]{1,256}$/;
|
|
2034
|
+
var refPattern = /^refs\/(?:heads|tags)\/[A-Za-z0-9._/-]+\*?$/;
|
|
2035
|
+
var workflowRefPattern = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+\/\.github\/workflows\/[A-Za-z0-9_.-]+\.ya?ml@refs\/(?:heads|tags)\/[A-Za-z0-9._/-]+\*?$/;
|
|
2036
|
+
var packageSegmentPattern = /^(?!\.)(?:[a-z0-9._-]+)$/;
|
|
2037
|
+
var maximumGithubSubjects = 128;
|
|
2038
|
+
var maximumPackagesPerSubject = 128;
|
|
2039
|
+
var maximumRuntimeConfigBytes = 5 * 1024;
|
|
2028
2040
|
function isObject(value) {
|
|
2029
2041
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2030
2042
|
}
|
|
2043
|
+
function normalizePermissions(value, label) {
|
|
2044
|
+
if (!Array.isArray(value) || value.length === 0 || value.some((permission) => permission !== "read" && permission !== "publish")) {
|
|
2045
|
+
throw new Error(`invalid permissions for ${label}`);
|
|
2046
|
+
}
|
|
2047
|
+
return [...new Set(value)];
|
|
2048
|
+
}
|
|
2049
|
+
function isSafePattern(value, pattern) {
|
|
2050
|
+
if (!pattern.test(value)) return false;
|
|
2051
|
+
const wildcard = value.indexOf("*");
|
|
2052
|
+
return wildcard === -1 || wildcard === value.length - 1;
|
|
2053
|
+
}
|
|
2054
|
+
function normalizeGithubOidc(value, configuredScopes) {
|
|
2055
|
+
if (!isObject(value) || typeof value.audience !== "string") {
|
|
2056
|
+
throw new Error("githubOidc must define an audience and trusted subjects");
|
|
2057
|
+
}
|
|
2058
|
+
if (!audiencePattern.test(value.audience)) {
|
|
2059
|
+
throw new Error("githubOidc audience must be 1-256 printable ASCII characters");
|
|
2060
|
+
}
|
|
2061
|
+
if (!Array.isArray(value.subjects) || value.subjects.length === 0 || value.subjects.length > maximumGithubSubjects) {
|
|
2062
|
+
throw new Error(`githubOidc must define 1-${String(maximumGithubSubjects)} subjects`);
|
|
2063
|
+
}
|
|
2064
|
+
const subjects = value.subjects.map((subjectValue, index) => {
|
|
2065
|
+
const label = `githubOidc subject ${String(index + 1)}`;
|
|
2066
|
+
if (!isObject(subjectValue)) throw new Error(`${label} must be an object`);
|
|
2067
|
+
const { repositoryId, repositoryOwnerId, ref, workflowRef, jobWorkflowRef } = subjectValue;
|
|
2068
|
+
if (typeof repositoryId !== "string" || !githubIdPattern.test(repositoryId)) {
|
|
2069
|
+
throw new Error(`${label} repositoryId must be a decimal GitHub repository ID`);
|
|
2070
|
+
}
|
|
2071
|
+
if (typeof repositoryOwnerId !== "string" || !githubIdPattern.test(repositoryOwnerId)) {
|
|
2072
|
+
throw new Error(`${label} repositoryOwnerId must be a decimal GitHub owner ID`);
|
|
2073
|
+
}
|
|
2074
|
+
if (typeof ref !== "string" || !isSafePattern(ref, refPattern)) {
|
|
2075
|
+
throw new Error(`${label} ref must be an exact branch/tag ref or trailing-wildcard pattern`);
|
|
2076
|
+
}
|
|
2077
|
+
if (typeof workflowRef !== "string" || !isSafePattern(workflowRef, workflowRefPattern)) {
|
|
2078
|
+
throw new Error(
|
|
2079
|
+
`${label} workflowRef must identify a workflow file at an exact or trailing-wildcard ref`
|
|
2080
|
+
);
|
|
2081
|
+
}
|
|
2082
|
+
if (jobWorkflowRef !== void 0 && (typeof jobWorkflowRef !== "string" || !isSafePattern(jobWorkflowRef, workflowRefPattern))) {
|
|
2083
|
+
throw new Error(
|
|
2084
|
+
`${label} jobWorkflowRef must identify a reusable workflow at an exact or trailing-wildcard ref`
|
|
2085
|
+
);
|
|
2086
|
+
}
|
|
2087
|
+
const permissions = normalizePermissions(subjectValue.permissions, label);
|
|
2088
|
+
if (!Array.isArray(subjectValue.packages) || subjectValue.packages.length === 0 || subjectValue.packages.length > maximumPackagesPerSubject || subjectValue.packages.some((packageName) => typeof packageName !== "string")) {
|
|
2089
|
+
throw new Error(
|
|
2090
|
+
`${label} must define 1-${String(maximumPackagesPerSubject)} package patterns`
|
|
2091
|
+
);
|
|
2092
|
+
}
|
|
2093
|
+
const packages = [...new Set(subjectValue.packages)];
|
|
2094
|
+
for (const packagePattern of packages) {
|
|
2095
|
+
const slash = packagePattern.indexOf("/");
|
|
2096
|
+
const scope = packagePattern.slice(0, slash);
|
|
2097
|
+
const packageSegment = packagePattern.slice(slash + 1);
|
|
2098
|
+
if (slash === -1 || packagePattern.length > 214 || !configuredScopes.includes(scope) || packageSegment !== "*" && !packageSegmentPattern.test(packageSegment)) {
|
|
2099
|
+
throw new Error(`${label} contains an invalid or unconfigured package pattern`);
|
|
2100
|
+
}
|
|
2101
|
+
}
|
|
2102
|
+
return {
|
|
2103
|
+
repositoryId,
|
|
2104
|
+
repositoryOwnerId,
|
|
2105
|
+
ref,
|
|
2106
|
+
workflowRef,
|
|
2107
|
+
...jobWorkflowRef === void 0 ? {} : { jobWorkflowRef },
|
|
2108
|
+
permissions,
|
|
2109
|
+
packages
|
|
2110
|
+
};
|
|
2111
|
+
});
|
|
2112
|
+
return { audience: value.audience, subjects };
|
|
2113
|
+
}
|
|
2031
2114
|
function normalizeConfig(value) {
|
|
2032
2115
|
if (!isObject(value)) throw new Error("configuration must be an object");
|
|
2033
2116
|
const { name, scopes: scopeValues, accountId, hostname, auth } = value;
|
|
@@ -2052,11 +2135,12 @@ function normalizeConfig(value) {
|
|
|
2052
2135
|
if (!isObject(auth) || auth.provider !== "secrets") {
|
|
2053
2136
|
throw new Error("unsupported authentication provider");
|
|
2054
2137
|
}
|
|
2055
|
-
|
|
2056
|
-
|
|
2138
|
+
const tokenValues = auth.tokens ?? [];
|
|
2139
|
+
if (!Array.isArray(tokenValues)) {
|
|
2140
|
+
throw new Error("authentication token bindings must be an array");
|
|
2057
2141
|
}
|
|
2058
2142
|
const seenBindings = /* @__PURE__ */ new Set();
|
|
2059
|
-
const tokens =
|
|
2143
|
+
const tokens = tokenValues.map((tokenValue) => {
|
|
2060
2144
|
if (!isObject(tokenValue) || typeof tokenValue.binding !== "string") {
|
|
2061
2145
|
throw new Error("authentication token binding must be an object with a binding name");
|
|
2062
2146
|
}
|
|
@@ -2071,20 +2155,1079 @@ function normalizeConfig(value) {
|
|
|
2071
2155
|
throw new Error(`duplicate secret binding: ${binding}`);
|
|
2072
2156
|
}
|
|
2073
2157
|
seenBindings.add(binding);
|
|
2074
|
-
|
|
2075
|
-
throw new Error(`invalid permissions for ${binding}`);
|
|
2076
|
-
}
|
|
2077
|
-
const permissions = [...new Set(permissionValues)];
|
|
2158
|
+
const permissions = normalizePermissions(permissionValues, binding);
|
|
2078
2159
|
return { binding, permissions };
|
|
2079
2160
|
});
|
|
2080
|
-
|
|
2161
|
+
const githubOidc = auth.githubOidc === void 0 ? void 0 : normalizeGithubOidc(auth.githubOidc, scopes);
|
|
2162
|
+
if (tokens.length === 0 && githubOidc === void 0) {
|
|
2163
|
+
throw new Error("at least one authentication method is required");
|
|
2164
|
+
}
|
|
2165
|
+
const normalized = {
|
|
2081
2166
|
name,
|
|
2082
2167
|
scopes,
|
|
2083
2168
|
...accountId === void 0 ? {} : { accountId },
|
|
2084
2169
|
...hostname === void 0 ? {} : { hostname },
|
|
2085
|
-
auth: {
|
|
2170
|
+
auth: {
|
|
2171
|
+
provider: "secrets",
|
|
2172
|
+
tokens,
|
|
2173
|
+
...githubOidc === void 0 ? {} : { githubOidc }
|
|
2174
|
+
}
|
|
2175
|
+
};
|
|
2176
|
+
if (new TextEncoder().encode(JSON.stringify(normalized)).byteLength > maximumRuntimeConfigBytes) {
|
|
2177
|
+
throw new Error("normalized configuration exceeds the 5 KiB Worker variable limit");
|
|
2178
|
+
}
|
|
2179
|
+
return normalized;
|
|
2180
|
+
}
|
|
2181
|
+
|
|
2182
|
+
// src/runtime/diagnostics.ts
|
|
2183
|
+
function logRegistryError(requestId, operation, error) {
|
|
2184
|
+
console.error(
|
|
2185
|
+
JSON.stringify({
|
|
2186
|
+
level: "error",
|
|
2187
|
+
requestId,
|
|
2188
|
+
operation,
|
|
2189
|
+
errorType: error instanceof Error ? error.name : typeof error
|
|
2190
|
+
})
|
|
2191
|
+
);
|
|
2192
|
+
}
|
|
2193
|
+
|
|
2194
|
+
// node_modules/jose/dist/webapi/lib/buffer_utils.js
|
|
2195
|
+
var encoder = new TextEncoder();
|
|
2196
|
+
var decoder = new TextDecoder();
|
|
2197
|
+
var strictDecoder = new TextDecoder("utf-8", { fatal: true });
|
|
2198
|
+
var MAX_INT32 = 2 ** 32;
|
|
2199
|
+
function concat(...buffers) {
|
|
2200
|
+
const size = buffers.reduce((acc, { length }) => acc + length, 0);
|
|
2201
|
+
const buf = new Uint8Array(size);
|
|
2202
|
+
let i = 0;
|
|
2203
|
+
for (const buffer of buffers) {
|
|
2204
|
+
buf.set(buffer, i);
|
|
2205
|
+
i += buffer.length;
|
|
2206
|
+
}
|
|
2207
|
+
return buf;
|
|
2208
|
+
}
|
|
2209
|
+
function encode(string) {
|
|
2210
|
+
const bytes = new Uint8Array(string.length);
|
|
2211
|
+
for (let i = 0; i < string.length; i++) {
|
|
2212
|
+
const code = string.charCodeAt(i);
|
|
2213
|
+
if (code > 127) {
|
|
2214
|
+
throw new TypeError("non-ASCII string encountered in encode()");
|
|
2215
|
+
}
|
|
2216
|
+
bytes[i] = code;
|
|
2217
|
+
}
|
|
2218
|
+
return bytes;
|
|
2219
|
+
}
|
|
2220
|
+
|
|
2221
|
+
// node_modules/jose/dist/webapi/lib/crypto_key.js
|
|
2222
|
+
var unusable = (name, prop = "algorithm.name") => new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name}`);
|
|
2223
|
+
function checkUsage(key, usage) {
|
|
2224
|
+
if (usage && !key.usages.includes(usage)) {
|
|
2225
|
+
throw new TypeError(`CryptoKey does not support this operation, its usages must include ${usage}.`);
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2228
|
+
function checkModulusLength(alg, key) {
|
|
2229
|
+
const { modulusLength } = key.algorithm;
|
|
2230
|
+
if (typeof modulusLength !== "number" || modulusLength < 2048) {
|
|
2231
|
+
throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`);
|
|
2232
|
+
}
|
|
2233
|
+
}
|
|
2234
|
+
function checkCryptoKey(key, expected, usage) {
|
|
2235
|
+
const algorithm = key.algorithm;
|
|
2236
|
+
if (algorithm.name !== expected.name) {
|
|
2237
|
+
throw unusable(expected.name);
|
|
2238
|
+
}
|
|
2239
|
+
if (expected.hash && algorithm.hash?.name !== expected.hash) {
|
|
2240
|
+
throw unusable(expected.hash, "algorithm.hash");
|
|
2241
|
+
}
|
|
2242
|
+
if (expected.namedCurve && algorithm.namedCurve !== expected.namedCurve) {
|
|
2243
|
+
throw unusable(expected.namedCurve, "algorithm.namedCurve");
|
|
2244
|
+
}
|
|
2245
|
+
if (expected.length !== void 0 && algorithm.length !== expected.length) {
|
|
2246
|
+
throw unusable(expected.length, "algorithm.length");
|
|
2247
|
+
}
|
|
2248
|
+
checkUsage(key, usage);
|
|
2249
|
+
}
|
|
2250
|
+
|
|
2251
|
+
// node_modules/jose/dist/webapi/lib/invalid_key_input.js
|
|
2252
|
+
function message(msg, actual, ...types) {
|
|
2253
|
+
if (types.length > 2) {
|
|
2254
|
+
const last = types.pop();
|
|
2255
|
+
msg += `one of type ${types.join(", ")}, or ${last}.`;
|
|
2256
|
+
} else if (types.length === 2) {
|
|
2257
|
+
msg += `one of type ${types[0]} or ${types[1]}.`;
|
|
2258
|
+
} else {
|
|
2259
|
+
msg += `of type ${types[0]}.`;
|
|
2260
|
+
}
|
|
2261
|
+
if (actual == null) {
|
|
2262
|
+
msg += ` Received ${actual}`;
|
|
2263
|
+
} else if (typeof actual === "function" && actual.name) {
|
|
2264
|
+
msg += ` Received function ${actual.name}`;
|
|
2265
|
+
} else if (typeof actual === "object" && actual != null) {
|
|
2266
|
+
if (actual.constructor?.name) {
|
|
2267
|
+
msg += ` Received an instance of ${actual.constructor.name}`;
|
|
2268
|
+
}
|
|
2269
|
+
}
|
|
2270
|
+
return msg;
|
|
2271
|
+
}
|
|
2272
|
+
var withAlg = (alg, actual, ...types) => message(`Key for the ${alg} algorithm must be `, actual, ...types);
|
|
2273
|
+
|
|
2274
|
+
// node_modules/jose/dist/webapi/util/errors.js
|
|
2275
|
+
var errors_exports = {};
|
|
2276
|
+
__export(errors_exports, {
|
|
2277
|
+
JOSEAlgNotAllowed: () => JOSEAlgNotAllowed,
|
|
2278
|
+
JOSEError: () => JOSEError,
|
|
2279
|
+
JOSENotSupported: () => JOSENotSupported,
|
|
2280
|
+
JWEDecryptionFailed: () => JWEDecryptionFailed,
|
|
2281
|
+
JWEInvalid: () => JWEInvalid,
|
|
2282
|
+
JWKInvalid: () => JWKInvalid,
|
|
2283
|
+
JWKSInvalid: () => JWKSInvalid,
|
|
2284
|
+
JWKSMultipleMatchingKeys: () => JWKSMultipleMatchingKeys,
|
|
2285
|
+
JWKSNoMatchingKey: () => JWKSNoMatchingKey,
|
|
2286
|
+
JWKSTimeout: () => JWKSTimeout,
|
|
2287
|
+
JWSInvalid: () => JWSInvalid,
|
|
2288
|
+
JWSSignatureVerificationFailed: () => JWSSignatureVerificationFailed,
|
|
2289
|
+
JWTClaimValidationFailed: () => JWTClaimValidationFailed,
|
|
2290
|
+
JWTExpired: () => JWTExpired,
|
|
2291
|
+
JWTInvalid: () => JWTInvalid
|
|
2292
|
+
});
|
|
2293
|
+
var JOSEError = class extends Error {
|
|
2294
|
+
static code = "ERR_JOSE_GENERIC";
|
|
2295
|
+
code = "ERR_JOSE_GENERIC";
|
|
2296
|
+
constructor(message2, options) {
|
|
2297
|
+
super(message2, options);
|
|
2298
|
+
this.name = this.constructor.name;
|
|
2299
|
+
Error.captureStackTrace?.(this, this.constructor);
|
|
2300
|
+
}
|
|
2301
|
+
};
|
|
2302
|
+
var JWTClaimValidationFailed = class extends JOSEError {
|
|
2303
|
+
static code = "ERR_JWT_CLAIM_VALIDATION_FAILED";
|
|
2304
|
+
code = "ERR_JWT_CLAIM_VALIDATION_FAILED";
|
|
2305
|
+
claim;
|
|
2306
|
+
reason;
|
|
2307
|
+
payload;
|
|
2308
|
+
constructor(message2, payload, claim2 = "unspecified", reason = "unspecified") {
|
|
2309
|
+
super(message2, { cause: { claim: claim2, reason, payload } });
|
|
2310
|
+
this.claim = claim2;
|
|
2311
|
+
this.reason = reason;
|
|
2312
|
+
this.payload = payload;
|
|
2313
|
+
}
|
|
2314
|
+
};
|
|
2315
|
+
var JWTExpired = class extends JOSEError {
|
|
2316
|
+
static code = "ERR_JWT_EXPIRED";
|
|
2317
|
+
code = "ERR_JWT_EXPIRED";
|
|
2318
|
+
claim;
|
|
2319
|
+
reason;
|
|
2320
|
+
payload;
|
|
2321
|
+
constructor(message2, payload, claim2 = "unspecified", reason = "unspecified") {
|
|
2322
|
+
super(message2, { cause: { claim: claim2, reason, payload } });
|
|
2323
|
+
this.claim = claim2;
|
|
2324
|
+
this.reason = reason;
|
|
2325
|
+
this.payload = payload;
|
|
2326
|
+
}
|
|
2327
|
+
};
|
|
2328
|
+
var JOSEAlgNotAllowed = class extends JOSEError {
|
|
2329
|
+
static code = "ERR_JOSE_ALG_NOT_ALLOWED";
|
|
2330
|
+
code = "ERR_JOSE_ALG_NOT_ALLOWED";
|
|
2331
|
+
};
|
|
2332
|
+
var JOSENotSupported = class extends JOSEError {
|
|
2333
|
+
static code = "ERR_JOSE_NOT_SUPPORTED";
|
|
2334
|
+
code = "ERR_JOSE_NOT_SUPPORTED";
|
|
2335
|
+
};
|
|
2336
|
+
var JWEDecryptionFailed = class extends JOSEError {
|
|
2337
|
+
static code = "ERR_JWE_DECRYPTION_FAILED";
|
|
2338
|
+
code = "ERR_JWE_DECRYPTION_FAILED";
|
|
2339
|
+
constructor(message2 = "decryption operation failed", options) {
|
|
2340
|
+
super(message2, options);
|
|
2341
|
+
}
|
|
2342
|
+
};
|
|
2343
|
+
var JWEInvalid = class extends JOSEError {
|
|
2344
|
+
static code = "ERR_JWE_INVALID";
|
|
2345
|
+
code = "ERR_JWE_INVALID";
|
|
2346
|
+
};
|
|
2347
|
+
var JWSInvalid = class extends JOSEError {
|
|
2348
|
+
static code = "ERR_JWS_INVALID";
|
|
2349
|
+
code = "ERR_JWS_INVALID";
|
|
2350
|
+
};
|
|
2351
|
+
var JWTInvalid = class extends JOSEError {
|
|
2352
|
+
static code = "ERR_JWT_INVALID";
|
|
2353
|
+
code = "ERR_JWT_INVALID";
|
|
2354
|
+
};
|
|
2355
|
+
var JWKInvalid = class extends JOSEError {
|
|
2356
|
+
static code = "ERR_JWK_INVALID";
|
|
2357
|
+
code = "ERR_JWK_INVALID";
|
|
2358
|
+
};
|
|
2359
|
+
var JWKSInvalid = class extends JOSEError {
|
|
2360
|
+
static code = "ERR_JWKS_INVALID";
|
|
2361
|
+
code = "ERR_JWKS_INVALID";
|
|
2362
|
+
};
|
|
2363
|
+
var JWKSNoMatchingKey = class extends JOSEError {
|
|
2364
|
+
static code = "ERR_JWKS_NO_MATCHING_KEY";
|
|
2365
|
+
code = "ERR_JWKS_NO_MATCHING_KEY";
|
|
2366
|
+
constructor(message2 = "no applicable key found in the JSON Web Key Set", options) {
|
|
2367
|
+
super(message2, options);
|
|
2368
|
+
}
|
|
2369
|
+
};
|
|
2370
|
+
var JWKSMultipleMatchingKeys = class extends JOSEError {
|
|
2371
|
+
[Symbol.asyncIterator] = async function* () {
|
|
2372
|
+
};
|
|
2373
|
+
static code = "ERR_JWKS_MULTIPLE_MATCHING_KEYS";
|
|
2374
|
+
code = "ERR_JWKS_MULTIPLE_MATCHING_KEYS";
|
|
2375
|
+
constructor(message2 = "multiple matching keys found in the JSON Web Key Set", options) {
|
|
2376
|
+
super(message2, options);
|
|
2377
|
+
}
|
|
2378
|
+
};
|
|
2379
|
+
var JWKSTimeout = class extends JOSEError {
|
|
2380
|
+
static code = "ERR_JWKS_TIMEOUT";
|
|
2381
|
+
code = "ERR_JWKS_TIMEOUT";
|
|
2382
|
+
constructor(message2 = "request timed out", options) {
|
|
2383
|
+
super(message2, options);
|
|
2384
|
+
}
|
|
2385
|
+
};
|
|
2386
|
+
var JWSSignatureVerificationFailed = class extends JOSEError {
|
|
2387
|
+
static code = "ERR_JWS_SIGNATURE_VERIFICATION_FAILED";
|
|
2388
|
+
code = "ERR_JWS_SIGNATURE_VERIFICATION_FAILED";
|
|
2389
|
+
constructor(message2 = "signature verification failed", options) {
|
|
2390
|
+
super(message2, options);
|
|
2391
|
+
}
|
|
2392
|
+
};
|
|
2393
|
+
|
|
2394
|
+
// node_modules/jose/dist/webapi/lib/is_key_like.js
|
|
2395
|
+
var isCryptoKey = (key) => {
|
|
2396
|
+
if (key?.[Symbol.toStringTag] === "CryptoKey")
|
|
2397
|
+
return true;
|
|
2398
|
+
try {
|
|
2399
|
+
return key instanceof CryptoKey;
|
|
2400
|
+
} catch {
|
|
2401
|
+
return false;
|
|
2402
|
+
}
|
|
2403
|
+
};
|
|
2404
|
+
var isKeyObject = (key) => key?.[Symbol.toStringTag] === "KeyObject";
|
|
2405
|
+
var isKeyLike = (key) => isCryptoKey(key) || isKeyObject(key);
|
|
2406
|
+
|
|
2407
|
+
// node_modules/jose/dist/webapi/lib/base64.js
|
|
2408
|
+
function decodeBase64(encoded) {
|
|
2409
|
+
if (Uint8Array.fromBase64) {
|
|
2410
|
+
return Uint8Array.fromBase64(encoded);
|
|
2411
|
+
}
|
|
2412
|
+
const binary = atob(encoded);
|
|
2413
|
+
const bytes = new Uint8Array(binary.length);
|
|
2414
|
+
for (let i = 0; i < binary.length; i++) {
|
|
2415
|
+
bytes[i] = binary.charCodeAt(i);
|
|
2416
|
+
}
|
|
2417
|
+
return bytes;
|
|
2418
|
+
}
|
|
2419
|
+
|
|
2420
|
+
// node_modules/jose/dist/webapi/util/base64url.js
|
|
2421
|
+
var invalid = "The input to be decoded is not correctly encoded.";
|
|
2422
|
+
function decode(input) {
|
|
2423
|
+
if (Uint8Array.fromBase64) {
|
|
2424
|
+
try {
|
|
2425
|
+
return Uint8Array.fromBase64(typeof input === "string" ? input : decoder.decode(input), {
|
|
2426
|
+
alphabet: "base64url"
|
|
2427
|
+
});
|
|
2428
|
+
} catch (cause) {
|
|
2429
|
+
throw new TypeError(invalid, { cause });
|
|
2430
|
+
}
|
|
2431
|
+
}
|
|
2432
|
+
let encoded = input;
|
|
2433
|
+
if (encoded instanceof Uint8Array) {
|
|
2434
|
+
encoded = decoder.decode(encoded);
|
|
2435
|
+
}
|
|
2436
|
+
if (encoded.includes("+") || encoded.includes("/")) {
|
|
2437
|
+
throw new TypeError(invalid);
|
|
2438
|
+
}
|
|
2439
|
+
encoded = encoded.replace(/-/g, "+").replace(/_/g, "/");
|
|
2440
|
+
try {
|
|
2441
|
+
return decodeBase64(encoded);
|
|
2442
|
+
} catch {
|
|
2443
|
+
throw new TypeError(invalid);
|
|
2444
|
+
}
|
|
2445
|
+
}
|
|
2446
|
+
|
|
2447
|
+
// node_modules/jose/dist/webapi/lib/type_checks.js
|
|
2448
|
+
function isObject2(input) {
|
|
2449
|
+
if (typeof input !== "object" || input === null || Object.prototype.toString.call(input) !== "[object Object]") {
|
|
2450
|
+
return false;
|
|
2451
|
+
}
|
|
2452
|
+
const prototype = Object.getPrototypeOf(input);
|
|
2453
|
+
return prototype === null || Object.getPrototypeOf(prototype) === null;
|
|
2454
|
+
}
|
|
2455
|
+
function isJwkSet(input) {
|
|
2456
|
+
return isObject2(input) && Array.isArray(input.keys) && Array.from(input.keys).every(isObject2);
|
|
2457
|
+
}
|
|
2458
|
+
|
|
2459
|
+
// node_modules/jose/dist/webapi/lib/helpers.js
|
|
2460
|
+
function decodeBase64url(value, label, ErrorClass) {
|
|
2461
|
+
try {
|
|
2462
|
+
return decode(value);
|
|
2463
|
+
} catch {
|
|
2464
|
+
throw new ErrorClass(`Failed to base64url decode the ${label}`);
|
|
2465
|
+
}
|
|
2466
|
+
}
|
|
2467
|
+
function encodeBase64url(value, label, ErrorClass) {
|
|
2468
|
+
try {
|
|
2469
|
+
return encode(value);
|
|
2470
|
+
} catch {
|
|
2471
|
+
throw new ErrorClass(`The ${label} is not a valid base64url string`);
|
|
2472
|
+
}
|
|
2473
|
+
}
|
|
2474
|
+
function parseJoseHeader(b64, ErrorClass, message2) {
|
|
2475
|
+
let parsed;
|
|
2476
|
+
try {
|
|
2477
|
+
parsed = JSON.parse(strictDecoder.decode(decode(b64)));
|
|
2478
|
+
} catch {
|
|
2479
|
+
throw new ErrorClass(message2);
|
|
2480
|
+
}
|
|
2481
|
+
if (!isObject2(parsed)) {
|
|
2482
|
+
throw new ErrorClass(message2);
|
|
2483
|
+
}
|
|
2484
|
+
return parsed;
|
|
2485
|
+
}
|
|
2486
|
+
|
|
2487
|
+
// node_modules/jose/dist/webapi/lib/jwk_to_key.js
|
|
2488
|
+
async function jwkToKey(entry, jwk) {
|
|
2489
|
+
if (jwk.kty === "RSA" && "oth" in jwk && jwk.oth !== void 0) {
|
|
2490
|
+
throw new JOSENotSupported('RSA JWK "oth" (Other Primes Info) Parameter value is not supported');
|
|
2491
|
+
}
|
|
2492
|
+
if (!entry.kty.includes(jwk.kty)) {
|
|
2493
|
+
throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
|
|
2494
|
+
}
|
|
2495
|
+
const algorithm = entry.resolve?.({ kty: jwk.kty, crv: jwk.crv }) ?? entry.subtle;
|
|
2496
|
+
const isPrivate = !!(jwk.d || jwk.priv);
|
|
2497
|
+
const keyData = { ...jwk };
|
|
2498
|
+
if (keyData.kty !== "AKP") {
|
|
2499
|
+
delete keyData.alg;
|
|
2500
|
+
}
|
|
2501
|
+
delete keyData.use;
|
|
2502
|
+
return crypto.subtle.importKey("jwk", keyData, algorithm, jwk.ext ?? !isPrivate, jwk.key_ops ?? entry.usages[isPrivate ? 1 : 0]);
|
|
2503
|
+
}
|
|
2504
|
+
|
|
2505
|
+
// node_modules/jose/dist/webapi/lib/jwk_metadata.js
|
|
2506
|
+
function snapshotJwk(jwk) {
|
|
2507
|
+
return { __proto__: null, ...jwk };
|
|
2508
|
+
}
|
|
2509
|
+
function normalizeJwk(jwk) {
|
|
2510
|
+
const normalized = snapshotJwk(jwk);
|
|
2511
|
+
if (normalized.ext !== void 0 && typeof normalized.ext !== "boolean") {
|
|
2512
|
+
throw new TypeError('"ext" (Extractable) Parameter must be a boolean');
|
|
2513
|
+
}
|
|
2514
|
+
if (normalized.key_ops !== void 0) {
|
|
2515
|
+
const value = normalized.key_ops;
|
|
2516
|
+
const keyOps = Array.isArray(value) ? [...value] : void 0;
|
|
2517
|
+
if (!keyOps || keyOps.some((operation) => typeof operation !== "string") || new Set(keyOps).size !== keyOps.length) {
|
|
2518
|
+
throw new TypeError('"key_ops" (Key Operations) Parameter must be an array of unique strings');
|
|
2519
|
+
}
|
|
2520
|
+
normalized.key_ops = keyOps;
|
|
2521
|
+
}
|
|
2522
|
+
return normalized;
|
|
2523
|
+
}
|
|
2524
|
+
|
|
2525
|
+
// node_modules/jose/dist/webapi/lib/key.js
|
|
2526
|
+
var tag = (key) => key[Symbol.toStringTag];
|
|
2527
|
+
var jwkMatchesOp = (entry, key, usage) => {
|
|
2528
|
+
const { alg } = entry;
|
|
2529
|
+
if (key.use !== void 0) {
|
|
2530
|
+
const expected = usage === "sign" || usage === "verify" ? "sig" : "enc";
|
|
2531
|
+
if (key.use !== expected) {
|
|
2532
|
+
throw new TypeError(`Invalid key for this operation, its "use" must be "${expected}" when present`);
|
|
2533
|
+
}
|
|
2534
|
+
}
|
|
2535
|
+
if (key.alg !== void 0 && key.alg !== alg) {
|
|
2536
|
+
throw new TypeError(`Invalid key for this operation, its "alg" must be "${alg}" when present`);
|
|
2537
|
+
}
|
|
2538
|
+
if (Array.isArray(key.key_ops)) {
|
|
2539
|
+
const expectedKeyOp = usage === "encrypt" || usage === "decrypt" ? entry.ops?.[usage === "encrypt" ? 0 : 1] : usage;
|
|
2540
|
+
if (expectedKeyOp && !key.key_ops.includes(expectedKeyOp)) {
|
|
2541
|
+
throw new TypeError(`Invalid key for this operation, its "key_ops" must include "${expectedKeyOp}" when present`);
|
|
2542
|
+
}
|
|
2543
|
+
}
|
|
2544
|
+
};
|
|
2545
|
+
function checkKeyType(entry, key, usage) {
|
|
2546
|
+
const { alg, secret } = entry;
|
|
2547
|
+
const privateKey = usage === "decrypt" || usage === "sign";
|
|
2548
|
+
if (secret && key instanceof Uint8Array)
|
|
2549
|
+
return [BYTES, key];
|
|
2550
|
+
if (isObject2(key)) {
|
|
2551
|
+
const normalized = normalizeJwk(key);
|
|
2552
|
+
if (typeof normalized.kty !== "string") {
|
|
2553
|
+
throw new TypeError(secret ? withAlg(alg, key, "CryptoKey", "KeyObject", "JSON Web Key", "Uint8Array") : withAlg(alg, key, "CryptoKey", "KeyObject", "JSON Web Key"));
|
|
2554
|
+
}
|
|
2555
|
+
const valid = secret ? normalized.kty === "oct" && typeof normalized.k === "string" : normalized.kty !== "oct" && (privateKey ? normalized.kty === "AKP" && typeof normalized.priv === "string" || typeof normalized.d === "string" : normalized.d === void 0 && normalized.priv === void 0);
|
|
2556
|
+
if (!valid) {
|
|
2557
|
+
throw new TypeError(secret ? `JSON Web Key for symmetric algorithms must have JWK "kty" (Key Type) equal to "oct" and the JWK "k" (Key Value) present` : `JSON Web Key for this operation must be a ${privateKey ? "private" : "public"} JWK`);
|
|
2558
|
+
}
|
|
2559
|
+
jwkMatchesOp(entry, normalized, usage);
|
|
2560
|
+
return [JWK, key, normalized];
|
|
2561
|
+
}
|
|
2562
|
+
if (!isKeyLike(key)) {
|
|
2563
|
+
throw new TypeError(secret ? withAlg(alg, key, "CryptoKey", "KeyObject", "JSON Web Key", "Uint8Array") : withAlg(alg, key, "CryptoKey", "KeyObject", "JSON Web Key"));
|
|
2564
|
+
}
|
|
2565
|
+
if (secret) {
|
|
2566
|
+
if (key.type !== "secret") {
|
|
2567
|
+
throw new TypeError(`${tag(key)} instances for symmetric algorithms must be of type "secret"`);
|
|
2568
|
+
}
|
|
2569
|
+
} else {
|
|
2570
|
+
if (key.type === "secret") {
|
|
2571
|
+
throw new TypeError(`${tag(key)} instances for asymmetric algorithms must not be of type "secret"`);
|
|
2572
|
+
}
|
|
2573
|
+
const expectedType = privateKey ? "private" : "public";
|
|
2574
|
+
if ((key.type === "public" || key.type === "private") && key.type !== expectedType) {
|
|
2575
|
+
const operation = usage === "sign" ? "signing" : usage === "verify" ? "verifying" : `${usage.slice(0, -1)}tion`;
|
|
2576
|
+
throw new TypeError(`${tag(key)} instances for asymmetric algorithm ${operation} must be of type "${expectedType}"`);
|
|
2577
|
+
}
|
|
2578
|
+
}
|
|
2579
|
+
return isCryptoKey(key) ? [CRYPTO, key] : [KEYOBJECT, key];
|
|
2580
|
+
}
|
|
2581
|
+
var BYTES = 0;
|
|
2582
|
+
var CRYPTO = 1;
|
|
2583
|
+
var KEYOBJECT = 2;
|
|
2584
|
+
var JWK = 3;
|
|
2585
|
+
var cache;
|
|
2586
|
+
var nist = {
|
|
2587
|
+
__proto__: null,
|
|
2588
|
+
prime256v1: "P-256",
|
|
2589
|
+
secp384r1: "P-384",
|
|
2590
|
+
secp521r1: "P-521"
|
|
2591
|
+
};
|
|
2592
|
+
function cached(key, alg, value) {
|
|
2593
|
+
cache ||= /* @__PURE__ */ new WeakMap();
|
|
2594
|
+
const entry = cache.get(key);
|
|
2595
|
+
if (value) {
|
|
2596
|
+
if (entry) {
|
|
2597
|
+
entry[alg] = value;
|
|
2598
|
+
} else {
|
|
2599
|
+
cache.set(key, { [alg]: value });
|
|
2600
|
+
}
|
|
2601
|
+
}
|
|
2602
|
+
return value ?? entry?.[alg];
|
|
2603
|
+
}
|
|
2604
|
+
var handleJWK = async (key, jwk, entry) => cached(key, entry.alg) ?? cached(key, entry.alg, await jwkToKey(entry, { ...jwk, alg: entry.alg }));
|
|
2605
|
+
var handleKeyObject = (keyObject, entry) => {
|
|
2606
|
+
const hit = cached(keyObject, entry.alg);
|
|
2607
|
+
if (hit)
|
|
2608
|
+
return hit;
|
|
2609
|
+
const isPublic = keyObject.type === "public";
|
|
2610
|
+
const usages = entry.usages[isPublic ? 0 : 1];
|
|
2611
|
+
const { asymmetricKeyType } = keyObject;
|
|
2612
|
+
const crv = nist[keyObject.asymmetricKeyDetails?.namedCurve];
|
|
2613
|
+
const params = entry.resolve?.({ crv, asymmetricKeyType }) ?? entry.subtle;
|
|
2614
|
+
return cached(keyObject, entry.alg, keyObject.toCryptoKey(params, isPublic, usages));
|
|
2615
|
+
};
|
|
2616
|
+
async function prepareKey(entry, key, usage) {
|
|
2617
|
+
const tagged = checkKeyType(entry, key, usage);
|
|
2618
|
+
switch (tagged[0]) {
|
|
2619
|
+
case BYTES:
|
|
2620
|
+
case CRYPTO:
|
|
2621
|
+
return tagged[1];
|
|
2622
|
+
case JWK: {
|
|
2623
|
+
const key2 = tagged[1];
|
|
2624
|
+
const normalized = tagged[2];
|
|
2625
|
+
if (normalized.kty === "oct") {
|
|
2626
|
+
return decode(normalized.k);
|
|
2627
|
+
}
|
|
2628
|
+
if (!Object.isFrozen(key2)) {
|
|
2629
|
+
const { key_ops } = key2;
|
|
2630
|
+
if (Array.isArray(key_ops))
|
|
2631
|
+
Object.freeze(key_ops);
|
|
2632
|
+
Object.freeze(key2);
|
|
2633
|
+
}
|
|
2634
|
+
return handleJWK(key2, normalized, entry);
|
|
2635
|
+
}
|
|
2636
|
+
case KEYOBJECT: {
|
|
2637
|
+
const keyObject = tagged[1];
|
|
2638
|
+
if (keyObject.type === "secret") {
|
|
2639
|
+
return keyObject.export();
|
|
2640
|
+
}
|
|
2641
|
+
if ("toCryptoKey" in keyObject && typeof keyObject.toCryptoKey === "function") {
|
|
2642
|
+
return handleKeyObject(keyObject, entry);
|
|
2643
|
+
}
|
|
2644
|
+
return handleJWK(keyObject, keyObject.export({ format: "jwk" }), entry);
|
|
2645
|
+
}
|
|
2646
|
+
}
|
|
2647
|
+
}
|
|
2648
|
+
|
|
2649
|
+
// node_modules/jose/dist/webapi/lib/key_descriptor.js
|
|
2650
|
+
function table(entries) {
|
|
2651
|
+
const out = { __proto__: null };
|
|
2652
|
+
for (const alg in entries) {
|
|
2653
|
+
out[alg] = { ...entries[alg], alg };
|
|
2654
|
+
}
|
|
2655
|
+
return out;
|
|
2656
|
+
}
|
|
2657
|
+
|
|
2658
|
+
// node_modules/jose/dist/webapi/lib/options.js
|
|
2659
|
+
var JWS_RECOGNIZED = { __proto__: null, b64: true };
|
|
2660
|
+
function validateAlgorithms(option, algorithms) {
|
|
2661
|
+
if (algorithms !== void 0 && (!Array.isArray(algorithms) || algorithms.some((s) => typeof s !== "string"))) {
|
|
2662
|
+
throw new TypeError(`"${option}" option must be an array of strings`);
|
|
2663
|
+
}
|
|
2664
|
+
if (!algorithms) {
|
|
2665
|
+
return void 0;
|
|
2666
|
+
}
|
|
2667
|
+
return new Set(algorithms);
|
|
2668
|
+
}
|
|
2669
|
+
function validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader, joseHeader) {
|
|
2670
|
+
if (joseHeader.crit !== void 0 && protectedHeader?.crit === void 0) {
|
|
2671
|
+
throw new Err('"crit" (Critical) Header Parameter MUST be integrity protected');
|
|
2672
|
+
}
|
|
2673
|
+
if (!protectedHeader || protectedHeader.crit === void 0) {
|
|
2674
|
+
return [];
|
|
2675
|
+
}
|
|
2676
|
+
if (!Array.isArray(protectedHeader.crit) || protectedHeader.crit.length === 0 || protectedHeader.crit.some((input) => typeof input !== "string" || input.length === 0)) {
|
|
2677
|
+
throw new Err('"crit" (Critical) Header Parameter MUST be an array of non-empty strings when present');
|
|
2678
|
+
}
|
|
2679
|
+
const recognized = recognizedOption === void 0 ? recognizedDefault : { __proto__: null, ...recognizedOption, ...recognizedDefault };
|
|
2680
|
+
for (const parameter of protectedHeader.crit) {
|
|
2681
|
+
if (!(parameter in recognized)) {
|
|
2682
|
+
throw new JOSENotSupported(`Extension Header Parameter "${parameter}" is not recognized`);
|
|
2683
|
+
}
|
|
2684
|
+
if (!Object.hasOwn(joseHeader, parameter) || joseHeader[parameter] === void 0) {
|
|
2685
|
+
throw new Err(`Extension Header Parameter "${parameter}" is missing`);
|
|
2686
|
+
}
|
|
2687
|
+
if (recognized[parameter] && (!Object.hasOwn(protectedHeader, parameter) || protectedHeader[parameter] === void 0)) {
|
|
2688
|
+
throw new Err(`Extension Header Parameter "${parameter}" MUST be integrity protected`);
|
|
2689
|
+
}
|
|
2690
|
+
}
|
|
2691
|
+
return protectedHeader.crit;
|
|
2692
|
+
}
|
|
2693
|
+
function validateB64(protectedHeader, extensions) {
|
|
2694
|
+
if (extensions.includes("b64")) {
|
|
2695
|
+
const b64 = protectedHeader.b64;
|
|
2696
|
+
if (typeof b64 !== "boolean") {
|
|
2697
|
+
throw new JWSInvalid('The "b64" (base64url-encode payload) Header Parameter must be a boolean');
|
|
2698
|
+
}
|
|
2699
|
+
return b64;
|
|
2700
|
+
}
|
|
2701
|
+
return true;
|
|
2702
|
+
}
|
|
2703
|
+
|
|
2704
|
+
// node_modules/jose/dist/webapi/lib/signing.js
|
|
2705
|
+
async function getSigKey(entry, key, usage) {
|
|
2706
|
+
if (key instanceof Uint8Array) {
|
|
2707
|
+
return crypto.subtle.importKey("raw", key, entry.subtle, false, [
|
|
2708
|
+
usage
|
|
2709
|
+
]);
|
|
2710
|
+
}
|
|
2711
|
+
checkCryptoKey(key, entry.subtle, usage);
|
|
2712
|
+
if (entry.minRsaBits)
|
|
2713
|
+
checkModulusLength(entry.alg, key);
|
|
2714
|
+
return key;
|
|
2715
|
+
}
|
|
2716
|
+
async function verify(entry, key, signature, data) {
|
|
2717
|
+
const cryptoKey = await getSigKey(entry, key, "verify");
|
|
2718
|
+
try {
|
|
2719
|
+
return await crypto.subtle.verify(entry.signing, cryptoKey, signature, data);
|
|
2720
|
+
} catch {
|
|
2721
|
+
return false;
|
|
2722
|
+
}
|
|
2723
|
+
}
|
|
2724
|
+
|
|
2725
|
+
// node_modules/jose/dist/webapi/lib/jws_algorithms.js
|
|
2726
|
+
var sig = [["verify"], ["sign"]];
|
|
2727
|
+
function hmac(bits) {
|
|
2728
|
+
const subtle = { name: "HMAC", hash: `SHA-${bits}` };
|
|
2729
|
+
return { kty: ["oct"], secret: true, subtle, signing: subtle, usages: sig };
|
|
2730
|
+
}
|
|
2731
|
+
function rsa(bits, saltLength) {
|
|
2732
|
+
const name = saltLength ? "RSA-PSS" : "RSASSA-PKCS1-v1_5";
|
|
2733
|
+
const subtle = { name, hash: `SHA-${bits}` };
|
|
2734
|
+
return {
|
|
2735
|
+
kty: ["RSA"],
|
|
2736
|
+
subtle,
|
|
2737
|
+
signing: saltLength ? { ...subtle, saltLength } : subtle,
|
|
2738
|
+
usages: sig,
|
|
2739
|
+
minRsaBits: 2048
|
|
2086
2740
|
};
|
|
2087
2741
|
}
|
|
2742
|
+
function ecdsa(crv, bits) {
|
|
2743
|
+
return {
|
|
2744
|
+
kty: ["EC"],
|
|
2745
|
+
crv,
|
|
2746
|
+
subtle: { name: "ECDSA", namedCurve: crv },
|
|
2747
|
+
signing: { name: "ECDSA", hash: `SHA-${bits}` },
|
|
2748
|
+
usages: sig
|
|
2749
|
+
};
|
|
2750
|
+
}
|
|
2751
|
+
function eddsa() {
|
|
2752
|
+
const subtle = { name: "Ed25519" };
|
|
2753
|
+
return {
|
|
2754
|
+
kty: ["OKP"],
|
|
2755
|
+
crv: "Ed25519",
|
|
2756
|
+
subtle,
|
|
2757
|
+
signing: subtle,
|
|
2758
|
+
usages: sig
|
|
2759
|
+
};
|
|
2760
|
+
}
|
|
2761
|
+
function mldsa(bits) {
|
|
2762
|
+
const name = `ML-DSA-${bits}`;
|
|
2763
|
+
const subtle = { name };
|
|
2764
|
+
return {
|
|
2765
|
+
kty: ["AKP"],
|
|
2766
|
+
subtle,
|
|
2767
|
+
signing: subtle,
|
|
2768
|
+
usages: sig
|
|
2769
|
+
};
|
|
2770
|
+
}
|
|
2771
|
+
var JWS = table({
|
|
2772
|
+
HS256: hmac(256),
|
|
2773
|
+
HS384: hmac(384),
|
|
2774
|
+
HS512: hmac(512),
|
|
2775
|
+
RS256: rsa(256),
|
|
2776
|
+
RS384: rsa(384),
|
|
2777
|
+
RS512: rsa(512),
|
|
2778
|
+
PS256: rsa(256, 32),
|
|
2779
|
+
PS384: rsa(384, 48),
|
|
2780
|
+
PS512: rsa(512, 64),
|
|
2781
|
+
ES256: ecdsa("P-256", 256),
|
|
2782
|
+
ES384: ecdsa("P-384", 384),
|
|
2783
|
+
ES512: ecdsa("P-521", 512),
|
|
2784
|
+
EdDSA: eddsa(),
|
|
2785
|
+
Ed25519: eddsa(),
|
|
2786
|
+
"ML-DSA-44": mldsa(44),
|
|
2787
|
+
"ML-DSA-65": mldsa(65),
|
|
2788
|
+
"ML-DSA-87": mldsa(87)
|
|
2789
|
+
});
|
|
2790
|
+
function jwsAlgorithm(alg) {
|
|
2791
|
+
const entry = typeof alg === "string" ? JWS[alg] : void 0;
|
|
2792
|
+
if (!entry) {
|
|
2793
|
+
throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`);
|
|
2794
|
+
}
|
|
2795
|
+
return entry;
|
|
2796
|
+
}
|
|
2797
|
+
|
|
2798
|
+
// node_modules/jose/dist/webapi/lib/jws_verify.js
|
|
2799
|
+
function prepareVerify(options) {
|
|
2800
|
+
return [options && validateAlgorithms("algorithms", options.algorithms), options?.crit];
|
|
2801
|
+
}
|
|
2802
|
+
function parseProtectedHeader(encodedProtected, parsedProtected = encodedProtected === void 0 ? {} : parseJoseHeader(encodedProtected, JWSInvalid, "JWS Protected Header is invalid")) {
|
|
2803
|
+
return parsedProtected;
|
|
2804
|
+
}
|
|
2805
|
+
function validateJwsHeaders(parsedProt, joseHeader, shared) {
|
|
2806
|
+
const b64 = validateB64(parsedProt, validateCrit(JWSInvalid, JWS_RECOGNIZED, shared[1], parsedProt, joseHeader));
|
|
2807
|
+
const alg = joseHeader.alg;
|
|
2808
|
+
if (typeof alg !== "string" || !alg) {
|
|
2809
|
+
throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid');
|
|
2810
|
+
}
|
|
2811
|
+
if (shared[0] && !shared[0].has(alg)) {
|
|
2812
|
+
throw new JOSEAlgNotAllowed('"alg" (Algorithm) Header Parameter value not allowed');
|
|
2813
|
+
}
|
|
2814
|
+
return [b64, alg];
|
|
2815
|
+
}
|
|
2816
|
+
function encodeCompactUnencodedPayload(payload) {
|
|
2817
|
+
try {
|
|
2818
|
+
return encode(payload);
|
|
2819
|
+
} catch {
|
|
2820
|
+
throw new JWSInvalid("JWS Compact Serialization payload must use only ASCII characters");
|
|
2821
|
+
}
|
|
2822
|
+
}
|
|
2823
|
+
async function verifyPrepared(jws, shared, key, encodedProtected, parsedProt, alg, signingPayload) {
|
|
2824
|
+
let resolvedKey = false;
|
|
2825
|
+
if (typeof key === "function") {
|
|
2826
|
+
key = await key(parsedProt, jws);
|
|
2827
|
+
resolvedKey = true;
|
|
2828
|
+
}
|
|
2829
|
+
const b64 = typeof signingPayload === "string";
|
|
2830
|
+
const entry = jwsAlgorithm(alg);
|
|
2831
|
+
const data = concat(encodedProtected !== void 0 ? encode(encodedProtected) : new Uint8Array(), encode("."), b64 ? shared[2] ??= encodeBase64url(signingPayload, "payload", JWSInvalid) : signingPayload);
|
|
2832
|
+
const signature = decodeBase64url(jws.signature, "signature", JWSInvalid);
|
|
2833
|
+
const k = await prepareKey(entry, key, "verify");
|
|
2834
|
+
if (!await verify(entry, k, signature, data)) {
|
|
2835
|
+
throw new JWSSignatureVerificationFailed();
|
|
2836
|
+
}
|
|
2837
|
+
const payload = b64 ? decodeBase64url(signingPayload, "payload", JWSInvalid) : signingPayload;
|
|
2838
|
+
return [payload, parsedProt, b64, k, resolvedKey];
|
|
2839
|
+
}
|
|
2840
|
+
async function verifyCompact(jws, shared, key) {
|
|
2841
|
+
if (jws instanceof Uint8Array) {
|
|
2842
|
+
jws = decoder.decode(jws);
|
|
2843
|
+
}
|
|
2844
|
+
if (typeof jws !== "string") {
|
|
2845
|
+
throw new JWSInvalid("Compact JWS must be a string or Uint8Array");
|
|
2846
|
+
}
|
|
2847
|
+
const { 0: protectedHeader, 1: payload, 2: signature, length } = jws.split(".");
|
|
2848
|
+
if (length !== 3) {
|
|
2849
|
+
throw new JWSInvalid("Invalid Compact JWS");
|
|
2850
|
+
}
|
|
2851
|
+
const compactJws = { payload, protected: protectedHeader, signature };
|
|
2852
|
+
const parsedProt = parseProtectedHeader(protectedHeader);
|
|
2853
|
+
const [b64, alg] = validateJwsHeaders(parsedProt, parsedProt, shared);
|
|
2854
|
+
const signingPayload = b64 ? payload : encodeCompactUnencodedPayload(payload);
|
|
2855
|
+
return verifyPrepared(compactJws, shared, key, protectedHeader, parsedProt, alg, signingPayload);
|
|
2856
|
+
}
|
|
2857
|
+
|
|
2858
|
+
// node_modules/jose/dist/webapi/lib/jwt_claims_set.js
|
|
2859
|
+
var epoch = (date) => Math.floor(date.getTime() / 1e3);
|
|
2860
|
+
var multipliers = {
|
|
2861
|
+
s: 1,
|
|
2862
|
+
m: 60,
|
|
2863
|
+
h: 3600,
|
|
2864
|
+
d: 86400,
|
|
2865
|
+
w: 604800,
|
|
2866
|
+
y: 31557600
|
|
2867
|
+
};
|
|
2868
|
+
var REGEX = /^(\+|\-)? ?(\d+|\d+\.\d+) ?(seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)(?: (ago|from now))?$/i;
|
|
2869
|
+
var checkFailed = "check_failed";
|
|
2870
|
+
function invalidDuration() {
|
|
2871
|
+
throw new TypeError("Invalid time period format");
|
|
2872
|
+
}
|
|
2873
|
+
function secs(str) {
|
|
2874
|
+
if (typeof str !== "string") {
|
|
2875
|
+
invalidDuration();
|
|
2876
|
+
}
|
|
2877
|
+
const matched = REGEX.exec(str);
|
|
2878
|
+
if (!matched || matched[4] && matched[1]) {
|
|
2879
|
+
invalidDuration();
|
|
2880
|
+
}
|
|
2881
|
+
const value = parseFloat(matched[2]);
|
|
2882
|
+
const numericDate = Math.round(value * multipliers[matched[3][0].toLowerCase()]);
|
|
2883
|
+
if (!Number.isFinite(numericDate)) {
|
|
2884
|
+
invalidDuration();
|
|
2885
|
+
}
|
|
2886
|
+
if (matched[1] === "-" || matched[4] === "ago") {
|
|
2887
|
+
return -numericDate;
|
|
2888
|
+
}
|
|
2889
|
+
return numericDate;
|
|
2890
|
+
}
|
|
2891
|
+
function validateInput(label, input) {
|
|
2892
|
+
if (!Number.isFinite(input)) {
|
|
2893
|
+
throw new TypeError(`Invalid ${label} input`);
|
|
2894
|
+
}
|
|
2895
|
+
return input;
|
|
2896
|
+
}
|
|
2897
|
+
var normalizeTyp = (value) => {
|
|
2898
|
+
const normalized = value.toLowerCase();
|
|
2899
|
+
return value.includes("/") ? normalized : `application/${normalized}`;
|
|
2900
|
+
};
|
|
2901
|
+
var checkAudiencePresence = (audPayload, audOption) => {
|
|
2902
|
+
if (typeof audPayload === "string") {
|
|
2903
|
+
return audOption.includes(audPayload);
|
|
2904
|
+
}
|
|
2905
|
+
if (Array.isArray(audPayload)) {
|
|
2906
|
+
return audOption.some((aud) => audPayload.includes(aud));
|
|
2907
|
+
}
|
|
2908
|
+
return false;
|
|
2909
|
+
};
|
|
2910
|
+
function validateNumericDate(payload, claim2, required = false) {
|
|
2911
|
+
const value = payload[claim2];
|
|
2912
|
+
if (value === void 0 && !required)
|
|
2913
|
+
return void 0;
|
|
2914
|
+
if (typeof value !== "number") {
|
|
2915
|
+
throw new JWTClaimValidationFailed(`"${claim2}" claim must be a number`, payload, claim2, "invalid");
|
|
2916
|
+
}
|
|
2917
|
+
return value;
|
|
2918
|
+
}
|
|
2919
|
+
function unexpectedClaim(payload, claim2) {
|
|
2920
|
+
throw new JWTClaimValidationFailed(`unexpected "${claim2}" claim value`, payload, claim2, checkFailed);
|
|
2921
|
+
}
|
|
2922
|
+
function validateClaimsSet(protectedHeader, encodedPayload, options = {}) {
|
|
2923
|
+
let payload;
|
|
2924
|
+
try {
|
|
2925
|
+
payload = JSON.parse(strictDecoder.decode(encodedPayload));
|
|
2926
|
+
} catch {
|
|
2927
|
+
}
|
|
2928
|
+
if (!isObject2(payload)) {
|
|
2929
|
+
throw new JWTInvalid("JWT Claims Set must be a top-level JSON object");
|
|
2930
|
+
}
|
|
2931
|
+
const { typ } = options;
|
|
2932
|
+
if (typ !== void 0 && (typeof protectedHeader.typ !== "string" || normalizeTyp(protectedHeader.typ) !== normalizeTyp(typ))) {
|
|
2933
|
+
throw new JWTClaimValidationFailed('unexpected "typ" JWT header value', payload, "typ", checkFailed);
|
|
2934
|
+
}
|
|
2935
|
+
const { requiredClaims = [], issuer, subject, audience, maxTokenAge } = options;
|
|
2936
|
+
const presenceCheck = [...requiredClaims];
|
|
2937
|
+
if (maxTokenAge !== void 0)
|
|
2938
|
+
presenceCheck.push("iat");
|
|
2939
|
+
if (audience !== void 0)
|
|
2940
|
+
presenceCheck.push("aud");
|
|
2941
|
+
if (subject !== void 0)
|
|
2942
|
+
presenceCheck.push("sub");
|
|
2943
|
+
if (issuer !== void 0)
|
|
2944
|
+
presenceCheck.push("iss");
|
|
2945
|
+
for (const claim2 of new Set(presenceCheck.reverse())) {
|
|
2946
|
+
if (!Object.hasOwn(payload, claim2)) {
|
|
2947
|
+
throw new JWTClaimValidationFailed(`missing required "${claim2}" claim`, payload, claim2, "missing");
|
|
2948
|
+
}
|
|
2949
|
+
}
|
|
2950
|
+
if (issuer !== void 0 && !(Array.isArray(issuer) ? issuer : [issuer]).includes(payload.iss)) {
|
|
2951
|
+
unexpectedClaim(payload, "iss");
|
|
2952
|
+
}
|
|
2953
|
+
if (subject !== void 0 && payload.sub !== subject) {
|
|
2954
|
+
unexpectedClaim(payload, "sub");
|
|
2955
|
+
}
|
|
2956
|
+
if (audience !== void 0 && !checkAudiencePresence(payload.aud, typeof audience === "string" ? [audience] : audience)) {
|
|
2957
|
+
unexpectedClaim(payload, "aud");
|
|
2958
|
+
}
|
|
2959
|
+
const { clockTolerance } = options;
|
|
2960
|
+
let tolerance = 0;
|
|
2961
|
+
if (typeof clockTolerance === "string") {
|
|
2962
|
+
tolerance = secs(clockTolerance);
|
|
2963
|
+
} else if (clockTolerance !== void 0) {
|
|
2964
|
+
if (typeof clockTolerance !== "number") {
|
|
2965
|
+
throw new TypeError("Invalid clockTolerance option type");
|
|
2966
|
+
}
|
|
2967
|
+
tolerance = clockTolerance;
|
|
2968
|
+
}
|
|
2969
|
+
validateInput("clockTolerance option", tolerance);
|
|
2970
|
+
const { currentDate } = options;
|
|
2971
|
+
const now = validateInput("currentDate option", epoch(currentDate === void 0 ? /* @__PURE__ */ new Date() : currentDate));
|
|
2972
|
+
const iat = validateNumericDate(payload, "iat", maxTokenAge !== void 0);
|
|
2973
|
+
const nbf = validateNumericDate(payload, "nbf");
|
|
2974
|
+
if (nbf !== void 0) {
|
|
2975
|
+
if (nbf > now + tolerance) {
|
|
2976
|
+
throw new JWTClaimValidationFailed('"nbf" claim timestamp check failed', payload, "nbf", checkFailed);
|
|
2977
|
+
}
|
|
2978
|
+
}
|
|
2979
|
+
const exp = validateNumericDate(payload, "exp");
|
|
2980
|
+
if (exp !== void 0) {
|
|
2981
|
+
if (exp <= now - tolerance) {
|
|
2982
|
+
throw new JWTExpired('"exp" claim timestamp check failed', payload, "exp", checkFailed);
|
|
2983
|
+
}
|
|
2984
|
+
}
|
|
2985
|
+
if (maxTokenAge !== void 0) {
|
|
2986
|
+
const age = now - iat;
|
|
2987
|
+
const max = validateInput("maxTokenAge option", typeof maxTokenAge === "number" ? maxTokenAge : secs(maxTokenAge));
|
|
2988
|
+
if (age - tolerance > max) {
|
|
2989
|
+
throw new JWTExpired('"iat" claim timestamp check failed (too far in the past)', payload, "iat", checkFailed);
|
|
2990
|
+
}
|
|
2991
|
+
if (age < -tolerance) {
|
|
2992
|
+
throw new JWTClaimValidationFailed('"iat" claim timestamp check failed (it should be in the past)', payload, "iat", checkFailed);
|
|
2993
|
+
}
|
|
2994
|
+
}
|
|
2995
|
+
return payload;
|
|
2996
|
+
}
|
|
2997
|
+
|
|
2998
|
+
// node_modules/jose/dist/webapi/jwt/verify.js
|
|
2999
|
+
async function jwtVerify(jwt, key, options) {
|
|
3000
|
+
const verified = await verifyCompact(jwt, prepareVerify(options), key);
|
|
3001
|
+
if (!verified[2]) {
|
|
3002
|
+
throw new JWTInvalid("JWTs MUST NOT use unencoded payload");
|
|
3003
|
+
}
|
|
3004
|
+
const payload = validateClaimsSet(verified[1], verified[0], options);
|
|
3005
|
+
const result = { payload, protectedHeader: verified[1] };
|
|
3006
|
+
if (typeof key === "function") {
|
|
3007
|
+
return { ...result, key: verified[3] };
|
|
3008
|
+
}
|
|
3009
|
+
return result;
|
|
3010
|
+
}
|
|
3011
|
+
|
|
3012
|
+
// node_modules/jose/dist/webapi/jwks/local.js
|
|
3013
|
+
function isUsableJWK(jwk, entry, alg, kid) {
|
|
3014
|
+
const { kty, key_ops, ext, kid: jwkKid, alg: jwkAlg, use, crv } = snapshotJwk(jwk);
|
|
3015
|
+
const keyOps = Array.isArray(key_ops) ? [...key_ops] : key_ops;
|
|
3016
|
+
return (ext === void 0 || typeof ext === "boolean") && (keyOps === void 0 || Array.isArray(keyOps) && keyOps.every((operation, index) => typeof operation === "string" && keyOps.indexOf(operation) === index) && keyOps.includes("verify")) && entry.kty.includes(kty) && (kid === void 0 || typeof kid === "string" && kid === jwkKid) && (jwkAlg === void 0 ? kty !== "AKP" : alg === jwkAlg) && (use === void 0 || use === "sig") && (!entry.crv || crv === entry.crv);
|
|
3017
|
+
}
|
|
3018
|
+
async function importWithAlgCache(cache2, jwk, entry) {
|
|
3019
|
+
const cached2 = cache2.get(jwk) || cache2.set(jwk, {}).get(jwk);
|
|
3020
|
+
const { alg } = entry;
|
|
3021
|
+
if (cached2[alg] === void 0) {
|
|
3022
|
+
const key = await jwkToKey(entry, { ...jwk, alg, ext: true });
|
|
3023
|
+
if (key.type !== "public") {
|
|
3024
|
+
throw new JWKSInvalid("JSON Web Key Set members must be public keys");
|
|
3025
|
+
}
|
|
3026
|
+
cached2[alg] = key;
|
|
3027
|
+
}
|
|
3028
|
+
return cached2[alg];
|
|
3029
|
+
}
|
|
3030
|
+
function createLocalJWKSet(jwks) {
|
|
3031
|
+
let snapshot;
|
|
3032
|
+
try {
|
|
3033
|
+
snapshot = structuredClone(jwks);
|
|
3034
|
+
} catch {
|
|
3035
|
+
}
|
|
3036
|
+
if (!isJwkSet(snapshot)) {
|
|
3037
|
+
throw new JWKSInvalid("JSON Web Key Set malformed");
|
|
3038
|
+
}
|
|
3039
|
+
const cached2 = /* @__PURE__ */ new WeakMap();
|
|
3040
|
+
const localJWKSet = async (protectedHeader, token) => {
|
|
3041
|
+
const { alg, kid } = { ...protectedHeader, ...token?.header };
|
|
3042
|
+
const entry = typeof alg === "string" ? JWS[alg] : void 0;
|
|
3043
|
+
if (!entry || entry.secret) {
|
|
3044
|
+
throw new JOSENotSupported('Unsupported "alg" value for a JSON Web Key Set');
|
|
3045
|
+
}
|
|
3046
|
+
const candidates = snapshot.keys.filter((jwk2) => isUsableJWK(jwk2, entry, alg, kid));
|
|
3047
|
+
const { 0: jwk, length } = candidates;
|
|
3048
|
+
if (!length) {
|
|
3049
|
+
throw new JWKSNoMatchingKey();
|
|
3050
|
+
}
|
|
3051
|
+
if (length !== 1) {
|
|
3052
|
+
const error = new JWKSMultipleMatchingKeys();
|
|
3053
|
+
error[Symbol.asyncIterator] = async function* () {
|
|
3054
|
+
for (const jwk2 of candidates) {
|
|
3055
|
+
try {
|
|
3056
|
+
yield await importWithAlgCache(cached2, jwk2, entry);
|
|
3057
|
+
} catch {
|
|
3058
|
+
}
|
|
3059
|
+
}
|
|
3060
|
+
};
|
|
3061
|
+
throw error;
|
|
3062
|
+
}
|
|
3063
|
+
return importWithAlgCache(cached2, jwk, entry);
|
|
3064
|
+
};
|
|
3065
|
+
return Object.defineProperty(localJWKSet, "jwks", {
|
|
3066
|
+
value: () => structuredClone(snapshot)
|
|
3067
|
+
});
|
|
3068
|
+
}
|
|
3069
|
+
|
|
3070
|
+
// src/runtime/github-oidc.ts
|
|
3071
|
+
var githubIssuer = "https://token.actions.githubusercontent.com";
|
|
3072
|
+
var githubJwksUrl = new URL(`${githubIssuer}/.well-known/jwks`);
|
|
3073
|
+
var maximumJwksBytes = 64 * 1024;
|
|
3074
|
+
var maximumJwksKeys = 16;
|
|
3075
|
+
var jwksCacheMilliseconds = 5 * 60 * 1e3;
|
|
3076
|
+
var jwksCooldownMilliseconds = 30 * 1e3;
|
|
3077
|
+
var jwksTimeoutMilliseconds = 5e3;
|
|
3078
|
+
var maximumClaimLength = 512;
|
|
3079
|
+
var cachedJwks;
|
|
3080
|
+
var pendingJwks;
|
|
3081
|
+
var GitHubOidcUnavailableError = class extends Error {
|
|
3082
|
+
name = "GitHubOidcUnavailableError";
|
|
3083
|
+
};
|
|
3084
|
+
function isObject3(value) {
|
|
3085
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3086
|
+
}
|
|
3087
|
+
async function readBoundedBody(response) {
|
|
3088
|
+
if (response.body === null) throw new GitHubOidcUnavailableError("GitHub JWKS response is empty");
|
|
3089
|
+
const reader = response.body.getReader();
|
|
3090
|
+
const decoder2 = new TextDecoder("utf-8", { fatal: true });
|
|
3091
|
+
let size = 0;
|
|
3092
|
+
let contents = "";
|
|
3093
|
+
try {
|
|
3094
|
+
while (true) {
|
|
3095
|
+
const { done, value } = await reader.read();
|
|
3096
|
+
if (done) break;
|
|
3097
|
+
size += value.byteLength;
|
|
3098
|
+
if (size > maximumJwksBytes) {
|
|
3099
|
+
await reader.cancel();
|
|
3100
|
+
throw new GitHubOidcUnavailableError("GitHub JWKS response is too large");
|
|
3101
|
+
}
|
|
3102
|
+
contents += decoder2.decode(value, { stream: true });
|
|
3103
|
+
}
|
|
3104
|
+
contents += decoder2.decode();
|
|
3105
|
+
return contents;
|
|
3106
|
+
} catch (error) {
|
|
3107
|
+
if (error instanceof GitHubOidcUnavailableError) throw error;
|
|
3108
|
+
throw new GitHubOidcUnavailableError("GitHub JWKS response could not be read");
|
|
3109
|
+
} finally {
|
|
3110
|
+
reader.releaseLock();
|
|
3111
|
+
}
|
|
3112
|
+
}
|
|
3113
|
+
async function fetchJwks() {
|
|
3114
|
+
let response;
|
|
3115
|
+
try {
|
|
3116
|
+
response = await fetch(githubJwksUrl, {
|
|
3117
|
+
headers: { accept: "application/json" },
|
|
3118
|
+
redirect: "error",
|
|
3119
|
+
signal: AbortSignal.timeout(jwksTimeoutMilliseconds)
|
|
3120
|
+
});
|
|
3121
|
+
} catch {
|
|
3122
|
+
throw new GitHubOidcUnavailableError("GitHub JWKS endpoint is unavailable");
|
|
3123
|
+
}
|
|
3124
|
+
if (!response.ok)
|
|
3125
|
+
throw new GitHubOidcUnavailableError("GitHub JWKS endpoint rejected the request");
|
|
3126
|
+
let value;
|
|
3127
|
+
try {
|
|
3128
|
+
value = JSON.parse(await readBoundedBody(response));
|
|
3129
|
+
} catch (error) {
|
|
3130
|
+
if (error instanceof GitHubOidcUnavailableError) throw error;
|
|
3131
|
+
throw new GitHubOidcUnavailableError("GitHub JWKS response is invalid");
|
|
3132
|
+
}
|
|
3133
|
+
if (!isObject3(value) || !Array.isArray(value.keys) || value.keys.length === 0 || value.keys.length > maximumJwksKeys || value.keys.some(
|
|
3134
|
+
(key) => !isObject3(key) || key.kty !== "RSA" || typeof key.kid !== "string" || key.kid.length === 0 || key.kid.length > 256 || key.alg !== void 0 && key.alg !== "RS256" || key.use !== void 0 && key.use !== "sig" || typeof key.n !== "string" || typeof key.e !== "string"
|
|
3135
|
+
)) {
|
|
3136
|
+
throw new GitHubOidcUnavailableError("GitHub JWKS response is invalid");
|
|
3137
|
+
}
|
|
3138
|
+
let resolver;
|
|
3139
|
+
try {
|
|
3140
|
+
resolver = createLocalJWKSet(value);
|
|
3141
|
+
} catch {
|
|
3142
|
+
throw new GitHubOidcUnavailableError("GitHub JWKS response is invalid");
|
|
3143
|
+
}
|
|
3144
|
+
const fetchedAt = Date.now();
|
|
3145
|
+
return { resolver, fetchedAt, expiresAt: fetchedAt + jwksCacheMilliseconds };
|
|
3146
|
+
}
|
|
3147
|
+
async function loadJwks(force) {
|
|
3148
|
+
const now = Date.now();
|
|
3149
|
+
if (!force && cachedJwks !== void 0 && cachedJwks.expiresAt > now) return cachedJwks;
|
|
3150
|
+
if (pendingJwks !== void 0) return pendingJwks;
|
|
3151
|
+
pendingJwks = fetchJwks();
|
|
3152
|
+
try {
|
|
3153
|
+
cachedJwks = await pendingJwks;
|
|
3154
|
+
return cachedJwks;
|
|
3155
|
+
} finally {
|
|
3156
|
+
pendingJwks = void 0;
|
|
3157
|
+
}
|
|
3158
|
+
}
|
|
3159
|
+
async function resolveGithubKey(protectedHeader, token) {
|
|
3160
|
+
const jwks = await loadJwks(false);
|
|
3161
|
+
try {
|
|
3162
|
+
return await jwks.resolver(protectedHeader, token);
|
|
3163
|
+
} catch (error) {
|
|
3164
|
+
if (!(error instanceof errors_exports.JWKSNoMatchingKey) || Date.now() - jwks.fetchedAt < jwksCooldownMilliseconds) {
|
|
3165
|
+
throw error;
|
|
3166
|
+
}
|
|
3167
|
+
return (await loadJwks(true)).resolver(protectedHeader, token);
|
|
3168
|
+
}
|
|
3169
|
+
}
|
|
3170
|
+
function claim(payload, name) {
|
|
3171
|
+
const value = payload[name];
|
|
3172
|
+
return typeof value === "string" && value.length > 0 && value.length <= maximumClaimLength ? value : null;
|
|
3173
|
+
}
|
|
3174
|
+
function matchesPattern(value, pattern) {
|
|
3175
|
+
return pattern.endsWith("*") ? value.startsWith(pattern.slice(0, -1)) : value === pattern;
|
|
3176
|
+
}
|
|
3177
|
+
function grants(permissions, required) {
|
|
3178
|
+
return permissions.includes("publish") || permissions.includes(required);
|
|
3179
|
+
}
|
|
3180
|
+
function grantsPackage(patterns, packageName) {
|
|
3181
|
+
if (packageName === void 0) return true;
|
|
3182
|
+
return patterns.some((pattern) => {
|
|
3183
|
+
if (pattern.endsWith("/*")) return packageName.startsWith(pattern.slice(0, -1));
|
|
3184
|
+
return packageName === pattern;
|
|
3185
|
+
});
|
|
3186
|
+
}
|
|
3187
|
+
async function authorizeGitHubOidc(token, context, required, packageName) {
|
|
3188
|
+
const configuration = context.config.auth.githubOidc;
|
|
3189
|
+
if (configuration === void 0) return false;
|
|
3190
|
+
let payload;
|
|
3191
|
+
try {
|
|
3192
|
+
const verified = await jwtVerify(token, resolveGithubKey, {
|
|
3193
|
+
algorithms: ["RS256"],
|
|
3194
|
+
audience: configuration.audience,
|
|
3195
|
+
clockTolerance: 5,
|
|
3196
|
+
issuer: githubIssuer,
|
|
3197
|
+
maxTokenAge: "10m",
|
|
3198
|
+
requiredClaims: [
|
|
3199
|
+
"sub",
|
|
3200
|
+
"exp",
|
|
3201
|
+
"iat",
|
|
3202
|
+
"nbf",
|
|
3203
|
+
"jti",
|
|
3204
|
+
"repository_id",
|
|
3205
|
+
"repository_owner_id",
|
|
3206
|
+
"ref",
|
|
3207
|
+
"workflow_ref",
|
|
3208
|
+
"event_name"
|
|
3209
|
+
],
|
|
3210
|
+
typ: "JWT"
|
|
3211
|
+
});
|
|
3212
|
+
payload = verified.payload;
|
|
3213
|
+
} catch (error) {
|
|
3214
|
+
if (error instanceof GitHubOidcUnavailableError) throw error;
|
|
3215
|
+
return false;
|
|
3216
|
+
}
|
|
3217
|
+
const repositoryId = claim(payload, "repository_id");
|
|
3218
|
+
const repositoryOwnerId = claim(payload, "repository_owner_id");
|
|
3219
|
+
const ref = claim(payload, "ref");
|
|
3220
|
+
const workflowRef = claim(payload, "workflow_ref");
|
|
3221
|
+
const eventName = claim(payload, "event_name");
|
|
3222
|
+
const jobWorkflowRef = claim(payload, "job_workflow_ref");
|
|
3223
|
+
if (repositoryId === null || repositoryOwnerId === null || ref === null || workflowRef === null || eventName === null) {
|
|
3224
|
+
return false;
|
|
3225
|
+
}
|
|
3226
|
+
if (eventName.includes("pull_request") || eventName === "merge_group") return false;
|
|
3227
|
+
return configuration.subjects.some(
|
|
3228
|
+
(subject) => subject.repositoryId === repositoryId && subject.repositoryOwnerId === repositoryOwnerId && matchesPattern(ref, subject.ref) && matchesPattern(workflowRef, subject.workflowRef) && (subject.jobWorkflowRef === void 0 ? jobWorkflowRef === null : jobWorkflowRef !== null && matchesPattern(jobWorkflowRef, subject.jobWorkflowRef)) && grants(subject.permissions, required) && grantsPackage(subject.packages, packageName)
|
|
3229
|
+
);
|
|
3230
|
+
}
|
|
2088
3231
|
|
|
2089
3232
|
// src/runtime/response.ts
|
|
2090
3233
|
function json(value, init = {}) {
|
|
@@ -2123,35 +3266,37 @@ function equalDigest(left, right) {
|
|
|
2123
3266
|
}
|
|
2124
3267
|
return difference === 0;
|
|
2125
3268
|
}
|
|
2126
|
-
function
|
|
3269
|
+
function grants2(permissions, required) {
|
|
2127
3270
|
return permissions.includes("publish") || permissions.includes(required);
|
|
2128
3271
|
}
|
|
2129
|
-
|
|
3272
|
+
var maximumBearerTokenBytes = 16 * 1024;
|
|
3273
|
+
async function authorize(request, context, required, packageName) {
|
|
2130
3274
|
const candidate = bearerToken(request);
|
|
2131
3275
|
if (candidate === null) {
|
|
2132
3276
|
return npmError(401, "unauthorized", "authentication required");
|
|
2133
3277
|
}
|
|
3278
|
+
if (candidate.length > maximumBearerTokenBytes) {
|
|
3279
|
+
return npmError(403, "forbidden", `token does not grant ${required} access`);
|
|
3280
|
+
}
|
|
2134
3281
|
const candidateDigest = await digest(candidate);
|
|
2135
3282
|
let authorized = false;
|
|
2136
3283
|
for (const token of context.config.auth.tokens) {
|
|
2137
3284
|
const secret = context.env[token.binding];
|
|
2138
3285
|
if (typeof secret !== "string" || secret.length === 0) continue;
|
|
2139
3286
|
const matches = equalDigest(candidateDigest, await digest(secret));
|
|
2140
|
-
authorized ||= matches &&
|
|
3287
|
+
authorized ||= matches && grants2(token.permissions, required);
|
|
2141
3288
|
}
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
})
|
|
2154
|
-
);
|
|
3289
|
+
if (authorized) return null;
|
|
3290
|
+
try {
|
|
3291
|
+
if (await authorizeGitHubOidc(candidate, context, required, packageName)) return null;
|
|
3292
|
+
} catch (error) {
|
|
3293
|
+
if (error instanceof GitHubOidcUnavailableError) {
|
|
3294
|
+
logRegistryError(context.requestId, "github_oidc_jwks", error);
|
|
3295
|
+
return npmError(503, "authentication_unavailable", "OIDC authentication is unavailable");
|
|
3296
|
+
}
|
|
3297
|
+
throw error;
|
|
3298
|
+
}
|
|
3299
|
+
return npmError(403, "forbidden", `token does not grant ${required} access`);
|
|
2155
3300
|
}
|
|
2156
3301
|
|
|
2157
3302
|
// src/runtime/dist-tags.ts
|
|
@@ -2193,15 +3338,15 @@ function parseDistTagRoute(pathname) {
|
|
|
2193
3338
|
if (scope === void 0 || name === void 0) return null;
|
|
2194
3339
|
const packageName = `${scope}/${name}`;
|
|
2195
3340
|
if (packageName.length > 214 || !packageNamePattern.test(packageName)) return null;
|
|
2196
|
-
const
|
|
2197
|
-
return
|
|
3341
|
+
const tag2 = segments[5];
|
|
3342
|
+
return tag2 === void 0 ? { packageName } : { packageName, tag: tag2 };
|
|
2198
3343
|
}
|
|
2199
3344
|
function isAllowedPackage(packageName, scopes) {
|
|
2200
3345
|
const separator = packageName.indexOf("/");
|
|
2201
3346
|
return separator > 0 && scopes.includes(packageName.slice(0, separator));
|
|
2202
3347
|
}
|
|
2203
|
-
function isValidDistTag(
|
|
2204
|
-
return /^[a-z0-9][a-z0-9._-]*$/i.test(
|
|
3348
|
+
function isValidDistTag(tag2) {
|
|
3349
|
+
return /^[a-z0-9][a-z0-9._-]*$/i.test(tag2) && (0, import_semver.validRange)(tag2, { loose: false }) === null;
|
|
2205
3350
|
}
|
|
2206
3351
|
|
|
2207
3352
|
// src/runtime/dist-tags.ts
|
|
@@ -2209,7 +3354,7 @@ var maximumDistTagBodyBytes = 256;
|
|
|
2209
3354
|
async function readVersion(request) {
|
|
2210
3355
|
if (request.body === null) throw new Error("missing body");
|
|
2211
3356
|
const reader = request.body.getReader();
|
|
2212
|
-
const
|
|
3357
|
+
const decoder2 = new TextDecoder("utf-8", { fatal: true });
|
|
2213
3358
|
let bytesRead = 0;
|
|
2214
3359
|
let contents = "";
|
|
2215
3360
|
try {
|
|
@@ -2221,17 +3366,17 @@ async function readVersion(request) {
|
|
|
2221
3366
|
await reader.cancel();
|
|
2222
3367
|
throw new PublishTagBodyError(413, "dist-tag request body exceeds 256 bytes");
|
|
2223
3368
|
}
|
|
2224
|
-
contents +=
|
|
3369
|
+
contents += decoder2.decode(value, { stream: true });
|
|
2225
3370
|
}
|
|
2226
|
-
contents +=
|
|
3371
|
+
contents += decoder2.decode();
|
|
2227
3372
|
return JSON.parse(contents);
|
|
2228
3373
|
} finally {
|
|
2229
3374
|
reader.releaseLock();
|
|
2230
3375
|
}
|
|
2231
3376
|
}
|
|
2232
3377
|
var PublishTagBodyError = class extends Error {
|
|
2233
|
-
constructor(status,
|
|
2234
|
-
super(
|
|
3378
|
+
constructor(status, message2) {
|
|
3379
|
+
super(message2);
|
|
2235
3380
|
this.status = status;
|
|
2236
3381
|
}
|
|
2237
3382
|
status;
|
|
@@ -2253,11 +3398,11 @@ async function readDistTags(context, packageName) {
|
|
|
2253
3398
|
headers: { "cache-control": "private, no-store" }
|
|
2254
3399
|
});
|
|
2255
3400
|
}
|
|
2256
|
-
async function setDistTag(request, context, packageName,
|
|
3401
|
+
async function setDistTag(request, context, packageName, tag2) {
|
|
2257
3402
|
if (!isAllowedPackage(packageName, context.config.scopes)) {
|
|
2258
3403
|
return npmError(404, "not_found", "package not found");
|
|
2259
3404
|
}
|
|
2260
|
-
if (!isValidDistTag(
|
|
3405
|
+
if (!isValidDistTag(tag2)) return npmError(400, "bad_request", "dist-tag is invalid");
|
|
2261
3406
|
let version;
|
|
2262
3407
|
try {
|
|
2263
3408
|
version = await readVersion(request);
|
|
@@ -2272,20 +3417,20 @@ async function setDistTag(request, context, packageName, tag) {
|
|
|
2272
3417
|
}
|
|
2273
3418
|
const result = await context.env.PKGFLARE_DB.prepare(
|
|
2274
3419
|
"INSERT INTO dist_tags (package_name, tag, version) SELECT package_name, ?3, version FROM versions WHERE package_name = ?1 AND version = ?2 ON CONFLICT(package_name, tag) DO UPDATE SET version = excluded.version"
|
|
2275
|
-
).bind(packageName, version,
|
|
3420
|
+
).bind(packageName, version, tag2).run();
|
|
2276
3421
|
if (result.meta.changes === 0) {
|
|
2277
3422
|
return npmError(404, "not_found", "package version not found");
|
|
2278
3423
|
}
|
|
2279
3424
|
return json({ ok: true });
|
|
2280
3425
|
}
|
|
2281
|
-
async function deleteDistTag(context, packageName,
|
|
3426
|
+
async function deleteDistTag(context, packageName, tag2) {
|
|
2282
3427
|
if (!isAllowedPackage(packageName, context.config.scopes)) {
|
|
2283
3428
|
return npmError(404, "not_found", "package not found");
|
|
2284
3429
|
}
|
|
2285
|
-
if (!isValidDistTag(
|
|
3430
|
+
if (!isValidDistTag(tag2)) return npmError(400, "bad_request", "dist-tag is invalid");
|
|
2286
3431
|
const result = await context.env.PKGFLARE_DB.prepare(
|
|
2287
3432
|
"DELETE FROM dist_tags WHERE package_name = ?1 AND tag = ?2"
|
|
2288
|
-
).bind(packageName,
|
|
3433
|
+
).bind(packageName, tag2).run();
|
|
2289
3434
|
return result.meta.changes === 0 ? npmError(404, "not_found", "dist-tag not found") : json({ ok: true });
|
|
2290
3435
|
}
|
|
2291
3436
|
|
|
@@ -2302,16 +3447,16 @@ for (let index = 0; index < base64Alphabet.length; index += 1) {
|
|
|
2302
3447
|
base64Values[base64Alphabet.charCodeAt(index)] = index;
|
|
2303
3448
|
}
|
|
2304
3449
|
var PublishStreamError = class extends Error {
|
|
2305
|
-
constructor(status, code,
|
|
2306
|
-
super(
|
|
3450
|
+
constructor(status, code, message2) {
|
|
3451
|
+
super(message2);
|
|
2307
3452
|
this.status = status;
|
|
2308
3453
|
this.code = code;
|
|
2309
3454
|
}
|
|
2310
3455
|
status;
|
|
2311
3456
|
code;
|
|
2312
3457
|
};
|
|
2313
|
-
function badJson(
|
|
2314
|
-
return new PublishStreamError(400, "bad_request",
|
|
3458
|
+
function badJson(message2 = "request body must be valid JSON") {
|
|
3459
|
+
return new PublishStreamError(400, "bad_request", message2);
|
|
2315
3460
|
}
|
|
2316
3461
|
function hex(bytes) {
|
|
2317
3462
|
return [...new Uint8Array(bytes)].map((value) => value.toString(16).padStart(2, "0")).join("");
|
|
@@ -2837,8 +3982,8 @@ async function parsePublishRequest(request, bucket, packageName) {
|
|
|
2837
3982
|
|
|
2838
3983
|
// src/runtime/publish.ts
|
|
2839
3984
|
var PublishError = class extends Error {
|
|
2840
|
-
constructor(status, code,
|
|
2841
|
-
super(
|
|
3985
|
+
constructor(status, code, message2) {
|
|
3986
|
+
super(message2);
|
|
2842
3987
|
this.status = status;
|
|
2843
3988
|
this.code = code;
|
|
2844
3989
|
}
|
|
@@ -2878,11 +4023,11 @@ function validateDocument(value, pathPackageName, scopes, tarball) {
|
|
|
2878
4023
|
throw new PublishError(400, "bad_request", "at least one dist-tag is required");
|
|
2879
4024
|
}
|
|
2880
4025
|
const tags = {};
|
|
2881
|
-
for (const [
|
|
2882
|
-
if (!/^[a-z0-9][a-z0-9._-]*$/i.test(
|
|
4026
|
+
for (const [tag2, target] of Object.entries(document["dist-tags"])) {
|
|
4027
|
+
if (!/^[a-z0-9][a-z0-9._-]*$/i.test(tag2) || target !== version) {
|
|
2883
4028
|
throw new PublishError(400, "bad_request", "dist-tags must reference the published version");
|
|
2884
4029
|
}
|
|
2885
|
-
tags[
|
|
4030
|
+
tags[tag2] = version;
|
|
2886
4031
|
}
|
|
2887
4032
|
if (!object(document._attachments) || Object.keys(document._attachments).length !== 1) {
|
|
2888
4033
|
throw new PublishError(
|
|
@@ -3016,9 +4161,9 @@ async function publishPackage(request, context, packageName) {
|
|
|
3016
4161
|
now
|
|
3017
4162
|
),
|
|
3018
4163
|
...Object.entries(publish.tags).map(
|
|
3019
|
-
([
|
|
4164
|
+
([tag2, version]) => context.env.PKGFLARE_DB.prepare(
|
|
3020
4165
|
"INSERT INTO dist_tags (package_name, tag, version) VALUES (?1, ?2, ?3) ON CONFLICT(package_name, tag) DO UPDATE SET version = excluded.version"
|
|
3021
|
-
).bind(publish.packageName,
|
|
4166
|
+
).bind(publish.packageName, tag2, version)
|
|
3022
4167
|
)
|
|
3023
4168
|
];
|
|
3024
4169
|
try {
|
|
@@ -3188,7 +4333,7 @@ async function handle(request, env, requestId) {
|
|
|
3188
4333
|
if (request.method !== "GET" && request.method !== "HEAD") {
|
|
3189
4334
|
return methodNotAllowed(["GET", "HEAD"]);
|
|
3190
4335
|
}
|
|
3191
|
-
const denied2 = await authorize(request, context, "read");
|
|
4336
|
+
const denied2 = await authorize(request, context, "read", distTagRoute.packageName);
|
|
3192
4337
|
if (denied2 !== null) return denied2;
|
|
3193
4338
|
const response = await readDistTags(context, distTagRoute.packageName);
|
|
3194
4339
|
return request.method === "HEAD" ? new Response(null, { status: response.status, headers: response.headers }) : response;
|
|
@@ -3196,7 +4341,7 @@ async function handle(request, env, requestId) {
|
|
|
3196
4341
|
if (request.method !== "PUT" && request.method !== "DELETE") {
|
|
3197
4342
|
return methodNotAllowed(["PUT", "DELETE"]);
|
|
3198
4343
|
}
|
|
3199
|
-
const denied = await authorize(request, context, "publish");
|
|
4344
|
+
const denied = await authorize(request, context, "publish", distTagRoute.packageName);
|
|
3200
4345
|
if (denied !== null) return denied;
|
|
3201
4346
|
return request.method === "PUT" ? setDistTag(request, context, distTagRoute.packageName, distTagRoute.tag) : deleteDistTag(context, distTagRoute.packageName, distTagRoute.tag);
|
|
3202
4347
|
}
|
|
@@ -3206,18 +4351,18 @@ async function handle(request, env, requestId) {
|
|
|
3206
4351
|
if (request.method !== "GET" && request.method !== "HEAD") {
|
|
3207
4352
|
return methodNotAllowed(["GET", "HEAD"]);
|
|
3208
4353
|
}
|
|
3209
|
-
const denied = await authorize(request, context, "read");
|
|
4354
|
+
const denied = await authorize(request, context, "read", route.packageName);
|
|
3210
4355
|
if (denied !== null) return denied;
|
|
3211
4356
|
return readTarball(request, context, route.packageName, route.remainder[1] ?? "");
|
|
3212
4357
|
}
|
|
3213
4358
|
if (route.remainder.length > 1) return npmError(404, "not_found", "endpoint not found");
|
|
3214
4359
|
if (request.method === "PUT" && route.remainder.length === 0) {
|
|
3215
|
-
const denied = await authorize(request, context, "publish");
|
|
4360
|
+
const denied = await authorize(request, context, "publish", route.packageName);
|
|
3216
4361
|
if (denied !== null) return denied;
|
|
3217
4362
|
return publishPackage(request, context, route.packageName);
|
|
3218
4363
|
}
|
|
3219
4364
|
if ((request.method === "GET" || request.method === "HEAD") && route.remainder.length <= 1) {
|
|
3220
|
-
const denied = await authorize(request, context, "read");
|
|
4365
|
+
const denied = await authorize(request, context, "read", route.packageName);
|
|
3221
4366
|
if (denied !== null) return denied;
|
|
3222
4367
|
const response = await readPackage(request, context, route.packageName, route.remainder[0]);
|
|
3223
4368
|
return request.method === "HEAD" ? new Response(null, { status: response.status, headers: response.headers }) : response;
|