@finueva/auth 0.16.1 → 0.18.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 +36 -22
- package/dist/device.d.ts +4 -2
- package/dist/device.js +163 -39
- package/dist/index.d.ts +2 -2
- package/dist/index.js +165 -1
- package/dist/server.d.ts +56 -2
- package/dist/server.js +2631 -1161
- package/dist/{types-Dpy17xNC.d.ts → types-CrdIcEJ3.d.ts} +28 -2
- package/package.json +4 -2
package/dist/server.js
CHANGED
|
@@ -8,16 +8,16 @@ const ENC_CARET_RE = /%5e/gi;
|
|
|
8
8
|
const ENC_BACKTICK_RE = /%60/gi;
|
|
9
9
|
const ENC_PIPE_RE = /%7c/gi;
|
|
10
10
|
const ENC_SPACE_RE = /%20/gi;
|
|
11
|
-
function encode(text) {
|
|
11
|
+
function encode$2(text) {
|
|
12
12
|
return encodeURI("" + text).replace(ENC_PIPE_RE, "|");
|
|
13
13
|
}
|
|
14
14
|
function encodeQueryValue(input) {
|
|
15
|
-
return encode(typeof input === "string" ? input : JSON.stringify(input)).replace(PLUS_RE, "%2B").replace(ENC_SPACE_RE, "+").replace(HASH_RE, "%23").replace(AMPERSAND_RE, "%26").replace(ENC_BACKTICK_RE, "`").replace(ENC_CARET_RE, "^").replace(SLASH_RE, "%2F");
|
|
15
|
+
return encode$2(typeof input === "string" ? input : JSON.stringify(input)).replace(PLUS_RE, "%2B").replace(ENC_SPACE_RE, "+").replace(HASH_RE, "%23").replace(AMPERSAND_RE, "%26").replace(ENC_BACKTICK_RE, "`").replace(ENC_CARET_RE, "^").replace(SLASH_RE, "%2F");
|
|
16
16
|
}
|
|
17
17
|
function encodeQueryKey(text) {
|
|
18
18
|
return encodeQueryValue(text).replace(EQUAL_RE, "%3D");
|
|
19
19
|
}
|
|
20
|
-
function decode(text = "") {
|
|
20
|
+
function decode$1(text = "") {
|
|
21
21
|
try {
|
|
22
22
|
return decodeURIComponent("" + text);
|
|
23
23
|
} catch {
|
|
@@ -25,10 +25,10 @@ function decode(text = "") {
|
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
function decodeQueryKey(text) {
|
|
28
|
-
return decode(text.replace(PLUS_RE, " "));
|
|
28
|
+
return decode$1(text.replace(PLUS_RE, " "));
|
|
29
29
|
}
|
|
30
30
|
function decodeQueryValue(text) {
|
|
31
|
-
return decode(text.replace(PLUS_RE, " "));
|
|
31
|
+
return decode$1(text.replace(PLUS_RE, " "));
|
|
32
32
|
}
|
|
33
33
|
function parseQuery(parametersString = "") {
|
|
34
34
|
const object = Object.create(null);
|
|
@@ -187,6 +187,7 @@ const messages = {
|
|
|
187
187
|
recipient_unavailable: "The recipient is unavailable.",
|
|
188
188
|
invitation_recipient_mismatch: "The invitation cannot be accepted by this account.",
|
|
189
189
|
invitation_recovery_required: "Invitation administration requires separate recovery.",
|
|
190
|
+
membership_removal_recovery_required: "Membership removal requires separate recovery.",
|
|
190
191
|
email_verification_required: "Email verification is required.",
|
|
191
192
|
invalid_workspace_selection: "The workspace selection is invalid.",
|
|
192
193
|
organization_context_too_large: "The organization context is too large.",
|
|
@@ -212,1278 +213,2682 @@ var AuthError = class extends Error {
|
|
|
212
213
|
}
|
|
213
214
|
};
|
|
214
215
|
//#endregion
|
|
215
|
-
//#region src/
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
const MAX_SOCIAL_ID_TOKEN_BYTES = 16 * 1024;
|
|
220
|
-
function normalizeEmail(value) {
|
|
221
|
-
if (typeof value !== "string") throw new TypeError("email is invalid");
|
|
222
|
-
const normalized = value.trim().toLowerCase();
|
|
223
|
-
if (normalized.length === 0 || normalized.length > 320 || !email.test(normalized)) throw new TypeError("email is invalid");
|
|
224
|
-
return normalized;
|
|
216
|
+
//#region src/user-api/credential.ts
|
|
217
|
+
function userApiApplication(input) {
|
|
218
|
+
if (!input || typeof input.applicationId !== "string" || !/^[A-Za-z0-9_-]{1,128}$(?![\s\S])/.test(input.applicationId) || input.forceRefresh !== void 0 && typeof input.forceRefresh !== "boolean") throw new TypeError("User API credential input is invalid");
|
|
219
|
+
return input.applicationId;
|
|
225
220
|
}
|
|
226
|
-
function
|
|
227
|
-
if (!
|
|
228
|
-
const keys = Object.keys(value);
|
|
229
|
-
if (keys.length !== 3 && keys.length !== 4 || keys.some((key) => key !== "provider" && key !== "idToken" && key !== "nonce" && key !== "signUp") || value.provider !== "google" && value.provider !== "apple" || typeof value.signUp !== "boolean" || typeof value.idToken !== "string" || value.idToken.length < 1 || new TextEncoder().encode(value.idToken).byteLength > MAX_SOCIAL_ID_TOKEN_BYTES || !/^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/.test(value.idToken) || value.nonce !== void 0 && (typeof value.nonce !== "string" || value.nonce.length < 1 || value.nonce.length > 256 || !/^[\x20-\x7e]+$/.test(value.nonce))) throw new TypeError("social ID token input is invalid");
|
|
221
|
+
function normalizeUserApiCredential(value, startedAt) {
|
|
222
|
+
if (!value || typeof value !== "object" || Array.isArray(value) || !("tokenType" in value) || value.tokenType !== "Bearer" || !("token" in value) || typeof value.token !== "string" || value.token.length + 7 > 16 * 1024 || !/^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/.test(value.token) || !("expiresIn" in value) || typeof value.expiresIn !== "number" || !Number.isInteger(value.expiresIn) || value.expiresIn < 1 || value.expiresIn > 840 || Object.keys(value).sort().join(",") !== "expiresIn,token,tokenType") throw new AuthError("identity_authority_unavailable", 503);
|
|
230
223
|
return {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
signUp: value.signUp
|
|
224
|
+
tokenType: "Bearer",
|
|
225
|
+
token: value.token,
|
|
226
|
+
expiresAt: new Date(startedAt + value.expiresIn * 1e3)
|
|
235
227
|
};
|
|
236
228
|
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
229
|
+
//#endregion
|
|
230
|
+
//#region ../../node_modules/.pnpm/jose@6.2.4/node_modules/jose/dist/webapi/lib/buffer_utils.js
|
|
231
|
+
const encoder$1 = new TextEncoder();
|
|
232
|
+
const decoder = new TextDecoder();
|
|
233
|
+
function concat(...buffers) {
|
|
234
|
+
const size = buffers.reduce((acc, { length }) => acc + length, 0);
|
|
235
|
+
const buf = new Uint8Array(size);
|
|
236
|
+
let i = 0;
|
|
237
|
+
for (const buffer of buffers) {
|
|
238
|
+
buf.set(buffer, i);
|
|
239
|
+
i += buffer.length;
|
|
240
|
+
}
|
|
241
|
+
return buf;
|
|
242
|
+
}
|
|
243
|
+
function encode$1(string) {
|
|
244
|
+
const bytes = new Uint8Array(string.length);
|
|
245
|
+
for (let i = 0; i < string.length; i++) {
|
|
246
|
+
const code = string.charCodeAt(i);
|
|
247
|
+
if (code > 127) throw new TypeError("non-ASCII string encountered in encode()");
|
|
248
|
+
bytes[i] = code;
|
|
249
|
+
}
|
|
250
|
+
return bytes;
|
|
246
251
|
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
252
|
+
//#endregion
|
|
253
|
+
//#region ../../node_modules/.pnpm/jose@6.2.4/node_modules/jose/dist/webapi/lib/base64.js
|
|
254
|
+
function encodeBase64(input) {
|
|
255
|
+
if (Uint8Array.prototype.toBase64) return input.toBase64();
|
|
256
|
+
const CHUNK_SIZE = 32768;
|
|
257
|
+
const arr = [];
|
|
258
|
+
for (let i = 0; i < input.length; i += CHUNK_SIZE) arr.push(String.fromCharCode.apply(null, input.subarray(i, i + CHUNK_SIZE)));
|
|
259
|
+
return btoa(arr.join(""));
|
|
260
|
+
}
|
|
261
|
+
function decodeBase64(encoded) {
|
|
262
|
+
if (Uint8Array.fromBase64) return Uint8Array.fromBase64(encoded);
|
|
263
|
+
const binary = atob(encoded);
|
|
264
|
+
const bytes = new Uint8Array(binary.length);
|
|
265
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
266
|
+
return bytes;
|
|
267
|
+
}
|
|
268
|
+
//#endregion
|
|
269
|
+
//#region ../../node_modules/.pnpm/jose@6.2.4/node_modules/jose/dist/webapi/util/base64url.js
|
|
270
|
+
function decode(input) {
|
|
271
|
+
if (Uint8Array.fromBase64) return Uint8Array.fromBase64(typeof input === "string" ? input : decoder.decode(input), { alphabet: "base64url" });
|
|
272
|
+
let encoded = input;
|
|
273
|
+
if (encoded instanceof Uint8Array) encoded = decoder.decode(encoded);
|
|
274
|
+
encoded = encoded.replace(/-/g, "+").replace(/_/g, "/");
|
|
250
275
|
try {
|
|
251
|
-
|
|
276
|
+
return decodeBase64(encoded);
|
|
252
277
|
} catch {
|
|
253
|
-
throw new TypeError(
|
|
278
|
+
throw new TypeError("The input to be decoded is not correctly encoded.");
|
|
254
279
|
}
|
|
255
|
-
const local = url.hostname === "localhost" || url.hostname.endsWith(".localhost") || url.hostname === "127.0.0.1";
|
|
256
|
-
if (url.protocol !== "https:" && !(local && url.protocol === "http:") || url.username || url.password || url.pathname !== "/" || url.search || url.hash || url.origin !== value) throw new TypeError(`${name} must be an ASCII HTTP origin`);
|
|
257
|
-
return url.origin;
|
|
258
280
|
}
|
|
259
|
-
function
|
|
260
|
-
|
|
261
|
-
if (
|
|
262
|
-
return
|
|
281
|
+
function encode(input) {
|
|
282
|
+
let unencoded = input;
|
|
283
|
+
if (typeof unencoded === "string") unencoded = encoder$1.encode(unencoded);
|
|
284
|
+
if (Uint8Array.prototype.toBase64) return unencoded.toBase64({
|
|
285
|
+
alphabet: "base64url",
|
|
286
|
+
omitPadding: true
|
|
287
|
+
});
|
|
288
|
+
return encodeBase64(unencoded).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
|
|
263
289
|
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
290
|
+
//#endregion
|
|
291
|
+
//#region ../../node_modules/.pnpm/jose@6.2.4/node_modules/jose/dist/webapi/lib/crypto_key.js
|
|
292
|
+
const unusable = (name, prop = "algorithm.name") => new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name}`);
|
|
293
|
+
const isAlgorithm = (algorithm, name) => algorithm.name === name;
|
|
294
|
+
function getHashLength(hash) {
|
|
295
|
+
return parseInt(hash.name.slice(4), 10);
|
|
296
|
+
}
|
|
297
|
+
function checkHashLength(algorithm, expected) {
|
|
298
|
+
if (getHashLength(algorithm.hash) !== expected) throw unusable(`SHA-${expected}`, "algorithm.hash");
|
|
299
|
+
}
|
|
300
|
+
function getNamedCurve(alg) {
|
|
301
|
+
switch (alg) {
|
|
302
|
+
case "ES256": return "P-256";
|
|
303
|
+
case "ES384": return "P-384";
|
|
304
|
+
case "ES512": return "P-521";
|
|
305
|
+
default: throw new Error("unreachable");
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
function checkUsage(key, usage) {
|
|
309
|
+
if (usage && !key.usages.includes(usage)) throw new TypeError(`CryptoKey does not support this operation, its usages must include ${usage}.`);
|
|
310
|
+
}
|
|
311
|
+
function checkSigCryptoKey(key, alg, usage) {
|
|
312
|
+
switch (alg) {
|
|
313
|
+
case "HS256":
|
|
314
|
+
case "HS384":
|
|
315
|
+
case "HS512":
|
|
316
|
+
if (!isAlgorithm(key.algorithm, "HMAC")) throw unusable("HMAC");
|
|
317
|
+
checkHashLength(key.algorithm, parseInt(alg.slice(2), 10));
|
|
318
|
+
break;
|
|
319
|
+
case "RS256":
|
|
320
|
+
case "RS384":
|
|
321
|
+
case "RS512":
|
|
322
|
+
if (!isAlgorithm(key.algorithm, "RSASSA-PKCS1-v1_5")) throw unusable("RSASSA-PKCS1-v1_5");
|
|
323
|
+
checkHashLength(key.algorithm, parseInt(alg.slice(2), 10));
|
|
324
|
+
break;
|
|
325
|
+
case "PS256":
|
|
326
|
+
case "PS384":
|
|
327
|
+
case "PS512":
|
|
328
|
+
if (!isAlgorithm(key.algorithm, "RSA-PSS")) throw unusable("RSA-PSS");
|
|
329
|
+
checkHashLength(key.algorithm, parseInt(alg.slice(2), 10));
|
|
330
|
+
break;
|
|
331
|
+
case "Ed25519":
|
|
332
|
+
case "EdDSA":
|
|
333
|
+
if (!isAlgorithm(key.algorithm, "Ed25519")) throw unusable("Ed25519");
|
|
334
|
+
break;
|
|
335
|
+
case "ML-DSA-44":
|
|
336
|
+
case "ML-DSA-65":
|
|
337
|
+
case "ML-DSA-87":
|
|
338
|
+
if (!isAlgorithm(key.algorithm, alg)) throw unusable(alg);
|
|
339
|
+
break;
|
|
340
|
+
case "ES256":
|
|
341
|
+
case "ES384":
|
|
342
|
+
case "ES512": {
|
|
343
|
+
if (!isAlgorithm(key.algorithm, "ECDSA")) throw unusable("ECDSA");
|
|
344
|
+
const expected = getNamedCurve(alg);
|
|
345
|
+
if (key.algorithm.namedCurve !== expected) throw unusable(expected, "algorithm.namedCurve");
|
|
346
|
+
break;
|
|
279
347
|
}
|
|
280
|
-
|
|
348
|
+
default: throw new TypeError("CryptoKey does not support this operation");
|
|
349
|
+
}
|
|
350
|
+
checkUsage(key, usage);
|
|
281
351
|
}
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
352
|
+
//#endregion
|
|
353
|
+
//#region ../../node_modules/.pnpm/jose@6.2.4/node_modules/jose/dist/webapi/lib/invalid_key_input.js
|
|
354
|
+
function message(msg, actual, ...types) {
|
|
355
|
+
types = types.filter(Boolean);
|
|
356
|
+
if (types.length > 2) {
|
|
357
|
+
const last = types.pop();
|
|
358
|
+
msg += `one of type ${types.join(", ")}, or ${last}.`;
|
|
359
|
+
} else if (types.length === 2) msg += `one of type ${types[0]} or ${types[1]}.`;
|
|
360
|
+
else msg += `of type ${types[0]}.`;
|
|
361
|
+
if (actual == null) msg += ` Received ${actual}`;
|
|
362
|
+
else if (typeof actual === "function" && actual.name) msg += ` Received function ${actual.name}`;
|
|
363
|
+
else if (typeof actual === "object" && actual != null) {
|
|
364
|
+
if (actual.constructor?.name) msg += ` Received an instance of ${actual.constructor.name}`;
|
|
365
|
+
}
|
|
366
|
+
return msg;
|
|
289
367
|
}
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
368
|
+
const invalidKeyInput = (actual, ...types) => message("Key must be ", actual, ...types);
|
|
369
|
+
const withAlg = (alg, actual, ...types) => message(`Key for the ${alg} algorithm must be `, actual, ...types);
|
|
370
|
+
//#endregion
|
|
371
|
+
//#region ../../node_modules/.pnpm/jose@6.2.4/node_modules/jose/dist/webapi/util/errors.js
|
|
372
|
+
var JOSEError = class extends Error {
|
|
373
|
+
static code = "ERR_JOSE_GENERIC";
|
|
374
|
+
code = "ERR_JOSE_GENERIC";
|
|
375
|
+
constructor(message, options) {
|
|
376
|
+
super(message, options);
|
|
377
|
+
this.name = this.constructor.name;
|
|
378
|
+
Error.captureStackTrace?.(this, this.constructor);
|
|
298
379
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
380
|
+
};
|
|
381
|
+
var JWTClaimValidationFailed = class extends JOSEError {
|
|
382
|
+
static code = "ERR_JWT_CLAIM_VALIDATION_FAILED";
|
|
383
|
+
code = "ERR_JWT_CLAIM_VALIDATION_FAILED";
|
|
384
|
+
claim;
|
|
385
|
+
reason;
|
|
386
|
+
payload;
|
|
387
|
+
constructor(message, payload, claim = "unspecified", reason = "unspecified") {
|
|
388
|
+
super(message, { cause: {
|
|
389
|
+
claim,
|
|
390
|
+
reason,
|
|
391
|
+
payload
|
|
392
|
+
} });
|
|
393
|
+
this.claim = claim;
|
|
394
|
+
this.reason = reason;
|
|
395
|
+
this.payload = payload;
|
|
302
396
|
}
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
397
|
+
};
|
|
398
|
+
var JWTExpired = class extends JOSEError {
|
|
399
|
+
static code = "ERR_JWT_EXPIRED";
|
|
400
|
+
code = "ERR_JWT_EXPIRED";
|
|
401
|
+
claim;
|
|
402
|
+
reason;
|
|
403
|
+
payload;
|
|
404
|
+
constructor(message, payload, claim = "unspecified", reason = "unspecified") {
|
|
405
|
+
super(message, { cause: {
|
|
406
|
+
claim,
|
|
407
|
+
reason,
|
|
408
|
+
payload
|
|
409
|
+
} });
|
|
410
|
+
this.claim = claim;
|
|
411
|
+
this.reason = reason;
|
|
412
|
+
this.payload = payload;
|
|
413
|
+
}
|
|
414
|
+
};
|
|
415
|
+
var JOSEAlgNotAllowed = class extends JOSEError {
|
|
416
|
+
static code = "ERR_JOSE_ALG_NOT_ALLOWED";
|
|
417
|
+
code = "ERR_JOSE_ALG_NOT_ALLOWED";
|
|
418
|
+
};
|
|
419
|
+
var JOSENotSupported = class extends JOSEError {
|
|
420
|
+
static code = "ERR_JOSE_NOT_SUPPORTED";
|
|
421
|
+
code = "ERR_JOSE_NOT_SUPPORTED";
|
|
422
|
+
};
|
|
423
|
+
var JWSInvalid = class extends JOSEError {
|
|
424
|
+
static code = "ERR_JWS_INVALID";
|
|
425
|
+
code = "ERR_JWS_INVALID";
|
|
426
|
+
};
|
|
427
|
+
var JWTInvalid = class extends JOSEError {
|
|
428
|
+
static code = "ERR_JWT_INVALID";
|
|
429
|
+
code = "ERR_JWT_INVALID";
|
|
430
|
+
};
|
|
431
|
+
var JWKInvalid = class extends JOSEError {
|
|
432
|
+
static code = "ERR_JWK_INVALID";
|
|
433
|
+
code = "ERR_JWK_INVALID";
|
|
434
|
+
};
|
|
435
|
+
var JWSSignatureVerificationFailed = class extends JOSEError {
|
|
436
|
+
static code = "ERR_JWS_SIGNATURE_VERIFICATION_FAILED";
|
|
437
|
+
code = "ERR_JWS_SIGNATURE_VERIFICATION_FAILED";
|
|
438
|
+
constructor(message = "signature verification failed", options) {
|
|
439
|
+
super(message, options);
|
|
440
|
+
}
|
|
441
|
+
};
|
|
442
|
+
//#endregion
|
|
443
|
+
//#region ../../node_modules/.pnpm/jose@6.2.4/node_modules/jose/dist/webapi/lib/is_key_like.js
|
|
444
|
+
const isCryptoKey = (key) => {
|
|
445
|
+
if (key?.[Symbol.toStringTag] === "CryptoKey") return true;
|
|
344
446
|
try {
|
|
345
|
-
|
|
447
|
+
return key instanceof CryptoKey;
|
|
346
448
|
} catch {
|
|
347
|
-
|
|
449
|
+
return false;
|
|
348
450
|
}
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
function normalizeOrganizationDisplay(value) {
|
|
451
|
+
};
|
|
452
|
+
const isKeyObject = (key) => key?.[Symbol.toStringTag] === "KeyObject";
|
|
453
|
+
const isKeyLike = (key) => isCryptoKey(key) || isKeyObject(key);
|
|
454
|
+
//#endregion
|
|
455
|
+
//#region ../../node_modules/.pnpm/jose@6.2.4/node_modules/jose/dist/webapi/lib/helpers.js
|
|
456
|
+
function decodeBase64url(value, label, ErrorClass) {
|
|
356
457
|
try {
|
|
357
|
-
return
|
|
458
|
+
return decode(value);
|
|
358
459
|
} catch {
|
|
359
|
-
throw
|
|
460
|
+
throw new ErrorClass(`Failed to base64url decode the ${label}`);
|
|
360
461
|
}
|
|
361
462
|
}
|
|
362
|
-
function
|
|
363
|
-
|
|
364
|
-
return
|
|
463
|
+
async function digest(algorithm, data) {
|
|
464
|
+
const subtleDigest = `SHA-${algorithm.slice(-3)}`;
|
|
465
|
+
return new Uint8Array(await crypto.subtle.digest(subtleDigest, data));
|
|
365
466
|
}
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
467
|
+
//#endregion
|
|
468
|
+
//#region ../../node_modules/.pnpm/jose@6.2.4/node_modules/jose/dist/webapi/lib/type_checks.js
|
|
469
|
+
const isObjectLike = (value) => typeof value === "object" && value !== null;
|
|
470
|
+
function isObject$1(input) {
|
|
471
|
+
if (!isObjectLike(input) || Object.prototype.toString.call(input) !== "[object Object]") return false;
|
|
472
|
+
if (Object.getPrototypeOf(input) === null) return true;
|
|
473
|
+
let proto = input;
|
|
474
|
+
while (Object.getPrototypeOf(proto) !== null) proto = Object.getPrototypeOf(proto);
|
|
475
|
+
return Object.getPrototypeOf(input) === proto;
|
|
476
|
+
}
|
|
477
|
+
function isDisjoint(...headers) {
|
|
478
|
+
const sources = headers.filter(Boolean);
|
|
479
|
+
if (sources.length === 0 || sources.length === 1) return true;
|
|
480
|
+
let acc;
|
|
481
|
+
for (const header of sources) {
|
|
482
|
+
const parameters = Object.keys(header);
|
|
483
|
+
if (!acc || acc.size === 0) {
|
|
484
|
+
acc = new Set(parameters);
|
|
485
|
+
continue;
|
|
486
|
+
}
|
|
487
|
+
for (const parameter of parameters) {
|
|
488
|
+
if (acc.has(parameter)) return false;
|
|
489
|
+
acc.add(parameter);
|
|
490
|
+
}
|
|
371
491
|
}
|
|
492
|
+
return true;
|
|
372
493
|
}
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
494
|
+
const isJWK = (key) => isObject$1(key) && typeof key.kty === "string";
|
|
495
|
+
const isPrivateJWK = (key) => key.kty !== "oct" && (key.kty === "AKP" && typeof key.priv === "string" || typeof key.d === "string");
|
|
496
|
+
const isPublicJWK = (key) => key.kty !== "oct" && key.d === void 0 && key.priv === void 0;
|
|
497
|
+
const isSecretJWK = (key) => key.kty === "oct" && typeof key.k === "string";
|
|
498
|
+
//#endregion
|
|
499
|
+
//#region ../../node_modules/.pnpm/jose@6.2.4/node_modules/jose/dist/webapi/lib/signing.js
|
|
500
|
+
function checkKeyLength(alg, key) {
|
|
501
|
+
if (alg.startsWith("RS") || alg.startsWith("PS")) {
|
|
502
|
+
const { modulusLength } = key.algorithm;
|
|
503
|
+
if (typeof modulusLength !== "number" || modulusLength < 2048) throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`);
|
|
504
|
+
}
|
|
379
505
|
}
|
|
380
|
-
function
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
506
|
+
function subtleAlgorithm(alg, algorithm) {
|
|
507
|
+
const hash = `SHA-${alg.slice(-3)}`;
|
|
508
|
+
switch (alg) {
|
|
509
|
+
case "HS256":
|
|
510
|
+
case "HS384":
|
|
511
|
+
case "HS512": return {
|
|
512
|
+
hash,
|
|
513
|
+
name: "HMAC"
|
|
514
|
+
};
|
|
515
|
+
case "PS256":
|
|
516
|
+
case "PS384":
|
|
517
|
+
case "PS512": return {
|
|
518
|
+
hash,
|
|
519
|
+
name: "RSA-PSS",
|
|
520
|
+
saltLength: parseInt(alg.slice(-3), 10) >> 3
|
|
521
|
+
};
|
|
522
|
+
case "RS256":
|
|
523
|
+
case "RS384":
|
|
524
|
+
case "RS512": return {
|
|
525
|
+
hash,
|
|
526
|
+
name: "RSASSA-PKCS1-v1_5"
|
|
527
|
+
};
|
|
528
|
+
case "ES256":
|
|
529
|
+
case "ES384":
|
|
530
|
+
case "ES512": return {
|
|
531
|
+
hash,
|
|
532
|
+
name: "ECDSA",
|
|
533
|
+
namedCurve: algorithm.namedCurve
|
|
534
|
+
};
|
|
535
|
+
case "Ed25519":
|
|
536
|
+
case "EdDSA": return { name: "Ed25519" };
|
|
537
|
+
case "ML-DSA-44":
|
|
538
|
+
case "ML-DSA-65":
|
|
539
|
+
case "ML-DSA-87": return { name: alg };
|
|
540
|
+
default: throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`);
|
|
541
|
+
}
|
|
387
542
|
}
|
|
388
|
-
function
|
|
389
|
-
if (
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
543
|
+
async function getSigKey(alg, key, usage) {
|
|
544
|
+
if (key instanceof Uint8Array) {
|
|
545
|
+
if (!alg.startsWith("HS")) throw new TypeError(invalidKeyInput(key, "CryptoKey", "KeyObject", "JSON Web Key"));
|
|
546
|
+
return crypto.subtle.importKey("raw", key, {
|
|
547
|
+
hash: `SHA-${alg.slice(-3)}`,
|
|
548
|
+
name: "HMAC"
|
|
549
|
+
}, false, [usage]);
|
|
550
|
+
}
|
|
551
|
+
checkSigCryptoKey(key, alg, usage);
|
|
552
|
+
return key;
|
|
553
|
+
}
|
|
554
|
+
async function verify(alg, key, signature, data) {
|
|
555
|
+
const cryptoKey = await getSigKey(alg, key, "verify");
|
|
556
|
+
checkKeyLength(alg, cryptoKey);
|
|
557
|
+
const algorithm = subtleAlgorithm(alg, cryptoKey.algorithm);
|
|
393
558
|
try {
|
|
394
|
-
|
|
559
|
+
return await crypto.subtle.verify(algorithm, cryptoKey, signature, data);
|
|
395
560
|
} catch {
|
|
396
|
-
|
|
561
|
+
return false;
|
|
397
562
|
}
|
|
398
|
-
if (new TextEncoder().encode(normalizedEmail).byteLength > 320 || !boundedString(value.idempotencyKey, 255) || value.teamIds !== void 0 && (!Array.isArray(value.teamIds) || value.teamIds.length > 100)) throw new AuthError("invalid_request", 400);
|
|
399
|
-
const teamIds = value.teamIds?.map((teamId) => normalizeIdInput(teamId));
|
|
400
|
-
if (teamIds && new Set(teamIds).size !== teamIds.length) throw new AuthError("invalid_request", 400);
|
|
401
|
-
return {
|
|
402
|
-
email: normalizedEmail,
|
|
403
|
-
...teamIds === void 0 ? {} : { teamIds },
|
|
404
|
-
idempotencyKey: value.idempotencyKey
|
|
405
|
-
};
|
|
406
563
|
}
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
564
|
+
//#endregion
|
|
565
|
+
//#region ../../node_modules/.pnpm/jose@6.2.4/node_modules/jose/dist/webapi/lib/jwk_to_key.js
|
|
566
|
+
const unsupportedAlg = "Invalid or unsupported JWK \"alg\" (Algorithm) Parameter value";
|
|
567
|
+
function subtleMapping(jwk) {
|
|
568
|
+
let algorithm;
|
|
569
|
+
let keyUsages;
|
|
570
|
+
switch (jwk.kty) {
|
|
571
|
+
case "AKP":
|
|
572
|
+
switch (jwk.alg) {
|
|
573
|
+
case "ML-DSA-44":
|
|
574
|
+
case "ML-DSA-65":
|
|
575
|
+
case "ML-DSA-87":
|
|
576
|
+
algorithm = { name: jwk.alg };
|
|
577
|
+
keyUsages = jwk.priv ? ["sign"] : ["verify"];
|
|
578
|
+
break;
|
|
579
|
+
default: throw new JOSENotSupported(unsupportedAlg);
|
|
580
|
+
}
|
|
581
|
+
break;
|
|
582
|
+
case "RSA":
|
|
583
|
+
switch (jwk.alg) {
|
|
584
|
+
case "PS256":
|
|
585
|
+
case "PS384":
|
|
586
|
+
case "PS512":
|
|
587
|
+
algorithm = {
|
|
588
|
+
name: "RSA-PSS",
|
|
589
|
+
hash: `SHA-${jwk.alg.slice(-3)}`
|
|
590
|
+
};
|
|
591
|
+
keyUsages = jwk.d ? ["sign"] : ["verify"];
|
|
592
|
+
break;
|
|
593
|
+
case "RS256":
|
|
594
|
+
case "RS384":
|
|
595
|
+
case "RS512":
|
|
596
|
+
algorithm = {
|
|
597
|
+
name: "RSASSA-PKCS1-v1_5",
|
|
598
|
+
hash: `SHA-${jwk.alg.slice(-3)}`
|
|
599
|
+
};
|
|
600
|
+
keyUsages = jwk.d ? ["sign"] : ["verify"];
|
|
601
|
+
break;
|
|
602
|
+
case "RSA-OAEP":
|
|
603
|
+
case "RSA-OAEP-256":
|
|
604
|
+
case "RSA-OAEP-384":
|
|
605
|
+
case "RSA-OAEP-512":
|
|
606
|
+
algorithm = {
|
|
607
|
+
name: "RSA-OAEP",
|
|
608
|
+
hash: `SHA-${parseInt(jwk.alg.slice(-3), 10) || 1}`
|
|
609
|
+
};
|
|
610
|
+
keyUsages = jwk.d ? ["decrypt", "unwrapKey"] : ["encrypt", "wrapKey"];
|
|
611
|
+
break;
|
|
612
|
+
default: throw new JOSENotSupported(unsupportedAlg);
|
|
613
|
+
}
|
|
614
|
+
break;
|
|
615
|
+
case "EC":
|
|
616
|
+
switch (jwk.alg) {
|
|
617
|
+
case "ES256":
|
|
618
|
+
case "ES384":
|
|
619
|
+
case "ES512":
|
|
620
|
+
algorithm = {
|
|
621
|
+
name: "ECDSA",
|
|
622
|
+
namedCurve: {
|
|
623
|
+
ES256: "P-256",
|
|
624
|
+
ES384: "P-384",
|
|
625
|
+
ES512: "P-521"
|
|
626
|
+
}[jwk.alg]
|
|
627
|
+
};
|
|
628
|
+
keyUsages = jwk.d ? ["sign"] : ["verify"];
|
|
629
|
+
break;
|
|
630
|
+
case "ECDH-ES":
|
|
631
|
+
case "ECDH-ES+A128KW":
|
|
632
|
+
case "ECDH-ES+A192KW":
|
|
633
|
+
case "ECDH-ES+A256KW":
|
|
634
|
+
algorithm = {
|
|
635
|
+
name: "ECDH",
|
|
636
|
+
namedCurve: jwk.crv
|
|
637
|
+
};
|
|
638
|
+
keyUsages = jwk.d ? ["deriveBits"] : [];
|
|
639
|
+
break;
|
|
640
|
+
default: throw new JOSENotSupported(unsupportedAlg);
|
|
641
|
+
}
|
|
642
|
+
break;
|
|
643
|
+
case "OKP":
|
|
644
|
+
switch (jwk.alg) {
|
|
645
|
+
case "Ed25519":
|
|
646
|
+
case "EdDSA":
|
|
647
|
+
algorithm = { name: "Ed25519" };
|
|
648
|
+
keyUsages = jwk.d ? ["sign"] : ["verify"];
|
|
649
|
+
break;
|
|
650
|
+
case "ECDH-ES":
|
|
651
|
+
case "ECDH-ES+A128KW":
|
|
652
|
+
case "ECDH-ES+A192KW":
|
|
653
|
+
case "ECDH-ES+A256KW":
|
|
654
|
+
algorithm = { name: jwk.crv };
|
|
655
|
+
keyUsages = jwk.d ? ["deriveBits"] : [];
|
|
656
|
+
break;
|
|
657
|
+
default: throw new JOSENotSupported(unsupportedAlg);
|
|
658
|
+
}
|
|
659
|
+
break;
|
|
660
|
+
default: throw new JOSENotSupported("Invalid or unsupported JWK \"kty\" (Key Type) Parameter value");
|
|
661
|
+
}
|
|
410
662
|
return {
|
|
411
|
-
|
|
412
|
-
|
|
663
|
+
algorithm,
|
|
664
|
+
keyUsages
|
|
413
665
|
};
|
|
414
666
|
}
|
|
415
|
-
function
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
667
|
+
async function jwkToKey(jwk) {
|
|
668
|
+
if (!jwk.alg) throw new TypeError("\"alg\" argument is required when \"jwk.alg\" is not present");
|
|
669
|
+
const { algorithm, keyUsages } = subtleMapping(jwk);
|
|
670
|
+
const keyData = { ...jwk };
|
|
671
|
+
if (keyData.kty !== "AKP") delete keyData.alg;
|
|
672
|
+
delete keyData.use;
|
|
673
|
+
return crypto.subtle.importKey("jwk", keyData, algorithm, jwk.ext ?? (jwk.d || jwk.priv ? false : true), jwk.key_ops ?? keyUsages);
|
|
419
674
|
}
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
675
|
+
//#endregion
|
|
676
|
+
//#region ../../node_modules/.pnpm/jose@6.2.4/node_modules/jose/dist/webapi/lib/normalize_key.js
|
|
677
|
+
const unusableForAlg = "given KeyObject instance cannot be used for this algorithm";
|
|
678
|
+
let cache;
|
|
679
|
+
const handleJWK = async (key, jwk, alg, freeze = false) => {
|
|
680
|
+
cache ||= new WeakMap();
|
|
681
|
+
let cached = cache.get(key);
|
|
682
|
+
if (cached?.[alg]) return cached[alg];
|
|
683
|
+
const cryptoKey = await jwkToKey({
|
|
684
|
+
...jwk,
|
|
685
|
+
alg
|
|
686
|
+
});
|
|
687
|
+
if (freeze) Object.freeze(key);
|
|
688
|
+
if (!cached) cache.set(key, { [alg]: cryptoKey });
|
|
689
|
+
else cached[alg] = cryptoKey;
|
|
690
|
+
return cryptoKey;
|
|
691
|
+
};
|
|
692
|
+
const handleKeyObject = (keyObject, alg) => {
|
|
693
|
+
cache ||= new WeakMap();
|
|
694
|
+
let cached = cache.get(keyObject);
|
|
695
|
+
if (cached?.[alg]) return cached[alg];
|
|
696
|
+
const isPublic = keyObject.type === "public";
|
|
697
|
+
const extractable = isPublic ? true : false;
|
|
698
|
+
let cryptoKey;
|
|
699
|
+
if (keyObject.asymmetricKeyType === "x25519") {
|
|
700
|
+
switch (alg) {
|
|
701
|
+
case "ECDH-ES":
|
|
702
|
+
case "ECDH-ES+A128KW":
|
|
703
|
+
case "ECDH-ES+A192KW":
|
|
704
|
+
case "ECDH-ES+A256KW": break;
|
|
705
|
+
default: throw new TypeError(unusableForAlg);
|
|
706
|
+
}
|
|
707
|
+
cryptoKey = keyObject.toCryptoKey(keyObject.asymmetricKeyType, extractable, isPublic ? [] : ["deriveBits"]);
|
|
708
|
+
}
|
|
709
|
+
if (keyObject.asymmetricKeyType === "ed25519") {
|
|
710
|
+
if (alg !== "EdDSA" && alg !== "Ed25519") throw new TypeError(unusableForAlg);
|
|
711
|
+
cryptoKey = keyObject.toCryptoKey(keyObject.asymmetricKeyType, extractable, [isPublic ? "verify" : "sign"]);
|
|
712
|
+
}
|
|
713
|
+
switch (keyObject.asymmetricKeyType) {
|
|
714
|
+
case "ml-dsa-44":
|
|
715
|
+
case "ml-dsa-65":
|
|
716
|
+
case "ml-dsa-87":
|
|
717
|
+
if (alg !== keyObject.asymmetricKeyType.toUpperCase()) throw new TypeError(unusableForAlg);
|
|
718
|
+
cryptoKey = keyObject.toCryptoKey(keyObject.asymmetricKeyType, extractable, [isPublic ? "verify" : "sign"]);
|
|
719
|
+
}
|
|
720
|
+
if (keyObject.asymmetricKeyType === "rsa") {
|
|
721
|
+
let hash;
|
|
722
|
+
switch (alg) {
|
|
723
|
+
case "RSA-OAEP":
|
|
724
|
+
hash = "SHA-1";
|
|
725
|
+
break;
|
|
726
|
+
case "RS256":
|
|
727
|
+
case "PS256":
|
|
728
|
+
case "RSA-OAEP-256":
|
|
729
|
+
hash = "SHA-256";
|
|
730
|
+
break;
|
|
731
|
+
case "RS384":
|
|
732
|
+
case "PS384":
|
|
733
|
+
case "RSA-OAEP-384":
|
|
734
|
+
hash = "SHA-384";
|
|
735
|
+
break;
|
|
736
|
+
case "RS512":
|
|
737
|
+
case "PS512":
|
|
738
|
+
case "RSA-OAEP-512":
|
|
739
|
+
hash = "SHA-512";
|
|
740
|
+
break;
|
|
741
|
+
default: throw new TypeError(unusableForAlg);
|
|
742
|
+
}
|
|
743
|
+
if (alg.startsWith("RSA-OAEP")) return keyObject.toCryptoKey({
|
|
744
|
+
name: "RSA-OAEP",
|
|
745
|
+
hash
|
|
746
|
+
}, extractable, isPublic ? ["encrypt"] : ["decrypt"]);
|
|
747
|
+
cryptoKey = keyObject.toCryptoKey({
|
|
748
|
+
name: alg.startsWith("PS") ? "RSA-PSS" : "RSASSA-PKCS1-v1_5",
|
|
749
|
+
hash
|
|
750
|
+
}, extractable, [isPublic ? "verify" : "sign"]);
|
|
751
|
+
}
|
|
752
|
+
if (keyObject.asymmetricKeyType === "ec") {
|
|
753
|
+
const namedCurve = new Map([
|
|
754
|
+
["prime256v1", "P-256"],
|
|
755
|
+
["secp384r1", "P-384"],
|
|
756
|
+
["secp521r1", "P-521"]
|
|
757
|
+
]).get(keyObject.asymmetricKeyDetails?.namedCurve);
|
|
758
|
+
if (!namedCurve) throw new TypeError(unusableForAlg);
|
|
759
|
+
const expectedCurve = {
|
|
760
|
+
ES256: "P-256",
|
|
761
|
+
ES384: "P-384",
|
|
762
|
+
ES512: "P-521"
|
|
763
|
+
};
|
|
764
|
+
if (expectedCurve[alg] && namedCurve === expectedCurve[alg]) cryptoKey = keyObject.toCryptoKey({
|
|
765
|
+
name: "ECDSA",
|
|
766
|
+
namedCurve
|
|
767
|
+
}, extractable, [isPublic ? "verify" : "sign"]);
|
|
768
|
+
if (alg.startsWith("ECDH-ES")) cryptoKey = keyObject.toCryptoKey({
|
|
769
|
+
name: "ECDH",
|
|
770
|
+
namedCurve
|
|
771
|
+
}, extractable, isPublic ? [] : ["deriveBits"]);
|
|
772
|
+
}
|
|
773
|
+
if (!cryptoKey) throw new TypeError(unusableForAlg);
|
|
774
|
+
if (!cached) cache.set(keyObject, { [alg]: cryptoKey });
|
|
775
|
+
else cached[alg] = cryptoKey;
|
|
776
|
+
return cryptoKey;
|
|
777
|
+
};
|
|
778
|
+
async function normalizeKey(key, alg) {
|
|
779
|
+
if (key instanceof Uint8Array) return key;
|
|
780
|
+
if (isCryptoKey(key)) return key;
|
|
781
|
+
if (isKeyObject(key)) {
|
|
782
|
+
if (key.type === "secret") return key.export();
|
|
783
|
+
if ("toCryptoKey" in key && typeof key.toCryptoKey === "function") try {
|
|
784
|
+
return handleKeyObject(key, alg);
|
|
785
|
+
} catch (err) {
|
|
786
|
+
if (err instanceof TypeError) throw err;
|
|
787
|
+
}
|
|
788
|
+
let jwk = key.export({ format: "jwk" });
|
|
789
|
+
return handleJWK(key, jwk, alg);
|
|
790
|
+
}
|
|
791
|
+
if (isJWK(key)) {
|
|
792
|
+
if (key.k) return decode(key.k);
|
|
793
|
+
return handleJWK(key, key, alg, true);
|
|
794
|
+
}
|
|
795
|
+
throw new Error("unreachable");
|
|
423
796
|
}
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
797
|
+
//#endregion
|
|
798
|
+
//#region ../../node_modules/.pnpm/jose@6.2.4/node_modules/jose/dist/webapi/key/import.js
|
|
799
|
+
async function importJWK(jwk, alg, options) {
|
|
800
|
+
if (!isObject$1(jwk)) throw new TypeError("JWK must be an object");
|
|
801
|
+
let ext;
|
|
802
|
+
alg ??= jwk.alg;
|
|
803
|
+
ext ??= options?.extractable ?? jwk.ext;
|
|
804
|
+
switch (jwk.kty) {
|
|
805
|
+
case "oct":
|
|
806
|
+
if (typeof jwk.k !== "string" || !jwk.k) throw new TypeError("missing \"k\" (Key Value) Parameter value");
|
|
807
|
+
return decode(jwk.k);
|
|
808
|
+
case "RSA":
|
|
809
|
+
if ("oth" in jwk && jwk.oth !== void 0) throw new JOSENotSupported("RSA JWK \"oth\" (Other Primes Info) Parameter value is not supported");
|
|
810
|
+
return jwkToKey({
|
|
811
|
+
...jwk,
|
|
812
|
+
alg,
|
|
813
|
+
ext
|
|
814
|
+
});
|
|
815
|
+
case "AKP":
|
|
816
|
+
if (typeof jwk.alg !== "string" || !jwk.alg) throw new TypeError("missing \"alg\" (Algorithm) Parameter value");
|
|
817
|
+
if (alg !== void 0 && alg !== jwk.alg) throw new TypeError("JWK alg and alg option value mismatch");
|
|
818
|
+
return jwkToKey({
|
|
819
|
+
...jwk,
|
|
820
|
+
ext
|
|
821
|
+
});
|
|
822
|
+
case "EC":
|
|
823
|
+
case "OKP": return jwkToKey({
|
|
824
|
+
...jwk,
|
|
825
|
+
alg,
|
|
826
|
+
ext
|
|
827
|
+
});
|
|
828
|
+
default: throw new JOSENotSupported("Unsupported \"kty\" (Key Type) Parameter value");
|
|
829
|
+
}
|
|
428
830
|
}
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
return
|
|
433
|
-
|
|
434
|
-
|
|
831
|
+
//#endregion
|
|
832
|
+
//#region ../../node_modules/.pnpm/jose@6.2.4/node_modules/jose/dist/webapi/lib/key_to_jwk.js
|
|
833
|
+
function omitUndefinedProperties(jwk) {
|
|
834
|
+
return Object.fromEntries(Object.entries(jwk).filter(([, value]) => value !== void 0));
|
|
835
|
+
}
|
|
836
|
+
async function keyToJWK(key) {
|
|
837
|
+
if (isKeyObject(key)) if (key.type === "secret") key = key.export();
|
|
838
|
+
else return key.export({ format: "jwk" });
|
|
839
|
+
if (key instanceof Uint8Array) return {
|
|
840
|
+
kty: "oct",
|
|
841
|
+
k: encode(key)
|
|
435
842
|
};
|
|
843
|
+
if (!isCryptoKey(key)) throw new TypeError(invalidKeyInput(key, "CryptoKey", "KeyObject", "Uint8Array"));
|
|
844
|
+
if (!key.extractable) throw new TypeError("non-extractable CryptoKey cannot be exported as a JWK");
|
|
845
|
+
const { ext, key_ops, alg, use, ...jwk } = omitUndefinedProperties(await crypto.subtle.exportKey("jwk", key));
|
|
846
|
+
if (jwk.kty === "AKP") jwk.alg = alg;
|
|
847
|
+
return jwk;
|
|
436
848
|
}
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
return
|
|
441
|
-
members: unique(value.members.map((member) => {
|
|
442
|
-
exact$2(member, [
|
|
443
|
-
"email",
|
|
444
|
-
"id",
|
|
445
|
-
"image",
|
|
446
|
-
"joinedAt",
|
|
447
|
-
"name",
|
|
448
|
-
"owner",
|
|
449
|
-
"role",
|
|
450
|
-
"teamIds",
|
|
451
|
-
"userId"
|
|
452
|
-
]);
|
|
453
|
-
if (!isId(member.id) || !isId(member.userId) || !boundedString(member.name, 255) || typeof member.email !== "string" || member.email.length > 320 || !email.test(member.email) || !role(member.role) || typeof member.owner !== "boolean" || !Array.isArray(member.teamIds) || member.teamIds.length > 100) throw authorityUnavailable();
|
|
454
|
-
const teamIds = unique(member.teamIds.map((teamId) => normalizeResponseId(teamId)), (item) => item);
|
|
455
|
-
return {
|
|
456
|
-
id: member.id,
|
|
457
|
-
userId: member.userId,
|
|
458
|
-
name: member.name,
|
|
459
|
-
email: member.email,
|
|
460
|
-
image: nullableHttpsUrl(member.image),
|
|
461
|
-
role: member.role,
|
|
462
|
-
owner: member.owner,
|
|
463
|
-
joinedAt: responseDate(member.joinedAt),
|
|
464
|
-
teamIds
|
|
465
|
-
};
|
|
466
|
-
}), (item) => item.id),
|
|
467
|
-
nextCursor: nullableCursor(value.nextCursor)
|
|
468
|
-
};
|
|
849
|
+
//#endregion
|
|
850
|
+
//#region ../../node_modules/.pnpm/jose@6.2.4/node_modules/jose/dist/webapi/key/export.js
|
|
851
|
+
async function exportJWK(key) {
|
|
852
|
+
return keyToJWK(key);
|
|
469
853
|
}
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
category: team.category,
|
|
486
|
-
createdAt: responseDate(team.createdAt)
|
|
487
|
-
};
|
|
488
|
-
}), (item) => item.id),
|
|
489
|
-
nextCursor: nullableCursor(value.nextCursor)
|
|
490
|
-
};
|
|
854
|
+
//#endregion
|
|
855
|
+
//#region ../../node_modules/.pnpm/jose@6.2.4/node_modules/jose/dist/webapi/lib/validate_crit.js
|
|
856
|
+
function validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader, joseHeader) {
|
|
857
|
+
if (joseHeader.crit !== void 0 && protectedHeader?.crit === void 0) throw new Err("\"crit\" (Critical) Header Parameter MUST be integrity protected");
|
|
858
|
+
if (!protectedHeader || protectedHeader.crit === void 0) return new Set();
|
|
859
|
+
if (!Array.isArray(protectedHeader.crit) || protectedHeader.crit.length === 0 || protectedHeader.crit.some((input) => typeof input !== "string" || input.length === 0)) throw new Err("\"crit\" (Critical) Header Parameter MUST be an array of non-empty strings when present");
|
|
860
|
+
let recognized;
|
|
861
|
+
if (recognizedOption !== void 0) recognized = new Map([...Object.entries(recognizedOption), ...recognizedDefault.entries()]);
|
|
862
|
+
else recognized = recognizedDefault;
|
|
863
|
+
for (const parameter of protectedHeader.crit) {
|
|
864
|
+
if (!recognized.has(parameter)) throw new JOSENotSupported(`Extension Header Parameter "${parameter}" is not recognized`);
|
|
865
|
+
if (joseHeader[parameter] === void 0) throw new Err(`Extension Header Parameter "${parameter}" is missing`);
|
|
866
|
+
if (recognized.get(parameter) && protectedHeader[parameter] === void 0) throw new Err(`Extension Header Parameter "${parameter}" MUST be integrity protected`);
|
|
867
|
+
}
|
|
868
|
+
return new Set(protectedHeader.crit);
|
|
491
869
|
}
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
};
|
|
870
|
+
//#endregion
|
|
871
|
+
//#region ../../node_modules/.pnpm/jose@6.2.4/node_modules/jose/dist/webapi/lib/validate_algorithms.js
|
|
872
|
+
function validateAlgorithms(option, algorithms) {
|
|
873
|
+
if (algorithms !== void 0 && (!Array.isArray(algorithms) || algorithms.some((s) => typeof s !== "string"))) throw new TypeError(`"${option}" option must be an array of strings`);
|
|
874
|
+
if (!algorithms) return;
|
|
875
|
+
return new Set(algorithms);
|
|
499
876
|
}
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
877
|
+
//#endregion
|
|
878
|
+
//#region ../../node_modules/.pnpm/jose@6.2.4/node_modules/jose/dist/webapi/lib/check_key_type.js
|
|
879
|
+
const tag = (key) => key?.[Symbol.toStringTag];
|
|
880
|
+
const jwkMatchesOp = (alg, key, usage) => {
|
|
881
|
+
if (key.use !== void 0) {
|
|
882
|
+
let expected;
|
|
883
|
+
switch (usage) {
|
|
884
|
+
case "sign":
|
|
885
|
+
case "verify":
|
|
886
|
+
expected = "sig";
|
|
887
|
+
break;
|
|
888
|
+
case "encrypt":
|
|
889
|
+
case "decrypt":
|
|
890
|
+
expected = "enc";
|
|
891
|
+
break;
|
|
892
|
+
}
|
|
893
|
+
if (key.use !== expected) throw new TypeError(`Invalid key for this operation, its "use" must be "${expected}" when present`);
|
|
894
|
+
}
|
|
895
|
+
if (key.alg !== void 0 && key.alg !== alg) throw new TypeError(`Invalid key for this operation, its "alg" must be "${alg}" when present`);
|
|
896
|
+
if (Array.isArray(key.key_ops)) {
|
|
897
|
+
let expectedKeyOp;
|
|
898
|
+
switch (true) {
|
|
899
|
+
case usage === "sign" || usage === "verify":
|
|
900
|
+
case alg === "dir":
|
|
901
|
+
case alg.includes("CBC-HS"):
|
|
902
|
+
expectedKeyOp = usage;
|
|
903
|
+
break;
|
|
904
|
+
case alg.startsWith("PBES2"):
|
|
905
|
+
expectedKeyOp = "deriveBits";
|
|
906
|
+
break;
|
|
907
|
+
case /^A\d{3}(?:GCM)?(?:KW)?$/.test(alg):
|
|
908
|
+
if (!alg.includes("GCM") && alg.endsWith("KW")) expectedKeyOp = usage === "encrypt" ? "wrapKey" : "unwrapKey";
|
|
909
|
+
else expectedKeyOp = usage;
|
|
910
|
+
break;
|
|
911
|
+
case usage === "encrypt" && alg.startsWith("RSA"):
|
|
912
|
+
expectedKeyOp = "wrapKey";
|
|
913
|
+
break;
|
|
914
|
+
case usage === "decrypt":
|
|
915
|
+
expectedKeyOp = alg.startsWith("RSA") ? "unwrapKey" : "deriveBits";
|
|
916
|
+
break;
|
|
917
|
+
}
|
|
918
|
+
if (expectedKeyOp && key.key_ops?.includes?.(expectedKeyOp) === false) throw new TypeError(`Invalid key for this operation, its "key_ops" must include "${expectedKeyOp}" when present`);
|
|
919
|
+
}
|
|
920
|
+
return true;
|
|
921
|
+
};
|
|
922
|
+
const symmetricTypeCheck = (alg, key, usage) => {
|
|
923
|
+
if (key instanceof Uint8Array) return;
|
|
924
|
+
if (isJWK(key)) {
|
|
925
|
+
if (isSecretJWK(key) && jwkMatchesOp(alg, key, usage)) return;
|
|
926
|
+
throw new TypeError(`JSON Web Key for symmetric algorithms must have JWK "kty" (Key Type) equal to "oct" and the JWK "k" (Key Value) present`);
|
|
927
|
+
}
|
|
928
|
+
if (!isKeyLike(key)) throw new TypeError(withAlg(alg, key, "CryptoKey", "KeyObject", "JSON Web Key", "Uint8Array"));
|
|
929
|
+
if (key.type !== "secret") throw new TypeError(`${tag(key)} instances for symmetric algorithms must be of type "secret"`);
|
|
930
|
+
};
|
|
931
|
+
const asymmetricTypeCheck = (alg, key, usage) => {
|
|
932
|
+
if (isJWK(key)) switch (usage) {
|
|
933
|
+
case "decrypt":
|
|
934
|
+
case "sign":
|
|
935
|
+
if (isPrivateJWK(key) && jwkMatchesOp(alg, key, usage)) return;
|
|
936
|
+
throw new TypeError(`JSON Web Key for this operation must be a private JWK`);
|
|
937
|
+
case "encrypt":
|
|
938
|
+
case "verify":
|
|
939
|
+
if (isPublicJWK(key) && jwkMatchesOp(alg, key, usage)) return;
|
|
940
|
+
throw new TypeError(`JSON Web Key for this operation must be a public JWK`);
|
|
941
|
+
}
|
|
942
|
+
if (!isKeyLike(key)) throw new TypeError(withAlg(alg, key, "CryptoKey", "KeyObject", "JSON Web Key"));
|
|
943
|
+
if (key.type === "secret") throw new TypeError(`${tag(key)} instances for asymmetric algorithms must not be of type "secret"`);
|
|
944
|
+
if (key.type === "public") switch (usage) {
|
|
945
|
+
case "sign": throw new TypeError(`${tag(key)} instances for asymmetric algorithm signing must be of type "private"`);
|
|
946
|
+
case "decrypt": throw new TypeError(`${tag(key)} instances for asymmetric algorithm decryption must be of type "private"`);
|
|
947
|
+
}
|
|
948
|
+
if (key.type === "private") switch (usage) {
|
|
949
|
+
case "verify": throw new TypeError(`${tag(key)} instances for asymmetric algorithm verifying must be of type "public"`);
|
|
950
|
+
case "encrypt": throw new TypeError(`${tag(key)} instances for asymmetric algorithm encryption must be of type "public"`);
|
|
951
|
+
}
|
|
952
|
+
};
|
|
953
|
+
function checkKeyType(alg, key, usage) {
|
|
954
|
+
switch (alg.substring(0, 2)) {
|
|
955
|
+
case "A1":
|
|
956
|
+
case "A2":
|
|
957
|
+
case "di":
|
|
958
|
+
case "HS":
|
|
959
|
+
case "PB":
|
|
960
|
+
symmetricTypeCheck(alg, key, usage);
|
|
961
|
+
break;
|
|
962
|
+
default: asymmetricTypeCheck(alg, key, usage);
|
|
963
|
+
}
|
|
527
964
|
}
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
965
|
+
//#endregion
|
|
966
|
+
//#region ../../node_modules/.pnpm/jose@6.2.4/node_modules/jose/dist/webapi/jws/flattened/verify.js
|
|
967
|
+
async function flattenedVerify(jws, key, options) {
|
|
968
|
+
if (!isObject$1(jws)) throw new JWSInvalid("Flattened JWS must be an object");
|
|
969
|
+
if (jws.protected === void 0 && jws.header === void 0) throw new JWSInvalid("Flattened JWS must have either of the \"protected\" or \"header\" members");
|
|
970
|
+
if (jws.protected !== void 0 && typeof jws.protected !== "string") throw new JWSInvalid("JWS Protected Header incorrect type");
|
|
971
|
+
if (jws.payload === void 0) throw new JWSInvalid("JWS Payload missing");
|
|
972
|
+
if (typeof jws.signature !== "string") throw new JWSInvalid("JWS Signature missing or incorrect type");
|
|
973
|
+
if (jws.header !== void 0 && !isObject$1(jws.header)) throw new JWSInvalid("JWS Unprotected Header incorrect type");
|
|
974
|
+
let parsedProt = {};
|
|
975
|
+
if (jws.protected) try {
|
|
976
|
+
const protectedHeader = decode(jws.protected);
|
|
977
|
+
parsedProt = JSON.parse(decoder.decode(protectedHeader));
|
|
978
|
+
} catch {
|
|
979
|
+
throw new JWSInvalid("JWS Protected Header is invalid");
|
|
980
|
+
}
|
|
981
|
+
if (!isDisjoint(parsedProt, jws.header)) throw new JWSInvalid("JWS Protected and JWS Unprotected Header Parameter names must be disjoint");
|
|
982
|
+
const joseHeader = {
|
|
983
|
+
...parsedProt,
|
|
984
|
+
...jws.header
|
|
534
985
|
};
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
"
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
if (
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
};
|
|
569
|
-
}), (item) => item.id),
|
|
570
|
-
inviterName: value.inviterName,
|
|
571
|
-
expiresAt: responseDate(value.expiresAt)
|
|
986
|
+
const extensions = validateCrit(JWSInvalid, new Map([["b64", true]]), options?.crit, parsedProt, joseHeader);
|
|
987
|
+
let b64 = true;
|
|
988
|
+
if (extensions.has("b64")) {
|
|
989
|
+
b64 = parsedProt.b64;
|
|
990
|
+
if (typeof b64 !== "boolean") throw new JWSInvalid("The \"b64\" (base64url-encode payload) Header Parameter must be a boolean");
|
|
991
|
+
}
|
|
992
|
+
const { alg } = joseHeader;
|
|
993
|
+
if (typeof alg !== "string" || !alg) throw new JWSInvalid("JWS \"alg\" (Algorithm) Header Parameter missing or invalid");
|
|
994
|
+
const algorithms = options && validateAlgorithms("algorithms", options.algorithms);
|
|
995
|
+
if (algorithms && !algorithms.has(alg)) throw new JOSEAlgNotAllowed("\"alg\" (Algorithm) Header Parameter value not allowed");
|
|
996
|
+
if (b64) {
|
|
997
|
+
if (typeof jws.payload !== "string") throw new JWSInvalid("JWS Payload must be a string");
|
|
998
|
+
} else if (typeof jws.payload !== "string" && !(jws.payload instanceof Uint8Array)) throw new JWSInvalid("JWS Payload must be a string or an Uint8Array instance");
|
|
999
|
+
let resolvedKey = false;
|
|
1000
|
+
if (typeof key === "function") {
|
|
1001
|
+
key = await key(parsedProt, jws);
|
|
1002
|
+
resolvedKey = true;
|
|
1003
|
+
}
|
|
1004
|
+
checkKeyType(alg, key, "verify");
|
|
1005
|
+
const data = concat(jws.protected !== void 0 ? encode$1(jws.protected) : new Uint8Array(), encode$1("."), typeof jws.payload === "string" ? b64 ? encode$1(jws.payload) : encoder$1.encode(jws.payload) : jws.payload);
|
|
1006
|
+
const signature = decodeBase64url(jws.signature, "signature", JWSInvalid);
|
|
1007
|
+
const k = await normalizeKey(key, alg);
|
|
1008
|
+
if (!await verify(alg, k, signature, data)) throw new JWSSignatureVerificationFailed();
|
|
1009
|
+
let payload;
|
|
1010
|
+
if (b64) payload = decodeBase64url(jws.payload, "payload", JWSInvalid);
|
|
1011
|
+
else if (typeof jws.payload === "string") payload = encoder$1.encode(jws.payload);
|
|
1012
|
+
else payload = jws.payload;
|
|
1013
|
+
const result = { payload };
|
|
1014
|
+
if (jws.protected !== void 0) result.protectedHeader = parsedProt;
|
|
1015
|
+
if (jws.header !== void 0) result.unprotectedHeader = jws.header;
|
|
1016
|
+
if (resolvedKey) return {
|
|
1017
|
+
...result,
|
|
1018
|
+
key: k
|
|
572
1019
|
};
|
|
1020
|
+
return result;
|
|
573
1021
|
}
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
1022
|
+
//#endregion
|
|
1023
|
+
//#region ../../node_modules/.pnpm/jose@6.2.4/node_modules/jose/dist/webapi/jws/compact/verify.js
|
|
1024
|
+
async function compactVerify(jws, key, options) {
|
|
1025
|
+
if (jws instanceof Uint8Array) jws = decoder.decode(jws);
|
|
1026
|
+
if (typeof jws !== "string") throw new JWSInvalid("Compact JWS must be a string or Uint8Array");
|
|
1027
|
+
const { 0: protectedHeader, 1: payload, 2: signature, length } = jws.split(".");
|
|
1028
|
+
if (length !== 3) throw new JWSInvalid("Invalid Compact JWS");
|
|
1029
|
+
const verified = await flattenedVerify({
|
|
1030
|
+
payload,
|
|
1031
|
+
protected: protectedHeader,
|
|
1032
|
+
signature
|
|
1033
|
+
}, key, options);
|
|
1034
|
+
const result = {
|
|
1035
|
+
payload: verified.payload,
|
|
1036
|
+
protectedHeader: verified.protectedHeader
|
|
580
1037
|
};
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
return { invitationId: value.invitationId };
|
|
585
|
-
}
|
|
586
|
-
function normalizeInvitationAcceptance(value, invitationId) {
|
|
587
|
-
if (!isObject(value) || !isObject(value.invitation) || !isObject(value.member) || value.invitation.id !== invitationId || value.invitation.status !== "accepted" || !isId(value.invitation.organizationId) || value.member.organizationId !== value.invitation.organizationId) throw authorityUnavailable();
|
|
588
|
-
return { organizationId: value.invitation.organizationId };
|
|
589
|
-
}
|
|
590
|
-
function normalizeWorkspaceSelection(value) {
|
|
591
|
-
if (!isObject(value)) throw new AuthError("invalid_workspace_selection", 422);
|
|
592
|
-
const keys = Object.keys(value);
|
|
593
|
-
if (value.type === "personal" && keys.length === 1 && keys[0] === "type") return { type: "personal" };
|
|
594
|
-
if (value.type === "organization" && keys.length === 2 && keys.includes("type") && keys.includes("organizationId") && typeof value.organizationId === "string" && id.test(value.organizationId)) return {
|
|
595
|
-
type: "organization",
|
|
596
|
-
organizationId: value.organizationId
|
|
1038
|
+
if (typeof key === "function") return {
|
|
1039
|
+
...result,
|
|
1040
|
+
key: verified.key
|
|
597
1041
|
};
|
|
598
|
-
|
|
1042
|
+
return result;
|
|
599
1043
|
}
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
1044
|
+
//#endregion
|
|
1045
|
+
//#region ../../node_modules/.pnpm/jose@6.2.4/node_modules/jose/dist/webapi/lib/jwt_claims_set.js
|
|
1046
|
+
const epoch = (date) => Math.floor(date.getTime() / 1e3);
|
|
1047
|
+
const minute = 60;
|
|
1048
|
+
const hour = minute * 60;
|
|
1049
|
+
const day = hour * 24;
|
|
1050
|
+
const week = day * 7;
|
|
1051
|
+
const year = day * 365.25;
|
|
1052
|
+
const REGEX = /^(\+|\-)? ?(\d+|\d+\.\d+) ?(seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)(?: (ago|from now))?$/i;
|
|
1053
|
+
function secs(str) {
|
|
1054
|
+
const matched = REGEX.exec(str);
|
|
1055
|
+
if (!matched || matched[4] && matched[1]) throw new TypeError("Invalid time period format");
|
|
1056
|
+
const value = parseFloat(matched[2]);
|
|
1057
|
+
const unit = matched[3].toLowerCase();
|
|
1058
|
+
let numericDate;
|
|
1059
|
+
switch (unit) {
|
|
1060
|
+
case "sec":
|
|
1061
|
+
case "secs":
|
|
1062
|
+
case "second":
|
|
1063
|
+
case "seconds":
|
|
1064
|
+
case "s":
|
|
1065
|
+
numericDate = Math.round(value);
|
|
1066
|
+
break;
|
|
1067
|
+
case "minute":
|
|
1068
|
+
case "minutes":
|
|
1069
|
+
case "min":
|
|
1070
|
+
case "mins":
|
|
1071
|
+
case "m":
|
|
1072
|
+
numericDate = Math.round(value * minute);
|
|
1073
|
+
break;
|
|
1074
|
+
case "hour":
|
|
1075
|
+
case "hours":
|
|
1076
|
+
case "hr":
|
|
1077
|
+
case "hrs":
|
|
1078
|
+
case "h":
|
|
1079
|
+
numericDate = Math.round(value * hour);
|
|
1080
|
+
break;
|
|
1081
|
+
case "day":
|
|
1082
|
+
case "days":
|
|
1083
|
+
case "d":
|
|
1084
|
+
numericDate = Math.round(value * day);
|
|
1085
|
+
break;
|
|
1086
|
+
case "week":
|
|
1087
|
+
case "weeks":
|
|
1088
|
+
case "w":
|
|
1089
|
+
numericDate = Math.round(value * week);
|
|
1090
|
+
break;
|
|
1091
|
+
default:
|
|
1092
|
+
numericDate = Math.round(value * year);
|
|
1093
|
+
break;
|
|
1094
|
+
}
|
|
1095
|
+
if (matched[1] === "-" || matched[4] === "ago") return -numericDate;
|
|
1096
|
+
return numericDate;
|
|
603
1097
|
}
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
if (
|
|
610
|
-
if (
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
1098
|
+
const normalizeTyp = (value) => {
|
|
1099
|
+
if (value.includes("/")) return value.toLowerCase();
|
|
1100
|
+
return `application/${value.toLowerCase()}`;
|
|
1101
|
+
};
|
|
1102
|
+
const checkAudiencePresence = (audPayload, audOption) => {
|
|
1103
|
+
if (typeof audPayload === "string") return audOption.includes(audPayload);
|
|
1104
|
+
if (Array.isArray(audPayload)) return audOption.some(Set.prototype.has.bind(new Set(audPayload)));
|
|
1105
|
+
return false;
|
|
1106
|
+
};
|
|
1107
|
+
function validateClaimsSet(protectedHeader, encodedPayload, options = {}) {
|
|
1108
|
+
let payload;
|
|
1109
|
+
try {
|
|
1110
|
+
payload = JSON.parse(decoder.decode(encodedPayload));
|
|
1111
|
+
} catch {}
|
|
1112
|
+
if (!isObject$1(payload)) throw new JWTInvalid("JWT Claims Set must be a top-level JSON object");
|
|
1113
|
+
const { typ } = options;
|
|
1114
|
+
if (typ && (typeof protectedHeader.typ !== "string" || normalizeTyp(protectedHeader.typ) !== normalizeTyp(typ))) throw new JWTClaimValidationFailed("unexpected \"typ\" JWT header value", payload, "typ", "check_failed");
|
|
1115
|
+
const { requiredClaims = [], issuer, subject, audience, maxTokenAge } = options;
|
|
1116
|
+
const presenceCheck = [...requiredClaims];
|
|
1117
|
+
if (maxTokenAge !== void 0) presenceCheck.push("iat");
|
|
1118
|
+
if (audience !== void 0) presenceCheck.push("aud");
|
|
1119
|
+
if (subject !== void 0) presenceCheck.push("sub");
|
|
1120
|
+
if (issuer !== void 0) presenceCheck.push("iss");
|
|
1121
|
+
for (const claim of new Set(presenceCheck.reverse())) if (!(claim in payload)) throw new JWTClaimValidationFailed(`missing required "${claim}" claim`, payload, claim, "missing");
|
|
1122
|
+
if (issuer && !(Array.isArray(issuer) ? issuer : [issuer]).includes(payload.iss)) throw new JWTClaimValidationFailed("unexpected \"iss\" claim value", payload, "iss", "check_failed");
|
|
1123
|
+
if (subject && payload.sub !== subject) throw new JWTClaimValidationFailed("unexpected \"sub\" claim value", payload, "sub", "check_failed");
|
|
1124
|
+
if (audience && !checkAudiencePresence(payload.aud, typeof audience === "string" ? [audience] : audience)) throw new JWTClaimValidationFailed("unexpected \"aud\" claim value", payload, "aud", "check_failed");
|
|
1125
|
+
let tolerance;
|
|
1126
|
+
switch (typeof options.clockTolerance) {
|
|
1127
|
+
case "string":
|
|
1128
|
+
tolerance = secs(options.clockTolerance);
|
|
1129
|
+
break;
|
|
1130
|
+
case "number":
|
|
1131
|
+
tolerance = options.clockTolerance;
|
|
1132
|
+
break;
|
|
1133
|
+
case "undefined":
|
|
1134
|
+
tolerance = 0;
|
|
1135
|
+
break;
|
|
1136
|
+
default: throw new TypeError("Invalid clockTolerance option type");
|
|
1137
|
+
}
|
|
1138
|
+
const { currentDate } = options;
|
|
1139
|
+
const now = epoch(currentDate || new Date());
|
|
1140
|
+
if ((payload.iat !== void 0 || maxTokenAge) && typeof payload.iat !== "number") throw new JWTClaimValidationFailed("\"iat\" claim must be a number", payload, "iat", "invalid");
|
|
1141
|
+
if (payload.nbf !== void 0) {
|
|
1142
|
+
if (typeof payload.nbf !== "number") throw new JWTClaimValidationFailed("\"nbf\" claim must be a number", payload, "nbf", "invalid");
|
|
1143
|
+
if (payload.nbf > now + tolerance) throw new JWTClaimValidationFailed("\"nbf\" claim timestamp check failed", payload, "nbf", "check_failed");
|
|
1144
|
+
}
|
|
1145
|
+
if (payload.exp !== void 0) {
|
|
1146
|
+
if (typeof payload.exp !== "number") throw new JWTClaimValidationFailed("\"exp\" claim must be a number", payload, "exp", "invalid");
|
|
1147
|
+
if (payload.exp <= now - tolerance) throw new JWTExpired("\"exp\" claim timestamp check failed", payload, "exp", "check_failed");
|
|
1148
|
+
}
|
|
1149
|
+
if (maxTokenAge) {
|
|
1150
|
+
const age = now - payload.iat;
|
|
1151
|
+
const max = typeof maxTokenAge === "number" ? maxTokenAge : secs(maxTokenAge);
|
|
1152
|
+
if (age - tolerance > max) throw new JWTExpired("\"iat\" claim timestamp check failed (too far in the past)", payload, "iat", "check_failed");
|
|
1153
|
+
if (age < 0 - tolerance) throw new JWTClaimValidationFailed("\"iat\" claim timestamp check failed (it should be in the past)", payload, "iat", "check_failed");
|
|
1154
|
+
}
|
|
1155
|
+
return payload;
|
|
617
1156
|
}
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
1157
|
+
//#endregion
|
|
1158
|
+
//#region ../../node_modules/.pnpm/jose@6.2.4/node_modules/jose/dist/webapi/jwt/verify.js
|
|
1159
|
+
async function jwtVerify(jwt, key, options) {
|
|
1160
|
+
const verified = await compactVerify(jwt, key, options);
|
|
1161
|
+
if (verified.protectedHeader.crit?.includes("b64") && verified.protectedHeader.b64 === false) throw new JWTInvalid("JWTs MUST NOT use unencoded payload");
|
|
1162
|
+
const result = {
|
|
1163
|
+
payload: validateClaimsSet(verified.protectedHeader, verified.payload, options),
|
|
1164
|
+
protectedHeader: verified.protectedHeader
|
|
1165
|
+
};
|
|
1166
|
+
if (typeof key === "function") return {
|
|
1167
|
+
...result,
|
|
1168
|
+
key: verified.key
|
|
1169
|
+
};
|
|
1170
|
+
return result;
|
|
623
1171
|
}
|
|
624
|
-
|
|
625
|
-
|
|
1172
|
+
//#endregion
|
|
1173
|
+
//#region ../../node_modules/.pnpm/jose@6.2.4/node_modules/jose/dist/webapi/jwk/thumbprint.js
|
|
1174
|
+
const check = (value, description) => {
|
|
1175
|
+
if (typeof value !== "string" || !value) throw new JWKInvalid(`${description} missing or invalid`);
|
|
1176
|
+
};
|
|
1177
|
+
async function calculateJwkThumbprint(key, digestAlgorithm) {
|
|
1178
|
+
let jwk;
|
|
1179
|
+
if (isJWK(key)) jwk = key;
|
|
1180
|
+
else if (isKeyLike(key)) jwk = await exportJWK(key);
|
|
1181
|
+
else throw new TypeError(invalidKeyInput(key, "CryptoKey", "KeyObject", "JSON Web Key"));
|
|
1182
|
+
digestAlgorithm ??= "sha256";
|
|
1183
|
+
if (digestAlgorithm !== "sha256" && digestAlgorithm !== "sha384" && digestAlgorithm !== "sha512") throw new TypeError("digestAlgorithm must one of \"sha256\", \"sha384\", or \"sha512\"");
|
|
1184
|
+
let components;
|
|
1185
|
+
switch (jwk.kty) {
|
|
1186
|
+
case "AKP":
|
|
1187
|
+
check(jwk.alg, "\"alg\" (Algorithm) Parameter");
|
|
1188
|
+
check(jwk.pub, "\"pub\" (Public key) Parameter");
|
|
1189
|
+
components = {
|
|
1190
|
+
alg: jwk.alg,
|
|
1191
|
+
kty: jwk.kty,
|
|
1192
|
+
pub: jwk.pub
|
|
1193
|
+
};
|
|
1194
|
+
break;
|
|
1195
|
+
case "EC":
|
|
1196
|
+
check(jwk.crv, "\"crv\" (Curve) Parameter");
|
|
1197
|
+
check(jwk.x, "\"x\" (X Coordinate) Parameter");
|
|
1198
|
+
check(jwk.y, "\"y\" (Y Coordinate) Parameter");
|
|
1199
|
+
components = {
|
|
1200
|
+
crv: jwk.crv,
|
|
1201
|
+
kty: jwk.kty,
|
|
1202
|
+
x: jwk.x,
|
|
1203
|
+
y: jwk.y
|
|
1204
|
+
};
|
|
1205
|
+
break;
|
|
1206
|
+
case "OKP":
|
|
1207
|
+
check(jwk.crv, "\"crv\" (Subtype of Key Pair) Parameter");
|
|
1208
|
+
check(jwk.x, "\"x\" (Public Key) Parameter");
|
|
1209
|
+
components = {
|
|
1210
|
+
crv: jwk.crv,
|
|
1211
|
+
kty: jwk.kty,
|
|
1212
|
+
x: jwk.x
|
|
1213
|
+
};
|
|
1214
|
+
break;
|
|
1215
|
+
case "RSA":
|
|
1216
|
+
check(jwk.e, "\"e\" (Exponent) Parameter");
|
|
1217
|
+
check(jwk.n, "\"n\" (Modulus) Parameter");
|
|
1218
|
+
components = {
|
|
1219
|
+
e: jwk.e,
|
|
1220
|
+
kty: jwk.kty,
|
|
1221
|
+
n: jwk.n
|
|
1222
|
+
};
|
|
1223
|
+
break;
|
|
1224
|
+
case "oct":
|
|
1225
|
+
check(jwk.k, "\"k\" (Key Value) Parameter");
|
|
1226
|
+
components = {
|
|
1227
|
+
k: jwk.k,
|
|
1228
|
+
kty: jwk.kty
|
|
1229
|
+
};
|
|
1230
|
+
break;
|
|
1231
|
+
default: throw new JOSENotSupported("\"kty\" (Key Type) Parameter missing or unsupported");
|
|
1232
|
+
}
|
|
1233
|
+
const data = encode$1(JSON.stringify(components));
|
|
1234
|
+
return encode(await digest(digestAlgorithm, data));
|
|
626
1235
|
}
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
1236
|
+
//#endregion
|
|
1237
|
+
//#region ../../node_modules/.pnpm/jose@6.2.4/node_modules/jose/dist/webapi/util/decode_protected_header.js
|
|
1238
|
+
function decodeProtectedHeader(token) {
|
|
1239
|
+
let protectedB64u;
|
|
1240
|
+
if (typeof token === "string") {
|
|
1241
|
+
const parts = token.split(".");
|
|
1242
|
+
if (parts.length === 3 || parts.length === 5) [protectedB64u] = parts;
|
|
1243
|
+
} else if (typeof token === "object" && token) if ("protected" in token) protectedB64u = token.protected;
|
|
1244
|
+
else throw new TypeError("Token does not contain a Protected Header");
|
|
1245
|
+
try {
|
|
1246
|
+
if (typeof protectedB64u !== "string" || !protectedB64u) throw new Error();
|
|
1247
|
+
const result = JSON.parse(decoder.decode(decode(protectedB64u)));
|
|
1248
|
+
if (!isObject$1(result)) throw new Error();
|
|
1249
|
+
return result;
|
|
1250
|
+
} catch {
|
|
1251
|
+
throw new TypeError("Invalid Token or Protected Header formatting");
|
|
1252
|
+
}
|
|
631
1253
|
}
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
if (
|
|
636
|
-
|
|
1254
|
+
//#endregion
|
|
1255
|
+
//#region ../../node_modules/.pnpm/jose@6.2.4/node_modules/jose/dist/webapi/util/decode_jwt.js
|
|
1256
|
+
function decodeJwt(jwt) {
|
|
1257
|
+
if (typeof jwt !== "string") throw new JWTInvalid("JWTs must use Compact JWS serialization, JWT must be a string");
|
|
1258
|
+
const { 1: payload, length } = jwt.split(".");
|
|
1259
|
+
if (length === 5) throw new JWTInvalid("Only JWTs using Compact JWS serialization can be decoded");
|
|
1260
|
+
if (length !== 3) throw new JWTInvalid("Invalid JWT");
|
|
1261
|
+
if (!payload) throw new JWTInvalid("JWTs must contain a payload");
|
|
1262
|
+
let decoded;
|
|
1263
|
+
try {
|
|
1264
|
+
decoded = decode(payload);
|
|
1265
|
+
} catch {
|
|
1266
|
+
throw new JWTInvalid("Failed to base64url decode the payload");
|
|
1267
|
+
}
|
|
1268
|
+
let result;
|
|
1269
|
+
try {
|
|
1270
|
+
result = JSON.parse(decoder.decode(decoded));
|
|
1271
|
+
} catch {
|
|
1272
|
+
throw new JWTInvalid("Failed to parse the decoded payload as JSON");
|
|
1273
|
+
}
|
|
1274
|
+
if (!isObject$1(result)) throw new JWTInvalid("Invalid JWT Claims Set");
|
|
1275
|
+
return result;
|
|
637
1276
|
}
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
1277
|
+
//#endregion
|
|
1278
|
+
//#region ../../node_modules/.pnpm/destr@2.0.5/node_modules/destr/dist/index.mjs
|
|
1279
|
+
const suspectProtoRx = /"(?:_|\\u0{2}5[Ff]){2}(?:p|\\u0{2}70)(?:r|\\u0{2}72)(?:o|\\u0{2}6[Ff])(?:t|\\u0{2}74)(?:o|\\u0{2}6[Ff])(?:_|\\u0{2}5[Ff]){2}"\s*:/;
|
|
1280
|
+
const suspectConstructorRx = /"(?:c|\\u0063)(?:o|\\u006[Ff])(?:n|\\u006[Ee])(?:s|\\u0073)(?:t|\\u0074)(?:r|\\u0072)(?:u|\\u0075)(?:c|\\u0063)(?:t|\\u0074)(?:o|\\u006[Ff])(?:r|\\u0072)"\s*:/;
|
|
1281
|
+
const JsonSigRx = /^\s*["[{]|^\s*-?\d{1,16}(\.\d{1,17})?([Ee][+-]?\d+)?\s*$/;
|
|
1282
|
+
function jsonParseTransform(key, value) {
|
|
1283
|
+
if (key === "__proto__" || key === "constructor" && value && typeof value === "object" && "prototype" in value) {
|
|
1284
|
+
warnKeyDropped(key);
|
|
1285
|
+
return;
|
|
1286
|
+
}
|
|
1287
|
+
return value;
|
|
645
1288
|
}
|
|
646
|
-
function
|
|
647
|
-
|
|
648
|
-
return fromOrganizationMutationAuthorityError(value, status, retryAfter);
|
|
1289
|
+
function warnKeyDropped(key) {
|
|
1290
|
+
console.warn(`[destr] Dropping "${key}" key to prevent prototype pollution.`);
|
|
649
1291
|
}
|
|
650
|
-
function
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
}
|
|
1292
|
+
function destr(value, options = {}) {
|
|
1293
|
+
if (typeof value !== "string") return value;
|
|
1294
|
+
if (value[0] === "\"" && value[value.length - 1] === "\"" && value.indexOf("\\") === -1) return value.slice(1, -1);
|
|
1295
|
+
const _value = value.trim();
|
|
1296
|
+
if (_value.length <= 9) switch (_value.toLowerCase()) {
|
|
1297
|
+
case "true": return true;
|
|
1298
|
+
case "false": return false;
|
|
1299
|
+
case "undefined": return;
|
|
1300
|
+
case "null": return null;
|
|
1301
|
+
case "nan": return NaN;
|
|
1302
|
+
case "infinity": return Number.POSITIVE_INFINITY;
|
|
1303
|
+
case "-infinity": return Number.NEGATIVE_INFINITY;
|
|
1304
|
+
}
|
|
1305
|
+
if (!JsonSigRx.test(value)) {
|
|
1306
|
+
if (options.strict) throw new SyntaxError("[destr] Invalid JSON");
|
|
1307
|
+
return value;
|
|
1308
|
+
}
|
|
1309
|
+
try {
|
|
1310
|
+
if (suspectProtoRx.test(value) || suspectConstructorRx.test(value)) {
|
|
1311
|
+
if (options.strict) throw new Error("[destr] Possible prototype pollution");
|
|
1312
|
+
return JSON.parse(value, jsonParseTransform);
|
|
1313
|
+
}
|
|
1314
|
+
return JSON.parse(value);
|
|
1315
|
+
} catch (error) {
|
|
1316
|
+
if (options.strict) throw error;
|
|
1317
|
+
return value;
|
|
1318
|
+
}
|
|
667
1319
|
}
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
"
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
1320
|
+
//#endregion
|
|
1321
|
+
//#region ../../node_modules/.pnpm/ofetch@1.5.1/node_modules/ofetch/dist/shared/ofetch.CWycOUEr.mjs
|
|
1322
|
+
var FetchError = class extends Error {
|
|
1323
|
+
constructor(message, opts) {
|
|
1324
|
+
super(message, opts);
|
|
1325
|
+
this.name = "FetchError";
|
|
1326
|
+
if (opts?.cause && !this.cause) this.cause = opts.cause;
|
|
1327
|
+
}
|
|
1328
|
+
};
|
|
1329
|
+
function createFetchError(ctx) {
|
|
1330
|
+
const errorMessage = ctx.error?.message || ctx.error?.toString() || "";
|
|
1331
|
+
const method = ctx.request?.method || ctx.options?.method || "GET";
|
|
1332
|
+
const url = ctx.request?.url || String(ctx.request) || "/";
|
|
1333
|
+
const fetchError = new FetchError(`${`[${method}] ${JSON.stringify(url)}`}: ${ctx.response ? `${ctx.response.status} ${ctx.response.statusText}` : "<no response>"}${errorMessage ? ` ${errorMessage}` : ""}`, ctx.error ? { cause: ctx.error } : void 0);
|
|
1334
|
+
for (const key of [
|
|
1335
|
+
"request",
|
|
1336
|
+
"options",
|
|
1337
|
+
"response"
|
|
1338
|
+
]) Object.defineProperty(fetchError, key, { get() {
|
|
1339
|
+
return ctx[key];
|
|
1340
|
+
} });
|
|
1341
|
+
for (const [key, refKey] of [
|
|
1342
|
+
["data", "_data"],
|
|
1343
|
+
["status", "status"],
|
|
1344
|
+
["statusCode", "status"],
|
|
1345
|
+
["statusText", "statusText"],
|
|
1346
|
+
["statusMessage", "statusText"]
|
|
1347
|
+
]) Object.defineProperty(fetchError, key, { get() {
|
|
1348
|
+
return ctx.response && ctx.response[refKey];
|
|
1349
|
+
} });
|
|
1350
|
+
return fetchError;
|
|
683
1351
|
}
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
1352
|
+
const payloadMethods = new Set(Object.freeze([
|
|
1353
|
+
"PATCH",
|
|
1354
|
+
"POST",
|
|
1355
|
+
"PUT",
|
|
1356
|
+
"DELETE"
|
|
1357
|
+
]));
|
|
1358
|
+
function isPayloadMethod(method = "GET") {
|
|
1359
|
+
return payloadMethods.has(method.toUpperCase());
|
|
687
1360
|
}
|
|
688
|
-
function
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
if (
|
|
692
|
-
if (
|
|
693
|
-
if (
|
|
694
|
-
if (
|
|
695
|
-
|
|
1361
|
+
function isJSONSerializable(value) {
|
|
1362
|
+
if (value === void 0) return false;
|
|
1363
|
+
const t = typeof value;
|
|
1364
|
+
if (t === "string" || t === "number" || t === "boolean" || t === null) return true;
|
|
1365
|
+
if (t !== "object") return false;
|
|
1366
|
+
if (Array.isArray(value)) return true;
|
|
1367
|
+
if (value.buffer) return false;
|
|
1368
|
+
if (value instanceof FormData || value instanceof URLSearchParams) return false;
|
|
1369
|
+
return value.constructor && value.constructor.name === "Object" || typeof value.toJSON === "function";
|
|
696
1370
|
}
|
|
697
|
-
|
|
698
|
-
|
|
1371
|
+
const textTypes = new Set([
|
|
1372
|
+
"image/svg",
|
|
1373
|
+
"application/xml",
|
|
1374
|
+
"application/xhtml",
|
|
1375
|
+
"application/html"
|
|
1376
|
+
]);
|
|
1377
|
+
const JSON_RE = /^application\/(?:[\w!#$%&*.^`~-]*\+)?json(;.+)?$/i;
|
|
1378
|
+
function detectResponseType(_contentType = "") {
|
|
1379
|
+
if (!_contentType) return "json";
|
|
1380
|
+
const contentType = _contentType.split(";").shift() || "";
|
|
1381
|
+
if (JSON_RE.test(contentType)) return "json";
|
|
1382
|
+
if (contentType === "text/event-stream") return "stream";
|
|
1383
|
+
if (textTypes.has(contentType) || contentType.startsWith("text/")) return "text";
|
|
1384
|
+
return "blob";
|
|
699
1385
|
}
|
|
700
|
-
function
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
};
|
|
709
|
-
if (code === "invalid_workspace_selection") return {
|
|
710
|
-
code,
|
|
711
|
-
status: 422
|
|
712
|
-
};
|
|
713
|
-
if (code === "organization_context_too_large") return {
|
|
714
|
-
code,
|
|
715
|
-
status: 422
|
|
716
|
-
};
|
|
717
|
-
if (code === "credential_rate_limited") return {
|
|
718
|
-
code,
|
|
719
|
-
status: 429
|
|
720
|
-
};
|
|
721
|
-
if (code === "identity_authority_unavailable") return {
|
|
722
|
-
code,
|
|
723
|
-
status: 503
|
|
724
|
-
};
|
|
725
|
-
if (status === 401 || status === 400) return {
|
|
726
|
-
code: "invalid_credentials",
|
|
727
|
-
status: 401
|
|
728
|
-
};
|
|
729
|
-
if (status === 403) return {
|
|
730
|
-
code: "access_denied",
|
|
731
|
-
status: 403
|
|
732
|
-
};
|
|
733
|
-
if (status === 409) return {
|
|
734
|
-
code: "state_conflict",
|
|
735
|
-
status: 409
|
|
736
|
-
};
|
|
737
|
-
if (status === 422) return {
|
|
738
|
-
code: "invalid_workspace_selection",
|
|
739
|
-
status: 422
|
|
740
|
-
};
|
|
741
|
-
if (status === 429) return {
|
|
742
|
-
code: "credential_rate_limited",
|
|
743
|
-
status: 429
|
|
1386
|
+
function resolveFetchOptions(request, input, defaults, Headers) {
|
|
1387
|
+
const headers = mergeHeaders(input?.headers ?? request?.headers, defaults?.headers, Headers);
|
|
1388
|
+
let query;
|
|
1389
|
+
if (defaults?.query || defaults?.params || input?.params || input?.query) query = {
|
|
1390
|
+
...defaults?.params,
|
|
1391
|
+
...defaults?.query,
|
|
1392
|
+
...input?.params,
|
|
1393
|
+
...input?.query
|
|
744
1394
|
};
|
|
745
1395
|
return {
|
|
746
|
-
|
|
747
|
-
|
|
1396
|
+
...defaults,
|
|
1397
|
+
...input,
|
|
1398
|
+
query,
|
|
1399
|
+
params: query,
|
|
1400
|
+
headers
|
|
748
1401
|
};
|
|
749
1402
|
}
|
|
750
|
-
function
|
|
751
|
-
if (!
|
|
752
|
-
const
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
function toDate(value) {
|
|
756
|
-
const result = value instanceof Date ? value : typeof value === "string" ? new Date(value) : void 0;
|
|
757
|
-
return result && Number.isFinite(result.getTime()) ? result : void 0;
|
|
758
|
-
}
|
|
759
|
-
function isId(value) {
|
|
760
|
-
return typeof value === "string" && id.test(value);
|
|
761
|
-
}
|
|
762
|
-
function exact$2(value, keys) {
|
|
763
|
-
if (!isObject(value) || Object.keys(value).sort().join(",") !== [...keys].sort().join(",")) throw authorityUnavailable();
|
|
764
|
-
}
|
|
765
|
-
function boundedString(value, maximum) {
|
|
766
|
-
return typeof value === "string" && value.length > 0 && new TextEncoder().encode(value).byteLength <= maximum;
|
|
1403
|
+
function mergeHeaders(input, defaults, Headers) {
|
|
1404
|
+
if (!defaults) return new Headers(input);
|
|
1405
|
+
const headers = new Headers(defaults);
|
|
1406
|
+
if (input) for (const [key, value] of Symbol.iterator in input || Array.isArray(input) ? input : new Headers(input)) headers.set(key, value);
|
|
1407
|
+
return headers;
|
|
767
1408
|
}
|
|
768
|
-
function
|
|
769
|
-
|
|
1409
|
+
async function callHooks(context, hooks) {
|
|
1410
|
+
if (hooks) if (Array.isArray(hooks)) for (const hook of hooks) await hook(context);
|
|
1411
|
+
else await hooks(context);
|
|
770
1412
|
}
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
1413
|
+
const retryStatusCodes = new Set([
|
|
1414
|
+
408,
|
|
1415
|
+
409,
|
|
1416
|
+
425,
|
|
1417
|
+
429,
|
|
1418
|
+
500,
|
|
1419
|
+
502,
|
|
1420
|
+
503,
|
|
1421
|
+
504
|
|
1422
|
+
]);
|
|
1423
|
+
const nullBodyResponses = new Set([
|
|
1424
|
+
101,
|
|
1425
|
+
204,
|
|
1426
|
+
205,
|
|
1427
|
+
304
|
|
1428
|
+
]);
|
|
1429
|
+
function createFetch(globalOptions = {}) {
|
|
1430
|
+
const { fetch = globalThis.fetch, Headers = globalThis.Headers, AbortController = globalThis.AbortController } = globalOptions;
|
|
1431
|
+
async function onError(context) {
|
|
1432
|
+
const isAbort = context.error && context.error.name === "AbortError" && !context.options.timeout || false;
|
|
1433
|
+
if (context.options.retry !== false && !isAbort) {
|
|
1434
|
+
let retries;
|
|
1435
|
+
if (typeof context.options.retry === "number") retries = context.options.retry;
|
|
1436
|
+
else retries = isPayloadMethod(context.options.method) ? 0 : 1;
|
|
1437
|
+
const responseCode = context.response && context.response.status || 500;
|
|
1438
|
+
if (retries > 0 && (Array.isArray(context.options.retryStatusCodes) ? context.options.retryStatusCodes.includes(responseCode) : retryStatusCodes.has(responseCode))) {
|
|
1439
|
+
const retryDelay = typeof context.options.retryDelay === "function" ? context.options.retryDelay(context) : context.options.retryDelay || 0;
|
|
1440
|
+
if (retryDelay > 0) await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
|
1441
|
+
return $fetchRaw(context.request, {
|
|
1442
|
+
...context.options,
|
|
1443
|
+
retry: retries - 1
|
|
1444
|
+
});
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
const error = createFetchError(context);
|
|
1448
|
+
if (Error.captureStackTrace) Error.captureStackTrace(error, $fetchRaw);
|
|
1449
|
+
throw error;
|
|
779
1450
|
}
|
|
780
|
-
|
|
781
|
-
|
|
1451
|
+
const $fetchRaw = async function $fetchRaw2(_request, _options = {}) {
|
|
1452
|
+
const context = {
|
|
1453
|
+
request: _request,
|
|
1454
|
+
options: resolveFetchOptions(_request, _options, globalOptions.defaults, Headers),
|
|
1455
|
+
response: void 0,
|
|
1456
|
+
error: void 0
|
|
1457
|
+
};
|
|
1458
|
+
if (context.options.method) context.options.method = context.options.method.toUpperCase();
|
|
1459
|
+
if (context.options.onRequest) {
|
|
1460
|
+
await callHooks(context, context.options.onRequest);
|
|
1461
|
+
if (!(context.options.headers instanceof Headers)) context.options.headers = new Headers(context.options.headers || {});
|
|
1462
|
+
}
|
|
1463
|
+
if (typeof context.request === "string") {
|
|
1464
|
+
if (context.options.baseURL) context.request = withBase(context.request, context.options.baseURL);
|
|
1465
|
+
if (context.options.query) {
|
|
1466
|
+
context.request = withQuery(context.request, context.options.query);
|
|
1467
|
+
delete context.options.query;
|
|
1468
|
+
}
|
|
1469
|
+
if ("query" in context.options) delete context.options.query;
|
|
1470
|
+
if ("params" in context.options) delete context.options.params;
|
|
1471
|
+
}
|
|
1472
|
+
if (context.options.body && isPayloadMethod(context.options.method)) {
|
|
1473
|
+
if (isJSONSerializable(context.options.body)) {
|
|
1474
|
+
const contentType = context.options.headers.get("content-type");
|
|
1475
|
+
if (typeof context.options.body !== "string") context.options.body = contentType === "application/x-www-form-urlencoded" ? new URLSearchParams(context.options.body).toString() : JSON.stringify(context.options.body);
|
|
1476
|
+
if (!contentType) context.options.headers.set("content-type", "application/json");
|
|
1477
|
+
if (!context.options.headers.has("accept")) context.options.headers.set("accept", "application/json");
|
|
1478
|
+
} else if ("pipeTo" in context.options.body && typeof context.options.body.pipeTo === "function" || typeof context.options.body.pipe === "function") {
|
|
1479
|
+
if (!("duplex" in context.options)) context.options.duplex = "half";
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
let abortTimeout;
|
|
1483
|
+
if (!context.options.signal && context.options.timeout) {
|
|
1484
|
+
const controller = new AbortController();
|
|
1485
|
+
abortTimeout = setTimeout(() => {
|
|
1486
|
+
const error = new Error("[TimeoutError]: The operation was aborted due to timeout");
|
|
1487
|
+
error.name = "TimeoutError";
|
|
1488
|
+
error.code = 23;
|
|
1489
|
+
controller.abort(error);
|
|
1490
|
+
}, context.options.timeout);
|
|
1491
|
+
context.options.signal = controller.signal;
|
|
1492
|
+
}
|
|
1493
|
+
try {
|
|
1494
|
+
context.response = await fetch(context.request, context.options);
|
|
1495
|
+
} catch (error) {
|
|
1496
|
+
context.error = error;
|
|
1497
|
+
if (context.options.onRequestError) await callHooks(context, context.options.onRequestError);
|
|
1498
|
+
return await onError(context);
|
|
1499
|
+
} finally {
|
|
1500
|
+
if (abortTimeout) clearTimeout(abortTimeout);
|
|
1501
|
+
}
|
|
1502
|
+
if ((context.response.body || context.response._bodyInit) && !nullBodyResponses.has(context.response.status) && context.options.method !== "HEAD") {
|
|
1503
|
+
const responseType = (context.options.parseResponse ? "json" : context.options.responseType) || detectResponseType(context.response.headers.get("content-type") || "");
|
|
1504
|
+
switch (responseType) {
|
|
1505
|
+
case "json": {
|
|
1506
|
+
const data = await context.response.text();
|
|
1507
|
+
const parseFunction = context.options.parseResponse || destr;
|
|
1508
|
+
context.response._data = parseFunction(data);
|
|
1509
|
+
break;
|
|
1510
|
+
}
|
|
1511
|
+
case "stream":
|
|
1512
|
+
context.response._data = context.response.body || context.response._bodyInit;
|
|
1513
|
+
break;
|
|
1514
|
+
default: context.response._data = await context.response[responseType]();
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
if (context.options.onResponse) await callHooks(context, context.options.onResponse);
|
|
1518
|
+
if (!context.options.ignoreResponseError && context.response.status >= 400 && context.response.status < 600) {
|
|
1519
|
+
if (context.options.onResponseError) await callHooks(context, context.options.onResponseError);
|
|
1520
|
+
return await onError(context);
|
|
1521
|
+
}
|
|
1522
|
+
return context.response;
|
|
1523
|
+
};
|
|
1524
|
+
const $fetch = async function $fetch2(request, options) {
|
|
1525
|
+
return (await $fetchRaw(request, options))._data;
|
|
1526
|
+
};
|
|
1527
|
+
$fetch.raw = $fetchRaw;
|
|
1528
|
+
$fetch.native = (...args) => fetch(...args);
|
|
1529
|
+
$fetch.create = (defaultOptions = {}, customGlobalOptions = {}) => createFetch({
|
|
1530
|
+
...globalOptions,
|
|
1531
|
+
...customGlobalOptions,
|
|
1532
|
+
defaults: {
|
|
1533
|
+
...globalOptions.defaults,
|
|
1534
|
+
...customGlobalOptions.defaults,
|
|
1535
|
+
...defaultOptions
|
|
1536
|
+
}
|
|
1537
|
+
});
|
|
1538
|
+
return $fetch;
|
|
782
1539
|
}
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
1540
|
+
//#endregion
|
|
1541
|
+
//#region src/shared.ts
|
|
1542
|
+
const DRIVE_CREDENTIAL_LIFETIME_SECONDS = 840;
|
|
1543
|
+
const id = /^[A-Za-z0-9_-]{1,128}$/;
|
|
1544
|
+
const email = /^[^\s@]+@[^\s@]+$/;
|
|
1545
|
+
const MAX_SOCIAL_ID_TOKEN_BYTES = 16 * 1024;
|
|
1546
|
+
function normalizeEmail(value) {
|
|
1547
|
+
if (typeof value !== "string") throw new TypeError("email is invalid");
|
|
1548
|
+
const normalized = value.trim().toLowerCase();
|
|
1549
|
+
if (normalized.length === 0 || normalized.length > 320 || !email.test(normalized)) throw new TypeError("email is invalid");
|
|
1550
|
+
return normalized;
|
|
788
1551
|
}
|
|
789
|
-
function
|
|
1552
|
+
function normalizeSocialIdTokenInput(value) {
|
|
1553
|
+
if (!isObject(value)) throw new TypeError("social ID token input is invalid");
|
|
1554
|
+
const keys = Object.keys(value);
|
|
1555
|
+
if (keys.length !== 3 && keys.length !== 4 || keys.some((key) => key !== "provider" && key !== "idToken" && key !== "nonce" && key !== "signUp") || value.provider !== "google" && value.provider !== "apple" || typeof value.signUp !== "boolean" || typeof value.idToken !== "string" || value.idToken.length < 1 || new TextEncoder().encode(value.idToken).byteLength > MAX_SOCIAL_ID_TOKEN_BYTES || !/^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/.test(value.idToken) || value.nonce !== void 0 && (typeof value.nonce !== "string" || value.nonce.length < 1 || value.nonce.length > 256 || !/^[\x20-\x7e]+$/.test(value.nonce))) throw new TypeError("social ID token input is invalid");
|
|
1556
|
+
return {
|
|
1557
|
+
provider: value.provider,
|
|
1558
|
+
idToken: value.idToken,
|
|
1559
|
+
...value.nonce === void 0 ? {} : { nonce: value.nonce },
|
|
1560
|
+
signUp: value.signUp
|
|
1561
|
+
};
|
|
1562
|
+
}
|
|
1563
|
+
function socialIdTokenRequest(value) {
|
|
1564
|
+
return {
|
|
1565
|
+
provider: value.provider,
|
|
1566
|
+
idToken: {
|
|
1567
|
+
token: value.idToken,
|
|
1568
|
+
...value.nonce === void 0 ? {} : { nonce: value.nonce }
|
|
1569
|
+
},
|
|
1570
|
+
requestSignUp: value.signUp
|
|
1571
|
+
};
|
|
1572
|
+
}
|
|
1573
|
+
function normalizeOrigin(value, name) {
|
|
1574
|
+
if (value.length === 0 || value.length > 2048 || /[^\x20-\x7e]/.test(value)) throw new TypeError(`${name} must be an ASCII HTTP origin`);
|
|
1575
|
+
let url;
|
|
1576
|
+
try {
|
|
1577
|
+
url = new URL(value);
|
|
1578
|
+
} catch {
|
|
1579
|
+
throw new TypeError(`${name} must be an ASCII HTTP origin`);
|
|
1580
|
+
}
|
|
1581
|
+
const local = url.hostname === "localhost" || url.hostname.endsWith(".localhost") || url.hostname === "127.0.0.1";
|
|
1582
|
+
if (url.protocol !== "https:" && !(local && url.protocol === "http:") || url.username || url.password || url.pathname !== "/" || url.search || url.hash || url.origin !== value) throw new TypeError(`${name} must be an ASCII HTTP origin`);
|
|
1583
|
+
return url.origin;
|
|
1584
|
+
}
|
|
1585
|
+
function normalizeTimeout(value) {
|
|
1586
|
+
const timeout = value ?? 1e4;
|
|
1587
|
+
if (!Number.isSafeInteger(timeout) || timeout < 1 || timeout > 6e4) throw new TypeError("timeoutMs must be an integer from 1 to 60000");
|
|
1588
|
+
return timeout;
|
|
1589
|
+
}
|
|
1590
|
+
function normalizeSession(value) {
|
|
790
1591
|
if (value === null) return null;
|
|
791
|
-
if (
|
|
792
|
-
|
|
1592
|
+
if (!isObject(value) || !isObject(value.session) || !isObject(value.user)) throw authorityUnavailable();
|
|
1593
|
+
const expiresAt = toDate(value.session.expiresAt);
|
|
1594
|
+
const image = value.user.image;
|
|
1595
|
+
if (!isId(value.session.id) || !expiresAt || !isId(value.user.id) || typeof value.user.name !== "string" || value.user.name.length > 256 || typeof value.user.email !== "string" || value.user.email.length > 320 || !email.test(value.user.email) || typeof value.user.emailVerified !== "boolean" || image !== null && image !== void 0 && (typeof image !== "string" || image.length > 2048)) throw authorityUnavailable();
|
|
1596
|
+
return {
|
|
1597
|
+
id: value.session.id,
|
|
1598
|
+
expiresAt,
|
|
1599
|
+
user: {
|
|
1600
|
+
id: value.user.id,
|
|
1601
|
+
name: value.user.name,
|
|
1602
|
+
email: value.user.email,
|
|
1603
|
+
emailVerified: value.user.emailVerified,
|
|
1604
|
+
image: image ?? null
|
|
1605
|
+
}
|
|
1606
|
+
};
|
|
793
1607
|
}
|
|
794
|
-
function
|
|
795
|
-
if (!
|
|
1608
|
+
function normalizeDriveCredential(value, now) {
|
|
1609
|
+
if (!isObject(value) || value.tokenType !== "Bearer" || value.expiresIn !== DRIVE_CREDENTIAL_LIFETIME_SECONDS || typeof value.token !== "string" || value.token.length === 0 || new TextEncoder().encode(`Bearer ${value.token}`).byteLength > 16 * 1024) throw authorityUnavailable();
|
|
1610
|
+
return {
|
|
1611
|
+
tokenType: "Bearer",
|
|
1612
|
+
token: value.token,
|
|
1613
|
+
expiresAt: new Date(now + value.expiresIn * 1e3)
|
|
1614
|
+
};
|
|
1615
|
+
}
|
|
1616
|
+
function normalizeOrganizationPageInput(value) {
|
|
1617
|
+
if (value === void 0) return new URLSearchParams();
|
|
1618
|
+
if (!isObject(value) || Object.keys(value).some((key) => key !== "limit" && key !== "cursor")) throw new AuthError("invalid_request", 400);
|
|
1619
|
+
const input = value;
|
|
1620
|
+
const query = new URLSearchParams();
|
|
1621
|
+
if (input.limit !== void 0) {
|
|
1622
|
+
if (!Number.isSafeInteger(input.limit) || input.limit < 1 || input.limit > 100) throw new AuthError("invalid_request", 400);
|
|
1623
|
+
query.set("limit", String(input.limit));
|
|
1624
|
+
}
|
|
1625
|
+
if (input.cursor !== void 0) {
|
|
1626
|
+
if (typeof input.cursor !== "string" || input.cursor.length < 1 || input.cursor.length > 820 || !/^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/.test(input.cursor)) throw new AuthError("invalid_request", 400);
|
|
1627
|
+
query.set("cursor", input.cursor);
|
|
1628
|
+
}
|
|
1629
|
+
return query;
|
|
1630
|
+
}
|
|
1631
|
+
function normalizeIdInput(value) {
|
|
1632
|
+
if (!isId(value)) throw new AuthError("invalid_request", 400);
|
|
796
1633
|
return value;
|
|
797
1634
|
}
|
|
798
|
-
function
|
|
799
|
-
|
|
800
|
-
|
|
1635
|
+
function normalizeOrganization(value) {
|
|
1636
|
+
exact$3(value, [
|
|
1637
|
+
"capabilities",
|
|
1638
|
+
"id",
|
|
1639
|
+
"lifecycle",
|
|
1640
|
+
"logo",
|
|
1641
|
+
"name",
|
|
1642
|
+
"role",
|
|
1643
|
+
"slug"
|
|
1644
|
+
]);
|
|
1645
|
+
if (!isId(value.id) || !boundedString(value.name, 255) || !boundedString(value.slug, 255) || value.lifecycle !== "ordinary" && value.lifecycle !== "managed" || !role(value.role) || !isObject(value.capabilities)) throw authorityUnavailable();
|
|
1646
|
+
exact$3(value.capabilities, [
|
|
1647
|
+
"readInvitations",
|
|
1648
|
+
"readMembers",
|
|
1649
|
+
"readTeams"
|
|
1650
|
+
]);
|
|
1651
|
+
if (value.capabilities.readMembers !== true || value.capabilities.readTeams !== true || typeof value.capabilities.readInvitations !== "boolean") throw authorityUnavailable();
|
|
1652
|
+
return {
|
|
1653
|
+
id: value.id,
|
|
1654
|
+
name: value.name,
|
|
1655
|
+
slug: value.slug,
|
|
1656
|
+
logo: nullableHttpsUrl(value.logo),
|
|
1657
|
+
lifecycle: value.lifecycle,
|
|
1658
|
+
role: value.role,
|
|
1659
|
+
capabilities: {
|
|
1660
|
+
readMembers: true,
|
|
1661
|
+
readTeams: true,
|
|
1662
|
+
readInvitations: value.capabilities.readInvitations
|
|
1663
|
+
}
|
|
1664
|
+
};
|
|
801
1665
|
}
|
|
802
|
-
function
|
|
803
|
-
|
|
1666
|
+
function normalizeOrganizationDisplayInput(value) {
|
|
1667
|
+
if (!isObject(value) || Object.keys(value).sort().join(",") !== "logo,name,slug") throw new AuthError("invalid_request", 400);
|
|
1668
|
+
if (!boundedString(value.name, 255) || !boundedString(value.slug, 255)) throw new AuthError("invalid_request", 400);
|
|
1669
|
+
let logo;
|
|
1670
|
+
try {
|
|
1671
|
+
logo = nullableHttpsUrl(value.logo);
|
|
1672
|
+
} catch {
|
|
1673
|
+
throw new AuthError("invalid_request", 400);
|
|
1674
|
+
}
|
|
1675
|
+
return {
|
|
1676
|
+
name: value.name,
|
|
1677
|
+
slug: value.slug,
|
|
1678
|
+
logo
|
|
1679
|
+
};
|
|
804
1680
|
}
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
1681
|
+
function normalizeOrganizationDisplay(value) {
|
|
1682
|
+
try {
|
|
1683
|
+
return normalizeOrganizationDisplayInput(value);
|
|
1684
|
+
} catch {
|
|
1685
|
+
throw authorityUnavailable();
|
|
1686
|
+
}
|
|
810
1687
|
}
|
|
811
|
-
function
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
1688
|
+
function normalizeOrganizationTeamDisplayInput(value) {
|
|
1689
|
+
if (!isObject(value) || Object.keys(value).join(",") !== "name" || !boundedString(value.name, 255)) throw new AuthError("invalid_request", 400);
|
|
1690
|
+
return { name: value.name };
|
|
1691
|
+
}
|
|
1692
|
+
function normalizeOrganizationTeamDisplay(value) {
|
|
1693
|
+
try {
|
|
1694
|
+
return normalizeOrganizationTeamDisplayInput(value);
|
|
1695
|
+
} catch {
|
|
1696
|
+
throw authorityUnavailable();
|
|
1697
|
+
}
|
|
1698
|
+
}
|
|
1699
|
+
function normalizeOrganizationCreationInput(name, slug, idempotencyKey) {
|
|
1700
|
+
if (!boundedString(name, 255) || !boundedString(idempotencyKey, 255) || typeof slug !== "string" || !/^[a-z0-9-]{1,128}$/.test(slug)) throw new AuthError("invalid_request", 400);
|
|
1701
|
+
return {
|
|
1702
|
+
name,
|
|
1703
|
+
slug,
|
|
1704
|
+
idempotencyKey
|
|
1705
|
+
};
|
|
1706
|
+
}
|
|
1707
|
+
function normalizeCreatedOrganization(value) {
|
|
1708
|
+
exact$3(value, [
|
|
1709
|
+
"id",
|
|
1710
|
+
"name",
|
|
1711
|
+
"slug"
|
|
1712
|
+
]);
|
|
1713
|
+
if (!isId(value.id) || !boundedString(value.name, 255) || !boundedString(value.slug, 128)) throw authorityUnavailable();
|
|
1714
|
+
return {
|
|
1715
|
+
id: value.id,
|
|
1716
|
+
name: value.name,
|
|
1717
|
+
slug: value.slug
|
|
1718
|
+
};
|
|
1719
|
+
}
|
|
1720
|
+
function normalizeOrganizationTeamCreationInput(name, idempotencyKey) {
|
|
1721
|
+
if (!boundedString(name, 255) || !boundedString(idempotencyKey, 255)) throw new AuthError("invalid_request", 400);
|
|
1722
|
+
return {
|
|
1723
|
+
name,
|
|
1724
|
+
idempotencyKey
|
|
1725
|
+
};
|
|
1726
|
+
}
|
|
1727
|
+
function normalizeCreatedOrganizationTeam(value) {
|
|
1728
|
+
exact$3(value, ["id", "name"]);
|
|
1729
|
+
if (!isId(value.id) || !boundedString(value.name, 255)) throw authorityUnavailable();
|
|
1730
|
+
return {
|
|
1731
|
+
id: value.id,
|
|
1732
|
+
name: value.name
|
|
1733
|
+
};
|
|
1734
|
+
}
|
|
1735
|
+
function normalizeOrganizationMemberInvitationCreationInput(value) {
|
|
1736
|
+
if (!isObject(value)) throw new AuthError("invalid_request", 400);
|
|
1737
|
+
const keys = Object.keys(value).sort().join(",");
|
|
1738
|
+
if (keys !== "email,idempotencyKey" && keys !== "email,idempotencyKey,teamIds") throw new AuthError("invalid_request", 400);
|
|
1739
|
+
let normalizedEmail;
|
|
1740
|
+
try {
|
|
1741
|
+
normalizedEmail = normalizeEmail(value.email);
|
|
1742
|
+
} catch {
|
|
1743
|
+
throw new AuthError("invalid_request", 400);
|
|
1744
|
+
}
|
|
1745
|
+
if (new TextEncoder().encode(normalizedEmail).byteLength > 320 || !boundedString(value.idempotencyKey, 255) || value.teamIds !== void 0 && (!Array.isArray(value.teamIds) || value.teamIds.length > 100)) throw new AuthError("invalid_request", 400);
|
|
1746
|
+
const teamIds = value.teamIds?.map((teamId) => normalizeIdInput(teamId));
|
|
1747
|
+
if (teamIds && new Set(teamIds).size !== teamIds.length) throw new AuthError("invalid_request", 400);
|
|
1748
|
+
return {
|
|
1749
|
+
email: normalizedEmail,
|
|
1750
|
+
...teamIds === void 0 ? {} : { teamIds },
|
|
1751
|
+
idempotencyKey: value.idempotencyKey
|
|
1752
|
+
};
|
|
1753
|
+
}
|
|
1754
|
+
function normalizeCreatedOrganizationMemberInvitation(value) {
|
|
1755
|
+
exact$3(value, ["expiresAt", "id"]);
|
|
1756
|
+
if (!isId(value.id)) throw authorityUnavailable();
|
|
1757
|
+
return {
|
|
1758
|
+
id: value.id,
|
|
1759
|
+
expiresAt: responseDate(value.expiresAt)
|
|
1760
|
+
};
|
|
1761
|
+
}
|
|
1762
|
+
function normalizeResentOrganizationInvitation(value, invitationId) {
|
|
1763
|
+
const invitation = normalizeCreatedOrganizationMemberInvitation(value);
|
|
1764
|
+
if (invitation.id !== invitationId) throw authorityUnavailable();
|
|
1765
|
+
return invitation;
|
|
1766
|
+
}
|
|
1767
|
+
function normalizeOrganizationInvitationAdministrationInput(idempotencyKey) {
|
|
1768
|
+
if (!boundedString(idempotencyKey, 255)) throw new AuthError("invalid_request", 400);
|
|
1769
|
+
return { idempotencyKey };
|
|
1770
|
+
}
|
|
1771
|
+
function normalizeCanceledOrganizationInvitation(value) {
|
|
1772
|
+
exact$3(value, ["status"]);
|
|
1773
|
+
if (value.status !== "canceled") throw authorityUnavailable();
|
|
1774
|
+
return { status: "canceled" };
|
|
1775
|
+
}
|
|
1776
|
+
function normalizeOrganizationMembershipRemovalInput(idempotencyKey) {
|
|
1777
|
+
if (!boundedString(idempotencyKey, 255)) throw new AuthError("invalid_request", 400);
|
|
1778
|
+
return { idempotencyKey };
|
|
1779
|
+
}
|
|
1780
|
+
function normalizeRemovedOrganizationMember(value) {
|
|
1781
|
+
exact$3(value, ["status"]);
|
|
1782
|
+
if (value.status !== "removed") throw authorityUnavailable();
|
|
1783
|
+
return { status: "removed" };
|
|
1784
|
+
}
|
|
1785
|
+
function normalizeOrganizationDeparture(value) {
|
|
1786
|
+
exact$3(value, ["status"]);
|
|
1787
|
+
if (value.status !== "left") throw authorityUnavailable();
|
|
1788
|
+
return { status: "left" };
|
|
1789
|
+
}
|
|
1790
|
+
function normalizeOrganizations(value) {
|
|
1791
|
+
exact$3(value, ["nextCursor", "organizations"]);
|
|
1792
|
+
if (!Array.isArray(value.organizations) || value.organizations.length > 100) throw authorityUnavailable();
|
|
1793
|
+
return {
|
|
1794
|
+
organizations: unique(value.organizations.map(normalizeOrganization), (item) => item.id),
|
|
1795
|
+
nextCursor: nullableCursor(value.nextCursor)
|
|
1796
|
+
};
|
|
1797
|
+
}
|
|
1798
|
+
function normalizeOrganizationMembers(value) {
|
|
1799
|
+
exact$3(value, ["members", "nextCursor"]);
|
|
1800
|
+
if (!Array.isArray(value.members) || value.members.length > 100) throw authorityUnavailable();
|
|
1801
|
+
return {
|
|
1802
|
+
members: unique(value.members.map((member) => {
|
|
1803
|
+
exact$3(member, [
|
|
1804
|
+
"email",
|
|
1805
|
+
"id",
|
|
1806
|
+
"image",
|
|
1807
|
+
"joinedAt",
|
|
1808
|
+
"name",
|
|
1809
|
+
"owner",
|
|
1810
|
+
"role",
|
|
1811
|
+
"teamIds",
|
|
1812
|
+
"userId"
|
|
1813
|
+
]);
|
|
1814
|
+
if (!isId(member.id) || !isId(member.userId) || !boundedString(member.name, 255) || typeof member.email !== "string" || member.email.length > 320 || !email.test(member.email) || !role(member.role) || typeof member.owner !== "boolean" || !Array.isArray(member.teamIds) || member.teamIds.length > 100) throw authorityUnavailable();
|
|
1815
|
+
const teamIds = unique(member.teamIds.map((teamId) => normalizeResponseId(teamId)), (item) => item);
|
|
1816
|
+
return {
|
|
1817
|
+
id: member.id,
|
|
1818
|
+
userId: member.userId,
|
|
1819
|
+
name: member.name,
|
|
1820
|
+
email: member.email,
|
|
1821
|
+
image: nullableHttpsUrl(member.image),
|
|
1822
|
+
role: member.role,
|
|
1823
|
+
owner: member.owner,
|
|
1824
|
+
joinedAt: responseDate(member.joinedAt),
|
|
1825
|
+
teamIds
|
|
883
1826
|
};
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
} catch (error) {
|
|
888
|
-
if (mappedError && mappedError === error) throw mappedError;
|
|
889
|
-
throw authorityUnavailable();
|
|
890
|
-
} finally {
|
|
891
|
-
clearTimeout(timer);
|
|
892
|
-
controller.abort();
|
|
893
|
-
reader?.cancel().catch(() => {});
|
|
894
|
-
}
|
|
895
|
-
} };
|
|
1827
|
+
}), (item) => item.id),
|
|
1828
|
+
nextCursor: nullableCursor(value.nextCursor)
|
|
1829
|
+
};
|
|
896
1830
|
}
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
1831
|
+
function normalizeOrganizationTeams(value) {
|
|
1832
|
+
exact$3(value, ["nextCursor", "teams"]);
|
|
1833
|
+
if (!Array.isArray(value.teams) || value.teams.length > 100) throw authorityUnavailable();
|
|
1834
|
+
return {
|
|
1835
|
+
teams: unique(value.teams.map((team) => {
|
|
1836
|
+
exact$3(team, [
|
|
1837
|
+
"category",
|
|
1838
|
+
"createdAt",
|
|
1839
|
+
"id",
|
|
1840
|
+
"name"
|
|
1841
|
+
]);
|
|
1842
|
+
if (!isId(team.id) || !boundedString(team.name, 255) || team.category !== "manual" && team.category !== "managed") throw authorityUnavailable();
|
|
1843
|
+
return {
|
|
1844
|
+
id: team.id,
|
|
1845
|
+
name: team.name,
|
|
1846
|
+
category: team.category,
|
|
1847
|
+
createdAt: responseDate(team.createdAt)
|
|
1848
|
+
};
|
|
1849
|
+
}), (item) => item.id),
|
|
1850
|
+
nextCursor: nullableCursor(value.nextCursor)
|
|
1851
|
+
};
|
|
903
1852
|
}
|
|
904
|
-
function
|
|
905
|
-
|
|
1853
|
+
function normalizeOrganizationTeamMembers(value) {
|
|
1854
|
+
exact$3(value, ["memberIds", "nextCursor"]);
|
|
1855
|
+
if (!Array.isArray(value.memberIds) || value.memberIds.length > 100) throw authorityUnavailable();
|
|
1856
|
+
return {
|
|
1857
|
+
memberIds: unique(value.memberIds.map((item) => normalizeResponseId(item)), (item) => item),
|
|
1858
|
+
nextCursor: nullableCursor(value.nextCursor)
|
|
1859
|
+
};
|
|
906
1860
|
}
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
"
|
|
910
|
-
"
|
|
911
|
-
"
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
"
|
|
915
|
-
"
|
|
916
|
-
"
|
|
917
|
-
]
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
}, timeoutMs);
|
|
976
|
-
});
|
|
977
|
-
const exchange = async () => {
|
|
978
|
-
const response = await fetchImpl(url, {
|
|
979
|
-
method: "POST",
|
|
980
|
-
headers: {
|
|
981
|
-
authorization: `Bearer ${clientAssertion}`,
|
|
982
|
-
accept: "application/json",
|
|
983
|
-
"content-type": "application/json"
|
|
984
|
-
},
|
|
985
|
-
body,
|
|
986
|
-
credentials: "omit",
|
|
987
|
-
cache: "no-store",
|
|
988
|
-
redirect: "manual",
|
|
989
|
-
signal: controller.signal
|
|
990
|
-
});
|
|
991
|
-
if (controller.signal.aborted) {
|
|
992
|
-
response.body?.cancel().catch(() => {});
|
|
993
|
-
throw authorityUnavailable();
|
|
994
|
-
}
|
|
995
|
-
if (!response.body) throw authorityUnavailable();
|
|
996
|
-
reader = response.body.getReader();
|
|
997
|
-
const contentType = response.headers.get("content-type")?.split(";", 1)[0]?.trim().toLowerCase();
|
|
998
|
-
const length = response.headers.get("content-length");
|
|
999
|
-
if (response.redirected || contentType !== "application/json" || length !== null && (!/^\d+$/.test(length) || Number(length) > 4096)) throw authorityUnavailable();
|
|
1000
|
-
const bytes = new Uint8Array(4096);
|
|
1001
|
-
let size = 0;
|
|
1002
|
-
while (true) {
|
|
1003
|
-
const chunk = await reader.read();
|
|
1004
|
-
if (controller.signal.aborted) throw authorityUnavailable();
|
|
1005
|
-
if (chunk.done) break;
|
|
1006
|
-
if (size + chunk.value.byteLength > bytes.byteLength) throw authorityUnavailable();
|
|
1007
|
-
bytes.set(chunk.value, size);
|
|
1008
|
-
size += chunk.value.byteLength;
|
|
1009
|
-
}
|
|
1010
|
-
const value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(0, size)));
|
|
1011
|
-
if (response.status !== 200) {
|
|
1012
|
-
const status = response.status;
|
|
1013
|
-
const failure = failures[status];
|
|
1014
|
-
if (!failure || !exact(value, ["code", "message"]) || value.code !== failure[0] || value.message !== failure[1]) throw authorityUnavailable();
|
|
1015
|
-
let retryAfterSeconds;
|
|
1016
|
-
if (status === 429) {
|
|
1017
|
-
const retryAfter = response.headers.get("retry-after");
|
|
1018
|
-
if (retryAfter === null || !/^(?:[1-9]|[1-5][0-9]|60)$/.test(retryAfter)) throw authorityUnavailable();
|
|
1019
|
-
retryAfterSeconds = Number(retryAfter);
|
|
1020
|
-
}
|
|
1021
|
-
authorityError = new AuthError(failure[2], status, retryAfterSeconds);
|
|
1022
|
-
throw authorityError;
|
|
1023
|
-
}
|
|
1024
|
-
if (!exact(value, ["recipient"]) || !exact(value.recipient, [
|
|
1025
|
-
"userId",
|
|
1026
|
-
"name",
|
|
1027
|
-
"email"
|
|
1028
|
-
])) throw authorityUnavailable();
|
|
1029
|
-
const recipient = value.recipient;
|
|
1030
|
-
if (typeof recipient.userId !== "string" || !/^[A-Za-z0-9_-]{1,128}$(?![\s\S])/.test(recipient.userId) || typeof recipient.name !== "string" || recipient.name.length === 0 || encoder.encode(recipient.name).byteLength > 1024 || !validEmail(recipient.email) || recipient.email !== recipient.email.trim().toLowerCase() || recipient.email !== email) throw authorityUnavailable();
|
|
1031
|
-
return {
|
|
1032
|
-
userId: recipient.userId,
|
|
1033
|
-
name: recipient.name,
|
|
1034
|
-
email: recipient.email
|
|
1035
|
-
};
|
|
1861
|
+
function normalizeOrganizationInvitation(value) {
|
|
1862
|
+
exact$3(value, [
|
|
1863
|
+
"createdAt",
|
|
1864
|
+
"email",
|
|
1865
|
+
"expiresAt",
|
|
1866
|
+
"id",
|
|
1867
|
+
"inviter",
|
|
1868
|
+
"role",
|
|
1869
|
+
"status",
|
|
1870
|
+
"teamIds"
|
|
1871
|
+
]);
|
|
1872
|
+
if (!isId(value.id) || typeof value.email !== "string" || value.email.length > 320 || !email.test(value.email) || !role(value.role) || value.status !== "pending" || !Array.isArray(value.teamIds) || value.teamIds.length > 100 || !isObject(value.inviter)) throw authorityUnavailable();
|
|
1873
|
+
exact$3(value.inviter, ["membershipId", "name"]);
|
|
1874
|
+
if (!isId(value.inviter.membershipId) || !boundedString(value.inviter.name, 255)) throw authorityUnavailable();
|
|
1875
|
+
return {
|
|
1876
|
+
id: value.id,
|
|
1877
|
+
email: value.email,
|
|
1878
|
+
role: value.role,
|
|
1879
|
+
teamIds: unique(value.teamIds.map(normalizeResponseId), (item) => item),
|
|
1880
|
+
inviter: {
|
|
1881
|
+
membershipId: value.inviter.membershipId,
|
|
1882
|
+
name: value.inviter.name
|
|
1883
|
+
},
|
|
1884
|
+
createdAt: responseDate(value.createdAt),
|
|
1885
|
+
expiresAt: responseDate(value.expiresAt),
|
|
1886
|
+
status: "pending"
|
|
1887
|
+
};
|
|
1888
|
+
}
|
|
1889
|
+
function normalizeOrganizationInvitations(value) {
|
|
1890
|
+
exact$3(value, ["invitations", "nextCursor"]);
|
|
1891
|
+
if (!Array.isArray(value.invitations) || value.invitations.length > 100) throw authorityUnavailable();
|
|
1892
|
+
return {
|
|
1893
|
+
invitations: unique(value.invitations.map(normalizeOrganizationInvitation), (item) => item.id),
|
|
1894
|
+
nextCursor: nullableCursor(value.nextCursor)
|
|
1895
|
+
};
|
|
1896
|
+
}
|
|
1897
|
+
function normalizeReceivedInvitation(value) {
|
|
1898
|
+
exact$3(value, [
|
|
1899
|
+
"expiresAt",
|
|
1900
|
+
"id",
|
|
1901
|
+
"inviterName",
|
|
1902
|
+
"organization",
|
|
1903
|
+
"role",
|
|
1904
|
+
"teams"
|
|
1905
|
+
]);
|
|
1906
|
+
if (!isId(value.id) || !boundedString(value.inviterName, 255) || !role(value.role) || !Array.isArray(value.teams) || value.teams.length > 100 || !isObject(value.organization)) throw authorityUnavailable();
|
|
1907
|
+
exact$3(value.organization, [
|
|
1908
|
+
"id",
|
|
1909
|
+
"logo",
|
|
1910
|
+
"name",
|
|
1911
|
+
"slug"
|
|
1912
|
+
]);
|
|
1913
|
+
if (!isId(value.organization.id) || !boundedString(value.organization.name, 255) || !boundedString(value.organization.slug, 255)) throw authorityUnavailable();
|
|
1914
|
+
return {
|
|
1915
|
+
id: value.id,
|
|
1916
|
+
organization: {
|
|
1917
|
+
id: value.organization.id,
|
|
1918
|
+
name: value.organization.name,
|
|
1919
|
+
slug: value.organization.slug,
|
|
1920
|
+
logo: nullableHttpsUrl(value.organization.logo)
|
|
1921
|
+
},
|
|
1922
|
+
role: value.role,
|
|
1923
|
+
teams: unique(value.teams.map((team) => {
|
|
1924
|
+
exact$3(team, ["id", "name"]);
|
|
1925
|
+
if (!isId(team.id) || !boundedString(team.name, 255)) throw authorityUnavailable();
|
|
1926
|
+
return {
|
|
1927
|
+
id: team.id,
|
|
1928
|
+
name: team.name
|
|
1036
1929
|
};
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
}
|
|
1930
|
+
}), (item) => item.id),
|
|
1931
|
+
inviterName: value.inviterName,
|
|
1932
|
+
expiresAt: responseDate(value.expiresAt)
|
|
1933
|
+
};
|
|
1934
|
+
}
|
|
1935
|
+
function normalizeReceivedInvitations(value) {
|
|
1936
|
+
exact$3(value, ["invitations", "nextCursor"]);
|
|
1937
|
+
if (!Array.isArray(value.invitations) || value.invitations.length > 100) throw authorityUnavailable();
|
|
1938
|
+
return {
|
|
1939
|
+
invitations: unique(value.invitations.map(normalizeReceivedInvitation), (item) => item.id),
|
|
1940
|
+
nextCursor: nullableCursor(value.nextCursor)
|
|
1941
|
+
};
|
|
1942
|
+
}
|
|
1943
|
+
function normalizeInvitationInput(value) {
|
|
1944
|
+
if (!isObject(value) || Object.keys(value).length !== 1 || !isId(value.invitationId)) throw new AuthError("invalid_invitation", 422);
|
|
1945
|
+
return { invitationId: value.invitationId };
|
|
1946
|
+
}
|
|
1947
|
+
function normalizeInvitationAcceptance(value, invitationId) {
|
|
1948
|
+
if (!isObject(value) || !isObject(value.invitation) || !isObject(value.member) || value.invitation.id !== invitationId || value.invitation.status !== "accepted" || !isId(value.invitation.organizationId) || value.member.organizationId !== value.invitation.organizationId) throw authorityUnavailable();
|
|
1949
|
+
return { organizationId: value.invitation.organizationId };
|
|
1950
|
+
}
|
|
1951
|
+
function normalizeWorkspaceSelection(value) {
|
|
1952
|
+
if (!isObject(value)) throw new AuthError("invalid_workspace_selection", 422);
|
|
1953
|
+
const keys = Object.keys(value);
|
|
1954
|
+
if (value.type === "personal" && keys.length === 1 && keys[0] === "type") return { type: "personal" };
|
|
1955
|
+
if (value.type === "organization" && keys.length === 2 && keys.includes("type") && keys.includes("organizationId") && typeof value.organizationId === "string" && id.test(value.organizationId)) return {
|
|
1956
|
+
type: "organization",
|
|
1957
|
+
organizationId: value.organizationId
|
|
1958
|
+
};
|
|
1959
|
+
throw new AuthError("invalid_workspace_selection", 422);
|
|
1960
|
+
}
|
|
1961
|
+
function fromAuthorityError(value, fallbackStatus, retryAfter) {
|
|
1962
|
+
const mapped = mapError(isObject(value) && typeof value.code === "string" ? value.code : void 0, fallbackStatus);
|
|
1963
|
+
return new AuthError(mapped.code, mapped.status, parseRetryAfter(retryAfter));
|
|
1964
|
+
}
|
|
1965
|
+
function fromAccountAuthorityError(value, status, retryAfter) {
|
|
1966
|
+
const code = isObject(value) && typeof value.code === "string" ? value.code : void 0;
|
|
1967
|
+
if (status === 403 && (code === "INVALID_ORIGIN" || code === "MISSING_OR_NULL_ORIGIN")) return new AuthError("request_origin_denied", 403);
|
|
1968
|
+
if (code === "USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL") return new AuthError("account_conflict", 409);
|
|
1969
|
+
if (code === "INVALID_TOKEN") return new AuthError("password_reset_invalid", 422);
|
|
1970
|
+
if (code === "INVALID_PASSWORD" || code === "INVALID_EMAIL_OR_PASSWORD") return new AuthError("invalid_credentials", 401);
|
|
1971
|
+
if (code === "INVALID_EMAIL" || code === "PASSWORD_TOO_SHORT" || code === "PASSWORD_TOO_LONG" || code === "BODY_MUST_BE_AN_OBJECT" || code === "EMAIL_CAN_NOT_BE_UPDATED") return new AuthError("invalid_auth_input", 422);
|
|
1972
|
+
if (status === 401) return new AuthError("authentication_required", 401);
|
|
1973
|
+
if (status === 403) return new AuthError("access_denied", 403);
|
|
1974
|
+
if (status === 409) return new AuthError("state_conflict", 409);
|
|
1975
|
+
if (status === 429) return new AuthError("auth_request_rate_limited", 429, parseRetryAfter(retryAfter));
|
|
1976
|
+
if (status === 400 || status === 422) return new AuthError("invalid_auth_input", 422);
|
|
1977
|
+
return authorityUnavailable();
|
|
1978
|
+
}
|
|
1979
|
+
function fromSocialIdTokenAuthorityError(value, status, retryAfter) {
|
|
1980
|
+
const code = isObject(value) && typeof value.code === "string" ? value.code : void 0;
|
|
1981
|
+
if (code === "INVALID_TOKEN" || code === "FAILED_TO_GET_USER_INFO" || code === "USER_EMAIL_NOT_FOUND") return new AuthError("invalid_credentials", 401);
|
|
1982
|
+
if (code === "OAUTH_LINK_ERROR") return new AuthError("account_conflict", 409);
|
|
1983
|
+
return fromAccountAuthorityError(value, status, retryAfter);
|
|
1984
|
+
}
|
|
1985
|
+
function authorityUnavailable() {
|
|
1986
|
+
return new AuthError("identity_authority_unavailable", 503);
|
|
1987
|
+
}
|
|
1988
|
+
function fromOrganizationListError(error) {
|
|
1989
|
+
if (error instanceof AuthError && error.status === 401) return new AuthError("authentication_required", 401);
|
|
1990
|
+
if (error instanceof AuthError) return error;
|
|
1991
|
+
return authorityUnavailable();
|
|
1992
|
+
}
|
|
1993
|
+
function fromOrganizationReadAuthorityError(value, status) {
|
|
1994
|
+
if (status === 400) return new AuthError("invalid_request", 400);
|
|
1995
|
+
if (status === 401) return new AuthError("authentication_required", 401);
|
|
1996
|
+
if (status === 403) return new AuthError("access_denied", 403);
|
|
1997
|
+
return authorityUnavailable();
|
|
1998
|
+
}
|
|
1999
|
+
function fromOrganizationMutationAuthorityError(value, status, retryAfter) {
|
|
2000
|
+
if (status === 400 || status === 413 || status === 415) return new AuthError("invalid_request", 400);
|
|
2001
|
+
if (status === 409) return new AuthError("state_conflict", 409);
|
|
2002
|
+
if (status === 429) return new AuthError("auth_request_rate_limited", 429, parseRetryAfter(retryAfter));
|
|
2003
|
+
const code = isObject(value) && typeof value.code === "string" ? value.code : void 0;
|
|
2004
|
+
if (status === 403 && code === "REQUEST_ORIGIN_DENIED") return new AuthError("request_origin_denied", 403);
|
|
2005
|
+
return fromOrganizationReadAuthorityError(value, status);
|
|
2006
|
+
}
|
|
2007
|
+
function fromOrganizationInvitationAdministrationError(value, status, retryAfter) {
|
|
2008
|
+
if (status === 422 && isObject(value) && value.code === "RECOVERY_REQUIRED") return new AuthError("invitation_recovery_required", 422);
|
|
2009
|
+
return fromOrganizationMutationAuthorityError(value, status, retryAfter);
|
|
2010
|
+
}
|
|
2011
|
+
function fromOrganizationMembershipRemovalError(value, status, retryAfter) {
|
|
2012
|
+
if (status === 422 && isObject(value) && value.code === "RECOVERY_REQUIRED") return new AuthError("membership_removal_recovery_required", 422);
|
|
2013
|
+
return fromOrganizationMutationAuthorityError(value, status, retryAfter);
|
|
2014
|
+
}
|
|
2015
|
+
function normalizeOrganizationMemberAuthority(value, organizationId, memberId) {
|
|
2016
|
+
exact$3(value, [
|
|
2017
|
+
"organizationId",
|
|
2018
|
+
"actor",
|
|
2019
|
+
"target"
|
|
2020
|
+
]);
|
|
2021
|
+
if (!isId(value.organizationId) || value.organizationId !== organizationId) throw authorityUnavailable();
|
|
2022
|
+
const actor = normalizeOrganizationAuthorityMemberOutcome(value.actor);
|
|
2023
|
+
const target = normalizeOrganizationAuthorityMemberOutcome(value.target);
|
|
2024
|
+
if (target.memberId !== memberId || actor.manualRole !== "owner" && actor.manualRole !== "admin") throw authorityUnavailable();
|
|
2025
|
+
for (const member of [actor, target]) if (member.manualRole === "member" ? member.role === "owner" : member.role !== member.manualRole) throw authorityUnavailable();
|
|
2026
|
+
if (actor.memberId === target.memberId && (actor.manualRole !== target.manualRole || actor.role !== target.role || actor.authorityRevision !== target.authorityRevision)) throw authorityUnavailable();
|
|
2027
|
+
return {
|
|
2028
|
+
organizationId: value.organizationId,
|
|
2029
|
+
actor,
|
|
2030
|
+
target
|
|
2031
|
+
};
|
|
2032
|
+
}
|
|
2033
|
+
function normalizeOrganizationAuthorityMemberOutcome(value, includesStatus = false) {
|
|
2034
|
+
exact$3(value, [
|
|
2035
|
+
"memberId",
|
|
2036
|
+
"manualRole",
|
|
2037
|
+
"role",
|
|
2038
|
+
"authorityRevision",
|
|
2039
|
+
...includesStatus ? ["status"] : []
|
|
2040
|
+
]);
|
|
2041
|
+
if (!isId(value.memberId) || value.manualRole !== "owner" && value.manualRole !== "admin" && value.manualRole !== "member" || value.role !== "owner" && value.role !== "admin" && value.role !== "member") throw authorityUnavailable();
|
|
2042
|
+
return {
|
|
2043
|
+
memberId: value.memberId,
|
|
2044
|
+
manualRole: value.manualRole,
|
|
2045
|
+
role: value.role,
|
|
2046
|
+
authorityRevision: normalizeAuthorityResultRevision(value.authorityRevision)
|
|
2047
|
+
};
|
|
2048
|
+
}
|
|
2049
|
+
function normalizeAuthorityResultRevision(value) {
|
|
2050
|
+
if (!Number.isSafeInteger(value) || value < 0 || value >= Number.MAX_SAFE_INTEGER) throw authorityUnavailable();
|
|
2051
|
+
return value;
|
|
2052
|
+
}
|
|
2053
|
+
function fromInvitationAuthorityError(value, status) {
|
|
2054
|
+
const code = isObject(value) && typeof value.code === "string" ? value.code : void 0;
|
|
2055
|
+
if (status === 401 && code === "UNAUTHORIZED") return new AuthError("authentication_required", 401);
|
|
2056
|
+
if (status === 403 && (code === "INVALID_ORIGIN" || code === "MISSING_OR_NULL_ORIGIN")) return new AuthError("request_origin_denied", 403);
|
|
2057
|
+
if (status === 403 && code === "YOU_ARE_NOT_THE_RECIPIENT_OF_THE_INVITATION") return new AuthError("invitation_recipient_mismatch", 403);
|
|
2058
|
+
if (status === 403 && code === "EMAIL_VERIFICATION_REQUIRED_BEFORE_ACCEPTING_OR_REJECTING_INVITATION") return new AuthError("email_verification_required", 403);
|
|
2059
|
+
if (status === 400 && (code === "INVITATION_NOT_FOUND" || code === "ORGANIZATION_NOT_FOUND" || code === "TEAM_NOT_FOUND")) return new AuthError("invitation_unavailable", 409);
|
|
2060
|
+
return authorityUnavailable();
|
|
2061
|
+
}
|
|
2062
|
+
function fromInvitationError(error) {
|
|
2063
|
+
return error instanceof AuthError ? error : authorityUnavailable();
|
|
2064
|
+
}
|
|
2065
|
+
function mapError(code, status) {
|
|
2066
|
+
if (code === "authentication_required") return {
|
|
2067
|
+
code,
|
|
2068
|
+
status: 401
|
|
2069
|
+
};
|
|
2070
|
+
if (code === "request_origin_denied") return {
|
|
2071
|
+
code,
|
|
2072
|
+
status: 403
|
|
2073
|
+
};
|
|
2074
|
+
if (code === "invalid_workspace_selection") return {
|
|
2075
|
+
code,
|
|
2076
|
+
status: 422
|
|
2077
|
+
};
|
|
2078
|
+
if (code === "organization_context_too_large") return {
|
|
2079
|
+
code,
|
|
2080
|
+
status: 422
|
|
2081
|
+
};
|
|
2082
|
+
if (code === "credential_rate_limited") return {
|
|
2083
|
+
code,
|
|
2084
|
+
status: 429
|
|
2085
|
+
};
|
|
2086
|
+
if (code === "identity_authority_unavailable") return {
|
|
2087
|
+
code,
|
|
2088
|
+
status: 503
|
|
2089
|
+
};
|
|
2090
|
+
if (status === 401 || status === 400) return {
|
|
2091
|
+
code: "invalid_credentials",
|
|
2092
|
+
status: 401
|
|
2093
|
+
};
|
|
2094
|
+
if (status === 403) return {
|
|
2095
|
+
code: "access_denied",
|
|
2096
|
+
status: 403
|
|
2097
|
+
};
|
|
2098
|
+
if (status === 409) return {
|
|
2099
|
+
code: "state_conflict",
|
|
2100
|
+
status: 409
|
|
2101
|
+
};
|
|
2102
|
+
if (status === 422) return {
|
|
2103
|
+
code: "invalid_workspace_selection",
|
|
2104
|
+
status: 422
|
|
2105
|
+
};
|
|
2106
|
+
if (status === 429) return {
|
|
2107
|
+
code: "credential_rate_limited",
|
|
2108
|
+
status: 429
|
|
2109
|
+
};
|
|
2110
|
+
return {
|
|
2111
|
+
code: "identity_authority_unavailable",
|
|
2112
|
+
status: 503
|
|
2113
|
+
};
|
|
1049
2114
|
}
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
const
|
|
1053
|
-
|
|
1054
|
-
function isCompactCredential(value) {
|
|
1055
|
-
return typeof value === "string" && value.length + 7 <= MAX_BYTES && compactJwt.test(value);
|
|
2115
|
+
function parseRetryAfter(value) {
|
|
2116
|
+
if (!value || !/^\d+$/.test(value)) return void 0;
|
|
2117
|
+
const seconds = Number(value);
|
|
2118
|
+
return Number.isSafeInteger(seconds) && seconds >= 1 && seconds <= 3600 ? seconds : void 0;
|
|
1056
2119
|
}
|
|
1057
|
-
function
|
|
1058
|
-
const
|
|
1059
|
-
|
|
1060
|
-
if (typeof fetchImpl !== "function") throw new TypeError("fetch is required");
|
|
1061
|
-
const timeoutMs = normalizeTimeout(options.timeoutMs);
|
|
1062
|
-
const now = options.now ?? Date.now;
|
|
1063
|
-
let inFlight = false;
|
|
1064
|
-
return { async getDriveProvisioningCredential(clientAssertion) {
|
|
1065
|
-
if (!isCompactCredential(clientAssertion)) throw new AuthError("invalid_request", 400);
|
|
1066
|
-
if (inFlight) throw new AuthError("state_conflict", 409);
|
|
1067
|
-
inFlight = true;
|
|
1068
|
-
const controller = new AbortController();
|
|
1069
|
-
let reader;
|
|
1070
|
-
let timer;
|
|
1071
|
-
let exchangeStarted = false;
|
|
1072
|
-
let authorityError;
|
|
1073
|
-
try {
|
|
1074
|
-
const startedAt = now();
|
|
1075
|
-
if (!Number.isSafeInteger(startedAt) || startedAt < 0 || startedAt > 86399999997e5) throw authorityUnavailable();
|
|
1076
|
-
const deadline = new Promise((_, reject) => {
|
|
1077
|
-
timer = setTimeout(() => {
|
|
1078
|
-
reject(authorityUnavailable());
|
|
1079
|
-
controller.abort();
|
|
1080
|
-
reader?.cancel().catch(() => {});
|
|
1081
|
-
}, timeoutMs);
|
|
1082
|
-
});
|
|
1083
|
-
const exchange = async () => {
|
|
1084
|
-
const response = await fetchImpl(url, {
|
|
1085
|
-
method: "POST",
|
|
1086
|
-
headers: {
|
|
1087
|
-
authorization: `Bearer ${clientAssertion}`,
|
|
1088
|
-
accept: "application/json"
|
|
1089
|
-
},
|
|
1090
|
-
credentials: "omit",
|
|
1091
|
-
cache: "no-store",
|
|
1092
|
-
redirect: "manual",
|
|
1093
|
-
signal: controller.signal
|
|
1094
|
-
});
|
|
1095
|
-
if (controller.signal.aborted) {
|
|
1096
|
-
response.body?.cancel().catch(() => {});
|
|
1097
|
-
throw authorityUnavailable();
|
|
1098
|
-
}
|
|
1099
|
-
if (!response.body) throw authorityUnavailable();
|
|
1100
|
-
reader = response.body.getReader();
|
|
1101
|
-
const contentType = response.headers.get("content-type")?.split(";", 1)[0]?.trim().toLowerCase();
|
|
1102
|
-
const length = response.headers.get("content-length");
|
|
1103
|
-
if (contentType !== "application/json" || length !== null && (!/^\d+$/.test(length) || Number(length) > MAX_BYTES)) throw authorityUnavailable();
|
|
1104
|
-
const bytes = new Uint8Array(MAX_BYTES);
|
|
1105
|
-
let size = 0;
|
|
1106
|
-
while (true) {
|
|
1107
|
-
const chunk = await reader.read();
|
|
1108
|
-
if (chunk.done) break;
|
|
1109
|
-
if (controller.signal.aborted || size + chunk.value.byteLength > MAX_BYTES) throw authorityUnavailable();
|
|
1110
|
-
bytes.set(chunk.value, size);
|
|
1111
|
-
size += chunk.value.byteLength;
|
|
1112
|
-
}
|
|
1113
|
-
const value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(0, size)));
|
|
1114
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) throw authorityUnavailable();
|
|
1115
|
-
const record = value;
|
|
1116
|
-
if (response.status !== 200) {
|
|
1117
|
-
if (Object.keys(record).length !== 2 || !("code" in record) || !("message" in record)) throw authorityUnavailable();
|
|
1118
|
-
if (response.status === 401 && record.code === "UNAUTHORIZED" && record.message === "The ecosystem client assertion is invalid.") {
|
|
1119
|
-
authorityError = new AuthError("authentication_required", 401);
|
|
1120
|
-
throw authorityError;
|
|
1121
|
-
}
|
|
1122
|
-
const retryAfter = response.headers.get("retry-after");
|
|
1123
|
-
if (response.status === 429 && record.code === "TOO_MANY_REQUESTS" && record.message === "Ecosystem credential exchanges are temporarily limited." && retryAfter !== null && /^(?:[1-9]|[1-5][0-9]|60)$/.test(retryAfter)) {
|
|
1124
|
-
authorityError = new AuthError("auth_request_rate_limited", 429, Number(retryAfter));
|
|
1125
|
-
throw authorityError;
|
|
1126
|
-
}
|
|
1127
|
-
throw authorityUnavailable();
|
|
1128
|
-
}
|
|
1129
|
-
if (Object.keys(record).length !== 3 || record.tokenType !== "Bearer" || record.expiresIn !== 300 || !isCompactCredential(record.token)) throw authorityUnavailable();
|
|
1130
|
-
const expiresAt = new Date(Math.floor(startedAt / 1e3) * 1e3 + 3e5);
|
|
1131
|
-
const completedAt = now();
|
|
1132
|
-
if (!Number.isSafeInteger(completedAt) || completedAt < 0 || completedAt >= expiresAt.getTime()) throw authorityUnavailable();
|
|
1133
|
-
return {
|
|
1134
|
-
tokenType: "Bearer",
|
|
1135
|
-
token: record.token,
|
|
1136
|
-
expiresAt
|
|
1137
|
-
};
|
|
1138
|
-
};
|
|
1139
|
-
exchangeStarted = true;
|
|
1140
|
-
return await Promise.race([exchange().finally(() => {
|
|
1141
|
-
inFlight = false;
|
|
1142
|
-
}), deadline]);
|
|
1143
|
-
} catch (error) {
|
|
1144
|
-
if (authorityError && error === authorityError) throw authorityError;
|
|
1145
|
-
throw authorityUnavailable();
|
|
1146
|
-
} finally {
|
|
1147
|
-
clearTimeout(timer);
|
|
1148
|
-
controller.abort();
|
|
1149
|
-
reader?.cancel().catch(() => {});
|
|
1150
|
-
if (!exchangeStarted) inFlight = false;
|
|
1151
|
-
}
|
|
1152
|
-
} };
|
|
2120
|
+
function toDate(value) {
|
|
2121
|
+
const result = value instanceof Date ? value : typeof value === "string" ? new Date(value) : void 0;
|
|
2122
|
+
return result && Number.isFinite(result.getTime()) ? result : void 0;
|
|
1153
2123
|
}
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
const suspectProtoRx = /"(?:_|\\u0{2}5[Ff]){2}(?:p|\\u0{2}70)(?:r|\\u0{2}72)(?:o|\\u0{2}6[Ff])(?:t|\\u0{2}74)(?:o|\\u0{2}6[Ff])(?:_|\\u0{2}5[Ff]){2}"\s*:/;
|
|
1157
|
-
const suspectConstructorRx = /"(?:c|\\u0063)(?:o|\\u006[Ff])(?:n|\\u006[Ee])(?:s|\\u0073)(?:t|\\u0074)(?:r|\\u0072)(?:u|\\u0075)(?:c|\\u0063)(?:t|\\u0074)(?:o|\\u006[Ff])(?:r|\\u0072)"\s*:/;
|
|
1158
|
-
const JsonSigRx = /^\s*["[{]|^\s*-?\d{1,16}(\.\d{1,17})?([Ee][+-]?\d+)?\s*$/;
|
|
1159
|
-
function jsonParseTransform(key, value) {
|
|
1160
|
-
if (key === "__proto__" || key === "constructor" && value && typeof value === "object" && "prototype" in value) {
|
|
1161
|
-
warnKeyDropped(key);
|
|
1162
|
-
return;
|
|
1163
|
-
}
|
|
1164
|
-
return value;
|
|
2124
|
+
function isId(value) {
|
|
2125
|
+
return typeof value === "string" && id.test(value);
|
|
1165
2126
|
}
|
|
1166
|
-
function
|
|
1167
|
-
|
|
2127
|
+
function exact$3(value, keys) {
|
|
2128
|
+
if (!isObject(value) || Object.keys(value).sort().join(",") !== [...keys].sort().join(",")) throw authorityUnavailable();
|
|
1168
2129
|
}
|
|
1169
|
-
function
|
|
1170
|
-
|
|
1171
|
-
if (value[0] === "\"" && value[value.length - 1] === "\"" && value.indexOf("\\") === -1) return value.slice(1, -1);
|
|
1172
|
-
const _value = value.trim();
|
|
1173
|
-
if (_value.length <= 9) switch (_value.toLowerCase()) {
|
|
1174
|
-
case "true": return true;
|
|
1175
|
-
case "false": return false;
|
|
1176
|
-
case "undefined": return;
|
|
1177
|
-
case "null": return null;
|
|
1178
|
-
case "nan": return NaN;
|
|
1179
|
-
case "infinity": return Number.POSITIVE_INFINITY;
|
|
1180
|
-
case "-infinity": return Number.NEGATIVE_INFINITY;
|
|
1181
|
-
}
|
|
1182
|
-
if (!JsonSigRx.test(value)) {
|
|
1183
|
-
if (options.strict) throw new SyntaxError("[destr] Invalid JSON");
|
|
1184
|
-
return value;
|
|
1185
|
-
}
|
|
1186
|
-
try {
|
|
1187
|
-
if (suspectProtoRx.test(value) || suspectConstructorRx.test(value)) {
|
|
1188
|
-
if (options.strict) throw new Error("[destr] Possible prototype pollution");
|
|
1189
|
-
return JSON.parse(value, jsonParseTransform);
|
|
1190
|
-
}
|
|
1191
|
-
return JSON.parse(value);
|
|
1192
|
-
} catch (error) {
|
|
1193
|
-
if (options.strict) throw error;
|
|
1194
|
-
return value;
|
|
1195
|
-
}
|
|
2130
|
+
function boundedString(value, maximum) {
|
|
2131
|
+
return typeof value === "string" && value.length > 0 && new TextEncoder().encode(value).byteLength <= maximum;
|
|
1196
2132
|
}
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
2133
|
+
function role(value) {
|
|
2134
|
+
return value === "owner" || value === "admin" || value === "member";
|
|
2135
|
+
}
|
|
2136
|
+
function nullableHttpsUrl(value) {
|
|
2137
|
+
if (value === null) return null;
|
|
2138
|
+
if (typeof value !== "string" || value.length > 2048) throw authorityUnavailable();
|
|
2139
|
+
let url;
|
|
2140
|
+
try {
|
|
2141
|
+
url = new URL(value);
|
|
2142
|
+
} catch {
|
|
2143
|
+
throw authorityUnavailable();
|
|
1204
2144
|
}
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
const errorMessage = ctx.error?.message || ctx.error?.toString() || "";
|
|
1208
|
-
const method = ctx.request?.method || ctx.options?.method || "GET";
|
|
1209
|
-
const url = ctx.request?.url || String(ctx.request) || "/";
|
|
1210
|
-
const fetchError = new FetchError(`${`[${method}] ${JSON.stringify(url)}`}: ${ctx.response ? `${ctx.response.status} ${ctx.response.statusText}` : "<no response>"}${errorMessage ? ` ${errorMessage}` : ""}`, ctx.error ? { cause: ctx.error } : void 0);
|
|
1211
|
-
for (const key of [
|
|
1212
|
-
"request",
|
|
1213
|
-
"options",
|
|
1214
|
-
"response"
|
|
1215
|
-
]) Object.defineProperty(fetchError, key, { get() {
|
|
1216
|
-
return ctx[key];
|
|
1217
|
-
} });
|
|
1218
|
-
for (const [key, refKey] of [
|
|
1219
|
-
["data", "_data"],
|
|
1220
|
-
["status", "status"],
|
|
1221
|
-
["statusCode", "status"],
|
|
1222
|
-
["statusText", "statusText"],
|
|
1223
|
-
["statusMessage", "statusText"]
|
|
1224
|
-
]) Object.defineProperty(fetchError, key, { get() {
|
|
1225
|
-
return ctx.response && ctx.response[refKey];
|
|
1226
|
-
} });
|
|
1227
|
-
return fetchError;
|
|
2145
|
+
if (url.protocol !== "https:" || url.username || url.password || url.toString() !== value) throw authorityUnavailable();
|
|
2146
|
+
return value;
|
|
1228
2147
|
}
|
|
1229
|
-
|
|
1230
|
-
"
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
]));
|
|
1235
|
-
function isPayloadMethod(method = "GET") {
|
|
1236
|
-
return payloadMethods.has(method.toUpperCase());
|
|
2148
|
+
function responseDate(value) {
|
|
2149
|
+
if (typeof value !== "string") throw authorityUnavailable();
|
|
2150
|
+
const date = new Date(value);
|
|
2151
|
+
if (!Number.isFinite(date.getTime()) || date.toISOString() !== value) throw authorityUnavailable();
|
|
2152
|
+
return date;
|
|
1237
2153
|
}
|
|
1238
|
-
function
|
|
1239
|
-
if (value ===
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
if (t !== "object") return false;
|
|
1243
|
-
if (Array.isArray(value)) return true;
|
|
1244
|
-
if (value.buffer) return false;
|
|
1245
|
-
if (value instanceof FormData || value instanceof URLSearchParams) return false;
|
|
1246
|
-
return value.constructor && value.constructor.name === "Object" || typeof value.toJSON === "function";
|
|
2154
|
+
function nullableCursor(value) {
|
|
2155
|
+
if (value === null) return null;
|
|
2156
|
+
if (typeof value !== "string" || value.length < 1 || value.length > 820 || !/^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/.test(value)) throw authorityUnavailable();
|
|
2157
|
+
return value;
|
|
1247
2158
|
}
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
"application/xhtml",
|
|
1252
|
-
"application/html"
|
|
1253
|
-
]);
|
|
1254
|
-
const JSON_RE = /^application\/(?:[\w!#$%&*.^`~-]*\+)?json(;.+)?$/i;
|
|
1255
|
-
function detectResponseType(_contentType = "") {
|
|
1256
|
-
if (!_contentType) return "json";
|
|
1257
|
-
const contentType = _contentType.split(";").shift() || "";
|
|
1258
|
-
if (JSON_RE.test(contentType)) return "json";
|
|
1259
|
-
if (contentType === "text/event-stream") return "stream";
|
|
1260
|
-
if (textTypes.has(contentType) || contentType.startsWith("text/")) return "text";
|
|
1261
|
-
return "blob";
|
|
2159
|
+
function normalizeResponseId(value) {
|
|
2160
|
+
if (!isId(value)) throw authorityUnavailable();
|
|
2161
|
+
return value;
|
|
1262
2162
|
}
|
|
1263
|
-
function
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
2163
|
+
function unique(items, key) {
|
|
2164
|
+
if (new Set(items.map(key)).size !== items.length) throw authorityUnavailable();
|
|
2165
|
+
return items;
|
|
2166
|
+
}
|
|
2167
|
+
function isObject(value) {
|
|
2168
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2169
|
+
}
|
|
2170
|
+
//#endregion
|
|
2171
|
+
//#region src/http.ts
|
|
2172
|
+
const MAX_RESPONSE_BYTES = 64 * 1024;
|
|
2173
|
+
async function requestJson(url, options) {
|
|
2174
|
+
return (await requestJsonResponse(url, options)).value;
|
|
2175
|
+
}
|
|
2176
|
+
async function requestJsonResponse(url, options) {
|
|
2177
|
+
let response;
|
|
2178
|
+
try {
|
|
2179
|
+
response = await createFetch({ fetch: options.fetch }).raw(url, {
|
|
2180
|
+
method: options.method,
|
|
2181
|
+
headers: options.headers,
|
|
2182
|
+
body: options.body,
|
|
2183
|
+
credentials: options.credentials ?? "include",
|
|
2184
|
+
retry: 0,
|
|
2185
|
+
timeout: options.timeoutMs,
|
|
2186
|
+
redirect: "manual",
|
|
2187
|
+
signal: options.signal,
|
|
2188
|
+
responseType: "stream",
|
|
2189
|
+
ignoreResponseError: true
|
|
2190
|
+
});
|
|
2191
|
+
} catch {
|
|
2192
|
+
throw authorityUnavailable();
|
|
2193
|
+
}
|
|
2194
|
+
const contentType = response.headers.get("content-type")?.split(";", 1)[0]?.trim().toLowerCase();
|
|
2195
|
+
if (response.status >= 300 || response.status < 200 || contentType !== "application/json") {
|
|
2196
|
+
const body = contentType === "application/json" ? await readJson(response, options.maxResponseBytes) : void 0;
|
|
2197
|
+
await response.body?.cancel();
|
|
2198
|
+
throw (options.mapError ?? fromAuthorityError)(body, response.status, response.headers.get("retry-after"));
|
|
2199
|
+
}
|
|
1272
2200
|
return {
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
query,
|
|
1276
|
-
params: query,
|
|
1277
|
-
headers
|
|
2201
|
+
value: await readJson(response, options.maxResponseBytes),
|
|
2202
|
+
headers: response.headers
|
|
1278
2203
|
};
|
|
1279
2204
|
}
|
|
1280
|
-
function
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
}
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
2205
|
+
async function readJson(response, maximum = MAX_RESPONSE_BYTES) {
|
|
2206
|
+
const length = response.headers.get("content-length");
|
|
2207
|
+
if (length && (!/^\d+$/.test(length) || Number(length) > maximum)) {
|
|
2208
|
+
await response.body?.cancel();
|
|
2209
|
+
throw authorityUnavailable();
|
|
2210
|
+
}
|
|
2211
|
+
if (!response.body) throw authorityUnavailable();
|
|
2212
|
+
const reader = response.body.getReader();
|
|
2213
|
+
const chunks = [];
|
|
2214
|
+
let size = 0;
|
|
2215
|
+
try {
|
|
2216
|
+
while (true) {
|
|
2217
|
+
const { done, value } = await reader.read();
|
|
2218
|
+
if (done) break;
|
|
2219
|
+
size += value.byteLength;
|
|
2220
|
+
if (size > maximum) throw authorityUnavailable();
|
|
2221
|
+
chunks.push(value);
|
|
2222
|
+
}
|
|
2223
|
+
} catch (error) {
|
|
2224
|
+
await reader.cancel();
|
|
2225
|
+
throw error;
|
|
2226
|
+
} finally {
|
|
2227
|
+
reader.releaseLock();
|
|
2228
|
+
}
|
|
2229
|
+
const bytes = new Uint8Array(size);
|
|
2230
|
+
let offset = 0;
|
|
2231
|
+
for (const chunk of chunks) {
|
|
2232
|
+
bytes.set(chunk, offset);
|
|
2233
|
+
offset += chunk.byteLength;
|
|
2234
|
+
}
|
|
2235
|
+
try {
|
|
2236
|
+
return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
|
|
2237
|
+
} catch {
|
|
2238
|
+
throw authorityUnavailable();
|
|
2239
|
+
}
|
|
1289
2240
|
}
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
function
|
|
1307
|
-
const {
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
2241
|
+
//#endregion
|
|
2242
|
+
//#region src/user-api/verifier.ts
|
|
2243
|
+
const ID = /^[A-Za-z0-9_-]{1,128}$(?![\s\S])/;
|
|
2244
|
+
const KID = /^[A-Za-z0-9_-]{43}$(?![\s\S])/;
|
|
2245
|
+
const PROFILE = "finueva-user-api+jwt";
|
|
2246
|
+
const CACHE_MS = 3e5;
|
|
2247
|
+
const REFRESH_COOLDOWN_MS = 3e4;
|
|
2248
|
+
const TIMEOUT_MS = 2e3;
|
|
2249
|
+
const invalid = () => new AuthError("authentication_required", 401);
|
|
2250
|
+
const unavailable = () => new AuthError("identity_authority_unavailable", 503);
|
|
2251
|
+
function record(value) {
|
|
2252
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
2253
|
+
}
|
|
2254
|
+
function exactKeys(value, keys) {
|
|
2255
|
+
return Object.keys(value).sort().join(",") === keys.sort().join(",");
|
|
2256
|
+
}
|
|
2257
|
+
function createUserApiVerifier(options) {
|
|
2258
|
+
const { issuer, audience, applicationId, environment } = options;
|
|
2259
|
+
if (!issuer || !audience || issuer.length > 2048 || audience.length > 2048 || !ID.test(applicationId) || ![
|
|
2260
|
+
"local",
|
|
2261
|
+
"development",
|
|
2262
|
+
"staging",
|
|
2263
|
+
"production"
|
|
2264
|
+
].includes(environment)) throw new TypeError("User API verifier configuration is invalid");
|
|
2265
|
+
const url = new URL(options.jwksUrl);
|
|
2266
|
+
const local = url.hostname === "localhost" || url.hostname.endsWith(".localhost");
|
|
2267
|
+
if (url.protocol !== "https:" && !(environment === "local" && local && url.protocol === "http:") || url.username || url.password || url.search || url.hash) throw new TypeError("User API JWKS URL is invalid");
|
|
2268
|
+
const jwksUrl = url.href;
|
|
2269
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
2270
|
+
const now = options.now ?? Date.now;
|
|
2271
|
+
let cached;
|
|
2272
|
+
let pending;
|
|
2273
|
+
let nextRefreshAt = -Infinity;
|
|
2274
|
+
async function loadKeys() {
|
|
2275
|
+
const controller = new AbortController();
|
|
2276
|
+
let timer;
|
|
2277
|
+
const deadline = new Promise((_, reject) => {
|
|
2278
|
+
timer = setTimeout(() => {
|
|
2279
|
+
controller.abort();
|
|
2280
|
+
reject(unavailable());
|
|
2281
|
+
}, TIMEOUT_MS);
|
|
2282
|
+
});
|
|
2283
|
+
const started = now();
|
|
2284
|
+
try {
|
|
2285
|
+
const value = await Promise.race([requestJson(jwksUrl, {
|
|
2286
|
+
fetch: fetchImpl,
|
|
2287
|
+
timeoutMs: TIMEOUT_MS,
|
|
2288
|
+
method: "GET",
|
|
2289
|
+
credentials: "omit",
|
|
2290
|
+
signal: controller.signal,
|
|
2291
|
+
maxResponseBytes: 64 * 1024
|
|
2292
|
+
}), deadline]);
|
|
2293
|
+
if (!record(value) || !exactKeys(value, ["keys"]) || !Array.isArray(value.keys) || value.keys.length < 1 || value.keys.length > 20) throw unavailable();
|
|
2294
|
+
const keys = new Map();
|
|
2295
|
+
for (const entry of value.keys) {
|
|
2296
|
+
if (!record(entry) || !exactKeys(entry, [
|
|
2297
|
+
"kty",
|
|
2298
|
+
"crv",
|
|
2299
|
+
"x",
|
|
2300
|
+
"kid",
|
|
2301
|
+
"alg",
|
|
2302
|
+
"use"
|
|
2303
|
+
]) || entry.kty !== "OKP" || entry.crv !== "Ed25519" || entry.alg !== "EdDSA" || entry.use !== "sig" || typeof entry.x !== "string" || !KID.test(entry.x) || typeof entry.kid !== "string" || !KID.test(entry.kid) || keys.has(entry.kid)) throw unavailable();
|
|
2304
|
+
const jwk = {
|
|
2305
|
+
kty: "OKP",
|
|
2306
|
+
crv: "Ed25519",
|
|
2307
|
+
x: entry.x
|
|
2308
|
+
};
|
|
2309
|
+
if (await calculateJwkThumbprint(jwk) !== entry.kid) throw unavailable();
|
|
2310
|
+
keys.set(entry.kid, await importJWK(jwk, "EdDSA"));
|
|
1322
2311
|
}
|
|
2312
|
+
if (controller.signal.aborted || now() < started || now() >= started + CACHE_MS) throw unavailable();
|
|
2313
|
+
cached = {
|
|
2314
|
+
keys,
|
|
2315
|
+
loadedAt: started,
|
|
2316
|
+
expiresAt: started + CACHE_MS
|
|
2317
|
+
};
|
|
2318
|
+
} catch {
|
|
2319
|
+
throw unavailable();
|
|
2320
|
+
} finally {
|
|
2321
|
+
clearTimeout(timer);
|
|
1323
2322
|
}
|
|
1324
|
-
const error = createFetchError(context);
|
|
1325
|
-
if (Error.captureStackTrace) Error.captureStackTrace(error, $fetchRaw);
|
|
1326
|
-
throw error;
|
|
1327
2323
|
}
|
|
1328
|
-
|
|
1329
|
-
const
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
2324
|
+
async function keyFor(kid) {
|
|
2325
|
+
const time = now();
|
|
2326
|
+
const known = cached && time >= cached.loadedAt && time < cached.expiresAt ? cached?.keys.get(kid) : void 0;
|
|
2327
|
+
if (known) return known;
|
|
2328
|
+
if (pending) await pending;
|
|
2329
|
+
else if (time >= nextRefreshAt) {
|
|
2330
|
+
nextRefreshAt = time + REFRESH_COOLDOWN_MS;
|
|
2331
|
+
const request = loadKeys().finally(() => {
|
|
2332
|
+
if (pending === request) pending = void 0;
|
|
2333
|
+
});
|
|
2334
|
+
pending = request;
|
|
2335
|
+
await request;
|
|
1339
2336
|
}
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
2337
|
+
const current = now();
|
|
2338
|
+
if (!cached || current < cached.loadedAt || current >= cached.expiresAt) throw unavailable();
|
|
2339
|
+
const key = cached.keys.get(kid);
|
|
2340
|
+
if (!key) throw invalid();
|
|
2341
|
+
return key;
|
|
2342
|
+
}
|
|
2343
|
+
return { async verify(token) {
|
|
2344
|
+
if (typeof token !== "string" || token.length + 7 > 16 * 1024 || !/^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/.test(token)) throw invalid();
|
|
2345
|
+
let kid;
|
|
2346
|
+
try {
|
|
2347
|
+
const header = decodeProtectedHeader(token);
|
|
2348
|
+
if (!exactKeys(header, [
|
|
2349
|
+
"alg",
|
|
2350
|
+
"typ",
|
|
2351
|
+
"kid"
|
|
2352
|
+
]) || header.alg !== "EdDSA" || header.typ !== PROFILE || typeof header.kid !== "string" || !KID.test(header.kid)) throw invalid();
|
|
2353
|
+
kid = header.kid;
|
|
2354
|
+
} catch {
|
|
2355
|
+
throw invalid();
|
|
1348
2356
|
}
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
2357
|
+
let identity;
|
|
2358
|
+
try {
|
|
2359
|
+
const payload = decodeJwt(token);
|
|
2360
|
+
const time = Math.floor(now() / 1e3);
|
|
2361
|
+
if (!exactKeys(payload, [
|
|
2362
|
+
"iss",
|
|
2363
|
+
"aud",
|
|
2364
|
+
"sub",
|
|
2365
|
+
"sid",
|
|
2366
|
+
"iat",
|
|
2367
|
+
"exp",
|
|
2368
|
+
"ver",
|
|
2369
|
+
"principal_type",
|
|
2370
|
+
"scope",
|
|
2371
|
+
"app",
|
|
2372
|
+
"environment",
|
|
2373
|
+
"user"
|
|
2374
|
+
]) || payload.iss !== issuer || payload.aud !== audience || payload.app !== applicationId || payload.environment !== environment || payload.ver !== 1 || payload.principal_type !== "user" || payload.scope !== "user:api" || typeof payload.sub !== "string" || !ID.test(payload.sub) || typeof payload.sid !== "string" || !ID.test(payload.sid) || !Number.isSafeInteger(payload.iat) || !Number.isSafeInteger(payload.exp) || payload.iat < 0 || payload.iat > time || payload.exp <= time || payload.exp <= payload.iat || payload.exp - payload.iat > 840) throw invalid();
|
|
2375
|
+
const user = payload.user;
|
|
2376
|
+
if (!record(user) || !exactKeys(user, [
|
|
2377
|
+
"name",
|
|
2378
|
+
"email",
|
|
2379
|
+
"emailVerified",
|
|
2380
|
+
"image"
|
|
2381
|
+
]) || typeof user.name !== "string" || user.name.length > 200 || typeof user.email !== "string" || user.email.length < 1 || user.email.length > 320 || typeof user.emailVerified !== "boolean" || !(user.image === null || typeof user.image === "string" && user.image.length <= 2048)) throw invalid();
|
|
2382
|
+
identity = {
|
|
2383
|
+
userId: payload.sub,
|
|
2384
|
+
sessionId: payload.sid,
|
|
2385
|
+
applicationId,
|
|
2386
|
+
issuedAt: new Date(payload.iat * 1e3),
|
|
2387
|
+
expiresAt: new Date(payload.exp * 1e3),
|
|
2388
|
+
user: {
|
|
2389
|
+
id: payload.sub,
|
|
2390
|
+
name: user.name,
|
|
2391
|
+
email: user.email,
|
|
2392
|
+
emailVerified: user.emailVerified,
|
|
2393
|
+
image: user.image
|
|
2394
|
+
}
|
|
2395
|
+
};
|
|
2396
|
+
} catch {
|
|
2397
|
+
throw invalid();
|
|
1358
2398
|
}
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
2399
|
+
const key = await keyFor(kid);
|
|
2400
|
+
try {
|
|
2401
|
+
await jwtVerify(token, key, {
|
|
2402
|
+
algorithms: ["EdDSA"],
|
|
2403
|
+
issuer,
|
|
2404
|
+
audience,
|
|
2405
|
+
typ: PROFILE,
|
|
2406
|
+
currentDate: new Date(now()),
|
|
2407
|
+
clockTolerance: 0,
|
|
2408
|
+
requiredClaims: [
|
|
2409
|
+
"iss",
|
|
2410
|
+
"aud",
|
|
2411
|
+
"sub",
|
|
2412
|
+
"sid",
|
|
2413
|
+
"iat",
|
|
2414
|
+
"exp"
|
|
2415
|
+
]
|
|
2416
|
+
});
|
|
2417
|
+
} catch {
|
|
2418
|
+
throw invalid();
|
|
1369
2419
|
}
|
|
2420
|
+
return identity;
|
|
2421
|
+
} };
|
|
2422
|
+
}
|
|
2423
|
+
//#endregion
|
|
2424
|
+
//#region src/identity-resolution.ts
|
|
2425
|
+
const emailPattern$1 = /^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9-]*\.)+[A-Za-z]{2,}$(?![\s\S])/;
|
|
2426
|
+
function exact$2(value, keys) {
|
|
2427
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === keys.length && keys.every((key) => Object.hasOwn(value, key));
|
|
2428
|
+
}
|
|
2429
|
+
function createIdentityResolverAuth(options) {
|
|
2430
|
+
const url = joinURL(normalizeOrigin(options.authOrigin, "authOrigin"), "api/v1/auth/identities/resolve");
|
|
2431
|
+
const fetchImpl = options.fetch ?? globalThis.fetch?.bind(globalThis);
|
|
2432
|
+
if (typeof fetchImpl !== "function") throw new TypeError("fetch is required");
|
|
2433
|
+
const timeoutMs = normalizeTimeout(options.timeoutMs);
|
|
2434
|
+
let inFlight = false;
|
|
2435
|
+
return { async resolveIdentity(input, clientAssertion) {
|
|
2436
|
+
if (!exact$2(input, ["identifier"]) || typeof input.identifier !== "string" || input.identifier.length > 324) throw new AuthError("invalid_request", 400);
|
|
2437
|
+
const identifier = input.identifier.trim().toLowerCase();
|
|
2438
|
+
if (!(identifier.length <= 320 && emailPattern$1.test(identifier)) && !/^[a-z0-9_.]{3,30}$(?![\s\S])/.test(identifier)) throw new AuthError("invalid_request", 400);
|
|
2439
|
+
if (typeof clientAssertion !== "string" || clientAssertion.length + 7 > 16 * 1024 || !/^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$(?![\s\S])/.test(clientAssertion)) throw new AuthError("invalid_request", 400);
|
|
2440
|
+
if (inFlight) throw new AuthError("state_conflict", 409);
|
|
2441
|
+
inFlight = true;
|
|
2442
|
+
const controller = new AbortController();
|
|
2443
|
+
let reader;
|
|
2444
|
+
let timer;
|
|
2445
|
+
let mappedError;
|
|
1370
2446
|
try {
|
|
1371
|
-
|
|
2447
|
+
const deadline = new Promise((_, reject) => {
|
|
2448
|
+
timer = setTimeout(() => {
|
|
2449
|
+
reject(authorityUnavailable());
|
|
2450
|
+
controller.abort();
|
|
2451
|
+
reader?.cancel().catch(() => {});
|
|
2452
|
+
}, timeoutMs);
|
|
2453
|
+
});
|
|
2454
|
+
const exchange = async () => {
|
|
2455
|
+
const response = await fetchImpl(url, {
|
|
2456
|
+
method: "POST",
|
|
2457
|
+
headers: {
|
|
2458
|
+
authorization: `Bearer ${clientAssertion}`,
|
|
2459
|
+
accept: "application/json",
|
|
2460
|
+
"content-type": "application/json"
|
|
2461
|
+
},
|
|
2462
|
+
body: JSON.stringify({ identifier }),
|
|
2463
|
+
credentials: "omit",
|
|
2464
|
+
cache: "no-store",
|
|
2465
|
+
redirect: "manual",
|
|
2466
|
+
signal: controller.signal
|
|
2467
|
+
});
|
|
2468
|
+
if (controller.signal.aborted) {
|
|
2469
|
+
response.body?.cancel().catch(() => {});
|
|
2470
|
+
throw authorityUnavailable();
|
|
2471
|
+
}
|
|
2472
|
+
if (!response.body) throw authorityUnavailable();
|
|
2473
|
+
reader = response.body.getReader();
|
|
2474
|
+
const length = response.headers.get("content-length");
|
|
2475
|
+
if (response.redirected || response.headers.get("content-type")?.split(";", 1)[0]?.trim().toLowerCase() !== "application/json" || length !== null && (!/^\d+$/.test(length) || Number(length) > 1024)) throw authorityUnavailable();
|
|
2476
|
+
const bytes = new Uint8Array(1024);
|
|
2477
|
+
let size = 0;
|
|
2478
|
+
while (true) {
|
|
2479
|
+
const chunk = await reader.read();
|
|
2480
|
+
if (controller.signal.aborted) throw authorityUnavailable();
|
|
2481
|
+
if (chunk.done) break;
|
|
2482
|
+
if (size + chunk.value.byteLength > bytes.length) throw authorityUnavailable();
|
|
2483
|
+
bytes.set(chunk.value, size);
|
|
2484
|
+
size += chunk.value.byteLength;
|
|
2485
|
+
}
|
|
2486
|
+
const value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(0, size)));
|
|
2487
|
+
if (response.status !== 200) {
|
|
2488
|
+
if (!exact$2(value, ["code", "message"])) throw authorityUnavailable();
|
|
2489
|
+
if (response.status === 401 && value.code === "UNAUTHORIZED" && value.message === "The identity resolution assertion is invalid.") mappedError = new AuthError("authentication_required", 401);
|
|
2490
|
+
if (response.status === 429 && value.code === "TOO_MANY_REQUESTS" && value.message === "Identity resolution requests are temporarily limited.") {
|
|
2491
|
+
const retryAfter = response.headers.get("retry-after");
|
|
2492
|
+
if (retryAfter === null || !/^(?:[1-9]|[1-5][0-9]|60)$/.test(retryAfter)) throw authorityUnavailable();
|
|
2493
|
+
mappedError = new AuthError("auth_request_rate_limited", 429, Number(retryAfter));
|
|
2494
|
+
}
|
|
2495
|
+
throw mappedError ?? authorityUnavailable();
|
|
2496
|
+
}
|
|
2497
|
+
if (!exact$2(value, ["identity"])) throw authorityUnavailable();
|
|
2498
|
+
if (value.identity === null) return null;
|
|
2499
|
+
if (!exact$2(value.identity, ["userId"]) || typeof value.identity.userId !== "string" || !/^[A-Za-z0-9_-]{1,128}$(?![\s\S])/.test(value.identity.userId)) throw authorityUnavailable();
|
|
2500
|
+
return { userId: value.identity.userId };
|
|
2501
|
+
};
|
|
2502
|
+
return await Promise.race([exchange().finally(() => {
|
|
2503
|
+
inFlight = false;
|
|
2504
|
+
}), deadline]);
|
|
1372
2505
|
} catch (error) {
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
return await onError(context);
|
|
2506
|
+
if (mappedError && mappedError === error) throw mappedError;
|
|
2507
|
+
throw authorityUnavailable();
|
|
1376
2508
|
} finally {
|
|
1377
|
-
|
|
2509
|
+
clearTimeout(timer);
|
|
2510
|
+
controller.abort();
|
|
2511
|
+
reader?.cancel().catch(() => {});
|
|
1378
2512
|
}
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
2513
|
+
} };
|
|
2514
|
+
}
|
|
2515
|
+
//#endregion
|
|
2516
|
+
//#region src/membership-resolution.ts
|
|
2517
|
+
const idPattern = /^[A-Za-z0-9_-]{1,128}$(?![\s\S])/;
|
|
2518
|
+
const isoPattern = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?Z$(?![\s\S])/;
|
|
2519
|
+
const roles = [
|
|
2520
|
+
"admin",
|
|
2521
|
+
"member",
|
|
2522
|
+
"owner"
|
|
2523
|
+
];
|
|
2524
|
+
const membershipKeys = [
|
|
2525
|
+
"checkedAt",
|
|
2526
|
+
"manualRole",
|
|
2527
|
+
"memberCount",
|
|
2528
|
+
"memberId",
|
|
2529
|
+
"organizationId",
|
|
2530
|
+
"owner",
|
|
2531
|
+
"role",
|
|
2532
|
+
"userId"
|
|
2533
|
+
];
|
|
2534
|
+
function exact$1(value, keys) {
|
|
2535
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === keys.length && keys.every((key) => Object.hasOwn(value, key));
|
|
2536
|
+
}
|
|
2537
|
+
function createMembershipResolverAuth(options) {
|
|
2538
|
+
const url = joinURL(normalizeOrigin(options.authOrigin, "authOrigin"), "api/v1/auth/memberships/resolve");
|
|
2539
|
+
const fetchImpl = options.fetch ?? globalThis.fetch?.bind(globalThis);
|
|
2540
|
+
if (typeof fetchImpl !== "function") throw new TypeError("fetch is required");
|
|
2541
|
+
const timeoutMs = normalizeTimeout(options.timeoutMs);
|
|
2542
|
+
let inFlight = false;
|
|
2543
|
+
return { async resolveMembership(input, clientAssertion) {
|
|
2544
|
+
if (!exact$1(input, ["organizationId", "userId"]) || typeof input.organizationId !== "string" || typeof input.userId !== "string" || !idPattern.test(input.organizationId) || !idPattern.test(input.userId)) throw new AuthError("invalid_request", 400);
|
|
2545
|
+
if (typeof clientAssertion !== "string" || clientAssertion.length + 7 > 16 * 1024 || !/^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$(?![\s\S])/.test(clientAssertion)) throw new AuthError("invalid_request", 400);
|
|
2546
|
+
if (inFlight) throw new AuthError("state_conflict", 409);
|
|
2547
|
+
inFlight = true;
|
|
2548
|
+
const organizationId = input.organizationId;
|
|
2549
|
+
const userId = input.userId;
|
|
2550
|
+
const controller = new AbortController();
|
|
2551
|
+
let reader;
|
|
2552
|
+
let timer;
|
|
2553
|
+
let mappedError;
|
|
2554
|
+
try {
|
|
2555
|
+
const deadline = new Promise((_, reject) => {
|
|
2556
|
+
timer = setTimeout(() => {
|
|
2557
|
+
reject(authorityUnavailable());
|
|
2558
|
+
controller.abort();
|
|
2559
|
+
reader?.cancel().catch(() => {});
|
|
2560
|
+
}, timeoutMs);
|
|
2561
|
+
});
|
|
2562
|
+
const exchange = async () => {
|
|
2563
|
+
const response = await fetchImpl(url, {
|
|
2564
|
+
method: "POST",
|
|
2565
|
+
headers: {
|
|
2566
|
+
authorization: `Bearer ${clientAssertion}`,
|
|
2567
|
+
accept: "application/json",
|
|
2568
|
+
"content-type": "application/json"
|
|
2569
|
+
},
|
|
2570
|
+
body: JSON.stringify({
|
|
2571
|
+
organizationId,
|
|
2572
|
+
userId
|
|
2573
|
+
}),
|
|
2574
|
+
credentials: "omit",
|
|
2575
|
+
cache: "no-store",
|
|
2576
|
+
redirect: "manual",
|
|
2577
|
+
signal: controller.signal
|
|
2578
|
+
});
|
|
2579
|
+
if (controller.signal.aborted) {
|
|
2580
|
+
response.body?.cancel().catch(() => {});
|
|
2581
|
+
throw authorityUnavailable();
|
|
1387
2582
|
}
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
2583
|
+
if (!response.body) throw authorityUnavailable();
|
|
2584
|
+
reader = response.body.getReader();
|
|
2585
|
+
const length = response.headers.get("content-length");
|
|
2586
|
+
if (response.redirected || response.headers.get("content-type")?.split(";", 1)[0]?.trim().toLowerCase() !== "application/json" || length !== null && (!/^\d+$/.test(length) || Number(length) > 1024)) throw authorityUnavailable();
|
|
2587
|
+
const bytes = new Uint8Array(1024);
|
|
2588
|
+
let size = 0;
|
|
2589
|
+
while (true) {
|
|
2590
|
+
const chunk = await reader.read();
|
|
2591
|
+
if (controller.signal.aborted) throw authorityUnavailable();
|
|
2592
|
+
if (chunk.done) break;
|
|
2593
|
+
if (size + chunk.value.byteLength > bytes.length) throw authorityUnavailable();
|
|
2594
|
+
bytes.set(chunk.value, size);
|
|
2595
|
+
size += chunk.value.byteLength;
|
|
2596
|
+
}
|
|
2597
|
+
const value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(0, size)));
|
|
2598
|
+
if (response.status !== 200) {
|
|
2599
|
+
if (!exact$1(value, ["code", "message"])) throw authorityUnavailable();
|
|
2600
|
+
if (response.status === 401 && value.code === "UNAUTHORIZED" && value.message === "The membership resolution assertion is invalid.") mappedError = new AuthError("authentication_required", 401);
|
|
2601
|
+
if (response.status === 429 && value.code === "TOO_MANY_REQUESTS" && value.message === "Membership resolution requests are temporarily limited.") {
|
|
2602
|
+
const retryAfter = response.headers.get("retry-after");
|
|
2603
|
+
if (retryAfter === null || !/^(?:[1-9]|[1-5][0-9]|60)$/.test(retryAfter)) throw authorityUnavailable();
|
|
2604
|
+
mappedError = new AuthError("auth_request_rate_limited", 429, Number(retryAfter));
|
|
2605
|
+
}
|
|
2606
|
+
throw mappedError ?? authorityUnavailable();
|
|
2607
|
+
}
|
|
2608
|
+
if (!exact$1(value, ["membership"])) throw authorityUnavailable();
|
|
2609
|
+
if (value.membership === null) return null;
|
|
2610
|
+
const membership = value.membership;
|
|
2611
|
+
if (!exact$1(membership, membershipKeys) || typeof membership.checkedAt !== "string" || !isoPattern.test(membership.checkedAt) || Number.isNaN(Date.parse(membership.checkedAt)) || typeof membership.manualRole !== "string" || !roles.includes(membership.manualRole) || typeof membership.role !== "string" || !roles.includes(membership.role) || typeof membership.memberCount !== "number" || !Number.isSafeInteger(membership.memberCount) || membership.memberCount < 0 || typeof membership.memberId !== "string" || !idPattern.test(membership.memberId) || typeof membership.owner !== "boolean" || membership.organizationId !== organizationId || membership.userId !== userId) throw authorityUnavailable();
|
|
2612
|
+
return {
|
|
2613
|
+
checkedAt: membership.checkedAt,
|
|
2614
|
+
manualRole: membership.manualRole,
|
|
2615
|
+
memberCount: membership.memberCount,
|
|
2616
|
+
memberId: membership.memberId,
|
|
2617
|
+
organizationId,
|
|
2618
|
+
owner: membership.owner,
|
|
2619
|
+
role: membership.role,
|
|
2620
|
+
userId
|
|
2621
|
+
};
|
|
2622
|
+
};
|
|
2623
|
+
return await Promise.race([exchange().finally(() => {
|
|
2624
|
+
inFlight = false;
|
|
2625
|
+
}), deadline]);
|
|
2626
|
+
} catch (error) {
|
|
2627
|
+
if (mappedError && mappedError === error) throw mappedError;
|
|
2628
|
+
throw authorityUnavailable();
|
|
2629
|
+
} finally {
|
|
2630
|
+
clearTimeout(timer);
|
|
2631
|
+
controller.abort();
|
|
2632
|
+
reader?.cancel().catch(() => {});
|
|
1393
2633
|
}
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
2634
|
+
} };
|
|
2635
|
+
}
|
|
2636
|
+
//#endregion
|
|
2637
|
+
//#region src/drive-recipients.ts
|
|
2638
|
+
const encoder = new TextEncoder();
|
|
2639
|
+
const emailPattern = /^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9-]*\.)+[A-Za-z]{2,}$/;
|
|
2640
|
+
function validEmail(value) {
|
|
2641
|
+
return typeof value === "string" && encoder.encode(value).byteLength <= 320 && emailPattern.test(value);
|
|
2642
|
+
}
|
|
2643
|
+
function exact(value, keys) {
|
|
2644
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === keys.length && keys.every((key) => Object.hasOwn(value, key));
|
|
2645
|
+
}
|
|
2646
|
+
const failures = {
|
|
2647
|
+
400: [
|
|
2648
|
+
"BAD_REQUEST",
|
|
2649
|
+
"The recipient request is invalid.",
|
|
2650
|
+
"invalid_request"
|
|
2651
|
+
],
|
|
2652
|
+
401: [
|
|
2653
|
+
"UNAUTHORIZED",
|
|
2654
|
+
"The recipient service assertion is invalid.",
|
|
2655
|
+
"authentication_required"
|
|
2656
|
+
],
|
|
2657
|
+
404: [
|
|
2658
|
+
"NOT_FOUND",
|
|
2659
|
+
"The recipient is unavailable.",
|
|
2660
|
+
"recipient_unavailable"
|
|
2661
|
+
],
|
|
2662
|
+
405: [
|
|
2663
|
+
"METHOD_NOT_ALLOWED",
|
|
2664
|
+
"METHOD_NOT_ALLOWED",
|
|
2665
|
+
"invalid_request"
|
|
2666
|
+
],
|
|
2667
|
+
413: [
|
|
2668
|
+
"REQUEST_TOO_LONG",
|
|
2669
|
+
"The recipient request is too large.",
|
|
2670
|
+
"invalid_request"
|
|
2671
|
+
],
|
|
2672
|
+
429: [
|
|
2673
|
+
"TOO_MANY_REQUESTS",
|
|
2674
|
+
"Recipient requests are temporarily limited.",
|
|
2675
|
+
"auth_request_rate_limited"
|
|
2676
|
+
],
|
|
2677
|
+
503: [
|
|
2678
|
+
"SERVICE_UNAVAILABLE",
|
|
2679
|
+
"Recipient resolution is temporarily unavailable.",
|
|
2680
|
+
"identity_authority_unavailable"
|
|
2681
|
+
]
|
|
2682
|
+
};
|
|
2683
|
+
function createDriveRecipientAuth(options) {
|
|
2684
|
+
const url = joinURL(normalizeOrigin(options.authOrigin, "authOrigin"), "api/v1/auth/drive-share-recipients/resolve");
|
|
2685
|
+
const fetchImpl = options.fetch ?? globalThis.fetch?.bind(globalThis);
|
|
2686
|
+
if (typeof fetchImpl !== "function") throw new TypeError("fetch is required");
|
|
2687
|
+
const timeoutMs = normalizeTimeout(options.timeoutMs);
|
|
2688
|
+
let inFlight = false;
|
|
2689
|
+
return { async resolveRecipient(input, clientAssertion) {
|
|
2690
|
+
let body;
|
|
2691
|
+
let email;
|
|
2692
|
+
try {
|
|
2693
|
+
if (!exact(input, ["email"]) || typeof input.email !== "string") throw new Error();
|
|
2694
|
+
email = input.email.trim().toLowerCase();
|
|
2695
|
+
if (!validEmail(email)) throw new Error();
|
|
2696
|
+
body = JSON.stringify({ email });
|
|
2697
|
+
} catch {
|
|
2698
|
+
throw new AuthError("invalid_request", 400);
|
|
1398
2699
|
}
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
2700
|
+
if (encoder.encode(body).byteLength > 1024) throw new AuthError("invalid_request", 413);
|
|
2701
|
+
if (typeof clientAssertion !== "string" || clientAssertion.length + 7 > 16 * 1024 || !/^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$(?![\s\S])/.test(clientAssertion)) throw new AuthError("invalid_request", 400);
|
|
2702
|
+
if (inFlight) throw new AuthError("state_conflict", 409);
|
|
2703
|
+
inFlight = true;
|
|
2704
|
+
const controller = new AbortController();
|
|
2705
|
+
let reader;
|
|
2706
|
+
let timer;
|
|
2707
|
+
let authorityError;
|
|
2708
|
+
try {
|
|
2709
|
+
const deadline = new Promise((_, reject) => {
|
|
2710
|
+
timer = setTimeout(() => {
|
|
2711
|
+
reject(authorityUnavailable());
|
|
2712
|
+
controller.abort();
|
|
2713
|
+
reader?.cancel().catch(() => {});
|
|
2714
|
+
}, timeoutMs);
|
|
2715
|
+
});
|
|
2716
|
+
const exchange = async () => {
|
|
2717
|
+
const response = await fetchImpl(url, {
|
|
2718
|
+
method: "POST",
|
|
2719
|
+
headers: {
|
|
2720
|
+
authorization: `Bearer ${clientAssertion}`,
|
|
2721
|
+
accept: "application/json",
|
|
2722
|
+
"content-type": "application/json"
|
|
2723
|
+
},
|
|
2724
|
+
body,
|
|
2725
|
+
credentials: "omit",
|
|
2726
|
+
cache: "no-store",
|
|
2727
|
+
redirect: "manual",
|
|
2728
|
+
signal: controller.signal
|
|
2729
|
+
});
|
|
2730
|
+
if (controller.signal.aborted) {
|
|
2731
|
+
response.body?.cancel().catch(() => {});
|
|
2732
|
+
throw authorityUnavailable();
|
|
2733
|
+
}
|
|
2734
|
+
if (!response.body) throw authorityUnavailable();
|
|
2735
|
+
reader = response.body.getReader();
|
|
2736
|
+
const contentType = response.headers.get("content-type")?.split(";", 1)[0]?.trim().toLowerCase();
|
|
2737
|
+
const length = response.headers.get("content-length");
|
|
2738
|
+
if (response.redirected || contentType !== "application/json" || length !== null && (!/^\d+$/.test(length) || Number(length) > 4096)) throw authorityUnavailable();
|
|
2739
|
+
const bytes = new Uint8Array(4096);
|
|
2740
|
+
let size = 0;
|
|
2741
|
+
while (true) {
|
|
2742
|
+
const chunk = await reader.read();
|
|
2743
|
+
if (controller.signal.aborted) throw authorityUnavailable();
|
|
2744
|
+
if (chunk.done) break;
|
|
2745
|
+
if (size + chunk.value.byteLength > bytes.byteLength) throw authorityUnavailable();
|
|
2746
|
+
bytes.set(chunk.value, size);
|
|
2747
|
+
size += chunk.value.byteLength;
|
|
2748
|
+
}
|
|
2749
|
+
const value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(0, size)));
|
|
2750
|
+
if (response.status !== 200) {
|
|
2751
|
+
const status = response.status;
|
|
2752
|
+
const failure = failures[status];
|
|
2753
|
+
if (!failure || !exact(value, ["code", "message"]) || value.code !== failure[0] || value.message !== failure[1]) throw authorityUnavailable();
|
|
2754
|
+
let retryAfterSeconds;
|
|
2755
|
+
if (status === 429) {
|
|
2756
|
+
const retryAfter = response.headers.get("retry-after");
|
|
2757
|
+
if (retryAfter === null || !/^(?:[1-9]|[1-5][0-9]|60)$/.test(retryAfter)) throw authorityUnavailable();
|
|
2758
|
+
retryAfterSeconds = Number(retryAfter);
|
|
2759
|
+
}
|
|
2760
|
+
authorityError = new AuthError(failure[2], status, retryAfterSeconds);
|
|
2761
|
+
throw authorityError;
|
|
2762
|
+
}
|
|
2763
|
+
if (!exact(value, ["recipient"]) || !exact(value.recipient, [
|
|
2764
|
+
"userId",
|
|
2765
|
+
"name",
|
|
2766
|
+
"email"
|
|
2767
|
+
])) throw authorityUnavailable();
|
|
2768
|
+
const recipient = value.recipient;
|
|
2769
|
+
if (typeof recipient.userId !== "string" || !/^[A-Za-z0-9_-]{1,128}$(?![\s\S])/.test(recipient.userId) || typeof recipient.name !== "string" || recipient.name.length === 0 || encoder.encode(recipient.name).byteLength > 1024 || !validEmail(recipient.email) || recipient.email !== recipient.email.trim().toLowerCase() || recipient.email !== email) throw authorityUnavailable();
|
|
2770
|
+
return {
|
|
2771
|
+
userId: recipient.userId,
|
|
2772
|
+
name: recipient.name,
|
|
2773
|
+
email: recipient.email
|
|
2774
|
+
};
|
|
2775
|
+
};
|
|
2776
|
+
return await Promise.race([exchange().finally(() => {
|
|
2777
|
+
inFlight = false;
|
|
2778
|
+
}), deadline]);
|
|
2779
|
+
} catch (error) {
|
|
2780
|
+
if (authorityError && error === authorityError) throw authorityError;
|
|
2781
|
+
throw authorityUnavailable();
|
|
2782
|
+
} finally {
|
|
2783
|
+
clearTimeout(timer);
|
|
2784
|
+
controller.abort();
|
|
2785
|
+
reader?.cancel().catch(() => {});
|
|
1413
2786
|
}
|
|
1414
|
-
}
|
|
1415
|
-
return $fetch;
|
|
2787
|
+
} };
|
|
1416
2788
|
}
|
|
1417
2789
|
//#endregion
|
|
1418
|
-
//#region src/
|
|
1419
|
-
const
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
async function requestJsonResponse(url, options) {
|
|
1424
|
-
let response;
|
|
1425
|
-
try {
|
|
1426
|
-
response = await createFetch({ fetch: options.fetch }).raw(url, {
|
|
1427
|
-
method: options.method,
|
|
1428
|
-
headers: options.headers,
|
|
1429
|
-
body: options.body,
|
|
1430
|
-
credentials: options.credentials ?? "include",
|
|
1431
|
-
retry: 0,
|
|
1432
|
-
timeout: options.timeoutMs,
|
|
1433
|
-
redirect: "manual",
|
|
1434
|
-
signal: options.signal,
|
|
1435
|
-
responseType: "stream",
|
|
1436
|
-
ignoreResponseError: true
|
|
1437
|
-
});
|
|
1438
|
-
} catch {
|
|
1439
|
-
throw authorityUnavailable();
|
|
1440
|
-
}
|
|
1441
|
-
const contentType = response.headers.get("content-type")?.split(";", 1)[0]?.trim().toLowerCase();
|
|
1442
|
-
if (response.status >= 300 || response.status < 200 || contentType !== "application/json") {
|
|
1443
|
-
const body = contentType === "application/json" ? await readJson(response, options.maxResponseBytes) : void 0;
|
|
1444
|
-
await response.body?.cancel();
|
|
1445
|
-
throw (options.mapError ?? fromAuthorityError)(body, response.status, response.headers.get("retry-after"));
|
|
1446
|
-
}
|
|
1447
|
-
return {
|
|
1448
|
-
value: await readJson(response, options.maxResponseBytes),
|
|
1449
|
-
headers: response.headers
|
|
1450
|
-
};
|
|
2790
|
+
//#region src/provisioning.ts
|
|
2791
|
+
const MAX_BYTES = 16 * 1024;
|
|
2792
|
+
const compactJwt = /^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/;
|
|
2793
|
+
function isCompactCredential(value) {
|
|
2794
|
+
return typeof value === "string" && value.length + 7 <= MAX_BYTES && compactJwt.test(value);
|
|
1451
2795
|
}
|
|
1452
|
-
|
|
1453
|
-
const
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
2796
|
+
function createDriveProvisioningAuth(options) {
|
|
2797
|
+
const url = joinURL(normalizeOrigin(options.authOrigin, "authOrigin"), "api/v1/auth/drive-provisioning-credential");
|
|
2798
|
+
const fetchImpl = options.fetch ?? globalThis.fetch?.bind(globalThis);
|
|
2799
|
+
if (typeof fetchImpl !== "function") throw new TypeError("fetch is required");
|
|
2800
|
+
const timeoutMs = normalizeTimeout(options.timeoutMs);
|
|
2801
|
+
const now = options.now ?? Date.now;
|
|
2802
|
+
let inFlight = false;
|
|
2803
|
+
return { async getDriveProvisioningCredential(clientAssertion) {
|
|
2804
|
+
if (!isCompactCredential(clientAssertion)) throw new AuthError("invalid_request", 400);
|
|
2805
|
+
if (inFlight) throw new AuthError("state_conflict", 409);
|
|
2806
|
+
inFlight = true;
|
|
2807
|
+
const controller = new AbortController();
|
|
2808
|
+
let reader;
|
|
2809
|
+
let timer;
|
|
2810
|
+
let exchangeStarted = false;
|
|
2811
|
+
let authorityError;
|
|
2812
|
+
try {
|
|
2813
|
+
const startedAt = now();
|
|
2814
|
+
if (!Number.isSafeInteger(startedAt) || startedAt < 0 || startedAt > 86399999997e5) throw authorityUnavailable();
|
|
2815
|
+
const deadline = new Promise((_, reject) => {
|
|
2816
|
+
timer = setTimeout(() => {
|
|
2817
|
+
reject(authorityUnavailable());
|
|
2818
|
+
controller.abort();
|
|
2819
|
+
reader?.cancel().catch(() => {});
|
|
2820
|
+
}, timeoutMs);
|
|
2821
|
+
});
|
|
2822
|
+
const exchange = async () => {
|
|
2823
|
+
const response = await fetchImpl(url, {
|
|
2824
|
+
method: "POST",
|
|
2825
|
+
headers: {
|
|
2826
|
+
authorization: `Bearer ${clientAssertion}`,
|
|
2827
|
+
accept: "application/json"
|
|
2828
|
+
},
|
|
2829
|
+
credentials: "omit",
|
|
2830
|
+
cache: "no-store",
|
|
2831
|
+
redirect: "manual",
|
|
2832
|
+
signal: controller.signal
|
|
2833
|
+
});
|
|
2834
|
+
if (controller.signal.aborted) {
|
|
2835
|
+
response.body?.cancel().catch(() => {});
|
|
2836
|
+
throw authorityUnavailable();
|
|
2837
|
+
}
|
|
2838
|
+
if (!response.body) throw authorityUnavailable();
|
|
2839
|
+
reader = response.body.getReader();
|
|
2840
|
+
const contentType = response.headers.get("content-type")?.split(";", 1)[0]?.trim().toLowerCase();
|
|
2841
|
+
const length = response.headers.get("content-length");
|
|
2842
|
+
if (contentType !== "application/json" || length !== null && (!/^\d+$/.test(length) || Number(length) > MAX_BYTES)) throw authorityUnavailable();
|
|
2843
|
+
const bytes = new Uint8Array(MAX_BYTES);
|
|
2844
|
+
let size = 0;
|
|
2845
|
+
while (true) {
|
|
2846
|
+
const chunk = await reader.read();
|
|
2847
|
+
if (chunk.done) break;
|
|
2848
|
+
if (controller.signal.aborted || size + chunk.value.byteLength > MAX_BYTES) throw authorityUnavailable();
|
|
2849
|
+
bytes.set(chunk.value, size);
|
|
2850
|
+
size += chunk.value.byteLength;
|
|
2851
|
+
}
|
|
2852
|
+
const value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(0, size)));
|
|
2853
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw authorityUnavailable();
|
|
2854
|
+
const record = value;
|
|
2855
|
+
if (response.status !== 200) {
|
|
2856
|
+
if (Object.keys(record).length !== 2 || !("code" in record) || !("message" in record)) throw authorityUnavailable();
|
|
2857
|
+
if (response.status === 401 && record.code === "UNAUTHORIZED" && record.message === "The ecosystem client assertion is invalid.") {
|
|
2858
|
+
authorityError = new AuthError("authentication_required", 401);
|
|
2859
|
+
throw authorityError;
|
|
2860
|
+
}
|
|
2861
|
+
const retryAfter = response.headers.get("retry-after");
|
|
2862
|
+
if (response.status === 429 && record.code === "TOO_MANY_REQUESTS" && record.message === "Ecosystem credential exchanges are temporarily limited." && retryAfter !== null && /^(?:[1-9]|[1-5][0-9]|60)$/.test(retryAfter)) {
|
|
2863
|
+
authorityError = new AuthError("auth_request_rate_limited", 429, Number(retryAfter));
|
|
2864
|
+
throw authorityError;
|
|
2865
|
+
}
|
|
2866
|
+
throw authorityUnavailable();
|
|
2867
|
+
}
|
|
2868
|
+
if (Object.keys(record).length !== 3 || record.tokenType !== "Bearer" || record.expiresIn !== 300 || !isCompactCredential(record.token)) throw authorityUnavailable();
|
|
2869
|
+
const expiresAt = new Date(Math.floor(startedAt / 1e3) * 1e3 + 3e5);
|
|
2870
|
+
const completedAt = now();
|
|
2871
|
+
if (!Number.isSafeInteger(completedAt) || completedAt < 0 || completedAt >= expiresAt.getTime()) throw authorityUnavailable();
|
|
2872
|
+
return {
|
|
2873
|
+
tokenType: "Bearer",
|
|
2874
|
+
token: record.token,
|
|
2875
|
+
expiresAt
|
|
2876
|
+
};
|
|
2877
|
+
};
|
|
2878
|
+
exchangeStarted = true;
|
|
2879
|
+
return await Promise.race([exchange().finally(() => {
|
|
2880
|
+
inFlight = false;
|
|
2881
|
+
}), deadline]);
|
|
2882
|
+
} catch (error) {
|
|
2883
|
+
if (authorityError && error === authorityError) throw authorityError;
|
|
2884
|
+
throw authorityUnavailable();
|
|
2885
|
+
} finally {
|
|
2886
|
+
clearTimeout(timer);
|
|
2887
|
+
controller.abort();
|
|
2888
|
+
reader?.cancel().catch(() => {});
|
|
2889
|
+
if (!exchangeStarted) inFlight = false;
|
|
1469
2890
|
}
|
|
1470
|
-
}
|
|
1471
|
-
await reader.cancel();
|
|
1472
|
-
throw error;
|
|
1473
|
-
} finally {
|
|
1474
|
-
reader.releaseLock();
|
|
1475
|
-
}
|
|
1476
|
-
const bytes = new Uint8Array(size);
|
|
1477
|
-
let offset = 0;
|
|
1478
|
-
for (const chunk of chunks) {
|
|
1479
|
-
bytes.set(chunk, offset);
|
|
1480
|
-
offset += chunk.byteLength;
|
|
1481
|
-
}
|
|
1482
|
-
try {
|
|
1483
|
-
return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
|
|
1484
|
-
} catch {
|
|
1485
|
-
throw authorityUnavailable();
|
|
1486
|
-
}
|
|
2891
|
+
} };
|
|
1487
2892
|
}
|
|
1488
2893
|
//#endregion
|
|
1489
2894
|
//#region src/server.ts
|
|
@@ -1566,6 +2971,21 @@ function createServerAuth(options) {
|
|
|
1566
2971
|
const member = normalizeIdInput(memberId);
|
|
1567
2972
|
return organizationRead(`${organization}/members/${member}/authority`, void 0, (value) => normalizeOrganizationMemberAuthority(value, organization, member));
|
|
1568
2973
|
},
|
|
2974
|
+
async createOrganization(name, slug, idempotencyKey) {
|
|
2975
|
+
const body = normalizeOrganizationCreationInput(name, slug, idempotencyKey);
|
|
2976
|
+
return normalizeCreatedOrganization(await requestJson(joinURL(authOrigin, "api/v1/auth/organizations"), {
|
|
2977
|
+
fetch: fetchImpl,
|
|
2978
|
+
timeoutMs,
|
|
2979
|
+
method: "POST",
|
|
2980
|
+
credentials,
|
|
2981
|
+
headers: {
|
|
2982
|
+
...authHeaders(!authorization),
|
|
2983
|
+
"content-type": "application/json"
|
|
2984
|
+
},
|
|
2985
|
+
body,
|
|
2986
|
+
mapError: fromOrganizationMutationAuthorityError
|
|
2987
|
+
}));
|
|
2988
|
+
},
|
|
1569
2989
|
async createOrganizationTeam(organizationId, name, idempotencyKey) {
|
|
1570
2990
|
const id = normalizeIdInput(organizationId);
|
|
1571
2991
|
const body = normalizeOrganizationTeamCreationInput(name, idempotencyKey);
|
|
@@ -1634,6 +3054,41 @@ function createServerAuth(options) {
|
|
|
1634
3054
|
mapError: fromOrganizationInvitationAdministrationError
|
|
1635
3055
|
}));
|
|
1636
3056
|
},
|
|
3057
|
+
async removeOrganizationMember(organizationId, memberId, idempotencyKey) {
|
|
3058
|
+
if (authorization) throw new AuthError("authentication_required", 401);
|
|
3059
|
+
const organization = normalizeIdInput(organizationId);
|
|
3060
|
+
const member = normalizeIdInput(memberId);
|
|
3061
|
+
const body = normalizeOrganizationMembershipRemovalInput(idempotencyKey);
|
|
3062
|
+
return normalizeRemovedOrganizationMember(await requestJson(joinURL(authOrigin, "api/v1/auth/organizations", organization, "members", member, "remove"), {
|
|
3063
|
+
fetch: fetchImpl,
|
|
3064
|
+
timeoutMs,
|
|
3065
|
+
method: "POST",
|
|
3066
|
+
credentials,
|
|
3067
|
+
headers: {
|
|
3068
|
+
...authHeaders(),
|
|
3069
|
+
"content-type": "application/json"
|
|
3070
|
+
},
|
|
3071
|
+
body,
|
|
3072
|
+
mapError: fromOrganizationMembershipRemovalError
|
|
3073
|
+
}));
|
|
3074
|
+
},
|
|
3075
|
+
async leaveOrganization(organizationId, idempotencyKey) {
|
|
3076
|
+
if (authorization) throw new AuthError("authentication_required", 401);
|
|
3077
|
+
const organization = normalizeIdInput(organizationId);
|
|
3078
|
+
const body = normalizeOrganizationMembershipRemovalInput(idempotencyKey);
|
|
3079
|
+
return normalizeOrganizationDeparture(await requestJson(joinURL(authOrigin, "api/v1/auth/organizations", organization, "leave"), {
|
|
3080
|
+
fetch: fetchImpl,
|
|
3081
|
+
timeoutMs,
|
|
3082
|
+
method: "POST",
|
|
3083
|
+
credentials,
|
|
3084
|
+
headers: {
|
|
3085
|
+
...authHeaders(),
|
|
3086
|
+
"content-type": "application/json"
|
|
3087
|
+
},
|
|
3088
|
+
body,
|
|
3089
|
+
mapError: fromOrganizationMembershipRemovalError
|
|
3090
|
+
}));
|
|
3091
|
+
},
|
|
1637
3092
|
async updateOrganizationDisplay(organizationId, input) {
|
|
1638
3093
|
const id = normalizeIdInput(organizationId);
|
|
1639
3094
|
const desired = normalizeOrganizationDisplayInput(input);
|
|
@@ -1734,6 +3189,21 @@ function createServerAuth(options) {
|
|
|
1734
3189
|
body: { workspace }
|
|
1735
3190
|
}), now());
|
|
1736
3191
|
},
|
|
3192
|
+
async getUserApiCredential(input) {
|
|
3193
|
+
const applicationId = userApiApplication(input);
|
|
3194
|
+
const startedAt = now();
|
|
3195
|
+
return normalizeUserApiCredential(await requestJson(joinURL(authOrigin, "api/v1/auth/user-api-credential"), {
|
|
3196
|
+
fetch: fetchImpl,
|
|
3197
|
+
timeoutMs,
|
|
3198
|
+
method: "POST",
|
|
3199
|
+
credentials,
|
|
3200
|
+
headers: {
|
|
3201
|
+
...authHeaders(),
|
|
3202
|
+
"content-type": "application/json; charset=utf-8"
|
|
3203
|
+
},
|
|
3204
|
+
body: { applicationId }
|
|
3205
|
+
}), startedAt);
|
|
3206
|
+
},
|
|
1737
3207
|
async signOut() {
|
|
1738
3208
|
let response;
|
|
1739
3209
|
try {
|
|
@@ -1785,4 +3255,4 @@ function authAuthorizationHeader(value) {
|
|
|
1785
3255
|
return value;
|
|
1786
3256
|
}
|
|
1787
3257
|
//#endregion
|
|
1788
|
-
export { AuthError, createDriveProvisioningAuth, createDriveRecipientAuth, createIdentityResolverAuth, createServerAuth };
|
|
3258
|
+
export { AuthError, createDriveProvisioningAuth, createDriveRecipientAuth, createIdentityResolverAuth, createMembershipResolverAuth, createServerAuth, createUserApiVerifier };
|