修复了全局wxid错误清洗的问题

This commit is contained in:
cc
2026-05-10 15:17:02 +08:00
parent 2d5832d6a9
commit 39e527a21a
15 changed files with 84 additions and 37 deletions

View File

@@ -2430,7 +2430,7 @@ function registerIpcHandlers() {
return { success: false, error: '请至少选择一项清理范围' }
}
const rawWxid = String(cfg.get('myWxid') || '').trim()
const rawWxid = String(cfg.getMyWxidCleaned() || '').trim()
if (!rawWxid) {
return { success: false, error: '当前账号未登录或未识别,无法清理' }
}
@@ -3180,7 +3180,7 @@ function registerIpcHandlers() {
const logEnabled = cfg.get('logEnabled')
const dbPath = String(cfg.get('dbPath') || '').trim()
const decryptKey = String(cfg.get('decryptKey') || '').trim()
const myWxid = String(cfg.get('myWxid') || '').trim()
const myWxid = String(cfg.getMyWxidCleaned() || '').trim()
const imageKeys = cfg.getImageKeysForCurrentWxid()
const resourcesPath = app.isPackaged
? join(process.resourcesPath, 'resources')
@@ -3329,7 +3329,7 @@ function registerIpcHandlers() {
options,
dbPath: String(cfg.get('dbPath') || '').trim(),
decryptKey: String(cfg.get('decryptKey') || '').trim(),
myWxid: String(cfg.get('myWxid') || '').trim(),
myWxid: String(cfg.getMyWxidCleaned() || '').trim(),
imageXorKey: imageKeys.xorKey,
imageAesKey: imageKeys.aesKey,
resourcesPath: app.isPackaged ? join(process.resourcesPath, 'resources') : join(app.getAppPath(), 'resources'),
@@ -3398,7 +3398,7 @@ function registerIpcHandlers() {
options,
dbPath: String(cfg.get('dbPath') || '').trim(),
decryptKey: String(cfg.get('decryptKey') || '').trim(),
myWxid: String(cfg.get('myWxid') || '').trim(),
myWxid: String(cfg.getMyWxidCleaned() || '').trim(),
resourcesPath: app.isPackaged ? join(process.resourcesPath, 'resources') : join(app.getAppPath(), 'resources'),
userDataPath: app.getPath('userData'),
logEnabled: cfg.get('logEnabled')
@@ -3631,7 +3631,7 @@ function registerIpcHandlers() {
return annualReportService.getAvailableYears({
dbPath: cfg.get('dbPath'),
decryptKey: cfg.get('decryptKey'),
wxid: cfg.get('myWxid')
wxid: cfg.getMyWxidCleaned()
})
})
@@ -3828,7 +3828,7 @@ function registerIpcHandlers() {
const dbPath = cfg.get('dbPath')
const decryptKey = cfg.get('decryptKey')
const wxid = cfg.get('myWxid')
const wxid = cfg.getMyWxidCleaned()
const logEnabled = cfg.get('logEnabled')
const resourcesPath = app.isPackaged
@@ -3889,7 +3889,7 @@ function registerIpcHandlers() {
const dbPath = cfg.get('dbPath')
const decryptKey = cfg.get('decryptKey')
const wxid = cfg.get('myWxid')
const wxid = cfg.getMyWxidCleaned()
const logEnabled = cfg.get('logEnabled')
const friendUsername = payload?.friendUsername
const year = payload?.year ?? 0

View File

@@ -127,6 +127,7 @@ class AnalyticsService {
const wxid = this.configService.get('myWxid')
const dbPath = this.configService.get('dbPath')
const decryptKey = this.configService.get('decryptKey')
if (!wxid) return { success: false, error: '未配置微信ID' }
if (!dbPath) return { success: false, error: '未配置数据库路径' }
if (!decryptKey) return { success: false, error: '未配置解密密钥' }
@@ -138,6 +139,7 @@ class AnalyticsService {
if (!ok) return { success: false, error: 'WCDB 打开失败' }
const cleanedWxid = this.cleanAccountDirName(wxid)
return { success: true, cleanedWxid }
}
@@ -237,8 +239,7 @@ class AnalyticsService {
}
private async computeAggregateByCursor(sessionIds: string[], beginTimestamp = 0, endTimestamp = 0): Promise<any> {
const wxid = this.configService.get('myWxid')
const cleanedWxid = wxid ? this.cleanAccountDirName(wxid) : ''
const cleanedWxid = this.configService.getMyWxidCleaned() || ''
const aggregate = {
total: 0,
@@ -275,8 +276,7 @@ class AnalyticsService {
const myWxidLower = cleanedWxid.toLowerCase()
isSend = (
senderLower === myWxidLower ||
// 兼容非 wxid 开头的账号(如果文件夹名带后缀,如 custom_backup而 sender 是 custom
(myWxidLower.startsWith(senderLower + '_'))
senderLower.startsWith(myWxidLower + '_')
)
}
}

View File

@@ -447,7 +447,7 @@ export class BackupService {
}
private async ensureConnected(wxidOverride?: string): Promise<{ success: boolean; wxid?: string; dbPath?: string; dbStorage?: string; error?: string }> {
const configuredWxid = String(this.configService.get('myWxid') || '').trim()
const configuredWxid = String(this.configService.getMyWxidCleaned() || '').trim()
const wxid = String(wxidOverride || configuredWxid || '').trim()
const dbPath = String(this.configService.get('dbPath') || '').trim()
const decryptKey = String(this.configService.get('decryptKey') || '').trim()

View File

@@ -100,7 +100,7 @@ export class BizService {
const contactInfoMap = enrichment.success && enrichment.contacts ? enrichment.contacts : {}
const root = this.configService.get('dbPath')
const myWxid = this.configService.get('myWxid')
const myWxid = this.configService.getMyWxidCleaned()
const accountWxid = account || myWxid
if (!root || !accountWxid) return []

View File

@@ -851,7 +851,7 @@ class ChatService {
// 转换为 ChatSession先加载缓存但不等待额外状态查询
const sessions: ChatSession[] = []
const now = Date.now()
const myWxid = this.configService.get('myWxid')
const myWxid = this.configService.getMyWxidCleaned()
for (const row of rows) {
const username =
@@ -1086,7 +1086,7 @@ class ChatService {
const contactMap = await this.loadAntiRevokeContactMap(privateCandidateIds)
const sessions: ChatSession[] = []
const myWxid = this.configService.get('myWxid')
const myWxid = this.configService.getMyWxidCleaned()
const now = Date.now()
for (const { username, row } of candidateRows) {
@@ -2027,7 +2027,7 @@ class ChatService {
private getContactsCacheScope(): string {
const dbPath = String(this.configService.get('dbPath') || '').trim()
const myWxid = String(this.configService.get('myWxid') || '').trim()
const myWxid = String(this.configService.getMyWxidCleaned() || '').trim()
return `${dbPath}::${myWxid}`
}
@@ -3699,7 +3699,7 @@ class ChatService {
}
}
const myWxid = String(this.configService.get('myWxid') || '').trim()
const myWxid = String(this.configService.getMyWxidCleaned() || '').trim()
const selfKeys = this.buildIdentityKeys(myWxid)
if (selfKeys.length === 0) {
return {
@@ -3877,7 +3877,7 @@ class ChatService {
private refreshSessionMessageCountCacheScope(): void {
const dbPath = String(this.configService.get('dbPath') || '')
const myWxid = String(this.configService.get('myWxid') || '')
const myWxid = String(this.configService.getMyWxidCleaned() || '')
const scope = `${dbPath}::${myWxid}`
if (scope === this.sessionMessageCountCacheScope) {
this.refreshSessionStatsCacheScope(scope)
@@ -4831,7 +4831,7 @@ class ChatService {
}
mapRowsToMessagesLiteForApi(rows: Record<string, any>[]): Message[] {
const myWxid = String(this.configService.get('myWxid') || '').trim()
const myWxid = String(this.configService.getMyWxidCleaned() || '').trim()
const messages: Message[] = []
for (const row of rows) {
const sourceInfo = this.getMessageSourceInfo(row)
@@ -4882,7 +4882,7 @@ class ChatService {
}
private mapRowsToMessages(rows: Record<string, any>[], sessionId: string): Message[] {
const myWxid = this.configService.get('myWxid')
const myWxid = this.configService.getMyWxidCleaned()
const messages: Message[] = []
for (const row of rows) {
@@ -7265,7 +7265,7 @@ class ChatService {
}
// 获取当前用户 wxid用于识别"自己"
const myWxid = this.configService.get('myWxid')
const myWxid = this.configService.getMyWxidCleaned()
const cleanedMyWxid = myWxid ? this.cleanAccountDirName(myWxid) : ''
// 解析付款方名称:自己 > 群昵称 > 备注 > 昵称 > alias > wxid
@@ -7319,7 +7319,7 @@ class ChatService {
return { success: false, error: connectResult.error }
}
const myWxid = this.configService.get('myWxid')
const myWxid = this.configService.getMyWxidCleaned()
if (!myWxid) {
return { success: false, error: '未配置微信ID' }
}
@@ -7963,7 +7963,7 @@ class ChatService {
}
if (pendingSessionIds.length > 0) {
const myWxid = this.configService.get('myWxid') || ''
const myWxid = this.configService.getMyWxidCleaned() || ''
const selfIdentitySet = new Set<string>(this.buildIdentityKeys(myWxid))
let usedBatchedCompute = false
if (pendingSessionIds.length === 1) {
@@ -8270,7 +8270,7 @@ class ChatService {
// 构建查找候选
const candidates: string[] = []
const myWxid = this.configService.get('myWxid') as string
const myWxid = this.configService.getMyWxidCleaned() as string
// 如果有 senderWxid优先使用群聊中最重要
if (senderWxid) {
@@ -8469,7 +8469,7 @@ class ChatService {
if (!normalizedSessionId) return { success: true, prepared: 0 }
if (!Array.isArray(messages) || messages.length === 0) return { success: true, prepared: 0 }
const myWxid = String(this.configService.get('myWxid') || '').trim()
const myWxid = String(this.configService.getMyWxidCleaned() || '').trim()
const nowPrepared = new Set<string>()
const pending: Array<{
cacheKey: string
@@ -9207,7 +9207,7 @@ class ChatService {
let myWxid = String(options?.myWxid || '').trim()
if (!myWxid) {
myWxid = String(this.configService.get('myWxid') || '').trim()
myWxid = String(this.configService.getMyWxidCleaned() || '').trim()
}
if (!myWxid) {
return { success: false, error: '未识别当前账号 wxid' }

View File

@@ -837,6 +837,14 @@ export class ConfigService {
// === 工具方法 ===
/**
* 获取当前用户 wxid清洗后不带后缀
*/
getMyWxidCleaned(): string {
const wxid = this.get('myWxid')
return wxid ? this.cleanAccountDirName(wxid) : ''
}
/**
* 获取当前 wxid 对应的图片密钥,优先从 wxidConfigs 中取,找不到则回退到全局配置
*/

View File

@@ -338,7 +338,7 @@ class ExportService {
}
private getConfiguredMyWxid(): string {
return String(this.runtimeConfig?.myWxid || this.configService.get('myWxid') || '').trim()
return String(this.runtimeConfig?.myWxid || this.configService.getMyWxidCleaned() || '').trim()
}
private normalizeSessionIds(sessionIds: string[]): string[] {

View File

@@ -251,7 +251,7 @@ class GroupAnalyticsService {
}
private async ensureConnected(): Promise<{ success: boolean; error?: string }> {
const wxid = this.configService.get('myWxid')
const wxid = this.configService.getMyWxidCleaned()
const dbPath = this.configService.get('dbPath')
const decryptKey = this.configService.get('decryptKey')
if (!wxid) return { success: false, error: '未配置微信ID' }
@@ -1557,7 +1557,7 @@ class GroupAnalyticsService {
const phraseCounts = new Map<string, number>()
const emojiCounts = new Map<string, number>()
const myWxid = String(this.configService.get('myWxid') || '').trim()
const myWxid = String(this.configService.getMyWxidCleaned() || '').trim()
try {
while (true) {

View File

@@ -674,7 +674,7 @@ class HttpService {
const targets = messages.filter((msg) => !String(msg.senderUsername || '').trim())
if (targets.length === 0) return
const myWxid = (this.configService.get('myWxid') || '').trim()
const myWxid = (this.configService.getMyWxidCleaned() || '').trim()
const MAX_DETAIL_BACKFILL = 120
if (targets.length > MAX_DETAIL_BACKFILL) {
for (const msg of targets) {
@@ -1832,7 +1832,7 @@ class HttpService {
mediaMap: Map<number, ApiExportedMedia> = new Map()
): Promise<ChatLabData> {
const isGroup = talkerId.endsWith('@chatroom')
const myWxid = this.configService.get('myWxid') || ''
const myWxid = this.configService.getMyWxidCleaned() || ''
const normalizedMyWxid = this.normalizeAccountId(myWxid).toLowerCase()
// 收集所有发送者

View File

@@ -109,7 +109,7 @@ export class ImageDecryptService {
}
private getConfiguredMyWxid(): string {
return String(this.runtimeConfig?.myWxid || this.configService.get('myWxid') || '').trim()
return String(this.runtimeConfig?.myWxid || this.configService.getMyWxidCleaned() || '').trim()
}
private getConfiguredImageKeys(): { xorKey: unknown; aesKey: string } {

View File

@@ -116,7 +116,7 @@ class InsightRecordService {
private getCurrentAccountScope(): string {
const config = ConfigService.getInstance()
const myWxid = String(config.get('myWxid') || '').trim()
const myWxid = String(config.getMyWxidCleaned() || '').trim()
if (myWxid) return `wxid:${myWxid}`
const dbPath = String(config.get('dbPath') || '').trim()

View File

@@ -914,7 +914,7 @@ class SnsService {
const allowTimelineFallback = options?.allowTimelineFallback ?? true
const preferCache = options?.preferCache ?? false
const now = Date.now()
const myWxid = this.toOptionalString(this.configService.get('myWxid'))
const myWxid = this.toOptionalString(this.configService.getMyWxidCleaned())
try {
if (preferCache && this.exportStatsCache && now - this.exportStatsCache.updatedAt <= this.exportStatsCacheTtlMs) {

View File

@@ -96,7 +96,7 @@ class VideoService {
* 获取当前用户的wxid
*/
private getMyWxid(): string {
return this.configService.get('myWxid') || ''
return this.configService.getMyWxidCleaned() || ''
}
/**

View File

@@ -11,6 +11,19 @@ export function getLastDllInitError(): string | null {
return lastDllInitError
}
function cleanAccountDirName(dirName: string): string {
const trimmed = dirName.trim()
if (!trimmed) return trimmed
if (trimmed.toLowerCase().startsWith('wxid_')) {
const match = trimmed.match(/^(wxid_[^_]+)/i)
if (match) return match[1]
return trimmed
}
const suffixMatch = trimmed.match(/^(.+)_([a-zA-Z0-9]{4})$/)
if (suffixMatch) return suffixMatch[1]
return trimmed
}
export class WcdbCore {
private resourcesPath: string | null = null
private userDataPath: string | null = null
@@ -1607,7 +1620,8 @@ export class WcdbCore {
}
// 从账号目录路径中提取 wxid目录名
const wxid = basename(accountDir)
const rawWxid = basename(accountDir)
const wxid = cleanAccountDirName(rawWxid)
this.handle = handle
this.currentPath = accountDir

View File

@@ -198,12 +198,37 @@ export async function setDbPath(path: string): Promise<void> {
await config.set(CONFIG_KEYS.DB_PATH, path)
}
// 获取当前用户 wxid
// 清洗账号目录名称(移除后缀)
function cleanAccountDirName(dirName: string): string {
const trimmed = dirName.trim()
if (!trimmed) return trimmed
// wxid_ 开头的特殊处理
if (trimmed.toLowerCase().startsWith('wxid_')) {
const match = trimmed.match(/^(wxid_[^_]+)/i)
if (match) return match[1]
return trimmed
}
// 移除4位后缀
const suffixMatch = trimmed.match(/^(.+)_([a-zA-Z0-9]{4})$/)
if (suffixMatch) return suffixMatch[1]
return trimmed
}
// 获取当前用户 wxid原始值可能带后缀
export async function getMyWxid(): Promise<string | null> {
const value = await config.get(CONFIG_KEYS.MY_WXID)
return value as string | null
}
// 获取当前用户 wxid清洗后不带后缀
export async function getMyWxidCleaned(): Promise<string | null> {
const value = await getMyWxid()
return value ? cleanAccountDirName(value) : null
}
// 设置当前用户 wxid
export async function setMyWxid(wxid: string): Promise<void> {
await config.set(CONFIG_KEYS.MY_WXID, wxid)