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:
DarkSky
2026-06-01 17:11:15 +08:00
committed by GitHub
parent 5b9d51b41b
commit ce9841df9d
74 changed files with 3719 additions and 939 deletions
@@ -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;