mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-09-05 00:16:47 +08:00
feat(core): improve login flow (#15219)
#### PR Dependency Tree * **PR #15219** 👈 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 secure, automatic auth session token refresh and request replay for expired-token responses across Android, iOS, and Electron. * Updated sign-in flows to manage sessions without returning tokens to the app layer. * Added “Devices” management UI with sign out per device and sign out all. * Enabled support for both Hashcash and Turnstile captcha providers. * **Bug Fixes** * Improved refresh de-duplication, inflight cancellation/clear behavior, and recovery from corrupted/invalid sessions. * **Tests** * Expanded auth-session, refresh/revoke, and replay coverage (Electron unit tests, Android instrumentation tests, iOS auth date parser tests). * **Chores** * Removed CAPTCHA site key from build-time configuration and adjusted CI test execution. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -11,7 +11,11 @@ import {
|
||||
resolvePathInBase,
|
||||
resourcesPath,
|
||||
} from '../shared/utils';
|
||||
import { getAuthTokenForUrl } from './auth/native-token';
|
||||
import {
|
||||
executeAuthSessionRequest,
|
||||
getAccessTokenForUrl,
|
||||
isManagedAuthEndpoint,
|
||||
} from './auth/auth-session';
|
||||
import { buildType, isDev } from './config';
|
||||
import { logger } from './logger';
|
||||
|
||||
@@ -64,26 +68,6 @@ function buildTargetUrl(base: string, urlObject: URL) {
|
||||
return new URL(`${urlObject.pathname}${urlObject.search}`, base).toString();
|
||||
}
|
||||
|
||||
async function buildAuthorizedRequest(request: Request, targetUrl: string) {
|
||||
const clonedRequest = request.clone();
|
||||
const headers = new Headers(clonedRequest.headers);
|
||||
const token = getAuthTokenForUrl(targetUrl);
|
||||
if (token) {
|
||||
headers.set('Authorization', `Bearer ${token}`);
|
||||
}
|
||||
|
||||
return new Request(targetUrl, {
|
||||
body:
|
||||
clonedRequest.method === 'GET' || clonedRequest.method === 'HEAD'
|
||||
? undefined
|
||||
: clonedRequest.body,
|
||||
headers,
|
||||
method: clonedRequest.method,
|
||||
redirect: clonedRequest.redirect,
|
||||
signal: clonedRequest.signal,
|
||||
});
|
||||
}
|
||||
|
||||
async function proxyRequest(
|
||||
request: Request,
|
||||
urlObject: URL,
|
||||
@@ -92,13 +76,13 @@ async function proxyRequest(
|
||||
) {
|
||||
const { bypassCustomProtocolHandlers = true } = options;
|
||||
const targetUrl = buildTargetUrl(base, urlObject);
|
||||
const authorizedRequest = await buildAuthorizedRequest(request, targetUrl);
|
||||
const proxiedRequest = bypassCustomProtocolHandlers
|
||||
? Object.assign(authorizedRequest, {
|
||||
bypassCustomProtocolHandlers: true,
|
||||
})
|
||||
: authorizedRequest;
|
||||
return net.fetch(proxiedRequest);
|
||||
return await executeAuthSessionRequest(request, targetUrl, request =>
|
||||
net.fetch(
|
||||
bypassCustomProtocolHandlers
|
||||
? Object.assign(request, { bypassCustomProtocolHandlers: true })
|
||||
: request
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
async function handleFileRequest(request: Request) {
|
||||
@@ -268,17 +252,20 @@ export function registerProtocol() {
|
||||
|
||||
session.defaultSession.webRequest.onBeforeSendHeaders((details, callback) => {
|
||||
const url = new URL(details.url);
|
||||
|
||||
(async () => {
|
||||
if (
|
||||
url.protocol === 'http:' ||
|
||||
const managedAuthRequest =
|
||||
(url.protocol === 'http:' ||
|
||||
url.protocol === 'https:' ||
|
||||
url.protocol === 'ws:' ||
|
||||
url.protocol === 'wss:'
|
||||
) {
|
||||
const token = getAuthTokenForUrl(details.url);
|
||||
url.protocol === 'wss:') &&
|
||||
isManagedAuthEndpoint(details.url);
|
||||
let cancel = false;
|
||||
|
||||
(async () => {
|
||||
if (managedAuthRequest) {
|
||||
delete details.requestHeaders.authorization;
|
||||
delete details.requestHeaders.Authorization;
|
||||
const token = await getAccessTokenForUrl(details.url, 120_000);
|
||||
if (token) {
|
||||
delete details.requestHeaders.authorization;
|
||||
details.requestHeaders.Authorization = `Bearer ${token}`;
|
||||
}
|
||||
}
|
||||
@@ -292,11 +279,12 @@ export function registerProtocol() {
|
||||
}
|
||||
})()
|
||||
.catch(err => {
|
||||
cancel = managedAuthRequest;
|
||||
logger.error('error handling before send headers', err);
|
||||
})
|
||||
.finally(() => {
|
||||
callback({
|
||||
cancel: false,
|
||||
cancel,
|
||||
requestHeaders: details.requestHeaders,
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user