mirror of
https://github.com/tinyauthapp/tinyauth.git
synced 2026-09-07 23:13:32 +08:00
Merge branch 'main' into feat/oidc-consent-screen
# Conflicts: # internal/controller/oidc_controller.go # internal/model/runtime.go
This commit is contained in:
+29
-29
@@ -12,49 +12,49 @@
|
||||
},
|
||||
"packageManager": "pnpm@11.1.2",
|
||||
"dependencies": {
|
||||
"@hookform/resolvers": "^5.4.0",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.19",
|
||||
"@radix-ui/react-label": "^2.1.11",
|
||||
"@radix-ui/react-select": "^2.3.2",
|
||||
"@radix-ui/react-separator": "^1.1.11",
|
||||
"@radix-ui/react-slot": "^1.3.0",
|
||||
"@tailwindcss/vite": "^4.3.2",
|
||||
"@tanstack/react-query": "^5.101.2",
|
||||
"axios": "^1.18.1",
|
||||
"@hookform/resolvers": "^5.7.1",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.24",
|
||||
"@radix-ui/react-label": "^2.1.15",
|
||||
"@radix-ui/react-select": "^2.3.7",
|
||||
"@radix-ui/react-separator": "^1.1.15",
|
||||
"@radix-ui/react-slot": "^1.3.3",
|
||||
"@tailwindcss/vite": "^4.3.3",
|
||||
"@tanstack/react-query": "^5.101.4",
|
||||
"axios": "^1.19.0",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"i18next": "^26.3.4",
|
||||
"i18next": "^26.3.6",
|
||||
"i18next-browser-languagedetector": "^8.2.1",
|
||||
"i18next-resources-to-backend": "^1.2.1",
|
||||
"lucide-react": "^1.23.0",
|
||||
"i18next-resources-to-backend": "^1.2.3",
|
||||
"lucide-react": "^1.31.0",
|
||||
"next-themes": "^0.4.6",
|
||||
"radix-ui": "^1.6.1",
|
||||
"react": "^19.2.7",
|
||||
"react-dom": "^19.2.7",
|
||||
"react-hook-form": "^7.81.0",
|
||||
"react-i18next": "^17.0.8",
|
||||
"radix-ui": "^1.6.7",
|
||||
"react": "^19.2.8",
|
||||
"react-dom": "^19.2.8",
|
||||
"react-hook-form": "^7.85.0",
|
||||
"react-i18next": "^17.0.11",
|
||||
"react-markdown": "^10.1.0",
|
||||
"react-router": "^8.1.0",
|
||||
"sonner": "^2.0.7",
|
||||
"react-router": "^8.3.0",
|
||||
"sonner": "^2.0.8",
|
||||
"tailwind-merge": "^3.5.0",
|
||||
"tailwindcss": "^4.3.2",
|
||||
"tailwindcss": "^4.3.3",
|
||||
"zod": "^4.3.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@tanstack/eslint-plugin-query": "^5.101.2",
|
||||
"@types/node": "^26.1.0",
|
||||
"@types/react": "^19.2.17",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"@vitejs/plugin-react": "^6.0.3",
|
||||
"eslint": "^10.6.0",
|
||||
"@tanstack/eslint-plugin-query": "^5.101.4",
|
||||
"@types/node": "^26.2.0",
|
||||
"@types/react": "^19.2.18",
|
||||
"@types/react-dom": "^19.2.4",
|
||||
"@vitejs/plugin-react": "^6.0.5",
|
||||
"eslint": "^10.8.1",
|
||||
"eslint-plugin-react-hooks": "^7.0.1",
|
||||
"eslint-plugin-react-refresh": "^0.5.3",
|
||||
"globals": "^17.7.0",
|
||||
"globals": "^17.9.0",
|
||||
"rollup-plugin-visualizer": "^7.0.1",
|
||||
"tw-animate-css": "^1.4.0",
|
||||
"typescript": "~6.0.2",
|
||||
"typescript-eslint": "^8.62.1",
|
||||
"vite": "^8.1.3"
|
||||
"typescript-eslint": "^8.66.0",
|
||||
"vite": "^8.2.1"
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+1502
-1274
File diff suppressed because it is too large
Load Diff
@@ -32,8 +32,8 @@ import { useTranslation } from "react-i18next";
|
||||
import { useLocation } from "react-router";
|
||||
import { useRef } from "react";
|
||||
import {
|
||||
searchParamsFromObject,
|
||||
useScreenParams,
|
||||
recompileScreenParams,
|
||||
} from "@/lib/hooks/screen-params";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import axios from "axios";
|
||||
@@ -70,7 +70,13 @@ export const QuickActions = () => {
|
||||
const redirectTimer = useRef<number | null>(null);
|
||||
const searchParams = new URLSearchParams(search);
|
||||
const screenParams = useScreenParams(searchParams);
|
||||
const compiledParams = recompileScreenParams(screenParams);
|
||||
const compiledParams = (() => {
|
||||
const params = searchParamsFromObject(screenParams).toString();
|
||||
if (params.length > 0) {
|
||||
return `?${params}`;
|
||||
}
|
||||
return "";
|
||||
})();
|
||||
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
type UseLoginForProps = {
|
||||
login_for?: "oidc" | "app";
|
||||
compiledParams: string;
|
||||
params: URLSearchParams;
|
||||
};
|
||||
|
||||
export const useLoginFor = (props: UseLoginForProps): string => {
|
||||
const { login_for, compiledParams } = props;
|
||||
const { login_for, params } = props;
|
||||
const compiledParams = params.toString() ? "?" + params.toString() : "";
|
||||
|
||||
switch (login_for) {
|
||||
case "oidc":
|
||||
@@ -12,6 +13,9 @@ export const useLoginFor = (props: UseLoginForProps): string => {
|
||||
case "app":
|
||||
return "/continue" + compiledParams;
|
||||
default:
|
||||
if (params.get("redirect_uri")) {
|
||||
return "/continue" + compiledParams
|
||||
}
|
||||
return "/logout";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -75,18 +75,21 @@ export const useRedirectUri = (
|
||||
};
|
||||
};
|
||||
|
||||
// ported from internal/controller/oauth_controller.go
|
||||
const getEffectivePort = (url: URL): string => {
|
||||
if (url.port) {
|
||||
return url.port;
|
||||
}
|
||||
// https://www.geeksforgeeks.org/javascript/how-to-check-if-a-string-is-a-valid-ip-address-format-in-javascript
|
||||
const isIP = (str: string): boolean => {
|
||||
const ipv4 =
|
||||
/^(\d{1,3}\.){3}\d{1,3}$/;
|
||||
const ipv6 =
|
||||
/^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/;
|
||||
return ipv4.test(str) || ipv6.test(str) || str.startsWith("[");
|
||||
}
|
||||
|
||||
if (url.protocol == "https:") {
|
||||
return "443";
|
||||
const trimPeriod = (str: string): string => {
|
||||
if(str.lastIndexOf('.') === (str.length - 1)){
|
||||
str = str.substring(0, str.length - 1);
|
||||
}
|
||||
|
||||
return "80";
|
||||
};
|
||||
return str
|
||||
}
|
||||
|
||||
export const isTrustedDomain = (
|
||||
url: URL,
|
||||
@@ -94,15 +97,15 @@ export const isTrustedDomain = (
|
||||
cookieDomain: string,
|
||||
subdomainsEnabled: boolean,
|
||||
): boolean => {
|
||||
if (url.protocol != appUrl.protocol) {
|
||||
if (isIP(url.hostname)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (getEffectivePort(url) != getEffectivePort(appUrl)) {
|
||||
if (url.port != appUrl.port) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (url.hostname == appUrl.hostname) {
|
||||
if (trimPeriod(url.hostname) == trimPeriod(appUrl.hostname)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -110,9 +113,6 @@ export const isTrustedDomain = (
|
||||
return false;
|
||||
}
|
||||
|
||||
if (url.hostname.endsWith("." + cookieDomain.toLowerCase())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return trimPeriod(url.hostname).endsWith("." + cookieDomain.toLowerCase())
|
||||
|| trimPeriod(url.hostname) == cookieDomain.toLowerCase();
|
||||
};
|
||||
|
||||
@@ -27,16 +27,10 @@ export function useScreenParams(params: URLSearchParams): ScreenParams {
|
||||
return parsed.data;
|
||||
}
|
||||
|
||||
export function recompileScreenParams(params: ScreenParams): string {
|
||||
const p = new URLSearchParams(
|
||||
export function searchParamsFromObject(obj: object): URLSearchParams {
|
||||
return new URLSearchParams(
|
||||
Object.fromEntries(
|
||||
Object.entries(params).filter(([, v]) => v !== undefined),
|
||||
Object.entries(obj).filter(([, v]) => v !== undefined),
|
||||
) as Record<string, string>,
|
||||
).toString();
|
||||
|
||||
if (p.length > 0) {
|
||||
return "?" + p;
|
||||
}
|
||||
|
||||
return "";
|
||||
);
|
||||
}
|
||||
|
||||
@@ -15,16 +15,16 @@
|
||||
"loginOauthSuccessTitle": "Přesměrování",
|
||||
"loginOauthSuccessSubtitle": "Přesměrování k poskytovateli OAuth",
|
||||
"loginOauthAutoRedirectTitle": "Automatické přesměrování OAuth",
|
||||
"loginOauthAutoRedirectSubtitle": "You will be automatically redirected to your OAuth provider to authenticate.",
|
||||
"loginOauthAutoRedirectButton": "Redirect now",
|
||||
"loginOauthAutoRedirectSubtitle": "Pro ověření budete automaticky přesměrování na svého poskytovatele OAuth.",
|
||||
"loginOauthAutoRedirectButton": "Přesměrovat nyní",
|
||||
"continueTitle": "Pokračovat",
|
||||
"continueRedirectingTitle": "Přesměrování...",
|
||||
"continueRedirectingSubtitle": "Brzy budete přesměrováni do aplikace",
|
||||
"continueRedirectManually": "Redirect me manually",
|
||||
"continueRedirectManually": "Přesměrovat ručně",
|
||||
"continueInsecureRedirectTitle": "Nezabezpečené přesměrování",
|
||||
"continueInsecureRedirectSubtitle": "Pokoušíte se přesměrovat z <code>https</code> na <code>http</code>, které není bezpečné. Opravdu chcete pokračovat?",
|
||||
"continueUntrustedRedirectTitle": "Untrusted redirect",
|
||||
"continueUntrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<code>{{cookieDomain}}</code>). Are you sure you want to continue?",
|
||||
"continueUntrustedRedirectTitle": "Nedůvěryhodné přesměrování",
|
||||
"continueUntrustedRedirectSubtitle": "Pokoušíte se přesměrovat na doménu, která neodpovídá vaší nakonfigurované doméně (<code>{{cookieDomain}}</code>). Opravdu chcete pokračovat?",
|
||||
"logoutFailTitle": "Odhlášení se nezdařilo",
|
||||
"logoutFailSubtitle": "Zkuste to prosím znovu",
|
||||
"logoutSuccessTitle": "Odhlášen",
|
||||
@@ -51,53 +51,53 @@
|
||||
"forgotPasswordTitle": "Zapomněli jste heslo?",
|
||||
"failedToFetchProvidersTitle": "Nepodařilo se načíst poskytovatele ověřování. Zkontrolujte prosím konfiguraci.",
|
||||
"errorTitle": "Došlo k chybě",
|
||||
"errorSubtitleInfo": "The following error occurred while processing your request:",
|
||||
"errorSubtitleInfo": "Při zpracování požadavku došlo k následující chybě:",
|
||||
"errorSubtitle": "Nastala chyba při pokusu o provedení této akce. Pro více informací prosím zkontrolujte konzolu.",
|
||||
"forgotPasswordMessage": "Heslo můžete obnovit změnou proměnné `USERS`.",
|
||||
"fieldRequired": "Toto pole je povinné",
|
||||
"invalidInput": "Neplatný údaj",
|
||||
"domainWarningTitle": "Invalid Domain",
|
||||
"domainWarningSubtitle": "You are accessing this instance from an incorrect domain. If you proceed, you may encounter issues with authentication.",
|
||||
"domainWarningCurrent": "Current:",
|
||||
"domainWarningExpected": "Expected:",
|
||||
"ignoreTitle": "Ignore",
|
||||
"goToCorrectDomainTitle": "Go to correct domain",
|
||||
"authorizeTitle": "Authorize",
|
||||
"authorizeCardTitle": "Continue to {{app}}?",
|
||||
"authorizeSubtitle": "Would you like to continue to this app? Please carefully review the permissions requested by the app.",
|
||||
"authorizeSubtitleOAuth": "Would you like to continue to this app?",
|
||||
"authorizeLoadingTitle": "Loading...",
|
||||
"domainWarningTitle": "Neplatná doména",
|
||||
"domainWarningSubtitle": "Pro přístup k této instanci používáte špatnou doménu. Při pokračování mohou nastat problémy s autentizací.",
|
||||
"domainWarningCurrent": "Aktuální:",
|
||||
"domainWarningExpected": "Vyžadovaná:",
|
||||
"ignoreTitle": "Ignorovat",
|
||||
"goToCorrectDomainTitle": "Přejít na správnou doménu",
|
||||
"authorizeTitle": "Autorizovat",
|
||||
"authorizeCardTitle": "Pokračovat do {{app}}?",
|
||||
"authorizeSubtitle": "Chcete pokračovat do této aplikace? Pečlivě si zkontrolujte jí vyžadovaná oprávnění, prosím.",
|
||||
"authorizeSubtitleOAuth": "Chcete pokračovat do této aplikace?",
|
||||
"authorizeLoadingTitle": "Načítání...",
|
||||
"authorizeLoadingSubtitle": "Please wait while we load the client information.",
|
||||
"authorizeSuccessTitle": "Authorized",
|
||||
"authorizeSuccessSubtitle": "You will be redirected to the app in a few seconds.",
|
||||
"authorizeErrorClientInfo": "An error occurred while loading the client information. Please try again later.",
|
||||
"authorizeErrorInvalidParams": "The request is missing required parameters or has invalid parameters. Please check the URL and try again.",
|
||||
"authorizeSuccessTitle": "Autorizováno",
|
||||
"authorizeSuccessSubtitle": "Během několika vteřin budete přesměrováni do aplikace.",
|
||||
"authorizeErrorClientInfo": "Při načítání klientských informací došlo k chybě. Zkuste to prosím později.",
|
||||
"authorizeErrorInvalidParams": "Parametry požadavku jsou chybné/neplatné. Prosím, zkontrolujte URL a zkuste znovu.",
|
||||
"openidScopeName": "OpenID Connect",
|
||||
"openidScopeDescription": "Allows the app to access your OpenID Connect information.",
|
||||
"emailScopeName": "Email",
|
||||
"emailScopeDescription": "Allows the app to access your email address.",
|
||||
"profileScopeName": "Profile",
|
||||
"profileScopeDescription": "Allows the app to access your profile information.",
|
||||
"groupsScopeName": "Groups",
|
||||
"groupsScopeDescription": "Allows the app to access your group information.",
|
||||
"backToLoginButton": "Back to login",
|
||||
"phoneScopeName": "Phone",
|
||||
"phoneScopeDescription": "Allows the app to access your phone number.",
|
||||
"addressScopeName": "Address",
|
||||
"addressScopeDescription": "Allows the app to access your address.",
|
||||
"loginTailscaleTitle": "Continue with Tailscale",
|
||||
"openidScopeDescription": "Povolí aplikaci přístup k Vaším informacím OpenID Connect.",
|
||||
"emailScopeName": "E-mail",
|
||||
"emailScopeDescription": "Povolí aplikaci přístup k Vaší e-mailové adrese.",
|
||||
"profileScopeName": "Profil",
|
||||
"profileScopeDescription": "Povolí aplikaci přístup k informacím o Vašem profilu.",
|
||||
"groupsScopeName": "Skupiny",
|
||||
"groupsScopeDescription": "Povolí aplikaci přístup k informacím o Vaší skupině.",
|
||||
"backToLoginButton": "Zpět na přihlášení",
|
||||
"phoneScopeName": "Telefon",
|
||||
"phoneScopeDescription": "Povolí aplikaci přístup k Vašemu telefonnímu číslu.",
|
||||
"addressScopeName": "Adresa",
|
||||
"addressScopeDescription": "Povolí aplikaci přístup k Vaší adrese.",
|
||||
"loginTailscaleTitle": "Pokračovat přes Tailscale",
|
||||
"loginTailscaleDescription": "You appear to be accessing Tinyauth from an authorized Tailscale device. Would you like to continue with your Tailscale connection?",
|
||||
"loginTailscaleDeviceName": "Device name:",
|
||||
"loginTailscaleOtherMethod": "Login with another method",
|
||||
"loginTailscaleSuccess": "Successfully authenticated with Tailscale.",
|
||||
"loginTailscaleFail": "Failed to authenticate with Tailscale. Please try again or use another login method.",
|
||||
"loginTailscaleDeviceName": "Název zařízení:",
|
||||
"loginTailscaleOtherMethod": "Přihlásit jinou metodou",
|
||||
"loginTailscaleSuccess": "Úspěšně přihlášeno přes Tailscale.",
|
||||
"loginTailscaleFail": "Chyba při přihlášení přes Tailscale. Zkuste znovu, případně se přihlašte jiným způsobem, prosím.",
|
||||
"logoutTailscaleSubtitle": "You are currently logged in with Tailscale on your device <code>{{deviceName}}</code>. Click the button below to logout.",
|
||||
"quickActionsLanguage": "Language",
|
||||
"quickActionsTheme": "Theme",
|
||||
"quickActionsThemeLight": "Light",
|
||||
"quickActionsThemeDark": "Dark",
|
||||
"quickActionsThemeSystem": "System",
|
||||
"quickActionsLogout": "Logout",
|
||||
"quickActionsLanguage": "Jazyk",
|
||||
"quickActionsTheme": "Motiv",
|
||||
"quickActionsThemeLight": "Světlý",
|
||||
"quickActionsThemeDark": "Tmavý",
|
||||
"quickActionsThemeSystem": "Systémový",
|
||||
"quickActionsLogout": "Odhlásit se",
|
||||
"quickActionsTitle": "Quick Actions",
|
||||
"quickActionsProviderLocal": "Local",
|
||||
"quickActionsProviderLDAP": "LDAP",
|
||||
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import {
|
||||
recompileScreenParams,
|
||||
searchParamsFromObject,
|
||||
useScreenParams,
|
||||
} from "@/lib/hooks/screen-params";
|
||||
import { useEffect } from "react";
|
||||
@@ -89,7 +89,13 @@ export const AuthorizePage = () => {
|
||||
const searchParams = new URLSearchParams(search);
|
||||
const screenParams = useScreenParams(searchParams);
|
||||
const isOidc = screenParams.login_for === "oidc";
|
||||
const compiledParams = recompileScreenParams(screenParams);
|
||||
const compiledParams = (() => {
|
||||
const params = searchParamsFromObject(screenParams).toString();
|
||||
if (params.length > 0) {
|
||||
return `?${params}`;
|
||||
}
|
||||
return "";
|
||||
})();
|
||||
|
||||
// TODO: maybe a better way to do this
|
||||
const shouldAutoAuthorize =
|
||||
|
||||
@@ -13,7 +13,7 @@ import { Navigate, useLocation, useNavigate } from "react-router";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { useRedirectUri } from "@/lib/hooks/redirect-uri";
|
||||
import {
|
||||
recompileScreenParams,
|
||||
searchParamsFromObject,
|
||||
useScreenParams,
|
||||
} from "@/lib/hooks/screen-params";
|
||||
|
||||
@@ -31,8 +31,14 @@ export const ContinuePage = () => {
|
||||
const searchParams = new URLSearchParams(search);
|
||||
const screenParams = useScreenParams(searchParams);
|
||||
const redirectUri = screenParams.redirect_uri;
|
||||
const isAppLogin = screenParams.login_for === "app";
|
||||
const recompiledParams = recompileScreenParams(screenParams);
|
||||
const isAppLogin = screenParams.login_for === "app" || !screenParams.login_for;
|
||||
const compiledParams = (() => {
|
||||
const params = searchParamsFromObject(screenParams).toString();
|
||||
if (params.length > 0) {
|
||||
return `?${params}`;
|
||||
}
|
||||
return "";
|
||||
})();
|
||||
|
||||
const { url, valid, trusted, allowedProto, httpsDowngrade } = useRedirectUri(
|
||||
redirectUri,
|
||||
@@ -89,7 +95,7 @@ export const ContinuePage = () => {
|
||||
}, [shouldAutoRedirect, redirectToTarget]);
|
||||
|
||||
if (!auth.authenticated) {
|
||||
return <Navigate to={`/login${recompiledParams}`} replace />;
|
||||
return <Navigate to={`/login${compiledParams}`} replace />;
|
||||
}
|
||||
|
||||
if (!hasValidRedirect || !isAppLogin) {
|
||||
|
||||
@@ -12,8 +12,8 @@ import { useTranslation } from "react-i18next";
|
||||
import Markdown from "react-markdown";
|
||||
import { useLocation } from "react-router";
|
||||
import {
|
||||
recompileScreenParams,
|
||||
useScreenParams,
|
||||
searchParamsFromObject,
|
||||
useScreenParams,
|
||||
} from "@/lib/hooks/screen-params";
|
||||
|
||||
export const ForgotPasswordPage = () => {
|
||||
@@ -22,7 +22,13 @@ export const ForgotPasswordPage = () => {
|
||||
const { search } = useLocation();
|
||||
const searchParams = new URLSearchParams(search);
|
||||
const screenParams = useScreenParams(searchParams);
|
||||
const compiledParams = recompileScreenParams(screenParams);
|
||||
const compiledParams = (() => {
|
||||
const params = searchParamsFromObject(screenParams).toString();
|
||||
if (params.length > 0) {
|
||||
return `?${params}`;
|
||||
}
|
||||
return "";
|
||||
})();
|
||||
|
||||
return (
|
||||
<Card>
|
||||
|
||||
@@ -26,7 +26,7 @@ import { useTranslation } from "react-i18next";
|
||||
import { Navigate, useLocation } from "react-router";
|
||||
import { toast } from "sonner";
|
||||
import {
|
||||
recompileScreenParams,
|
||||
searchParamsFromObject,
|
||||
useScreenParams,
|
||||
} from "@/lib/hooks/screen-params";
|
||||
import { useLoginFor } from "@/lib/hooks/login-for";
|
||||
@@ -63,18 +63,21 @@ export const LoginPage = () => {
|
||||
|
||||
const searchParams = new URLSearchParams(search);
|
||||
const screenParams = useScreenParams(searchParams);
|
||||
const compiledParams = recompileScreenParams({
|
||||
...screenParams,
|
||||
oidc_prompt: undefined,
|
||||
});
|
||||
const compiledParams = (() => {
|
||||
const params = searchParamsFromObject(screenParams).toString();
|
||||
if (params.length > 0) {
|
||||
return `?${params}`;
|
||||
}
|
||||
return "";
|
||||
})();
|
||||
const loginForUrl = useLoginFor({
|
||||
login_for: screenParams.login_for,
|
||||
compiledParams,
|
||||
params: searchParamsFromObject({ ...screenParams, oidc_prompt: undefined}),
|
||||
});
|
||||
|
||||
const [isOauthAutoRedirect, setIsOauthAutoRedirect] = useState(
|
||||
providers.find((provider) => provider.id === oauth.autoRedirect) !==
|
||||
undefined && screenParams.redirect_uri !== undefined,
|
||||
undefined && (screenParams.redirect_uri || screenParams.oidc_ticket),
|
||||
);
|
||||
|
||||
const oauthProviders = providers.filter(
|
||||
@@ -171,8 +174,7 @@ export const LoginPage = () => {
|
||||
!auth.authenticated &&
|
||||
isOauthAutoRedirect &&
|
||||
!hasAutoRedirectedRef.current &&
|
||||
screenParams.redirect_uri &&
|
||||
screenParams.login_for
|
||||
(screenParams.redirect_uri || screenParams.oidc_ticket)
|
||||
) {
|
||||
hasAutoRedirectedRef.current = true;
|
||||
oauthMutate(oauth.autoRedirect);
|
||||
@@ -183,8 +185,8 @@ export const LoginPage = () => {
|
||||
hasAutoRedirectedRef,
|
||||
oauth.autoRedirect,
|
||||
isOauthAutoRedirect,
|
||||
screenParams.login_for,
|
||||
screenParams.redirect_uri,
|
||||
screenParams.oidc_ticket
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -17,8 +17,8 @@ import { type UseMutationResult } from "@tanstack/react-query";
|
||||
import { type AxiosResponse } from "axios";
|
||||
import { useLocation } from "react-router";
|
||||
import {
|
||||
searchParamsFromObject,
|
||||
useScreenParams,
|
||||
recompileScreenParams,
|
||||
} from "@/lib/hooks/screen-params";
|
||||
|
||||
export const LogoutPage = () => {
|
||||
@@ -29,7 +29,13 @@ export const LogoutPage = () => {
|
||||
const redirectTimer = useRef<number | null>(null);
|
||||
const searchParams = new URLSearchParams(search);
|
||||
const screenParams = useScreenParams(searchParams);
|
||||
const compiledParams = recompileScreenParams(screenParams);
|
||||
const compiledParams = (() => {
|
||||
const params = searchParamsFromObject(screenParams).toString();
|
||||
if (params.length > 0) {
|
||||
return `?${params}`;
|
||||
}
|
||||
return "";
|
||||
})();
|
||||
|
||||
const logoutMutation = useMutation({
|
||||
mutationFn: () => axios.post("/api/user/logout"),
|
||||
|
||||
@@ -17,7 +17,7 @@ import { useTranslation } from "react-i18next";
|
||||
import { Navigate, useLocation } from "react-router";
|
||||
import { toast } from "sonner";
|
||||
import {
|
||||
recompileScreenParams,
|
||||
searchParamsFromObject,
|
||||
useScreenParams,
|
||||
} from "@/lib/hooks/screen-params";
|
||||
import { useLoginFor } from "@/lib/hooks/login-for";
|
||||
@@ -32,10 +32,16 @@ export const TotpPage = () => {
|
||||
|
||||
const searchParams = new URLSearchParams(search);
|
||||
const screenParams = useScreenParams(searchParams);
|
||||
const compiledParams = recompileScreenParams(screenParams);
|
||||
const compiledParams = (() => {
|
||||
const params = searchParamsFromObject(screenParams).toString();
|
||||
if (params.length > 0) {
|
||||
return `?${params}`;
|
||||
}
|
||||
return "";
|
||||
})();
|
||||
const loginForUrl = useLoginFor({
|
||||
login_for: screenParams.login_for,
|
||||
compiledParams,
|
||||
params: searchParamsFromObject(screenParams),
|
||||
});
|
||||
|
||||
const totpMutation = useMutation({
|
||||
|
||||
Reference in New Issue
Block a user