refactor(quickconnect): implement zod validation for quick connect secret

This commit is contained in:
fallenbagel
2026-03-19 19:54:54 +08:00
parent 095d9172b7
commit 7d2d839aa8
2 changed files with 23 additions and 29 deletions

View File

@@ -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 },

View File

@@ -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