mirror of
https://github.com/formbricks/formbricks.git
synced 2026-02-19 10:09:57 -06:00
fix: Validation for callback URL (#3061)
This commit is contained in:
committed by
GitHub
parent
14e0d57091
commit
0076cbaf54
@@ -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(() => {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
@@ -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";
|
||||
|
||||
Reference in New Issue
Block a user