From 174f4df735503b679dcc3822a5011ee3da1d11e3 Mon Sep 17 00:00:00 2001 From: Arvin Xu Date: Sun, 25 Aug 2024 23:46:05 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20fix:=20fix=20dayjs=20error=20in?= =?UTF-8?q?=20en-US=20language=20(#3604)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🐛 fix: fix dayjs issue * 🐛 fix: fix user auth and password issue --- src/layout/GlobalProvider/Locale.tsx | 12 ++++++++- src/libs/trpc/index.ts | 4 +-- .../{password.test.ts => jwtPayload.test.ts} | 25 +++--------------- src/libs/trpc/middleware/jwtPayload.ts | 14 ++++++++++ src/libs/trpc/middleware/password.ts | 26 ------------------- 5 files changed, 30 insertions(+), 51 deletions(-) rename src/libs/trpc/middleware/{password.test.ts => jwtPayload.test.ts} (70%) create mode 100644 src/libs/trpc/middleware/jwtPayload.ts delete mode 100644 src/libs/trpc/middleware/password.ts diff --git a/src/layout/GlobalProvider/Locale.tsx b/src/layout/GlobalProvider/Locale.tsx index 5235340dacb9..bea22e8ad9cc 100644 --- a/src/layout/GlobalProvider/Locale.tsx +++ b/src/layout/GlobalProvider/Locale.tsx @@ -37,7 +37,17 @@ const Locale = memo(({ children, defaultLang, antdLocale }) = if (!lang) return; // load default lang - const dayJSLocale = await import(`dayjs/locale/${lang!.toLowerCase()}.js`); + let dayJSLocale; + try { + // dayjs locale is using `en` instead of `en-US` + // refs: https://github.com/lobehub/lobe-chat/issues/3396 + const locale = lang!.toLowerCase() === 'en-us' ? 'en' : lang!.toLowerCase(); + + dayJSLocale = await import(`dayjs/locale/${locale}.js`); + } catch { + console.warn(`dayjs locale for ${lang} not found, fallback to en`); + dayJSLocale = await import(`dayjs/locale/en.js`); + } dayjs.locale(dayJSLocale.default); }); diff --git a/src/libs/trpc/index.ts b/src/libs/trpc/index.ts index e4486319166e..c507507d989e 100644 --- a/src/libs/trpc/index.ts +++ b/src/libs/trpc/index.ts @@ -8,7 +8,7 @@ * @link https://trpc.io/docs/v11/procedures */ import { trpc } from './init'; -import { passwordChecker } from './middleware/password'; +import { jwtPayloadChecker } from './middleware/jwtPayload'; import { userAuth } from './middleware/userAuth'; /** @@ -27,7 +27,7 @@ export const publicProcedure = trpc.procedure; export const authedProcedure = trpc.procedure.use(userAuth); // procedure that asserts that the user add the password -export const passwordProcedure = trpc.procedure.use(passwordChecker); +export const passwordProcedure = trpc.procedure.use(jwtPayloadChecker); /** * Merge multiple routers together diff --git a/src/libs/trpc/middleware/password.test.ts b/src/libs/trpc/middleware/jwtPayload.test.ts similarity index 70% rename from src/libs/trpc/middleware/password.test.ts rename to src/libs/trpc/middleware/jwtPayload.test.ts index 48866cd47153..8a467fd02930 100644 --- a/src/libs/trpc/middleware/password.test.ts +++ b/src/libs/trpc/middleware/jwtPayload.test.ts @@ -3,15 +3,14 @@ import { TRPCError } from '@trpc/server'; import { beforeEach, describe, expect, it, vi } from 'vitest'; import * as utils from '@/app/api/middleware/auth/utils'; -import * as appConfig from '@/config/app'; import { createCallerFactory } from '@/libs/trpc'; import { trpc } from '@/libs/trpc/init'; import { AuthContext, createContextInner } from '@/server/context'; -import { passwordChecker } from './password'; +import { jwtPayloadChecker } from './jwtPayload'; const appRouter = trpc.router({ - protectedQuery: trpc.procedure.use(passwordChecker).query(async ({ ctx }) => { + protectedQuery: trpc.procedure.use(jwtPayloadChecker).query(async ({ ctx }) => { return ctx.jwtPayload; }), }); @@ -38,23 +37,9 @@ describe('passwordChecker middleware', () => { await expect(router.protectedQuery()).rejects.toThrow(new TRPCError({ code: 'UNAUTHORIZED' })); }); - it('should throw UNAUTHORIZED error if access code is not correct', async () => { - vi.spyOn(appConfig, 'getAppConfig').mockReturnValue({ - ACCESS_CODES: ['123'], - } as any); - vi.spyOn(utils, 'getJWTPayload').mockResolvedValue({ accessCode: '456' }); - - ctx = await createContextInner({ authorizationHeader: 'Bearer token' }); - router = createCaller(ctx); - - await expect(router.protectedQuery()).rejects.toThrow(new TRPCError({ code: 'UNAUTHORIZED' })); - }); - it('should call next with jwtPayload in context if access code is correct', async () => { const jwtPayload = { accessCode: '123' }; - vi.spyOn(appConfig, 'getAppConfig').mockReturnValue({ - ACCESS_CODES: ['123'], - } as any); + vi.spyOn(utils, 'getJWTPayload').mockResolvedValue(jwtPayload); ctx = await createContextInner({ authorizationHeader: 'Bearer token' }); @@ -67,9 +52,6 @@ describe('passwordChecker middleware', () => { it('should call next with jwtPayload in context if no access codes are set', async () => { const jwtPayload = {}; - vi.spyOn(appConfig, 'getAppConfig').mockReturnValue({ - ACCESS_CODES: [], - } as any); vi.spyOn(utils, 'getJWTPayload').mockResolvedValue(jwtPayload); ctx = await createContextInner({ authorizationHeader: 'Bearer token' }); @@ -81,7 +63,6 @@ describe('passwordChecker middleware', () => { }); it('should call next with jwtPayload in context if access codes is undefined', async () => { const jwtPayload = {}; - vi.spyOn(appConfig, 'getAppConfig').mockReturnValue({} as any); vi.spyOn(utils, 'getJWTPayload').mockResolvedValue(jwtPayload); ctx = await createContextInner({ authorizationHeader: 'Bearer token' }); diff --git a/src/libs/trpc/middleware/jwtPayload.ts b/src/libs/trpc/middleware/jwtPayload.ts new file mode 100644 index 000000000000..cf0d0a3b7ecc --- /dev/null +++ b/src/libs/trpc/middleware/jwtPayload.ts @@ -0,0 +1,14 @@ +import { TRPCError } from '@trpc/server'; + +import { getJWTPayload } from '@/app/api/middleware/auth/utils'; +import { trpc } from '@/libs/trpc/init'; + +export const jwtPayloadChecker = trpc.middleware(async (opts) => { + const { ctx } = opts; + + if (!ctx.authorizationHeader) throw new TRPCError({ code: 'UNAUTHORIZED' }); + + const jwtPayload = await getJWTPayload(ctx.authorizationHeader); + + return opts.next({ ctx: { jwtPayload } }); +}); diff --git a/src/libs/trpc/middleware/password.ts b/src/libs/trpc/middleware/password.ts deleted file mode 100644 index 7336d5273410..000000000000 --- a/src/libs/trpc/middleware/password.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { TRPCError } from '@trpc/server'; - -import { getJWTPayload } from '@/app/api/middleware/auth/utils'; -import { getAppConfig } from '@/config/app'; -import { trpc } from '@/libs/trpc/init'; - -export const passwordChecker = trpc.middleware(async (opts) => { - const { ACCESS_CODES } = getAppConfig(); - - const { ctx } = opts; - - if (!ctx.authorizationHeader) throw new TRPCError({ code: 'UNAUTHORIZED' }); - - const jwtPayload = await getJWTPayload(ctx.authorizationHeader); - - // if there are access codes, check if the user has set correct one - if (ACCESS_CODES && ACCESS_CODES.length > 0) { - const accessCode = jwtPayload.accessCode; - - if (!accessCode || !ACCESS_CODES.includes(accessCode)) { - throw new TRPCError({ code: 'UNAUTHORIZED' }); - } - } - - return opts.next({ ctx: { jwtPayload } }); -});