From 814ea52c0e77f773d403ceb63509efaffcb2a6ea Mon Sep 17 00:00:00 2001 From: liangxu Date: Thu, 30 Apr 2026 01:28:41 +0800 Subject: [PATCH] feat(desktop-client): validate qiehao session via detected account MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 企鹅号 console returns 200 even when the session is silently expired, so probe/silent-refresh/console-open now require detect() to return an account whose identity matches the bound one. Surface a localized "授权已过期" prompt in the renderer when the new desktop_account_session_expired error bubbles up. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../desktop-client/src/main/account-binder.ts | 51 ++++++++++++++++++- .../src/renderer/lib/client-errors.ts | 10 ++++ 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/apps/desktop-client/src/main/account-binder.ts b/apps/desktop-client/src/main/account-binder.ts index a9e98ad..44a81a7 100644 --- a/apps/desktop-client/src/main/account-binder.ts +++ b/apps/desktop-client/src/main/account-binder.ts @@ -2044,7 +2044,10 @@ export async function probePublishAccountSession( webContents: window.webContents, }); if (detected) { - if (account.platform === "zol" && !detectedAccountMatchesIdentity(detected, account)) { + if ( + platformRequiresDetectedAccountIdentityMatch(account.platform) + && !detectedAccountMatchesIdentity(detected, account) + ) { return { verdict: "expired", reason: "login_redirect", @@ -2065,6 +2068,19 @@ export async function probePublishAccountSession( }; } + if (platformRequiresDetectedAccountForConsoleAccess(account.platform)) { + return { + verdict: "expired", + reason: "login_redirect", + profile: null, + sessionFingerprint: null, + evidence: { + url: currentURL, + code: "account_api_empty", + }, + }; + } + const consoleReady = account.platform === "zol" ? await verifyZolConsoleAccess(window, handle.session, account) : await verifyPublishAccountConsoleAccess(account, handle); @@ -2152,6 +2168,14 @@ export async function silentRefreshPublishAccountSession( return await verifyZolConsoleAccess(window, handle.session, account); } + if (platformRequiresDetectedAccountForConsoleAccess(account.platform)) { + const detected = await definition.detect({ + session: handle.session, + webContents: window.webContents, + }).catch(() => null); + return detected ? detectedAccountMatchesIdentity(detected, account) : false; + } + return !definitionLooksLikeLoginRedirect(window.webContents.getURL(), definition); } catch { return false; @@ -2331,6 +2355,14 @@ function detectedAccountMatchesIdentity( return sameAccountPlatformUid(detected.platformUid, expected); } +function platformRequiresDetectedAccountForConsoleAccess(platformId: string): boolean { + return platformId === "qiehao"; +} + +function platformRequiresDetectedAccountIdentityMatch(platformId: string): boolean { + return platformId === "qiehao" || platformId === "zol"; +} + async function verifyZolConsoleAccess( window: BrowserWindow, session: Session, @@ -2440,6 +2472,14 @@ async function verifyPublishAccountConsoleAccess( return await verifyZolConsoleAccess(window, handle.session, account); } + if (platformRequiresDetectedAccountForConsoleAccess(account.platform)) { + const detected = await definition.detect({ + session: handle.session, + webContents: window.webContents, + }).catch(() => null); + return detected ? detectedAccountMatchesIdentity(detected, account) : false; + } + return !definitionLooksLikeLoginRedirect(currentURL, definition); } finally { if (!window.isDestroyed()) { @@ -3453,6 +3493,15 @@ export async function openPublishAccountConsole(account: PublishAccountIdentity) const handle = await ensurePublishAccountSessionHandle(account); const consoleURL = await resolvePublishAccountConsoleURL(definition, handle.session); + if (platformRequiresDetectedAccountForConsoleAccess(account.platform)) { + const detected = await definition.detect({ + session: handle.session, + webContents: undefined as unknown as WebContents, + }).catch(() => null); + if (!detected || !detectedAccountMatchesIdentity(detected, account)) { + throw new Error(`desktop_account_session_expired:${account.platform}`); + } + } const window = createBoundWindow(`${definition.label} 创作台`, consoleURL, handle.session); window.show(); window.focus(); diff --git a/apps/desktop-client/src/renderer/lib/client-errors.ts b/apps/desktop-client/src/renderer/lib/client-errors.ts index 37dba3b..2418acb 100644 --- a/apps/desktop-client/src/renderer/lib/client-errors.ts +++ b/apps/desktop-client/src/renderer/lib/client-errors.ts @@ -96,6 +96,16 @@ function presentClientError(kind: ClientActionKind, error: unknown): ClientError }; } + if (message.startsWith("desktop_account_session_expired:")) { + const platformId = message.split(":")[1] || "当前平台"; + const platformLabel = platformId === "qiehao" ? "企鹅号" : platformId; + return { + tone: "warning", + title: "授权已过期", + content: `${platformLabel} 登录态已失效,请重新授权后再打开工作台。`, + }; + } + if (message === "desktop_account_delete_failed") { return { tone: "error",