capabilities: send the denied routes too
the server half of the previous commit, which belonged with it. the frontend guard needs both lists: absence from `routes` cannot tell a route this account lacks from a route no capability claims, so without this the guard permits everything. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -34,11 +34,17 @@ selfCapabilitiesRouter.get('/capabilities', async (ctx) => {
|
|||||||
? CAPABILITIES.map((c) => ({ key: c.key, level: 'write' as const }))
|
? CAPABILITIES.map((c) => ({ key: c.key, level: 'write' as const }))
|
||||||
: [...grants].map(([key, level]) => ({ key, level }));
|
: [...grants].map(([key, level]) => ({ key, level }));
|
||||||
|
|
||||||
|
const heldKeys = new Set(held.map((h) => h.key));
|
||||||
|
|
||||||
return ctx.json({
|
return ctx.json({
|
||||||
isOwner,
|
isOwner,
|
||||||
capabilities: held,
|
capabilities: held,
|
||||||
// Flattened for the dock and the route guard, which care about paths rather than capability keys.
|
// Flattened for the dock and the route guard, which care about paths rather than capability keys.
|
||||||
routes: held.flatMap(({ key }) => CAPABILITY_BY_KEY.get(key)?.routes ?? []),
|
routes: held.flatMap(({ key }) => CAPABILITY_BY_KEY.get(key)?.routes ?? []),
|
||||||
|
// The complement, and the frontend genuinely needs both. "Not in `routes`" cannot distinguish a route
|
||||||
|
// this account lacks from a route no capability claims at all — `/`, the settings shell, the sign-in
|
||||||
|
// screens — and a guard that cannot tell those apart either blanks the app or guards nothing.
|
||||||
|
deniedRoutes: CAPABILITIES.filter((c) => !heldKeys.has(c.key)).flatMap((c) => c.routes ?? []),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user