Fix login return routes and recovery feedback
All checks were successful
Deploy MineGeo to Dokploy / deploy (push) Successful in 6m29s

This commit is contained in:
2026-10-31 13:56:01 +05:00
parent 48d4058e06
commit 0d62f08e77
6 changed files with 47 additions and 7 deletions

View File

@@ -158,6 +158,7 @@ export function AccountSettings({
async function recover() { async function recover() {
setSending(true); setSending(true);
setRecoveryError(""); setRecoveryError("");
setRecoveryMessage("");
try { try {
const data = await api<{ message: string }>("auth", { const data = await api<{ message: string }>("auth", {
action: "recover", action: "recover",
@@ -344,12 +345,12 @@ export function AccountSettings({
</button> </button>
{recoveryMessage && ( {recoveryMessage && (
<p role="status" className="success-message"> <p role="status" className="success-message">
{recoveryMessage} {t(recoveryMessage)}
</p> </p>
)} )}
{recoveryError && ( {recoveryError && (
<p role="alert" className="error-message"> <p role="alert" className="error-message">
{recoveryError} {t(recoveryError)}
</p> </p>
)} )}
</div> </div>

View File

@@ -145,7 +145,10 @@ export function MapCommunity({
</div> </div>
{!data.viewer && ( {!data.viewer && (
<p> <p>
<Link className="button" href="/log-in"> <Link
className="button"
href={`/log-in?next=${encodeURIComponent(`/servers/${datasetId}`)}`}
>
{t("Sign in to react, comment, or report.")} {t("Sign in to react, comment, or report.")}
</Link> </Link>
</p> </p>

View File

@@ -338,7 +338,11 @@ export function StartGame({
) : ( ) : (
<p className="muted"> <p className="muted">
{t("Log in to create a multiplayer room")}{" "} {t("Log in to create a multiplayer room")}{" "}
<Link href="/log-in?next=/servers">{t("Log in")}</Link> <Link
href={`/log-in?next=${encodeURIComponent(`/servers/${datasetId}`)}`}
>
{t("Log in")}
</Link>
</p> </p>
)} )}
<label htmlFor="room-player-limit"> <label htmlFor="room-player-limit">

View File

@@ -157,7 +157,14 @@ export function TournamentIndex({
{t(creating ? "Close" : "Create tournament")} {t(creating ? "Close" : "Create tournament")}
</button> </button>
) : ( ) : (
<Link href="/log-in" className="button primary"> <Link
href={`/log-in?next=${encodeURIComponent(
initialMapId
? `/tournaments?map=${initialMapId}`
: "/tournaments",
)}`}
className="button primary"
>
{t("Log in to create or join")} {t("Log in to create or join")}
</Link> </Link>
)} )}
@@ -595,7 +602,10 @@ export function TournamentLobby({
{event.status === "scheduled" && ( {event.status === "scheduled" && (
<div className="tournament-actions"> <div className="tournament-actions">
{!signedIn ? ( {!signedIn ? (
<Link className="button primary" href="/log-in"> <Link
className="button primary"
href={`/log-in?next=${encodeURIComponent(`/tournaments/${id}`)}`}
>
{t("Log in to create or join")} {t("Log in to create or join")}
</Link> </Link>
) : joined ? ( ) : joined ? (

View File

@@ -77,9 +77,16 @@ export function authDestination(value: string | null | undefined): string {
value === "/dashboard" || value === "/dashboard" ||
value === "/servers" || value === "/servers" ||
value === "/support" || value === "/support" ||
value === "/tournaments" ||
value === "/ban/appeal" ||
value === "/dev/api" ||
value === "/admin" ||
value === "/moderation" ||
value === "/auth/reset-password" value === "/auth/reset-password"
) )
return value; return value;
if (value && /^\/(?:servers|tournaments)\/[0-9a-f-]{36}$/i.test(value))
return value;
if (value && /^\/dashboard\/[0-9a-f-]{36}$/i.test(value)) return value; if (value && /^\/dashboard\/[0-9a-f-]{36}$/i.test(value)) return value;
if (value && /^\/support\/[0-9a-f-]{36}$/i.test(value)) return value; if (value && /^\/support\/[0-9a-f-]{36}$/i.test(value)) return value;
if (value && /^\/tournaments\?map=[0-9a-f-]{36}$/i.test(value)) return value; if (value && /^\/tournaments\?map=[0-9a-f-]{36}$/i.test(value)) return value;

View File

@@ -84,7 +84,22 @@ test("authentication redirects accept supported local routes and reject open red
assert.equal(authDestination(next), "/dashboard"); assert.equal(authDestination(next), "/dashboard");
assert.equal(authDestination("/settings"), "/settings"); assert.equal(authDestination("/settings"), "/settings");
assert.equal(authDestination("/servers"), "/servers"); assert.equal(authDestination("/servers"), "/servers");
const tournamentMap = "/tournaments?map=123e4567-e89b-12d3-a456-426614174000"; const id = "123e4567-e89b-12d3-a456-426614174000";
for (const next of [
"/ban/appeal",
"/dev/api",
"/admin",
"/moderation",
"/tournaments",
`/servers/${id}`,
`/tournaments/${id}`,
])
assert.equal(authDestination(next), next);
assert.equal(
authDestination(`/servers/${id}?next=//evil.example`),
"/dashboard",
);
const tournamentMap = `/tournaments?map=${id}`;
assert.equal(authDestination(tournamentMap), tournamentMap); assert.equal(authDestination(tournamentMap), tournamentMap);
assert.equal( assert.equal(
authDestination(`${tournamentMap}&next=//evil.example`), authDestination(`${tournamentMap}&next=//evil.example`),