@lobehub/chat 1.16.9 → 1.16.11
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.
Potentially problematic release.
This version of @lobehub/chat might be problematic. Click here for more details.
- package/CHANGELOG.md +66 -0
- package/docs/self-hosting/server-database/docker-compose.mdx +1 -0
- package/docs/self-hosting/server-database/docker-compose.zh-CN.mdx +1 -0
- package/package.json +3 -3
- package/src/app/api/webhooks/logto/__tests__/route.test.ts +92 -0
- package/src/app/api/webhooks/logto/route.ts +40 -0
- package/src/app/api/webhooks/logto/validateRequest.ts +50 -0
- package/src/config/__tests__/auth.test.ts +200 -0
- package/src/config/auth.ts +99 -2
- package/src/config/modelProviders/bedrock.ts +14 -14
- package/src/config/modelProviders/mistral.ts +0 -3
- package/src/libs/agent-runtime/qwen/index.test.ts +20 -4
- package/src/libs/agent-runtime/qwen/index.ts +1 -1
- package/src/libs/next-auth/auth.config.ts +3 -1
- package/src/libs/next-auth/sso-providers/auth0.ts +5 -3
- package/src/libs/next-auth/sso-providers/authelia.ts +6 -6
- package/src/libs/next-auth/sso-providers/authentik.ts +5 -3
- package/src/libs/next-auth/sso-providers/azure-ad.ts +5 -3
- package/src/libs/next-auth/sso-providers/cloudflare-zero-trust.ts +4 -3
- package/src/libs/next-auth/sso-providers/generic-oidc.ts +3 -3
- package/src/libs/next-auth/sso-providers/github.ts +4 -2
- package/src/libs/next-auth/sso-providers/logto.ts +3 -3
- package/src/libs/next-auth/sso-providers/zitadel.ts +5 -3
- package/src/server/services/nextAuthUser/index.ts +42 -0
package/CHANGELOG.md
CHANGED
@@ -2,6 +2,72 @@
|
|
2
2
|
|
3
3
|
# Changelog
|
4
4
|
|
5
|
+
### [Version 1.16.11](https://github.com/lobehub/lobe-chat/compare/v1.16.10...v1.16.11)
|
6
|
+
|
7
|
+
<sup>Released on **2024-09-12**</sup>
|
8
|
+
|
9
|
+
#### 🐛 Bug Fixes
|
10
|
+
|
11
|
+
- **misc**: Support webhooks for logto.
|
12
|
+
|
13
|
+
#### 💄 Styles
|
14
|
+
|
15
|
+
- **misc**: Default disable mistral provider useless models.
|
16
|
+
|
17
|
+
<br/>
|
18
|
+
|
19
|
+
<details>
|
20
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
21
|
+
|
22
|
+
#### What's fixed
|
23
|
+
|
24
|
+
- **misc**: Support webhooks for logto, closes [#3774](https://github.com/lobehub/lobe-chat/issues/3774) ([0cfee6b](https://github.com/lobehub/lobe-chat/commit/0cfee6b))
|
25
|
+
|
26
|
+
#### Styles
|
27
|
+
|
28
|
+
- **misc**: Default disable mistral provider useless models, closes [#3922](https://github.com/lobehub/lobe-chat/issues/3922) ([bdbc647](https://github.com/lobehub/lobe-chat/commit/bdbc647))
|
29
|
+
|
30
|
+
</details>
|
31
|
+
|
32
|
+
<div align="right">
|
33
|
+
|
34
|
+
[](#readme-top)
|
35
|
+
|
36
|
+
</div>
|
37
|
+
|
38
|
+
### [Version 1.16.10](https://github.com/lobehub/lobe-chat/compare/v1.16.9...v1.16.10)
|
39
|
+
|
40
|
+
<sup>Released on **2024-09-12**</sup>
|
41
|
+
|
42
|
+
#### ♻ Code Refactoring
|
43
|
+
|
44
|
+
- **misc**: Support Environment Variable Inference For NextAuth.
|
45
|
+
|
46
|
+
#### 🐛 Bug Fixes
|
47
|
+
|
48
|
+
- **misc**: Qwen model param error.
|
49
|
+
|
50
|
+
<br/>
|
51
|
+
|
52
|
+
<details>
|
53
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
54
|
+
|
55
|
+
#### Code refactoring
|
56
|
+
|
57
|
+
- **misc**: Support Environment Variable Inference For NextAuth, closes [#3701](https://github.com/lobehub/lobe-chat/issues/3701) ([b956755](https://github.com/lobehub/lobe-chat/commit/b956755))
|
58
|
+
|
59
|
+
#### What's fixed
|
60
|
+
|
61
|
+
- **misc**: Qwen model param error, closes [#3902](https://github.com/lobehub/lobe-chat/issues/3902) ([c9f00e5](https://github.com/lobehub/lobe-chat/commit/c9f00e5))
|
62
|
+
|
63
|
+
</details>
|
64
|
+
|
65
|
+
<div align="right">
|
66
|
+
|
67
|
+
[](#readme-top)
|
68
|
+
|
69
|
+
</div>
|
70
|
+
|
5
71
|
### [Version 1.16.9](https://github.com/lobehub/lobe-chat/compare/v1.16.8...v1.16.9)
|
6
72
|
|
7
73
|
<sup>Released on **2024-09-12**</sup>
|
@@ -186,6 +186,7 @@ And the service port without reverse proxy:
|
|
186
186
|
|
187
187
|
<Callout type="warning">
|
188
188
|
Please note that CORS cross-origin is configured internally in MinIO / Logto service, do not configure CORS additionally in your reverse proxy, as this will cause errors.
|
189
|
+
For minio ports other than 443, Host must be $http_host (with port number), otherwise a 403 error will occur: proxy_set_header Host $http_host.
|
189
190
|
|
190
191
|
If you need to configure SSL certificates, please configure them uniformly in the outer Nginx reverse proxy, rather than in MinIO.
|
191
192
|
|
@@ -185,6 +185,7 @@ docker compose up -d
|
|
185
185
|
|
186
186
|
<Callout type="warning">
|
187
187
|
请务必注意,CORS 跨域是在 MinIO / Logto 服务端内部配置的,请勿在你的反向代理中额外配置 CORS,这会导致错误。
|
188
|
+
对于minio非443端口时,Host必须是$http_host(带端口号),否则会403错误:proxy_set_header Host $http_host。
|
188
189
|
|
189
190
|
如果你需要配置 SSL 证书,请统一在外层的 Nginx 反向代理中配置,而不是在 MinIO 中配置。
|
190
191
|
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@lobehub/chat",
|
3
|
-
"version": "1.16.
|
3
|
+
"version": "1.16.11",
|
4
4
|
"description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
|
5
5
|
"keywords": [
|
6
6
|
"framework",
|
@@ -102,7 +102,7 @@
|
|
102
102
|
"@ant-design/icons": "^5.4.0",
|
103
103
|
"@ant-design/pro-components": "^2.7.10",
|
104
104
|
"@anthropic-ai/sdk": "^0.27.0",
|
105
|
-
"@auth/core": "0.
|
105
|
+
"@auth/core": "^0.34.2",
|
106
106
|
"@aws-sdk/client-bedrock-runtime": "^3.637.0",
|
107
107
|
"@aws-sdk/client-s3": "^3.637.0",
|
108
108
|
"@aws-sdk/s3-request-presigner": "^3.637.0",
|
@@ -169,7 +169,7 @@
|
|
169
169
|
"modern-screenshot": "^4.4.39",
|
170
170
|
"nanoid": "^5.0.7",
|
171
171
|
"next": "14.2.8",
|
172
|
-
"next-auth": "
|
172
|
+
"next-auth": "beta",
|
173
173
|
"next-sitemap": "^4.2.3",
|
174
174
|
"numeral": "^2.0.6",
|
175
175
|
"nuqs": "^1.17.8",
|
@@ -0,0 +1,92 @@
|
|
1
|
+
import { createHmac } from 'node:crypto';
|
2
|
+
import { describe, expect, it } from 'vitest';
|
3
|
+
|
4
|
+
interface UserDataUpdatedEvent {
|
5
|
+
event: string;
|
6
|
+
createdAt: string;
|
7
|
+
userAgent: string;
|
8
|
+
ip: string;
|
9
|
+
path: string;
|
10
|
+
method: string;
|
11
|
+
status: number;
|
12
|
+
params: {
|
13
|
+
userId: string;
|
14
|
+
};
|
15
|
+
matchedRoute: string;
|
16
|
+
data: {
|
17
|
+
id: string;
|
18
|
+
username: string;
|
19
|
+
primaryEmail: string;
|
20
|
+
primaryPhone: string | null;
|
21
|
+
name: string;
|
22
|
+
avatar: string | null;
|
23
|
+
customData: Record<string, unknown>;
|
24
|
+
identities: Record<string, unknown>;
|
25
|
+
lastSignInAt: number;
|
26
|
+
createdAt: number;
|
27
|
+
updatedAt: number;
|
28
|
+
profile: Record<string, unknown>;
|
29
|
+
applicationId: string;
|
30
|
+
isSuspended: boolean;
|
31
|
+
};
|
32
|
+
hookId: string;
|
33
|
+
}
|
34
|
+
|
35
|
+
const userDataUpdatedEvent: UserDataUpdatedEvent = {
|
36
|
+
event: 'User.Data.Updated',
|
37
|
+
createdAt: '2024-09-07T08:29:09.381Z',
|
38
|
+
userAgent:
|
39
|
+
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 Edg/128.0.0.0',
|
40
|
+
ip: '223.104.76.217',
|
41
|
+
path: '/users/rra41h9vmpnd',
|
42
|
+
method: 'PATCH',
|
43
|
+
status: 200,
|
44
|
+
params: {
|
45
|
+
userId: 'rra41h9vmpnd',
|
46
|
+
},
|
47
|
+
matchedRoute: '/users/:userId',
|
48
|
+
data: {
|
49
|
+
id: 'uid',
|
50
|
+
username: 'test',
|
51
|
+
primaryEmail: 'user@example.com',
|
52
|
+
primaryPhone: null,
|
53
|
+
name: 'test',
|
54
|
+
avatar: null,
|
55
|
+
customData: {},
|
56
|
+
identities: {},
|
57
|
+
lastSignInAt: 1725446291545,
|
58
|
+
createdAt: 1725440405556,
|
59
|
+
updatedAt: 1725697749337,
|
60
|
+
profile: {},
|
61
|
+
applicationId: 'appid',
|
62
|
+
isSuspended: false,
|
63
|
+
},
|
64
|
+
hookId: 'hookId',
|
65
|
+
};
|
66
|
+
|
67
|
+
const LOGTO_WEBHOOK_SIGNING_KEY = 'logto-signing-key';
|
68
|
+
|
69
|
+
// Test Logto Webhooks in Local dev, here is some tips:
|
70
|
+
// - Replace the var `LOGTO_WEBHOOK_SIGNING_KEY` with the actual value in your `.env` file
|
71
|
+
// - Start web request: If you want to run the test, replace `describe.skip` with `describe` below
|
72
|
+
|
73
|
+
describe.skip('Test Logto Webhooks in Local dev', () => {
|
74
|
+
// describe('Test Logto Webhooks in Local dev', () => {
|
75
|
+
it('should send a POST request with logto headers', async () => {
|
76
|
+
const url = 'http://localhost:3010/api/webhooks/logto'; // 替换为目标URL
|
77
|
+
const data = userDataUpdatedEvent;
|
78
|
+
// Generate data signature
|
79
|
+
const hmac = createHmac('sha256', LOGTO_WEBHOOK_SIGNING_KEY!);
|
80
|
+
hmac.update(JSON.stringify(data));
|
81
|
+
const signature = hmac.digest('hex');
|
82
|
+
const response = await fetch(url, {
|
83
|
+
method: 'POST',
|
84
|
+
headers: {
|
85
|
+
'Content-Type': 'application/json',
|
86
|
+
'logto-signature-sha-256': signature,
|
87
|
+
},
|
88
|
+
body: JSON.stringify(data),
|
89
|
+
});
|
90
|
+
expect(response.status).toBe(200); // 检查响应状态
|
91
|
+
});
|
92
|
+
});
|
@@ -0,0 +1,40 @@
|
|
1
|
+
import { NextResponse } from 'next/server';
|
2
|
+
|
3
|
+
import { authEnv } from '@/config/auth';
|
4
|
+
import { pino } from '@/libs/logger';
|
5
|
+
import { NextAuthUserService } from '@/server/services/nextAuthUser';
|
6
|
+
|
7
|
+
import { validateRequest } from './validateRequest';
|
8
|
+
|
9
|
+
export const POST = async (req: Request): Promise<NextResponse> => {
|
10
|
+
const payload = await validateRequest(req, authEnv.LOGTO_WEBHOOK_SIGNING_KEY!);
|
11
|
+
|
12
|
+
if (!payload) {
|
13
|
+
return NextResponse.json(
|
14
|
+
{ error: 'webhook verification failed or payload was malformed' },
|
15
|
+
{ status: 400 },
|
16
|
+
);
|
17
|
+
}
|
18
|
+
|
19
|
+
const { event, data } = payload;
|
20
|
+
|
21
|
+
pino.trace(`logto webhook payload: ${{ data, event }}`);
|
22
|
+
|
23
|
+
const nextAuthUserService = new NextAuthUserService();
|
24
|
+
switch (event) {
|
25
|
+
case 'User.Data.Updated': {
|
26
|
+
return nextAuthUserService.safeUpdateUser(data.id, {
|
27
|
+
avatar: data?.avatar,
|
28
|
+
email: data?.primaryEmail,
|
29
|
+
fullName: data?.name,
|
30
|
+
});
|
31
|
+
}
|
32
|
+
|
33
|
+
default: {
|
34
|
+
pino.warn(
|
35
|
+
`${req.url} received event type "${event}", but no handler is defined for this type`,
|
36
|
+
);
|
37
|
+
return NextResponse.json({ error: `unrecognised payload type: ${event}` }, { status: 400 });
|
38
|
+
}
|
39
|
+
}
|
40
|
+
};
|
@@ -0,0 +1,50 @@
|
|
1
|
+
import { headers } from 'next/headers';
|
2
|
+
import { createHmac } from 'node:crypto';
|
3
|
+
|
4
|
+
import { authEnv } from '@/config/auth';
|
5
|
+
|
6
|
+
export type LogtToUserEntity = {
|
7
|
+
applicationId?: string;
|
8
|
+
avatar?: string;
|
9
|
+
createdAt?: string;
|
10
|
+
customData?: object;
|
11
|
+
id: string;
|
12
|
+
identities?: object;
|
13
|
+
isSuspended?: boolean;
|
14
|
+
lastSignInAt?: string;
|
15
|
+
name?: string;
|
16
|
+
primaryEmail?: string;
|
17
|
+
primaryPhone?: string;
|
18
|
+
username?: string;
|
19
|
+
};
|
20
|
+
|
21
|
+
interface LogtoWebhookPayload {
|
22
|
+
// Only support user event currently
|
23
|
+
data: LogtToUserEntity;
|
24
|
+
event: string;
|
25
|
+
}
|
26
|
+
|
27
|
+
export const validateRequest = async (request: Request, signingKey: string) => {
|
28
|
+
const payloadString = await request.text();
|
29
|
+
const headerPayload = headers();
|
30
|
+
const logtoHeaderSignature = headerPayload.get('logto-signature-sha-256')!;
|
31
|
+
try {
|
32
|
+
const hmac = createHmac('sha256', signingKey);
|
33
|
+
hmac.update(payloadString);
|
34
|
+
const signature = hmac.digest('hex');
|
35
|
+
if (signature === logtoHeaderSignature) {
|
36
|
+
return JSON.parse(payloadString) as LogtoWebhookPayload;
|
37
|
+
} else {
|
38
|
+
console.warn(
|
39
|
+
'[logto]: signature verify failed, please check your logto signature in `LOGTO_WEBHOOK_SIGNING_KEY`',
|
40
|
+
);
|
41
|
+
return;
|
42
|
+
}
|
43
|
+
} catch (e) {
|
44
|
+
if (!authEnv.LOGTO_WEBHOOK_SIGNING_KEY) {
|
45
|
+
throw new Error('`LOGTO_WEBHOOK_SIGNING_KEY` environment variable is missing.');
|
46
|
+
}
|
47
|
+
console.error('[logto]: incoming webhook failed in verification.\n', e);
|
48
|
+
return;
|
49
|
+
}
|
50
|
+
};
|
@@ -0,0 +1,200 @@
|
|
1
|
+
// @vitest-environment node
|
2
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
3
|
+
|
4
|
+
import { getAuthConfig } from '../auth';
|
5
|
+
|
6
|
+
// Stub the global process object to safely mock environment variables
|
7
|
+
vi.stubGlobal('process', {
|
8
|
+
...process, // Preserve the original process object
|
9
|
+
env: { ...process.env }, // Clone the environment variables object for modification
|
10
|
+
});
|
11
|
+
|
12
|
+
const spyConsoleWarn = vi.spyOn(console, 'warn');
|
13
|
+
|
14
|
+
describe('getAuthConfig', () => {
|
15
|
+
beforeEach(() => {
|
16
|
+
// Clear all environment variables before each test
|
17
|
+
// @ts-expect-error
|
18
|
+
process.env = {};
|
19
|
+
});
|
20
|
+
|
21
|
+
// TODO(NextAuth ENVs Migration): Remove once nextauth envs migration time end
|
22
|
+
describe('should warn about deprecated environment variables', () => {
|
23
|
+
it('should warn about Auth0 deprecated environment variables', () => {
|
24
|
+
// Set all deprecated environment variables
|
25
|
+
process.env.AUTH0_CLIENT_ID = 'auth0_client_id';
|
26
|
+
process.env.AUTH0_CLIENT_SECRET = 'auth0_client_secret';
|
27
|
+
process.env.AUTH0_ISSUER = 'auth0_issuer';
|
28
|
+
// Call the function
|
29
|
+
getAuthConfig();
|
30
|
+
|
31
|
+
// Check that the spyConsoleWarn function was called for each deprecated environment variable
|
32
|
+
// Example: A warning meassage should incloud: `<Old Env> .* <New Env>`
|
33
|
+
// And the regex should match the warning message: `AUTH0_CLIENT_ID.*AUTH_AUTH0_ID`
|
34
|
+
expect(spyConsoleWarn).toHaveBeenCalledWith(
|
35
|
+
expect.stringMatching(/AUTH0_CLIENT_ID.*AUTH_AUTH0_ID/),
|
36
|
+
);
|
37
|
+
expect(spyConsoleWarn).toHaveBeenCalledWith(
|
38
|
+
expect.stringMatching(/AUTH0_CLIENT_SECRET.*AUTH_AUTH0_SECRET/),
|
39
|
+
);
|
40
|
+
expect(spyConsoleWarn).toHaveBeenCalledWith(
|
41
|
+
expect.stringMatching(/AUTH0_ISSUER.*AUTH_AUTH0_ISSUER/),
|
42
|
+
);
|
43
|
+
});
|
44
|
+
it('should warn about Authentik deprecated environment variables', () => {
|
45
|
+
// Set all deprecated environment variables
|
46
|
+
process.env.AUTHENTIK_CLIENT_ID = 'authentik_client_id';
|
47
|
+
process.env.AUTHENTIK_CLIENT_SECRET = 'authentik_client_secret';
|
48
|
+
process.env.AUTHENTIK_ISSUER = 'authentik_issuer';
|
49
|
+
|
50
|
+
// Call the function
|
51
|
+
getAuthConfig();
|
52
|
+
|
53
|
+
// Check that the spyConsoleWarn function was called for each deprecated environment variable
|
54
|
+
expect(spyConsoleWarn).toHaveBeenCalledWith(
|
55
|
+
expect.stringMatching(/AUTHENTIK_CLIENT_ID.*AUTH_AUTHENTIK_ID/),
|
56
|
+
);
|
57
|
+
expect(spyConsoleWarn).toHaveBeenCalledWith(
|
58
|
+
expect.stringMatching(/AUTHENTIK_CLIENT_SECRET.*AUTH_AUTHENTIK_SECRET/),
|
59
|
+
);
|
60
|
+
expect(spyConsoleWarn).toHaveBeenCalledWith(
|
61
|
+
expect.stringMatching(/AUTHENTIK_ISSUER.*AUTH_AUTHENTIK_ISSUER/),
|
62
|
+
);
|
63
|
+
});
|
64
|
+
it('should warn about Authelia deprecated environment variables', () => {
|
65
|
+
// Set all deprecated environment variables
|
66
|
+
process.env.AUTHELIA_CLIENT_ID = 'authelia_client_id';
|
67
|
+
process.env.AUTHELIA_CLIENT_SECRET = 'authelia_client_secret';
|
68
|
+
process.env.AUTHELIA_ISSUER = 'authelia_issuer';
|
69
|
+
|
70
|
+
// Call the function
|
71
|
+
getAuthConfig();
|
72
|
+
|
73
|
+
// Check that the spyConsoleWarn function was called for each deprecated environment variable
|
74
|
+
expect(spyConsoleWarn).toHaveBeenCalledWith(
|
75
|
+
expect.stringMatching(/AUTHELIA_CLIENT_ID.*AUTH_AUTHELIA_ID/),
|
76
|
+
);
|
77
|
+
expect(spyConsoleWarn).toHaveBeenCalledWith(
|
78
|
+
expect.stringMatching(/AUTHELIA_CLIENT_SECRET.*AUTH_AUTHELIA_SECRET/),
|
79
|
+
);
|
80
|
+
expect(spyConsoleWarn).toHaveBeenCalledWith(
|
81
|
+
expect.stringMatching(/AUTHELIA_ISSUER.*AUTH_AUTHELIA_ISSUER/),
|
82
|
+
);
|
83
|
+
});
|
84
|
+
it('should warn about AzureAD deprecated environment variables', () => {
|
85
|
+
// Set all deprecated environment variables
|
86
|
+
process.env.AZURE_AD_CLIENT_ID = 'azure_ad_client_id';
|
87
|
+
process.env.AZURE_AD_CLIENT_SECRET = 'azure_ad_client_secret';
|
88
|
+
process.env.AZURE_AD_TENANT_ID = 'azure_ad_tenant_id';
|
89
|
+
|
90
|
+
// Call the function
|
91
|
+
getAuthConfig();
|
92
|
+
|
93
|
+
// Check that the spyConsoleWarn function was called for each deprecated environment variable
|
94
|
+
expect(spyConsoleWarn).toHaveBeenCalledWith(
|
95
|
+
expect.stringMatching(/AZURE_AD_CLIENT_ID.*AUTH_AZURE_AD_ID/),
|
96
|
+
);
|
97
|
+
expect(spyConsoleWarn).toHaveBeenCalledWith(
|
98
|
+
expect.stringMatching(/AZURE_AD_CLIENT_SECRET.*AUTH_AZURE_AD_SECRET/),
|
99
|
+
);
|
100
|
+
expect(spyConsoleWarn).toHaveBeenCalledWith(
|
101
|
+
expect.stringMatching(/AZURE_AD_TENANT_ID.*AUTH_AZURE_AD_TENANT_ID/),
|
102
|
+
);
|
103
|
+
});
|
104
|
+
it('should warn about Cloudflare Zero Trust deprecated environment variables', () => {
|
105
|
+
// Set all deprecated environment variables
|
106
|
+
process.env.CLOUDFLARE_ZERO_TRUST_CLIENT_ID = 'cloudflare_zero_trust_client_id';
|
107
|
+
process.env.CLOUDFLARE_ZERO_TRUST_CLIENT_SECRET = 'cloudflare_zero_trust_client_secret';
|
108
|
+
process.env.CLOUDFLARE_ZERO_TRUST_ISSUER = 'cloudflare_zero_trust_issuer';
|
109
|
+
|
110
|
+
// Call the function
|
111
|
+
getAuthConfig();
|
112
|
+
|
113
|
+
// Check that the spyConsoleWarn function was called for each deprecated environment variable
|
114
|
+
expect(spyConsoleWarn).toHaveBeenCalledWith(
|
115
|
+
expect.stringMatching(/CLOUDFLARE_ZERO_TRUST_CLIENT_ID.*AUTH_CLOUDFLARE_ZERO_TRUST_ID/),
|
116
|
+
);
|
117
|
+
expect(spyConsoleWarn).toHaveBeenCalledWith(
|
118
|
+
expect.stringMatching(
|
119
|
+
/CLOUDFLARE_ZERO_TRUST_CLIENT_SECRET.*AUTH_CLOUDFLARE_ZERO_TRUST_SECRET/,
|
120
|
+
),
|
121
|
+
);
|
122
|
+
expect(spyConsoleWarn).toHaveBeenCalledWith(
|
123
|
+
expect.stringMatching(/CLOUDFLARE_ZERO_TRUST_ISSUER.*AUTH_CLOUDFLARE_ZERO_TRUST_ISSUER/),
|
124
|
+
);
|
125
|
+
});
|
126
|
+
it('should warn about Generic OIDC deprecated environment variables', () => {
|
127
|
+
// Set all deprecated environment variables
|
128
|
+
process.env.GENERIC_OIDC_CLIENT_ID = 'generic_oidc_client_id';
|
129
|
+
process.env.GENERIC_OIDC_CLIENT_SECRET = 'generic_oidc_client_secret';
|
130
|
+
process.env.GENERIC_OIDC_ISSUER = 'generic_oidc_issuer';
|
131
|
+
// Call the function
|
132
|
+
getAuthConfig();
|
133
|
+
|
134
|
+
// Check that the spyConsoleWarn function was called for each deprecated environment variable
|
135
|
+
expect(spyConsoleWarn).toHaveBeenCalledWith(
|
136
|
+
expect.stringMatching(/GENERIC_OIDC_CLIENT_ID.*AUTH_GENERIC_OIDC_ID/),
|
137
|
+
);
|
138
|
+
expect(spyConsoleWarn).toHaveBeenCalledWith(
|
139
|
+
expect.stringMatching(/GENERIC_OIDC_CLIENT_SECRET.*AUTH_GENERIC_OIDC_SECRET/),
|
140
|
+
);
|
141
|
+
expect(spyConsoleWarn).toHaveBeenCalledWith(
|
142
|
+
expect.stringMatching(/GENERIC_OIDC_ISSUER.*AUTH_GENERIC_OIDC_ISSUER/),
|
143
|
+
);
|
144
|
+
});
|
145
|
+
it('should warn about GitHub deprecated environment variables', () => {
|
146
|
+
// Set all deprecated environment variables
|
147
|
+
process.env.GITHUB_CLIENT_ID = 'github_client_id';
|
148
|
+
process.env.GITHUB_CLIENT_SECRET = 'github_client_secret';
|
149
|
+
// Call the function
|
150
|
+
getAuthConfig();
|
151
|
+
|
152
|
+
// Check that the spyConsoleWarn function was called for each deprecated environment variable
|
153
|
+
expect(spyConsoleWarn).toHaveBeenCalledWith(
|
154
|
+
expect.stringMatching(/GITHUB_CLIENT_ID.*AUTH_GITHUB_ID/),
|
155
|
+
);
|
156
|
+
expect(spyConsoleWarn).toHaveBeenCalledWith(
|
157
|
+
expect.stringMatching(/GITHUB_CLIENT_SECRET.*AUTH_GITHUB_SECRET/),
|
158
|
+
);
|
159
|
+
});
|
160
|
+
it('should warn about Logto deprecated environment variables', () => {
|
161
|
+
// Set all deprecated environment variables
|
162
|
+
process.env.LOGTO_CLIENT_ID = 'logto_client_id';
|
163
|
+
process.env.LOGTO_CLIENT_SECRET = 'logto_client_secret';
|
164
|
+
process.env.LOGTO_ISSUER = 'logto_issuer';
|
165
|
+
// Call the function
|
166
|
+
getAuthConfig();
|
167
|
+
|
168
|
+
// Check that the spyConsoleWarn function was called for each deprecated environment variable
|
169
|
+
expect(spyConsoleWarn).toHaveBeenCalledWith(
|
170
|
+
expect.stringMatching(/LOGTO_CLIENT_ID.*AUTH_LOGTO_ID/),
|
171
|
+
);
|
172
|
+
expect(spyConsoleWarn).toHaveBeenCalledWith(
|
173
|
+
expect.stringMatching(/LOGTO_CLIENT_SECRET.*AUTH_LOGTO_SECRET/),
|
174
|
+
);
|
175
|
+
expect(spyConsoleWarn).toHaveBeenCalledWith(
|
176
|
+
expect.stringMatching(/LOGTO_ISSUER.*AUTH_LOGTO_ISSUER/),
|
177
|
+
);
|
178
|
+
});
|
179
|
+
it('should warn about Zitadel deprecated environment variables', () => {
|
180
|
+
// Set all deprecated environment variables
|
181
|
+
process.env.ZITADEL_CLIENT_ID = 'zitadel_client_id';
|
182
|
+
process.env.ZITADEL_CLIENT_SECRET = 'zitadel_client_secret';
|
183
|
+
process.env.ZITADEL_ISSUER = 'zitadel_issuer';
|
184
|
+
// Call the function
|
185
|
+
getAuthConfig();
|
186
|
+
|
187
|
+
// Check that the spyConsoleWarn function was called for each deprecated environment variable
|
188
|
+
expect(spyConsoleWarn).toHaveBeenCalledWith(
|
189
|
+
expect.stringMatching(/ZITADEL_CLIENT_ID.*AUTH_ZITADEL_ID/),
|
190
|
+
);
|
191
|
+
expect(spyConsoleWarn).toHaveBeenCalledWith(
|
192
|
+
expect.stringMatching(/ZITADEL_CLIENT_SECRET.*AUTH_ZITADEL_SECRET/),
|
193
|
+
);
|
194
|
+
expect(spyConsoleWarn).toHaveBeenCalledWith(
|
195
|
+
expect.stringMatching(/ZITADEL_ISSUER.*AUTH_ZITADEL_ISSUER/),
|
196
|
+
);
|
197
|
+
});
|
198
|
+
});
|
199
|
+
// Remove end
|
200
|
+
});
|
package/src/config/auth.ts
CHANGED
@@ -42,7 +42,102 @@ declare global {
|
|
42
42
|
}
|
43
43
|
}
|
44
44
|
|
45
|
+
// TODO(NextAuth ENVs Migration): Remove once nextauth envs migration time end
|
46
|
+
const removeTipsTemplate = (willBeRemoved: string, replaceOne: string) =>
|
47
|
+
`${willBeRemoved} will be removed in the future. Please set ${replaceOne} instead.`;
|
48
|
+
// End
|
49
|
+
|
45
50
|
export const getAuthConfig = () => {
|
51
|
+
// TODO(NextAuth ENVs Migration): Remove once nextauth envs migration time end
|
52
|
+
if (process.env.AUTH0_CLIENT_ID) {
|
53
|
+
console.warn(removeTipsTemplate('AUTH0_CLIENT_ID', 'AUTH_AUTH0_ID'));
|
54
|
+
}
|
55
|
+
if (process.env.AUTH0_CLIENT_SECRET) {
|
56
|
+
console.warn(removeTipsTemplate('AUTH0_CLIENT_SECRET', 'AUTH_AUTH0_SECRET'));
|
57
|
+
}
|
58
|
+
if (process.env.AUTH0_ISSUER) {
|
59
|
+
console.warn(removeTipsTemplate('AUTH0_ISSUER', 'AUTH_AUTH0_ISSUER'));
|
60
|
+
}
|
61
|
+
if (process.env.AUTHENTIK_CLIENT_ID) {
|
62
|
+
console.warn(removeTipsTemplate('AUTHENTIK_CLIENT_ID', 'AUTH_AUTHENTIK_ID'));
|
63
|
+
}
|
64
|
+
if (process.env.AUTHENTIK_CLIENT_SECRET) {
|
65
|
+
console.warn(removeTipsTemplate('AUTHENTIK_CLIENT_SECRET', 'AUTH_AUTHENTIK_SECRET'));
|
66
|
+
}
|
67
|
+
if (process.env.AUTHENTIK_ISSUER) {
|
68
|
+
console.warn(removeTipsTemplate('AUTHENTIK_ISSUER', 'AUTH_AUTHENTIK_ISSUER'));
|
69
|
+
}
|
70
|
+
if (process.env.AUTHELIA_CLIENT_ID) {
|
71
|
+
console.warn(removeTipsTemplate('AUTHELIA_CLIENT_ID', 'AUTH_AUTHELIA_ID'));
|
72
|
+
}
|
73
|
+
if (process.env.AUTHELIA_CLIENT_SECRET) {
|
74
|
+
console.warn(removeTipsTemplate('AUTHELIA_CLIENT_SECRET', 'AUTH_AUTHELIA_SECRET'));
|
75
|
+
}
|
76
|
+
if (process.env.AUTHELIA_ISSUER) {
|
77
|
+
console.warn(removeTipsTemplate('AUTHELIA_ISSUER', 'AUTH_AUTHELIA_ISSUER'));
|
78
|
+
}
|
79
|
+
if (process.env.AZURE_AD_CLIENT_ID) {
|
80
|
+
console.warn(removeTipsTemplate('AZURE_AD_CLIENT_ID', 'AUTH_AZURE_AD_ID'));
|
81
|
+
}
|
82
|
+
if (process.env.AZURE_AD_CLIENT_SECRET) {
|
83
|
+
console.warn(removeTipsTemplate('AZURE_AD_CLIENT_SECRET', 'AUTH_AZURE_AD_SECRET'));
|
84
|
+
}
|
85
|
+
if (process.env.AZURE_AD_TENANT_ID) {
|
86
|
+
console.warn(removeTipsTemplate('AZURE_AD_TENANT_ID', 'AUTH_AZURE_AD_TENANT_ID'));
|
87
|
+
}
|
88
|
+
if (process.env.CLOUDFLARE_ZERO_TRUST_CLIENT_ID) {
|
89
|
+
console.warn(
|
90
|
+
removeTipsTemplate('CLOUDFLARE_ZERO_TRUST_CLIENT_ID', 'AUTH_CLOUDFLARE_ZERO_TRUST_ID'),
|
91
|
+
);
|
92
|
+
}
|
93
|
+
if (process.env.CLOUDFLARE_ZERO_TRUST_CLIENT_SECRET) {
|
94
|
+
console.warn(
|
95
|
+
removeTipsTemplate(
|
96
|
+
'CLOUDFLARE_ZERO_TRUST_CLIENT_SECRET',
|
97
|
+
'AUTH_CLOUDFLARE_ZERO_TRUST_SECRET',
|
98
|
+
),
|
99
|
+
);
|
100
|
+
}
|
101
|
+
if (process.env.CLOUDFLARE_ZERO_TRUST_ISSUER) {
|
102
|
+
console.warn(
|
103
|
+
removeTipsTemplate('CLOUDFLARE_ZERO_TRUST_ISSUER', 'AUTH_CLOUDFLARE_ZERO_TRUST_ISSUER'),
|
104
|
+
);
|
105
|
+
}
|
106
|
+
if (process.env.GENERIC_OIDC_CLIENT_ID) {
|
107
|
+
console.warn(removeTipsTemplate('GENERIC_OIDC_CLIENT_ID', 'AUTH_GENERIC_OIDC_ID'));
|
108
|
+
}
|
109
|
+
if (process.env.GENERIC_OIDC_CLIENT_SECRET) {
|
110
|
+
console.warn(removeTipsTemplate('GENERIC_OIDC_CLIENT_SECRET', 'AUTH_GENERIC_OIDC_SECRET'));
|
111
|
+
}
|
112
|
+
if (process.env.GENERIC_OIDC_ISSUER) {
|
113
|
+
console.warn(removeTipsTemplate('GENERIC_OIDC_ISSUER', 'AUTH_GENERIC_OIDC_ISSUER'));
|
114
|
+
}
|
115
|
+
if (process.env.GITHUB_CLIENT_ID) {
|
116
|
+
console.warn(removeTipsTemplate('GITHUB_CLIENT_ID', 'AUTH_GITHUB_ID'));
|
117
|
+
}
|
118
|
+
if (process.env.GITHUB_CLIENT_SECRET) {
|
119
|
+
console.warn(removeTipsTemplate('GITHUB_CLIENT_SECRET', 'AUTH_GITHUB_SECRET'));
|
120
|
+
}
|
121
|
+
if (process.env.LOGTO_CLIENT_ID) {
|
122
|
+
console.warn(removeTipsTemplate('LOGTO_CLIENT_ID', 'AUTH_LOGTO_ID'));
|
123
|
+
}
|
124
|
+
if (process.env.LOGTO_CLIENT_SECRET) {
|
125
|
+
console.warn(removeTipsTemplate('LOGTO_CLIENT_SECRET', 'AUTH_LOGTO_SECRET'));
|
126
|
+
}
|
127
|
+
if (process.env.LOGTO_ISSUER) {
|
128
|
+
console.warn(removeTipsTemplate('LOGTO_ISSUER', 'AUTH_LOGTO_ISSUER'));
|
129
|
+
}
|
130
|
+
if (process.env.ZITADEL_CLIENT_ID) {
|
131
|
+
console.warn(removeTipsTemplate('ZITADEL_CLIENT_ID', 'AUTH_ZITADEL_ID'));
|
132
|
+
}
|
133
|
+
if (process.env.ZITADEL_CLIENT_SECRET) {
|
134
|
+
console.warn(removeTipsTemplate('ZITADEL_CLIENT_SECRET', 'AUTH_ZITADEL_SECRET'));
|
135
|
+
}
|
136
|
+
if (process.env.ZITADEL_ISSUER) {
|
137
|
+
console.warn(removeTipsTemplate('ZITADEL_ISSUER', 'AUTH_ZITADEL_ISSUER'));
|
138
|
+
}
|
139
|
+
// End
|
140
|
+
|
46
141
|
return createEnv({
|
47
142
|
client: {
|
48
143
|
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: z.string().optional(),
|
@@ -95,7 +190,7 @@ export const getAuthConfig = () => {
|
|
95
190
|
GENERIC_OIDC_CLIENT_ID: z.string().optional(),
|
96
191
|
GENERIC_OIDC_CLIENT_SECRET: z.string().optional(),
|
97
192
|
GENERIC_OIDC_ISSUER: z.string().optional(),
|
98
|
-
|
193
|
+
|
99
194
|
// ZITADEL
|
100
195
|
ZITADEL_CLIENT_ID: z.string().optional(),
|
101
196
|
ZITADEL_CLIENT_SECRET: z.string().optional(),
|
@@ -105,6 +200,7 @@ export const getAuthConfig = () => {
|
|
105
200
|
LOGTO_CLIENT_ID: z.string().optional(),
|
106
201
|
LOGTO_CLIENT_SECRET: z.string().optional(),
|
107
202
|
LOGTO_ISSUER: z.string().optional(),
|
203
|
+
LOGTO_WEBHOOK_SIGNING_KEY: z.string().optional(),
|
108
204
|
},
|
109
205
|
|
110
206
|
runtimeEnv: {
|
@@ -152,7 +248,7 @@ export const getAuthConfig = () => {
|
|
152
248
|
GENERIC_OIDC_CLIENT_ID: process.env.GENERIC_OIDC_CLIENT_ID,
|
153
249
|
GENERIC_OIDC_CLIENT_SECRET: process.env.GENERIC_OIDC_CLIENT_SECRET,
|
154
250
|
GENERIC_OIDC_ISSUER: process.env.GENERIC_OIDC_ISSUER,
|
155
|
-
|
251
|
+
|
156
252
|
// ZITADEL
|
157
253
|
ZITADEL_CLIENT_ID: process.env.ZITADEL_CLIENT_ID,
|
158
254
|
ZITADEL_CLIENT_SECRET: process.env.ZITADEL_CLIENT_SECRET,
|
@@ -162,6 +258,7 @@ export const getAuthConfig = () => {
|
|
162
258
|
LOGTO_CLIENT_ID: process.env.LOGTO_CLIENT_ID,
|
163
259
|
LOGTO_CLIENT_SECRET: process.env.LOGTO_CLIENT_SECRET,
|
164
260
|
LOGTO_ISSUER: process.env.LOGTO_ISSUER,
|
261
|
+
LOGTO_WEBHOOK_SIGNING_KEY: process.env.LOGTO_WEBHOOK_SIGNING_KEY,
|
165
262
|
},
|
166
263
|
});
|
167
264
|
};
|
@@ -40,6 +40,20 @@ const Bedrock: ModelProviderCard = {
|
|
40
40
|
tokens: 200_000,
|
41
41
|
vision: true,
|
42
42
|
},
|
43
|
+
{
|
44
|
+
description:
|
45
|
+
'Claude 3 Haiku 是 Anthropic 最快、最紧凑的模型,提供近乎即时的响应速度。它可以快速回答简单的查询和请求。客户将能够构建模仿人类互动的无缝 AI 体验。Claude 3 Haiku 可以处理图像并返回文本输出,具有 200K 的上下文窗口。',
|
46
|
+
displayName: 'Claude 3 Haiku',
|
47
|
+
enabled: true,
|
48
|
+
functionCall: true,
|
49
|
+
id: 'anthropic.claude-3-haiku-20240307-v1:0',
|
50
|
+
pricing: {
|
51
|
+
input: 0.25,
|
52
|
+
output: 1.25,
|
53
|
+
},
|
54
|
+
tokens: 200_000,
|
55
|
+
vision: true,
|
56
|
+
},
|
43
57
|
{
|
44
58
|
description:
|
45
59
|
'Anthropic 的 Claude 3 Sonnet 在智能和速度之间达到了理想的平衡——特别适合企业工作负载。它以低于竞争对手的价格提供最大的效用,并被设计成为可靠的、高耐用的主力机,适用于规模化的 AI 部署。Claude 3 Sonnet 可以处理图像并返回文本输出,具有 200K 的上下文窗口。',
|
@@ -68,20 +82,6 @@ const Bedrock: ModelProviderCard = {
|
|
68
82
|
tokens: 200_000,
|
69
83
|
vision: true,
|
70
84
|
},
|
71
|
-
{
|
72
|
-
description:
|
73
|
-
'Claude 3 Haiku 是 Anthropic 最快、最紧凑的模型,提供近乎即时的响应速度。它可以快速回答简单的查询和请求。客户将能够构建模仿人类互动的无缝 AI 体验。Claude 3 Haiku 可以处理图像并返回文本输出,具有 200K 的上下文窗口。',
|
74
|
-
displayName: 'Claude 3 Haiku',
|
75
|
-
enabled: true,
|
76
|
-
functionCall: true,
|
77
|
-
id: 'anthropic.claude-3-haiku-20240307-v1:0',
|
78
|
-
pricing: {
|
79
|
-
input: 0.25,
|
80
|
-
output: 1.25,
|
81
|
-
},
|
82
|
-
tokens: 200_000,
|
83
|
-
vision: true,
|
84
|
-
},
|
85
85
|
{
|
86
86
|
description:
|
87
87
|
'Claude 2 的更新版,具有双倍的上下文窗口,以及在长文档和 RAG 上下文中的可靠性、幻觉率和基于证据的准确性的改进。',
|
@@ -8,7 +8,6 @@ const Mistral: ModelProviderCard = {
|
|
8
8
|
description:
|
9
9
|
'Mistral 7B是一款紧凑但高性能的模型,擅长批量处理和简单任务,如分类和文本生成,具有良好的推理能力。',
|
10
10
|
displayName: 'Mistral 7B',
|
11
|
-
enabled: true,
|
12
11
|
id: 'open-mistral-7b',
|
13
12
|
tokens: 32_768,
|
14
13
|
},
|
@@ -16,7 +15,6 @@ const Mistral: ModelProviderCard = {
|
|
16
15
|
description:
|
17
16
|
'Mixtral 8x7B是一个稀疏专家模型,利用多个参数提高推理速度,适合处理多语言和代码生成任务。',
|
18
17
|
displayName: 'Mixtral 8x7B',
|
19
|
-
enabled: true,
|
20
18
|
id: 'open-mixtral-8x7b',
|
21
19
|
tokens: 32_768,
|
22
20
|
},
|
@@ -57,7 +55,6 @@ const Mistral: ModelProviderCard = {
|
|
57
55
|
description:
|
58
56
|
'Codestral Mamba是专注于代码生成的Mamba 2语言模型,为先进的代码和推理任务提供强力支持。',
|
59
57
|
displayName: 'Codestral Mamba',
|
60
|
-
enabled: true,
|
61
58
|
id: 'open-codestral-mamba',
|
62
59
|
tokens: 256_000,
|
63
60
|
},
|
@@ -161,13 +161,11 @@ describe('LobeQwenAI', () => {
|
|
161
161
|
vi.spyOn(instance['client'].chat.completions, 'create').mockResolvedValue(
|
162
162
|
new ReadableStream() as any,
|
163
163
|
);
|
164
|
-
|
165
164
|
await instance.chat({
|
166
165
|
messages: [{ content: 'Hello', role: 'user' }],
|
167
166
|
model: 'qwen-turbo',
|
168
167
|
temperature: temp,
|
169
168
|
});
|
170
|
-
|
171
169
|
expect(instance['client'].chat.completions.create).toHaveBeenCalledWith(
|
172
170
|
expect.objectContaining({
|
173
171
|
messages: expect.any(Array),
|
@@ -183,13 +181,11 @@ describe('LobeQwenAI', () => {
|
|
183
181
|
vi.spyOn(instance['client'].chat.completions, 'create').mockResolvedValue(
|
184
182
|
new ReadableStream() as any,
|
185
183
|
);
|
186
|
-
|
187
184
|
await instance.chat({
|
188
185
|
messages: [{ content: 'Hello', role: 'user' }],
|
189
186
|
model: 'qwen-turbo',
|
190
187
|
temperature: 1.5,
|
191
188
|
});
|
192
|
-
|
193
189
|
expect(instance['client'].chat.completions.create).toHaveBeenCalledWith(
|
194
190
|
expect.objectContaining({
|
195
191
|
messages: expect.any(Array),
|
@@ -199,6 +195,26 @@ describe('LobeQwenAI', () => {
|
|
199
195
|
expect.any(Object),
|
200
196
|
);
|
201
197
|
});
|
198
|
+
|
199
|
+
it('should set temperature to Float', async () => {
|
200
|
+
const createMock = vi.fn().mockResolvedValue(new ReadableStream() as any);
|
201
|
+
vi.spyOn(instance['client'].chat.completions, 'create').mockImplementation(createMock);
|
202
|
+
await instance.chat({
|
203
|
+
messages: [{ content: 'Hello', role: 'user' }],
|
204
|
+
model: 'qwen-turbo',
|
205
|
+
temperature: 1,
|
206
|
+
});
|
207
|
+
expect(instance['client'].chat.completions.create).toHaveBeenCalledWith(
|
208
|
+
expect.objectContaining({
|
209
|
+
messages: expect.any(Array),
|
210
|
+
model: 'qwen-turbo',
|
211
|
+
temperature: expect.any(Number),
|
212
|
+
}),
|
213
|
+
expect.any(Object),
|
214
|
+
);
|
215
|
+
const callArgs = createMock.mock.calls[0][0];
|
216
|
+
expect(Number.isInteger(callArgs.temperature)).toBe(false); // Temperature is always not an integer
|
217
|
+
});
|
202
218
|
});
|
203
219
|
|
204
220
|
describe('Error', () => {
|
@@ -111,7 +111,7 @@ export class LobeQwenAI implements LobeRuntimeAI {
|
|
111
111
|
temperature:
|
112
112
|
temperature === 0 || temperature >= 2
|
113
113
|
? undefined
|
114
|
-
: temperature,
|
114
|
+
: (temperature === 1 ? 0.999 : temperature), // 'temperature' must be Float
|
115
115
|
top_p: top_p && top_p >= 1 ? 0.999 : top_p,
|
116
116
|
};
|
117
117
|
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import type { NextAuthConfig } from 'next-auth';
|
2
|
+
import urlJoin from 'url-join';
|
2
3
|
|
3
4
|
import { authEnv } from '@/config/auth';
|
4
5
|
|
@@ -40,6 +41,7 @@ export default {
|
|
40
41
|
},
|
41
42
|
},
|
42
43
|
providers: initSSOProviders(),
|
44
|
+
redirectProxyUrl: process.env.APP_URL ? urlJoin(process.env.APP_URL, '/api/auth') : undefined,
|
43
45
|
secret: authEnv.NEXT_AUTH_SECRET,
|
44
|
-
trustHost: true,
|
46
|
+
trustHost: process.env?.AUTH_TRUST_HOST ? process.env.AUTH_TRUST_HOST === 'true' : true,
|
45
47
|
} satisfies NextAuthConfig;
|
@@ -11,9 +11,11 @@ const provider = {
|
|
11
11
|
// Specify auth scope, at least include 'openid email'
|
12
12
|
// all scopes in Auth0 ref: https://auth0.com/docs/get-started/apis/scopes/openid-connect-scopes#standard-claims
|
13
13
|
authorization: { params: { scope: 'openid email profile' } },
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
// TODO(NextAuth ENVs Migration): Remove once nextauth envs migration time end
|
15
|
+
clientId: authEnv.AUTH0_CLIENT_ID ?? process.env.AUTH_AUTH0_ID,
|
16
|
+
clientSecret: authEnv.AUTH0_CLIENT_SECRET ?? process.env.AUTH_AUTH0_SECRET,
|
17
|
+
issuer: authEnv.AUTH0_ISSUER ?? process.env.AUTH_AUTH0_ISSUER,
|
18
|
+
// Remove End
|
17
19
|
profile(profile) {
|
18
20
|
return {
|
19
21
|
email: profile.email,
|
@@ -6,11 +6,11 @@ import { CommonProviderConfig } from './sso.config';
|
|
6
6
|
|
7
7
|
export type AutheliaProfile = {
|
8
8
|
// The users display name
|
9
|
-
email: string;
|
9
|
+
email: string;
|
10
10
|
// The users email
|
11
|
-
groups: string[];
|
11
|
+
groups: string[];
|
12
12
|
// The username the user used to login with
|
13
|
-
name: string;
|
13
|
+
name: string;
|
14
14
|
preferred_username: string; // The users groups
|
15
15
|
sub: string; // The users id
|
16
16
|
};
|
@@ -21,10 +21,10 @@ const provider = {
|
|
21
21
|
...CommonProviderConfig,
|
22
22
|
authorization: { params: { scope: 'openid email profile' } },
|
23
23
|
checks: ['state', 'pkce'],
|
24
|
-
clientId: authEnv.AUTHELIA_CLIENT_ID,
|
25
|
-
clientSecret: authEnv.AUTHELIA_CLIENT_SECRET,
|
24
|
+
clientId: authEnv.AUTHELIA_CLIENT_ID ?? process.env.AUTH_AUTHELIA_ID,
|
25
|
+
clientSecret: authEnv.AUTHELIA_CLIENT_SECRET ?? process.env.AUTH_AUTHELIA_SECRET,
|
26
26
|
id: 'authelia',
|
27
|
-
issuer: authEnv.AUTHELIA_ISSUER,
|
27
|
+
issuer: authEnv.AUTHELIA_ISSUER ?? process.env.AUTH_AUTHELIA_ISSUER,
|
28
28
|
name: 'Authelia',
|
29
29
|
profile(profile) {
|
30
30
|
return {
|
@@ -11,9 +11,11 @@ const provider = {
|
|
11
11
|
// Specify auth scope, at least include 'openid email'
|
12
12
|
// all scopes in Authentik ref: https://goauthentik.io/docs/providers/oauth2
|
13
13
|
authorization: { params: { scope: 'openid email profile' } },
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
// TODO(NextAuth ENVs Migration): Remove once nextauth envs migration time end
|
15
|
+
clientId: authEnv.AUTHENTIK_CLIENT_ID ?? process.env.AUTH_AUTHENTIK_ID,
|
16
|
+
clientSecret: authEnv.AUTHENTIK_CLIENT_SECRET ?? process.env.AUTH_AUTHENTIK_SECRET,
|
17
|
+
issuer: authEnv.AUTHENTIK_ISSUER ?? process.env.AUTH_AUTHENTIK_ISSUER,
|
18
|
+
// Remove end
|
17
19
|
// TODO(NextAuth): map unique user id to `providerAccountId` field
|
18
20
|
// profile(profile) {
|
19
21
|
// return {
|
@@ -11,9 +11,11 @@ const provider = {
|
|
11
11
|
// Specify auth scope, at least include 'openid email'
|
12
12
|
// all scopes in Azure AD ref: https://learn.microsoft.com/en-us/entra/identity-platform/scopes-oidc#openid-connect-scopes
|
13
13
|
authorization: { params: { scope: 'openid email profile' } },
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
// TODO(NextAuth ENVs Migration): Remove once nextauth envs migration time end
|
15
|
+
clientId: authEnv.AZURE_AD_CLIENT_ID ?? process.env.AUTH_AZURE_AD_ID,
|
16
|
+
clientSecret: authEnv.AZURE_AD_CLIENT_SECRET ?? process.env.AUTH_AZURE_AD_SECRET,
|
17
|
+
tenantId: authEnv.AZURE_AD_TENANT_ID ?? process.env.AUTH_AZURE_AD_TENANT_ID,
|
18
|
+
// Remove end
|
17
19
|
// TODO(NextAuth): map unique user id to `providerAccountId` field
|
18
20
|
// profile(profile) {
|
19
21
|
// return {
|
@@ -16,10 +16,11 @@ const provider = {
|
|
16
16
|
...CommonProviderConfig,
|
17
17
|
authorization: { params: { scope: 'openid email profile' } },
|
18
18
|
checks: ['state', 'pkce'],
|
19
|
-
clientId: authEnv.CLOUDFLARE_ZERO_TRUST_CLIENT_ID,
|
20
|
-
clientSecret:
|
19
|
+
clientId: authEnv.CLOUDFLARE_ZERO_TRUST_CLIENT_ID ?? process.env.AUTH_CLOUDFLARE_ZERO_TRUST_ID,
|
20
|
+
clientSecret:
|
21
|
+
authEnv.CLOUDFLARE_ZERO_TRUST_CLIENT_SECRET ?? process.env.AUTH_CLOUDFLARE_ZERO_TRUST_SECRET,
|
21
22
|
id: 'cloudflare-zero-trust',
|
22
|
-
issuer: authEnv.CLOUDFLARE_ZERO_TRUST_ISSUER,
|
23
|
+
issuer: authEnv.CLOUDFLARE_ZERO_TRUST_ISSUER ?? process.env.AUTH_CLOUDFLARE_ZERO_TRUST_ISSUER,
|
23
24
|
name: 'Cloudflare Zero Trust',
|
24
25
|
profile(profile) {
|
25
26
|
return {
|
@@ -19,10 +19,10 @@ const provider = {
|
|
19
19
|
...CommonProviderConfig,
|
20
20
|
authorization: { params: { scope: 'email openid profile' } },
|
21
21
|
checks: ['state', 'pkce'],
|
22
|
-
clientId: authEnv.GENERIC_OIDC_CLIENT_ID,
|
23
|
-
clientSecret: authEnv.GENERIC_OIDC_CLIENT_SECRET,
|
22
|
+
clientId: authEnv.GENERIC_OIDC_CLIENT_ID ?? process.env.AUTH_GENERIC_OIDC_ID,
|
23
|
+
clientSecret: authEnv.GENERIC_OIDC_CLIENT_SECRET ?? process.env.AUTH_GENERIC_OIDC_SECRET,
|
24
24
|
id: 'generic-oidc',
|
25
|
-
issuer: authEnv.GENERIC_OIDC_ISSUER,
|
25
|
+
issuer: authEnv.GENERIC_OIDC_ISSUER ?? process.env.AUTH_GENERIC_OIDC_ISSUER,
|
26
26
|
name: 'Generic OIDC',
|
27
27
|
profile(profile) {
|
28
28
|
return {
|
@@ -10,8 +10,10 @@ const provider = {
|
|
10
10
|
...CommonProviderConfig,
|
11
11
|
// Specify auth scope, at least include 'openid email'
|
12
12
|
authorization: { params: { scope: 'read:user user:email' } },
|
13
|
-
|
14
|
-
|
13
|
+
// TODO(NextAuth ENVs Migration): Remove once nextauth envs migration time end
|
14
|
+
clientId: authEnv.GITHUB_CLIENT_ID ?? process.env.AUTH_GITHUB_ID,
|
15
|
+
clientSecret: authEnv.GITHUB_CLIENT_SECRET ?? process.env.AUTH_GITHUB_SECRET,
|
16
|
+
// Remove end
|
15
17
|
profile: (profile) => {
|
16
18
|
return {
|
17
19
|
email: profile.email,
|
@@ -41,9 +41,9 @@ const provider = {
|
|
41
41
|
},
|
42
42
|
// You can get the issuer value from the Logto Application Details page,
|
43
43
|
// in the field "Issuer endpoint"
|
44
|
-
clientId: authEnv.LOGTO_CLIENT_ID,
|
45
|
-
clientSecret: authEnv.LOGTO_CLIENT_SECRET,
|
46
|
-
issuer: authEnv.LOGTO_ISSUER,
|
44
|
+
clientId: authEnv.LOGTO_CLIENT_ID ?? process.env.AUTH_LOGTO_ID,
|
45
|
+
clientSecret: authEnv.LOGTO_CLIENT_SECRET ?? process.env.AUTH_LOGTO_SECRET,
|
46
|
+
issuer: authEnv.LOGTO_ISSUER ?? process.env.AUTH_LOGTO_ISSUER,
|
47
47
|
}),
|
48
48
|
};
|
49
49
|
|
@@ -7,9 +7,11 @@ const provider = {
|
|
7
7
|
provider: Zitadel({
|
8
8
|
// Available scopes in ZITADEL: https://zitadel.com/docs/apis/openidoauth/scopes
|
9
9
|
authorization: { params: { scope: 'openid email profile' } },
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
// TODO(NextAuth ENVs Migration): Remove once nextauth envs migration time end
|
11
|
+
clientId: authEnv.ZITADEL_CLIENT_ID ?? process.env.AUTH_ZITADEL_ID,
|
12
|
+
clientSecret: authEnv.ZITADEL_CLIENT_SECRET ?? process.env.AUTH_ZITADEL_SECRET,
|
13
|
+
issuer: authEnv.ZITADEL_ISSUER ?? process.env.AUTH_ZITADEL_ISSUER,
|
14
|
+
// Remove end
|
13
15
|
// TODO(NextAuth): map unique user id to `providerAccountId` field
|
14
16
|
// profile(profile) {
|
15
17
|
// return {
|
@@ -0,0 +1,42 @@
|
|
1
|
+
import { NextResponse } from 'next/server';
|
2
|
+
|
3
|
+
import { serverDB } from '@/database/server';
|
4
|
+
import { UserModel } from '@/database/server/models/user';
|
5
|
+
import { UserItem } from '@/database/server/schemas/lobechat';
|
6
|
+
import { pino } from '@/libs/logger';
|
7
|
+
import { LobeNextAuthDbAdapter } from '@/libs/next-auth/adapter';
|
8
|
+
|
9
|
+
export class NextAuthUserService {
|
10
|
+
userModel;
|
11
|
+
adapter;
|
12
|
+
|
13
|
+
constructor() {
|
14
|
+
this.userModel = new UserModel();
|
15
|
+
this.adapter = LobeNextAuthDbAdapter(serverDB);
|
16
|
+
}
|
17
|
+
|
18
|
+
safeUpdateUser = async (providerAccountId: string, data: Partial<UserItem>) => {
|
19
|
+
pino.info('updating user due to webhook');
|
20
|
+
// 1. Find User by account
|
21
|
+
// @ts-expect-error: Already impl in `LobeNextauthDbAdapter`
|
22
|
+
const user = await this.adapter.getUserByAccount({
|
23
|
+
provider: 'logto',
|
24
|
+
providerAccountId,
|
25
|
+
});
|
26
|
+
|
27
|
+
// 2. If found, Update user data from provider
|
28
|
+
if (user?.id) {
|
29
|
+
// Perform update
|
30
|
+
await this.userModel.updateUser(user.id, {
|
31
|
+
avatar: data?.avatar,
|
32
|
+
email: data?.email,
|
33
|
+
fullName: data?.fullName,
|
34
|
+
});
|
35
|
+
} else {
|
36
|
+
pino.warn(
|
37
|
+
`[logto]: Webhooks handler user update for "${JSON.stringify(data)}", but no user was found by the providerAccountId.`,
|
38
|
+
);
|
39
|
+
}
|
40
|
+
return NextResponse.json({ message: 'user updated', success: true }, { status: 200 });
|
41
|
+
};
|
42
|
+
}
|