mirror of
https://github.com/hicccc77/WeFlow.git
synced 2026-04-13 07:25:53 +00:00
支持自动化条件导出;优化引导页面提示;支持快速添加账号
This commit is contained in:
@@ -71,6 +71,7 @@ interface ConfigSchema {
|
||||
quoteLayout: 'quote-top' | 'quote-bottom'
|
||||
wordCloudExcludeWords: string[]
|
||||
exportWriteLayout: 'A' | 'B' | 'C'
|
||||
exportAutomationTaskMap: Record<string, unknown>
|
||||
|
||||
// AI 见解
|
||||
aiModelApiBaseUrl: string
|
||||
@@ -185,6 +186,7 @@ export class ConfigService {
|
||||
quoteLayout: 'quote-top',
|
||||
wordCloudExcludeWords: [],
|
||||
exportWriteLayout: 'A',
|
||||
exportAutomationTaskMap: {},
|
||||
aiModelApiBaseUrl: '',
|
||||
aiModelApiKey: '',
|
||||
aiModelApiModel: 'gpt-4o-mini',
|
||||
|
||||
@@ -9,7 +9,7 @@ import crypto from 'crypto'
|
||||
const execFileAsync = promisify(execFile)
|
||||
|
||||
type DbKeyResult = { success: boolean; key?: string; error?: string; logs?: string[] }
|
||||
type ImageKeyResult = { success: boolean; xorKey?: number; aesKey?: string; error?: string }
|
||||
type ImageKeyResult = { success: boolean; xorKey?: number; aesKey?: string; verified?: boolean; error?: string }
|
||||
|
||||
export class KeyService {
|
||||
private readonly isMac = process.platform === 'darwin'
|
||||
@@ -814,7 +814,7 @@ export class KeyService {
|
||||
if (!this.verifyDerivedAesKey(aesKey, verifyCiphertext)) continue
|
||||
onProgress?.(`密钥获取成功 (wxid: ${candidateWxid}, code: ${code})`)
|
||||
console.log('[ImageKey] 校验命中: wxid=', candidateWxid, 'code=', code)
|
||||
return { success: true, xorKey, aesKey }
|
||||
return { success: true, xorKey, aesKey, verified: true }
|
||||
}
|
||||
}
|
||||
return { success: false, error: '缓存 code 与当前账号 wxid 未匹配,请确认账号目录后重试,或使用内存扫描' }
|
||||
@@ -826,7 +826,7 @@ export class KeyService {
|
||||
const { xorKey, aesKey } = this.deriveImageKeys(fallbackCode, fallbackWxid)
|
||||
onProgress?.(`密钥获取成功 (wxid: ${fallbackWxid}, code: ${fallbackCode})`)
|
||||
console.log('[ImageKey] 回退计算: wxid=', fallbackWxid, 'code=', fallbackCode)
|
||||
return { success: true, xorKey, aesKey }
|
||||
return { success: true, xorKey, aesKey, verified: false }
|
||||
}
|
||||
|
||||
// --- 内存扫描备选方案(融合 Dart+Python 优点)---
|
||||
|
||||
@@ -3,6 +3,7 @@ import { join } from 'path'
|
||||
import { existsSync, readdirSync, statSync, readFileSync } from 'fs'
|
||||
import { execFile, exec, spawn } from 'child_process'
|
||||
import { promisify } from 'util'
|
||||
import crypto from 'crypto'
|
||||
import { createRequire } from 'module';
|
||||
const require = createRequire(import.meta.url);
|
||||
|
||||
@@ -10,7 +11,7 @@ const execFileAsync = promisify(execFile)
|
||||
const execAsync = promisify(exec)
|
||||
|
||||
type DbKeyResult = { success: boolean; key?: string; error?: string; logs?: string[] }
|
||||
type ImageKeyResult = { success: boolean; xorKey?: number; aesKey?: string; error?: string }
|
||||
type ImageKeyResult = { success: boolean; xorKey?: number; aesKey?: string; verified?: boolean; error?: string }
|
||||
|
||||
export class KeyServiceLinux {
|
||||
private sudo: any
|
||||
@@ -243,7 +244,14 @@ export class KeyServiceLinux {
|
||||
if (account && account.keys && account.keys.length > 0) {
|
||||
onProgress?.(`已找到匹配的图片密钥 (wxid: ${account.wxid})`);
|
||||
const keyObj = account.keys[0]
|
||||
return { success: true, xorKey: keyObj.xorKey, aesKey: keyObj.aesKey }
|
||||
const aesKey = String(keyObj.aesKey || '')
|
||||
const verified = await this.verifyImageKeyByTemplate(accountPath, aesKey)
|
||||
if (verified === true) {
|
||||
onProgress?.('缓存密钥校验成功,已确认可用')
|
||||
} else if (verified === false) {
|
||||
onProgress?.('已从缓存计算密钥,但未通过本地模板校验')
|
||||
}
|
||||
return { success: true, xorKey: keyObj.xorKey, aesKey, verified: verified === true }
|
||||
}
|
||||
return { success: false, error: '未在缓存中找到匹配的图片密钥' }
|
||||
} catch (err: any) {
|
||||
@@ -251,6 +259,35 @@ export class KeyServiceLinux {
|
||||
}
|
||||
}
|
||||
|
||||
private async verifyImageKeyByTemplate(accountPath: string | undefined, aesKey: string): Promise<boolean | null> {
|
||||
const normalizedPath = String(accountPath || '').trim()
|
||||
if (!normalizedPath || !aesKey || aesKey.length < 16 || !existsSync(normalizedPath)) return null
|
||||
try {
|
||||
const template = await this._findTemplateData(normalizedPath, 32)
|
||||
if (!template.ciphertext) return null
|
||||
return this.verifyDerivedAesKey(aesKey, template.ciphertext)
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
private verifyDerivedAesKey(aesKey: string, ciphertext: Buffer): boolean {
|
||||
try {
|
||||
if (!aesKey || aesKey.length < 16 || ciphertext.length !== 16) return false
|
||||
const decipher = crypto.createDecipheriv('aes-128-ecb', Buffer.from(aesKey, 'ascii').subarray(0, 16), null)
|
||||
decipher.setAutoPadding(false)
|
||||
const dec = Buffer.concat([decipher.update(ciphertext), decipher.final()])
|
||||
if (dec[0] === 0xFF && dec[1] === 0xD8 && dec[2] === 0xFF) return true
|
||||
if (dec[0] === 0x89 && dec[1] === 0x50 && dec[2] === 0x4E && dec[3] === 0x47) return true
|
||||
if (dec[0] === 0x52 && dec[1] === 0x49 && dec[2] === 0x46 && dec[3] === 0x46) return true
|
||||
if (dec[0] === 0x77 && dec[1] === 0x78 && dec[2] === 0x67 && dec[3] === 0x66) return true
|
||||
if (dec[0] === 0x47 && dec[1] === 0x49 && dec[2] === 0x46) return true
|
||||
return false
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
public async autoGetImageKeyByMemoryScan(
|
||||
accountPath: string,
|
||||
onProgress?: (msg: string) => void
|
||||
|
||||
@@ -7,7 +7,7 @@ import crypto from 'crypto'
|
||||
import { homedir } from 'os'
|
||||
|
||||
type DbKeyResult = { success: boolean; key?: string; error?: string; logs?: string[] }
|
||||
type ImageKeyResult = { success: boolean; xorKey?: number; aesKey?: string; error?: string }
|
||||
type ImageKeyResult = { success: boolean; xorKey?: number; aesKey?: string; verified?: boolean; error?: string }
|
||||
const execFileAsync = promisify(execFile)
|
||||
|
||||
export class KeyServiceMac {
|
||||
@@ -647,7 +647,7 @@ export class KeyServiceMac {
|
||||
const { xorKey, aesKey } = this.deriveImageKeys(code, candidateWxid)
|
||||
if (!this.verifyDerivedAesKey(aesKey, template.ciphertext)) continue
|
||||
onStatus?.(`密钥获取成功 (wxid: ${candidateWxid}, code: ${code})`)
|
||||
return { success: true, xorKey, aesKey }
|
||||
return { success: true, xorKey, aesKey, verified: true }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -662,7 +662,7 @@ export class KeyServiceMac {
|
||||
const fallbackCode = codes[0]
|
||||
const { xorKey, aesKey } = this.deriveImageKeys(fallbackCode, fallbackWxid)
|
||||
onStatus?.(`密钥获取成功 (wxid: ${fallbackWxid}, code: ${fallbackCode})`)
|
||||
return { success: true, xorKey, aesKey }
|
||||
return { success: true, xorKey, aesKey, verified: false }
|
||||
} catch (e: any) {
|
||||
return { success: false, error: `自动获取图片密钥失败: ${e.message}` }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user