fix and update

This commit is contained in:
lendry
2026-06-29 14:40:35 +03:00
parent 75ccbe5fc4
commit 0df7240dc8
21 changed files with 934 additions and 113 deletions

View File

@@ -15,6 +15,11 @@ import {
fetchOAuthClientPublicInfo,
type OAuthConsentCheckResponse
} from '@/lib/api';
import {
parseAuthorizationRedirect,
parsePopupOAuthParams,
postOneTapResult
} from '@/lib/oauth-popup-bridge';
function buildOAuthQuery(searchParams: URLSearchParams) {
const params = new URLSearchParams();
@@ -38,6 +43,8 @@ function OAuthAuthorizeContent() {
const autoApproveStartedRef = useRef(false);
const oauthQuery = useMemo(() => buildOAuthQuery(searchParams), [searchParams]);
const popupContext = useMemo(() => parsePopupOAuthParams(searchParams), [searchParams]);
const isPopupMode = Boolean(popupContext);
const clientId = searchParams.get('client_id') ?? searchParams.get('clientId');
const redirectUri = searchParams.get('redirect_uri') ?? searchParams.get('redirectUri');
@@ -99,6 +106,22 @@ function OAuthAuthorizeContent() {
};
}, [isLoading, isPinLocked, returnUrl, router, token, user]);
const finishPopupFlow = useCallback(
(redirectUrl: string) => {
if (!popupContext) return false;
const parsed = parseAuthorizationRedirect(redirectUrl);
postOneTapResult(popupContext.popupOrigin, {
code: parsed.code ?? undefined,
state: parsed.state ?? undefined,
token: parsed.code ?? undefined,
error: parsed.error ?? undefined,
errorDescription: parsed.errorDescription ?? undefined
});
return true;
},
[popupContext]
);
const approve = useCallback(async () => {
if (!token || !user || isPinLocked) return;
setSubmitting(true);
@@ -108,6 +131,9 @@ function OAuthAuthorizeContent() {
if (!data.redirectUrl) {
throw new Error('Сервер не вернул redirect URL');
}
if (finishPopupFlow(data.redirectUrl)) {
return;
}
window.location.href = data.redirectUrl;
} catch (err) {
setError(err instanceof Error ? err.message : 'Ошибка OAuth авторизации');
@@ -115,7 +141,7 @@ function OAuthAuthorizeContent() {
} finally {
setSubmitting(false);
}
}, [isPinLocked, oauthQuery, token, user]);
}, [finishPopupFlow, isPinLocked, oauthQuery, token, user]);
useEffect(() => {
if (!token || !clientId || !sessionChecked || isPinLocked) return;
@@ -149,6 +175,14 @@ function OAuthAuthorizeContent() {
}, [approve, clientId, isPinLocked, oauthQuery, sessionChecked, token]);
const cancel = useCallback(() => {
if (popupContext) {
postOneTapResult(popupContext.popupOrigin, {
error: 'access_denied',
errorDescription: 'Пользователь отклонил запрос'
});
return;
}
if (!redirectUri) {
router.push('/');
return;
@@ -162,7 +196,7 @@ function OAuthAuthorizeContent() {
} catch {
router.push('/');
}
}, [redirectUri, router, state]);
}, [popupContext, redirectUri, router, state]);
const authReady = Boolean(user && token && !isPinLocked && sessionChecked);
const scopeItems = consentInfo?.requestedScopes ?? [];
@@ -205,10 +239,12 @@ function OAuthAuthorizeContent() {
}
return (
<div className="mx-auto flex min-h-[70vh] max-w-lg flex-col justify-center px-4 py-12">
<div className="mb-8 flex justify-center">
<BrandLogo />
</div>
<div className={`mx-auto flex min-h-[70vh] max-w-lg flex-col justify-center px-4 ${isPopupMode ? 'py-6' : 'py-12'}`}>
{!isPopupMode ? (
<div className="mb-8 flex justify-center">
<BrandLogo />
</div>
) : null}
<div className="rounded-[24px] border border-[#eceef4] bg-white p-6 shadow-sm">
<div className="mb-4 flex h-12 w-12 items-center justify-center rounded-2xl bg-[#eef4ff] text-[#3390ec]">
<ShieldCheck className="h-6 w-6" />