From 259d150fc43b247d3c1e09566f06c346c5f78ed1 Mon Sep 17 00:00:00 2001
From: Aarnav Tale
Date: Wed, 2 Apr 2025 23:34:32 -0400
Subject: [PATCH] feat: add capabilities enforcement on users
---
app/routes/users/components/manage-banner.tsx | 7 ++++---
app/routes/users/dialogs/create-user.tsx | 8 ++++++--
app/routes/users/overview.tsx | 17 +++++++++++++++-
app/routes/users/user-actions.ts | 20 +++++--------------
4 files changed, 31 insertions(+), 21 deletions(-)
diff --git a/app/routes/users/components/manage-banner.tsx b/app/routes/users/components/manage-banner.tsx
index 8905e2a..726e95e 100644
--- a/app/routes/users/components/manage-banner.tsx
+++ b/app/routes/users/components/manage-banner.tsx
@@ -4,11 +4,12 @@ import Link from '~/components/Link';
import type { HeadplaneConfig } from '~/server/config/schema';
import CreateUser from '../dialogs/create-user';
-interface Props {
+interface ManageBannerProps {
oidc?: NonNullable;
+ isDisabled?: boolean;
}
-export default function ManageBanner({ oidc }: Props) {
+export default function ManageBanner({ oidc, isDisabled }: ManageBannerProps) {
return (
@@ -60,7 +61,7 @@ export default function ManageBanner({ oidc }: Props) {
: 'You can add, remove, and rename users here.'}
-
+
diff --git a/app/routes/users/dialogs/create-user.tsx b/app/routes/users/dialogs/create-user.tsx
index dd9819e..dc85ae8 100644
--- a/app/routes/users/dialogs/create-user.tsx
+++ b/app/routes/users/dialogs/create-user.tsx
@@ -1,11 +1,15 @@
import Dialog from '~/components/Dialog';
import Input from '~/components/Input';
+interface CreateUserProps {
+ isDisabled?: boolean;
+}
+
// TODO: Support image upload for user avatars
-export default function CreateUser() {
+export default function CreateUser({ isDisabled }: CreateUserProps) {
return (
-
+
diff --git a/app/routes/users/user-actions.ts b/app/routes/users/user-actions.ts
index 89d3320..d54eafd 100644
--- a/app/routes/users/user-actions.ts
+++ b/app/routes/users/user-actions.ts
@@ -9,8 +9,12 @@ export async function userAction({
context,
}: ActionFunctionArgs) {
const session = await context.sessions.auth(request);
- const apiKey = session.get('api_key')!;
+ const check = await context.sessions.check(request, Capabilities.write_users);
+ if (!check) {
+ return data({ success: false }, 403);
+ }
+ const apiKey = session.get('api_key')!;
const formData = await request.formData();
const action = formData.get('action_id')?.toString();
if (!action) {
@@ -84,20 +88,6 @@ async function reassignUser(
context: LoadContext,
session: Session,
) {
- const executor = session.get('user');
- if (!executor?.subject) {
- return data({ success: false }, 400);
- }
-
- const check = await context.sessions.checkSubject(
- executor.subject,
- Capabilities.write_users,
- );
-
- if (!check) {
- return data({ success: false }, 403);
- }
-
const userId = formData.get('user_id')?.toString();
const newRole = formData.get('new_role')?.toString();
if (!userId || !newRole) {