mirror of
https://github.com/docmost/docmost.git
synced 2026-05-06 22:03:06 +08:00
feat: API key restriction
This commit is contained in:
@@ -604,6 +604,10 @@
|
||||
"This action cannot be undone. Any applications using this API key will stop working.": "This action cannot be undone. Any applications using this API key will stop working.",
|
||||
"Update API key": "Update API key",
|
||||
"Manage API keys for all users in the workspace": "Manage API keys for all users in the workspace",
|
||||
"Restrict API key creation to admins": "Restrict API key creation to admins",
|
||||
"Only admins and owners can create new API keys. Existing member keys will continue to work.": "Only admins and owners can create new API keys. Existing member keys will continue to work.",
|
||||
"Toggle restrict API keys to admins": "Toggle restrict API keys to admins",
|
||||
"API key creation is restricted to admins by your workspace administrator.": "API key creation is restricted to admins by your workspace administrator.",
|
||||
"AI settings": "AI settings",
|
||||
"AI search": "AI search",
|
||||
"AI Answer": "AI Answer",
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
import { Text, Switch, Tooltip } from "@mantine/core";
|
||||
import { useAtom } from "jotai";
|
||||
import { workspaceAtom } from "@/features/user/atoms/current-user-atom.ts";
|
||||
import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { updateWorkspace } from "@/features/workspace/services/workspace-service.ts";
|
||||
import { notifications } from "@mantine/notifications";
|
||||
import useEnterpriseAccess from "@/ee/hooks/use-enterprise-access.tsx";
|
||||
import {
|
||||
ResponsiveSettingsRow,
|
||||
ResponsiveSettingsContent,
|
||||
ResponsiveSettingsControl,
|
||||
} from "@/components/ui/responsive-settings-row";
|
||||
|
||||
export default function RestrictApiToAdmins() {
|
||||
const { t } = useTranslation();
|
||||
const [workspace, setWorkspace] = useAtom(workspaceAtom);
|
||||
const [checked, setChecked] = useState(
|
||||
workspace?.settings?.api?.restrictToAdmins === true,
|
||||
);
|
||||
const hasAccess = useEnterpriseAccess();
|
||||
|
||||
const handleChange = async (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const value = event.currentTarget.checked;
|
||||
try {
|
||||
const updatedWorkspace = await updateWorkspace({
|
||||
restrictApiToAdmins: value,
|
||||
});
|
||||
setChecked(value);
|
||||
setWorkspace(updatedWorkspace);
|
||||
} catch (err) {
|
||||
notifications.show({
|
||||
message: err?.response?.data?.message,
|
||||
color: "red",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<ResponsiveSettingsRow>
|
||||
<ResponsiveSettingsContent>
|
||||
<Text size="md">
|
||||
{t("Restrict API key creation to admins")}
|
||||
</Text>
|
||||
<Text size="sm" c="dimmed">
|
||||
{t(
|
||||
"Only admins and owners can create new API keys. Existing member keys will continue to work.",
|
||||
)}
|
||||
</Text>
|
||||
</ResponsiveSettingsContent>
|
||||
|
||||
<ResponsiveSettingsControl>
|
||||
<Tooltip
|
||||
label={t("Requires an enterprise license")}
|
||||
disabled={hasAccess}
|
||||
refProp="rootRef"
|
||||
>
|
||||
<Switch
|
||||
checked={checked}
|
||||
onChange={handleChange}
|
||||
disabled={!hasAccess}
|
||||
aria-label={t("Toggle restrict API keys to admins")}
|
||||
/>
|
||||
</Tooltip>
|
||||
</ResponsiveSettingsControl>
|
||||
</ResponsiveSettingsRow>
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { useState } from "react";
|
||||
import { Anchor, Alert, Button, Group, Space, Text } from "@mantine/core";
|
||||
import { IconInfoCircle } from "@tabler/icons-react";
|
||||
import { Helmet } from "react-helmet-async";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import SettingsTitle from "@/components/settings/settings-title";
|
||||
@@ -15,6 +16,7 @@ import { useGetApiKeysQuery } from "@/ee/api-key/queries/api-key-query.ts";
|
||||
import { IApiKey } from "@/ee/api-key";
|
||||
import { useAtom } from "jotai";
|
||||
import { workspaceAtom } from "@/features/user/atoms/current-user-atom.ts";
|
||||
import useUserRole from "@/hooks/use-user-role.tsx";
|
||||
|
||||
export default function UserApiKeys() {
|
||||
const { t } = useTranslation();
|
||||
@@ -26,7 +28,10 @@ export default function UserApiKeys() {
|
||||
const [selectedApiKey, setSelectedApiKey] = useState<IApiKey | null>(null);
|
||||
const { data, isLoading } = useGetApiKeysQuery({ cursor });
|
||||
const [workspace] = useAtom(workspaceAtom);
|
||||
const { isAdmin } = useUserRole();
|
||||
const mcpEnabled = workspace?.settings?.ai?.mcp === true;
|
||||
const restrictToAdmins = workspace?.settings?.api?.restrictToAdmins === true;
|
||||
const canCreate = !restrictToAdmins || isAdmin;
|
||||
|
||||
const handleCreateSuccess = (response: IApiKey) => {
|
||||
setCreatedApiKey(response);
|
||||
@@ -60,8 +65,8 @@ export default function UserApiKeys() {
|
||||
{t("for usage details.")}
|
||||
</Text>
|
||||
|
||||
{mcpEnabled && (
|
||||
<Alert variant="light" color="blue" mb="md" p="sm">
|
||||
{mcpEnabled && canCreate && (
|
||||
<Alert variant="light" color="blue" mb="md" p="sm" icon={<IconInfoCircle />}>
|
||||
<Text size="sm">
|
||||
{t(
|
||||
"Your workspace has MCP enabled. Use your API key to connect AI assistants.",
|
||||
@@ -83,11 +88,19 @@ export default function UserApiKeys() {
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
<Group justify="flex-end" mb="md">
|
||||
<Button onClick={() => setCreateModalOpened(true)}>
|
||||
{t("Create API Key")}
|
||||
</Button>
|
||||
</Group>
|
||||
{canCreate ? (
|
||||
<Group justify="flex-end" mb="md">
|
||||
<Button onClick={() => setCreateModalOpened(true)}>
|
||||
{t("Create API Key")}
|
||||
</Button>
|
||||
</Group>
|
||||
) : restrictToAdmins ? (
|
||||
<Alert variant="light" color="yellow" mb="md" p="sm" icon={<IconInfoCircle />}>
|
||||
<Text size="sm">
|
||||
{t("API key creation is restricted to admins by your workspace administrator.")}
|
||||
</Text>
|
||||
</Alert>
|
||||
) : null}
|
||||
|
||||
<ApiKeyTable
|
||||
apiKeys={data?.items || []}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useState } from "react";
|
||||
import { Anchor, Button, Group, Space, Text } from "@mantine/core";
|
||||
import { Anchor, Button, Divider, Group, Space, Text } from "@mantine/core";
|
||||
import { Helmet } from "react-helmet-async";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import SettingsTitle from "@/components/settings/settings-title";
|
||||
@@ -14,6 +14,7 @@ import { useCursorPaginate } from "@/hooks/use-cursor-paginate";
|
||||
import { useGetApiKeysQuery } from "@/ee/api-key/queries/api-key-query.ts";
|
||||
import { IApiKey } from "@/ee/api-key";
|
||||
import useUserRole from '@/hooks/use-user-role.tsx';
|
||||
import RestrictApiToAdmins from "@/ee/api-key/components/restrict-api-to-admins";
|
||||
|
||||
export default function WorkspaceApiKeys() {
|
||||
const { t } = useTranslation();
|
||||
@@ -63,6 +64,9 @@ export default function WorkspaceApiKeys() {
|
||||
{t("for usage details.")}
|
||||
</Text>
|
||||
|
||||
<RestrictApiToAdmins />
|
||||
<Divider my="lg" />
|
||||
|
||||
<Group justify="flex-end" mb="md">
|
||||
<Button onClick={() => setCreateModalOpened(true)}>
|
||||
{t("Create API Key")}
|
||||
|
||||
@@ -32,6 +32,11 @@ export interface IWorkspace {
|
||||
export interface IWorkspaceSettings {
|
||||
ai?: IWorkspaceAiSettings;
|
||||
sharing?: IWorkspaceSharingSettings;
|
||||
api?: IWorkspaceApiSettings;
|
||||
}
|
||||
|
||||
export interface IWorkspaceApiSettings {
|
||||
restrictToAdmins?: boolean;
|
||||
}
|
||||
|
||||
export interface IWorkspaceAiSettings {
|
||||
|
||||
@@ -327,7 +327,8 @@ export class WorkspaceService {
|
||||
if (
|
||||
typeof updateWorkspaceDto.disablePublicSharing !== 'undefined' ||
|
||||
typeof updateWorkspaceDto.trashRetentionDays !== 'undefined' ||
|
||||
typeof updateWorkspaceDto.mcpEnabled !== 'undefined'
|
||||
typeof updateWorkspaceDto.mcpEnabled !== 'undefined' ||
|
||||
typeof updateWorkspaceDto.restrictApiToAdmins !== 'undefined'
|
||||
) {
|
||||
const ws = await this.db
|
||||
.selectFrom('workspaces')
|
||||
|
||||
+1
-1
Submodule apps/server/src/ee updated: 45fe7b1fda...8b7ae8cf1b
Reference in New Issue
Block a user