feat: drop outdated session (#14373)

#### PR Dependency Tree


* **PR #14373** 👈

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Added client version tracking and validation to ensure application
compatibility across authentication flows and sessions.
* Enhanced OAuth authentication with improved version handling during
sign-in and refresh operations.

* **Bug Fixes**
* Improved payment callback URL handling with safer defaults for
redirect links.

* **Tests**
* Expanded test coverage for client version enforcement and session
management.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
DarkSky
2026-02-05 21:35:36 +08:00
committed by GitHub
parent 161eb302fd
commit 944fab36ac
29 changed files with 845 additions and 125 deletions
@@ -4,11 +4,14 @@ import {
type LoaderFunction,
redirect,
useLoaderData,
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
useNavigate,
} from 'react-router-dom';
import { AuthService } from '../../../modules/cloud';
import {
buildAuthenticationDeepLink,
buildOpenAppUrlRoute,
} from '../../../modules/open-in-app';
import { supportedClient } from './common';
interface LoaderData {
@@ -44,13 +47,14 @@ export const loader: LoaderFunction = ({ request }) => {
return redirect('/sign-in?error=Invalid callback parameters');
}
const authParams = new URLSearchParams();
authParams.set('method', 'magic-link');
authParams.set('payload', JSON.stringify(payload));
const urlToOpen = buildAuthenticationDeepLink({
scheme: clientCheckResult.data,
method: 'magic-link',
payload,
server: location.origin,
});
return redirect(
`/open-app/url?url=${encodeURIComponent(`${client}://authentication?${authParams.toString()}`)}`
);
return redirect(buildOpenAppUrlRoute(urlToOpen));
};
export const Component = () => {
@@ -8,6 +8,10 @@ import {
} from 'react-router-dom';
import { AuthService } from '../../../modules/cloud';
import {
buildAuthenticationDeepLink,
buildOpenAppUrlRoute,
} from '../../../modules/open-in-app';
import { supportedClient } from './common';
interface LoaderData {
@@ -45,14 +49,14 @@ export const loader: LoaderFunction = async ({ request }) => {
return redirect('/sign-in?error=Invalid oauth callback parameters');
}
const authParams = new URLSearchParams();
authParams.set('method', 'oauth');
authParams.set('payload', JSON.stringify(payload));
authParams.set('server', location.origin);
const urlToOpen = buildAuthenticationDeepLink({
scheme: clientCheckResult.data,
method: 'oauth',
payload,
server: location.origin,
});
return redirect(
`/open-app/url?url=${encodeURIComponent(`${client}://authentication?${authParams.toString()}`)}`
);
return redirect(buildOpenAppUrlRoute(urlToOpen));
} catch {
return redirect('/sign-in?error=Invalid oauth callback parameters');
}
@@ -1,5 +1,10 @@
import { useNavigateHelper } from '@affine/core/components/hooks/use-navigate-helper';
import { AuthService } from '@affine/core/modules/cloud';
import {
buildAuthenticationDeepLink,
buildOpenAppUrlRoute,
normalizeOpenAppSignInNextParam,
} from '@affine/core/modules/open-in-app';
import { OpenInAppPage } from '@affine/core/modules/open-in-app/views/open-in-app-page';
import {
appSchemaUrl,
@@ -7,8 +12,8 @@ import {
channelToScheme,
} from '@affine/core/utils/channel';
import { useService } from '@toeverything/infra';
import { useCallback, useEffect, useRef, useState } from 'react';
import { useParams, useSearchParams } from 'react-router-dom';
import { useCallback, useEffect, useRef } from 'react';
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
import { AppContainer } from '../../components/app-container';
@@ -51,13 +56,16 @@ const OpenAppSignInRedirect = () => {
const authService = useService(AuthService);
const [params] = useSearchParams();
const triggeredRef = useRef(false);
const [urlToOpen, setUrlToOpen] = useState<string | null>(null);
const navigate = useNavigate();
const maybeScheme = appSchemes.safeParse(params.get('scheme'));
const scheme = maybeScheme.success
? maybeScheme.data
: channelToScheme[BUILD_CONFIG.appBuildType];
const next = params.get('next') || undefined;
const next = normalizeOpenAppSignInNextParam(
params.get('next'),
location.origin
);
useEffect(() => {
if (triggeredRef.current) {
@@ -68,23 +76,18 @@ const OpenAppSignInRedirect = () => {
authService
.createOpenAppSignInCode()
.then(code => {
const authParams = new URLSearchParams();
authParams.set('method', 'open-app-signin');
authParams.set(
'payload',
JSON.stringify(next ? { code, next } : { code })
);
authParams.set('server', location.origin);
setUrlToOpen(`${scheme}://authentication?${authParams.toString()}`);
const urlToOpen = buildAuthenticationDeepLink({
scheme,
method: 'open-app-signin',
payload: next ? { code, next } : { code },
server: location.origin,
});
navigate(buildOpenAppUrlRoute(urlToOpen), { replace: true });
})
.catch(console.error);
}, [authService, next, scheme]);
}, [authService, navigate, next, scheme]);
if (!urlToOpen) {
return <AppContainer fallback />;
}
return <OpenInAppPage urlToOpen={urlToOpen} />;
return <AppContainer fallback />;
};
export const Component = () => {