fix: Validation for callback URL (#3061)

This commit is contained in:
Dhruwang Jariwala
2024-09-02 18:45:57 +05:30
committed by GitHub
parent 14e0d57091
commit 0076cbaf54
4 changed files with 23 additions and 4 deletions

View File

@@ -50,13 +50,13 @@ export const SigninForm = ({
const searchParams = useSearchParams();
const emailRef = useRef<HTMLInputElement>(null);
const formMethods = useForm<TSigninFormState>();
const callbackUrl = searchParams?.get("callbackUrl");
const onSubmit: SubmitHandler<TSigninFormState> = async (data) => {
setLoggingIn(true);
try {
const signInResponse = await signIn("credentials", {
callbackUrl: searchParams?.get("callbackUrl") || "/",
callbackUrl: callbackUrl ?? "/",
email: data.email.toLowerCase(),
password: data.password,
...(totpLogin && { totpCode: data.totpCode }),
@@ -103,7 +103,6 @@ export const SigninForm = ({
const [signInError, setSignInError] = useState("");
const formRef = useRef<HTMLFormElement>(null);
const error = searchParams?.get("error");
const callbackUrl = searchParams?.get("callbackUrl");
const inviteToken = callbackUrl ? new URL(callbackUrl).searchParams.get("token") : null;
useEffect(() => {

View File

@@ -17,6 +17,7 @@ import { getToken } from "next-auth/jwt";
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
import { RATE_LIMITING_DISABLED, WEBAPP_URL } from "@formbricks/lib/constants";
import { isValidCallbackUrl } from "@formbricks/lib/utils/url";
export const middleware = async (request: NextRequest) => {
// issue with next auth types & Next 15; let's review when new fixes are available
@@ -28,6 +29,9 @@ export const middleware = async (request: NextRequest) => {
}
const callbackUrl = request.nextUrl.searchParams.get("callbackUrl");
if (callbackUrl && !isValidCallbackUrl(callbackUrl, WEBAPP_URL)) {
return NextResponse.json({ error: "Invalid callback URL" });
}
if (token && callbackUrl) {
return NextResponse.redirect(WEBAPP_URL + callbackUrl);
}

View File

@@ -22,3 +22,19 @@ export const testURLmatch = (
throw new Error("Invalid match type");
}
};
// Helper function to validate callback URLs
export const isValidCallbackUrl = (url: string, WEBAPP_URL: string): boolean => {
try {
const parsedUrl = new URL(url);
const allowedSchemes = ["https:", "http:"];
// Extract the domain from WEBAPP_URL
const parsedWebAppUrl = new URL(WEBAPP_URL);
const allowedDomains = [parsedWebAppUrl.hostname];
return allowedSchemes.includes(parsedUrl.protocol) && allowedDomains.includes(parsedUrl.hostname);
} catch (err) {
return false;
}
};

View File

@@ -4,7 +4,7 @@ import { Control, FieldArrayWithId, UseFieldArrayRemove, useFieldArray } from "r
import { UseFormReturn } from "react-hook-form";
import toast from "react-hot-toast";
import { cn } from "@formbricks/lib/cn";
import { testURLmatch } from "@formbricks/lib/utils/testUrlMatch";
import { testURLmatch } from "@formbricks/lib/utils/url";
import { TActionClassInput, TActionClassPageUrlRule } from "@formbricks/types/action-classes";
import { Alert, AlertDescription, AlertTitle } from "../../../Alert";
import { Button } from "../../../Button";