feat(permissions): update role-based access checks across dashboard components

- Refactored user role checks in various dashboard pages to utilize the new permissions structure.
- Replaced direct role comparisons with permission checks for enhanced security and maintainability.
- Updated the `validateRequest` function to streamline user role handling and ensure proper access control.
- Improved consistency in permission checks across components, ensuring only authorized users can access specific features.
This commit is contained in:
Mauricio Siu
2025-07-13 02:05:59 -06:00
parent 982a1d5d31
commit a43b8ee2d2
19 changed files with 51 additions and 80 deletions

View File

@@ -54,13 +54,8 @@ export async function getServerSideProps(
try {
await helpers.project.all.prefetch();
if (user.role?.name === "member" || user?.role?.) {
const userR = await helpers.user.one.fetch({
userId: user.id,
});
if (!userR?.role?.permissions?.includes(PERMISSIONS.DOCKER.VIEW.name)) {
if (user.role?.name === "member" || !user?.role?.isSystem) {
if (!user?.role?.permissions?.includes(PERMISSIONS.DOCKER.VIEW.name)) {
return {
redirect: {
permanent: true,

View File

@@ -39,7 +39,7 @@ export async function getServerSideProps(
};
}
const { user } = await validateRequest(ctx.req);
if (!user || user.role !== "owner") {
if (!user || (user.role?.name !== "owner" && user.role?.name !== "admin")) {
return {
redirect: {
permanent: true,

View File

@@ -44,7 +44,7 @@ export async function getServerSideProps(
await helpers.user.get.prefetch();
if (!user || user.role === "member") {
if (!user || (user.role?.name !== "owner" && user.role?.name !== "admin")) {
return {
redirect: {
permanent: true,

View File

@@ -31,7 +31,7 @@ export async function getServerSideProps(
}
const { req, res } = ctx;
const { user, session } = await validateRequest(req);
if (!user || user.role === "member") {
if (!user || (user.role?.name !== "owner" && user.role?.name !== "admin")) {
return {
redirect: {
permanent: true,

View File

@@ -25,7 +25,7 @@ export async function getServerSideProps(
) {
const { req, res } = ctx;
const { user, session } = await validateRequest(req);
if (!user || user.role === "member") {
if (!user || (user.role?.name !== "owner" && user.role?.name !== "admin")) {
return {
redirect: {
permanent: true,

View File

@@ -34,7 +34,7 @@ export async function getServerSideProps(
};
}
const { user, session } = await validateRequest(ctx.req);
if (!user || user.role === "member") {
if (!user || (user.role?.name !== "owner" && user.role?.name !== "admin")) {
return {
redirect: {
permanent: true,

View File

@@ -26,7 +26,7 @@ export async function getServerSideProps(
) {
const { req, res } = ctx;
const { user, session } = await validateRequest(req);
if (!user || user.role === "member") {
if (!user || (user.role?.name !== "owner" && user.role?.name !== "admin")) {
return {
redirect: {
permanent: true,

View File

@@ -3,6 +3,7 @@ import { DashboardLayout } from "@/components/layouts/dashboard-layout";
import { appRouter } from "@/server/api/root";
import { validateRequest } from "@dokploy/server";
import { PERMISSIONS } from "@dokploy/server/lib/permissions";
import { createServerSideHelpers } from "@trpc/react-query/server";
import type { GetServerSidePropsContext } from "next";
import type { ReactElement } from "react";
@@ -49,12 +50,12 @@ export async function getServerSideProps(
try {
await helpers.project.all.prefetch();
await helpers.settings.isCloud.prefetch();
if (user.role === "member") {
const userR = await helpers.user.one.fetch({
userId: user.id,
});
if (!userR?.canAccessToGitProviders) {
if (user.role?.name === "member" || !user?.role?.isSystem) {
if (
!user?.role?.permissions?.includes(
PERMISSIONS.GIT_PROVIDERS.ACCESS.name,
)
) {
return {
redirect: {
permanent: true,

View File

@@ -26,7 +26,7 @@ export async function getServerSideProps(
) {
const { req, res } = ctx;
const { user, session } = await validateRequest(req);
if (!user || user.role === "member") {
if (!user || (user.role?.name !== "owner" && user.role?.name !== "admin")) {
return {
redirect: {
permanent: true,

View File

@@ -26,7 +26,7 @@ export async function getServerSideProps(
) {
const { req, res } = ctx;
const { user, session } = await validateRequest(req);
if (!user || user.role === "member") {
if (!user || (user.role?.name !== "owner" && user.role?.name !== "admin")) {
return {
redirect: {
permanent: true,

View File

@@ -59,7 +59,7 @@ export async function getServerSideProps(
},
};
}
if (user.role === "member") {
if (user.role?.name === "member" || !user?.role?.isSystem) {
return {
redirect: {
permanent: true,

View File

@@ -36,7 +36,7 @@ export async function getServerSideProps(
},
};
}
if (user.role === "member") {
if (user.role?.name === "member" || !user?.role?.isSystem) {
return {
redirect: {
permanent: true,

View File

@@ -3,6 +3,7 @@ import { DashboardLayout } from "@/components/layouts/dashboard-layout";
import { appRouter } from "@/server/api/root";
import { validateRequest } from "@dokploy/server";
import { PERMISSIONS } from "@dokploy/server/lib/permissions";
import { createServerSideHelpers } from "@trpc/react-query/server";
import type { GetServerSidePropsContext } from "next";
import type { ReactElement } from "react";
@@ -50,12 +51,10 @@ export async function getServerSideProps(
await helpers.project.all.prefetch();
await helpers.settings.isCloud.prefetch();
if (user.role === "member") {
const userR = await helpers.user.one.fetch({
userId: user.id,
});
if (!userR?.canAccessToSSHKeys) {
if (user.role?.name === "member" || !user?.role?.isSystem) {
if (
!user?.role?.permissions?.includes(PERMISSIONS.SSH_KEYS.ACCESS.name)
) {
return {
redirect: {
permanent: true,

View File

@@ -29,7 +29,7 @@ export async function getServerSideProps(
const { req, res } = ctx;
const { user, session } = await validateRequest(req);
if (!user || user.role === "member") {
if (!user || (user.role?.name !== "owner" && user.role?.name !== "admin")) {
return {
redirect: {
permanent: true,

View File

@@ -3,6 +3,7 @@ import { DashboardLayout } from "@/components/layouts/dashboard-layout";
import { appRouter } from "@/server/api/root";
import { IS_CLOUD } from "@dokploy/server/constants";
import { validateRequest } from "@dokploy/server/lib/auth";
import { PERMISSIONS } from "@dokploy/server/lib/permissions";
import { createServerSideHelpers } from "@trpc/react-query/server";
import type { GetServerSidePropsContext } from "next";
import type { ReactElement } from "react";
@@ -53,12 +54,8 @@ export async function getServerSideProps(
try {
await helpers.project.all.prefetch();
if (user.role === "member") {
const userR = await helpers.user.one.fetch({
userId: user.id,
});
if (!userR?.canAccessToDocker) {
if (user.role?.name === "member" || !user?.role?.isSystem) {
if (!user?.role?.permissions?.includes(PERMISSIONS.DOCKER.VIEW.name)) {
return {
redirect: {
permanent: true,

View File

@@ -3,6 +3,7 @@ import { DashboardLayout } from "@/components/layouts/dashboard-layout";
import { appRouter } from "@/server/api/root";
import { IS_CLOUD } from "@dokploy/server/constants";
import { validateRequest } from "@dokploy/server/lib/auth";
import { PERMISSIONS } from "@dokploy/server/lib/permissions";
import { createServerSideHelpers } from "@trpc/react-query/server";
import type { GetServerSidePropsContext } from "next";
import type { ReactElement } from "react";
@@ -53,12 +54,8 @@ export async function getServerSideProps(
try {
await helpers.project.all.prefetch();
if (user.role === "member") {
const userR = await helpers.user.one.fetch({
userId: user.id,
});
if (!userR?.canAccessToTraefikFiles) {
if (user.role?.name === "member" || !user?.role?.isSystem) {
if (!user?.role?.permissions?.includes(PERMISSIONS.TRAEFIK.ACCESS.name)) {
return {
redirect: {
permanent: true,

View File

@@ -1,12 +1,10 @@
import { appRouter } from "@/server/api/root";
import { api } from "@/utils/api";
import { validateRequest } from "@dokploy/server";
import { createServerSideHelpers } from "@trpc/react-query/server";
import type { GetServerSidePropsContext, NextPage } from "next";
import dynamic from "next/dynamic";
import "swagger-ui-react/swagger-ui.css";
import { useEffect, useState } from "react";
import superjson from "superjson";
import { PERMISSIONS } from "@dokploy/server/lib/permissions";
const SwaggerUI = dynamic(() => import("swagger-ui-react"), { ssr: false });
@@ -71,8 +69,7 @@ const Home: NextPage = () => {
export default Home;
export async function getServerSideProps(context: GetServerSidePropsContext) {
const { req, res } = context;
const { user, session } = await validateRequest(context.req);
const { user } = await validateRequest(context.req);
if (!user) {
return {
redirect: {
@@ -81,23 +78,9 @@ export async function getServerSideProps(context: GetServerSidePropsContext) {
},
};
}
const helpers = createServerSideHelpers({
router: appRouter,
ctx: {
req: req as any,
res: res as any,
db: null as any,
session: session as any,
user: user as any,
},
transformer: superjson,
});
if (user.role === "member") {
const userR = await helpers.user.one.fetch({
userId: user.id,
});
if (!userR?.canAccessToAPI) {
if (user.role?.name === "member" || !user?.role?.isSystem) {
if (!user?.role?.permissions?.includes(PERMISSIONS.API.ACCESS.name)) {
return {
redirect: {
permanent: true,

View File

@@ -206,6 +206,7 @@ export const cliProcedure = t.procedure.use(({ ctx, next }) => {
});
export const adminProcedure = t.procedure.use(({ ctx, next }) => {
console.log("adminProcedure", ctx.session, ctx.user);
if (
!ctx.session ||
!ctx.user ||

View File

@@ -16,6 +16,7 @@ import {
findWebServer,
updateWebServer,
} from "@dokploy/server/services/web-server";
import type { Role } from "../db/schema/rbac";
const { handler, api } = betterAuth({
database: drizzleAdapter(db, {
@@ -409,15 +410,7 @@ export const validateRequest = async (request: IncomingMessage) => {
};
}
const mockSession = {
session: {
...session.session,
},
user: {
...session.user,
ownerId: session.user.ownerId,
},
};
let role: Role | null = null;
if (session?.user) {
const member = await db.query.member.findFirst({
where: and(
@@ -432,17 +425,22 @@ export const validateRequest = async (request: IncomingMessage) => {
organization: true,
},
});
if (member?.role) {
mockSession.user.role = member.role;
}
role = member?.role || null;
if (member) {
mockSession.user.ownerId = member.organization.ownerId;
session.user.ownerId = member.organization.ownerId;
} else {
mockSession.user.ownerId = session.user.id;
session.user.ownerId = session.user.id;
}
}
const mockSession = {
session: {
...session.session,
},
user: {
...session.user,
role,
ownerId: session.user.ownerId,
},
};
return mockSession;
};