@lobehub/chat 1.105.0 → 1.105.2
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.
- package/CHANGELOG.md +60 -0
- package/changelog/v1.json +18 -0
- package/locales/ar/auth.json +54 -0
- package/locales/bg-BG/auth.json +54 -0
- package/locales/de-DE/auth.json +54 -0
- package/locales/en-US/auth.json +54 -0
- package/locales/es-ES/auth.json +54 -0
- package/locales/fa-IR/auth.json +54 -0
- package/locales/fr-FR/auth.json +54 -0
- package/locales/it-IT/auth.json +54 -0
- package/locales/ja-JP/auth.json +54 -0
- package/locales/ko-KR/auth.json +54 -0
- package/locales/nl-NL/auth.json +54 -0
- package/locales/pl-PL/auth.json +54 -0
- package/locales/pt-BR/auth.json +54 -0
- package/locales/ru-RU/auth.json +54 -0
- package/locales/tr-TR/auth.json +54 -0
- package/locales/vi-VN/auth.json +54 -0
- package/locales/zh-CN/auth.json +54 -0
- package/locales/zh-TW/auth.json +54 -0
- package/package.json +2 -2
- package/src/app/(backend)/middleware/auth/index.test.ts +5 -5
- package/src/app/(backend)/middleware/auth/index.ts +6 -6
- package/src/app/(backend)/webapi/chat/[provider]/route.test.ts +11 -9
- package/src/app/(backend)/webapi/plugin/gateway/route.ts +2 -2
- package/src/app/sitemap.tsx +1 -10
- package/src/config/aiModels/giteeai.ts +269 -2
- package/src/config/aiModels/qwen.ts +207 -2
- package/src/config/aiModels/siliconcloud.ts +24 -2
- package/src/config/aiModels/stepfun.ts +67 -2
- package/src/config/aiModels/volcengine.ts +56 -2
- package/src/config/aiModels/wenxin.ts +62 -2
- package/src/config/aiModels/xai.ts +19 -2
- package/src/const/auth.ts +2 -3
- package/src/libs/model-runtime/ModelRuntime.test.ts +3 -3
- package/src/libs/model-runtime/qwen/createImage.ts +29 -9
- package/src/libs/trpc/async/context.ts +3 -3
- package/src/libs/trpc/edge/context.ts +7 -2
- package/src/libs/trpc/edge/middleware/jwtPayload.test.ts +4 -4
- package/src/libs/trpc/edge/middleware/jwtPayload.ts +2 -2
- package/src/libs/trpc/lambda/context.ts +2 -2
- package/src/libs/trpc/lambda/middleware/keyVaults.ts +2 -2
- package/src/server/modules/AgentRuntime/index.test.ts +28 -25
- package/src/server/modules/AgentRuntime/index.ts +3 -3
- package/src/server/routers/async/caller.ts +2 -2
- package/src/server/routers/lambda/market/index.ts +0 -14
- package/src/server/routers/tools/search.test.ts +2 -2
- package/src/server/services/chunk/index.ts +3 -3
- package/src/server/services/discover/index.ts +0 -13
- package/src/server/sitemap.test.ts +0 -52
- package/src/server/sitemap.ts +1 -38
- package/src/services/_auth.ts +3 -3
- package/src/services/discover.ts +0 -4
- package/src/store/discover/slices/mcp/action.ts +0 -8
- package/src/utils/client/xor-obfuscation.test.ts +370 -0
- package/src/utils/client/xor-obfuscation.ts +39 -0
- package/src/utils/server/xor.test.ts +123 -0
- package/src/utils/server/xor.ts +42 -0
- package/src/utils/jwt.test.ts +0 -27
- package/src/utils/jwt.ts +0 -37
- package/src/utils/server/jwt.test.ts +0 -62
- package/src/utils/server/jwt.ts +0 -28
@@ -1,4 +1,4 @@
|
|
1
|
-
import { AIChatModelCard } from '@/types/aiModel';
|
1
|
+
import { AIChatModelCard, AIImageModelCard } from '@/types/aiModel';
|
2
2
|
|
3
3
|
// https://siliconflow.cn/zh-cn/models
|
4
4
|
const siliconcloudChatModels: AIChatModelCard[] = [
|
@@ -830,6 +830,28 @@ const siliconcloudChatModels: AIChatModelCard[] = [
|
|
830
830
|
},
|
831
831
|
];
|
832
832
|
|
833
|
-
|
833
|
+
const siliconcloudImageModels: AIImageModelCard[] = [
|
834
|
+
{
|
835
|
+
description:
|
836
|
+
'Kolors 是由快手 Kolors 团队开发的基于潜在扩散的大规模文本到图像生成模型。该模型通过数十亿文本-图像对的训练,在视觉质量、复杂语义准确性以及中英文字符渲染方面展现出显著优势。它不仅支持中英文输入,在理解和生成中文特定内容方面也表现出色',
|
837
|
+
displayName: 'Kolors',
|
838
|
+
enabled: true,
|
839
|
+
id: 'Kwai-Kolors/Kolors',
|
840
|
+
parameters: {
|
841
|
+
prompt: {
|
842
|
+
default: '',
|
843
|
+
},
|
844
|
+
seed: { default: null },
|
845
|
+
size: {
|
846
|
+
default: '1024x1024',
|
847
|
+
enum: ['1024x1024', '960x1280', '768x1024', '720x1440', '720x1280'],
|
848
|
+
},
|
849
|
+
},
|
850
|
+
releasedAt: '2024-07-06',
|
851
|
+
type: 'image',
|
852
|
+
},
|
853
|
+
];
|
854
|
+
|
855
|
+
export const allModels = [...siliconcloudChatModels, ...siliconcloudImageModels];
|
834
856
|
|
835
857
|
export default allModels;
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { AIChatModelCard } from '@/types/aiModel';
|
1
|
+
import { AIChatModelCard, AIImageModelCard } from '@/types/aiModel';
|
2
2
|
|
3
3
|
// https://platform.stepfun.com/docs/pricing/details
|
4
4
|
|
@@ -275,6 +275,71 @@ const stepfunChatModels: AIChatModelCard[] = [
|
|
275
275
|
},
|
276
276
|
];
|
277
277
|
|
278
|
-
|
278
|
+
const stepfunImageModels: AIImageModelCard[] = [
|
279
|
+
// https://platform.stepfun.com/docs/llm/image
|
280
|
+
{
|
281
|
+
description:
|
282
|
+
'阶跃星辰新一代生图模型,该模型专注于图像生成任务,能够根据用户提供的文本描述,生成高质量的图像。新模型生成图片质感更真实,中英文文字生成能力更强。',
|
283
|
+
displayName: 'Step 2X Large',
|
284
|
+
enabled: true,
|
285
|
+
id: 'step-2x-large',
|
286
|
+
parameters: {
|
287
|
+
prompt: {
|
288
|
+
default: '',
|
289
|
+
},
|
290
|
+
seed: { default: null },
|
291
|
+
size: {
|
292
|
+
default: '1024x1024',
|
293
|
+
enum: ['256x256', '512x512', '768x768', '1024x1024', '1280x800', '800x1280'],
|
294
|
+
},
|
295
|
+
steps: { default: 50, max: 100, min: 1 },
|
296
|
+
},
|
297
|
+
releasedAt: '2024-08-07',
|
298
|
+
type: 'image',
|
299
|
+
},
|
300
|
+
{
|
301
|
+
description:
|
302
|
+
'该模型拥有强大的图像生成能力,支持文本描述作为输入方式。具备原生的中文支持,能够更好的理解和处理中文文本描述,并且能够更准确地捕捉文本描述中的语义信息,并将其转化为图像特征,从而实现更精准的图像生成。模型能够根据输入生成高分辨率、高质量的图像,并具备一定的风格迁移能力。',
|
303
|
+
displayName: 'Step 1X Medium',
|
304
|
+
enabled: true,
|
305
|
+
id: 'step-1x-medium',
|
306
|
+
parameters: {
|
307
|
+
prompt: {
|
308
|
+
default: '',
|
309
|
+
},
|
310
|
+
seed: { default: null },
|
311
|
+
size: {
|
312
|
+
default: '1024x1024',
|
313
|
+
enum: ['256x256', '512x512', '768x768', '1024x1024', '1280x800', '800x1280'],
|
314
|
+
},
|
315
|
+
steps: { default: 50, max: 100, min: 1 },
|
316
|
+
},
|
317
|
+
releasedAt: '2025-07-15',
|
318
|
+
type: 'image',
|
319
|
+
},
|
320
|
+
{
|
321
|
+
description:
|
322
|
+
'该模型专注于图像编辑任务,能够根据用户提供的图片和文本描述,对图片进行修改和增强。支持多种输入格式,包括文本描述和示例图像。模型能够理解用户的意图,并生成符合要求的图像编辑结果。',
|
323
|
+
displayName: 'Step 1X Edit',
|
324
|
+
enabled: true,
|
325
|
+
id: 'step-1x-edit',
|
326
|
+
parameters: {
|
327
|
+
imageUrl: { default: null },
|
328
|
+
prompt: {
|
329
|
+
default: '',
|
330
|
+
},
|
331
|
+
seed: { default: null },
|
332
|
+
size: {
|
333
|
+
default: '1024x1024',
|
334
|
+
enum: ['512x512', '768x768', '1024x1024'],
|
335
|
+
},
|
336
|
+
steps: { default: 28, max: 100, min: 1 },
|
337
|
+
},
|
338
|
+
releasedAt: '2025-03-04',
|
339
|
+
type: 'image',
|
340
|
+
},
|
341
|
+
];
|
342
|
+
|
343
|
+
export const allModels = [...stepfunChatModels, ...stepfunImageModels];
|
279
344
|
|
280
345
|
export default allModels;
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { AIChatModelCard } from '@/types/aiModel';
|
1
|
+
import { AIChatModelCard, AIImageModelCard } from '@/types/aiModel';
|
2
2
|
|
3
3
|
// modelInfo https://www.volcengine.com/docs/82379/1330310
|
4
4
|
// pricing https://console.volcengine.com/ark/region:ark+cn-beijing/openManagement
|
@@ -509,6 +509,60 @@ const doubaoChatModels: AIChatModelCard[] = [
|
|
509
509
|
},
|
510
510
|
];
|
511
511
|
|
512
|
-
|
512
|
+
const volcengineImageModels: AIImageModelCard[] = [
|
513
|
+
{
|
514
|
+
/*
|
515
|
+
// TODO: AIImageModelCard 不支持 config.deploymentName
|
516
|
+
config: {
|
517
|
+
deploymentName: 'doubao-seedream-3-0-t2i-250415',
|
518
|
+
},
|
519
|
+
*/
|
520
|
+
description:
|
521
|
+
'Doubao图片生成模型由字节跳动 Seed 团队研发,支持文字与图片输入,提供高可控、高质量的图片生成体验。基于文本提示词生成图片。',
|
522
|
+
displayName: 'Doubao Seedream 3.0 t2i',
|
523
|
+
enabled: true,
|
524
|
+
id: 'doubao-seedream-3-0-t2i-250415',
|
525
|
+
parameters: {
|
526
|
+
prompt: {
|
527
|
+
default: '',
|
528
|
+
},
|
529
|
+
seed: { default: null },
|
530
|
+
size: {
|
531
|
+
default: '1024x1024',
|
532
|
+
enum: ['1024x1024', '864x1152', '1152x864', '1280x720', '720x1280', '832x1248', '1248x832', '1512x648'],
|
533
|
+
},
|
534
|
+
},
|
535
|
+
releasedAt: '2025-04-15',
|
536
|
+
type: 'image',
|
537
|
+
},
|
538
|
+
/*
|
539
|
+
// Note: Doubao 图生图模型与文生图模型公用一个 Endpoint,当前如果存在 imageUrl 会切换至 edit endpoint 下
|
540
|
+
{
|
541
|
+
config: {
|
542
|
+
deploymentName: 'doubao-seededit-3-0-i2i-250628',
|
543
|
+
},
|
544
|
+
description:
|
545
|
+
'Doubao图片生成模型由字节跳动 Seed 团队研发,支持文字与图片输入,提供高可控、高质量的图片生成体验。支持通过文本指令编辑图像,生成图像的边长在512~1536之间。',
|
546
|
+
displayName: 'Doubao SeedEdit 3.0 i2i',
|
547
|
+
enabled: true,
|
548
|
+
id: 'doubao-seededit-3-0-i2i-250628',
|
549
|
+
parameters: {
|
550
|
+
imageUrl: { default: null },
|
551
|
+
prompt: {
|
552
|
+
default: '',
|
553
|
+
},
|
554
|
+
seed: { default: null },
|
555
|
+
size: {
|
556
|
+
default: '1024x1024',
|
557
|
+
enum: ['1024x1024', '864x1152', '1152x864', '1280x720', '720x1280', '832x1248', '1248x832', '1512x648'],
|
558
|
+
},
|
559
|
+
},
|
560
|
+
releasedAt: '2025-06-28',
|
561
|
+
type: 'image',
|
562
|
+
},
|
563
|
+
*/
|
564
|
+
];
|
565
|
+
|
566
|
+
export const allModels = [...doubaoChatModels, ...volcengineImageModels];
|
513
567
|
|
514
568
|
export default allModels;
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { AIChatModelCard } from '@/types/aiModel';
|
1
|
+
import { AIChatModelCard, AIImageModelCard } from '@/types/aiModel';
|
2
2
|
|
3
3
|
const wenxinChatModels: AIChatModelCard[] = [
|
4
4
|
{
|
@@ -564,6 +564,66 @@ const wenxinChatModels: AIChatModelCard[] = [
|
|
564
564
|
},
|
565
565
|
];
|
566
566
|
|
567
|
-
|
567
|
+
const wenxinImageModels: AIImageModelCard[] = [
|
568
|
+
{
|
569
|
+
description:
|
570
|
+
'百度自研的iRAG(image based RAG),检索增强的文生图技术,将百度搜索的亿级图片资源跟强大的基础模型能力相结合,就可以生成各种超真实的图片,整体效果远远超过文生图原生系统,去掉了AI味儿,而且成本很低。iRAG具备无幻觉、超真实、立等可取等特点。',
|
571
|
+
displayName: 'ERNIE iRAG',
|
572
|
+
enabled: true,
|
573
|
+
id: 'irag-1.0',
|
574
|
+
parameters: {
|
575
|
+
prompt: {
|
576
|
+
default: '',
|
577
|
+
},
|
578
|
+
size: {
|
579
|
+
default: '1024x1024',
|
580
|
+
enum: ['768x768', '1024x1024', '1536x1536', '2048x2048', '1024x768', '2048x1536', '768x1024', '1536x2048', '1024x576', '2048x1152', '576x1024', '1152x2048'],
|
581
|
+
},
|
582
|
+
},
|
583
|
+
releasedAt: '2025-02-05',
|
584
|
+
type: 'image',
|
585
|
+
},
|
586
|
+
{
|
587
|
+
description:
|
588
|
+
'百度自研的ERNIE iRAG Edit图像编辑模型支持基于图片进行erase(消除对象)、repaint(重绘对象)、variation(生成变体)等操作。',
|
589
|
+
displayName: 'ERNIE iRAG Edit',
|
590
|
+
enabled: true,
|
591
|
+
id: 'ernie-irag-edit',
|
592
|
+
parameters: {
|
593
|
+
imageUrl: { default: null },
|
594
|
+
prompt: {
|
595
|
+
default: '',
|
596
|
+
},
|
597
|
+
size: {
|
598
|
+
default: '1024x1024',
|
599
|
+
enum: ['768x768', '1024x1024', '1536x1536', '2048x2048', '1024x768', '2048x1536', '768x1024', '1536x2048', '1024x576', '2048x1152', '576x1024', '1152x2048'],
|
600
|
+
},
|
601
|
+
},
|
602
|
+
releasedAt: '2025-04-17',
|
603
|
+
type: 'image',
|
604
|
+
},
|
605
|
+
{
|
606
|
+
description:
|
607
|
+
'具有120亿参数的修正流变换器,能够根据文本描述生成图像。',
|
608
|
+
displayName: 'FLUX.1-schnell',
|
609
|
+
enabled: true,
|
610
|
+
id: 'flux.1-schnell',
|
611
|
+
parameters: {
|
612
|
+
prompt: {
|
613
|
+
default: '',
|
614
|
+
},
|
615
|
+
seed: { default: null },
|
616
|
+
size: {
|
617
|
+
default: '1024x1024',
|
618
|
+
enum: ['768x768', '1024x1024', '1536x1536', '2048x2048', '1024x768', '2048x1536', '768x1024', '1536x2048', '1024x576', '2048x1152', '576x1024', '1152x2048'],
|
619
|
+
},
|
620
|
+
steps: { default: 25, max: 50, min: 1 },
|
621
|
+
},
|
622
|
+
releasedAt: '2025-03-27',
|
623
|
+
type: 'image',
|
624
|
+
},
|
625
|
+
];
|
626
|
+
|
627
|
+
export const allModels = [...wenxinChatModels, ...wenxinImageModels];
|
568
628
|
|
569
629
|
export default allModels;
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { AIChatModelCard } from '@/types/aiModel';
|
1
|
+
import { AIChatModelCard, AIImageModelCard } from '@/types/aiModel';
|
2
2
|
|
3
3
|
// https://docs.x.ai/docs/models
|
4
4
|
const xaiChatModels: AIChatModelCard[] = [
|
@@ -158,6 +158,23 @@ const xaiChatModels: AIChatModelCard[] = [
|
|
158
158
|
},
|
159
159
|
];
|
160
160
|
|
161
|
-
|
161
|
+
const xaiImageModels: AIImageModelCard[] = [
|
162
|
+
{
|
163
|
+
description:
|
164
|
+
'我们最新的图像生成模型可以根据文本提示生成生动逼真的图像。它在营销、社交媒体和娱乐等领域的图像生成方面表现出色。',
|
165
|
+
displayName: 'Grok 2 Image 1212',
|
166
|
+
enabled: true,
|
167
|
+
id: 'grok-2-image-1212',
|
168
|
+
parameters: {
|
169
|
+
prompt: {
|
170
|
+
default: '',
|
171
|
+
},
|
172
|
+
},
|
173
|
+
releasedAt: '2024-12-12',
|
174
|
+
type: 'image',
|
175
|
+
},
|
176
|
+
];
|
177
|
+
|
178
|
+
export const allModels = [...xaiChatModels, ...xaiImageModels];
|
162
179
|
|
163
180
|
export default allModels;
|
package/src/const/auth.ts
CHANGED
@@ -9,11 +9,10 @@ export const LOBE_CHAT_OIDC_AUTH_HEADER = 'Oidc-Auth';
|
|
9
9
|
|
10
10
|
export const OAUTH_AUTHORIZED = 'X-oauth-authorized';
|
11
11
|
|
12
|
-
export const
|
13
|
-
export const NON_HTTP_PREFIX = 'http_nosafe';
|
12
|
+
export const SECRET_XOR_KEY = 'LobeHub · LobeHub';
|
14
13
|
|
15
14
|
/* eslint-disable typescript-sort-keys/interface */
|
16
|
-
export interface
|
15
|
+
export interface ClientSecretPayload {
|
17
16
|
/**
|
18
17
|
* password
|
19
18
|
*/
|
@@ -4,7 +4,7 @@ import { LangfuseGenerationClient, LangfuseTraceClient } from 'langfuse-core';
|
|
4
4
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
5
5
|
|
6
6
|
import * as langfuseCfg from '@/config/langfuse';
|
7
|
-
import {
|
7
|
+
import { ClientSecretPayload } from '@/const/auth';
|
8
8
|
import { TraceNameMap } from '@/const/trace';
|
9
9
|
import { AgentRuntime, ChatStreamPayload, LobeOpenAI, ModelProvider } from '@/libs/model-runtime';
|
10
10
|
import { providerRuntimeMap } from '@/libs/model-runtime/runtimeMap';
|
@@ -51,7 +51,7 @@ const specialProviders = [
|
|
51
51
|
const testRuntime = (providerId: string, payload?: any) => {
|
52
52
|
describe(`${providerId} provider runtime`, () => {
|
53
53
|
it('should initialize correctly', async () => {
|
54
|
-
const jwtPayload:
|
54
|
+
const jwtPayload: ClientSecretPayload = { apiKey: 'user-key', ...payload };
|
55
55
|
const runtime = await AgentRuntime.initializeWithProvider(providerId, jwtPayload);
|
56
56
|
|
57
57
|
// @ts-ignore
|
@@ -66,7 +66,7 @@ const testRuntime = (providerId: string, payload?: any) => {
|
|
66
66
|
|
67
67
|
let mockModelRuntime: AgentRuntime;
|
68
68
|
beforeEach(async () => {
|
69
|
-
const jwtPayload:
|
69
|
+
const jwtPayload: ClientSecretPayload = { apiKey: 'user-openai-key', baseURL: 'user-endpoint' };
|
70
70
|
mockModelRuntime = await AgentRuntime.initializeWithProvider(ModelProvider.OpenAI, jwtPayload);
|
71
71
|
});
|
72
72
|
|
@@ -18,20 +18,38 @@ interface QwenImageTaskResponse {
|
|
18
18
|
request_id: string;
|
19
19
|
}
|
20
20
|
|
21
|
+
const QwenText2ImageModels = [
|
22
|
+
'wan2.2-t2i',
|
23
|
+
'wanx2.1-t2i',
|
24
|
+
'wanx2.0-t2i',
|
25
|
+
'wanx-v1',
|
26
|
+
'flux',
|
27
|
+
'stable-diffusion'
|
28
|
+
];
|
29
|
+
|
30
|
+
const getModelType = (model: string): string => {
|
31
|
+
// 可以添加其他模型类型的判断
|
32
|
+
// if (QwenImage2ImageModels.some(prefix => model.startsWith(prefix))) {
|
33
|
+
// return 'image2image';
|
34
|
+
// }
|
35
|
+
|
36
|
+
if (QwenText2ImageModels.some(prefix => model.startsWith(prefix))) {
|
37
|
+
return 'text2image';
|
38
|
+
}
|
39
|
+
|
40
|
+
throw new Error(`Unsupported model: ${model}`);
|
41
|
+
}
|
42
|
+
|
21
43
|
/**
|
22
44
|
* Create an image generation task with Qwen API
|
23
45
|
*/
|
24
46
|
async function createImageTask(payload: CreateImagePayload, apiKey: string): Promise<string> {
|
25
47
|
const { model, params } = payload;
|
26
48
|
// I can only say that the design of Alibaba Cloud's API is really bad; each model has a different endpoint path.
|
27
|
-
const
|
28
|
-
|
29
|
-
'https://dashscope.aliyuncs.com/api/v1/services/aigc/text2image/image-synthesis',
|
30
|
-
};
|
31
|
-
|
32
|
-
const endpoint = modelEndpointMap[model];
|
49
|
+
const modelType = getModelType(model);
|
50
|
+
const endpoint = `https://dashscope.aliyuncs.com/api/v1/services/aigc/${modelType}/image-synthesis`
|
33
51
|
if (!endpoint) {
|
34
|
-
throw new Error(`
|
52
|
+
throw new Error(`No endpoint configured for model type: ${modelType}`);
|
35
53
|
}
|
36
54
|
log('Creating image task with model: %s, endpoint: %s', model, endpoint);
|
37
55
|
|
@@ -45,10 +63,12 @@ async function createImageTask(payload: CreateImagePayload, apiKey: string): Pro
|
|
45
63
|
model,
|
46
64
|
parameters: {
|
47
65
|
n: 1,
|
48
|
-
...(params.seed
|
66
|
+
...(typeof params.seed === 'number' ? { seed: params.seed } : {}),
|
49
67
|
...(params.width && params.height
|
50
68
|
? { size: `${params.width}*${params.height}` }
|
51
|
-
:
|
69
|
+
: params.size
|
70
|
+
? { size: params.size.replaceAll('x', '*') }
|
71
|
+
: { size: '1024*1024' }),
|
52
72
|
},
|
53
73
|
}),
|
54
74
|
headers: {
|
@@ -1,14 +1,14 @@
|
|
1
1
|
import debug from 'debug';
|
2
2
|
import { NextRequest } from 'next/server';
|
3
3
|
|
4
|
-
import {
|
4
|
+
import { ClientSecretPayload, LOBE_CHAT_AUTH_HEADER } from '@/const/auth';
|
5
5
|
import { LobeChatDatabase } from '@/database/type';
|
6
6
|
import { KeyVaultsGateKeeper } from '@/server/modules/KeyVaultsEncrypt';
|
7
7
|
|
8
8
|
const log = debug('lobe-async:context');
|
9
9
|
|
10
10
|
export interface AsyncAuthContext {
|
11
|
-
jwtPayload:
|
11
|
+
jwtPayload: ClientSecretPayload;
|
12
12
|
secret: string;
|
13
13
|
serverDB?: LobeChatDatabase;
|
14
14
|
userId?: string | null;
|
@@ -19,7 +19,7 @@ export interface AsyncAuthContext {
|
|
19
19
|
* This is useful for testing when we don't want to mock Next.js' request/response
|
20
20
|
*/
|
21
21
|
export const createAsyncContextInner = async (params?: {
|
22
|
-
jwtPayload?:
|
22
|
+
jwtPayload?: ClientSecretPayload;
|
23
23
|
secret?: string;
|
24
24
|
userId?: string | null;
|
25
25
|
}): Promise<AsyncAuthContext> => ({
|
@@ -1,13 +1,18 @@
|
|
1
1
|
import { User } from 'next-auth';
|
2
2
|
import { NextRequest } from 'next/server';
|
3
3
|
|
4
|
-
import {
|
4
|
+
import {
|
5
|
+
ClientSecretPayload,
|
6
|
+
LOBE_CHAT_AUTH_HEADER,
|
7
|
+
enableClerk,
|
8
|
+
enableNextAuth,
|
9
|
+
} from '@/const/auth';
|
5
10
|
import { ClerkAuth, IClerkAuth } from '@/libs/clerk-auth';
|
6
11
|
|
7
12
|
export interface AuthContext {
|
8
13
|
authorizationHeader?: string | null;
|
9
14
|
clerkAuth?: IClerkAuth;
|
10
|
-
jwtPayload?:
|
15
|
+
jwtPayload?: ClientSecretPayload | null;
|
11
16
|
nextAuth?: User;
|
12
17
|
userId?: string | null;
|
13
18
|
}
|
@@ -5,7 +5,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
5
5
|
import { createCallerFactory } from '@/libs/trpc/edge';
|
6
6
|
import { AuthContext, createContextInner } from '@/libs/trpc/edge/context';
|
7
7
|
import { edgeTrpc as trpc } from '@/libs/trpc/edge/init';
|
8
|
-
import * as utils from '@/utils/server/
|
8
|
+
import * as utils from '@/utils/server/xor';
|
9
9
|
|
10
10
|
import { jwtPayloadChecker } from './jwtPayload';
|
11
11
|
|
@@ -40,7 +40,7 @@ describe('passwordChecker middleware', () => {
|
|
40
40
|
it('should call next with jwtPayload in context if access code is correct', async () => {
|
41
41
|
const jwtPayload = { accessCode: '123' };
|
42
42
|
|
43
|
-
vi.spyOn(utils, '
|
43
|
+
vi.spyOn(utils, 'getXorPayload').mockResolvedValue(jwtPayload);
|
44
44
|
|
45
45
|
ctx = await createContextInner({ authorizationHeader: 'Bearer token' });
|
46
46
|
router = createCaller(ctx);
|
@@ -52,7 +52,7 @@ describe('passwordChecker middleware', () => {
|
|
52
52
|
|
53
53
|
it('should call next with jwtPayload in context if no access codes are set', async () => {
|
54
54
|
const jwtPayload = {};
|
55
|
-
vi.spyOn(utils, '
|
55
|
+
vi.spyOn(utils, 'getXorPayload').mockResolvedValue(jwtPayload);
|
56
56
|
|
57
57
|
ctx = await createContextInner({ authorizationHeader: 'Bearer token' });
|
58
58
|
router = createCaller(ctx);
|
@@ -63,7 +63,7 @@ describe('passwordChecker middleware', () => {
|
|
63
63
|
});
|
64
64
|
it('should call next with jwtPayload in context if access codes is undefined', async () => {
|
65
65
|
const jwtPayload = {};
|
66
|
-
vi.spyOn(utils, '
|
66
|
+
vi.spyOn(utils, 'getXorPayload').mockResolvedValue(jwtPayload);
|
67
67
|
|
68
68
|
ctx = await createContextInner({ authorizationHeader: 'Bearer token' });
|
69
69
|
router = createCaller(ctx);
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import { TRPCError } from '@trpc/server';
|
2
2
|
|
3
|
-
import {
|
3
|
+
import { getXorPayload } from '@/utils/server/xor';
|
4
4
|
|
5
5
|
import { edgeTrpc } from '../init';
|
6
6
|
|
@@ -9,7 +9,7 @@ export const jwtPayloadChecker = edgeTrpc.middleware(async (opts) => {
|
|
9
9
|
|
10
10
|
if (!ctx.authorizationHeader) throw new TRPCError({ code: 'UNAUTHORIZED' });
|
11
11
|
|
12
|
-
const jwtPayload =
|
12
|
+
const jwtPayload = getXorPayload(ctx.authorizationHeader);
|
13
13
|
|
14
14
|
return opts.next({ ctx: { jwtPayload } });
|
15
15
|
});
|
@@ -4,7 +4,7 @@ import { User } from 'next-auth';
|
|
4
4
|
import { NextRequest } from 'next/server';
|
5
5
|
|
6
6
|
import {
|
7
|
-
|
7
|
+
ClientSecretPayload,
|
8
8
|
LOBE_CHAT_AUTH_HEADER,
|
9
9
|
LOBE_CHAT_OIDC_AUTH_HEADER,
|
10
10
|
enableClerk,
|
@@ -29,7 +29,7 @@ export interface OIDCAuth {
|
|
29
29
|
export interface AuthContext {
|
30
30
|
authorizationHeader?: string | null;
|
31
31
|
clerkAuth?: IClerkAuth;
|
32
|
-
jwtPayload?:
|
32
|
+
jwtPayload?: ClientSecretPayload | null;
|
33
33
|
marketAccessToken?: string;
|
34
34
|
nextAuth?: User;
|
35
35
|
// Add OIDC authentication information
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import { TRPCError } from '@trpc/server';
|
2
2
|
|
3
|
-
import {
|
3
|
+
import { getXorPayload } from '@/utils/server/xor';
|
4
4
|
|
5
5
|
import { trpc } from '../init';
|
6
6
|
|
@@ -10,7 +10,7 @@ export const keyVaults = trpc.middleware(async (opts) => {
|
|
10
10
|
if (!ctx.authorizationHeader) throw new TRPCError({ code: 'UNAUTHORIZED' });
|
11
11
|
|
12
12
|
try {
|
13
|
-
const jwtPayload =
|
13
|
+
const jwtPayload = getXorPayload(ctx.authorizationHeader);
|
14
14
|
|
15
15
|
return opts.next({ ctx: { jwtPayload } });
|
16
16
|
} catch (e) {
|