修改后台权限

This commit is contained in:
yoyuzh
2026-03-24 14:30:59 +08:00
parent 00f902f475
commit b2d9db7be9
9310 changed files with 1246063 additions and 48 deletions

119
node_modules/jose/dist/webapi/jwks/local.js generated vendored Normal file
View File

@@ -0,0 +1,119 @@
import { importJWK } from '../key/import.js';
import { JWKSInvalid, JOSENotSupported, JWKSNoMatchingKey, JWKSMultipleMatchingKeys, } from '../util/errors.js';
import { isObject } from '../lib/type_checks.js';
function getKtyFromAlg(alg) {
switch (typeof alg === 'string' && alg.slice(0, 2)) {
case 'RS':
case 'PS':
return 'RSA';
case 'ES':
return 'EC';
case 'Ed':
return 'OKP';
case 'ML':
return 'AKP';
default:
throw new JOSENotSupported('Unsupported "alg" value for a JSON Web Key Set');
}
}
function isJWKSLike(jwks) {
return (jwks &&
typeof jwks === 'object' &&
Array.isArray(jwks.keys) &&
jwks.keys.every(isJWKLike));
}
function isJWKLike(key) {
return isObject(key);
}
class LocalJWKSet {
#jwks;
#cached = new WeakMap();
constructor(jwks) {
if (!isJWKSLike(jwks)) {
throw new JWKSInvalid('JSON Web Key Set malformed');
}
this.#jwks = structuredClone(jwks);
}
jwks() {
return this.#jwks;
}
async getKey(protectedHeader, token) {
const { alg, kid } = { ...protectedHeader, ...token?.header };
const kty = getKtyFromAlg(alg);
const candidates = this.#jwks.keys.filter((jwk) => {
let candidate = kty === jwk.kty;
if (candidate && typeof kid === 'string') {
candidate = kid === jwk.kid;
}
if (candidate && (typeof jwk.alg === 'string' || kty === 'AKP')) {
candidate = alg === jwk.alg;
}
if (candidate && typeof jwk.use === 'string') {
candidate = jwk.use === 'sig';
}
if (candidate && Array.isArray(jwk.key_ops)) {
candidate = jwk.key_ops.includes('verify');
}
if (candidate) {
switch (alg) {
case 'ES256':
candidate = jwk.crv === 'P-256';
break;
case 'ES384':
candidate = jwk.crv === 'P-384';
break;
case 'ES512':
candidate = jwk.crv === 'P-521';
break;
case 'Ed25519':
case 'EdDSA':
candidate = jwk.crv === 'Ed25519';
break;
}
}
return candidate;
});
const { 0: jwk, length } = candidates;
if (length === 0) {
throw new JWKSNoMatchingKey();
}
if (length !== 1) {
const error = new JWKSMultipleMatchingKeys();
const _cached = this.#cached;
error[Symbol.asyncIterator] = async function* () {
for (const jwk of candidates) {
try {
yield await importWithAlgCache(_cached, jwk, alg);
}
catch { }
}
};
throw error;
}
return importWithAlgCache(this.#cached, jwk, alg);
}
}
async function importWithAlgCache(cache, jwk, alg) {
const cached = cache.get(jwk) || cache.set(jwk, {}).get(jwk);
if (cached[alg] === undefined) {
const key = await importJWK({ ...jwk, ext: true }, alg);
if (key instanceof Uint8Array || key.type !== 'public') {
throw new JWKSInvalid('JSON Web Key Set members must be public keys');
}
cached[alg] = key;
}
return cached[alg];
}
export function createLocalJWKSet(jwks) {
const set = new LocalJWKSet(jwks);
const localJWKSet = async (protectedHeader, token) => set.getKey(protectedHeader, token);
Object.defineProperties(localJWKSet, {
jwks: {
value: () => structuredClone(set.jwks()),
enumerable: false,
configurable: false,
writable: false,
},
});
return localJWKSet;
}

179
node_modules/jose/dist/webapi/jwks/remote.js generated vendored Normal file
View File

@@ -0,0 +1,179 @@
import { JOSEError, JWKSNoMatchingKey, JWKSTimeout } from '../util/errors.js';
import { createLocalJWKSet } from './local.js';
import { isObject } from '../lib/type_checks.js';
function isCloudflareWorkers() {
return (typeof WebSocketPair !== 'undefined' ||
(typeof navigator !== 'undefined' && navigator.userAgent === 'Cloudflare-Workers') ||
(typeof EdgeRuntime !== 'undefined' && EdgeRuntime === 'vercel'));
}
let USER_AGENT;
if (typeof navigator === 'undefined' || !navigator.userAgent?.startsWith?.('Mozilla/5.0 ')) {
const NAME = 'jose';
const VERSION = 'v6.2.2';
USER_AGENT = `${NAME}/${VERSION}`;
}
export const customFetch = Symbol();
async function fetchJwks(url, headers, signal, fetchImpl = fetch) {
const response = await fetchImpl(url, {
method: 'GET',
signal,
redirect: 'manual',
headers,
}).catch((err) => {
if (err.name === 'TimeoutError') {
throw new JWKSTimeout();
}
throw err;
});
if (response.status !== 200) {
throw new JOSEError('Expected 200 OK from the JSON Web Key Set HTTP response');
}
try {
return await response.json();
}
catch {
throw new JOSEError('Failed to parse the JSON Web Key Set HTTP response as JSON');
}
}
export const jwksCache = Symbol();
function isFreshJwksCache(input, cacheMaxAge) {
if (typeof input !== 'object' || input === null) {
return false;
}
if (!('uat' in input) || typeof input.uat !== 'number' || Date.now() - input.uat >= cacheMaxAge) {
return false;
}
if (!('jwks' in input) ||
!isObject(input.jwks) ||
!Array.isArray(input.jwks.keys) ||
!Array.prototype.every.call(input.jwks.keys, isObject)) {
return false;
}
return true;
}
class RemoteJWKSet {
#url;
#timeoutDuration;
#cooldownDuration;
#cacheMaxAge;
#jwksTimestamp;
#pendingFetch;
#headers;
#customFetch;
#local;
#cache;
constructor(url, options) {
if (!(url instanceof URL)) {
throw new TypeError('url must be an instance of URL');
}
this.#url = new URL(url.href);
this.#timeoutDuration =
typeof options?.timeoutDuration === 'number' ? options?.timeoutDuration : 5000;
this.#cooldownDuration =
typeof options?.cooldownDuration === 'number' ? options?.cooldownDuration : 30000;
this.#cacheMaxAge = typeof options?.cacheMaxAge === 'number' ? options?.cacheMaxAge : 600000;
this.#headers = new Headers(options?.headers);
if (USER_AGENT && !this.#headers.has('User-Agent')) {
this.#headers.set('User-Agent', USER_AGENT);
}
if (!this.#headers.has('accept')) {
this.#headers.set('accept', 'application/json');
this.#headers.append('accept', 'application/jwk-set+json');
}
this.#customFetch = options?.[customFetch];
if (options?.[jwksCache] !== undefined) {
this.#cache = options?.[jwksCache];
if (isFreshJwksCache(options?.[jwksCache], this.#cacheMaxAge)) {
this.#jwksTimestamp = this.#cache.uat;
this.#local = createLocalJWKSet(this.#cache.jwks);
}
}
}
pendingFetch() {
return !!this.#pendingFetch;
}
coolingDown() {
return typeof this.#jwksTimestamp === 'number'
? Date.now() < this.#jwksTimestamp + this.#cooldownDuration
: false;
}
fresh() {
return typeof this.#jwksTimestamp === 'number'
? Date.now() < this.#jwksTimestamp + this.#cacheMaxAge
: false;
}
jwks() {
return this.#local?.jwks();
}
async getKey(protectedHeader, token) {
if (!this.#local || !this.fresh()) {
await this.reload();
}
try {
return await this.#local(protectedHeader, token);
}
catch (err) {
if (err instanceof JWKSNoMatchingKey) {
if (this.coolingDown() === false) {
await this.reload();
return this.#local(protectedHeader, token);
}
}
throw err;
}
}
async reload() {
if (this.#pendingFetch && isCloudflareWorkers()) {
this.#pendingFetch = undefined;
}
this.#pendingFetch ||= fetchJwks(this.#url.href, this.#headers, AbortSignal.timeout(this.#timeoutDuration), this.#customFetch)
.then((json) => {
this.#local = createLocalJWKSet(json);
if (this.#cache) {
this.#cache.uat = Date.now();
this.#cache.jwks = json;
}
this.#jwksTimestamp = Date.now();
this.#pendingFetch = undefined;
})
.catch((err) => {
this.#pendingFetch = undefined;
throw err;
});
await this.#pendingFetch;
}
}
export function createRemoteJWKSet(url, options) {
const set = new RemoteJWKSet(url, options);
const remoteJWKSet = async (protectedHeader, token) => set.getKey(protectedHeader, token);
Object.defineProperties(remoteJWKSet, {
coolingDown: {
get: () => set.coolingDown(),
enumerable: true,
configurable: false,
},
fresh: {
get: () => set.fresh(),
enumerable: true,
configurable: false,
},
reload: {
value: () => set.reload(),
enumerable: true,
configurable: false,
writable: false,
},
reloading: {
get: () => set.pendingFetch(),
enumerable: true,
configurable: false,
},
jwks: {
value: () => set.jwks(),
enumerable: true,
configurable: false,
writable: false,
},
});
return remoteJWKSet;
}