@forklaunch/core 0.13.1 → 0.13.2

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.js CHANGED
@@ -159,22 +159,44 @@ function isTypedHandler(maybeTypedHandler) {
159
159
  var import_common2 = require("@forklaunch/common");
160
160
 
161
161
  // src/http/discriminateAuthMethod.ts
162
+ var import_crypto = require("crypto");
162
163
  var import_jose = require("jose");
164
+
165
+ // src/http/guards/isBasicAuthMethod.ts
166
+ function isBasicAuthMethod(maybeBasicAuthMethod) {
167
+ return typeof maybeBasicAuthMethod === "object" && maybeBasicAuthMethod !== null && "basic" in maybeBasicAuthMethod && maybeBasicAuthMethod.basic != null;
168
+ }
169
+
170
+ // src/http/guards/isHmacMethod.ts
171
+ function isHmacMethod(maybeHmacMethod) {
172
+ return typeof maybeHmacMethod === "object" && maybeHmacMethod !== null && "secretKey" in maybeHmacMethod && maybeHmacMethod.secretKey != null;
173
+ }
174
+
175
+ // src/http/guards/isJwtAuthMethod.ts
176
+ function isJwtAuthMethod(maybeJwtAuthMethod) {
177
+ return typeof maybeJwtAuthMethod === "object" && maybeJwtAuthMethod !== null && "jwt" in maybeJwtAuthMethod && maybeJwtAuthMethod.jwt != null;
178
+ }
179
+
180
+ // src/http/discriminateAuthMethod.ts
163
181
  async function discriminateAuthMethod(auth) {
164
- if ("basic" in auth) {
165
- return {
182
+ let authMethod;
183
+ if (isBasicAuthMethod(auth)) {
184
+ authMethod = {
166
185
  type: "basic",
167
186
  auth: {
168
187
  decodeResource: auth.decodeResource,
169
188
  login: auth.basic.login
170
189
  }
171
190
  };
172
- } else if ("jwt" in auth && auth.jwt != null) {
191
+ } else if (isJwtAuthMethod(auth)) {
173
192
  const jwt = auth.jwt;
174
193
  let verificationFunction;
175
- if ("privateKey" in jwt) {
194
+ if ("signatureKey" in jwt) {
176
195
  verificationFunction = async (token) => {
177
- const { payload } = await (0, import_jose.jwtVerify)(token, Buffer.from(jwt.privateKey));
196
+ const { payload } = await (0, import_jose.jwtVerify)(
197
+ token,
198
+ Buffer.from(jwt.signatureKey)
199
+ );
178
200
  return payload;
179
201
  };
180
202
  } else {
@@ -182,7 +204,7 @@ async function discriminateAuthMethod(auth) {
182
204
  if ("jwksPublicKeyUrl" in jwt) {
183
205
  const jwksResponse = await fetch(jwt.jwksPublicKeyUrl);
184
206
  jwks = (await jwksResponse.json()).keys;
185
- } else {
207
+ } else if ("jwksPublicKey" in jwt) {
186
208
  jwks = [jwt.jwksPublicKey];
187
209
  }
188
210
  verificationFunction = async (token) => {
@@ -196,35 +218,35 @@ async function discriminateAuthMethod(auth) {
196
218
  }
197
219
  };
198
220
  }
199
- return {
221
+ authMethod = {
200
222
  type: "jwt",
201
223
  auth: {
202
224
  decodeResource: auth.decodeResource,
203
225
  verificationFunction
204
226
  }
205
227
  };
206
- } else if ("secretKey" in auth) {
207
- return {
208
- type: "system",
209
- auth: {
210
- secretKey: auth.secretKey
211
- }
212
- };
213
- } else {
214
- return {
215
- type: "jwt",
228
+ } else if (isHmacMethod(auth)) {
229
+ authMethod = {
230
+ type: "hmac",
216
231
  auth: {
217
- decodeResource: auth.decodeResource,
218
- verificationFunction: async (token) => {
219
- const { payload } = await (0, import_jose.jwtVerify)(
220
- token,
221
- Buffer.from(process.env.JWT_SECRET_KEY)
222
- );
223
- return payload;
232
+ secretKeys: auth.hmac.secretKeys,
233
+ verificationFunction: async (method, path, body, timestamp, nonce, signature, secretKey) => {
234
+ const hmac = (0, import_crypto.createHmac)("sha256", secretKey);
235
+ hmac.update(`${method}
236
+ ${path}
237
+ ${body}
238
+ ${timestamp}
239
+ ${nonce}`);
240
+ const digest = hmac.digest("base64");
241
+ return digest === signature;
224
242
  }
225
243
  }
226
244
  };
227
245
  }
246
+ if (authMethod == null) {
247
+ throw new Error("Invalid auth method");
248
+ }
249
+ return authMethod;
228
250
  }
229
251
 
230
252
  // src/http/guards/hasPermissionChecks.ts
@@ -242,19 +264,14 @@ function hasScopeChecks(maybePermissionedAuth) {
242
264
  return typeof maybePermissionedAuth === "object" && maybePermissionedAuth !== null && "requiredScope" in maybePermissionedAuth && maybePermissionedAuth.requiredScope != null;
243
265
  }
244
266
 
245
- // src/http/guards/isSystemAuthMethod.ts
246
- function isSystemAuthMethod(maybeSystemAuthMethod) {
247
- return typeof maybeSystemAuthMethod === "object" && maybeSystemAuthMethod !== null && "secretKey" in maybeSystemAuthMethod;
248
- }
249
-
250
267
  // src/http/middleware/request/auth.middleware.ts
251
268
  var invalidAuthorizationTokenFormat = [
252
269
  401,
253
270
  "Invalid Authorization token format."
254
271
  ];
255
- var invalidAuthorizationSubject = [
272
+ var invalidAuthorizationSignature = [
256
273
  403,
257
- "Invalid Authorization subject."
274
+ "Invalid Authorization signature."
258
275
  ];
259
276
  var invalidAuthorizationTokenPermissions = [
260
277
  403,
@@ -281,6 +298,16 @@ var authorizationTokenRequired = [
281
298
  401,
282
299
  "Authorization token required."
283
300
  ];
301
+ var invalidInstantiation = [
302
+ 500,
303
+ "Invalid instantiation of authorization method."
304
+ ];
305
+ function parseHmacTokenPart(part, expectedKey) {
306
+ if (!part) return void 0;
307
+ const [key, ...rest] = part.split("=");
308
+ if (key !== expectedKey || rest.length === 0) return void 0;
309
+ return rest.join("=");
310
+ }
284
311
  async function checkAuthorizationToken(authorizationMethod, globalOptions, authorizationToken, req) {
285
312
  if (authorizationMethod == null) {
286
313
  return void 0;
@@ -292,27 +319,54 @@ async function checkAuthorizationToken(authorizationMethod, globalOptions, autho
292
319
  if (authorizationToken == null) {
293
320
  return authorizationTokenRequired;
294
321
  }
295
- const [tokenPrefix, token] = authorizationToken.split(" ");
322
+ const [tokenPrefix, ...tokenParts] = authorizationToken.split(" ");
323
+ if (!tokenParts.length || !tokenPrefix) {
324
+ return invalidAuthorizationTokenFormat;
325
+ }
296
326
  let resourceId;
297
327
  const { type, auth } = await discriminateAuthMethod(
298
328
  collapsedAuthorizationMethod
299
329
  );
300
330
  switch (type) {
301
- case "system": {
302
- if (token !== auth.secretKey || tokenPrefix !== collapsedAuthorizationMethod.tokenPrefix) {
331
+ case "hmac": {
332
+ const [keyId, timestamp, nonce, signature] = tokenParts;
333
+ if (keyId == null || timestamp == null || nonce == null || signature == null || tokenPrefix !== (collapsedAuthorizationMethod.tokenPrefix ?? "HMAC")) {
303
334
  return invalidAuthorizationToken;
304
335
  }
336
+ if (!collapsedAuthorizationMethod.hmac?.secretKeys) {
337
+ return invalidInstantiation;
338
+ }
339
+ const parsedKeyId = parseHmacTokenPart(keyId, "keyId");
340
+ const parsedTimestamp = parseHmacTokenPart(timestamp, "ts");
341
+ const parsedNonce = parseHmacTokenPart(nonce, "nonce");
342
+ const parsedSignature = parseHmacTokenPart(signature, "signature");
343
+ if (!parsedKeyId || !parsedTimestamp || !parsedNonce || !parsedSignature) {
344
+ return invalidAuthorizationTokenFormat;
345
+ }
346
+ const verificationResult = await auth.verificationFunction(
347
+ req?.method ?? "",
348
+ req?.path ?? "",
349
+ JSON.stringify(req?.body ?? ""),
350
+ parsedTimestamp,
351
+ parsedNonce,
352
+ parsedSignature,
353
+ collapsedAuthorizationMethod.hmac.secretKeys[parsedKeyId]
354
+ );
355
+ if (!verificationResult) {
356
+ return invalidAuthorizationSignature;
357
+ }
305
358
  resourceId = null;
306
359
  break;
307
360
  }
308
361
  case "jwt": {
362
+ const [token] = tokenParts;
309
363
  if (tokenPrefix !== (collapsedAuthorizationMethod.tokenPrefix ?? "Bearer")) {
310
364
  return invalidAuthorizationTokenFormat;
311
365
  }
312
366
  try {
313
367
  const decodedJwt = "decodeResource" in auth && auth.decodeResource ? await auth.decodeResource(token) : "verificationFunction" in auth && auth.verificationFunction ? await auth.verificationFunction(token) : void 0;
314
368
  if (!decodedJwt) {
315
- return invalidAuthorizationSubject;
369
+ return invalidAuthorizationToken;
316
370
  }
317
371
  resourceId = decodedJwt;
318
372
  } catch (error) {
@@ -322,6 +376,7 @@ async function checkAuthorizationToken(authorizationMethod, globalOptions, autho
322
376
  break;
323
377
  }
324
378
  case "basic": {
379
+ const [token] = tokenParts;
325
380
  if (tokenPrefix !== (collapsedAuthorizationMethod.tokenPrefix ?? "Basic")) {
326
381
  return invalidAuthorizationTokenFormat;
327
382
  }
@@ -345,9 +400,12 @@ async function checkAuthorizationToken(authorizationMethod, globalOptions, autho
345
400
  (0, import_common2.isNever)(type);
346
401
  return [401, "Invalid Authorization method."];
347
402
  }
348
- if (isSystemAuthMethod(collapsedAuthorizationMethod) || resourceId == null) {
403
+ if (isHmacMethod(collapsedAuthorizationMethod) && resourceId == null) {
349
404
  return;
350
405
  }
406
+ if (resourceId == null) {
407
+ return invalidAuthorizationToken;
408
+ }
351
409
  if (hasScopeChecks(collapsedAuthorizationMethod)) {
352
410
  if (collapsedAuthorizationMethod.surfaceScopes) {
353
411
  const resourceScopes = await collapsedAuthorizationMethod.surfaceScopes(
@@ -1345,13 +1403,15 @@ var ForklaunchExpressLikeRouter = class _ForklaunchExpressLikeRouter {
1345
1403
  const maybeTypedHandler = middlewareOrMiddlewareAndTypedHandler[middlewareOrMiddlewareAndTypedHandler.length - 1];
1346
1404
  if (isTypedHandler(maybeTypedHandler)) {
1347
1405
  const { contractDetails, handlers } = maybeTypedHandler;
1348
- const router = this.registerRoute(
1349
- method,
1350
- path,
1351
- registrationMethod,
1352
- contractDetails,
1353
- ...middlewareOrMiddlewareAndTypedHandler.concat(handlers)
1354
- );
1406
+ const finalHandlers = [];
1407
+ if (isExpressLikeSchemaHandler(contractDetailsOrMiddlewareOrTypedHandler)) {
1408
+ finalHandlers.push(
1409
+ contractDetailsOrMiddlewareOrTypedHandler
1410
+ );
1411
+ }
1412
+ finalHandlers.push(...middlewareOrMiddlewareAndTypedHandler);
1413
+ finalHandlers.push(...handlers);
1414
+ const router = this.registerRoute(method, path, registrationMethod, contractDetails, ...finalHandlers);
1355
1415
  return router;
1356
1416
  } else {
1357
1417
  if (isExpressLikeSchemaHandler(contractDetailsOrMiddlewareOrTypedHandler) || isTypedHandler(contractDetailsOrMiddlewareOrTypedHandler)) {
@@ -1560,6 +1620,10 @@ var ForklaunchExpressLikeRouter = class _ForklaunchExpressLikeRouter {
1560
1620
  ].forEach((arg) => {
1561
1621
  if (isForklaunchRouter(arg)) {
1562
1622
  this.routers.push(arg);
1623
+ arg.routerOptions = {
1624
+ ...this.routerOptions ?? {},
1625
+ ...arg.routerOptions ?? {}
1626
+ };
1563
1627
  }
1564
1628
  });
1565
1629
  return this.registerNestableMiddlewareHandler(