mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-16 12:37:20 +00:00
add auth enabling hints
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
import type { AppAuthSchema } from "auth/auth-schema";
|
||||
import { useBknd } from "ui/client/bknd";
|
||||
import { routes } from "ui/lib/routes";
|
||||
|
||||
export function useBkndAuth() {
|
||||
const { config, schema, actions: bkndActions } = useBknd();
|
||||
const { config, schema, actions: bkndActions, app } = useBknd();
|
||||
|
||||
const actions = {
|
||||
config: {
|
||||
@@ -33,7 +34,29 @@ export function useBkndAuth() {
|
||||
}
|
||||
}
|
||||
};
|
||||
const $auth = {};
|
||||
|
||||
const minimum_permissions = [
|
||||
"system.access.admin",
|
||||
"system.access.api",
|
||||
"system.config.read",
|
||||
"system.config.read.secrets",
|
||||
"system.build"
|
||||
];
|
||||
const $auth = {
|
||||
roles: {
|
||||
none: Object.keys(config.auth.roles ?? {}).length === 0,
|
||||
minimum_permissions,
|
||||
has_admin: Object.entries(config.auth.roles ?? {}).some(
|
||||
([name, role]) =>
|
||||
role.implicit_allow ||
|
||||
minimum_permissions.every((p) => role.permissions?.includes(p))
|
||||
)
|
||||
},
|
||||
routes: {
|
||||
settings: app.getSettingsPath(["auth"]),
|
||||
listUsers: app.getAbsolutePath("/data/" + routes.data.entity.list(config.auth.entity_name))
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
$auth,
|
||||
|
||||
@@ -209,7 +209,8 @@ export const Switch = forwardRef<
|
||||
<RadixSwitch.Root
|
||||
className={clsx(
|
||||
"relative cursor-pointer rounded-full bg-muted border-2 border-transparent outline-none ring-1 dark:ring-primary/10 ring-primary/20 data-[state=checked]:ring-primary/60 data-[state=checked]:bg-primary/60 appearance-none transition-colors hover:bg-muted/80",
|
||||
SwitchSizes[props.size ?? "md"].root
|
||||
SwitchSizes[props.size ?? "md"].root,
|
||||
props.disabled && "opacity-50 !cursor-not-allowed"
|
||||
)}
|
||||
onCheckedChange={(bool) => {
|
||||
console.log("setting", bool);
|
||||
|
||||
@@ -12,6 +12,7 @@ import { coerce, isType, isTypeSchema } from "./utils";
|
||||
export type FieldProps = {
|
||||
onChange?: (e: ChangeEvent<any>) => void;
|
||||
placeholder?: string;
|
||||
disabled?: boolean;
|
||||
} & Omit<FieldwrapperProps, "children" | "schema">;
|
||||
|
||||
export const Field = (props: FieldProps) => {
|
||||
@@ -49,7 +50,7 @@ const FieldImpl = ({ name, onChange, placeholder, required: _required, ...props
|
||||
return <ArrayField path={name} />;
|
||||
}
|
||||
|
||||
const disabled = schema.readOnly ?? "const" in schema ?? false;
|
||||
const disabled = props.disabled ?? schema.readOnly ?? "const" in schema ?? false;
|
||||
|
||||
const handleChange = useEvent((e: ChangeEvent<HTMLInputElement>) => {
|
||||
const value = coerce(e.target.value, schema as any, { required });
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
import { IconFingerprint } from "@tabler/icons-react";
|
||||
import { TbSettings } from "react-icons/tb";
|
||||
import { useBknd } from "ui/client/bknd";
|
||||
import { useBkndAuth } from "ui/client/schema/auth/use-bknd-auth";
|
||||
import { IconButton } from "ui/components/buttons/IconButton";
|
||||
import { Empty } from "ui/components/display/Empty";
|
||||
import { Icon } from "ui/components/display/Icon";
|
||||
import { Link } from "ui/components/wouter/Link";
|
||||
import { useBrowserTitle } from "ui/hooks/use-browser-title";
|
||||
import * as AppShell from "ui/layouts/AppShell/AppShell";
|
||||
import { routes, useNavigate } from "ui/lib/routes";
|
||||
import { routes } from "ui/lib/routes";
|
||||
|
||||
export function AuthRoot({ children }) {
|
||||
const { app, config } = useBknd();
|
||||
const users_entity = config.auth.entity_name;
|
||||
const { config, $auth } = useBkndAuth();
|
||||
|
||||
return (
|
||||
<>
|
||||
<AppShell.Sidebar>
|
||||
<AppShell.SectionHeader
|
||||
right={
|
||||
<Link href={app.getSettingsPath(["auth"])}>
|
||||
<Link href={$auth.routes.settings}>
|
||||
<IconButton Icon={TbSettings} />
|
||||
</Link>
|
||||
}
|
||||
@@ -32,22 +32,42 @@ export function AuthRoot({ children }) {
|
||||
</AppShell.SidebarLink>
|
||||
<AppShell.SidebarLink
|
||||
as={Link}
|
||||
href={app.getAbsolutePath("/data/" + routes.data.entity.list(users_entity))}
|
||||
disabled={!config.auth.enabled}
|
||||
href={$auth.routes.listUsers}
|
||||
disabled={!config.enabled}
|
||||
className="justify-between"
|
||||
>
|
||||
Users
|
||||
{!config.enabled && <AuthWarning title="Auth is not enabled." />}
|
||||
</AppShell.SidebarLink>
|
||||
<AppShell.SidebarLink
|
||||
as={Link}
|
||||
href={routes.auth.roles.list()}
|
||||
disabled={!config.auth.enabled}
|
||||
disabled={!config.enabled}
|
||||
className="justify-between"
|
||||
>
|
||||
Roles & Permissions
|
||||
{!config.enabled ? (
|
||||
<AuthWarning title="Auth is not enabled." />
|
||||
) : $auth.roles.none ? (
|
||||
<AuthWarning title="No roles defined." />
|
||||
) : !$auth.roles.has_admin ? (
|
||||
<AuthWarning title="No admin role defined." />
|
||||
) : null}
|
||||
</AppShell.SidebarLink>
|
||||
<AppShell.SidebarLink as={Link} href={routes.auth.strategies()}>
|
||||
<AppShell.SidebarLink
|
||||
as={Link}
|
||||
href={routes.auth.strategies()}
|
||||
disabled={!config.enabled}
|
||||
className="justify-between"
|
||||
>
|
||||
Strategies
|
||||
{!config.enabled && <AuthWarning title="Auth is not enabled." />}
|
||||
</AppShell.SidebarLink>
|
||||
<AppShell.SidebarLink as={Link} href={routes.auth.settings()}>
|
||||
<AppShell.SidebarLink
|
||||
as={Link}
|
||||
href={routes.auth.settings()}
|
||||
className="justify-between"
|
||||
>
|
||||
Settings
|
||||
</AppShell.SidebarLink>
|
||||
</nav>
|
||||
@@ -59,6 +79,10 @@ export function AuthRoot({ children }) {
|
||||
);
|
||||
}
|
||||
|
||||
const AuthWarning = ({ title }) => (
|
||||
<Icon.Warning title={title} className="size-5 pointer-events-auto" />
|
||||
);
|
||||
|
||||
export function AuthEmpty() {
|
||||
useBrowserTitle(["Auth"]);
|
||||
return <Empty Icon={IconFingerprint} title="Not implemented yet" />;
|
||||
|
||||
@@ -21,7 +21,7 @@ export function AuthIndex() {
|
||||
|
||||
const usersLink = app.getAbsolutePath("/data/" + routes.data.entity.list(users_entity));
|
||||
const rolesLink = routes.auth.roles.list();
|
||||
const strategiesLink = app.getSettingsPath(["auth", "strategies"]);
|
||||
const strategiesLink = routes.auth.strategies();
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -50,7 +50,7 @@ export function AuthIndex() {
|
||||
value={!enabled ? 0 : rolesTotal}
|
||||
actions={[
|
||||
{ label: "View all", href: rolesLink },
|
||||
{ label: "Add new", variant: "default", href: rolesLink }
|
||||
{ label: "Manage", variant: "default", href: rolesLink }
|
||||
]}
|
||||
/>
|
||||
<KpiCard
|
||||
@@ -58,7 +58,7 @@ export function AuthIndex() {
|
||||
value={!enabled ? 0 : strategiesTotal}
|
||||
actions={[
|
||||
{ label: "View all", href: strategiesLink },
|
||||
{ label: "Add new", variant: "default", href: strategiesLink }
|
||||
{ label: "Manage", variant: "default", href: strategiesLink }
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -15,7 +15,6 @@ import {
|
||||
} from "ui/components/form/json-schema-form";
|
||||
import { useBrowserTitle } from "ui/hooks/use-browser-title";
|
||||
import * as AppShell from "ui/layouts/AppShell/AppShell";
|
||||
import { Breadcrumbs2 } from "ui/layouts/AppShell/Breadcrumbs2";
|
||||
import { create } from "zustand";
|
||||
import { combine } from "zustand/middleware";
|
||||
|
||||
@@ -52,9 +51,8 @@ const formConfig = {
|
||||
};
|
||||
|
||||
function AuthSettingsInternal() {
|
||||
const { config, schema: _schema, actions } = useBkndAuth();
|
||||
const { config, schema: _schema, actions, $auth } = useBkndAuth();
|
||||
const schema = JSON.parse(JSON.stringify(_schema));
|
||||
const hasRoles = Object.keys(config.roles ?? {}).length > 0;
|
||||
|
||||
schema.properties.jwt.required = ["alg"];
|
||||
|
||||
@@ -105,11 +103,12 @@ function AuthSettingsInternal() {
|
||||
label={
|
||||
<div className="flex flex-row gap-2 items-center">
|
||||
<span>Guard Enabled</span>
|
||||
{!hasRoles && (
|
||||
<Icon.Warning title="No roles defined. Enabling the guard will block all requests." />
|
||||
{!$auth.roles.has_admin && (
|
||||
<Icon.Warning title="No admin roles defined. Enabling the guard will likely block all requests." />
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
disabled={$auth.roles.none}
|
||||
description="When enabled, enforces permissions on all routes. Make sure to create roles first."
|
||||
descriptionPlacement="top"
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user