diff --git a/packages/frontend/apps/electron/src/main/auth/auth-session.ts b/packages/frontend/apps/electron/src/main/auth/auth-session.ts index b5f3578f66..4f158e349c 100644 --- a/packages/frontend/apps/electron/src/main/auth/auth-session.ts +++ b/packages/frontend/apps/electron/src/main/auth/auth-session.ts @@ -143,6 +143,16 @@ export function getAuthSessionBroker(endpoint: string) { return broker; } +export async function initializeAuthSessions() { + for (const endpoint of Object.keys(await readStore())) { + try { + getAuthSessionBroker(endpoint); + } catch (error) { + logger.error('failed to initialize auth session', endpoint, error); + } + } +} + export function isManagedAuthEndpoint(url: string) { try { const parsed = new URL(url); diff --git a/packages/frontend/apps/electron/src/main/protocol.ts b/packages/frontend/apps/electron/src/main/protocol.ts index c50a1f05e2..4c993bee2c 100644 --- a/packages/frontend/apps/electron/src/main/protocol.ts +++ b/packages/frontend/apps/electron/src/main/protocol.ts @@ -14,6 +14,7 @@ import { import { executeAuthSessionRequest, getAccessTokenForUrl, + initializeAuthSessions, isManagedAuthEndpoint, } from './auth/auth-session'; import { buildType, isDev } from './config'; @@ -213,7 +214,9 @@ function allowCors( ); } -export function registerProtocol() { +export async function registerProtocol() { + await initializeAuthSessions(); + protocol.handle('assets', request => { return handleFileRequest(request); }); diff --git a/packages/frontend/apps/electron/test/main/auth-session.spec.ts b/packages/frontend/apps/electron/test/main/auth-session.spec.ts index 542236e760..3117cda3f4 100644 --- a/packages/frontend/apps/electron/test/main/auth-session.spec.ts +++ b/packages/frontend/apps/electron/test/main/auth-session.spec.ts @@ -64,6 +64,8 @@ import { clearAuthSession, executeAuthSessionRequest, getValidAccessToken, + initializeAuthSessions, + isManagedAuthEndpoint, normalizeEndpoint, revokeAuthSession, setAuthSession, @@ -87,9 +89,32 @@ test.each([ expect(normalizeEndpoint(endpoint)).toBe(expected); }); -test('atomically persists one encrypted token-pair record', async () => { +test('loads and atomically persists one encrypted token-pair record', async () => { const endpoint = 'https://persistent.example'; const pair = tokenResponse('access-persistent', 'p', 900); + runtime.files.set( + sessionFile, + JSON.stringify({ + [endpoint]: Buffer.from( + JSON.stringify({ + version: 1, + tokenType: pair.tokenType, + accessToken: pair.accessToken, + accessExpiresAt: new Date( + Date.now() + pair.expiresIn * 1000 + ).toISOString(), + refreshToken: pair.refreshToken, + refreshExpiresAt: pair.refreshExpiresAt, + session: pair.session, + }) + ).toString('base64'), + }) + ); + + expect(isManagedAuthEndpoint(endpoint)).toBe(false); + await initializeAuthSessions(); + expect(isManagedAuthEndpoint(endpoint)).toBe(true); + expect(await getValidAccessToken(endpoint)).toBe('access-persistent'); await expect(setAuthSession(endpoint, pair)).resolves.toEqual({ persistent: true,