@forestadmin/agent-bff 1.2.0 → 1.4.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 +53 -5
- package/dist/agent/agent-stub.d.ts +3 -0
- package/dist/agent/agent-stub.js +19 -0
- package/dist/agent/build-agent-query.d.ts +8 -0
- package/dist/agent/build-agent-query.js +7 -0
- package/dist/api-key/agent-token.d.ts +8 -0
- package/dist/api-key/agent-token.js +34 -0
- package/dist/api-key/api-key-authenticator.d.ts +17 -0
- package/dist/api-key/api-key-authenticator.js +61 -0
- package/dist/api-key/api-key-client.d.ts +37 -0
- package/dist/api-key/api-key-client.js +85 -0
- package/dist/api-key/api-key-error.d.ts +20 -0
- package/dist/api-key/api-key-error.js +34 -0
- package/dist/api-key/api-key-middleware.d.ts +10 -0
- package/dist/api-key/api-key-middleware.js +47 -0
- package/dist/api-key/api-key-resolve-error.d.ts +16 -0
- package/dist/api-key/api-key-resolve-error.js +16 -0
- package/dist/api-key/api-key.d.ts +8 -0
- package/dist/api-key/api-key.js +23 -0
- package/dist/api-key/resolve-cache.d.ts +17 -0
- package/dist/api-key/resolve-cache.js +56 -0
- package/dist/auth/auth-mode-middleware.d.ts +7 -0
- package/dist/auth/auth-mode-middleware.js +53 -0
- package/dist/auth/auth-mode.d.ts +7 -0
- package/dist/auth/auth-mode.js +25 -0
- package/dist/cli-core.js +90 -3
- package/dist/config/env-config.d.ts +3 -0
- package/dist/config/env-config.js +15 -1
- package/dist/cors/cors-middleware.d.ts +9 -0
- package/dist/cors/cors-middleware.js +29 -0
- package/dist/cors/origin.d.ts +7 -0
- package/dist/cors/origin.js +47 -0
- package/dist/cors/per-key-origin.d.ts +3 -0
- package/dist/cors/per-key-origin.js +16 -0
- package/dist/http/bff-http-error.d.ts +34 -0
- package/dist/http/bff-http-error.js +55 -0
- package/dist/http/error-middleware.d.ts +7 -0
- package/dist/http/error-middleware.js +49 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +26 -2
- package/dist/timezone/timezone-middleware.d.ts +7 -0
- package/dist/timezone/timezone-middleware.js +24 -0
- package/dist/timezone/timezone.d.ts +8 -0
- package/dist/timezone/timezone.js +35 -0
- package/package.json +1 -1
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = createResolveCache;
|
|
4
|
+
const DEFAULT_POSITIVE_TTL_SECONDS = 60;
|
|
5
|
+
const DEFAULT_NEGATIVE_TTL_SECONDS = 10;
|
|
6
|
+
const DEFAULT_MAX_ENTRIES = 10000;
|
|
7
|
+
function createResolveCache({ now, positiveTtlSeconds = DEFAULT_POSITIVE_TTL_SECONDS, negativeTtlSeconds = DEFAULT_NEGATIVE_TTL_SECONDS, maxEntries = DEFAULT_MAX_ENTRIES, }) {
|
|
8
|
+
const entries = new Map();
|
|
9
|
+
function purgeExpired() {
|
|
10
|
+
const current = now();
|
|
11
|
+
for (const [hash, entry] of entries) {
|
|
12
|
+
if (current >= entry.expiresAt)
|
|
13
|
+
entries.delete(hash);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function liveEntry(hash) {
|
|
17
|
+
const entry = entries.get(hash);
|
|
18
|
+
if (!entry)
|
|
19
|
+
return undefined;
|
|
20
|
+
if (now() >= entry.expiresAt) {
|
|
21
|
+
entries.delete(hash);
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
return entry;
|
|
25
|
+
}
|
|
26
|
+
function store(hash, entry) {
|
|
27
|
+
purgeExpired();
|
|
28
|
+
if (!entries.has(hash) && entries.size >= maxEntries) {
|
|
29
|
+
const oldest = entries.keys().next().value;
|
|
30
|
+
if (oldest !== undefined)
|
|
31
|
+
entries.delete(oldest);
|
|
32
|
+
}
|
|
33
|
+
entries.set(hash, entry);
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
getPositive(hash) {
|
|
37
|
+
const entry = liveEntry(hash);
|
|
38
|
+
return entry?.kind === 'positive' ? entry.identity : undefined;
|
|
39
|
+
},
|
|
40
|
+
getNegative(hash) {
|
|
41
|
+
const entry = liveEntry(hash);
|
|
42
|
+
return entry?.kind === 'negative' ? entry.error : undefined;
|
|
43
|
+
},
|
|
44
|
+
setPositive(hash, identity) {
|
|
45
|
+
store(hash, { kind: 'positive', identity, expiresAt: now() + positiveTtlSeconds * 1000 });
|
|
46
|
+
},
|
|
47
|
+
setNegative(hash, error) {
|
|
48
|
+
store(hash, { kind: 'negative', error, expiresAt: now() + negativeTtlSeconds * 1000 });
|
|
49
|
+
},
|
|
50
|
+
size() {
|
|
51
|
+
purgeExpired();
|
|
52
|
+
return entries.size;
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVzb2x2ZS1jYWNoZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9hcGkta2V5L3Jlc29sdmUtY2FjaGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFvQ0EscUNBbUVDO0FBdkVELE1BQU0sNEJBQTRCLEdBQUcsRUFBRSxDQUFDO0FBQ3hDLE1BQU0sNEJBQTRCLEdBQUcsRUFBRSxDQUFDO0FBQ3hDLE1BQU0sbUJBQW1CLEdBQUcsS0FBTSxDQUFDO0FBRW5DLFNBQXdCLGtCQUFrQixDQUFDLEVBQ3pDLEdBQUcsRUFDSCxrQkFBa0IsR0FBRyw0QkFBNEIsRUFDakQsa0JBQWtCLEdBQUcsNEJBQTRCLEVBQ2pELFVBQVUsR0FBRyxtQkFBbUIsR0FDWjtJQUNwQixNQUFNLE9BQU8sR0FBRyxJQUFJLEdBQUcsRUFBc0IsQ0FBQztJQUU5QyxTQUFTLFlBQVk7UUFDbkIsTUFBTSxPQUFPLEdBQUcsR0FBRyxFQUFFLENBQUM7UUFFdEIsS0FBSyxNQUFNLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQyxJQUFJLE9BQU8sRUFBRSxDQUFDO1lBQ3BDLElBQUksT0FBTyxJQUFJLEtBQUssQ0FBQyxTQUFTO2dCQUFFLE9BQU8sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDdkQsQ0FBQztJQUNILENBQUM7SUFFRCxTQUFTLFNBQVMsQ0FBQyxJQUFZO1FBQzdCLE1BQU0sS0FBSyxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDaEMsSUFBSSxDQUFDLEtBQUs7WUFBRSxPQUFPLFNBQVMsQ0FBQztRQUU3QixJQUFJLEdBQUcsRUFBRSxJQUFJLEtBQUssQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUM3QixPQUFPLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDO1lBRXJCLE9BQU8sU0FBUyxDQUFDO1FBQ25CLENBQUM7UUFFRCxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFRCxTQUFTLEtBQUssQ0FBQyxJQUFZLEVBQUUsS0FBaUI7UUFDNUMsWUFBWSxFQUFFLENBQUM7UUFFZixJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsSUFBSSxPQUFPLENBQUMsSUFBSSxJQUFJLFVBQVUsRUFBRSxDQUFDO1lBQ3JELE1BQU0sTUFBTSxHQUFHLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxLQUFLLENBQUM7WUFDM0MsSUFBSSxNQUFNLEtBQUssU0FBUztnQkFBRSxPQUFPLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ25ELENBQUM7UUFFRCxPQUFPLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxLQUFLLENBQUMsQ0FBQztJQUMzQixDQUFDO0lBRUQsT0FBTztRQUNMLFdBQVcsQ0FBQyxJQUFJO1lBQ2QsTUFBTSxLQUFLLEdBQUcsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDO1lBRTlCLE9BQU8sS0FBSyxFQUFFLElBQUksS0FBSyxVQUFVLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztRQUNqRSxDQUFDO1FBRUQsV0FBVyxDQUFDLElBQUk7WUFDZCxNQUFNLEtBQUssR0FBRyxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUM7WUFFOUIsT0FBTyxLQUFLLEVBQUUsSUFBSSxLQUFLLFVBQVUsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO1FBQzlELENBQUM7UUFFRCxXQUFXLENBQUMsSUFBSSxFQUFFLFFBQVE7WUFDeEIsS0FBSyxDQUFDLElBQUksRUFBRSxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFFLFNBQVMsRUFBRSxHQUFHLEVBQUUsR0FBRyxrQkFBa0IsR0FBRyxJQUFJLEVBQUUsQ0FBQyxDQUFDO1FBQzVGLENBQUM7UUFFRCxXQUFXLENBQUMsSUFBSSxFQUFFLEtBQUs7WUFDckIsS0FBSyxDQUFDLElBQUksRUFBRSxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUUsS0FBSyxFQUFFLFNBQVMsRUFBRSxHQUFHLEVBQUUsR0FBRyxrQkFBa0IsR0FBRyxJQUFJLEVBQUUsQ0FBQyxDQUFDO1FBQ3pGLENBQUM7UUFFRCxJQUFJO1lBQ0YsWUFBWSxFQUFFLENBQUM7WUFFZixPQUFPLE9BQU8sQ0FBQyxJQUFJLENBQUM7UUFDdEIsQ0FBQztLQUNGLENBQUM7QUFDSixDQUFDIn0=
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Middleware } from 'koa';
|
|
2
|
+
export declare const BFF_KEY_HEADER = "X-Forest-Bff-Key";
|
|
3
|
+
export interface AuthModeMiddlewareOptions {
|
|
4
|
+
authSecret: string;
|
|
5
|
+
}
|
|
6
|
+
export default function createAuthModeMiddleware({ authSecret, }: AuthModeMiddlewareOptions): Middleware;
|
|
7
|
+
//# sourceMappingURL=auth-mode-middleware.d.ts.map
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.BFF_KEY_HEADER = void 0;
|
|
7
|
+
exports.default = createAuthModeMiddleware;
|
|
8
|
+
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
9
|
+
const auth_mode_1 = require("./auth-mode");
|
|
10
|
+
const bff_http_error_1 = require("../http/bff-http-error");
|
|
11
|
+
const bff_token_1 = require("../oauth/bff-token");
|
|
12
|
+
exports.BFF_KEY_HEADER = 'X-Forest-Bff-Key';
|
|
13
|
+
function verifyBffAccess(token, authSecret) {
|
|
14
|
+
let decoded;
|
|
15
|
+
// Verify the signature first but ignore expiration, so the token type can be
|
|
16
|
+
// checked before expiry: a wrong-typed token must be `unauthorized`, and only
|
|
17
|
+
// a genuine expired `bff_access` should map to `session_expired`.
|
|
18
|
+
try {
|
|
19
|
+
decoded = jsonwebtoken_1.default.verify(token, authSecret, {
|
|
20
|
+
algorithms: ['HS256'],
|
|
21
|
+
ignoreExpiration: true,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
throw (0, bff_http_error_1.unauthorized)();
|
|
26
|
+
}
|
|
27
|
+
if (typeof decoded !== 'object' ||
|
|
28
|
+
decoded === null ||
|
|
29
|
+
decoded.type !== bff_token_1.BFF_ACCESS_TOKEN_TYPE) {
|
|
30
|
+
throw (0, bff_http_error_1.unauthorized)();
|
|
31
|
+
}
|
|
32
|
+
const { exp } = decoded;
|
|
33
|
+
if (typeof exp !== 'number') {
|
|
34
|
+
throw (0, bff_http_error_1.unauthorized)();
|
|
35
|
+
}
|
|
36
|
+
if (exp * 1000 <= Date.now()) {
|
|
37
|
+
throw (0, bff_http_error_1.sessionExpired)();
|
|
38
|
+
}
|
|
39
|
+
return decoded;
|
|
40
|
+
}
|
|
41
|
+
function createAuthModeMiddleware({ authSecret, }) {
|
|
42
|
+
return async function authModeMiddleware(ctx, next) {
|
|
43
|
+
const bearer = (0, auth_mode_1.extractBearerToken)(ctx.get('Authorization'));
|
|
44
|
+
const apiKey = ctx.get(exports.BFF_KEY_HEADER);
|
|
45
|
+
const mode = (0, auth_mode_1.resolveAuthMode)({ hasBearer: bearer !== undefined, hasApiKey: apiKey !== '' });
|
|
46
|
+
ctx.state.authMode = mode;
|
|
47
|
+
if (mode === 'oauth') {
|
|
48
|
+
ctx.state.principal = verifyBffAccess(bearer, authSecret);
|
|
49
|
+
}
|
|
50
|
+
await next();
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aC1tb2RlLW1pZGRsZXdhcmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYXV0aC9hdXRoLW1vZGUtbWlkZGxld2FyZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFtREEsMkNBaUJDO0FBakVELGdFQUF3QztBQUV4QywyQ0FBa0U7QUFDbEUsMkRBQXNFO0FBQ3RFLGtEQUEyRDtBQUU5QyxRQUFBLGNBQWMsR0FBRyxrQkFBa0IsQ0FBQztBQU1qRCxTQUFTLGVBQWUsQ0FBQyxLQUFhLEVBQUUsVUFBa0I7SUFDeEQsSUFBSSxPQUFnQixDQUFDO0lBRXJCLDZFQUE2RTtJQUM3RSw4RUFBOEU7SUFDOUUsa0VBQWtFO0lBQ2xFLElBQUksQ0FBQztRQUNILE9BQU8sR0FBRyxzQkFBWSxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUUsVUFBVSxFQUFFO1lBQy9DLFVBQVUsRUFBRSxDQUFDLE9BQU8sQ0FBQztZQUNyQixnQkFBZ0IsRUFBRSxJQUFJO1NBQ3ZCLENBQUMsQ0FBQztJQUNMLENBQUM7SUFBQyxNQUFNLENBQUM7UUFDUCxNQUFNLElBQUEsNkJBQVksR0FBRSxDQUFDO0lBQ3ZCLENBQUM7SUFFRCxJQUNFLE9BQU8sT0FBTyxLQUFLLFFBQVE7UUFDM0IsT0FBTyxLQUFLLElBQUk7UUFDZixPQUE4QixDQUFDLElBQUksS0FBSyxpQ0FBcUIsRUFDOUQsQ0FBQztRQUNELE1BQU0sSUFBQSw2QkFBWSxHQUFFLENBQUM7SUFDdkIsQ0FBQztJQUVELE1BQU0sRUFBRSxHQUFHLEVBQUUsR0FBRyxPQUE0QixDQUFDO0lBRTdDLElBQUksT0FBTyxHQUFHLEtBQUssUUFBUSxFQUFFLENBQUM7UUFDNUIsTUFBTSxJQUFBLDZCQUFZLEdBQUUsQ0FBQztJQUN2QixDQUFDO0lBRUQsSUFBSSxHQUFHLEdBQUcsSUFBSSxJQUFJLElBQUksQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDO1FBQzdCLE1BQU0sSUFBQSwrQkFBYyxHQUFFLENBQUM7SUFDekIsQ0FBQztJQUVELE9BQU8sT0FBZ0MsQ0FBQztBQUMxQyxDQUFDO0FBRUQsU0FBd0Isd0JBQXdCLENBQUMsRUFDL0MsVUFBVSxHQUNnQjtJQUMxQixPQUFPLEtBQUssVUFBVSxrQkFBa0IsQ0FBQyxHQUFHLEVBQUUsSUFBSTtRQUNoRCxNQUFNLE1BQU0sR0FBRyxJQUFBLDhCQUFrQixFQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsZUFBZSxDQUFDLENBQUMsQ0FBQztRQUM1RCxNQUFNLE1BQU0sR0FBRyxHQUFHLENBQUMsR0FBRyxDQUFDLHNCQUFjLENBQUMsQ0FBQztRQUV2QyxNQUFNLElBQUksR0FBRyxJQUFBLDJCQUFlLEVBQUMsRUFBRSxTQUFTLEVBQUUsTUFBTSxLQUFLLFNBQVMsRUFBRSxTQUFTLEVBQUUsTUFBTSxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFFNUYsR0FBRyxDQUFDLEtBQUssQ0FBQyxRQUFRLEdBQUcsSUFBSSxDQUFDO1FBRTFCLElBQUksSUFBSSxLQUFLLE9BQU8sRUFBRSxDQUFDO1lBQ3JCLEdBQUcsQ0FBQyxLQUFLLENBQUMsU0FBUyxHQUFHLGVBQWUsQ0FBQyxNQUFnQixFQUFFLFVBQVUsQ0FBQyxDQUFDO1FBQ3RFLENBQUM7UUFFRCxNQUFNLElBQUksRUFBRSxDQUFDO0lBQ2YsQ0FBQyxDQUFDO0FBQ0osQ0FBQyJ9
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type AuthMode = 'oauth' | 'api-key';
|
|
2
|
+
export declare function extractBearerToken(authorization: string | undefined): string | undefined;
|
|
3
|
+
export declare function resolveAuthMode({ hasBearer, hasApiKey, }: {
|
|
4
|
+
hasBearer: boolean;
|
|
5
|
+
hasApiKey: boolean;
|
|
6
|
+
}): AuthMode;
|
|
7
|
+
//# sourceMappingURL=auth-mode.d.ts.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractBearerToken = extractBearerToken;
|
|
4
|
+
exports.resolveAuthMode = resolveAuthMode;
|
|
5
|
+
const bff_http_error_1 = require("../http/bff-http-error");
|
|
6
|
+
const BEARER_PATTERN = /^Bearer[ \t]+(.+)$/i;
|
|
7
|
+
function extractBearerToken(authorization) {
|
|
8
|
+
if (!authorization)
|
|
9
|
+
return undefined;
|
|
10
|
+
const match = BEARER_PATTERN.exec(authorization.trim());
|
|
11
|
+
if (!match)
|
|
12
|
+
return undefined;
|
|
13
|
+
const token = match[1].trim();
|
|
14
|
+
return token === '' ? undefined : token;
|
|
15
|
+
}
|
|
16
|
+
function resolveAuthMode({ hasBearer, hasApiKey, }) {
|
|
17
|
+
if (hasBearer && hasApiKey)
|
|
18
|
+
throw (0, bff_http_error_1.ambiguousCredentials)();
|
|
19
|
+
if (hasApiKey)
|
|
20
|
+
return 'api-key';
|
|
21
|
+
if (hasBearer)
|
|
22
|
+
return 'oauth';
|
|
23
|
+
throw (0, bff_http_error_1.unauthorized)();
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aC1tb2RlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2F1dGgvYXV0aC1tb2RlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBTUEsZ0RBU0M7QUFFRCwwQ0FZQztBQTdCRCwyREFBNEU7QUFJNUUsTUFBTSxjQUFjLEdBQUcscUJBQXFCLENBQUM7QUFFN0MsU0FBZ0Isa0JBQWtCLENBQUMsYUFBaUM7SUFDbEUsSUFBSSxDQUFDLGFBQWE7UUFBRSxPQUFPLFNBQVMsQ0FBQztJQUVyQyxNQUFNLEtBQUssR0FBRyxjQUFjLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQ3hELElBQUksQ0FBQyxLQUFLO1FBQUUsT0FBTyxTQUFTLENBQUM7SUFFN0IsTUFBTSxLQUFLLEdBQUcsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDO0lBRTlCLE9BQU8sS0FBSyxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUM7QUFDMUMsQ0FBQztBQUVELFNBQWdCLGVBQWUsQ0FBQyxFQUM5QixTQUFTLEVBQ1QsU0FBUyxHQUlWO0lBQ0MsSUFBSSxTQUFTLElBQUksU0FBUztRQUFFLE1BQU0sSUFBQSxxQ0FBb0IsR0FBRSxDQUFDO0lBQ3pELElBQUksU0FBUztRQUFFLE9BQU8sU0FBUyxDQUFDO0lBQ2hDLElBQUksU0FBUztRQUFFLE9BQU8sT0FBTyxDQUFDO0lBRTlCLE1BQU0sSUFBQSw2QkFBWSxHQUFFLENBQUM7QUFDdkIsQ0FBQyJ9
|
package/dist/cli-core.js
CHANGED
|
@@ -7,16 +7,48 @@ exports.default = runCli;
|
|
|
7
7
|
exports.reportFatalError = reportFatalError;
|
|
8
8
|
const bodyparser_1 = require("@koa/bodyparser");
|
|
9
9
|
const console_logger_1 = __importDefault(require("./adapters/console-logger"));
|
|
10
|
+
const agent_stub_1 = __importDefault(require("./agent/agent-stub"));
|
|
11
|
+
const api_key_authenticator_1 = __importDefault(require("./api-key/api-key-authenticator"));
|
|
12
|
+
const api_key_client_1 = __importDefault(require("./api-key/api-key-client"));
|
|
13
|
+
const api_key_middleware_1 = __importDefault(require("./api-key/api-key-middleware"));
|
|
14
|
+
const resolve_cache_1 = __importDefault(require("./api-key/resolve-cache"));
|
|
15
|
+
const auth_mode_middleware_1 = __importDefault(require("./auth/auth-mode-middleware"));
|
|
10
16
|
const env_config_1 = require("./config/env-config");
|
|
17
|
+
const cors_middleware_1 = __importDefault(require("./cors/cors-middleware"));
|
|
18
|
+
const per_key_origin_1 = __importDefault(require("./cors/per-key-origin"));
|
|
11
19
|
const errors_1 = require("./errors");
|
|
20
|
+
const bff_http_error_1 = require("./http/bff-http-error");
|
|
12
21
|
const bff_http_server_1 = __importDefault(require("./http/bff-http-server"));
|
|
22
|
+
const error_middleware_1 = __importDefault(require("./http/error-middleware"));
|
|
13
23
|
const forest_server_client_1 = __importDefault(require("./oauth/forest-server-client"));
|
|
14
24
|
const oauth_routes_1 = __importDefault(require("./oauth/oauth-routes"));
|
|
15
25
|
const session_store_1 = __importDefault(require("./oauth/session-store"));
|
|
16
26
|
const token_cipher_1 = __importDefault(require("./oauth/token-cipher"));
|
|
27
|
+
const timezone_middleware_1 = __importDefault(require("./timezone/timezone-middleware"));
|
|
17
28
|
const version_1 = __importDefault(require("./version"));
|
|
18
29
|
const BODY_LIMIT = '16kb';
|
|
19
30
|
const SESSION_TTL_SECONDS = 24 * 60 * 60;
|
|
31
|
+
function isAgentPath(path) {
|
|
32
|
+
return path === '/agent' || path.startsWith('/agent/');
|
|
33
|
+
}
|
|
34
|
+
function agentScoped(middleware) {
|
|
35
|
+
return async function scoped(ctx, next) {
|
|
36
|
+
if (!isAgentPath(ctx.path)) {
|
|
37
|
+
await next();
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
await middleware(ctx, next);
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function createApiKeyUnavailableGuard(logger) {
|
|
44
|
+
return async function apiKeyUnavailableGuard(ctx, next) {
|
|
45
|
+
if (ctx.state.authMode === 'api-key') {
|
|
46
|
+
logger('Error', 'API key auth requested but the resolver is not configured');
|
|
47
|
+
throw (0, bff_http_error_1.unauthorized)('Credentials could not be validated');
|
|
48
|
+
}
|
|
49
|
+
await next();
|
|
50
|
+
};
|
|
51
|
+
}
|
|
20
52
|
function resolveOAuthConfig(config) {
|
|
21
53
|
const { forestServerUrl, forestEnvSecret, forestAppUrl, forestAuthSecret, tokenEncryptionKey } = config;
|
|
22
54
|
if (forestServerUrl &&
|
|
@@ -50,11 +82,66 @@ async function buildOAuthMiddlewares(config, logger) {
|
|
|
50
82
|
environmentId,
|
|
51
83
|
logger,
|
|
52
84
|
});
|
|
53
|
-
return [
|
|
85
|
+
return [oauthRoutes];
|
|
86
|
+
}
|
|
87
|
+
function resolveApiKeyConfig(config) {
|
|
88
|
+
const { forestServerUrl, forestEnvSecret, forestAuthSecret } = config;
|
|
89
|
+
if (forestServerUrl && forestEnvSecret && forestAuthSecret) {
|
|
90
|
+
return { forestServerUrl, forestEnvSecret, forestAuthSecret };
|
|
91
|
+
}
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
function buildApiKeyMiddleware(config, logger) {
|
|
95
|
+
const apiKeyConfig = resolveApiKeyConfig(config);
|
|
96
|
+
if (!apiKeyConfig) {
|
|
97
|
+
logger('Warn', 'API key auth disabled: required configuration is missing');
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
const client = new api_key_client_1.default({
|
|
101
|
+
forestServerUrl: apiKeyConfig.forestServerUrl,
|
|
102
|
+
envSecret: apiKeyConfig.forestEnvSecret,
|
|
103
|
+
});
|
|
104
|
+
const cache = (0, resolve_cache_1.default)({ now: () => Date.now() });
|
|
105
|
+
const authenticator = (0, api_key_authenticator_1.default)({
|
|
106
|
+
client,
|
|
107
|
+
cache,
|
|
108
|
+
authSecret: apiKeyConfig.forestAuthSecret,
|
|
109
|
+
});
|
|
110
|
+
return (0, api_key_middleware_1.default)({ authenticator, logger });
|
|
111
|
+
}
|
|
112
|
+
function buildAgentMiddlewares(config, logger) {
|
|
113
|
+
const { forestAuthSecret, defaultTimezone } = config;
|
|
114
|
+
if (!forestAuthSecret) {
|
|
115
|
+
logger('Warn', 'Agent edge disabled: FOREST_AUTH_SECRET is missing');
|
|
116
|
+
return [];
|
|
117
|
+
}
|
|
118
|
+
const apiKeyStep = buildApiKeyMiddleware(config, logger) ?? createApiKeyUnavailableGuard(logger);
|
|
119
|
+
const chain = [
|
|
120
|
+
(0, auth_mode_middleware_1.default)({ authSecret: forestAuthSecret }),
|
|
121
|
+
apiKeyStep,
|
|
122
|
+
(0, per_key_origin_1.default)(),
|
|
123
|
+
(0, timezone_middleware_1.default)({ defaultTimezone }),
|
|
124
|
+
(0, agent_stub_1.default)(),
|
|
125
|
+
];
|
|
126
|
+
return chain.map(agentScoped);
|
|
54
127
|
}
|
|
55
128
|
async function runCli(env, logger = (0, console_logger_1.default)()) {
|
|
56
129
|
const config = (0, env_config_1.parseConfig)(env);
|
|
57
|
-
|
|
130
|
+
if (config.invalidAllowedOrigins.length > 0) {
|
|
131
|
+
logger('Warn', 'Ignoring malformed BFF_ALLOWED_ORIGINS entries', {
|
|
132
|
+
entries: config.invalidAllowedOrigins,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
const oauthMiddlewares = await buildOAuthMiddlewares(config, logger);
|
|
136
|
+
const agentMiddlewares = buildAgentMiddlewares(config, logger);
|
|
137
|
+
const agentErrorMiddleware = agentMiddlewares.length > 0 ? [agentScoped((0, error_middleware_1.default)({ logger }))] : [];
|
|
138
|
+
const middlewares = [
|
|
139
|
+
(0, cors_middleware_1.default)({ allowedOrigins: config.allowedOrigins }),
|
|
140
|
+
...agentErrorMiddleware,
|
|
141
|
+
(0, bodyparser_1.bodyParser)({ jsonLimit: BODY_LIMIT }),
|
|
142
|
+
...oauthMiddlewares,
|
|
143
|
+
...agentMiddlewares,
|
|
144
|
+
];
|
|
58
145
|
const server = new bff_http_server_1.default({
|
|
59
146
|
port: config.httpPort,
|
|
60
147
|
version: version_1.default,
|
|
@@ -69,4 +156,4 @@ function reportFatalError(err) {
|
|
|
69
156
|
process.stderr.write(`Error: ${(0, errors_1.extractErrorMessage)(err)}\n`);
|
|
70
157
|
process.exitCode = 1;
|
|
71
158
|
}
|
|
72
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
159
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpLWNvcmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvY2xpLWNvcmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFnTEEseUJBa0NDO0FBRUQsNENBR0M7QUFuTkQsZ0RBQTZDO0FBRTdDLCtFQUE0RDtBQUM1RCxvRUFBMkQ7QUFDM0QsNEZBQXdFO0FBQ3hFLDhFQUFvRDtBQUNwRCxzRkFBa0U7QUFDbEUsNEVBQXlEO0FBQ3pELHVGQUFtRTtBQUNuRSxvREFBa0Q7QUFDbEQsNkVBQTBEO0FBQzFELDJFQUFpRTtBQUNqRSxxQ0FBK0M7QUFDL0MsMERBQXFEO0FBQ3JELDZFQUFtRDtBQUNuRCwrRUFBNEQ7QUFDNUQsd0ZBQThEO0FBQzlELHdFQUFxRDtBQUNyRCwwRUFBK0Q7QUFDL0Qsd0VBQXFEO0FBQ3JELHlGQUFzRTtBQUN0RSx3REFBZ0M7QUFFaEMsTUFBTSxVQUFVLEdBQUcsTUFBTSxDQUFDO0FBQzFCLE1BQU0sbUJBQW1CLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLENBQUM7QUFFekMsU0FBUyxXQUFXLENBQUMsSUFBWTtJQUMvQixPQUFPLElBQUksS0FBSyxRQUFRLElBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQyxTQUFTLENBQUMsQ0FBQztBQUN6RCxDQUFDO0FBRUQsU0FBUyxXQUFXLENBQUMsVUFBc0I7SUFDekMsT0FBTyxLQUFLLFVBQVUsTUFBTSxDQUFDLEdBQUcsRUFBRSxJQUFJO1FBQ3BDLElBQUksQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7WUFDM0IsTUFBTSxJQUFJLEVBQUUsQ0FBQztZQUViLE9BQU87UUFDVCxDQUFDO1FBRUQsTUFBTSxVQUFVLENBQUMsR0FBRyxFQUFFLElBQUksQ0FBQyxDQUFDO0lBQzlCLENBQUMsQ0FBQztBQUNKLENBQUM7QUFFRCxTQUFTLDRCQUE0QixDQUFDLE1BQWM7SUFDbEQsT0FBTyxLQUFLLFVBQVUsc0JBQXNCLENBQUMs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
|
|
@@ -8,6 +8,9 @@ export interface BFFConfig {
|
|
|
8
8
|
forestAppUrl?: string;
|
|
9
9
|
agentUrl?: string;
|
|
10
10
|
tokenEncryptionKey?: string;
|
|
11
|
+
allowedOrigins: string[];
|
|
12
|
+
invalidAllowedOrigins: string[];
|
|
13
|
+
defaultTimezone?: string;
|
|
11
14
|
httpPort: number;
|
|
12
15
|
presence: PresenceMap;
|
|
13
16
|
hasAllRequired: boolean;
|
|
@@ -6,8 +6,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.REQUIRED_KEYS = void 0;
|
|
7
7
|
exports.parseConfig = parseConfig;
|
|
8
8
|
const zod_1 = require("zod");
|
|
9
|
+
const origin_1 = require("../cors/origin");
|
|
9
10
|
const defaults_1 = __importDefault(require("../defaults"));
|
|
10
11
|
const errors_1 = require("../errors");
|
|
12
|
+
const timezone_1 = require("../timezone/timezone");
|
|
11
13
|
exports.REQUIRED_KEYS = [
|
|
12
14
|
'FOREST_AUTH_SECRET',
|
|
13
15
|
'FOREST_ENV_SECRET',
|
|
@@ -47,6 +49,13 @@ function parseEncryptionKey(raw) {
|
|
|
47
49
|
}
|
|
48
50
|
return value;
|
|
49
51
|
}
|
|
52
|
+
function parseDefaultTimezone(raw) {
|
|
53
|
+
const value = normalize(raw);
|
|
54
|
+
if (value !== undefined && !(0, timezone_1.isValidTimezone)(value)) {
|
|
55
|
+
throw new errors_1.ConfigurationError(`Invalid configuration: BFF_DEFAULT_TIMEZONE must be a valid IANA timezone.`);
|
|
56
|
+
}
|
|
57
|
+
return value;
|
|
58
|
+
}
|
|
50
59
|
function parseConfig(env) {
|
|
51
60
|
const normalized = Object.fromEntries(exports.REQUIRED_KEYS.map(key => [key, normalize(env[key])]));
|
|
52
61
|
for (const key of URL_KEYS) {
|
|
@@ -57,6 +66,8 @@ function parseConfig(env) {
|
|
|
57
66
|
}
|
|
58
67
|
const presence = Object.fromEntries(exports.REQUIRED_KEYS.map(key => [key, normalized[key] !== undefined]));
|
|
59
68
|
const tokenEncryptionKey = parseEncryptionKey(env.BFF_TOKEN_ENCRYPTION_KEY);
|
|
69
|
+
const { origins: allowedOrigins, invalid: invalidAllowedOrigins } = (0, origin_1.parseAllowedOrigins)(env.BFF_ALLOWED_ORIGINS);
|
|
70
|
+
const defaultTimezone = parseDefaultTimezone(env.BFF_DEFAULT_TIMEZONE);
|
|
60
71
|
return {
|
|
61
72
|
forestAuthSecret: normalized.FOREST_AUTH_SECRET,
|
|
62
73
|
forestEnvSecret: normalized.FOREST_ENV_SECRET,
|
|
@@ -64,9 +75,12 @@ function parseConfig(env) {
|
|
|
64
75
|
forestAppUrl: normalized.FOREST_APP_URL,
|
|
65
76
|
agentUrl: normalized.AGENT_URL,
|
|
66
77
|
tokenEncryptionKey,
|
|
78
|
+
allowedOrigins,
|
|
79
|
+
invalidAllowedOrigins,
|
|
80
|
+
defaultTimezone,
|
|
67
81
|
httpPort: parsePort(env.HTTP_PORT),
|
|
68
82
|
presence,
|
|
69
83
|
hasAllRequired: exports.REQUIRED_KEYS.every(key => presence[key]) && tokenEncryptionKey !== undefined,
|
|
70
84
|
};
|
|
71
85
|
}
|
|
72
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
86
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW52LWNvbmZpZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jb25maWcvZW52LWNvbmZpZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUE2RkEsa0NBcUNDO0FBbElELDZCQUF3QjtBQUV4QiwyQ0FBcUQ7QUFDckQsMkRBQTJDO0FBQzNDLHNDQUErQztBQUMvQyxtREFBdUQ7QUFFMUMsUUFBQSxhQUFhLEdBQUc7SUFDM0Isb0JBQW9CO0lBQ3BCLG1CQUFtQjtJQUNuQixtQkFBbUI7SUFDbkIsZ0JBQWdCO0lBQ2hCLFdBQVc7Q0FDSCxDQUFDO0FBSVgsTUFBTSxRQUFRLEdBQUcsQ0FBQyxtQkFBbUIsRUFBRSxnQkFBZ0IsRUFBRSxXQUFXLENBQVUsQ0FBQztBQW1CL0UsTUFBTSxlQUFlLEdBQUcsT0FBTyxDQUFDO0FBQ2hDLE1BQU0sUUFBUSxHQUFHLEtBQUssQ0FBQztBQUN2QixNQUFNLG9CQUFvQixHQUFHLEVBQUUsQ0FBQztBQUNoQyxNQUFNLGNBQWMsR0FBRyx3QkFBd0IsQ0FBQztBQUNoRCxNQUFNLGVBQWUsR0FBRyxPQUFDLENBQUMsR0FBRyxDQUFDLEVBQUUsUUFBUSxFQUFFLFVBQVUsRUFBRSxDQUFDLENBQUM7QUFFeEQsU0FBUyxTQUFTLENBQUMsS0FBeUI7SUFDMUMsT0FBTyxLQUFLLEtBQUssU0FBUyxJQUFJLEtBQUssQ0FBQyxJQUFJLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDO0FBQ3hFLENBQUM7QUFFRCxTQUFTLFNBQVMsQ0FBQyxHQUF1QjtJQUN4QyxNQUFNLE9BQU8sR0FBRyxHQUFHLEVBQUUsSUFBSSxFQUFFLENBQUM7SUFDNUIsSUFBSSxPQUFPLEtBQUssU0FBUyxJQUFJLE9BQU8sS0FBSyxFQUFFO1FBQUUsT0FBTyxrQkFBZ0IsQ0FBQztJQUVyRSxNQUFNLElBQUksR0FBRyxlQUFlLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FB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
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Middleware } from 'koa';
|
|
2
|
+
export declare const ALLOWED_METHODS = "GET, POST, PUT, PATCH, DELETE, OPTIONS";
|
|
3
|
+
export declare const ALLOWED_HEADERS = "Authorization, Content-Type, X-Forest-Timezone, X-Forest-Bff-Key, X-Request-Id";
|
|
4
|
+
export declare const PREFLIGHT_MAX_AGE_SECONDS = 600;
|
|
5
|
+
export interface CorsMiddlewareOptions {
|
|
6
|
+
allowedOrigins: string[];
|
|
7
|
+
}
|
|
8
|
+
export default function createCorsMiddleware({ allowedOrigins, }: CorsMiddlewareOptions): Middleware;
|
|
9
|
+
//# sourceMappingURL=cors-middleware.d.ts.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PREFLIGHT_MAX_AGE_SECONDS = exports.ALLOWED_HEADERS = exports.ALLOWED_METHODS = void 0;
|
|
4
|
+
exports.default = createCorsMiddleware;
|
|
5
|
+
const origin_1 = require("./origin");
|
|
6
|
+
exports.ALLOWED_METHODS = 'GET, POST, PUT, PATCH, DELETE, OPTIONS';
|
|
7
|
+
exports.ALLOWED_HEADERS = 'Authorization, Content-Type, X-Forest-Timezone, X-Forest-Bff-Key, X-Request-Id';
|
|
8
|
+
exports.PREFLIGHT_MAX_AGE_SECONDS = 600;
|
|
9
|
+
function createCorsMiddleware({ allowedOrigins, }) {
|
|
10
|
+
return async function corsMiddleware(ctx, next) {
|
|
11
|
+
const origin = ctx.get('Origin');
|
|
12
|
+
if (origin)
|
|
13
|
+
ctx.vary('Origin');
|
|
14
|
+
const allowed = origin ? (0, origin_1.originAllowed)(origin, allowedOrigins) : false;
|
|
15
|
+
if (allowed)
|
|
16
|
+
ctx.set('Access-Control-Allow-Origin', origin);
|
|
17
|
+
if (ctx.method === 'OPTIONS') {
|
|
18
|
+
if (allowed) {
|
|
19
|
+
ctx.set('Access-Control-Allow-Methods', exports.ALLOWED_METHODS);
|
|
20
|
+
ctx.set('Access-Control-Allow-Headers', exports.ALLOWED_HEADERS);
|
|
21
|
+
ctx.set('Access-Control-Max-Age', String(exports.PREFLIGHT_MAX_AGE_SECONDS));
|
|
22
|
+
}
|
|
23
|
+
ctx.status = 204;
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
await next();
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29ycy1taWRkbGV3YXJlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvcnMvY29ycy1taWRkbGV3YXJlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQWFBLHVDQTBCQztBQXJDRCxxQ0FBeUM7QUFFNUIsUUFBQSxlQUFlLEdBQUcsd0NBQXdDLENBQUM7QUFDM0QsUUFBQSxlQUFlLEdBQzFCLGdGQUFnRixDQUFDO0FBQ3RFLFFBQUEseUJBQXlCLEdBQUcsR0FBRyxDQUFDO0FBTTdDLFNBQXdCLG9CQUFvQixDQUFDLEVBQzNDLGNBQWMsR0FDUTtJQUN0QixPQUFPLEtBQUssVUFBVSxjQUFjLENBQUMsR0FBRyxFQUFFLElBQUk7UUFDNUMsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUVqQyxJQUFJLE1BQU07WUFBRSxHQUFHLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBRS9CLE1BQU0sT0FBTyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsSUFBQSxzQkFBYSxFQUFDLE1BQU0sRUFBRSxjQUFjLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDO1FBRXZFLElBQUksT0FBTztZQUFFLEdBQUcsQ0FBQyxHQUFHLENBQUMsNkJBQTZCLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFFNUQsSUFBSSxHQUFHLENBQUMsTUFBTSxLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQzdCLElBQUksT0FBTyxFQUFFLENBQUM7Z0JBQ1osR0FBRyxDQUFDLEdBQUcsQ0FBQyw4QkFBOEIsRUFBRSx1QkFBZSxDQUFDLENBQUM7Z0JBQ3pELEdBQUcsQ0FBQyxHQUFHLENBQUMsOEJBQThCLEVBQUUsdUJBQWUsQ0FBQyxDQUFDO2dCQUN6RCxHQUFHLENBQUMsR0FBRyxDQUFDLHdCQUF3QixFQUFFLE1BQU0sQ0FBQyxpQ0FBeUIsQ0FBQyxDQUFDLENBQUM7WUFDdkUsQ0FBQztZQUVELEdBQUcsQ0FBQyxNQUFNLEdBQUcsR0FBRyxDQUFDO1lBRWpCLE9BQU87UUFDVCxDQUFDO1FBRUQsTUFBTSxJQUFJLEVBQUUsQ0FBQztJQUNmLENBQUMsQ0FBQztBQUNKLENBQUMifQ==
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare function normalizeOrigin(raw: string | undefined | null): string | null;
|
|
2
|
+
export declare function parseAllowedOrigins(raw: string | undefined): {
|
|
3
|
+
origins: string[];
|
|
4
|
+
invalid: string[];
|
|
5
|
+
};
|
|
6
|
+
export declare function originAllowed(requestOrigin: string | undefined, allowList: string[]): boolean;
|
|
7
|
+
//# sourceMappingURL=origin.d.ts.map
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.normalizeOrigin = normalizeOrigin;
|
|
4
|
+
exports.parseAllowedOrigins = parseAllowedOrigins;
|
|
5
|
+
exports.originAllowed = originAllowed;
|
|
6
|
+
function normalizeOrigin(raw) {
|
|
7
|
+
if (raw === undefined || raw === null)
|
|
8
|
+
return null;
|
|
9
|
+
const trimmed = raw.trim();
|
|
10
|
+
if (trimmed === '' || trimmed === 'null')
|
|
11
|
+
return null;
|
|
12
|
+
let url;
|
|
13
|
+
try {
|
|
14
|
+
url = new URL(trimmed);
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
if (url.origin === 'null')
|
|
20
|
+
return null;
|
|
21
|
+
return url.origin;
|
|
22
|
+
}
|
|
23
|
+
function parseAllowedOrigins(raw) {
|
|
24
|
+
if (raw === undefined || raw.trim() === '')
|
|
25
|
+
return { origins: [], invalid: [] };
|
|
26
|
+
const origins = [];
|
|
27
|
+
const invalid = [];
|
|
28
|
+
const entries = raw
|
|
29
|
+
.split(',')
|
|
30
|
+
.map(entry => entry.trim())
|
|
31
|
+
.filter(entry => entry !== '');
|
|
32
|
+
for (const entry of entries) {
|
|
33
|
+
const normalized = normalizeOrigin(entry);
|
|
34
|
+
if (normalized === null)
|
|
35
|
+
invalid.push(entry);
|
|
36
|
+
else if (!origins.includes(normalized))
|
|
37
|
+
origins.push(normalized);
|
|
38
|
+
}
|
|
39
|
+
return { origins, invalid };
|
|
40
|
+
}
|
|
41
|
+
function originAllowed(requestOrigin, allowList) {
|
|
42
|
+
const normalized = normalizeOrigin(requestOrigin);
|
|
43
|
+
if (normalized === null)
|
|
44
|
+
return false;
|
|
45
|
+
return allowList.some(entry => normalizeOrigin(entry) === normalized);
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3JpZ2luLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvcnMvb3JpZ2luLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsMENBaUJDO0FBRUQsa0RBc0JDO0FBRUQsc0NBS0M7QUFoREQsU0FBZ0IsZUFBZSxDQUFDLEdBQThCO0lBQzVELElBQUksR0FBRyxLQUFLLFNBQVMsSUFBSSxHQUFHLEtBQUssSUFBSTtRQUFFLE9BQU8sSUFBSSxDQUFDO0lBRW5ELE1BQU0sT0FBTyxHQUFHLEdBQUcsQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUMzQixJQUFJLE9BQU8sS0FBSyxFQUFFLElBQUksT0FBTyxLQUFLLE1BQU07UUFBRSxPQUFPLElBQUksQ0FBQztJQUV0RCxJQUFJLEdBQVEsQ0FBQztJQUViLElBQUksQ0FBQztRQUNILEdBQUcsR0FBRyxJQUFJLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUN6QixDQUFDO0lBQUMsTUFBTSxDQUFDO1FBQ1AsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQsSUFBSSxHQUFHLENBQUMsTUFBTSxLQUFLLE1BQU07UUFBRSxPQUFPLElBQUksQ0FBQztJQUV2QyxPQUFPLEdBQUcsQ0FBQyxNQUFNLENBQUM7QUFDcEIsQ0FBQztBQUVELFNBQWdCLG1CQUFtQixDQUFDLEdBQXVCO0lBSXpELElBQUksR0FBRyxLQUFLLFNBQVMsSUFBSSxHQUFHLENBQUMsSUFBSSxFQUFFLEtBQUssRUFBRTtRQUFFLE9BQU8sRUFBRSxPQUFPLEVBQUUsRUFBRSxFQUFFLE9BQU8sRUFBRSxFQUFFLEVBQUUsQ0FBQztJQUVoRixNQUFNLE9BQU8sR0FBYSxFQUFFLENBQUM7SUFDN0IsTUFBTSxPQUFPLEdBQWEsRUFBRSxDQUFDO0lBRTdCLE1BQU0sT0FBTyxHQUFHLEdBQUc7U0FDaEIsS0FBSyxDQUFDLEdBQUcsQ0FBQztTQUNWLEdBQUcsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQztTQUMxQixNQUFNLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxLQUFLLEtBQUssRUFBRSxDQUFDLENBQUM7SUFFakMsS0FBSyxNQUFNLEtBQUssSUFBSSxPQUFPLEVBQUUsQ0FBQztRQUM1QixNQUFNLFVBQVUsR0FBRyxlQUFlLENBQUMsS0FBSyxDQUFDLENBQUM7UUFFMUMsSUFBSSxVQUFVLEtBQUssSUFBSTtZQUFFLE9BQU8sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7YUFDeEMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDO1lBQUUsT0FBTyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUNuRSxDQUFDO0lBRUQsT0FBTyxFQUFFLE9BQU8sRUFBRSxPQUFPLEVBQUUsQ0FBQztBQUM5QixDQUFDO0FBRUQsU0FBZ0IsYUFBYSxDQUFDLGFBQWlDLEVBQUUsU0FBbUI7SUFDbEYsTUFBTSxVQUFVLEdBQUcsZUFBZSxDQUFDLGFBQWEsQ0FBQyxDQUFDO0lBQ2xELElBQUksVUFBVSxLQUFLLElBQUk7UUFBRSxPQUFPLEtBQUssQ0FBQztJQUV0QyxPQUFPLFNBQVMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxlQUFlLENBQUMsS0FBSyxDQUFDLEtBQUssVUFBVSxDQUFDLENBQUM7QUFDeEUsQ0FBQyJ9
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = createPerKeyOriginMiddleware;
|
|
4
|
+
const origin_1 = require("./origin");
|
|
5
|
+
const bff_http_error_1 = require("../http/bff-http-error");
|
|
6
|
+
function createPerKeyOriginMiddleware() {
|
|
7
|
+
return async function perKeyOriginMiddleware(ctx, next) {
|
|
8
|
+
const identity = ctx.state.apiKeyIdentity;
|
|
9
|
+
const allowedOrigins = identity?.allowedOrigins ?? [];
|
|
10
|
+
if (allowedOrigins.length > 0 && !(0, origin_1.originAllowed)(ctx.get('Origin'), allowedOrigins)) {
|
|
11
|
+
throw (0, bff_http_error_1.originNotAllowed)();
|
|
12
|
+
}
|
|
13
|
+
await next();
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGVyLWtleS1vcmlnaW4uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29ycy9wZXIta2V5LW9yaWdpbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUtBLCtDQVdDO0FBZEQscUNBQXlDO0FBQ3pDLDJEQUEwRDtBQUUxRCxTQUF3Qiw0QkFBNEI7SUFDbEQsT0FBTyxLQUFLLFVBQVUsc0JBQXNCLENBQUMsR0FBRyxFQUFFLElBQUk7UUFDcEQsTUFBTSxRQUFRLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxjQUEyRCxDQUFDO1FBQ3ZGLE1BQU0sY0FBYyxHQUFHLFFBQVEsRUFBRSxjQUFjLElBQUksRUFBRSxDQUFDO1FBRXRELElBQUksY0FBYyxDQUFDLE1BQU0sR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFBLHNCQUFhLEVBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsRUFBRSxjQUFjLENBQUMsRUFBRSxDQUFDO1lBQ25GLE1BQU0sSUFBQSxpQ0FBZ0IsR0FBRSxDQUFDO1FBQzNCLENBQUM7UUFFRCxNQUFNLElBQUksRUFBRSxDQUFDO0lBQ2YsQ0FBQyxDQUFDO0FBQ0osQ0FBQyJ9
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export declare class BffHttpError extends Error {
|
|
2
|
+
readonly status: number;
|
|
3
|
+
readonly type: string;
|
|
4
|
+
readonly details?: unknown;
|
|
5
|
+
constructor(status: number, type: string, message: string, details?: unknown);
|
|
6
|
+
}
|
|
7
|
+
export interface BffErrorBody {
|
|
8
|
+
error: {
|
|
9
|
+
type: string;
|
|
10
|
+
status: number;
|
|
11
|
+
message: string;
|
|
12
|
+
details?: unknown;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export declare function isSerializableError(error: unknown): error is {
|
|
16
|
+
status: number;
|
|
17
|
+
type: string;
|
|
18
|
+
message: string;
|
|
19
|
+
details?: unknown;
|
|
20
|
+
retryAfter?: number;
|
|
21
|
+
};
|
|
22
|
+
export declare function toErrorBody(error: {
|
|
23
|
+
status: number;
|
|
24
|
+
type: string;
|
|
25
|
+
message: string;
|
|
26
|
+
details?: unknown;
|
|
27
|
+
}): BffErrorBody;
|
|
28
|
+
export declare function unauthorized(message?: string): BffHttpError;
|
|
29
|
+
export declare function ambiguousCredentials(message?: string): BffHttpError;
|
|
30
|
+
export declare function sessionExpired(message?: string): BffHttpError;
|
|
31
|
+
export declare function originNotAllowed(message?: string): BffHttpError;
|
|
32
|
+
export declare function missingTimezone(message?: string): BffHttpError;
|
|
33
|
+
export declare function invalidTimezone(value: string): BffHttpError;
|
|
34
|
+
//# sourceMappingURL=bff-http-error.d.ts.map
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BffHttpError = void 0;
|
|
4
|
+
exports.isSerializableError = isSerializableError;
|
|
5
|
+
exports.toErrorBody = toErrorBody;
|
|
6
|
+
exports.unauthorized = unauthorized;
|
|
7
|
+
exports.ambiguousCredentials = ambiguousCredentials;
|
|
8
|
+
exports.sessionExpired = sessionExpired;
|
|
9
|
+
exports.originNotAllowed = originNotAllowed;
|
|
10
|
+
exports.missingTimezone = missingTimezone;
|
|
11
|
+
exports.invalidTimezone = invalidTimezone;
|
|
12
|
+
class BffHttpError extends Error {
|
|
13
|
+
constructor(status, type, message, details) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.name = 'BffHttpError';
|
|
16
|
+
this.status = status;
|
|
17
|
+
this.type = type;
|
|
18
|
+
this.details = details;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
exports.BffHttpError = BffHttpError;
|
|
22
|
+
function isSerializableError(error) {
|
|
23
|
+
return (typeof error === 'object' &&
|
|
24
|
+
error !== null &&
|
|
25
|
+
typeof error.status === 'number' &&
|
|
26
|
+
typeof error.type === 'string' &&
|
|
27
|
+
typeof error.message === 'string');
|
|
28
|
+
}
|
|
29
|
+
function toErrorBody(error) {
|
|
30
|
+
const body = {
|
|
31
|
+
error: { type: error.type, status: error.status, message: error.message },
|
|
32
|
+
};
|
|
33
|
+
if (error.details !== undefined)
|
|
34
|
+
body.error.details = error.details;
|
|
35
|
+
return body;
|
|
36
|
+
}
|
|
37
|
+
function unauthorized(message = 'Missing or invalid credentials') {
|
|
38
|
+
return new BffHttpError(401, 'unauthorized', message);
|
|
39
|
+
}
|
|
40
|
+
function ambiguousCredentials(message = 'Both Authorization and X-Forest-Bff-Key were provided') {
|
|
41
|
+
return new BffHttpError(400, 'ambiguous_credentials', message);
|
|
42
|
+
}
|
|
43
|
+
function sessionExpired(message = 'The BFF session has expired') {
|
|
44
|
+
return new BffHttpError(401, 'session_expired', message);
|
|
45
|
+
}
|
|
46
|
+
function originNotAllowed(message = 'Origin is not allowed for this key') {
|
|
47
|
+
return new BffHttpError(403, 'origin_not_allowed', message);
|
|
48
|
+
}
|
|
49
|
+
function missingTimezone(message = 'A timezone is required but none was provided') {
|
|
50
|
+
return new BffHttpError(400, 'missing_timezone', message);
|
|
51
|
+
}
|
|
52
|
+
function invalidTimezone(value) {
|
|
53
|
+
return new BffHttpError(400, 'invalid_timezone', `Invalid timezone: "${value}"`);
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmZmLWh0dHAtZXJyb3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaHR0cC9iZmYtaHR0cC1lcnJvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUF1QkEsa0RBY0M7QUFFRCxrQ0FhQztBQUVELG9DQUVDO0FBRUQsb0RBSUM7QUFFRCx3Q0FFQztBQUVELDRDQUVDO0FBRUQsMENBSUM7QUFFRCwwQ0FFQztBQWhGRCxNQUFhLFlBQWEsU0FBUSxLQUFLO0lBS3JDLFlBQVksTUFBYyxFQUFFLElBQVksRUFBRSxPQUFlLEVBQUUsT0FBaUI7UUFDMUUsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ2YsSUFBSSxDQUFDLElBQUksR0FBRyxjQUFjLENBQUM7UUFDM0IsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7UUFDckIsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUM7UUFDakIsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUM7SUFDekIsQ0FBQztDQUNGO0FBWkQsb0NBWUM7QUFXRCxTQUFnQixtQkFBbUIsQ0FBQyxLQUFjO0lBT2hELE9BQU8sQ0FDTCxPQUFPLEtBQUssS0FBSyxRQUFRO1FBQ3pCLEtBQUssS0FBSyxJQUFJO1FBQ2QsT0FBUSxLQUE4QixDQUFDLE1BQU0sS0FBSyxRQUFRO1FBQzFELE9BQVEsS0FBNEIsQ0FBQyxJQUFJLEtBQUssUUFBUTtRQUN0RCxPQUFRLEtBQStCLENBQUMsT0FBTyxLQUFLLFFBQVEsQ0FDN0QsQ0FBQztBQUNKLENBQUM7QUFFRCxTQUFnQixXQUFXLENBQUMsS0FLM0I7SUFDQyxNQUFNLElBQUksR0FBaUI7UUFDekIsS0FBSyxFQUFFLEVBQUUsSUFBSSxFQUFFLEtBQUssQ0FBQyxJQUFJLEVBQUUsTUFBTSxFQUFFLEtBQUssQ0FBQyxNQUFNLEVBQUUsT0FBTyxFQUFFLEtBQUssQ0FBQyxPQUFPLEVBQUU7S0FDMUUsQ0FBQztJQUVGLElBQUksS0FBSyxDQUFDLE9BQU8sS0FBSyxTQUFTO1FBQUUsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQztJQUVwRSxPQUFPLElBQUksQ0FBQztBQUNkLENBQUM7QUFFRCxTQUFnQixZQUFZLENBQUMsT0FBTyxHQUFHLGdDQUFnQztJQUNyRSxPQUFPLElBQUksWUFBWSxDQUFDLEdBQUcsRUFBRSxjQUFjLEVBQUUsT0FBTyxDQUFDLENBQUM7QUFDeEQsQ0FBQztBQUVELFNBQWdCLG9CQUFvQixDQUNsQyxPQUFPLEdBQUcsdURBQXVEO0lBRWpFLE9BQU8sSUFBSSxZQUFZLENBQUMsR0FBRyxFQUFFLHVCQUF1QixFQUFFLE9BQU8sQ0FBQyxDQUFDO0FBQ2pFLENBQUM7QUFFRCxTQUFnQixjQUFjLENBQUMsT0FBTyxHQUFHLDZCQUE2QjtJQUNwRSxPQUFPLElBQUksWUFBWSxDQUFDLEdBQUcsRUFBRSxpQkFBaUIsRUFBRSxPQUFPLENBQUMsQ0FBQztBQUMzRCxDQUFDO0FBRUQsU0FBZ0IsZ0JBQWdCLENBQUMsT0FBTyxHQUFHLG9DQUFvQztJQUM3RSxPQUFPLElBQUksWUFBWSxDQUFDLEdBQUcsRUFBRSxvQkFBb0IsRUFBRSxPQUFPLENBQUMsQ0FBQztBQUM5RCxDQUFDO0FBRUQsU0FBZ0IsZUFBZSxDQUM3QixPQUFPLEdBQUcsOENBQThDO0lBRXhELE9BQU8sSUFBSSxZQUFZLENBQUMsR0FBRyxFQUFFLGtCQUFrQixFQUFFLE9BQU8sQ0FBQyxDQUFDO0FBQzVELENBQUM7QUFFRCxTQUFnQixlQUFlLENBQUMsS0FBYTtJQUMzQyxPQUFPLElBQUksWUFBWSxDQUFDLEdBQUcsRUFBRSxrQkFBa0IsRUFBRSxzQkFBc0IsS0FBSyxHQUFHLENBQUMsQ0FBQztBQUNuRixDQUFDIn0=
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Logger } from '../ports/logger-port';
|
|
2
|
+
import type { Middleware } from 'koa';
|
|
3
|
+
export interface ErrorMiddlewareOptions {
|
|
4
|
+
logger: Logger;
|
|
5
|
+
}
|
|
6
|
+
export default function createErrorMiddleware({ logger }: ErrorMiddlewareOptions): Middleware;
|
|
7
|
+
//# sourceMappingURL=error-middleware.d.ts.map
|