diff --git a/server/routes/auth.ts b/server/routes/auth.ts index 26eda8aeb..f8453c5f5 100644 --- a/server/routes/auth.ts +++ b/server/routes/auth.ts @@ -18,9 +18,18 @@ import axios from 'axios'; import { Router } from 'express'; import net from 'net'; import validator from 'validator'; +import { z } from 'zod'; const authRoutes = Router(); +export const quickConnectSecret = z.object({ + secret: z + .string() + .min(8) + .max(128) + .regex(/^[A-Fa-f0-9]+$/), +}); + authRoutes.get('/me', isAuthenticated(), async (req, res) => { const userRepository = getRepository(User); if (!req.user) { @@ -621,21 +630,16 @@ authRoutes.post('/jellyfin/quickconnect/initiate', async (req, res, next) => { }); authRoutes.get('/jellyfin/quickconnect/check', async (req, res, next) => { - const secret = req.query.secret as string; - - if ( - !secret || - typeof secret !== 'string' || - secret.length < 8 || - secret.length > 128 || - !/^[A-Fa-f0-9]+$/.test(secret) - ) { + const result = quickConnectSecret.safeParse(req.query); + if (!result.success) { return next({ status: 400, message: 'Invalid secret format', }); } + const { secret } = result.data; + try { const hostname = getHostname(); const jellyfinServer = new JellyfinAPI( @@ -660,21 +664,16 @@ authRoutes.post( async (req, res, next) => { const settings = getSettings(); const userRepository = getRepository(User); - const body = req.body as { secret?: string }; - - if ( - !body.secret || - typeof body.secret !== 'string' || - body.secret.length < 8 || - body.secret.length > 128 || - !/^[A-Fa-f0-9]+$/.test(body.secret) - ) { + const result = quickConnectSecret.safeParse(req.body); + if (!result.success) { return next({ status: 400, message: 'Secret required', }); } + const { secret } = result.data; + if ( settings.main.mediaServerType === MediaServerType.NOT_CONFIGURED || !(await userRepository.count()) @@ -693,9 +692,7 @@ authRoutes.post( undefined ); - const account = await jellyfinServer.authenticateQuickConnect( - body.secret - ); + const account = await jellyfinServer.authenticateQuickConnect(secret); let user = await userRepository.findOne({ where: { jellyfinUserId: account.User.Id }, diff --git a/server/routes/user/usersettings.ts b/server/routes/user/usersettings.ts index 93defc193..d2c59a597 100644 --- a/server/routes/user/usersettings.ts +++ b/server/routes/user/usersettings.ts @@ -14,6 +14,7 @@ import { Permission } from '@server/lib/permissions'; import { getSettings } from '@server/lib/settings'; import logger from '@server/logger'; import { isAuthenticated } from '@server/middleware/auth'; +import { quickConnectSecret } from '@server/routes/auth'; import { ApiError } from '@server/types/error'; import { getHostname } from '@server/utils/getHostname'; import { @@ -525,17 +526,13 @@ userSettingsRoutes.post<{ secret: string }>( return res.status(401).json({ code: ApiErrorCode.Unauthorized }); } - const secret = req.body.secret; - if ( - !secret || - typeof secret !== 'string' || - secret.length < 8 || - secret.length > 128 || - !/^[A-Fa-f0-9]+$/.test(secret) - ) { + const result = quickConnectSecret.safeParse(req.body); + if (!result.success) { return res.status(400).json({ message: 'Invalid secret format' }); } + const { secret } = result.data; + if ( settings.main.mediaServerType !== MediaServerType.JELLYFIN && settings.main.mediaServerType !== MediaServerType.EMBY