mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-09-05 08:19:48 +08:00
feat(server): passkey pre-refactor (#15060)
#### PR Dependency Tree * **PR #15060** 👈 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** * OpenApp native sign-in and native session exchange (JWT) for mobile & desktop. * Centralized short-lived auth challenge store for one-time tokens. * Encrypted per-endpoint token storage and native token handlers (Android, iOS, Electron). * **Improvements** * Richer auth-method reporting (password, magic link, OAuth, passkey) and improved sign-in flows. * Hardened magic-link, OAuth, and session issuance; JWT-backed sessions and websocket JWT support. * UX tweaks: form-based password submit, OTP autocomplete, adjusted captcha flow. * **Bug Fixes** * Expanded tests and auth-state resets to avoid cross-test leakage. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -2,7 +2,6 @@ import path, { join } from 'node:path';
|
||||
import { pathToFileURL } from 'node:url';
|
||||
|
||||
import { app, net, protocol, session } from 'electron';
|
||||
import cookieParser from 'set-cookie-parser';
|
||||
|
||||
import { anotherHost, mainHost } from '../shared/internal-origin';
|
||||
import {
|
||||
@@ -12,6 +11,7 @@ import {
|
||||
resolvePathInBase,
|
||||
resourcesPath,
|
||||
} from '../shared/utils';
|
||||
import { getAuthTokenForUrl } from './auth/native-token';
|
||||
import { buildType, isDev } from './config';
|
||||
import { logger } from './logger';
|
||||
|
||||
@@ -64,7 +64,27 @@ function buildTargetUrl(base: string, urlObject: URL) {
|
||||
return new URL(`${urlObject.pathname}${urlObject.search}`, base).toString();
|
||||
}
|
||||
|
||||
function proxyRequest(
|
||||
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,
|
||||
base: string,
|
||||
@@ -72,12 +92,13 @@ function proxyRequest(
|
||||
) {
|
||||
const { bypassCustomProtocolHandlers = true } = options;
|
||||
const targetUrl = buildTargetUrl(base, urlObject);
|
||||
const authorizedRequest = await buildAuthorizedRequest(request, targetUrl);
|
||||
const proxiedRequest = bypassCustomProtocolHandlers
|
||||
? Object.assign(request.clone(), {
|
||||
? Object.assign(authorizedRequest, {
|
||||
bypassCustomProtocolHandlers: true,
|
||||
})
|
||||
: request;
|
||||
return net.fetch(targetUrl, proxiedRequest);
|
||||
: authorizedRequest;
|
||||
return net.fetch(proxiedRequest);
|
||||
}
|
||||
|
||||
async function handleFileRequest(request: Request) {
|
||||
@@ -218,41 +239,6 @@ export function registerProtocol() {
|
||||
const { responseHeaders, url } = responseDetails;
|
||||
(async () => {
|
||||
if (responseHeaders) {
|
||||
const originalCookie =
|
||||
responseHeaders['set-cookie'] || responseHeaders['Set-Cookie'];
|
||||
|
||||
if (originalCookie) {
|
||||
// save the cookies, to support third party cookies
|
||||
for (const cookies of originalCookie) {
|
||||
const parsedCookies = cookieParser.parse(cookies);
|
||||
for (const parsedCookie of parsedCookies) {
|
||||
if (!parsedCookie.value) {
|
||||
await session.defaultSession.cookies.remove(
|
||||
responseDetails.url,
|
||||
parsedCookie.name
|
||||
);
|
||||
} else {
|
||||
await session.defaultSession.cookies.set({
|
||||
url: responseDetails.url,
|
||||
domain: parsedCookie.domain,
|
||||
expirationDate: parsedCookie.expires?.getTime(),
|
||||
httpOnly: parsedCookie.httpOnly,
|
||||
secure: parsedCookie.secure,
|
||||
value: parsedCookie.value,
|
||||
name: parsedCookie.name,
|
||||
path: parsedCookie.path,
|
||||
sameSite: parsedCookie.sameSite?.toLowerCase() as
|
||||
| 'unspecified'
|
||||
| 'no_restriction'
|
||||
| 'lax'
|
||||
| 'strict'
|
||||
| undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const { protocol, hostname } = new URL(url);
|
||||
|
||||
// Adjust CORS for assets responses and allow blob redirects on affine domains
|
||||
@@ -284,23 +270,17 @@ export function registerProtocol() {
|
||||
const url = new URL(details.url);
|
||||
|
||||
(async () => {
|
||||
// session cookies are set to assets:// on production
|
||||
// if sending request to the cloud, attach the session cookie (to affine cloud server)
|
||||
if (
|
||||
url.protocol === 'http:' ||
|
||||
url.protocol === 'https:' ||
|
||||
url.protocol === 'ws:' ||
|
||||
url.protocol === 'wss:'
|
||||
) {
|
||||
const cookies = await session.defaultSession.cookies.get({
|
||||
url: details.url,
|
||||
});
|
||||
|
||||
const cookieString = cookies
|
||||
.map(c => `${c.name}=${c.value}`)
|
||||
.join('; ');
|
||||
delete details.requestHeaders['cookie'];
|
||||
details.requestHeaders['Cookie'] = cookieString;
|
||||
const token = getAuthTokenForUrl(details.url);
|
||||
if (token) {
|
||||
delete details.requestHeaders.authorization;
|
||||
details.requestHeaders.Authorization = `Bearer ${token}`;
|
||||
}
|
||||
}
|
||||
|
||||
const hostname = url.hostname;
|
||||
|
||||
Reference in New Issue
Block a user