mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-05 21:26:40 +00:00
feat(rbac): added org permission context for pulling permission from api
This commit is contained in:
@@ -13,8 +13,10 @@ import {
|
|||||||
CreateRoleSchema,
|
CreateRoleSchema,
|
||||||
DeleteRoleSchema,
|
DeleteRoleSchema,
|
||||||
GetRoleSchema,
|
GetRoleSchema,
|
||||||
|
GetUserPermission,
|
||||||
UpdateRoleSchema
|
UpdateRoleSchema
|
||||||
} from "../../validation";
|
} from "../../validation";
|
||||||
|
import { packRules } from "@casl/ability/extra";
|
||||||
|
|
||||||
export const createRole = async (req: Request, res: Response) => {
|
export const createRole = async (req: Request, res: Response) => {
|
||||||
const {
|
const {
|
||||||
@@ -160,3 +162,16 @@ export const getRoles = async (req: Request, res: Response) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getUserPermissions = async (req: Request, res: Response) => {
|
||||||
|
const {
|
||||||
|
params: { orgId }
|
||||||
|
} = await validateRequest(GetUserPermission, req);
|
||||||
|
const { permission } = await getUserOrgPermissions(req.user.id, orgId);
|
||||||
|
|
||||||
|
res.status(200).json({
|
||||||
|
data: {
|
||||||
|
permissions: packRules(permission.rules)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
@@ -17,4 +17,11 @@ router.delete(
|
|||||||
|
|
||||||
router.get("/", requireAuth({ acceptedAuthModes: [AuthMode.JWT] }), roleController.getRoles);
|
router.get("/", requireAuth({ acceptedAuthModes: [AuthMode.JWT] }), roleController.getRoles);
|
||||||
|
|
||||||
|
// get a user permissions in an org
|
||||||
|
router.get(
|
||||||
|
"/:orgId/permissions",
|
||||||
|
requireAuth({ acceptedAuthModes: [AuthMode.JWT] }),
|
||||||
|
roleController.getUserPermissions
|
||||||
|
);
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|||||||
@@ -40,13 +40,19 @@ export const UpdateRoleSchema = z.object({
|
|||||||
|
|
||||||
export const DeleteRoleSchema = z.object({
|
export const DeleteRoleSchema = z.object({
|
||||||
params: z.object({
|
params: z.object({
|
||||||
id: z.string()
|
id: z.string().trim()
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
export const GetRoleSchema = z.object({
|
export const GetRoleSchema = z.object({
|
||||||
query: z.object({
|
query: z.object({
|
||||||
workspaceId: z.string().optional(),
|
workspaceId: z.string().trim().optional(),
|
||||||
orgId: z.string()
|
orgId: z.string().trim()
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
export const GetUserPermission = z.object({
|
||||||
|
params: z.object({
|
||||||
|
orgId: z.string().trim()
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
import { createContext, ReactNode, useContext } from "react";
|
||||||
|
|
||||||
|
import { useGetUserOrgPermissions } from "@app/hooks/api";
|
||||||
|
|
||||||
|
import { useOrganization } from "../OrganizationContext";
|
||||||
|
import { TPermission } from "./types";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
children: ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
const PermissionContext = createContext<null | TPermission>(null);
|
||||||
|
|
||||||
|
export const OrgPermissionProvider = ({ children }: Props): JSX.Element => {
|
||||||
|
const { currentOrg } = useOrganization();
|
||||||
|
const orgId = currentOrg?._id || "";
|
||||||
|
const { data: permission, isLoading } = useGetUserOrgPermissions({ orgId });
|
||||||
|
|
||||||
|
if (isLoading) {
|
||||||
|
return (
|
||||||
|
<div className="flex items-center justify-center w-screen h-screen bg-bunker-800">
|
||||||
|
<img
|
||||||
|
src="/images/loading/loading.gif"
|
||||||
|
height={70}
|
||||||
|
width={120}
|
||||||
|
alt="infisical loading indicator"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!permission) {
|
||||||
|
return (
|
||||||
|
<div className="flex items-center justify-center w-screen h-screen bg-bunker-800">
|
||||||
|
Failed to load user permissions
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return <PermissionContext.Provider value={permission}>{children}</PermissionContext.Provider>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useOrgPermission = () => {
|
||||||
|
const ctx = useContext(PermissionContext);
|
||||||
|
if (!ctx) {
|
||||||
|
throw new Error("useOrgPermission to be used within <OrgPermissionProvider>");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx;
|
||||||
|
};
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { OrgPermissionProvider, useOrgPermission } from "./OrgPermissionContext";
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import { MongoAbility } from "@casl/ability";
|
||||||
|
|
||||||
|
export enum GeneralPermissionActions {
|
||||||
|
Read = "read",
|
||||||
|
Create = "create",
|
||||||
|
Edit = "edit",
|
||||||
|
Delete = "delete"
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum WorkspacePermissionActions {
|
||||||
|
Read = "read",
|
||||||
|
Create = "create"
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum OrgPermissionSubjects {
|
||||||
|
Workspace = "workspace",
|
||||||
|
Role = "role",
|
||||||
|
Member = "member",
|
||||||
|
Settings = "settings",
|
||||||
|
IncidentAccount = "incident-contact",
|
||||||
|
Sso = "sso",
|
||||||
|
Billing = "billing",
|
||||||
|
SecretScanning = "secret-scanning"
|
||||||
|
}
|
||||||
|
|
||||||
|
export type OrgPermissionSet =
|
||||||
|
| [WorkspacePermissionActions, OrgPermissionSubjects.Workspace]
|
||||||
|
| [GeneralPermissionActions, OrgPermissionSubjects.Role]
|
||||||
|
| [GeneralPermissionActions, OrgPermissionSubjects.Member]
|
||||||
|
| [GeneralPermissionActions, OrgPermissionSubjects.Settings]
|
||||||
|
| [GeneralPermissionActions, OrgPermissionSubjects.IncidentAccount]
|
||||||
|
| [GeneralPermissionActions, OrgPermissionSubjects.Sso]
|
||||||
|
| [GeneralPermissionActions, OrgPermissionSubjects.SecretScanning]
|
||||||
|
| [GeneralPermissionActions, OrgPermissionSubjects.Billing];
|
||||||
|
|
||||||
|
export type TPermission = MongoAbility<OrgPermissionSet>;
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
export { AuthProvider } from "./AuthContext";
|
export { AuthProvider } from "./AuthContext";
|
||||||
export { OrgProvider, useOrganization } from "./OrganizationContext";
|
export { OrgProvider, useOrganization } from "./OrganizationContext";
|
||||||
|
export { OrgPermissionProvider,useOrgPermission } from "./OrgPermissionContext";
|
||||||
export { SubscriptionProvider, useSubscription } from "./SubscriptionContext";
|
export { SubscriptionProvider, useSubscription } from "./SubscriptionContext";
|
||||||
export { UserProvider, useUser } from "./UserContext";
|
export { UserProvider, useUser } from "./UserContext";
|
||||||
export { useWorkspace, WorkspaceProvider } from "./WorkspaceContext";
|
export { useWorkspace, WorkspaceProvider } from "./WorkspaceContext";
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
export { useCreateRole, useDeleteRole,useUpdateRole } from "./mutation";
|
export { useCreateRole, useDeleteRole, useUpdateRole } from "./mutation";
|
||||||
export { useGetRoles } from "./queries";
|
export { useGetRoles, useGetUserOrgPermissions } from "./queries";
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
|
import { createMongoAbility, MongoAbility, RawRuleOf } from "@casl/ability";
|
||||||
|
import { PackRule, unpackRules } from "@casl/ability/extra";
|
||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
|
||||||
import { apiRequest } from "@app/config/request";
|
import { apiRequest } from "@app/config/request";
|
||||||
|
import { OrgPermissionSet } from "@app/context/OrgPermissionContext/types";
|
||||||
|
|
||||||
import { TGetRolesDTO, TRole } from "./types";
|
import { TGetRolesDTO, TGetUserOrgPermissionsDTO, TRole } from "./types";
|
||||||
|
|
||||||
export const roleQueryKeys = {
|
export const roleQueryKeys = {
|
||||||
getRoles: ({ orgId, workspaceId }: TGetRolesDTO) => ["roles", { orgId, workspaceId }] as const
|
getRoles: ({ orgId, workspaceId }: TGetRolesDTO) => ["roles", { orgId, workspaceId }] as const,
|
||||||
|
getUserOrgPermissions: ({ orgId }: TGetUserOrgPermissionsDTO) =>
|
||||||
|
["user-permissions", { orgId }] as const
|
||||||
};
|
};
|
||||||
|
|
||||||
const getRoles = async ({ orgId, workspaceId }: TGetRolesDTO) => {
|
const getRoles = async ({ orgId, workspaceId }: TGetRolesDTO) => {
|
||||||
@@ -25,3 +30,23 @@ export const useGetRoles = ({ orgId, workspaceId }: TGetRolesDTO) =>
|
|||||||
queryFn: () => getRoles({ orgId, workspaceId }),
|
queryFn: () => getRoles({ orgId, workspaceId }),
|
||||||
enabled: Boolean(orgId)
|
enabled: Boolean(orgId)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const getUserOrgPermissions = async ({ orgId }: TGetUserOrgPermissionsDTO) => {
|
||||||
|
const { data } = await apiRequest.get<{
|
||||||
|
data: { permissions: PackRule<RawRuleOf<MongoAbility<OrgPermissionSet>>>[] };
|
||||||
|
}>(`/api/v1/roles/${orgId}/permissions`, {});
|
||||||
|
|
||||||
|
return data.data.permissions;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useGetUserOrgPermissions = ({ orgId }: TGetUserOrgPermissionsDTO) =>
|
||||||
|
useQuery({
|
||||||
|
queryKey: roleQueryKeys.getUserOrgPermissions({ orgId }),
|
||||||
|
queryFn: () => getUserOrgPermissions({ orgId }),
|
||||||
|
enabled: Boolean(orgId),
|
||||||
|
select: (data) => {
|
||||||
|
const rule = unpackRules<RawRuleOf<MongoAbility<OrgPermissionSet>>>(data);
|
||||||
|
const ability = createMongoAbility<OrgPermissionSet>(rule);
|
||||||
|
return ability;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|||||||
@@ -49,3 +49,7 @@ export type TDeleteRoleDTO = {
|
|||||||
id: string;
|
id: string;
|
||||||
workspaceId?: string;
|
workspaceId?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type TGetUserOrgPermissionsDTO = {
|
||||||
|
orgId: string;
|
||||||
|
};
|
||||||
|
|||||||
+14
-11
@@ -17,6 +17,7 @@ import { TooltipProvider } from "@app/components/v2";
|
|||||||
import { publicPaths } from "@app/const";
|
import { publicPaths } from "@app/const";
|
||||||
import {
|
import {
|
||||||
AuthProvider,
|
AuthProvider,
|
||||||
|
OrgPermissionProvider,
|
||||||
OrgProvider,
|
OrgProvider,
|
||||||
SubscriptionProvider,
|
SubscriptionProvider,
|
||||||
UserProvider,
|
UserProvider,
|
||||||
@@ -95,17 +96,19 @@ const App = ({ Component, pageProps, ...appProps }: NextAppProp): JSX.Element =>
|
|||||||
<TooltipProvider>
|
<TooltipProvider>
|
||||||
<AuthProvider>
|
<AuthProvider>
|
||||||
<OrgProvider>
|
<OrgProvider>
|
||||||
<WorkspaceProvider>
|
<OrgPermissionProvider>
|
||||||
<SubscriptionProvider>
|
<WorkspaceProvider>
|
||||||
<UserProvider>
|
<SubscriptionProvider>
|
||||||
<NotificationProvider>
|
<UserProvider>
|
||||||
<AppLayout>
|
<NotificationProvider>
|
||||||
<Component {...pageProps} />
|
<AppLayout>
|
||||||
</AppLayout>
|
<Component {...pageProps} />
|
||||||
</NotificationProvider>
|
</AppLayout>
|
||||||
</UserProvider>
|
</NotificationProvider>
|
||||||
</SubscriptionProvider>
|
</UserProvider>
|
||||||
</WorkspaceProvider>
|
</SubscriptionProvider>
|
||||||
|
</WorkspaceProvider>
|
||||||
|
</OrgPermissionProvider>
|
||||||
</OrgProvider>
|
</OrgProvider>
|
||||||
</AuthProvider>
|
</AuthProvider>
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
|
|||||||
Reference in New Issue
Block a user