fix: crash due to lack of input validation in WizardForm (#21990)

* fix: crash due to lack of input validation in WizardForm

* server side validation

* refactor

* refactor
This commit is contained in:
Benny Joo
2025-06-23 17:03:51 -03:00
committed by GitHub
parent b381cfe207
commit 07c8bbc562
2 changed files with 17 additions and 5 deletions
@@ -2,6 +2,8 @@ import { withAppDirSsr } from "app/WithAppDirSsr";
import type { PageProps as ServerPageProps } from "app/_types";
import { _generateMetadata } from "app/_utils";
import { cookies, headers } from "next/headers";
import { redirect } from "next/navigation";
import { z } from "zod";
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
@@ -21,11 +23,18 @@ export const generateMetadata = async () => {
};
const getData = withAppDirSsr<ClientPageProps>(getServerSideProps);
const stepSchema = z.enum(["1", "2", "3", "4"]);
const ServerPage = async ({ params, searchParams }: ServerPageProps) => {
const props = await getData(
buildLegacyCtx(await headers(), await cookies(), await params, await searchParams)
);
const ServerPage = async ({ params, searchParams: _searchParams }: ServerPageProps) => {
const searchParams = await _searchParams;
const stepResult = stepSchema.safeParse(searchParams?.step);
// If step parameter is invalid, redirect to step 1
if (!stepResult.success) {
return redirect(`/auth/setup?step=1`);
}
const props = await getData(buildLegacyCtx(await headers(), await cookies(), await params, searchParams));
return <Setup {...props} />;
};
@@ -5,6 +5,7 @@ import { noop } from "lodash";
import { useRouter } from "next/navigation";
import type { Dispatch, SetStateAction } from "react";
import { useEffect, useState } from "react";
import { z } from "zod";
import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams";
import classNames from "@calcom/ui/classNames";
@@ -35,7 +36,9 @@ function WizardForm<T extends DefaultStep>(props: {
const searchParams = useCompatSearchParams();
const { href, steps, nextLabel = "Next", finishLabel = "Finish", prevLabel = "Back", stepLabel } = props;
const router = useRouter();
const step = parseInt((searchParams?.get("step") as string) || "1");
const stepSchema = z.coerce.number().int().min(1).max(steps.length).default(1);
const stepResult = stepSchema.safeParse(searchParams?.get("step"));
const step = stepResult.success ? stepResult.data : 1;
const currentStep = steps[step - 1];
const setStep = (newStep: number) => {
router.replace(`${href}?step=${newStep || 1}`);