capabilities: the api, and one honest exception
GET /api/user/capabilities is what the caller may reach, and every account may ask — it is mounted on a core capability so an account granted almost nothing can still find out what it has. the dock and route guards read it. it is a courtesy, never enforcement: hiding an icon is not access control and the 403 in origin-validation stays the lock. GET/PUT /api/users/capabilities edit the policy, owner-gated. the write path is where the registry's authority over capability keys is applied, which is why the column has no CHECK: unknown keys and non-app kinds are refused rather than stored for the resolver to drop on read. the exception is `selfService`. useAuth calls PUT /api/users to change your own name and avatar, and that route has always lived on the same router as the owner-only account administration around it — so declaring /users an admin capability locked every member out of their own profile. moving it to /api/user would be tidier and would break every shipped mobile client, so instead the registry says out loud that this one route is not what the capability around it is. exact method and exact path, so it cannot widen: verified that PUT /api/users passes while GET /api/users, PATCH /api/users/:id/role, DELETE /api/users/:id and PUT /api/users/:id are all still refused. 23 unit tests. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { createRouter } from '../../create-router';
|
||||
import { getUserSettings, setUserSettings, getUserState, patchUserState } from 'officerdb';
|
||||
import { selfCapabilitiesRouter } from '../users/capabilities-routes';
|
||||
|
||||
const DEFAULT_SETTINGS = {
|
||||
chat: {
|
||||
@@ -16,6 +17,10 @@ const DEFAULT_SETTINGS = {
|
||||
|
||||
export const settingsRouter = createRouter();
|
||||
|
||||
// What the caller may reach. Under /api/user because it is a `core` capability — every account can ask
|
||||
// what it is allowed to do, including an account that is allowed almost nothing.
|
||||
settingsRouter.route('/', selfCapabilitiesRouter);
|
||||
|
||||
// GET /settings — return user settings from DB, default if empty
|
||||
settingsRouter.get('/settings', async (ctx) => {
|
||||
const userId = ctx.get('user').id;
|
||||
|
||||
Reference in New Issue
Block a user