mirror of
https://github.com/NginxProxyManager/nginx-proxy-manager.git
synced 2025-11-04 17:35:15 +00:00
Permissions polish for restricted users
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
import type { Table as ReactTable } from "@tanstack/react-table";
|
||||
import cn from "classnames";
|
||||
import type { ReactNode } from "react";
|
||||
import { Button } from "src/components";
|
||||
import { Button, HasPermission } from "src/components";
|
||||
import { T } from "src/locale";
|
||||
import { type ADMIN, MANAGE, type Permission, type Section } from "src/modules/Permissions";
|
||||
|
||||
interface Props {
|
||||
tableInstance: ReactTable<any>;
|
||||
@@ -12,8 +13,20 @@ interface Props {
|
||||
objects: string;
|
||||
color?: string;
|
||||
customAddBtn?: ReactNode;
|
||||
permissionSection?: Section | typeof ADMIN;
|
||||
permission?: Permission;
|
||||
}
|
||||
function EmptyData({ tableInstance, onNew, isFiltered, object, objects, color = "primary", customAddBtn }: Props) {
|
||||
function EmptyData({
|
||||
tableInstance,
|
||||
onNew,
|
||||
isFiltered,
|
||||
object,
|
||||
objects,
|
||||
color = "primary",
|
||||
customAddBtn,
|
||||
permissionSection,
|
||||
permission,
|
||||
}: Props) {
|
||||
return (
|
||||
<tr>
|
||||
<td colSpan={tableInstance.getVisibleFlatColumns().length}>
|
||||
@@ -27,16 +40,18 @@ function EmptyData({ tableInstance, onNew, isFiltered, object, objects, color =
|
||||
<h2>
|
||||
<T id="object.empty" tData={{ objects }} />
|
||||
</h2>
|
||||
<p className="text-muted">
|
||||
<T id="empty-subtitle" />
|
||||
</p>
|
||||
{customAddBtn ? (
|
||||
customAddBtn
|
||||
) : (
|
||||
<Button className={cn("my-3", `btn-${color}`)} onClick={onNew}>
|
||||
<T id="object.add" tData={{ object }} />
|
||||
</Button>
|
||||
)}
|
||||
<HasPermission section={permissionSection} permission={permission || MANAGE} hideError>
|
||||
<p className="text-muted">
|
||||
<T id="empty-subtitle" />
|
||||
</p>
|
||||
{customAddBtn ? (
|
||||
customAddBtn
|
||||
) : (
|
||||
<Button className={cn("my-3", `btn-${color}`)} onClick={onNew}>
|
||||
<T id="object.add" tData={{ object }} />
|
||||
</Button>
|
||||
)}
|
||||
</HasPermission>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -3,25 +3,29 @@ import Alert from "react-bootstrap/Alert";
|
||||
import { Loading, LoadingPage } from "src/components";
|
||||
import { useUser } from "src/hooks";
|
||||
import { T } from "src/locale";
|
||||
import { type ADMIN, hasPermission, type Permission, type Section } from "src/modules/Permissions";
|
||||
|
||||
interface Props {
|
||||
permission: string;
|
||||
type: "manage" | "view";
|
||||
section?: Section | typeof ADMIN;
|
||||
permission: Permission;
|
||||
hideError?: boolean;
|
||||
children?: ReactNode;
|
||||
pageLoading?: boolean;
|
||||
loadingNoLogo?: boolean;
|
||||
}
|
||||
function HasPermission({
|
||||
section,
|
||||
permission,
|
||||
type,
|
||||
children,
|
||||
hideError = false,
|
||||
pageLoading = false,
|
||||
loadingNoLogo = false,
|
||||
}: Props) {
|
||||
const { data, isLoading } = useUser("me");
|
||||
const perms = data?.permissions;
|
||||
|
||||
if (!section) {
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
||||
if (isLoading) {
|
||||
if (hideError) {
|
||||
@@ -33,33 +37,7 @@ function HasPermission({
|
||||
return <Loading noLogo={loadingNoLogo} />;
|
||||
}
|
||||
|
||||
let allowed = permission === "";
|
||||
const acceptable = ["manage", type];
|
||||
|
||||
switch (permission) {
|
||||
case "admin":
|
||||
allowed = data?.roles?.includes("admin") || false;
|
||||
break;
|
||||
case "proxyHosts":
|
||||
allowed = acceptable.indexOf(perms?.proxyHosts || "") !== -1;
|
||||
break;
|
||||
case "redirectionHosts":
|
||||
allowed = acceptable.indexOf(perms?.redirectionHosts || "") !== -1;
|
||||
break;
|
||||
case "deadHosts":
|
||||
allowed = acceptable.indexOf(perms?.deadHosts || "") !== -1;
|
||||
break;
|
||||
case "streams":
|
||||
allowed = acceptable.indexOf(perms?.streams || "") !== -1;
|
||||
break;
|
||||
case "accessLists":
|
||||
allowed = acceptable.indexOf(perms?.accessLists || "") !== -1;
|
||||
break;
|
||||
case "certificates":
|
||||
allowed = acceptable.indexOf(perms?.certificates || "") !== -1;
|
||||
break;
|
||||
}
|
||||
|
||||
const allowed = hasPermission(section, permission, data?.permissions, data?.roles);
|
||||
if (allowed) {
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
||||
@@ -11,14 +11,26 @@ import cn from "classnames";
|
||||
import React from "react";
|
||||
import { HasPermission, NavLink } from "src/components";
|
||||
import { T } from "src/locale";
|
||||
import {
|
||||
ACCESS_LISTS,
|
||||
ADMIN,
|
||||
CERTIFICATES,
|
||||
DEAD_HOSTS,
|
||||
type MANAGE,
|
||||
PROXY_HOSTS,
|
||||
REDIRECTION_HOSTS,
|
||||
type Section,
|
||||
STREAMS,
|
||||
VIEW,
|
||||
} from "src/modules/Permissions";
|
||||
|
||||
interface MenuItem {
|
||||
label: string;
|
||||
icon?: React.ElementType;
|
||||
to?: string;
|
||||
items?: MenuItem[];
|
||||
permission?: string;
|
||||
permissionType?: "view" | "manage";
|
||||
permissionSection?: Section | typeof ADMIN;
|
||||
permission?: typeof VIEW | typeof MANAGE;
|
||||
}
|
||||
|
||||
const menuItems: MenuItem[] = [
|
||||
@@ -34,26 +46,26 @@ const menuItems: MenuItem[] = [
|
||||
{
|
||||
to: "/nginx/proxy",
|
||||
label: "proxy-hosts",
|
||||
permission: "proxyHosts",
|
||||
permissionType: "view",
|
||||
permissionSection: PROXY_HOSTS,
|
||||
permission: VIEW,
|
||||
},
|
||||
{
|
||||
to: "/nginx/redirection",
|
||||
label: "redirection-hosts",
|
||||
permission: "redirectionHosts",
|
||||
permissionType: "view",
|
||||
permissionSection: REDIRECTION_HOSTS,
|
||||
permission: VIEW,
|
||||
},
|
||||
{
|
||||
to: "/nginx/stream",
|
||||
label: "streams",
|
||||
permission: "streams",
|
||||
permissionType: "view",
|
||||
permissionSection: STREAMS,
|
||||
permission: VIEW,
|
||||
},
|
||||
{
|
||||
to: "/nginx/404",
|
||||
label: "dead-hosts",
|
||||
permission: "deadHosts",
|
||||
permissionType: "view",
|
||||
permissionSection: DEAD_HOSTS,
|
||||
permission: VIEW,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -61,33 +73,33 @@ const menuItems: MenuItem[] = [
|
||||
to: "/access",
|
||||
icon: IconLock,
|
||||
label: "access-lists",
|
||||
permission: "accessLists",
|
||||
permissionType: "view",
|
||||
permissionSection: ACCESS_LISTS,
|
||||
permission: VIEW,
|
||||
},
|
||||
{
|
||||
to: "/certificates",
|
||||
icon: IconShield,
|
||||
label: "certificates",
|
||||
permission: "certificates",
|
||||
permissionType: "view",
|
||||
permissionSection: CERTIFICATES,
|
||||
permission: VIEW,
|
||||
},
|
||||
{
|
||||
to: "/users",
|
||||
icon: IconUser,
|
||||
label: "users",
|
||||
permission: "admin",
|
||||
permissionSection: ADMIN,
|
||||
},
|
||||
{
|
||||
to: "/audit-log",
|
||||
icon: IconBook,
|
||||
label: "auditlogs",
|
||||
permission: "admin",
|
||||
permissionSection: ADMIN,
|
||||
},
|
||||
{
|
||||
to: "/settings",
|
||||
icon: IconSettings,
|
||||
label: "settings",
|
||||
permission: "admin",
|
||||
permissionSection: ADMIN,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -99,8 +111,8 @@ const getMenuItem = (item: MenuItem, onClick?: () => void) => {
|
||||
return (
|
||||
<HasPermission
|
||||
key={`item-${item.label}`}
|
||||
permission={item.permission || ""}
|
||||
type={item.permissionType || "view"}
|
||||
section={item.permissionSection}
|
||||
permission={item.permission || VIEW}
|
||||
hideError
|
||||
>
|
||||
<li className="nav-item">
|
||||
@@ -122,8 +134,8 @@ const getMenuDropown = (item: MenuItem, onClick?: () => void) => {
|
||||
return (
|
||||
<HasPermission
|
||||
key={`item-${item.label}`}
|
||||
permission={item.permission || ""}
|
||||
type={item.permissionType || "view"}
|
||||
section={item.permissionSection}
|
||||
permission={item.permission || VIEW}
|
||||
hideError
|
||||
>
|
||||
<li className={cns}>
|
||||
@@ -147,8 +159,8 @@ const getMenuDropown = (item: MenuItem, onClick?: () => void) => {
|
||||
return (
|
||||
<HasPermission
|
||||
key={`${idx}-${subitem.to}`}
|
||||
permission={subitem.permission || ""}
|
||||
type={subitem.permissionType || "view"}
|
||||
section={subitem.permissionSection}
|
||||
permission={subitem.permission || VIEW}
|
||||
hideError
|
||||
>
|
||||
<NavLink to={subitem.to} isDropdownItem onClick={onClick}>
|
||||
|
||||
Reference in New Issue
Block a user