From cddb29fef6363de066ca576787dc2f0148e7a21a Mon Sep 17 00:00:00 2001 From: lendry Date: Tue, 7 Jul 2026 08:14:26 +0300 Subject: [PATCH] fix and update --- apps/frontend/app/auth/login/page.tsx | 2 -- apps/frontend/components/id/auth-provider.tsx | 20 +++++++++-- apps/frontend/lib/auth-post-pin-redirect.ts | 33 +++++++++++++++++++ 3 files changed, 50 insertions(+), 5 deletions(-) create mode 100644 apps/frontend/lib/auth-post-pin-redirect.ts diff --git a/apps/frontend/app/auth/login/page.tsx b/apps/frontend/app/auth/login/page.tsx index 2546617..90670b3 100644 --- a/apps/frontend/app/auth/login/page.tsx +++ b/apps/frontend/app/auth/login/page.tsx @@ -655,8 +655,6 @@ export default function LoginPage() { await completePin(pendingSessionId, pin); - finishLoginRedirect(); - } catch (error) { showToast(error instanceof Error ? error.message : 'Не удалось проверить PIN-код'); diff --git a/apps/frontend/components/id/auth-provider.tsx b/apps/frontend/components/id/auth-provider.tsx index 0901bb2..9701150 100644 --- a/apps/frontend/components/id/auth-provider.tsx +++ b/apps/frontend/components/id/auth-provider.tsx @@ -34,6 +34,7 @@ import { subscribeApiReady, subscribeApiNotReady, } from '@/lib/api'; +import { resolvePostPinAuthRedirect } from '@/lib/auth-post-pin-redirect'; import { finalizeFedcmLogin, isFedcmLoginPopup, shouldFinalizeFedcmLogin } from '@/lib/fedcm-login-bridge'; import { FedcmApiLoginStatusBridge } from './fedcm-api-login-status'; import { usePublicSettings } from './public-settings-provider'; @@ -682,12 +683,25 @@ export function AuthProvider({ children }: { children: React.ReactNode }) { setIsLoading(false); } - if (pathname.startsWith('/auth/') && !isFedcmLoginPopup()) { - router.replace('/'); + if (isFedcmLoginPopup()) { + await finalizeFedcmLogin(response.accessToken); return; } - if (shouldFinalizeFedcmLogin(pathname) || isFedcmLoginPopup()) { + const postPinRedirect = + typeof window !== 'undefined' + ? resolvePostPinAuthRedirect(pathname, window.location.search) + : null; + + if (postPinRedirect !== null) { + if (shouldFinalizeFedcmLogin(pathname)) { + await finalizeFedcmLogin(response.accessToken); + } + router.replace(postPinRedirect); + return; + } + + if (shouldFinalizeFedcmLogin(pathname)) { await finalizeFedcmLogin(response.accessToken); } }, diff --git a/apps/frontend/lib/auth-post-pin-redirect.ts b/apps/frontend/lib/auth-post-pin-redirect.ts new file mode 100644 index 0000000..a9027c9 --- /dev/null +++ b/apps/frontend/lib/auth-post-pin-redirect.ts @@ -0,0 +1,33 @@ +/** Безопасный внутренний путь для post-login/post-pin редиректа (без open redirect). */ +export function isSafeInternalRedirect(path: string): boolean { + if (!path.startsWith('/') || path.startsWith('//')) return false; + if (path.includes('://')) return false; + return true; +} + +export function readPostAuthRedirect(search: string): string | null { + if (typeof window === 'undefined') return null; + const redirect = new URLSearchParams(search).get('redirect'); + if (!redirect || !isSafeInternalRedirect(redirect)) return null; + return redirect; +} + +/** + * Куда перейти после успешного ввода PIN на auth-страницах. + * null — остаться на текущей странице (OAuth consent, основное приложение). + */ +export function resolvePostPinAuthRedirect(pathname: string, search = ''): string | null { + if (pathname.startsWith('/auth/oauth/authorize')) { + return null; + } + + if (pathname.startsWith('/auth/login') || pathname.startsWith('/auth/register')) { + return readPostAuthRedirect(search) ?? '/'; + } + + if (pathname.startsWith('/auth/')) { + return '/'; + } + + return null; +}