From ff68f986890e3e256027125b08e1dbc8646ec99f Mon Sep 17 00:00:00 2001 From: Tagaishi Date: Wed, 24 Apr 2024 16:33:02 +0200 Subject: [PATCH] fix: timeout env variable parsing --- src/components/layout/header/AvatarMenu.tsx | 6 +----- src/env.js | 14 ++++++++++---- src/hooks/custom-session-provider.tsx | 5 +---- src/server/auth.ts | 2 +- src/tools/client/parseDuration.ts | 19 +++++++++++++++++++ 5 files changed, 32 insertions(+), 14 deletions(-) diff --git a/src/components/layout/header/AvatarMenu.tsx b/src/components/layout/header/AvatarMenu.tsx index 17166906eef..1b3b7fb19ae 100644 --- a/src/components/layout/header/AvatarMenu.tsx +++ b/src/components/layout/header/AvatarMenu.tsx @@ -34,11 +34,7 @@ export const AvatarMenu = () => { - } - onClick={toggleColorScheme} - > + } onClick={toggleColorScheme}> {t('actions.avatar.switchTheme')} {sessionData?.user && ( diff --git a/src/env.js b/src/env.js index dd1022f7f5d..629adf69dd3 100644 --- a/src/env.js +++ b/src/env.js @@ -1,5 +1,6 @@ const { z } = require('zod'); const { createEnv } = require('@t3-oss/env-nextjs'); +const { secondsFromTimeString } = require('./tools/client/parseDuration'); const trueStrings = ['1', 't', 'T', 'TRUE', 'true', 'True']; const falseStrings = ['0', 'f', 'F', 'FALSE', 'false', 'False']; @@ -16,7 +17,7 @@ const numberSchema = z .string() .regex(/\d*/) .transform((value) => (value === undefined ? undefined : Number(value))) - .optional() + .optional(); const portSchema = z .string() @@ -49,7 +50,12 @@ const env = createEnv({ DEMO_MODE: z.string().optional(), HOSTNAME: z.string().optional(), - AUTH_SESSION_EXPIRY_TIME: numberSchema, + //regex allows number with extra letter as time multiplier, applied with secondsFromTimeString + AUTH_SESSION_EXPIRY_TIME: z + .string() + .regex(/^\d+[smhd]?$/) + .transform(secondsFromTimeString) + .optional(), // Authentication AUTH_PROVIDER: z @@ -98,7 +104,7 @@ const env = createEnv({ AUTH_OIDC_OWNER_GROUP: z.string().default('admin'), AUTH_OIDC_AUTO_LOGIN: zodParsedBoolean(), AUTH_OIDC_SCOPE_OVERWRITE: z.string().default('openid email profile groups'), - AUTH_OIDC_TIMEOUT: numberSchema.default(3500) + AUTH_OIDC_TIMEOUT: numberSchema.default(3500), } : {}), }, @@ -120,7 +126,7 @@ const env = createEnv({ .optional() .default('light'), NEXT_PUBLIC_DOCKER_HOST: z.string().optional(), - NEXT_PUBLIC_LOGOUT_REDIRECT_URL: z.string().optional() + NEXT_PUBLIC_LOGOUT_REDIRECT_URL: z.string().optional(), }, /** * You can't destruct `process.env` as a regular object in the Next.js edge runtimes (e.g. diff --git a/src/hooks/custom-session-provider.tsx b/src/hooks/custom-session-provider.tsx index 62d9d6a90f8..e9a89a4884d 100644 --- a/src/hooks/custom-session-provider.tsx +++ b/src/hooks/custom-session-provider.tsx @@ -1,11 +1,8 @@ import dayjs from 'dayjs'; -import relativeTime from 'dayjs/plugin/relativeTime'; import { Session } from 'next-auth'; import { SessionProvider, signIn } from 'next-auth/react'; import { useEffect } from 'react'; -dayjs.extend(relativeTime); - interface CustomSessionProviderProps { session: Session; children: React.ReactNode; @@ -15,7 +12,7 @@ export const CustomSessionProvider = ({ session, children }: CustomSessionProvid //Automatically redirect to the login page after a session expires useEffect(() => { if (!session) return () => {}; - const timeout = setTimeout(signIn, dayjs(session?.expires).diff(new Date())); + const timeout = setTimeout(signIn, dayjs(session?.expires).diff()); return () => clearTimeout(timeout); }, [session]); diff --git a/src/server/auth.ts b/src/server/auth.ts index 4b25603c1dc..3c86016f0e0 100644 --- a/src/server/auth.ts +++ b/src/server/auth.ts @@ -4,13 +4,13 @@ import { type GetServerSidePropsContext, type NextApiRequest, type NextApiRespon import { type NextAuthOptions, getServerSession } from 'next-auth'; import { Adapter } from 'next-auth/adapters'; import { decode, encode } from 'next-auth/jwt'; +import { env } from '~/env'; import { adapter, getProviders, onCreateUser } from '~/utils/auth'; import { createRedirectUri } from '~/utils/auth/oidc'; import EmptyNextAuthProvider from '~/utils/empty-provider'; import { fromDate, generateSessionToken } from '~/utils/session'; import { colorSchemeParser } from '~/validations/user'; -import { env } from '~/env'; import { db } from './db'; import { users } from './db/schema'; diff --git a/src/tools/client/parseDuration.ts b/src/tools/client/parseDuration.ts index d59de519a9a..c3981230e16 100644 --- a/src/tools/client/parseDuration.ts +++ b/src/tools/client/parseDuration.ts @@ -18,3 +18,22 @@ export const parseDuration = (time: number, t: TFunction): string => { return eta; }; + +export const secondsFromTimeString = (time: string | undefined): number | undefined => { + if (!time) return undefined; + const lastChar = time[time.length - 1]; + if (!isNaN(+lastChar)) return Number(time); + const numTime = +time.substring(0, time.length - 1); + switch (lastChar.toLowerCase()) { + case 's': + return numTime; + case 'm': + return numTime * 60; + case 'h': + return numTime * 60 * 60; + case 'd': + return numTime * 24 * 60 * 60; + default: + return undefined; + } +};