SEC - LAUNCHER: scope service modules by Tasker workspace

This commit is contained in:
DCCONSTRUCTIONS 2026-05-14 21:18:53 +03:00
parent 0782e13c77
commit 17406d570f
1 changed files with 32 additions and 4 deletions

View File

@ -406,6 +406,7 @@ app.post("/api/internal/access/check", (req, res) => {
const snapshot = controlPlaneStore.getSnapshot({ name: "NODE.DC internal access check" }); const snapshot = controlPlaneStore.getSnapshot({ name: "NODE.DC internal access check" });
const user = findInternalAccessUser(snapshot.data, req.body); const user = findInternalAccessUser(snapshot.data, req.body);
const serviceSlug = sanitizeServiceSlug(req.body?.serviceSlug); const serviceSlug = sanitizeServiceSlug(req.body?.serviceSlug);
const workspaceSlug = normalizeOptionalText(req.body?.workspaceSlug ?? req.body?.workspace?.slug);
if (!user) { if (!user) {
res.json({ res.json({
@ -423,10 +424,10 @@ app.post("/api/internal/access/check", (req, res) => {
const groups = resolveRequiredGroups(snapshot.data, user); const groups = resolveRequiredGroups(snapshot.data, user);
const app = getAppsForUser(groups).find((candidate) => candidate.slug === serviceSlug); const app = getAppsForUser(groups).find((candidate) => candidate.slug === serviceSlug);
const allowed = Boolean(app?.hasAccess); const allowed = Boolean(app?.hasAccess);
const serviceModules = resolveUserServiceModules(snapshot.data, user, serviceSlug); const serviceModules = resolveUserServiceModules(snapshot.data, user, serviceSlug, workspaceSlug);
const workspacePolicy = const workspacePolicy =
serviceSlug === "task-manager" serviceSlug === "task-manager"
? resolveTaskManagerWorkspacePolicy(snapshot.data, groups, allowed, user, null, serviceModules) ? resolveTaskManagerWorkspacePolicy(snapshot.data, groups, allowed, user, workspaceSlug, serviceModules)
: null; : null;
res.json({ res.json({
@ -2508,20 +2509,47 @@ function resolveTaskManagerWorkspacePolicy(data, groups, hasTaskManagerAccess, u
}; };
} }
function resolveUserServiceModules(data, user, serviceSlug) { function resolveUserServiceModules(data, user, serviceSlug, workspaceSlug = null) {
if (!user?.id) return {}; if (!user?.id) return {};
const service = data.services.find( const service = data.services.find(
(candidate) => candidate.slug === serviceSlug || candidate.authentikApplicationSlug === serviceSlug (candidate) => candidate.slug === serviceSlug || candidate.authentikApplicationSlug === serviceSlug
); );
if (!service?.id) return {}; if (!service?.id) return {};
const workspaceClientIds = resolveTaskManagerWorkspaceClientIds(data, user, workspaceSlug);
return Object.fromEntries( return Object.fromEntries(
(data.serviceModuleEntitlements ?? []) (data.serviceModuleEntitlements ?? [])
.filter((entitlement) => entitlement.userId === user.id && entitlement.serviceId === service.id && entitlement.enabled) .filter(
(entitlement) =>
entitlement.userId === user.id &&
entitlement.serviceId === service.id &&
entitlement.enabled &&
(!workspaceClientIds || workspaceClientIds.has(entitlement.clientId))
)
.map((entitlement) => [entitlement.moduleId, true]) .map((entitlement) => [entitlement.moduleId, true])
); );
} }
function resolveTaskManagerWorkspaceClientIds(data, user, workspaceSlug) {
const normalizedWorkspaceSlug = normalizeOptionalText(workspaceSlug);
if (!normalizedWorkspaceSlug || !user?.id) return null;
const clientIds = new Set();
for (const membership of data.taskManagerMemberships ?? []) {
if (membership.userId === user.id && normalizeOptionalText(membership.workspaceSlug) === normalizedWorkspaceSlug) {
clientIds.add(membership.clientId);
}
}
for (const client of data.clients ?? []) {
if (resolveTaskManagerWorkspaceBinding(client, normalizedWorkspaceSlug)) {
clientIds.add(client.id);
}
}
return clientIds;
}
function getFrontchannelLogoutUrls() { function getFrontchannelLogoutUrls() {
const urls = [config.taskLogoutUrl]; const urls = [config.taskLogoutUrl];
const launcherData = readLauncherData(); const launcherData = readLauncherData();