@forestadmin/agent-bff 1.0.0 → 1.2.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 +19 -0
- package/dist/cli-core.js +51 -2
- package/dist/config/env-config.d.ts +1 -0
- package/dist/config/env-config.js +16 -2
- package/dist/http/bff-http-server.d.ts +2 -0
- package/dist/http/bff-http-server.js +4 -1
- package/dist/index.d.ts +11 -0
- package/dist/index.js +20 -2
- package/dist/oauth/bff-token.d.ts +24 -0
- package/dist/oauth/bff-token.js +29 -0
- package/dist/oauth/forest-server-client.d.ts +40 -0
- package/dist/oauth/forest-server-client.js +104 -0
- package/dist/oauth/oauth-error.d.ts +19 -0
- package/dist/oauth/oauth-error.js +49 -0
- package/dist/oauth/oauth-exchange-error.d.ts +5 -0
- package/dist/oauth/oauth-exchange-error.js +11 -0
- package/dist/oauth/oauth-routes.d.ts +14 -0
- package/dist/oauth/oauth-routes.js +352 -0
- package/dist/oauth/pkce.d.ts +8 -0
- package/dist/oauth/pkce.js +23 -0
- package/dist/oauth/session-lifecycle.d.ts +9 -0
- package/dist/oauth/session-lifecycle.js +57 -0
- package/dist/oauth/session-store.d.ts +61 -0
- package/dist/oauth/session-store.js +168 -0
- package/dist/oauth/token-cipher.d.ts +11 -0
- package/dist/oauth/token-cipher.js +42 -0
- package/package.json +5 -1
|
@@ -0,0 +1,168 @@
|
|
|
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.createSid = createSid;
|
|
7
|
+
exports.default = createInMemorySessionStore;
|
|
8
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
9
|
+
const DEFAULT_AUTH_CODE_TTL_SECONDS = 5 * 60;
|
|
10
|
+
const DEFAULT_MAX_PENDING_CODES = 10000;
|
|
11
|
+
function createSid() {
|
|
12
|
+
return crypto_1.default.randomBytes(32).toString('base64url');
|
|
13
|
+
}
|
|
14
|
+
function createOpaqueToken() {
|
|
15
|
+
return crypto_1.default.randomBytes(32).toString('base64url');
|
|
16
|
+
}
|
|
17
|
+
function hashToken(token) {
|
|
18
|
+
return crypto_1.default.createHash('sha256').update(token).digest('base64url');
|
|
19
|
+
}
|
|
20
|
+
function createInMemorySessionStore({ cipher, now, sessionTtlSeconds, authCodeTtlSeconds = DEFAULT_AUTH_CODE_TTL_SECONDS, maxPendingCodes = DEFAULT_MAX_PENDING_CODES, }) {
|
|
21
|
+
const sessions = new Map();
|
|
22
|
+
const usedCodes = new Map();
|
|
23
|
+
const activeRefreshHashToSid = new Map();
|
|
24
|
+
const rotatedRefreshHashToSid = new Map();
|
|
25
|
+
const lastRotationBySid = new Map();
|
|
26
|
+
function forgetRefreshHashes(sid) {
|
|
27
|
+
for (const [hash, owner] of activeRefreshHashToSid) {
|
|
28
|
+
if (owner === sid)
|
|
29
|
+
activeRefreshHashToSid.delete(hash);
|
|
30
|
+
}
|
|
31
|
+
for (const [hash, owner] of rotatedRefreshHashToSid) {
|
|
32
|
+
if (owner === sid)
|
|
33
|
+
rotatedRefreshHashToSid.delete(hash);
|
|
34
|
+
}
|
|
35
|
+
lastRotationBySid.delete(sid);
|
|
36
|
+
}
|
|
37
|
+
function dropSession(sid) {
|
|
38
|
+
sessions.delete(sid);
|
|
39
|
+
forgetRefreshHashes(sid);
|
|
40
|
+
}
|
|
41
|
+
function purgeExpiredCodes() {
|
|
42
|
+
const current = now();
|
|
43
|
+
for (const [code, expiresAt] of usedCodes) {
|
|
44
|
+
if (current >= expiresAt)
|
|
45
|
+
usedCodes.delete(code);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function purgeExpiredSessions() {
|
|
49
|
+
const current = now();
|
|
50
|
+
for (const [sid, session] of sessions) {
|
|
51
|
+
if (current >= session.expiresAt)
|
|
52
|
+
dropSession(sid);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function liveSession(sid) {
|
|
56
|
+
const session = sessions.get(sid);
|
|
57
|
+
if (!session)
|
|
58
|
+
return undefined;
|
|
59
|
+
if (now() >= session.expiresAt) {
|
|
60
|
+
dropSession(sid);
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
return session;
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
create(input) {
|
|
67
|
+
purgeExpiredSessions();
|
|
68
|
+
const sid = createSid();
|
|
69
|
+
const refreshToken = createOpaqueToken();
|
|
70
|
+
const refreshTokenHash = hashToken(refreshToken);
|
|
71
|
+
sessions.set(sid, {
|
|
72
|
+
saasAccessToken: input.saasAccessToken,
|
|
73
|
+
saasRefreshTokenBlob: cipher.encrypt(input.saasRefreshToken),
|
|
74
|
+
refreshTokenHash,
|
|
75
|
+
renderingId: input.renderingId,
|
|
76
|
+
userId: input.userId,
|
|
77
|
+
expiresAt: now() + sessionTtlSeconds * 1000,
|
|
78
|
+
});
|
|
79
|
+
activeRefreshHashToSid.set(refreshTokenHash, sid);
|
|
80
|
+
return { sid, refreshToken };
|
|
81
|
+
},
|
|
82
|
+
get(sid) {
|
|
83
|
+
const session = liveSession(sid);
|
|
84
|
+
return session ? { ...session } : undefined;
|
|
85
|
+
},
|
|
86
|
+
getSaasRefreshToken(sid) {
|
|
87
|
+
const session = liveSession(sid);
|
|
88
|
+
return session ? cipher.decrypt(session.saasRefreshTokenBlob) : undefined;
|
|
89
|
+
},
|
|
90
|
+
updateSaasTokens(sid, tokens) {
|
|
91
|
+
const session = liveSession(sid);
|
|
92
|
+
if (!session)
|
|
93
|
+
return;
|
|
94
|
+
session.saasAccessToken = tokens.saasAccessToken;
|
|
95
|
+
session.saasRefreshTokenBlob = cipher.encrypt(tokens.saasRefreshToken);
|
|
96
|
+
},
|
|
97
|
+
prepareRotation(presentedToken) {
|
|
98
|
+
const hash = hashToken(presentedToken);
|
|
99
|
+
const reusedSid = rotatedRefreshHashToSid.get(hash);
|
|
100
|
+
if (reusedSid !== undefined) {
|
|
101
|
+
const session = liveSession(reusedSid);
|
|
102
|
+
if (!session)
|
|
103
|
+
return { outcome: 'unknown' };
|
|
104
|
+
const lastRotation = lastRotationBySid.get(reusedSid);
|
|
105
|
+
if (lastRotation?.rotatedHash === hash) {
|
|
106
|
+
return {
|
|
107
|
+
outcome: 'replay',
|
|
108
|
+
sid: reusedSid,
|
|
109
|
+
renderingId: session.renderingId,
|
|
110
|
+
lastIssuedRefreshToken: cipher.decrypt(lastRotation.issuedRefreshBlob),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
return { outcome: 'reuse', sid: reusedSid };
|
|
114
|
+
}
|
|
115
|
+
const sid = activeRefreshHashToSid.get(hash);
|
|
116
|
+
if (sid === undefined)
|
|
117
|
+
return { outcome: 'unknown' };
|
|
118
|
+
const session = liveSession(sid);
|
|
119
|
+
if (!session)
|
|
120
|
+
return { outcome: 'unknown' };
|
|
121
|
+
return {
|
|
122
|
+
outcome: 'ready',
|
|
123
|
+
sid,
|
|
124
|
+
renderingId: session.renderingId,
|
|
125
|
+
newRefreshToken: createOpaqueToken(),
|
|
126
|
+
};
|
|
127
|
+
},
|
|
128
|
+
commitRotation(presentedToken, newRefreshToken) {
|
|
129
|
+
const hash = hashToken(presentedToken);
|
|
130
|
+
const sid = activeRefreshHashToSid.get(hash);
|
|
131
|
+
if (sid === undefined)
|
|
132
|
+
return false;
|
|
133
|
+
const session = liveSession(sid);
|
|
134
|
+
if (!session)
|
|
135
|
+
return false;
|
|
136
|
+
const newHash = hashToken(newRefreshToken);
|
|
137
|
+
activeRefreshHashToSid.delete(hash);
|
|
138
|
+
rotatedRefreshHashToSid.set(hash, sid);
|
|
139
|
+
lastRotationBySid.set(sid, {
|
|
140
|
+
rotatedHash: hash,
|
|
141
|
+
issuedRefreshBlob: cipher.encrypt(newRefreshToken),
|
|
142
|
+
});
|
|
143
|
+
activeRefreshHashToSid.set(newHash, sid);
|
|
144
|
+
session.refreshTokenHash = newHash;
|
|
145
|
+
return true;
|
|
146
|
+
},
|
|
147
|
+
destroy(sid) {
|
|
148
|
+
dropSession(sid);
|
|
149
|
+
},
|
|
150
|
+
claimAuthorizationCode(code) {
|
|
151
|
+
purgeExpiredCodes();
|
|
152
|
+
if (usedCodes.has(code))
|
|
153
|
+
return false;
|
|
154
|
+
if (usedCodes.size >= maxPendingCodes)
|
|
155
|
+
return false;
|
|
156
|
+
usedCodes.set(code, now() + authCodeTtlSeconds * 1000);
|
|
157
|
+
return true;
|
|
158
|
+
},
|
|
159
|
+
releaseAuthorizationCode(code) {
|
|
160
|
+
usedCodes.delete(code);
|
|
161
|
+
},
|
|
162
|
+
pendingClaimCount() {
|
|
163
|
+
purgeExpiredCodes();
|
|
164
|
+
return usedCodes.size;
|
|
165
|
+
},
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2Vzc2lvbi1zdG9yZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9vYXV0aC9zZXNzaW9uLXN0b3JlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBNERBLDhCQUVDO0FBVUQsNkNBMExDO0FBaFFELG9EQUE0QjtBQXVENUIsTUFBTSw2QkFBNkIsR0FBRyxDQUFDLEdBQUcsRUFBRSxDQUFDO0FBQzdDLE1BQU0seUJBQXlCLEdBQUcsS0FBTSxDQUFDO0FBRXpDLFNBQWdCLFNBQVM7SUFDdkIsT0FBTyxnQkFBTSxDQUFDLFdBQVcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDLENBQUM7QUFDdEQsQ0FBQztBQUVELFNBQVMsaUJBQWlCO0lBQ3hCLE9BQU8sZ0JBQU0sQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDLENBQUMsUUFBUSxDQUFDLFdBQVcsQ0FBQyxDQUFDO0FBQ3RELENBQUM7QUFFRCxTQUFTLFNBQVMsQ0FBQyxLQUFhO0lBQzlCLE9BQU8sZ0JBQU0sQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLE1BQU0sQ0FBQyxXQUFXLENBQUMsQ0FBQztBQUN2RSxDQUFDO0FBRUQsU0FBd0IsMEJBQTBCLENBQUMsRUFDakQsTUFBTSxFQUNOLEdBQUcsRUFDSCxpQkFBaUIsRUFDakIsa0JBQWtCLEdBQUcsNkJBQTZCLEVBQ2xELGVBQWUsR0FBRyx5QkFBeUIsR0FDdkI7SUFDcEIsTUFBTSxRQUFRLEdBQUcsSUFBSSxHQUFHLEVBQXlCLENBQUM7SUFDbEQsTUFBTSxTQUFTLEdBQUcsSUFBSSxHQUFHLEVBQWtCLENBQUM7SUFDNUMsTUFBTSxzQkFBc0IsR0FBRyxJQUFJLEdBQUcsRUFBa0IsQ0FBQztJQUN6RCxNQUFNLHVCQUF1QixHQUFHLElBQUksR0FBRyxFQUFrQixDQUFDO0lBQzFELE1BQU0saUJBQWlCLEdBQUcsSUFBSSxHQUFHLEVBRzlCLENB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
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface EncryptedBlob {
|
|
2
|
+
iv: string;
|
|
3
|
+
authTag: string;
|
|
4
|
+
ciphertext: string;
|
|
5
|
+
}
|
|
6
|
+
export interface TokenCipher {
|
|
7
|
+
encrypt(plaintext: string): EncryptedBlob;
|
|
8
|
+
decrypt(blob: EncryptedBlob): string;
|
|
9
|
+
}
|
|
10
|
+
export default function createTokenCipher(base64Key: string): TokenCipher;
|
|
11
|
+
//# sourceMappingURL=token-cipher.d.ts.map
|
|
@@ -0,0 +1,42 @@
|
|
|
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.default = createTokenCipher;
|
|
7
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
8
|
+
const ALGORITHM = 'aes-256-gcm';
|
|
9
|
+
const IV_BYTES = 12;
|
|
10
|
+
function bytes(value) {
|
|
11
|
+
return new Uint8Array(typeof value === 'string' ? Buffer.from(value, 'base64') : value);
|
|
12
|
+
}
|
|
13
|
+
function toBase64(value) {
|
|
14
|
+
return Buffer.from(value).toString('base64');
|
|
15
|
+
}
|
|
16
|
+
function createTokenCipher(base64Key) {
|
|
17
|
+
const key = bytes(base64Key);
|
|
18
|
+
return {
|
|
19
|
+
encrypt(plaintext) {
|
|
20
|
+
const iv = new Uint8Array(crypto_1.default.randomBytes(IV_BYTES));
|
|
21
|
+
const cipher = crypto_1.default.createCipheriv(ALGORITHM, key, iv);
|
|
22
|
+
const ciphertext = new Uint8Array(Buffer.concat([
|
|
23
|
+
new Uint8Array(cipher.update(plaintext, 'utf8')),
|
|
24
|
+
new Uint8Array(cipher.final()),
|
|
25
|
+
]));
|
|
26
|
+
return {
|
|
27
|
+
iv: toBase64(iv),
|
|
28
|
+
authTag: toBase64(new Uint8Array(cipher.getAuthTag())),
|
|
29
|
+
ciphertext: toBase64(ciphertext),
|
|
30
|
+
};
|
|
31
|
+
},
|
|
32
|
+
decrypt({ iv, authTag, ciphertext }) {
|
|
33
|
+
const decipher = crypto_1.default.createDecipheriv(ALGORITHM, key, bytes(iv));
|
|
34
|
+
decipher.setAuthTag(bytes(authTag));
|
|
35
|
+
return Buffer.concat([
|
|
36
|
+
new Uint8Array(decipher.update(bytes(ciphertext))),
|
|
37
|
+
new Uint8Array(decipher.final()),
|
|
38
|
+
]).toString('utf8');
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9rZW4tY2lwaGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL29hdXRoL3Rva2VuLWNpcGhlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQXdCQSxvQ0E4QkM7QUF0REQsb0RBQTRCO0FBRTVCLE1BQU0sU0FBUyxHQUFHLGFBQWEsQ0FBQztBQUNoQyxNQUFNLFFBQVEsR0FBRyxFQUFFLENBQUM7QUFhcEIsU0FBUyxLQUFLLENBQUMsS0FBMEI7SUFDdkMsT0FBTyxJQUFJLFVBQVUsQ0FBQyxPQUFPLEtBQUssS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUMxRixDQUFDO0FBRUQsU0FBUyxRQUFRLENBQUMsS0FBaUI7SUFDakMsT0FBTyxNQUFNLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsQ0FBQztBQUMvQyxDQUFDO0FBRUQsU0FBd0IsaUJBQWlCLENBQUMsU0FBaUI7SUFDekQsTUFBTSxHQUFHLEdBQUcsS0FBSyxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBRTdCLE9BQU87UUFDTCxPQUFPLENBQUMsU0FBUztZQUNmLE1BQU0sRUFBRSxHQUFHLElBQUksVUFBVSxDQUFDLGdCQUFNLENBQUMsV0FBVyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUM7WUFDeEQsTUFBTSxNQUFNLEdBQUcsZ0JBQU0sQ0FBQyxjQUFjLENBQUMsU0FBUyxFQUFFLEdBQUcsRUFBRSxFQUFFLENBQUMsQ0FBQztZQUN6RCxNQUFNLFVBQVUsR0FBRyxJQUFJLFVBQVUsQ0FDL0IsTUFBTSxDQUFDLE1BQU0sQ0FBQztnQkFDWixJQUFJLFVBQVUsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLFNBQVMsRUFBRSxNQUFNLENBQUMsQ0FBQztnQkFDaEQsSUFBSSxVQUFVLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRSxDQUFDO2FBQy9CLENBQUMsQ0FDSCxDQUFDO1lBRUYsT0FBTztnQkFDTCxFQUFFLEVBQUUsUUFBUSxDQUFDLEVBQUUsQ0FBQztnQkFDaEIsT0FBTyxFQUFFLFFBQVEsQ0FBQyxJQUFJLFVBQVUsQ0FBQyxNQUFNLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQztnQkFDdEQsVUFBVSxFQUFFLFFBQVEsQ0FBQyxVQUFVLENBQUM7YUFDakMsQ0FBQztRQUNKLENBQUM7UUFDRCxPQUFPLENBQUMsRUFBRSxFQUFFLEVBQUUsT0FBTyxFQUFFLFVBQVUsRUFBRTtZQUNqQyxNQUFNLFFBQVEsR0FBRyxnQkFBTSxDQUFDLGdCQUFnQixDQUFDLFNBQVMsRUFBRSxHQUFHLEVBQUUsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7WUFDcEUsUUFBUSxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQztZQUVwQyxPQUFPLE1BQU0sQ0FBQyxNQUFNLENBQUM7Z0JBQ25CLElBQUksVUFBVSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUM7Z0JBQ2xELElBQUksVUFBVSxDQUFDLFFBQVEsQ0FBQyxLQUFLLEVBQUUsQ0FBQzthQUNqQyxDQUFDLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ3RCLENBQUM7S0FDRixDQUFDO0FBQ0osQ0FBQyJ9
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forestadmin/agent-bff",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"bin": {
|
|
6
6
|
"forest-bff": "dist/cli.js"
|
|
@@ -31,10 +31,14 @@
|
|
|
31
31
|
"test": "jest"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
+
"@forestadmin/forestadmin-client": "1.40.3",
|
|
35
|
+
"@koa/bodyparser": "^6.1.0",
|
|
36
|
+
"jsonwebtoken": "^9.0.3",
|
|
34
37
|
"koa": "^3.0.1",
|
|
35
38
|
"zod": "4.3.6"
|
|
36
39
|
},
|
|
37
40
|
"devDependencies": {
|
|
41
|
+
"@types/jsonwebtoken": "^9.0.1",
|
|
38
42
|
"@types/koa": "^2.13.5",
|
|
39
43
|
"@types/supertest": "^6.0.2",
|
|
40
44
|
"supertest": "^7.1.3"
|