fix(auth): avoid logout on export-only clear and harden db key auto-fetch

This commit is contained in:
tisonhuang
2026-03-05 11:15:44 +08:00
parent 459f23bbd6
commit c5a6d765ee
5 changed files with 126 additions and 24 deletions

View File

@@ -1347,6 +1347,7 @@ function registerIpcHandlers() {
} }
} }
if (clearCache) {
try { try {
const wxidConfigsRaw = cfg.get('wxidConfigs') as Record<string, any> | undefined const wxidConfigsRaw = cfg.get('wxidConfigs') as Record<string, any> | undefined
if (wxidConfigsRaw && typeof wxidConfigsRaw === 'object') { if (wxidConfigsRaw && typeof wxidConfigsRaw === 'object') {
@@ -1369,6 +1370,7 @@ function registerIpcHandlers() {
} catch (error) { } catch (error) {
warnings.push(`清理账号配置失败: ${String(error)}`) warnings.push(`清理账号配置失败: ${String(error)}`)
} }
}
return { return {
success: true, success: true,
@@ -2172,7 +2174,7 @@ function registerIpcHandlers() {
// 密钥获取 // 密钥获取
ipcMain.handle('key:autoGetDbKey', async (event) => { ipcMain.handle('key:autoGetDbKey', async (event) => {
return keyService.autoGetDbKey(60_000, (message, level) => { return keyService.autoGetDbKey(180_000, (message, level) => {
event.sender.send('key:dbKeyStatus', { message, level }) event.sender.send('key:dbKeyStatus', { message, level })
}) })
}) })

View File

@@ -509,6 +509,58 @@ export class KeyService {
return false return false
} }
private isLoginRelatedText(value: string): boolean {
const normalized = String(value || '').replace(/\s+/g, '').toLowerCase()
if (!normalized) return false
const keywords = [
'登录',
'扫码',
'二维码',
'请在手机上确认',
'手机确认',
'切换账号',
'wechatlogin',
'qrcode',
'scan'
]
return keywords.some((keyword) => normalized.includes(keyword))
}
private async detectWeChatLoginRequired(pid: number): Promise<boolean> {
if (!this.ensureUser32()) return false
let loginRequired = false
const enumWindowsCallback = this.koffi.register((hWnd: any, _lParam: any) => {
if (!this.IsWindowVisible(hWnd)) return true
const title = this.getWindowTitle(hWnd)
if (!this.isWeChatWindowTitle(title)) return true
const pidBuf = Buffer.alloc(4)
this.GetWindowThreadProcessId(hWnd, pidBuf)
const windowPid = pidBuf.readUInt32LE(0)
if (windowPid !== pid) return true
if (this.isLoginRelatedText(title)) {
loginRequired = true
return false
}
const children = this.collectChildWindowInfos(hWnd)
for (const child of children) {
if (this.isLoginRelatedText(child.title) || this.isLoginRelatedText(child.className)) {
loginRequired = true
return false
}
}
return true
}, this.WNDENUMPROC_PTR)
this.EnumWindows(enumWindowsCallback, 0)
this.koffi.unregister(enumWindowsCallback)
return loginRequired
}
private async waitForWeChatWindowComponents(pid: number, timeoutMs = 15000): Promise<boolean> { private async waitForWeChatWindowComponents(pid: number, timeoutMs = 15000): Promise<boolean> {
if (!this.ensureUser32()) return true if (!this.ensureUser32()) return true
const startTime = Date.now() const startTime = Date.now()
@@ -605,6 +657,7 @@ export class KeyService {
const keyBuffer = Buffer.alloc(128) const keyBuffer = Buffer.alloc(128)
const start = Date.now() const start = Date.now()
let loginRequiredDetected = false
try { try {
while (Date.now() - start < timeoutMs) { while (Date.now() - start < timeoutMs) {
@@ -624,6 +677,9 @@ export class KeyService {
const level = levelOut[0] ?? 0 const level = levelOut[0] ?? 0
if (msg) { if (msg) {
logs.push(msg) logs.push(msg)
if (this.isLoginRelatedText(msg)) {
loginRequiredDetected = true
}
onStatus?.(msg, level) onStatus?.(msg, level)
} }
} }
@@ -635,6 +691,15 @@ export class KeyService {
} catch { } } catch { }
} }
const loginRequired = loginRequiredDetected || await this.detectWeChatLoginRequired(pid)
if (loginRequired) {
return {
success: false,
error: '微信已启动但尚未完成登录,请先在微信客户端完成登录后再重试自动获取密钥。',
logs
}
}
return { success: false, error: '获取密钥超时', logs } return { success: false, error: '获取密钥超时', logs }
} }

View File

@@ -305,9 +305,14 @@ function Sidebar() {
if (result.warning) { if (result.warning) {
detailLines.push('', `注意:${result.warning}`) detailLines.push('', `注意:${result.warning}`)
} }
window.alert(`账号数据清理完成。\n\n${detailLines.join('\n')}\n\n为保障数据安全WeFlow 已清除该账号本地缓存/导出相关数据。若需再次获取数据,请手动登录微信客户端并重新在 WeFlow 完成配置。`) const followupHint = shouldClearCacheData
? '若需再次获取数据,请手动登录微信客户端并重新在 WeFlow 完成配置。'
: '你可以继续使用当前登录状态,无需重新登录。'
window.alert(`账号数据清理完成。\n\n${detailLines.join('\n')}\n\n为保障数据安全WeFlow 已清除该账号本地缓存/导出相关数据。${followupHint}`)
resetClearDialogState() resetClearDialogState()
if (shouldClearCacheData) {
window.location.reload() window.location.reload()
}
} catch (error) { } catch (error) {
console.error('清理账号数据失败:', error) console.error('清理账号数据失败:', error)
window.alert('清理失败,请稍后重试。') window.alert('清理失败,请稍后重试。')

View File

@@ -36,6 +36,18 @@ interface WxidOption {
modifiedTime: number modifiedTime: number
} }
const formatDbKeyFailureMessage = (error?: string, logs?: string[]): string => {
const base = String(error || '自动获取密钥失败').trim()
const tailLogs = Array.isArray(logs)
? logs
.map(item => String(item || '').trim())
.filter(Boolean)
.slice(-6)
: []
if (tailLogs.length === 0) return base
return `${base};最近状态:${tailLogs.join(' | ')}`
}
function SettingsPage() { function SettingsPage() {
const { const {
isDbConnected, isDbConnected,
@@ -725,7 +737,10 @@ function SettingsPage() {
setIsManualStartPrompt(true) setIsManualStartPrompt(true)
setDbKeyStatus('需要手动启动微信') setDbKeyStatus('需要手动启动微信')
} else { } else {
showMessage(result.error || '自动获取密钥失败', false) if (result.error?.includes('尚未完成登录')) {
setDbKeyStatus('请先在微信完成登录后重试')
}
showMessage(formatDbKeyFailureMessage(result.error, result.logs), false)
} }
} }
} catch (e: any) { } catch (e: any) {

View File

@@ -23,6 +23,18 @@ interface WelcomePageProps {
standalone?: boolean standalone?: boolean
} }
const formatDbKeyFailureMessage = (error?: string, logs?: string[]): string => {
const base = String(error || '自动获取密钥失败').trim()
const tailLogs = Array.isArray(logs)
? logs
.map(item => String(item || '').trim())
.filter(Boolean)
.slice(-6)
: []
if (tailLogs.length === 0) return base
return `${base};最近状态:${tailLogs.join(' | ')}`
}
function WelcomePage({ standalone = false }: WelcomePageProps) { function WelcomePage({ standalone = false }: WelcomePageProps) {
const navigate = useNavigate() const navigate = useNavigate()
const { isDbConnected, setDbConnected, setLoading } = useAppStore() const { isDbConnected, setDbConnected, setLoading } = useAppStore()
@@ -292,7 +304,10 @@ function WelcomePage({ standalone = false }: WelcomePageProps) {
setIsManualStartPrompt(true) setIsManualStartPrompt(true)
setDbKeyStatus('需要手动启动微信') setDbKeyStatus('需要手动启动微信')
} else { } else {
setError(result.error || '自动获取密钥失败') if (result.error?.includes('尚未完成登录')) {
setDbKeyStatus('请先在微信完成登录后重试')
}
setError(formatDbKeyFailureMessage(result.error, result.logs))
} }
} }
} catch (e) { } catch (e) {