@lobehub/chat 0.124.3 → 0.126.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/README.md +8 -8
  3. package/README.zh-CN.md +8 -8
  4. package/docs/Deployment/Authentication.md +72 -0
  5. package/docs/Deployment/Authentication.zh-CN.md +72 -0
  6. package/docs/Deployment/Environment-Variable.md +75 -0
  7. package/docs/Deployment/Environment-Variable.zh-CN.md +76 -0
  8. package/docs/Development/Authentication.md +85 -0
  9. package/docs/Development/Authentication.zh-CN.md +83 -0
  10. package/locales/ar/common.json +1 -0
  11. package/locales/ar/error.json +6 -0
  12. package/locales/ar/setting.json +16 -0
  13. package/locales/de-DE/common.json +1 -0
  14. package/locales/de-DE/error.json +6 -0
  15. package/locales/de-DE/setting.json +16 -0
  16. package/locales/en-US/common.json +1 -0
  17. package/locales/en-US/error.json +6 -0
  18. package/locales/en-US/setting.json +16 -0
  19. package/locales/es-ES/common.json +1 -0
  20. package/locales/es-ES/error.json +6 -0
  21. package/locales/es-ES/setting.json +16 -0
  22. package/locales/fr-FR/common.json +1 -0
  23. package/locales/fr-FR/error.json +6 -0
  24. package/locales/fr-FR/setting.json +16 -0
  25. package/locales/it-IT/common.json +1 -0
  26. package/locales/it-IT/error.json +6 -0
  27. package/locales/it-IT/setting.json +16 -0
  28. package/locales/ja-JP/common.json +1 -0
  29. package/locales/ja-JP/error.json +6 -0
  30. package/locales/ja-JP/setting.json +16 -0
  31. package/locales/ko-KR/common.json +1 -0
  32. package/locales/ko-KR/error.json +6 -0
  33. package/locales/ko-KR/setting.json +16 -0
  34. package/locales/nl-NL/common.json +1 -0
  35. package/locales/nl-NL/error.json +6 -0
  36. package/locales/nl-NL/setting.json +16 -0
  37. package/locales/pl-PL/common.json +1 -0
  38. package/locales/pl-PL/error.json +6 -0
  39. package/locales/pl-PL/setting.json +16 -0
  40. package/locales/pt-BR/common.json +1 -0
  41. package/locales/pt-BR/error.json +6 -0
  42. package/locales/pt-BR/setting.json +16 -0
  43. package/locales/ru-RU/common.json +1 -0
  44. package/locales/ru-RU/error.json +6 -0
  45. package/locales/ru-RU/setting.json +16 -0
  46. package/locales/tr-TR/common.json +1 -0
  47. package/locales/tr-TR/error.json +6 -0
  48. package/locales/tr-TR/setting.json +16 -0
  49. package/locales/vi-VN/common.json +1 -0
  50. package/locales/vi-VN/error.json +6 -0
  51. package/locales/vi-VN/setting.json +16 -0
  52. package/locales/zh-CN/common.json +1 -0
  53. package/locales/zh-CN/error.json +6 -0
  54. package/locales/zh-CN/setting.json +16 -0
  55. package/locales/zh-TW/common.json +1 -0
  56. package/locales/zh-TW/error.json +6 -0
  57. package/locales/zh-TW/setting.json +16 -0
  58. package/package.json +2 -1
  59. package/src/app/api/auth.ts +7 -1
  60. package/src/app/api/chat/[provider]/route.ts +5 -3
  61. package/src/app/api/chat/auth.ts +11 -3
  62. package/src/app/api/chat/google/route.ts +5 -3
  63. package/src/app/api/config/route.ts +9 -2
  64. package/src/app/api/oauth/[...nextauth]/route.ts +3 -0
  65. package/src/app/api/oauth/next-auth.ts +21 -0
  66. package/src/app/api/openai/createBizOpenAI/index.ts +3 -2
  67. package/src/app/api/plugin/gateway/route.ts +7 -4
  68. package/src/app/chat/settings/(desktop)/features/Header.tsx +1 -1
  69. package/src/app/settings/common/Common.tsx +39 -1
  70. package/src/app/settings/common/page.tsx +2 -2
  71. package/src/app/settings/page.tsx +2 -2
  72. package/src/chains/summaryTitle.ts +1 -1
  73. package/src/components/Analytics/Umami.tsx +15 -0
  74. package/src/components/Analytics/index.tsx +4 -1
  75. package/src/config/client.ts +10 -0
  76. package/src/config/server/app.ts +5 -0
  77. package/src/const/auth.ts +2 -0
  78. package/src/const/fetch.ts +5 -1
  79. package/src/features/ChatInput/ActionBar/Clear.tsx +6 -8
  80. package/src/features/Conversation/Error/InvalidAccessCode.tsx +28 -10
  81. package/src/features/Conversation/Error/OAuthForm.tsx +95 -0
  82. package/src/layout/GlobalLayout/index.tsx +10 -7
  83. package/src/locales/default/common.ts +1 -0
  84. package/src/locales/default/error.ts +6 -0
  85. package/src/locales/default/setting.ts +16 -0
  86. package/src/middleware.ts +25 -0
  87. package/src/store/global/slices/common/initialState.ts +0 -1
  88. package/src/store/global/slices/common/selectors.ts +1 -0
  89. package/src/types/settings/index.ts +1 -0
  90. package/tsconfig.json +8 -8
@@ -0,0 +1,95 @@
1
+ import { Icon } from '@lobehub/ui';
2
+ import { App, Button } from 'antd';
3
+ import { ScanFace } from 'lucide-react';
4
+ import { signIn, signOut, useSession } from 'next-auth/react';
5
+ import { memo, useCallback } from 'react';
6
+ import { useTranslation } from 'react-i18next';
7
+ import { Center, Flexbox } from 'react-layout-kit';
8
+
9
+ import { useChatStore } from '@/store/chat';
10
+
11
+ import { FormAction } from './style';
12
+
13
+ const OAuthForm = memo<{ id: string }>(({ id }) => {
14
+ const { t } = useTranslation('error');
15
+
16
+ const { data: session, status } = useSession();
17
+ const isOAuthLoggedIn = status === 'authenticated' && session && session.user;
18
+
19
+ const [resend, deleteMessage] = useChatStore((s) => [s.resendMessage, s.deleteMessage]);
20
+
21
+ const { message, modal } = App.useApp();
22
+
23
+ const handleSignOut = useCallback(() => {
24
+ modal.confirm({
25
+ centered: true,
26
+ okButtonProps: { danger: true },
27
+ onOk: () => {
28
+ signOut();
29
+ message.success(t('settingSystem.oauth.signout.success', { ns: 'setting' }));
30
+ },
31
+ title: t('settingSystem.oauth.signout.confirm', { ns: 'setting' }),
32
+ });
33
+ }, []);
34
+
35
+ return (
36
+ <Center gap={16} style={{ maxWidth: 300 }}>
37
+ <FormAction
38
+ avatar={isOAuthLoggedIn ? '✅' : '🕵️‍♂️'}
39
+ description={
40
+ isOAuthLoggedIn
41
+ ? `${t('unlock.oauth.welcome')} ${session?.user?.name}`
42
+ : t('unlock.oauth.description')
43
+ }
44
+ title={isOAuthLoggedIn ? t('unlock.oauth.success') : t('unlock.oauth.title')}
45
+ >
46
+ {isOAuthLoggedIn ? (
47
+ <Button
48
+ block
49
+ icon={<Icon icon={ScanFace} />}
50
+ onClick={handleSignOut}
51
+ style={{ marginTop: 8 }}
52
+ >
53
+ {t('settingSystem.oauth.signout.action', { ns: 'setting' })}
54
+ </Button>
55
+ ) : (
56
+ <Button
57
+ block
58
+ icon={<Icon icon={ScanFace} />}
59
+ loading={status === 'loading'}
60
+ onClick={() => signIn('auth0')}
61
+ style={{ marginTop: 8 }}
62
+ type={'primary'}
63
+ >
64
+ {t('oauth', { ns: 'common' })}
65
+ </Button>
66
+ )}
67
+ </FormAction>
68
+ <Flexbox gap={12} width={'100%'}>
69
+ {isOAuthLoggedIn ? (
70
+ <Button
71
+ block
72
+ onClick={() => {
73
+ resend(id);
74
+ deleteMessage(id);
75
+ }}
76
+ style={{ marginTop: 8 }}
77
+ type={'primary'}
78
+ >
79
+ {t('unlock.confirm')}
80
+ </Button>
81
+ ) : (
82
+ <Button
83
+ onClick={() => {
84
+ deleteMessage(id);
85
+ }}
86
+ >
87
+ {t('unlock.closeMessage')}
88
+ </Button>
89
+ )}
90
+ </Flexbox>
91
+ </Center>
92
+ );
93
+ });
94
+
95
+ export default OAuthForm;
@@ -3,6 +3,7 @@
3
3
  import { App } from 'antd';
4
4
  import { createStyles } from 'antd-style';
5
5
  import 'antd/dist/reset.css';
6
+ import { SessionProvider } from 'next-auth/react';
6
7
  import dynamic from 'next/dynamic';
7
8
  import { FC, PropsWithChildren, memo } from 'react';
8
9
 
@@ -47,13 +48,15 @@ interface GlobalLayoutProps extends AppThemeProps {
47
48
  }
48
49
 
49
50
  const GlobalLayout = ({ children, defaultLang, ...theme }: GlobalLayoutProps) => (
50
- <AppTheme {...theme}>
51
- <Locale defaultLang={defaultLang}>
52
- <StoreHydration />
53
- <Container>{children}</Container>
54
- <DebugUI />
55
- </Locale>
56
- </AppTheme>
51
+ <SessionProvider basePath="/api/oauth">
52
+ <AppTheme {...theme}>
53
+ <Locale defaultLang={defaultLang}>
54
+ <StoreHydration />
55
+ <Container>{children}</Container>
56
+ <DebugUI />
57
+ </Locale>
58
+ </AppTheme>
59
+ </SessionProvider>
57
60
  );
58
61
 
59
62
  export default GlobalLayout;
@@ -108,6 +108,7 @@ export default {
108
108
  zhipu: '智谱AI',
109
109
  },
110
110
  noDescription: '暂无描述',
111
+ oauth: 'SSO 登录',
111
112
  ok: '确定',
112
113
  password: '密码',
113
114
  pin: '置顶',
@@ -110,6 +110,12 @@ export default {
110
110
  },
111
111
  closeMessage: '关闭提示',
112
112
  confirm: '确认并重试',
113
+ oauth: {
114
+ description: '管理员已开启统一登录认证,点击下方按钮登录,即可解锁应用',
115
+ success: '登录成功',
116
+ title: '登录账号',
117
+ welcome: '欢迎你!',
118
+ },
113
119
  password: {
114
120
  description: '管理员已开启应用加密,输入应用密码后即可解锁应用。密码只需填写一次',
115
121
  placeholder: '请输入密码',
@@ -265,6 +265,22 @@ export default {
265
265
  placeholder: '请输入访问密码',
266
266
  title: '访问密码',
267
267
  },
268
+ oauth: {
269
+ info: {
270
+ desc: '已登录',
271
+ title: '账户信息',
272
+ },
273
+ signin: {
274
+ action: '登录',
275
+ desc: '使用 SSO 登录以解锁应用',
276
+ title: '登录账号',
277
+ },
278
+ signout: {
279
+ action: '退出登录',
280
+ confirm: '确认退出?',
281
+ success: '退出登录成功',
282
+ },
283
+ },
268
284
  title: '系统设置',
269
285
  },
270
286
  settingTTS: {
@@ -0,0 +1,25 @@
1
+ // export { auth as middleware } from './app/api/next-auth';
2
+ import { NextResponse } from 'next/server';
3
+
4
+ import { auth } from './app/api/oauth/next-auth';
5
+ import { OAUTH_AUTHORIZED } from './const/auth';
6
+
7
+ export const config = {
8
+ matcher: '/api/:path*',
9
+ };
10
+
11
+ export default auth((req) => {
12
+ // Just check if session exists
13
+ const session = req.auth;
14
+ const isLoggedIn = !!session;
15
+
16
+ // Remove & amend OAuth authorized header
17
+ const requestHeaders = new Headers(req.headers);
18
+ requestHeaders.delete(OAUTH_AUTHORIZED);
19
+ if (isLoggedIn) requestHeaders.set(OAUTH_AUTHORIZED, 'true');
20
+ return NextResponse.next({
21
+ request: {
22
+ headers: requestHeaders,
23
+ },
24
+ });
25
+ });
@@ -1,6 +1,5 @@
1
1
  import { AppRouterInstance } from 'next/dist/shared/lib/app-router-context.shared-runtime';
2
2
 
3
-
4
3
  export enum SidebarTabKey {
5
4
  Chat = 'chat',
6
5
  Market = 'market',
@@ -1,5 +1,6 @@
1
1
  import { GlobalStore } from '@/store/global';
2
2
 
3
3
  export const commonSelectors = {
4
+ enabledOAuthSSO: (s: GlobalStore) => s.serverConfig.enabledOAuthSSO,
4
5
  userAvatar: (s: GlobalStore) => s.avatar || '',
5
6
  };
@@ -21,6 +21,7 @@ export interface GlobalTool {
21
21
  export interface GlobalServerConfig {
22
22
  customModelName?: string;
23
23
  defaultAgent?: DeepPartial<GlobalDefaultAgent>;
24
+ enabledOAuthSSO?: boolean;
24
25
  languageModel?: DeepPartial<GlobalLLMConfig>;
25
26
  }
26
27
 
package/tsconfig.json CHANGED
@@ -19,13 +19,13 @@
19
19
  "types": ["vitest/globals"],
20
20
  "paths": {
21
21
  "@/*": ["./src/*"],
22
- "~test-utils": ["./tests/utils.tsx"],
22
+ "~test-utils": ["./tests/utils.tsx"]
23
23
  },
24
24
  "plugins": [
25
25
  {
26
- "name": "next",
27
- },
28
- ],
26
+ "name": "next"
27
+ }
28
+ ]
29
29
  },
30
30
  "exclude": ["node_modules"],
31
31
  "include": [
@@ -36,11 +36,11 @@
36
36
  "**/*.ts",
37
37
  "**/*.d.ts",
38
38
  "**/*.tsx",
39
- ".next/types/**/*.ts",
39
+ ".next/types/**/*.ts"
40
40
  ],
41
41
  "ts-node": {
42
42
  "compilerOptions": {
43
- "module": "commonjs",
44
- },
45
- },
43
+ "module": "commonjs"
44
+ }
45
+ }
46
46
  }