@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.
@@ -83,22 +83,44 @@ function isTypedHandler(maybeTypedHandler) {
83
83
  import { isNever } from "@forklaunch/common";
84
84
 
85
85
  // src/http/discriminateAuthMethod.ts
86
+ import { createHmac } from "crypto";
86
87
  import { jwtVerify } from "jose";
88
+
89
+ // src/http/guards/isBasicAuthMethod.ts
90
+ function isBasicAuthMethod(maybeBasicAuthMethod) {
91
+ return typeof maybeBasicAuthMethod === "object" && maybeBasicAuthMethod !== null && "basic" in maybeBasicAuthMethod && maybeBasicAuthMethod.basic != null;
92
+ }
93
+
94
+ // src/http/guards/isHmacMethod.ts
95
+ function isHmacMethod(maybeHmacMethod) {
96
+ return typeof maybeHmacMethod === "object" && maybeHmacMethod !== null && "secretKey" in maybeHmacMethod && maybeHmacMethod.secretKey != null;
97
+ }
98
+
99
+ // src/http/guards/isJwtAuthMethod.ts
100
+ function isJwtAuthMethod(maybeJwtAuthMethod) {
101
+ return typeof maybeJwtAuthMethod === "object" && maybeJwtAuthMethod !== null && "jwt" in maybeJwtAuthMethod && maybeJwtAuthMethod.jwt != null;
102
+ }
103
+
104
+ // src/http/discriminateAuthMethod.ts
87
105
  async function discriminateAuthMethod(auth) {
88
- if ("basic" in auth) {
89
- return {
106
+ let authMethod;
107
+ if (isBasicAuthMethod(auth)) {
108
+ authMethod = {
90
109
  type: "basic",
91
110
  auth: {
92
111
  decodeResource: auth.decodeResource,
93
112
  login: auth.basic.login
94
113
  }
95
114
  };
96
- } else if ("jwt" in auth && auth.jwt != null) {
115
+ } else if (isJwtAuthMethod(auth)) {
97
116
  const jwt = auth.jwt;
98
117
  let verificationFunction;
99
- if ("privateKey" in jwt) {
118
+ if ("signatureKey" in jwt) {
100
119
  verificationFunction = async (token) => {
101
- const { payload } = await jwtVerify(token, Buffer.from(jwt.privateKey));
120
+ const { payload } = await jwtVerify(
121
+ token,
122
+ Buffer.from(jwt.signatureKey)
123
+ );
102
124
  return payload;
103
125
  };
104
126
  } else {
@@ -106,7 +128,7 @@ async function discriminateAuthMethod(auth) {
106
128
  if ("jwksPublicKeyUrl" in jwt) {
107
129
  const jwksResponse = await fetch(jwt.jwksPublicKeyUrl);
108
130
  jwks = (await jwksResponse.json()).keys;
109
- } else {
131
+ } else if ("jwksPublicKey" in jwt) {
110
132
  jwks = [jwt.jwksPublicKey];
111
133
  }
112
134
  verificationFunction = async (token) => {
@@ -120,35 +142,35 @@ async function discriminateAuthMethod(auth) {
120
142
  }
121
143
  };
122
144
  }
123
- return {
145
+ authMethod = {
124
146
  type: "jwt",
125
147
  auth: {
126
148
  decodeResource: auth.decodeResource,
127
149
  verificationFunction
128
150
  }
129
151
  };
130
- } else if ("secretKey" in auth) {
131
- return {
132
- type: "system",
133
- auth: {
134
- secretKey: auth.secretKey
135
- }
136
- };
137
- } else {
138
- return {
139
- type: "jwt",
152
+ } else if (isHmacMethod(auth)) {
153
+ authMethod = {
154
+ type: "hmac",
140
155
  auth: {
141
- decodeResource: auth.decodeResource,
142
- verificationFunction: async (token) => {
143
- const { payload } = await jwtVerify(
144
- token,
145
- Buffer.from(process.env.JWT_SECRET_KEY)
146
- );
147
- return payload;
156
+ secretKeys: auth.hmac.secretKeys,
157
+ verificationFunction: async (method, path, body, timestamp, nonce, signature, secretKey) => {
158
+ const hmac = createHmac("sha256", secretKey);
159
+ hmac.update(`${method}
160
+ ${path}
161
+ ${body}
162
+ ${timestamp}
163
+ ${nonce}`);
164
+ const digest = hmac.digest("base64");
165
+ return digest === signature;
148
166
  }
149
167
  }
150
168
  };
151
169
  }
170
+ if (authMethod == null) {
171
+ throw new Error("Invalid auth method");
172
+ }
173
+ return authMethod;
152
174
  }
153
175
 
154
176
  // src/http/guards/hasPermissionChecks.ts
@@ -166,19 +188,14 @@ function hasScopeChecks(maybePermissionedAuth) {
166
188
  return typeof maybePermissionedAuth === "object" && maybePermissionedAuth !== null && "requiredScope" in maybePermissionedAuth && maybePermissionedAuth.requiredScope != null;
167
189
  }
168
190
 
169
- // src/http/guards/isSystemAuthMethod.ts
170
- function isSystemAuthMethod(maybeSystemAuthMethod) {
171
- return typeof maybeSystemAuthMethod === "object" && maybeSystemAuthMethod !== null && "secretKey" in maybeSystemAuthMethod;
172
- }
173
-
174
191
  // src/http/middleware/request/auth.middleware.ts
175
192
  var invalidAuthorizationTokenFormat = [
176
193
  401,
177
194
  "Invalid Authorization token format."
178
195
  ];
179
- var invalidAuthorizationSubject = [
196
+ var invalidAuthorizationSignature = [
180
197
  403,
181
- "Invalid Authorization subject."
198
+ "Invalid Authorization signature."
182
199
  ];
183
200
  var invalidAuthorizationTokenPermissions = [
184
201
  403,
@@ -205,6 +222,16 @@ var authorizationTokenRequired = [
205
222
  401,
206
223
  "Authorization token required."
207
224
  ];
225
+ var invalidInstantiation = [
226
+ 500,
227
+ "Invalid instantiation of authorization method."
228
+ ];
229
+ function parseHmacTokenPart(part, expectedKey) {
230
+ if (!part) return void 0;
231
+ const [key, ...rest] = part.split("=");
232
+ if (key !== expectedKey || rest.length === 0) return void 0;
233
+ return rest.join("=");
234
+ }
208
235
  async function checkAuthorizationToken(authorizationMethod, globalOptions, authorizationToken, req) {
209
236
  if (authorizationMethod == null) {
210
237
  return void 0;
@@ -216,27 +243,54 @@ async function checkAuthorizationToken(authorizationMethod, globalOptions, autho
216
243
  if (authorizationToken == null) {
217
244
  return authorizationTokenRequired;
218
245
  }
219
- const [tokenPrefix, token] = authorizationToken.split(" ");
246
+ const [tokenPrefix, ...tokenParts] = authorizationToken.split(" ");
247
+ if (!tokenParts.length || !tokenPrefix) {
248
+ return invalidAuthorizationTokenFormat;
249
+ }
220
250
  let resourceId;
221
251
  const { type, auth } = await discriminateAuthMethod(
222
252
  collapsedAuthorizationMethod
223
253
  );
224
254
  switch (type) {
225
- case "system": {
226
- if (token !== auth.secretKey || tokenPrefix !== collapsedAuthorizationMethod.tokenPrefix) {
255
+ case "hmac": {
256
+ const [keyId, timestamp, nonce, signature] = tokenParts;
257
+ if (keyId == null || timestamp == null || nonce == null || signature == null || tokenPrefix !== (collapsedAuthorizationMethod.tokenPrefix ?? "HMAC")) {
227
258
  return invalidAuthorizationToken;
228
259
  }
260
+ if (!collapsedAuthorizationMethod.hmac?.secretKeys) {
261
+ return invalidInstantiation;
262
+ }
263
+ const parsedKeyId = parseHmacTokenPart(keyId, "keyId");
264
+ const parsedTimestamp = parseHmacTokenPart(timestamp, "ts");
265
+ const parsedNonce = parseHmacTokenPart(nonce, "nonce");
266
+ const parsedSignature = parseHmacTokenPart(signature, "signature");
267
+ if (!parsedKeyId || !parsedTimestamp || !parsedNonce || !parsedSignature) {
268
+ return invalidAuthorizationTokenFormat;
269
+ }
270
+ const verificationResult = await auth.verificationFunction(
271
+ req?.method ?? "",
272
+ req?.path ?? "",
273
+ JSON.stringify(req?.body ?? ""),
274
+ parsedTimestamp,
275
+ parsedNonce,
276
+ parsedSignature,
277
+ collapsedAuthorizationMethod.hmac.secretKeys[parsedKeyId]
278
+ );
279
+ if (!verificationResult) {
280
+ return invalidAuthorizationSignature;
281
+ }
229
282
  resourceId = null;
230
283
  break;
231
284
  }
232
285
  case "jwt": {
286
+ const [token] = tokenParts;
233
287
  if (tokenPrefix !== (collapsedAuthorizationMethod.tokenPrefix ?? "Bearer")) {
234
288
  return invalidAuthorizationTokenFormat;
235
289
  }
236
290
  try {
237
291
  const decodedJwt = "decodeResource" in auth && auth.decodeResource ? await auth.decodeResource(token) : "verificationFunction" in auth && auth.verificationFunction ? await auth.verificationFunction(token) : void 0;
238
292
  if (!decodedJwt) {
239
- return invalidAuthorizationSubject;
293
+ return invalidAuthorizationToken;
240
294
  }
241
295
  resourceId = decodedJwt;
242
296
  } catch (error) {
@@ -246,6 +300,7 @@ async function checkAuthorizationToken(authorizationMethod, globalOptions, autho
246
300
  break;
247
301
  }
248
302
  case "basic": {
303
+ const [token] = tokenParts;
249
304
  if (tokenPrefix !== (collapsedAuthorizationMethod.tokenPrefix ?? "Basic")) {
250
305
  return invalidAuthorizationTokenFormat;
251
306
  }
@@ -269,9 +324,12 @@ async function checkAuthorizationToken(authorizationMethod, globalOptions, autho
269
324
  isNever(type);
270
325
  return [401, "Invalid Authorization method."];
271
326
  }
272
- if (isSystemAuthMethod(collapsedAuthorizationMethod) || resourceId == null) {
327
+ if (isHmacMethod(collapsedAuthorizationMethod) && resourceId == null) {
273
328
  return;
274
329
  }
330
+ if (resourceId == null) {
331
+ return invalidAuthorizationToken;
332
+ }
275
333
  if (hasScopeChecks(collapsedAuthorizationMethod)) {
276
334
  if (collapsedAuthorizationMethod.surfaceScopes) {
277
335
  const resourceScopes = await collapsedAuthorizationMethod.surfaceScopes(
@@ -1280,13 +1338,15 @@ var ForklaunchExpressLikeRouter = class _ForklaunchExpressLikeRouter {
1280
1338
  const maybeTypedHandler = middlewareOrMiddlewareAndTypedHandler[middlewareOrMiddlewareAndTypedHandler.length - 1];
1281
1339
  if (isTypedHandler(maybeTypedHandler)) {
1282
1340
  const { contractDetails, handlers } = maybeTypedHandler;
1283
- const router = this.registerRoute(
1284
- method,
1285
- path,
1286
- registrationMethod,
1287
- contractDetails,
1288
- ...middlewareOrMiddlewareAndTypedHandler.concat(handlers)
1289
- );
1341
+ const finalHandlers = [];
1342
+ if (isExpressLikeSchemaHandler(contractDetailsOrMiddlewareOrTypedHandler)) {
1343
+ finalHandlers.push(
1344
+ contractDetailsOrMiddlewareOrTypedHandler
1345
+ );
1346
+ }
1347
+ finalHandlers.push(...middlewareOrMiddlewareAndTypedHandler);
1348
+ finalHandlers.push(...handlers);
1349
+ const router = this.registerRoute(method, path, registrationMethod, contractDetails, ...finalHandlers);
1290
1350
  return router;
1291
1351
  } else {
1292
1352
  if (isExpressLikeSchemaHandler(contractDetailsOrMiddlewareOrTypedHandler) || isTypedHandler(contractDetailsOrMiddlewareOrTypedHandler)) {
@@ -1495,6 +1555,10 @@ var ForklaunchExpressLikeRouter = class _ForklaunchExpressLikeRouter {
1495
1555
  ].forEach((arg) => {
1496
1556
  if (isForklaunchRouter(arg)) {
1497
1557
  this.routers.push(arg);
1558
+ arg.routerOptions = {
1559
+ ...this.routerOptions ?? {},
1560
+ ...arg.routerOptions ?? {}
1561
+ };
1498
1562
  }
1499
1563
  });
1500
1564
  return this.registerNestableMiddlewareHandler(