refactor: update permission checks to use organization context

This commit is contained in:
Mauricio Siu
2025-02-21 00:48:04 -06:00
parent a317f0c4cc
commit 5ae103e779
3 changed files with 107 additions and 50 deletions

View File

@@ -155,7 +155,7 @@ const MENU: Menu = {
// Only enabled for admins and users with access to Traefik files in non-cloud environments // Only enabled for admins and users with access to Traefik files in non-cloud environments
isEnabled: ({ auth, isCloud }) => isEnabled: ({ auth, isCloud }) =>
!!( !!(
(auth?.role === "owner" || auth?.user?.canAccessToTraefikFiles) && (auth?.role === "owner" || auth?.canAccessToTraefikFiles) &&
!isCloud !isCloud
), ),
}, },
@@ -166,10 +166,7 @@ const MENU: Menu = {
icon: BlocksIcon, icon: BlocksIcon,
// Only enabled for admins and users with access to Docker in non-cloud environments // Only enabled for admins and users with access to Docker in non-cloud environments
isEnabled: ({ auth, isCloud }) => isEnabled: ({ auth, isCloud }) =>
!!( !!((auth?.role === "owner" || auth?.canAccessToDocker) && !isCloud),
(auth?.role === "owner" || auth?.user?.canAccessToDocker) &&
!isCloud
),
}, },
{ {
isSingle: true, isSingle: true,
@@ -178,10 +175,7 @@ const MENU: Menu = {
icon: PieChart, icon: PieChart,
// Only enabled for admins and users with access to Docker in non-cloud environments // Only enabled for admins and users with access to Docker in non-cloud environments
isEnabled: ({ auth, isCloud }) => isEnabled: ({ auth, isCloud }) =>
!!( !!((auth?.role === "owner" || auth?.canAccessToDocker) && !isCloud),
(auth?.role === "owner" || auth?.user?.canAccessToDocker) &&
!isCloud
),
}, },
{ {
isSingle: true, isSingle: true,
@@ -190,10 +184,7 @@ const MENU: Menu = {
icon: Forward, icon: Forward,
// Only enabled for admins and users with access to Docker in non-cloud environments // Only enabled for admins and users with access to Docker in non-cloud environments
isEnabled: ({ auth, isCloud }) => isEnabled: ({ auth, isCloud }) =>
!!( !!((auth?.role === "owner" || auth?.canAccessToDocker) && !isCloud),
(auth?.role === "owner" || auth?.user?.canAccessToDocker) &&
!isCloud
),
}, },
// Legacy unused menu, adjusted to the new structure // Legacy unused menu, adjusted to the new structure
@@ -291,7 +282,7 @@ const MENU: Menu = {
url: "/dashboard/settings/ssh-keys", url: "/dashboard/settings/ssh-keys",
// Only enabled for admins and users with access to SSH keys // Only enabled for admins and users with access to SSH keys
isEnabled: ({ auth }) => isEnabled: ({ auth }) =>
!!(auth?.role === "owner" || auth?.user?.canAccessToSSHKeys), !!(auth?.role === "owner" || auth?.canAccessToSSHKeys),
}, },
{ {
isSingle: true, isSingle: true,
@@ -300,7 +291,7 @@ const MENU: Menu = {
icon: GitBranch, icon: GitBranch,
// Only enabled for admins and users with access to Git providers // Only enabled for admins and users with access to Git providers
isEnabled: ({ auth }) => isEnabled: ({ auth }) =>
!!(auth?.role === "owner" || auth?.user?.canAccessToGitProviders), !!(auth?.role === "owner" || auth?.canAccessToGitProviders),
}, },
{ {
isSingle: true, isSingle: true,

View File

@@ -38,7 +38,11 @@ export const projectRouter = createTRPCRouter({
.mutation(async ({ ctx, input }) => { .mutation(async ({ ctx, input }) => {
try { try {
if (ctx.user.rol === "member") { if (ctx.user.rol === "member") {
await checkProjectAccess(ctx.user.id, "create"); await checkProjectAccess(
ctx.user.id,
"create",
ctx.session.activeOrganizationId,
);
} }
const admin = await findUserById(ctx.user.ownerId); const admin = await findUserById(ctx.user.ownerId);
@@ -55,7 +59,11 @@ export const projectRouter = createTRPCRouter({
ctx.session.activeOrganizationId, ctx.session.activeOrganizationId,
); );
if (ctx.user.rol === "member") { if (ctx.user.rol === "member") {
await addNewProject(ctx.user.id, project.projectId); await addNewProject(
ctx.user.id,
project.projectId,
ctx.session.activeOrganizationId,
);
} }
return project; return project;
@@ -77,7 +85,12 @@ export const projectRouter = createTRPCRouter({
ctx.session.activeOrganizationId, ctx.session.activeOrganizationId,
); );
await checkProjectAccess(ctx.user.id, "access", input.projectId); await checkProjectAccess(
ctx.user.id,
"access",
ctx.session.activeOrganizationId,
input.projectId,
);
const project = await db.query.projects.findFirst({ const project = await db.query.projects.findFirst({
where: and( where: and(
@@ -212,7 +225,11 @@ export const projectRouter = createTRPCRouter({
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
try { try {
if (ctx.user.rol === "member") { if (ctx.user.rol === "member") {
await checkProjectAccess(ctx.user.id, "delete"); await checkProjectAccess(
ctx.user.id,
"delete",
ctx.session.activeOrganizationId,
);
} }
const currentProject = await findProjectById(input.projectId); const currentProject = await findProjectById(input.projectId);
if ( if (

View File

@@ -33,32 +33,48 @@ export const findUserByAuthId = async (authId: string) => {
// return userR; // return userR;
}; };
export const addNewProject = async (userId: string, projectId: string) => { export const addNewProject = async (
const userR = await findUserById(userId); userId: string,
projectId: string,
organizationId: string,
) => {
const userR = await findMemberById(userId, organizationId);
// await db await db
// .update(user) .update(member)
// .set({ .set({
// accessedProjects: [...userR.accessedProjects, projectId], accessedProjects: [...userR.accessedProjects, projectId],
// }) })
// .where(eq(user.authId, authId)); .where(
and(eq(member.id, userR.id), eq(member.organizationId, organizationId)),
);
}; };
export const addNewService = async (userId: string, serviceId: string) => { export const addNewService = async (
const userR = await findUserById(userId); userId: string,
// await db serviceId: string,
// .update(user) organizationId: string,
// .set({ ) => {
// accessedServices: [...userR.accessedServices, serviceId], const userR = await findMemberById(userId, organizationId);
// }) await db
// .where(eq(user.userId, userId)); .update(member)
.set({
accessedServices: [...userR.accessedServices, serviceId],
})
.where(
and(eq(member.id, userR.id), eq(member.organizationId, organizationId)),
);
}; };
export const canPerformCreationService = async ( export const canPerformCreationService = async (
userId: string, userId: string,
projectId: string, projectId: string,
organizationId: string,
) => { ) => {
const { accessedProjects, canCreateServices } = await findUserById(userId); const { accessedProjects, canCreateServices } = await findMemberById(
userId,
organizationId,
);
const haveAccessToProject = accessedProjects.includes(projectId); const haveAccessToProject = accessedProjects.includes(projectId);
if (canCreateServices && haveAccessToProject) { if (canCreateServices && haveAccessToProject) {
@@ -71,8 +87,9 @@ export const canPerformCreationService = async (
export const canPerformAccessService = async ( export const canPerformAccessService = async (
userId: string, userId: string,
serviceId: string, serviceId: string,
organizationId: string,
) => { ) => {
const { accessedServices } = await findUserById(userId); const { accessedServices } = await findMemberById(userId, organizationId);
const haveAccessToService = accessedServices.includes(serviceId); const haveAccessToService = accessedServices.includes(serviceId);
if (haveAccessToService) { if (haveAccessToService) {
@@ -85,8 +102,12 @@ export const canPerformAccessService = async (
export const canPeformDeleteService = async ( export const canPeformDeleteService = async (
userId: string, userId: string,
serviceId: string, serviceId: string,
organizationId: string,
) => { ) => {
const { accessedServices, canDeleteServices } = await findUserById(userId); const { accessedServices, canDeleteServices } = await findMemberById(
userId,
organizationId,
);
const haveAccessToService = accessedServices.includes(serviceId); const haveAccessToService = accessedServices.includes(serviceId);
if (canDeleteServices && haveAccessToService) { if (canDeleteServices && haveAccessToService) {
@@ -96,8 +117,11 @@ export const canPeformDeleteService = async (
return false; return false;
}; };
export const canPerformCreationProject = async (userId: string) => { export const canPerformCreationProject = async (
const { canCreateProjects } = await findUserById(userId); userId: string,
organizationId: string,
) => {
const { canCreateProjects } = await findMemberById(userId, organizationId);
if (canCreateProjects) { if (canCreateProjects) {
return true; return true;
@@ -106,8 +130,11 @@ export const canPerformCreationProject = async (userId: string) => {
return false; return false;
}; };
export const canPerformDeleteProject = async (userId: string) => { export const canPerformDeleteProject = async (
const { canDeleteProjects } = await findUserById(userId); userId: string,
organizationId: string,
) => {
const { canDeleteProjects } = await findMemberById(userId, organizationId);
if (canDeleteProjects) { if (canDeleteProjects) {
return true; return true;
@@ -119,8 +146,9 @@ export const canPerformDeleteProject = async (userId: string) => {
export const canPerformAccessProject = async ( export const canPerformAccessProject = async (
userId: string, userId: string,
projectId: string, projectId: string,
organizationId: string,
) => { ) => {
const { accessedProjects } = await findUserById(userId); const { accessedProjects } = await findMemberById(userId, organizationId);
const haveAccessToProject = accessedProjects.includes(projectId); const haveAccessToProject = accessedProjects.includes(projectId);
@@ -130,26 +158,45 @@ export const canPerformAccessProject = async (
return false; return false;
}; };
export const canAccessToTraefikFiles = async (userId: string) => { export const canAccessToTraefikFiles = async (
const { canAccessToTraefikFiles } = await findUserById(userId); userId: string,
organizationId: string,
) => {
const { canAccessToTraefikFiles } = await findMemberById(
userId,
organizationId,
);
return canAccessToTraefikFiles; return canAccessToTraefikFiles;
}; };
export const checkServiceAccess = async ( export const checkServiceAccess = async (
userId: string, userId: string,
serviceId: string, serviceId: string,
organizationId: string,
action = "access" as "access" | "create" | "delete", action = "access" as "access" | "create" | "delete",
) => { ) => {
let hasPermission = false; let hasPermission = false;
switch (action) { switch (action) {
case "create": case "create":
hasPermission = await canPerformCreationService(userId, serviceId); hasPermission = await canPerformCreationService(
userId,
serviceId,
organizationId,
);
break; break;
case "access": case "access":
hasPermission = await canPerformAccessService(userId, serviceId); hasPermission = await canPerformAccessService(
userId,
serviceId,
organizationId,
);
break; break;
case "delete": case "delete":
hasPermission = await canPeformDeleteService(userId, serviceId); hasPermission = await canPeformDeleteService(
userId,
serviceId,
organizationId,
);
break; break;
default: default:
hasPermission = false; hasPermission = false;
@@ -165,6 +212,7 @@ export const checkServiceAccess = async (
export const checkProjectAccess = async ( export const checkProjectAccess = async (
authId: string, authId: string,
action: "create" | "delete" | "access", action: "create" | "delete" | "access",
organizationId: string,
projectId?: string, projectId?: string,
) => { ) => {
let hasPermission = false; let hasPermission = false;
@@ -173,13 +221,14 @@ export const checkProjectAccess = async (
hasPermission = await canPerformAccessProject( hasPermission = await canPerformAccessProject(
authId, authId,
projectId as string, projectId as string,
organizationId,
); );
break; break;
case "create": case "create":
hasPermission = await canPerformCreationProject(authId); hasPermission = await canPerformCreationProject(authId, organizationId);
break; break;
case "delete": case "delete":
hasPermission = await canPerformDeleteProject(authId); hasPermission = await canPerformDeleteProject(authId, organizationId);
break; break;
default: default:
hasPermission = false; hasPermission = false;