mirror of
https://github.com/steveiliop56/tinyauth.git
synced 2026-02-22 17:02:01 +00:00
Compare commits
3 Commits
steveiliop
...
refactor/f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
089f926001 | ||
|
|
5932221d4d | ||
|
|
a2ac5e2498 |
64
frontend/src/lib/hooks/redirect-uri.ts
Normal file
64
frontend/src/lib/hooks/redirect-uri.ts
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
type IuseRedirectUri = {
|
||||||
|
url?: URL;
|
||||||
|
valid: boolean;
|
||||||
|
trusted: boolean;
|
||||||
|
allowedProto: boolean;
|
||||||
|
httpsDowngrade: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useRedirectUri = (
|
||||||
|
redirect_uri: string | null,
|
||||||
|
cookieDomain: string,
|
||||||
|
): IuseRedirectUri => {
|
||||||
|
let isValid = false;
|
||||||
|
let isTrusted = false;
|
||||||
|
let isAllowedProto = false;
|
||||||
|
let isHttpsDowngrade = false;
|
||||||
|
|
||||||
|
if (!redirect_uri) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
trusted: false,
|
||||||
|
allowedProto: false,
|
||||||
|
httpsDowngrade: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let url: URL;
|
||||||
|
|
||||||
|
try {
|
||||||
|
url = new URL(redirect_uri);
|
||||||
|
} catch {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
trusted: false,
|
||||||
|
allowedProto: false,
|
||||||
|
httpsDowngrade: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
isValid = true;
|
||||||
|
|
||||||
|
if (
|
||||||
|
url.hostname == cookieDomain ||
|
||||||
|
url.hostname.endsWith(`.${cookieDomain}`)
|
||||||
|
) {
|
||||||
|
isTrusted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (url.protocol == "http:" || url.protocol == "https:") {
|
||||||
|
isAllowedProto = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window.location.protocol == "https:" && url.protocol == "http:") {
|
||||||
|
isHttpsDowngrade = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
url,
|
||||||
|
valid: isValid,
|
||||||
|
trusted: isTrusted,
|
||||||
|
allowedProto: isAllowedProto,
|
||||||
|
httpsDowngrade: isHttpsDowngrade,
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -5,15 +5,6 @@ export function cn(...inputs: ClassValue[]) {
|
|||||||
return twMerge(clsx(inputs));
|
return twMerge(clsx(inputs));
|
||||||
}
|
}
|
||||||
|
|
||||||
export const isValidUrl = (url: string) => {
|
|
||||||
try {
|
|
||||||
new URL(url);
|
|
||||||
return true;
|
|
||||||
} catch {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const capitalize = (str: string) => {
|
export const capitalize = (str: string) => {
|
||||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ import {
|
|||||||
} from "@/components/ui/card";
|
} from "@/components/ui/card";
|
||||||
import { useAppContext } from "@/context/app-context";
|
import { useAppContext } from "@/context/app-context";
|
||||||
import { useUserContext } from "@/context/user-context";
|
import { useUserContext } from "@/context/user-context";
|
||||||
import { isValidUrl } from "@/lib/utils";
|
|
||||||
import { Trans, useTranslation } from "react-i18next";
|
import { Trans, useTranslation } from "react-i18next";
|
||||||
import { Navigate, useLocation, useNavigate } from "react-router";
|
import { Navigate, useLocation, useNavigate } from "react-router";
|
||||||
import { useEffect, useState } from "react";
|
import { useCallback, useEffect, useRef, useState } from "react";
|
||||||
|
import { useRedirectUri } from "@/lib/hooks/redirect-uri";
|
||||||
|
|
||||||
export const ContinuePage = () => {
|
export const ContinuePage = () => {
|
||||||
const { cookieDomain, disableUiWarnings } = useAppContext();
|
const { cookieDomain, disableUiWarnings } = useAppContext();
|
||||||
@@ -20,48 +20,35 @@ export const ContinuePage = () => {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const [loading, setLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [showRedirectButton, setShowRedirectButton] = useState(false);
|
const [showRedirectButton, setShowRedirectButton] = useState(false);
|
||||||
|
const hasRedirected = useRef(false);
|
||||||
|
|
||||||
const searchParams = new URLSearchParams(search);
|
const searchParams = new URLSearchParams(search);
|
||||||
const redirectUri = searchParams.get("redirect_uri");
|
const redirectUri = searchParams.get("redirect_uri");
|
||||||
|
|
||||||
const isValidRedirectUri =
|
const { url, valid, trusted, allowedProto, httpsDowngrade } = useRedirectUri(
|
||||||
redirectUri !== null ? isValidUrl(redirectUri) : false;
|
redirectUri,
|
||||||
const redirectUriObj = isValidRedirectUri
|
cookieDomain,
|
||||||
? new URL(redirectUri as string)
|
);
|
||||||
: null;
|
|
||||||
const isTrustedRedirectUri =
|
|
||||||
redirectUriObj !== null
|
|
||||||
? redirectUriObj.hostname === cookieDomain ||
|
|
||||||
redirectUriObj.hostname.endsWith(`.${cookieDomain}`)
|
|
||||||
: false;
|
|
||||||
const isAllowedRedirectProto =
|
|
||||||
redirectUriObj !== null
|
|
||||||
? redirectUriObj.protocol === "https:" ||
|
|
||||||
redirectUriObj.protocol === "http:"
|
|
||||||
: false;
|
|
||||||
const isHttpsDowngrade =
|
|
||||||
redirectUriObj !== null
|
|
||||||
? redirectUriObj.protocol === "http:" &&
|
|
||||||
window.location.protocol === "https:"
|
|
||||||
: false;
|
|
||||||
|
|
||||||
const handleRedirect = () => {
|
const handleRedirect = useCallback(() => {
|
||||||
setLoading(true);
|
hasRedirected.current = true;
|
||||||
window.location.assign(redirectUriObj!.toString());
|
setIsLoading(true);
|
||||||
};
|
window.location.assign(url!);
|
||||||
|
}, [url]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isLoggedIn) {
|
if (!isLoggedIn) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hasRedirected.current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(!isValidRedirectUri ||
|
(!valid || !allowedProto || !trusted || httpsDowngrade) &&
|
||||||
!isAllowedRedirectProto ||
|
|
||||||
!isTrustedRedirectUri ||
|
|
||||||
isHttpsDowngrade) &&
|
|
||||||
!disableUiWarnings
|
!disableUiWarnings
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
@@ -72,7 +59,7 @@ export const ContinuePage = () => {
|
|||||||
}, 100);
|
}, 100);
|
||||||
|
|
||||||
const reveal = setTimeout(() => {
|
const reveal = setTimeout(() => {
|
||||||
setLoading(false);
|
setIsLoading(false);
|
||||||
setShowRedirectButton(true);
|
setShowRedirectButton(true);
|
||||||
}, 5000);
|
}, 5000);
|
||||||
|
|
||||||
@@ -80,22 +67,33 @@ export const ContinuePage = () => {
|
|||||||
clearTimeout(auto);
|
clearTimeout(auto);
|
||||||
clearTimeout(reveal);
|
clearTimeout(reveal);
|
||||||
};
|
};
|
||||||
});
|
}, [
|
||||||
|
isLoggedIn,
|
||||||
|
hasRedirected,
|
||||||
|
valid,
|
||||||
|
allowedProto,
|
||||||
|
trusted,
|
||||||
|
httpsDowngrade,
|
||||||
|
disableUiWarnings,
|
||||||
|
setIsLoading,
|
||||||
|
handleRedirect,
|
||||||
|
setShowRedirectButton,
|
||||||
|
]);
|
||||||
|
|
||||||
if (!isLoggedIn) {
|
if (!isLoggedIn) {
|
||||||
return (
|
return (
|
||||||
<Navigate
|
<Navigate
|
||||||
to={`/login?redirect_uri=${encodeURIComponent(redirectUri || "")}`}
|
to={`/login${redirectUri ? `?redirect_uri=${encodeURIComponent(redirectUri)}` : ""}`}
|
||||||
replace
|
replace
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isValidRedirectUri || !isAllowedRedirectProto) {
|
if (!valid || !allowedProto) {
|
||||||
return <Navigate to="/logout" replace />;
|
return <Navigate to="/logout" replace />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isTrustedRedirectUri && !disableUiWarnings) {
|
if (!trusted && !disableUiWarnings) {
|
||||||
return (
|
return (
|
||||||
<Card role="alert" aria-live="assertive" className="min-w-xs sm:min-w-sm">
|
<Card role="alert" aria-live="assertive" className="min-w-xs sm:min-w-sm">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
@@ -115,8 +113,8 @@ export const ContinuePage = () => {
|
|||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardFooter className="flex flex-col items-stretch gap-2">
|
<CardFooter className="flex flex-col items-stretch gap-2">
|
||||||
<Button
|
<Button
|
||||||
onClick={handleRedirect}
|
onClick={() => handleRedirect()}
|
||||||
loading={loading}
|
loading={isLoading}
|
||||||
variant="destructive"
|
variant="destructive"
|
||||||
>
|
>
|
||||||
{t("continueTitle")}
|
{t("continueTitle")}
|
||||||
@@ -124,7 +122,7 @@ export const ContinuePage = () => {
|
|||||||
<Button
|
<Button
|
||||||
onClick={() => navigate("/logout")}
|
onClick={() => navigate("/logout")}
|
||||||
variant="outline"
|
variant="outline"
|
||||||
disabled={loading}
|
disabled={isLoading}
|
||||||
>
|
>
|
||||||
{t("cancelTitle")}
|
{t("cancelTitle")}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -133,7 +131,7 @@ export const ContinuePage = () => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isHttpsDowngrade && !disableUiWarnings) {
|
if (httpsDowngrade && !disableUiWarnings) {
|
||||||
return (
|
return (
|
||||||
<Card role="alert" aria-live="assertive" className="min-w-xs sm:min-w-sm">
|
<Card role="alert" aria-live="assertive" className="min-w-xs sm:min-w-sm">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
@@ -151,13 +149,17 @@ export const ContinuePage = () => {
|
|||||||
</CardDescription>
|
</CardDescription>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardFooter className="flex flex-col items-stretch gap-2">
|
<CardFooter className="flex flex-col items-stretch gap-2">
|
||||||
<Button onClick={handleRedirect} loading={loading} variant="warning">
|
<Button
|
||||||
|
onClick={() => handleRedirect()}
|
||||||
|
loading={isLoading}
|
||||||
|
variant="warning"
|
||||||
|
>
|
||||||
{t("continueTitle")}
|
{t("continueTitle")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => navigate("/logout")}
|
onClick={() => navigate("/logout")}
|
||||||
variant="outline"
|
variant="outline"
|
||||||
disabled={loading}
|
disabled={isLoading}
|
||||||
>
|
>
|
||||||
{t("cancelTitle")}
|
{t("cancelTitle")}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -176,7 +178,7 @@ export const ContinuePage = () => {
|
|||||||
</CardHeader>
|
</CardHeader>
|
||||||
{showRedirectButton && (
|
{showRedirectButton && (
|
||||||
<CardFooter className="flex flex-col items-stretch">
|
<CardFooter className="flex flex-col items-stretch">
|
||||||
<Button onClick={handleRedirect}>
|
<Button onClick={() => handleRedirect()}>
|
||||||
{t("continueRedirectManually")}
|
{t("continueRedirectManually")}
|
||||||
</Button>
|
</Button>
|
||||||
</CardFooter>
|
</CardFooter>
|
||||||
|
|||||||
@@ -40,10 +40,11 @@ export const LoginPage = () => {
|
|||||||
const { providers, title, oauthAutoRedirect } = useAppContext();
|
const { providers, title, oauthAutoRedirect } = useAppContext();
|
||||||
const { search } = useLocation();
|
const { search } = useLocation();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [oauthAutoRedirectHandover, setOauthAutoRedirectHandover] =
|
|
||||||
useState(false);
|
|
||||||
const [showRedirectButton, setShowRedirectButton] = useState(false);
|
const [showRedirectButton, setShowRedirectButton] = useState(false);
|
||||||
|
|
||||||
|
const hasAutoRedirectedRef = useRef(false);
|
||||||
|
|
||||||
const redirectTimer = useRef<number | null>(null);
|
const redirectTimer = useRef<number | null>(null);
|
||||||
const redirectButtonTimer = useRef<number | null>(null);
|
const redirectButtonTimer = useRef<number | null>(null);
|
||||||
|
|
||||||
@@ -54,6 +55,11 @@ export const LoginPage = () => {
|
|||||||
compiled: compiledOIDCParams,
|
compiled: compiledOIDCParams,
|
||||||
} = useOIDCParams(searchParams);
|
} = useOIDCParams(searchParams);
|
||||||
|
|
||||||
|
const [isOauthAutoRedirect, setIsOauthAutoRedirect] = useState(
|
||||||
|
providers.find((provider) => provider.id === oauthAutoRedirect) !==
|
||||||
|
undefined && props.redirect_uri,
|
||||||
|
);
|
||||||
|
|
||||||
const oauthProviders = providers.filter(
|
const oauthProviders = providers.filter(
|
||||||
(provider) => provider.id !== "local" && provider.id !== "ldap",
|
(provider) => provider.id !== "local" && provider.id !== "ldap",
|
||||||
);
|
);
|
||||||
@@ -62,10 +68,15 @@ export const LoginPage = () => {
|
|||||||
(provider) => provider.id === "local" || provider.id === "ldap",
|
(provider) => provider.id === "local" || provider.id === "ldap",
|
||||||
) !== undefined;
|
) !== undefined;
|
||||||
|
|
||||||
const oauthMutation = useMutation({
|
const {
|
||||||
|
mutate: oauthMutate,
|
||||||
|
data: oauthData,
|
||||||
|
isPending: oauthIsPending,
|
||||||
|
variables: oauthVariables,
|
||||||
|
} = useMutation({
|
||||||
mutationFn: (provider: string) =>
|
mutationFn: (provider: string) =>
|
||||||
axios.get(
|
axios.get(
|
||||||
`/api/oauth/url/${provider}?redirect_uri=${encodeURIComponent(props.redirect_uri)}`,
|
`/api/oauth/url/${provider}${props.redirect_uri ? `?redirect_uri=${encodeURIComponent(props.redirect_uri)}` : ""}`,
|
||||||
),
|
),
|
||||||
mutationKey: ["oauth"],
|
mutationKey: ["oauth"],
|
||||||
onSuccess: (data) => {
|
onSuccess: (data) => {
|
||||||
@@ -76,22 +87,28 @@ export const LoginPage = () => {
|
|||||||
redirectTimer.current = window.setTimeout(() => {
|
redirectTimer.current = window.setTimeout(() => {
|
||||||
window.location.replace(data.data.url);
|
window.location.replace(data.data.url);
|
||||||
}, 500);
|
}, 500);
|
||||||
|
|
||||||
|
if (isOauthAutoRedirect) {
|
||||||
|
redirectButtonTimer.current = window.setTimeout(() => {
|
||||||
|
setShowRedirectButton(true);
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onError: () => {
|
onError: () => {
|
||||||
setOauthAutoRedirectHandover(false);
|
setIsOauthAutoRedirect(false);
|
||||||
toast.error(t("loginOauthFailTitle"), {
|
toast.error(t("loginOauthFailTitle"), {
|
||||||
description: t("loginOauthFailSubtitle"),
|
description: t("loginOauthFailSubtitle"),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const loginMutation = useMutation({
|
const { mutate: loginMutate, isPending: loginIsPending } = useMutation({
|
||||||
mutationFn: (values: LoginSchema) => axios.post("/api/user/login", values),
|
mutationFn: (values: LoginSchema) => axios.post("/api/user/login", values),
|
||||||
mutationKey: ["login"],
|
mutationKey: ["login"],
|
||||||
onSuccess: (data) => {
|
onSuccess: (data) => {
|
||||||
if (data.data.totpPending) {
|
if (data.data.totpPending) {
|
||||||
window.location.replace(
|
window.location.replace(
|
||||||
`/totp?redirect_uri=${encodeURIComponent(props.redirect_uri)}`,
|
`/totp${props.redirect_uri ? `?redirect_uri=${encodeURIComponent(props.redirect_uri)}` : ""}`,
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -106,7 +123,7 @@ export const LoginPage = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
window.location.replace(
|
window.location.replace(
|
||||||
`/continue?redirect_uri=${encodeURIComponent(props.redirect_uri)}`,
|
`/continue${props.redirect_uri ? `?redirect_uri=${encodeURIComponent(props.redirect_uri)}` : ""}`,
|
||||||
);
|
);
|
||||||
}, 500);
|
}, 500);
|
||||||
},
|
},
|
||||||
@@ -122,34 +139,34 @@ export const LoginPage = () => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (
|
if (
|
||||||
providers.find((provider) => provider.id === oauthAutoRedirect) &&
|
|
||||||
!isLoggedIn &&
|
!isLoggedIn &&
|
||||||
props.redirect_uri !== ""
|
isOauthAutoRedirect &&
|
||||||
|
!hasAutoRedirectedRef.current &&
|
||||||
|
props.redirect_uri
|
||||||
) {
|
) {
|
||||||
// Not sure of a better way to do this
|
hasAutoRedirectedRef.current = true;
|
||||||
// eslint-disable-next-line react-hooks/set-state-in-effect
|
oauthMutate(oauthAutoRedirect);
|
||||||
setOauthAutoRedirectHandover(true);
|
|
||||||
oauthMutation.mutate(oauthAutoRedirect);
|
|
||||||
redirectButtonTimer.current = window.setTimeout(() => {
|
|
||||||
setShowRedirectButton(true);
|
|
||||||
}, 5000);
|
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
providers,
|
|
||||||
isLoggedIn,
|
isLoggedIn,
|
||||||
props.redirect_uri,
|
oauthMutate,
|
||||||
|
hasAutoRedirectedRef,
|
||||||
oauthAutoRedirect,
|
oauthAutoRedirect,
|
||||||
oauthMutation,
|
isOauthAutoRedirect,
|
||||||
|
props.redirect_uri,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
useEffect(
|
useEffect(() => {
|
||||||
() => () => {
|
return () => {
|
||||||
if (redirectTimer.current) clearTimeout(redirectTimer.current);
|
if (redirectTimer.current) {
|
||||||
if (redirectButtonTimer.current)
|
clearTimeout(redirectTimer.current);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (redirectButtonTimer.current) {
|
||||||
clearTimeout(redirectButtonTimer.current);
|
clearTimeout(redirectButtonTimer.current);
|
||||||
},
|
}
|
||||||
[],
|
};
|
||||||
);
|
}, [redirectTimer, redirectButtonTimer]);
|
||||||
|
|
||||||
if (isLoggedIn && isOidc) {
|
if (isLoggedIn && isOidc) {
|
||||||
return <Navigate to={`/authorize?${compiledOIDCParams}`} replace />;
|
return <Navigate to={`/authorize?${compiledOIDCParams}`} replace />;
|
||||||
@@ -158,7 +175,7 @@ export const LoginPage = () => {
|
|||||||
if (isLoggedIn && props.redirect_uri !== "") {
|
if (isLoggedIn && props.redirect_uri !== "") {
|
||||||
return (
|
return (
|
||||||
<Navigate
|
<Navigate
|
||||||
to={`/continue?redirect_uri=${encodeURIComponent(props.redirect_uri)}`}
|
to={`/continue${props.redirect_uri ? `?redirect_uri=${encodeURIComponent(props.redirect_uri)}` : ""}`}
|
||||||
replace
|
replace
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@@ -168,7 +185,7 @@ export const LoginPage = () => {
|
|||||||
return <Navigate to="/logout" replace />;
|
return <Navigate to="/logout" replace />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oauthAutoRedirectHandover) {
|
if (isOauthAutoRedirect) {
|
||||||
return (
|
return (
|
||||||
<Card className="min-w-xs sm:min-w-sm">
|
<Card className="min-w-xs sm:min-w-sm">
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
@@ -183,7 +200,14 @@ export const LoginPage = () => {
|
|||||||
<CardFooter className="flex flex-col items-stretch">
|
<CardFooter className="flex flex-col items-stretch">
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
window.location.replace(oauthMutation.data?.data.url);
|
if (oauthData?.data.url) {
|
||||||
|
window.location.replace(oauthData.data.url);
|
||||||
|
} else {
|
||||||
|
setIsOauthAutoRedirect(false);
|
||||||
|
toast.error(t("loginOauthFailTitle"), {
|
||||||
|
description: t("loginOauthFailSubtitle"),
|
||||||
|
});
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t("loginOauthAutoRedirectButton")}
|
{t("loginOauthAutoRedirectButton")}
|
||||||
@@ -214,12 +238,9 @@ export const LoginPage = () => {
|
|||||||
title={provider.name}
|
title={provider.name}
|
||||||
icon={iconMap[provider.id] ?? <OAuthIcon />}
|
icon={iconMap[provider.id] ?? <OAuthIcon />}
|
||||||
className="w-full"
|
className="w-full"
|
||||||
onClick={() => oauthMutation.mutate(provider.id)}
|
onClick={() => oauthMutate(provider.id)}
|
||||||
loading={
|
loading={oauthIsPending && oauthVariables === provider.id}
|
||||||
oauthMutation.isPending &&
|
disabled={oauthIsPending || loginIsPending}
|
||||||
oauthMutation.variables === provider.id
|
|
||||||
}
|
|
||||||
disabled={oauthMutation.isPending || loginMutation.isPending}
|
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@@ -229,8 +250,8 @@ export const LoginPage = () => {
|
|||||||
)}
|
)}
|
||||||
{userAuthConfigured && (
|
{userAuthConfigured && (
|
||||||
<LoginForm
|
<LoginForm
|
||||||
onSubmit={(values) => loginMutation.mutate(values)}
|
onSubmit={(values) => loginMutate(values)}
|
||||||
loading={loginMutation.isPending || oauthMutation.isPending}
|
loading={loginIsPending || oauthIsPending}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{providers.length == 0 && (
|
{providers.length == 0 && (
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export const LogoutPage = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
redirectTimer.current = window.setTimeout(() => {
|
redirectTimer.current = window.setTimeout(() => {
|
||||||
window.location.assign("/login");
|
window.location.replace("/login");
|
||||||
}, 500);
|
}, 500);
|
||||||
},
|
},
|
||||||
onError: () => {
|
onError: () => {
|
||||||
@@ -39,12 +39,13 @@ export const LogoutPage = () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(
|
useEffect(() => {
|
||||||
() => () => {
|
return () => {
|
||||||
if (redirectTimer.current) clearTimeout(redirectTimer.current);
|
if (redirectTimer.current) {
|
||||||
},
|
clearTimeout(redirectTimer.current);
|
||||||
[],
|
}
|
||||||
);
|
};
|
||||||
|
}, [redirectTimer]);
|
||||||
|
|
||||||
if (!isLoggedIn) {
|
if (!isLoggedIn) {
|
||||||
return <Navigate to="/login" replace />;
|
return <Navigate to="/login" replace />;
|
||||||
|
|||||||
@@ -45,11 +45,11 @@ export const TotpPage = () => {
|
|||||||
if (isOidc) {
|
if (isOidc) {
|
||||||
window.location.replace(`/authorize?${compiledOIDCParams}`);
|
window.location.replace(`/authorize?${compiledOIDCParams}`);
|
||||||
return;
|
return;
|
||||||
} else {
|
|
||||||
window.location.replace(
|
|
||||||
`/continue?redirect_uri=${encodeURIComponent(props.redirect_uri)}`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.location.replace(
|
||||||
|
`/continue${props.redirect_uri ? `?redirect_uri=${encodeURIComponent(props.redirect_uri)}` : ""}`,
|
||||||
|
);
|
||||||
}, 500);
|
}, 500);
|
||||||
},
|
},
|
||||||
onError: () => {
|
onError: () => {
|
||||||
@@ -59,12 +59,13 @@ export const TotpPage = () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(
|
useEffect(() => {
|
||||||
() => () => {
|
return () => {
|
||||||
if (redirectTimer.current) clearTimeout(redirectTimer.current);
|
if (redirectTimer.current) {
|
||||||
},
|
clearTimeout(redirectTimer.current);
|
||||||
[],
|
}
|
||||||
);
|
};
|
||||||
|
}, [redirectTimer]);
|
||||||
|
|
||||||
if (!totpPending) {
|
if (!totpPending) {
|
||||||
return <Navigate to="/" replace />;
|
return <Navigate to="/" replace />;
|
||||||
|
|||||||
Reference in New Issue
Block a user