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