@forklaunch/core 0.11.0 → 0.11.1
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 +3 -1
- package/lib/http/index.d.ts +3 -1
- package/lib/http/index.js +42 -17
- package/lib/http/index.js.map +1 -1
- package/lib/http/index.mjs +42 -17
- package/lib/http/index.mjs.map +1 -1
- package/package.json +1 -1
package/lib/http/index.d.mts
CHANGED
@@ -6,6 +6,7 @@ import { CorsOptions } from 'cors';
|
|
6
6
|
import { Counter, Gauge, Histogram, UpDownCounter, ObservableCounter, ObservableGauge, ObservableUpDownCounter, Span } from '@opentelemetry/api';
|
7
7
|
import { LevelWithSilentOrString, LevelWithSilent, Logger } from 'pino';
|
8
8
|
export { LevelWithSilent, LevelWithSilentOrString, Logger } from 'pino';
|
9
|
+
import { JWTPayload } from 'jose';
|
9
10
|
import { Readable } from 'stream';
|
10
11
|
import { ZodSchemaValidator } from '@forklaunch/validator/zod';
|
11
12
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
@@ -221,6 +222,7 @@ type JwtAuthMethods = {
|
|
221
222
|
type AuthMethodsBase = {
|
222
223
|
readonly tokenPrefix?: string;
|
223
224
|
readonly headerName?: string;
|
225
|
+
readonly decodeResource?: (token: string) => JWTPayload | Promise<JWTPayload>;
|
224
226
|
} & (BasicAuthMethods | JwtAuthMethods);
|
225
227
|
type PermissionSet = {
|
226
228
|
readonly allowedPermissions: Set<string>;
|
@@ -613,7 +615,7 @@ type ExpressLikeSchemaHandler<SV extends AnySchemaValidator, P extends ParamsObj
|
|
613
615
|
* @returns {Set<string> | Promise<Set<string>>} - A set of authorization strings or a promise that resolves to it.
|
614
616
|
*/
|
615
617
|
type ExpressLikeSchemaAuthMapper<SV extends AnySchemaValidator, P extends ParamsObject<SV>, ReqBody extends Body<SV>, ReqQuery extends QueryObject<SV>, ReqHeaders extends HeadersObject<SV>, BaseRequest> = ExpressLikeAuthMapper<SV, P extends infer UnmappedParams ? UnmappedParams extends ParamsObject<SV> ? MapParamsSchema<SV, UnmappedParams> : never : never, ReqBody extends infer UnmappedReqBody ? UnmappedReqBody extends Body<SV> ? MapReqBodySchema<SV, UnmappedReqBody> : never : never, ReqQuery extends infer UnmappedReqQuery ? UnmappedReqQuery extends QueryObject<SV> ? MapReqQuerySchema<SV, UnmappedReqQuery> : never : never, ReqHeaders extends infer UnmappedReqHeaders ? UnmappedReqHeaders extends HeadersObject<SV> ? MapReqHeadersSchema<SV, UnmappedReqHeaders> : never : never, BaseRequest>;
|
616
|
-
type ExpressLikeAuthMapper<SV extends AnySchemaValidator, P extends ParamsDictionary, ReqBody extends Record<string, unknown>, ReqQuery extends ParsedQs, ReqHeaders extends Record<string, string>, BaseRequest> = (
|
618
|
+
type ExpressLikeAuthMapper<SV extends AnySchemaValidator, P extends ParamsDictionary, ReqBody extends Record<string, unknown>, ReqQuery extends ParsedQs, ReqHeaders extends Record<string, string>, BaseRequest> = (payload: JWTPayload, req?: ResolvedForklaunchRequest<SV, P, ReqBody, ReqQuery, ReqHeaders, BaseRequest>) => Set<string> | Promise<Set<string>>;
|
617
619
|
type TokenPrefix<Auth extends AuthMethodsBase> = undefined extends Auth['tokenPrefix'] ? Auth extends BasicAuthMethods ? 'Basic ' : 'Bearer ' : `${Auth['tokenPrefix']} `;
|
618
620
|
type AuthHeaders<Auth extends AuthMethodsBase> = undefined extends Auth['headerName'] ? {
|
619
621
|
authorization: `${TokenPrefix<Auth>}${string}`;
|
package/lib/http/index.d.ts
CHANGED
@@ -6,6 +6,7 @@ import { CorsOptions } from 'cors';
|
|
6
6
|
import { Counter, Gauge, Histogram, UpDownCounter, ObservableCounter, ObservableGauge, ObservableUpDownCounter, Span } from '@opentelemetry/api';
|
7
7
|
import { LevelWithSilentOrString, LevelWithSilent, Logger } from 'pino';
|
8
8
|
export { LevelWithSilent, LevelWithSilentOrString, Logger } from 'pino';
|
9
|
+
import { JWTPayload } from 'jose';
|
9
10
|
import { Readable } from 'stream';
|
10
11
|
import { ZodSchemaValidator } from '@forklaunch/validator/zod';
|
11
12
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
@@ -221,6 +222,7 @@ type JwtAuthMethods = {
|
|
221
222
|
type AuthMethodsBase = {
|
222
223
|
readonly tokenPrefix?: string;
|
223
224
|
readonly headerName?: string;
|
225
|
+
readonly decodeResource?: (token: string) => JWTPayload | Promise<JWTPayload>;
|
224
226
|
} & (BasicAuthMethods | JwtAuthMethods);
|
225
227
|
type PermissionSet = {
|
226
228
|
readonly allowedPermissions: Set<string>;
|
@@ -613,7 +615,7 @@ type ExpressLikeSchemaHandler<SV extends AnySchemaValidator, P extends ParamsObj
|
|
613
615
|
* @returns {Set<string> | Promise<Set<string>>} - A set of authorization strings or a promise that resolves to it.
|
614
616
|
*/
|
615
617
|
type ExpressLikeSchemaAuthMapper<SV extends AnySchemaValidator, P extends ParamsObject<SV>, ReqBody extends Body<SV>, ReqQuery extends QueryObject<SV>, ReqHeaders extends HeadersObject<SV>, BaseRequest> = ExpressLikeAuthMapper<SV, P extends infer UnmappedParams ? UnmappedParams extends ParamsObject<SV> ? MapParamsSchema<SV, UnmappedParams> : never : never, ReqBody extends infer UnmappedReqBody ? UnmappedReqBody extends Body<SV> ? MapReqBodySchema<SV, UnmappedReqBody> : never : never, ReqQuery extends infer UnmappedReqQuery ? UnmappedReqQuery extends QueryObject<SV> ? MapReqQuerySchema<SV, UnmappedReqQuery> : never : never, ReqHeaders extends infer UnmappedReqHeaders ? UnmappedReqHeaders extends HeadersObject<SV> ? MapReqHeadersSchema<SV, UnmappedReqHeaders> : never : never, BaseRequest>;
|
616
|
-
type ExpressLikeAuthMapper<SV extends AnySchemaValidator, P extends ParamsDictionary, ReqBody extends Record<string, unknown>, ReqQuery extends ParsedQs, ReqHeaders extends Record<string, string>, BaseRequest> = (
|
618
|
+
type ExpressLikeAuthMapper<SV extends AnySchemaValidator, P extends ParamsDictionary, ReqBody extends Record<string, unknown>, ReqQuery extends ParsedQs, ReqHeaders extends Record<string, string>, BaseRequest> = (payload: JWTPayload, req?: ResolvedForklaunchRequest<SV, P, ReqBody, ReqQuery, ReqHeaders, BaseRequest>) => Set<string> | Promise<Set<string>>;
|
617
619
|
type TokenPrefix<Auth extends AuthMethodsBase> = undefined extends Auth['tokenPrefix'] ? Auth extends BasicAuthMethods ? 'Basic ' : 'Bearer ' : `${Auth['tokenPrefix']} `;
|
618
620
|
type AuthHeaders<Auth extends AuthMethodsBase> = undefined extends Auth['headerName'] ? {
|
619
621
|
authorization: `${TokenPrefix<Auth>}${string}`;
|
package/lib/http/index.js
CHANGED
@@ -147,16 +147,24 @@ function discriminateAuthMethod(auth) {
|
|
147
147
|
if ("basic" in auth) {
|
148
148
|
return {
|
149
149
|
type: "basic",
|
150
|
-
auth:
|
150
|
+
auth: {
|
151
|
+
decodeResource: auth.decodeResource,
|
152
|
+
login: auth.basic.login
|
153
|
+
}
|
151
154
|
};
|
152
155
|
} else if ("jwt" in auth) {
|
153
156
|
return {
|
154
157
|
type: "jwt",
|
155
|
-
auth:
|
158
|
+
auth: {
|
159
|
+
decodeResource: auth.decodeResource
|
160
|
+
}
|
156
161
|
};
|
157
162
|
} else {
|
158
163
|
return {
|
159
|
-
type: "jwt"
|
164
|
+
type: "jwt",
|
165
|
+
auth: {
|
166
|
+
decodeResource: auth.decodeResource
|
167
|
+
}
|
160
168
|
};
|
161
169
|
}
|
162
170
|
}
|
@@ -209,32 +217,38 @@ async function checkAuthorizationToken(authorizationMethod, authorizationToken,
|
|
209
217
|
return invalidAuthorizationTokenFormat;
|
210
218
|
}
|
211
219
|
try {
|
212
|
-
const decodedJwt = await (0, import_jose.jwtVerify)(
|
220
|
+
const decodedJwt = await auth?.decodeResource?.(token) ?? (await (0, import_jose.jwtVerify)(
|
213
221
|
token,
|
214
222
|
new TextEncoder().encode(process.env.JWT_SECRET)
|
215
|
-
);
|
216
|
-
if (!decodedJwt
|
223
|
+
)).payload;
|
224
|
+
if (!decodedJwt) {
|
217
225
|
return invalidAuthorizationSubject;
|
218
226
|
}
|
219
|
-
resourceId = decodedJwt
|
227
|
+
resourceId = decodedJwt;
|
220
228
|
} catch (error) {
|
221
|
-
req
|
229
|
+
req?.openTelemetryCollector.error(error);
|
222
230
|
return invalidAuthorizationToken;
|
223
231
|
}
|
224
232
|
break;
|
225
233
|
}
|
226
234
|
case "basic": {
|
227
|
-
if (
|
228
|
-
return invalidAuthorizationTokenFormat;
|
229
|
-
}
|
230
|
-
const [username, password] = Buffer.from(token, "base64").toString("utf-8").split(":");
|
231
|
-
if (!username || !password) {
|
235
|
+
if (tokenPrefix !== (authorizationMethod.tokenPrefix ?? "Basic")) {
|
232
236
|
return invalidAuthorizationTokenFormat;
|
233
237
|
}
|
234
|
-
if (
|
235
|
-
|
238
|
+
if (auth.decodeResource) {
|
239
|
+
resourceId = await auth.decodeResource(token);
|
240
|
+
} else {
|
241
|
+
const [username, password] = Buffer.from(token, "base64").toString("utf-8").split(":");
|
242
|
+
if (!username || !password) {
|
243
|
+
return invalidAuthorizationTokenFormat;
|
244
|
+
}
|
245
|
+
if (!auth.login(username, password)) {
|
246
|
+
return invalidAuthorizationLogin;
|
247
|
+
}
|
248
|
+
resourceId = {
|
249
|
+
sub: username
|
250
|
+
};
|
236
251
|
}
|
237
|
-
resourceId = username;
|
238
252
|
break;
|
239
253
|
}
|
240
254
|
default:
|
@@ -629,7 +643,18 @@ function parse(req, res, next) {
|
|
629
643
|
enumerable: true,
|
630
644
|
configurable: false
|
631
645
|
});
|
632
|
-
|
646
|
+
const parsedHeaders = parsedRequest.value.headers ?? {};
|
647
|
+
req.headers = Object.keys(req.headers).reduce(
|
648
|
+
(acc, key) => {
|
649
|
+
if (parsedHeaders?.[key]) {
|
650
|
+
acc[key] = parsedHeaders[key];
|
651
|
+
} else {
|
652
|
+
acc[key] = req.headers[key];
|
653
|
+
}
|
654
|
+
return acc;
|
655
|
+
},
|
656
|
+
{}
|
657
|
+
);
|
633
658
|
}
|
634
659
|
if (!parsedRequest.ok) {
|
635
660
|
switch (req.contractDetails.options?.requestValidation) {
|