Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion frontend/apply/src/app/apply/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,10 @@ export default function ApplyPage() {

<div className={styles.guestLoginCard}>
<p>{t("applyPage.loginRequiredMessage")}</p>
<Link href="/login" className={`button activeButton ${styles.guestLoginButton}`}>
<Link
href={`/login?next=${encodeURIComponent(`/apply/${positionId}`)}`}
className={`button activeButton ${styles.guestLoginButton}`}
>
{t("applyPage.goToLogin")}
</Link>
</div>
Expand Down
24 changes: 22 additions & 2 deletions frontend/apply/src/app/login/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"use client";

import { useState, useEffect } from "react";
import { useRouter } from "next/navigation";
import { useRouter, useSearchParams } from "next/navigation";
import TextInput from "@/components/TextInput";
import Button from "@/components/Button";
import styles from "./login.module.css";
Expand All @@ -12,6 +12,8 @@ import "@/i18n/config";
export default function Login() {
const { t } = useTranslation();
const router = useRouter();
const searchParams = useSearchParams();
const rawNext = searchParams.get("next");
const { isLoggedIn, loading } = useIsLoggedIn();
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
Expand All @@ -34,7 +36,25 @@ export default function Login() {

if (response.status === 200) {
window.dispatchEvent(new CustomEvent("logged-in"));
router.push("/");

const isSafeRedirect = (path: string | null) => {
if (!path) return false;
// Disallow absolute URLs or protocol markers
if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(path)) return false;
// Must be a normalized absolute path within this site
if (!path.startsWith("/")) return false;
// Prevent double slashes or attempts to break out
if (path.includes("//")) return false;
// Only allow redirects under /apply (application form pages)
return /^\/apply(\/.*)?$/.test(path);
};

const next = rawNext;
if (isSafeRedirect(next)) {
router.push(next as string);
} else {
router.push("/");
}
} else if (response.status === 401) {
setError(t("loginPage.incorrectCredentials"));
} else if (response.status === 403) {
Expand Down
Loading