@forklaunch/core 0.14.9 → 0.14.11
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/lib/http/index.d.mts +87 -73
- package/lib/http/index.d.ts +87 -73
- package/lib/http/index.js +60 -26
- package/lib/http/index.js.map +1 -1
- package/lib/http/index.mjs +62 -26
- package/lib/http/index.mjs.map +1 -1
- package/package.json +9 -9
package/lib/http/index.js
CHANGED
@@ -158,6 +158,7 @@ function isTypedHandler(maybeTypedHandler) {
|
|
158
158
|
|
159
159
|
// src/http/middleware/request/auth.middleware.ts
|
160
160
|
var import_common3 = require("@forklaunch/common");
|
161
|
+
var import_validator = require("@forklaunch/validator");
|
161
162
|
|
162
163
|
// src/http/discriminateAuthMethod.ts
|
163
164
|
var import_jose = require("jose");
|
@@ -176,10 +177,12 @@ function createHmacToken({
|
|
176
177
|
const hmac = (0, import_crypto.createHmac)("sha256", secretKey);
|
177
178
|
const bodyString = body ? `${(0, import_common2.safeStringify)(body)}
|
178
179
|
` : void 0;
|
179
|
-
hmac.update(
|
180
|
+
hmac.update(
|
181
|
+
`${method}
|
180
182
|
${path}
|
181
|
-
${bodyString}${timestamp}
|
182
|
-
${nonce}`
|
183
|
+
${bodyString}${timestamp.toISOString()}
|
184
|
+
${nonce}`
|
185
|
+
);
|
183
186
|
return hmac.digest("base64");
|
184
187
|
}
|
185
188
|
|
@@ -199,6 +202,12 @@ function isJwtAuthMethod(maybeJwtAuthMethod) {
|
|
199
202
|
}
|
200
203
|
|
201
204
|
// src/http/discriminateAuthMethod.ts
|
205
|
+
var DEFAULT_TTL = 60 * 1e3 * 5;
|
206
|
+
var memoizedJwks = {
|
207
|
+
value: null,
|
208
|
+
lastUpdated: null,
|
209
|
+
ttl: DEFAULT_TTL
|
210
|
+
};
|
202
211
|
async function discriminateAuthMethod(auth) {
|
203
212
|
let authMethod;
|
204
213
|
if (isBasicAuthMethod(auth)) {
|
@@ -223,8 +232,17 @@ async function discriminateAuthMethod(auth) {
|
|
223
232
|
} else {
|
224
233
|
let jwks;
|
225
234
|
if ("jwksPublicKeyUrl" in jwt) {
|
226
|
-
|
227
|
-
|
235
|
+
if (memoizedJwks.value && memoizedJwks.lastUpdated && Date.now() - memoizedJwks.lastUpdated.getTime() < memoizedJwks.ttl) {
|
236
|
+
jwks = memoizedJwks.value;
|
237
|
+
} else {
|
238
|
+
const jwksResponse = await fetch(jwt.jwksPublicKeyUrl);
|
239
|
+
jwks = (await jwksResponse.json()).keys;
|
240
|
+
memoizedJwks.value = jwks;
|
241
|
+
memoizedJwks.lastUpdated = /* @__PURE__ */ new Date();
|
242
|
+
memoizedJwks.ttl = parseInt(
|
243
|
+
jwksResponse.headers.get("cache-control")?.split("=")[1] ?? `${DEFAULT_TTL / 1e3}`
|
244
|
+
) * 1e3;
|
245
|
+
}
|
228
246
|
} else if ("jwksPublicKey" in jwt) {
|
229
247
|
jwks = [jwt.jwksPublicKey];
|
230
248
|
}
|
@@ -234,6 +252,9 @@ async function discriminateAuthMethod(auth) {
|
|
234
252
|
const { payload } = await (0, import_jose.jwtVerify)(token, key);
|
235
253
|
return payload;
|
236
254
|
} catch {
|
255
|
+
memoizedJwks.value = null;
|
256
|
+
memoizedJwks.lastUpdated = null;
|
257
|
+
memoizedJwks.ttl = DEFAULT_TTL;
|
237
258
|
continue;
|
238
259
|
}
|
239
260
|
}
|
@@ -337,7 +358,7 @@ function parseHmacTokenPart(part, expectedKey) {
|
|
337
358
|
if (key !== expectedKey || rest.length === 0) return void 0;
|
338
359
|
return rest.join("=");
|
339
360
|
}
|
340
|
-
async function checkAuthorizationToken(
|
361
|
+
async function checkAuthorizationToken(req, authorizationMethod, authorizationToken, globalOptions) {
|
341
362
|
if (authorizationMethod == null) {
|
342
363
|
return void 0;
|
343
364
|
}
|
@@ -352,7 +373,7 @@ async function checkAuthorizationToken(authorizationMethod, globalOptions, autho
|
|
352
373
|
if (!tokenParts.length || !tokenPrefix) {
|
353
374
|
return invalidAuthorizationTokenFormat;
|
354
375
|
}
|
355
|
-
let
|
376
|
+
let sessionPayload;
|
356
377
|
const { type, auth } = await discriminateAuthMethod(
|
357
378
|
collapsedAuthorizationMethod
|
358
379
|
);
|
@@ -376,7 +397,7 @@ async function checkAuthorizationToken(authorizationMethod, globalOptions, autho
|
|
376
397
|
method: req?.method ?? "",
|
377
398
|
path: req?.path ?? "",
|
378
399
|
body: req?.body,
|
379
|
-
timestamp: parsedTimestamp,
|
400
|
+
timestamp: new Date(parsedTimestamp),
|
380
401
|
nonce: parsedNonce,
|
381
402
|
signature: parsedSignature,
|
382
403
|
secretKey: collapsedAuthorizationMethod.hmac.secretKeys[parsedKeyId]
|
@@ -384,7 +405,7 @@ async function checkAuthorizationToken(authorizationMethod, globalOptions, autho
|
|
384
405
|
if (!verificationResult) {
|
385
406
|
return invalidAuthorizationSignature;
|
386
407
|
}
|
387
|
-
|
408
|
+
sessionPayload = null;
|
388
409
|
break;
|
389
410
|
}
|
390
411
|
case "jwt": {
|
@@ -397,7 +418,7 @@ async function checkAuthorizationToken(authorizationMethod, globalOptions, autho
|
|
397
418
|
if (!decodedJwt) {
|
398
419
|
return invalidAuthorizationToken;
|
399
420
|
}
|
400
|
-
|
421
|
+
sessionPayload = decodedJwt;
|
401
422
|
} catch (error) {
|
402
423
|
req?.openTelemetryCollector.error(error);
|
403
424
|
return invalidAuthorizationToken;
|
@@ -410,7 +431,7 @@ async function checkAuthorizationToken(authorizationMethod, globalOptions, autho
|
|
410
431
|
return invalidAuthorizationTokenFormat;
|
411
432
|
}
|
412
433
|
if (auth.decodeResource) {
|
413
|
-
|
434
|
+
sessionPayload = await auth.decodeResource(token);
|
414
435
|
} else {
|
415
436
|
const [username, password] = Buffer.from(token, "base64").toString("utf-8").split(":");
|
416
437
|
if (!username || !password) {
|
@@ -419,7 +440,7 @@ async function checkAuthorizationToken(authorizationMethod, globalOptions, autho
|
|
419
440
|
if (!auth.login(username, password)) {
|
420
441
|
return invalidAuthorizationLogin;
|
421
442
|
}
|
422
|
-
|
443
|
+
sessionPayload = {
|
423
444
|
sub: username
|
424
445
|
};
|
425
446
|
}
|
@@ -429,16 +450,29 @@ async function checkAuthorizationToken(authorizationMethod, globalOptions, autho
|
|
429
450
|
(0, import_common3.isNever)(type);
|
430
451
|
return [401, "Invalid Authorization method."];
|
431
452
|
}
|
432
|
-
if (isHmacMethod(collapsedAuthorizationMethod) &&
|
453
|
+
if (isHmacMethod(collapsedAuthorizationMethod) && sessionPayload == null) {
|
433
454
|
return;
|
434
455
|
}
|
435
|
-
if (
|
456
|
+
if (sessionPayload == null) {
|
436
457
|
return invalidAuthorizationToken;
|
437
458
|
}
|
459
|
+
req.session = sessionPayload;
|
460
|
+
if (collapsedAuthorizationMethod.sessionSchema) {
|
461
|
+
const parsedSession = req.schemaValidator.parse(
|
462
|
+
collapsedAuthorizationMethod.sessionSchema,
|
463
|
+
sessionPayload
|
464
|
+
);
|
465
|
+
if (!parsedSession.ok) {
|
466
|
+
return [
|
467
|
+
400,
|
468
|
+
`Invalid session: ${(0, import_validator.prettyPrintParseErrors)(parsedSession.errors, "Session")}`
|
469
|
+
];
|
470
|
+
}
|
471
|
+
}
|
438
472
|
if (hasScopeChecks(collapsedAuthorizationMethod)) {
|
439
473
|
if (collapsedAuthorizationMethod.surfaceScopes) {
|
440
474
|
const resourceScopes = await collapsedAuthorizationMethod.surfaceScopes(
|
441
|
-
|
475
|
+
sessionPayload,
|
442
476
|
req
|
443
477
|
);
|
444
478
|
if (collapsedAuthorizationMethod.scopeHeirarchy) {
|
@@ -457,7 +491,7 @@ async function checkAuthorizationToken(authorizationMethod, globalOptions, autho
|
|
457
491
|
return [500, "No permission surfacing function provided."];
|
458
492
|
}
|
459
493
|
const resourcePermissions = await collapsedAuthorizationMethod.surfacePermissions(
|
460
|
-
|
494
|
+
sessionPayload,
|
461
495
|
req
|
462
496
|
);
|
463
497
|
if ("allowedPermissions" in collapsedAuthorizationMethod && collapsedAuthorizationMethod.allowedPermissions) {
|
@@ -479,7 +513,7 @@ async function checkAuthorizationToken(authorizationMethod, globalOptions, autho
|
|
479
513
|
return [500, "No role surfacing function provided."];
|
480
514
|
}
|
481
515
|
const resourceRoles = await collapsedAuthorizationMethod.surfaceRoles(
|
482
|
-
|
516
|
+
sessionPayload,
|
483
517
|
req
|
484
518
|
);
|
485
519
|
if ("allowedRoles" in collapsedAuthorizationMethod && collapsedAuthorizationMethod.allowedRoles) {
|
@@ -499,10 +533,10 @@ async function checkAuthorizationToken(authorizationMethod, globalOptions, autho
|
|
499
533
|
async function parseRequestAuth(req, res, next) {
|
500
534
|
const auth = req.contractDetails.auth;
|
501
535
|
const [error, message] = await checkAuthorizationToken(
|
536
|
+
req,
|
502
537
|
auth,
|
503
|
-
req._globalOptions?.()?.auth,
|
504
538
|
req.headers[auth?.headerName ?? "Authorization"] || req.headers[auth?.headerName ?? "authorization"],
|
505
|
-
req
|
539
|
+
req._globalOptions?.()?.auth
|
506
540
|
) ?? [];
|
507
541
|
if (error != null) {
|
508
542
|
res.type("text/plain");
|
@@ -871,7 +905,7 @@ function enrichDetails(path, contractDetails, requestSchema, responseSchemas, op
|
|
871
905
|
|
872
906
|
// src/http/middleware/request/parse.middleware.ts
|
873
907
|
var import_common8 = require("@forklaunch/common");
|
874
|
-
var
|
908
|
+
var import_validator2 = require("@forklaunch/validator");
|
875
909
|
|
876
910
|
// src/http/guards/hasSend.ts
|
877
911
|
function hasSend(res) {
|
@@ -909,7 +943,7 @@ function parse(req, res, next) {
|
|
909
943
|
req.version = version;
|
910
944
|
res.version = req.version;
|
911
945
|
} else {
|
912
|
-
runningParseErrors += (0,
|
946
|
+
runningParseErrors += (0, import_validator2.prettyPrintParseErrors)(
|
913
947
|
parsingResult.errors,
|
914
948
|
`Version ${version} request`
|
915
949
|
);
|
@@ -967,7 +1001,7 @@ function parse(req, res, next) {
|
|
967
1001
|
res.status(400);
|
968
1002
|
if (hasSend(res)) {
|
969
1003
|
res.send(
|
970
|
-
`${collectedParseErrors ?? (0,
|
1004
|
+
`${collectedParseErrors ?? (0, import_validator2.prettyPrintParseErrors)(parsedRequest.errors, "Request")}
|
971
1005
|
|
972
1006
|
Correlation id: ${req.context.correlationId ?? "No correlation ID"}`
|
973
1007
|
);
|
@@ -977,7 +1011,7 @@ Correlation id: ${req.context.correlationId ?? "No correlation ID"}`
|
|
977
1011
|
return;
|
978
1012
|
case "warning":
|
979
1013
|
req.openTelemetryCollector.warn(
|
980
|
-
collectedParseErrors ?? (0,
|
1014
|
+
collectedParseErrors ?? (0, import_validator2.prettyPrintParseErrors)(parsedRequest.errors, "Request")
|
981
1015
|
);
|
982
1016
|
break;
|
983
1017
|
case "none":
|
@@ -3261,7 +3295,7 @@ function generateMcpServer(schemaValidator, protocol, host, port, version, appli
|
|
3261
3295
|
}
|
3262
3296
|
|
3263
3297
|
// src/http/middleware/response/parse.middleware.ts
|
3264
|
-
var
|
3298
|
+
var import_validator3 = require("@forklaunch/validator");
|
3265
3299
|
|
3266
3300
|
// src/http/guards/isResponseCompiledSchema.ts
|
3267
3301
|
function isResponseCompiledSchema(schema) {
|
@@ -3322,13 +3356,13 @@ function parse2(req, res, next) {
|
|
3322
3356
|
);
|
3323
3357
|
const parseErrors = [];
|
3324
3358
|
if (!parsedHeaders.ok) {
|
3325
|
-
const headerErrors = (0,
|
3359
|
+
const headerErrors = (0, import_validator3.prettyPrintParseErrors)(parsedHeaders.errors, "Header");
|
3326
3360
|
if (headerErrors) {
|
3327
3361
|
parseErrors.push(headerErrors);
|
3328
3362
|
}
|
3329
3363
|
}
|
3330
3364
|
if (!parsedResponse.ok) {
|
3331
|
-
const responseErrors = (0,
|
3365
|
+
const responseErrors = (0, import_validator3.prettyPrintParseErrors)(
|
3332
3366
|
parsedResponse.errors,
|
3333
3367
|
"Response"
|
3334
3368
|
);
|