@agenticmail/enterprise 0.5.310 → 0.5.312
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/dist/agent-heartbeat-5Y7JCWDU.js +510 -0
- package/dist/agent-heartbeat-RLRA5KVZ.js +510 -0
- package/dist/chunk-EKMS2KSE.js +25098 -0
- package/dist/chunk-FNUFLQJ3.js +4909 -0
- package/dist/chunk-HP42WFMQ.js +4909 -0
- package/dist/chunk-HZZPIICV.js +25098 -0
- package/dist/chunk-MBT5ND3D.js +1519 -0
- package/dist/chunk-NM4KTDG2.js +4932 -0
- package/dist/chunk-OPOBUYJT.js +1519 -0
- package/dist/chunk-PFMIOSR5.js +1519 -0
- package/dist/chunk-VKSOKBVG.js +4932 -0
- package/dist/chunk-Y2KIY4BA.js +4969 -0
- package/dist/cli-agent-EV7RDHZ4.js +2169 -0
- package/dist/cli-agent-KWSWAFQU.js +2169 -0
- package/dist/cli-serve-COFEVLTD.js +143 -0
- package/dist/cli-serve-FE4CMMSN.js +143 -0
- package/dist/cli-serve-PSM73OAW.js +143 -0
- package/dist/cli.js +3 -3
- package/dist/dashboard/app.js +8 -1
- package/dist/index.js +4 -4
- package/dist/routes-A2PWCOQV.js +90 -0
- package/dist/routes-SL5Y25K3.js +90 -0
- package/dist/runtime-KFD322X5.js +45 -0
- package/dist/runtime-UCP46CVY.js +45 -0
- package/dist/server-6JMYVJVM.js +28 -0
- package/dist/server-CA2I3LJY.js +28 -0
- package/dist/server-ZA2N7MOP.js +28 -0
- package/dist/setup-HUYSMSBI.js +20 -0
- package/dist/setup-PT6WGOYB.js +20 -0
- package/dist/setup-VF4ZBLQQ.js +20 -0
- package/package.json +1 -1
- package/src/admin/routes.ts +24 -4
- package/src/auth/routes.ts +14 -11
- package/src/dashboard/app.js +8 -1
- package/src/engine/compliance.ts +2 -2
- package/src/server.ts +30 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AgentRuntime,
|
|
3
|
+
EmailChannel,
|
|
4
|
+
FollowUpScheduler,
|
|
5
|
+
SessionManager,
|
|
6
|
+
SubAgentManager,
|
|
7
|
+
ToolRegistry,
|
|
8
|
+
callLLM,
|
|
9
|
+
createAgentRuntime,
|
|
10
|
+
createNoopHooks,
|
|
11
|
+
createRuntimeHooks,
|
|
12
|
+
estimateMessageTokens,
|
|
13
|
+
estimateTokens,
|
|
14
|
+
executeTool,
|
|
15
|
+
runAgentLoop,
|
|
16
|
+
toolsToDefinitions
|
|
17
|
+
} from "./chunk-FNUFLQJ3.js";
|
|
18
|
+
import {
|
|
19
|
+
PROVIDER_REGISTRY,
|
|
20
|
+
listAllProviders,
|
|
21
|
+
resolveApiKeyForProvider,
|
|
22
|
+
resolveProvider
|
|
23
|
+
} from "./chunk-UF3ZJMJO.js";
|
|
24
|
+
import "./chunk-KFQGP6VL.js";
|
|
25
|
+
export {
|
|
26
|
+
AgentRuntime,
|
|
27
|
+
EmailChannel,
|
|
28
|
+
FollowUpScheduler,
|
|
29
|
+
PROVIDER_REGISTRY,
|
|
30
|
+
SessionManager,
|
|
31
|
+
SubAgentManager,
|
|
32
|
+
ToolRegistry,
|
|
33
|
+
callLLM,
|
|
34
|
+
createAgentRuntime,
|
|
35
|
+
createNoopHooks,
|
|
36
|
+
createRuntimeHooks,
|
|
37
|
+
estimateMessageTokens,
|
|
38
|
+
estimateTokens,
|
|
39
|
+
executeTool,
|
|
40
|
+
listAllProviders,
|
|
41
|
+
resolveApiKeyForProvider,
|
|
42
|
+
resolveProvider,
|
|
43
|
+
runAgentLoop,
|
|
44
|
+
toolsToDefinitions
|
|
45
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AgentRuntime,
|
|
3
|
+
EmailChannel,
|
|
4
|
+
FollowUpScheduler,
|
|
5
|
+
SessionManager,
|
|
6
|
+
SubAgentManager,
|
|
7
|
+
ToolRegistry,
|
|
8
|
+
callLLM,
|
|
9
|
+
createAgentRuntime,
|
|
10
|
+
createNoopHooks,
|
|
11
|
+
createRuntimeHooks,
|
|
12
|
+
estimateMessageTokens,
|
|
13
|
+
estimateTokens,
|
|
14
|
+
executeTool,
|
|
15
|
+
runAgentLoop,
|
|
16
|
+
toolsToDefinitions
|
|
17
|
+
} from "./chunk-HP42WFMQ.js";
|
|
18
|
+
import {
|
|
19
|
+
PROVIDER_REGISTRY,
|
|
20
|
+
listAllProviders,
|
|
21
|
+
resolveApiKeyForProvider,
|
|
22
|
+
resolveProvider
|
|
23
|
+
} from "./chunk-UF3ZJMJO.js";
|
|
24
|
+
import "./chunk-KFQGP6VL.js";
|
|
25
|
+
export {
|
|
26
|
+
AgentRuntime,
|
|
27
|
+
EmailChannel,
|
|
28
|
+
FollowUpScheduler,
|
|
29
|
+
PROVIDER_REGISTRY,
|
|
30
|
+
SessionManager,
|
|
31
|
+
SubAgentManager,
|
|
32
|
+
ToolRegistry,
|
|
33
|
+
callLLM,
|
|
34
|
+
createAgentRuntime,
|
|
35
|
+
createNoopHooks,
|
|
36
|
+
createRuntimeHooks,
|
|
37
|
+
estimateMessageTokens,
|
|
38
|
+
estimateTokens,
|
|
39
|
+
executeTool,
|
|
40
|
+
listAllProviders,
|
|
41
|
+
resolveApiKeyForProvider,
|
|
42
|
+
resolveProvider,
|
|
43
|
+
runAgentLoop,
|
|
44
|
+
toolsToDefinitions
|
|
45
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createServer
|
|
3
|
+
} from "./chunk-VKSOKBVG.js";
|
|
4
|
+
import "./chunk-DJBCRQTD.js";
|
|
5
|
+
import "./chunk-UF3ZJMJO.js";
|
|
6
|
+
import "./chunk-EKMS2KSE.js";
|
|
7
|
+
import "./chunk-VSBC4SWO.js";
|
|
8
|
+
import "./chunk-AF3WSNVX.js";
|
|
9
|
+
import "./chunk-74ZCQKYU.js";
|
|
10
|
+
import "./chunk-MOGIJA6K.js";
|
|
11
|
+
import "./chunk-C6JP5NR6.js";
|
|
12
|
+
import "./chunk-M6ZIC5H3.js";
|
|
13
|
+
import "./chunk-PWWV2U5P.js";
|
|
14
|
+
import "./chunk-MXK7RLTF.js";
|
|
15
|
+
import "./chunk-3FMK32KQ.js";
|
|
16
|
+
import "./chunk-Z7NVD3OQ.js";
|
|
17
|
+
import "./chunk-YDD5TC5Q.js";
|
|
18
|
+
import "./chunk-37ABTUFU.js";
|
|
19
|
+
import "./chunk-NU657BBQ.js";
|
|
20
|
+
import "./chunk-PGAU3W3M.js";
|
|
21
|
+
import "./chunk-JGEVQZDR.js";
|
|
22
|
+
import "./chunk-WUAWWKTN.js";
|
|
23
|
+
import "./chunk-HS5YWSGM.js";
|
|
24
|
+
import "./chunk-22U7TZPN.js";
|
|
25
|
+
import "./chunk-KFQGP6VL.js";
|
|
26
|
+
export {
|
|
27
|
+
createServer
|
|
28
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createServer
|
|
3
|
+
} from "./chunk-Y2KIY4BA.js";
|
|
4
|
+
import "./chunk-DJBCRQTD.js";
|
|
5
|
+
import "./chunk-UF3ZJMJO.js";
|
|
6
|
+
import "./chunk-EKMS2KSE.js";
|
|
7
|
+
import "./chunk-VSBC4SWO.js";
|
|
8
|
+
import "./chunk-AF3WSNVX.js";
|
|
9
|
+
import "./chunk-74ZCQKYU.js";
|
|
10
|
+
import "./chunk-MOGIJA6K.js";
|
|
11
|
+
import "./chunk-C6JP5NR6.js";
|
|
12
|
+
import "./chunk-M6ZIC5H3.js";
|
|
13
|
+
import "./chunk-PWWV2U5P.js";
|
|
14
|
+
import "./chunk-MXK7RLTF.js";
|
|
15
|
+
import "./chunk-3FMK32KQ.js";
|
|
16
|
+
import "./chunk-Z7NVD3OQ.js";
|
|
17
|
+
import "./chunk-YDD5TC5Q.js";
|
|
18
|
+
import "./chunk-37ABTUFU.js";
|
|
19
|
+
import "./chunk-NU657BBQ.js";
|
|
20
|
+
import "./chunk-PGAU3W3M.js";
|
|
21
|
+
import "./chunk-JGEVQZDR.js";
|
|
22
|
+
import "./chunk-WUAWWKTN.js";
|
|
23
|
+
import "./chunk-HS5YWSGM.js";
|
|
24
|
+
import "./chunk-22U7TZPN.js";
|
|
25
|
+
import "./chunk-KFQGP6VL.js";
|
|
26
|
+
export {
|
|
27
|
+
createServer
|
|
28
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createServer
|
|
3
|
+
} from "./chunk-NM4KTDG2.js";
|
|
4
|
+
import "./chunk-DJBCRQTD.js";
|
|
5
|
+
import "./chunk-UF3ZJMJO.js";
|
|
6
|
+
import "./chunk-HZZPIICV.js";
|
|
7
|
+
import "./chunk-VSBC4SWO.js";
|
|
8
|
+
import "./chunk-AF3WSNVX.js";
|
|
9
|
+
import "./chunk-74ZCQKYU.js";
|
|
10
|
+
import "./chunk-MOGIJA6K.js";
|
|
11
|
+
import "./chunk-C6JP5NR6.js";
|
|
12
|
+
import "./chunk-M6ZIC5H3.js";
|
|
13
|
+
import "./chunk-PWWV2U5P.js";
|
|
14
|
+
import "./chunk-MXK7RLTF.js";
|
|
15
|
+
import "./chunk-3FMK32KQ.js";
|
|
16
|
+
import "./chunk-Z7NVD3OQ.js";
|
|
17
|
+
import "./chunk-YDD5TC5Q.js";
|
|
18
|
+
import "./chunk-37ABTUFU.js";
|
|
19
|
+
import "./chunk-NU657BBQ.js";
|
|
20
|
+
import "./chunk-PGAU3W3M.js";
|
|
21
|
+
import "./chunk-JGEVQZDR.js";
|
|
22
|
+
import "./chunk-WUAWWKTN.js";
|
|
23
|
+
import "./chunk-HS5YWSGM.js";
|
|
24
|
+
import "./chunk-22U7TZPN.js";
|
|
25
|
+
import "./chunk-KFQGP6VL.js";
|
|
26
|
+
export {
|
|
27
|
+
createServer
|
|
28
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import {
|
|
2
|
+
promptCompanyInfo,
|
|
3
|
+
promptDatabase,
|
|
4
|
+
promptDeployment,
|
|
5
|
+
promptDomain,
|
|
6
|
+
promptRegistration,
|
|
7
|
+
provision,
|
|
8
|
+
runSetupWizard
|
|
9
|
+
} from "./chunk-PFMIOSR5.js";
|
|
10
|
+
import "./chunk-4WLJIZZB.js";
|
|
11
|
+
import "./chunk-KFQGP6VL.js";
|
|
12
|
+
export {
|
|
13
|
+
promptCompanyInfo,
|
|
14
|
+
promptDatabase,
|
|
15
|
+
promptDeployment,
|
|
16
|
+
promptDomain,
|
|
17
|
+
promptRegistration,
|
|
18
|
+
provision,
|
|
19
|
+
runSetupWizard
|
|
20
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import {
|
|
2
|
+
promptCompanyInfo,
|
|
3
|
+
promptDatabase,
|
|
4
|
+
promptDeployment,
|
|
5
|
+
promptDomain,
|
|
6
|
+
promptRegistration,
|
|
7
|
+
provision,
|
|
8
|
+
runSetupWizard
|
|
9
|
+
} from "./chunk-OPOBUYJT.js";
|
|
10
|
+
import "./chunk-4WLJIZZB.js";
|
|
11
|
+
import "./chunk-KFQGP6VL.js";
|
|
12
|
+
export {
|
|
13
|
+
promptCompanyInfo,
|
|
14
|
+
promptDatabase,
|
|
15
|
+
promptDeployment,
|
|
16
|
+
promptDomain,
|
|
17
|
+
promptRegistration,
|
|
18
|
+
provision,
|
|
19
|
+
runSetupWizard
|
|
20
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import {
|
|
2
|
+
promptCompanyInfo,
|
|
3
|
+
promptDatabase,
|
|
4
|
+
promptDeployment,
|
|
5
|
+
promptDomain,
|
|
6
|
+
promptRegistration,
|
|
7
|
+
provision,
|
|
8
|
+
runSetupWizard
|
|
9
|
+
} from "./chunk-MBT5ND3D.js";
|
|
10
|
+
import "./chunk-4WLJIZZB.js";
|
|
11
|
+
import "./chunk-KFQGP6VL.js";
|
|
12
|
+
export {
|
|
13
|
+
promptCompanyInfo,
|
|
14
|
+
promptDatabase,
|
|
15
|
+
promptDeployment,
|
|
16
|
+
promptDomain,
|
|
17
|
+
promptRegistration,
|
|
18
|
+
provision,
|
|
19
|
+
runSetupWizard
|
|
20
|
+
};
|
package/package.json
CHANGED
package/src/admin/routes.ts
CHANGED
|
@@ -757,13 +757,15 @@ export function createAdminRoutes(db: DatabaseAdapter) {
|
|
|
757
757
|
const userRole = c.get('userRole' as any);
|
|
758
758
|
if (!userId) return c.json({ error: 'Not authenticated' }, 401);
|
|
759
759
|
|
|
760
|
+
const user = await db.getUser(userId);
|
|
761
|
+
const clientOrgId = user?.clientOrgId || c.get('clientOrgId' as any) || null;
|
|
762
|
+
|
|
760
763
|
// Owner and admin always get full access
|
|
761
764
|
if (userRole === 'owner' || userRole === 'admin') {
|
|
762
|
-
return c.json({ permissions: '*', role: userRole });
|
|
765
|
+
return c.json({ permissions: '*', role: userRole, clientOrgId });
|
|
763
766
|
}
|
|
764
767
|
|
|
765
|
-
|
|
766
|
-
return c.json({ permissions: user?.permissions ?? '*', role: userRole, clientOrgId: user?.clientOrgId || null });
|
|
768
|
+
return c.json({ permissions: user?.permissions ?? '*', role: userRole, clientOrgId });
|
|
767
769
|
});
|
|
768
770
|
|
|
769
771
|
// ─── Platform Capabilities ──────────────────────────
|
|
@@ -2195,8 +2197,26 @@ export function createAdminRoutes(db: DatabaseAdapter) {
|
|
|
2195
2197
|
|
|
2196
2198
|
// ─── Client Organizations ─────────────────────────────
|
|
2197
2199
|
|
|
2198
|
-
api.get('/organizations',
|
|
2200
|
+
api.get('/organizations', async (c) => {
|
|
2199
2201
|
try {
|
|
2202
|
+
// Org-bound users can only see their own organization
|
|
2203
|
+
const clientOrgId = c.get('clientOrgId' as any);
|
|
2204
|
+
if (clientOrgId) {
|
|
2205
|
+
const isPostgres = (db as any).pool;
|
|
2206
|
+
if (isPostgres) {
|
|
2207
|
+
const { rows } = await (db as any)._query(
|
|
2208
|
+
`SELECT o.*, COUNT(a.id) as agent_count FROM client_organizations o LEFT JOIN agents a ON a.client_org_id = o.id WHERE o.id = $1 GROUP BY o.id`, [clientOrgId]);
|
|
2209
|
+
return c.json({ organizations: rows });
|
|
2210
|
+
}
|
|
2211
|
+
return c.json({ organizations: [] });
|
|
2212
|
+
}
|
|
2213
|
+
|
|
2214
|
+
// Full access for admins/owners
|
|
2215
|
+
const userRole = c.get('userRole' as any);
|
|
2216
|
+
if (userRole !== 'admin' && userRole !== 'owner') {
|
|
2217
|
+
return c.json({ error: 'Insufficient permissions' }, 403);
|
|
2218
|
+
}
|
|
2219
|
+
|
|
2200
2220
|
const isPostgres = (db as any).pool;
|
|
2201
2221
|
if (isPostgres) {
|
|
2202
2222
|
const { rows } = await (db as any)._query(`
|
package/src/auth/routes.ts
CHANGED
|
@@ -73,11 +73,14 @@ export function createAuthRoutes(
|
|
|
73
73
|
return process.env.NODE_ENV === 'production' || process.env.SECURE_COOKIES === '1';
|
|
74
74
|
};
|
|
75
75
|
|
|
76
|
-
async function issueTokens(userId: string, email: string, role: string) {
|
|
76
|
+
async function issueTokens(userId: string, email: string, role: string, clientOrgId?: string | null) {
|
|
77
77
|
const { SignJWT } = await import('jose');
|
|
78
78
|
const secret = new TextEncoder().encode(jwtSecret);
|
|
79
79
|
|
|
80
|
-
const
|
|
80
|
+
const payload: Record<string, any> = { sub: userId, email, role };
|
|
81
|
+
if (clientOrgId) payload.clientOrgId = clientOrgId;
|
|
82
|
+
|
|
83
|
+
const token = await new SignJWT(payload)
|
|
81
84
|
.setProtectedHeader({ alg: 'HS256' })
|
|
82
85
|
.setIssuedAt()
|
|
83
86
|
.setExpirationTime(TOKEN_TTL)
|
|
@@ -93,8 +96,8 @@ export function createAuthRoutes(
|
|
|
93
96
|
}
|
|
94
97
|
|
|
95
98
|
/** Set session cookies and return token info */
|
|
96
|
-
async function setSessionCookies(c: any, userId: string, email: string, role: string, method: string) {
|
|
97
|
-
const { token, refreshToken } = await issueTokens(userId, email, role);
|
|
99
|
+
async function setSessionCookies(c: any, userId: string, email: string, role: string, method: string, clientOrgId?: string | null) {
|
|
100
|
+
const { token, refreshToken } = await issueTokens(userId, email, role, clientOrgId);
|
|
98
101
|
const csrf = generateCsrf();
|
|
99
102
|
const secure = isSecure();
|
|
100
103
|
|
|
@@ -301,7 +304,7 @@ export function createAuthRoutes(
|
|
|
301
304
|
});
|
|
302
305
|
}
|
|
303
306
|
|
|
304
|
-
const { token, refreshToken, csrf } = await setSessionCookies(c, user.id, user.email, user.role, 'password');
|
|
307
|
+
const { token, refreshToken, csrf } = await setSessionCookies(c, user.id, user.email, user.role, 'password', user.clientOrgId);
|
|
305
308
|
|
|
306
309
|
return c.json({
|
|
307
310
|
token,
|
|
@@ -360,7 +363,7 @@ export function createAuthRoutes(
|
|
|
360
363
|
|
|
361
364
|
pending2fa.delete(challengeToken);
|
|
362
365
|
|
|
363
|
-
const { token, refreshToken, csrf } = await setSessionCookies(c, user.id, user.email, user.role, 'password+2fa');
|
|
366
|
+
const { token, refreshToken, csrf } = await setSessionCookies(c, user.id, user.email, user.role, 'password+2fa', user.clientOrgId);
|
|
364
367
|
|
|
365
368
|
return c.json({
|
|
366
369
|
token,
|
|
@@ -614,7 +617,7 @@ export function createAuthRoutes(
|
|
|
614
617
|
const user = await db.getUser(key.createdBy);
|
|
615
618
|
if (!user) return c.json({ error: 'API key owner not found' }, 401);
|
|
616
619
|
|
|
617
|
-
const { token, refreshToken, csrf } = await setSessionCookies(c, user.id, user.email, user.role, 'api-key');
|
|
620
|
+
const { token, refreshToken, csrf } = await setSessionCookies(c, user.id, user.email, user.role, 'api-key', user.clientOrgId);
|
|
618
621
|
|
|
619
622
|
return c.json({
|
|
620
623
|
token,
|
|
@@ -643,7 +646,7 @@ export function createAuthRoutes(
|
|
|
643
646
|
const user = await db.getUser(payload.sub as string);
|
|
644
647
|
if (!user) return c.json({ error: 'User not found' }, 401);
|
|
645
648
|
|
|
646
|
-
const { token, refreshToken } = await issueTokens(user.id, user.email, user.role);
|
|
649
|
+
const { token, refreshToken } = await issueTokens(user.id, user.email, user.role, user.clientOrgId);
|
|
647
650
|
const csrf = generateCsrf();
|
|
648
651
|
const secure = isSecure();
|
|
649
652
|
|
|
@@ -890,7 +893,7 @@ export function createAuthRoutes(
|
|
|
890
893
|
ip: c.req.header('x-forwarded-for') || c.req.header('x-real-ip'),
|
|
891
894
|
});
|
|
892
895
|
|
|
893
|
-
const { token, refreshToken, csrf } = await setSessionCookies(c, user.id, user.email, user.role, 'bootstrap');
|
|
896
|
+
const { token, refreshToken, csrf } = await setSessionCookies(c, user.id, user.email, user.role, 'bootstrap', user.clientOrgId);
|
|
894
897
|
|
|
895
898
|
// Notify server that setup is complete (flips the dashboard latch)
|
|
896
899
|
opts?.onBootstrap?.();
|
|
@@ -1214,7 +1217,7 @@ export function createAuthRoutes(
|
|
|
1214
1217
|
}
|
|
1215
1218
|
|
|
1216
1219
|
// Issue session
|
|
1217
|
-
await setSessionCookies(c, result.user.id, result.user.email, result.user.role, 'oidc');
|
|
1220
|
+
await setSessionCookies(c, result.user.id, result.user.email, result.user.role, 'oidc', result.user.clientOrgId);
|
|
1218
1221
|
|
|
1219
1222
|
// Redirect to dashboard
|
|
1220
1223
|
return c.redirect('/dashboard');
|
|
@@ -1363,7 +1366,7 @@ export function createAuthRoutes(
|
|
|
1363
1366
|
}
|
|
1364
1367
|
|
|
1365
1368
|
// Issue session
|
|
1366
|
-
await setSessionCookies(c, result.user.id, result.user.email, result.user.role, 'saml');
|
|
1369
|
+
await setSessionCookies(c, result.user.id, result.user.email, result.user.role, 'saml', result.user.clientOrgId);
|
|
1367
1370
|
|
|
1368
1371
|
// Redirect to dashboard (or RelayState)
|
|
1369
1372
|
return c.redirect('/dashboard');
|
package/src/dashboard/app.js
CHANGED
|
@@ -163,6 +163,12 @@ function App() {
|
|
|
163
163
|
if (document.cookie.match(/em_session|em_csrf/)) {
|
|
164
164
|
authCall('/me').then(async d => {
|
|
165
165
|
setUser(d.user || d);
|
|
166
|
+
// If user is org-bound, lock org context immediately
|
|
167
|
+
var u = d.user || d;
|
|
168
|
+
if (u.clientOrgId) {
|
|
169
|
+
setSelectedOrgId(u.clientOrgId);
|
|
170
|
+
localStorage.setItem('em_client_org_id', u.clientOrgId);
|
|
171
|
+
}
|
|
166
172
|
// Init transport encryption BEFORE setting authed — ensures all subsequent
|
|
167
173
|
// API calls from child components are encrypted
|
|
168
174
|
try {
|
|
@@ -202,9 +208,10 @@ function App() {
|
|
|
202
208
|
apiCall('/settings').then(d => { const s = d.settings || d || {}; if (s.primaryColor) applyBrandColor(s.primaryColor); if (s.orgId) setOrgId(s.orgId); }).catch(() => {});
|
|
203
209
|
apiCall('/me/permissions').then(d => {
|
|
204
210
|
if (d && d.permissions) setPermissions(d.permissions);
|
|
205
|
-
// If user is assigned to a client org, auto-set org context
|
|
211
|
+
// If user is assigned to a client org, auto-set org context and lock switcher
|
|
206
212
|
if (d && d.clientOrgId) {
|
|
207
213
|
localStorage.setItem('em_client_org_id', d.clientOrgId);
|
|
214
|
+
setSelectedOrgId(d.clientOrgId);
|
|
208
215
|
} else {
|
|
209
216
|
localStorage.removeItem('em_client_org_id');
|
|
210
217
|
}
|
package/src/engine/compliance.ts
CHANGED
|
@@ -705,7 +705,7 @@ export class ComplianceReporter {
|
|
|
705
705
|
timeline.push({ timestamp: v.created_at, source: 'vault_access', category: 'access', agentId: v.agent_id, detail: `Vault ${v.action}: ${v.key}`, data: { action: v.action, key: v.key } });
|
|
706
706
|
}
|
|
707
707
|
|
|
708
|
-
timeline.sort((a, b) => a.timestamp.localeCompare(b.timestamp));
|
|
708
|
+
timeline.sort((a, b) => String(a.timestamp || '').localeCompare(String(b.timestamp || '')));
|
|
709
709
|
data.timeline = timeline;
|
|
710
710
|
|
|
711
711
|
// Summary statistics
|
|
@@ -720,7 +720,7 @@ export class ComplianceReporter {
|
|
|
720
720
|
data.summary.bySource[e.source] = (data.summary.bySource[e.source] || 0) + 1;
|
|
721
721
|
data.summary.byCategory[e.category] = (data.summary.byCategory[e.category] || 0) + 1;
|
|
722
722
|
data.summary.byAgent[e.agentId] = (data.summary.byAgent[e.agentId] || 0) + 1;
|
|
723
|
-
const day = e.timestamp
|
|
723
|
+
const day = String(e.timestamp || '').substring(0, 10);
|
|
724
724
|
if (day) data.summary.byDay[day] = (data.summary.byDay[day] || 0) + 1;
|
|
725
725
|
}
|
|
726
726
|
|
package/src/server.ts
CHANGED
|
@@ -278,6 +278,7 @@ export function createServer(config: ServerConfig): ServerInstance {
|
|
|
278
278
|
c.set('userRole', (payload.role as string) || '');
|
|
279
279
|
c.set('userEmail', (payload.email as string) || '');
|
|
280
280
|
c.set('userOrgId', (payload.orgId as string) || '');
|
|
281
|
+
c.set('clientOrgId', (payload.clientOrgId as string) || '');
|
|
281
282
|
c.set('authType', cookieToken ? 'cookie' : 'jwt');
|
|
282
283
|
return next();
|
|
283
284
|
} catch {
|
|
@@ -285,6 +286,35 @@ export function createServer(config: ServerConfig): ServerInstance {
|
|
|
285
286
|
}
|
|
286
287
|
});
|
|
287
288
|
|
|
289
|
+
// ─── Org-scoping enforcement for client-bound users ───
|
|
290
|
+
// Users with clientOrgId in JWT can ONLY access their bound org's data
|
|
291
|
+
api.use('*', async (c: any, next: any) => {
|
|
292
|
+
const clientOrgId = c.get('clientOrgId');
|
|
293
|
+
if (!clientOrgId) return next(); // Not org-bound, full access
|
|
294
|
+
|
|
295
|
+
// Override orgId in query params to enforce scoping
|
|
296
|
+
const url = new URL(c.req.url);
|
|
297
|
+
const requestedOrg = url.searchParams.get('orgId');
|
|
298
|
+
if (requestedOrg && requestedOrg !== clientOrgId) {
|
|
299
|
+
return c.json({ error: 'Access denied: you can only access your assigned organization' }, 403);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Block org listing — only return their own org
|
|
303
|
+
const path = c.req.path;
|
|
304
|
+
if (path === '/api/organizations' && c.req.method === 'GET') {
|
|
305
|
+
// Let it through but we'll filter in the response
|
|
306
|
+
// Store the clientOrgId for downstream filtering
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Block access to other orgs' data via path params (e.g., /api/engine/stats/:orgId)
|
|
310
|
+
const orgIdMatch = path.match(/\/stats\/([^/]+)/);
|
|
311
|
+
if (orgIdMatch && orgIdMatch[1] !== clientOrgId) {
|
|
312
|
+
return c.json({ error: 'Access denied: you can only access your assigned organization' }, 403);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return next();
|
|
316
|
+
});
|
|
317
|
+
|
|
288
318
|
// Audit logging on all API mutations
|
|
289
319
|
api.use('*', auditLogger(config.db));
|
|
290
320
|
|