mirror of
https://github.com/LifeArchiveProject/WeChatDataAnalysis.git
synced 2026-02-19 22:30:49 +08:00
feat(detection): 添加当前登录账号检测功能
This commit is contained in:
@@ -39,6 +39,9 @@
|
||||
/* 边框颜色 */
|
||||
--border-color: #e7e7e7;
|
||||
--border-light: #f4f4f4;
|
||||
|
||||
/* 统一消息圆角(聊天所有消息共用) */
|
||||
--message-radius: 4px;
|
||||
}
|
||||
|
||||
body {
|
||||
@@ -52,6 +55,31 @@
|
||||
|
||||
/* 微信风格组件样式 */
|
||||
@layer components {
|
||||
/* 聊天气泡尾巴(左右),与高度 42px 居中对齐 */
|
||||
.bubble-tail-l, .bubble-tail-r { position: relative; }
|
||||
.bubble-tail-l::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: -4px;
|
||||
top: 12px; /* 36px 中线 18px,减去 6px ≈ 12px */
|
||||
width: 12px; height: 12px;
|
||||
background: #FFFFFF;
|
||||
transform: rotate(45deg);
|
||||
border-radius: 2px;
|
||||
}
|
||||
.bubble-tail-r::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
right: -4px;
|
||||
top: 12px;
|
||||
width: 12px; height: 12px;
|
||||
background: #95EC69;
|
||||
transform: rotate(45deg);
|
||||
border-radius: 2px;
|
||||
}
|
||||
/* 统一的消息圆角工具类 */
|
||||
.msg-radius { border-radius: var(--message-radius); }
|
||||
.msg-bubble { @apply leading-normal break-words text-pretty; border-radius: var(--message-radius); }
|
||||
/* 按钮样式 */
|
||||
.btn {
|
||||
@apply px-6 py-3 rounded-full font-medium transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 transform active:scale-95;
|
||||
|
||||
@@ -27,8 +27,23 @@ export const useApi = () => {
|
||||
}
|
||||
|
||||
// 微信检测API
|
||||
const detectWechat = async () => {
|
||||
return await request('/wechat-detection')
|
||||
const detectWechat = async (params = {}) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params && params.data_root_path) {
|
||||
query.set('data_root_path', params.data_root_path)
|
||||
}
|
||||
const url = '/wechat-detection' + (query.toString() ? `?${query.toString()}` : '')
|
||||
return await request(url)
|
||||
}
|
||||
|
||||
// 检测当前登录账号API
|
||||
const detectCurrentAccount = async (params = {}) => {
|
||||
const query = new URLSearchParams()
|
||||
if (params && params.data_root_path) {
|
||||
query.set('data_root_path', params.data_root_path)
|
||||
}
|
||||
const url = '/current-account' + (query.toString() ? `?${query.toString()}` : '')
|
||||
return await request(url)
|
||||
}
|
||||
|
||||
// 数据库解密API
|
||||
@@ -46,6 +61,7 @@ export const useApi = () => {
|
||||
|
||||
return {
|
||||
detectWechat,
|
||||
detectCurrentAccount,
|
||||
decryptDatabase,
|
||||
healthCheck
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
</div>
|
||||
<div class="w-12 h-12 bg-[#10AEEF]/10 rounded-lg flex items-center justify-center">
|
||||
<svg class="w-6 h-6 text-[#10AEEF]" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"/>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283-.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
@@ -110,6 +110,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 账户列表 -->
|
||||
@@ -119,8 +120,9 @@
|
||||
<h3 class="text-base font-semibold text-[#000000e6]">微信账户详情</h3>
|
||||
</div>
|
||||
<div class="divide-y divide-[#EDEDED] max-h-64 overflow-y-auto">
|
||||
<div v-for="(account, index) in detectionResult.data.accounts" :key="index"
|
||||
class="p-4 hover:bg-gray-50 transition-all duration-200">
|
||||
<!-- 将当前登录账号放在第一位 -->
|
||||
<div v-for="(account, index) in sortedAccounts" :key="index"
|
||||
:class="['p-4 hover:bg-gray-50 transition-all duration-200', isCurrentAccount(account.account_name) ? 'bg-[#07C160]/5' : '']">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex-1">
|
||||
<div class="flex items-center">
|
||||
@@ -128,7 +130,17 @@
|
||||
<span class="text-[#07C160] font-bold text-lg">{{ account.account_name?.charAt(0)?.toUpperCase() || 'U' }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-lg font-medium text-[#000000e6]">{{ account.account_name || '未知账户' }}</p>
|
||||
<div class="flex items-center">
|
||||
<p class="text-lg font-medium text-[#000000e6]">{{ account.account_name || '未知账户' }}</p>
|
||||
<!-- 当前登录账号标识 -->
|
||||
<span v-if="isCurrentAccount(account.account_name)"
|
||||
class="ml-2 inline-flex items-center px-2 py-1 bg-[#07C160]/10 text-[#07C160] rounded text-xs font-medium">
|
||||
<svg class="w-3 h-3 mr-1" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z" clip-rule="evenodd"/>
|
||||
</svg>
|
||||
当前登录
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center mt-1 space-x-4 text-sm text-[#7F7F7F]">
|
||||
<span class="flex items-center">
|
||||
<svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
@@ -192,14 +204,35 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { ref, onMounted, computed } from 'vue'
|
||||
import { useApi } from '~/composables/useApi'
|
||||
import { useAppStore } from '~/stores/app'
|
||||
|
||||
const { detectWechat } = useApi()
|
||||
const { detectWechat, detectCurrentAccount } = useApi()
|
||||
const appStore = useAppStore()
|
||||
const loading = ref(false)
|
||||
const detectionResult = ref(null)
|
||||
const customPath = ref('')
|
||||
|
||||
// 计算属性:将当前登录账号排在第一位
|
||||
const sortedAccounts = computed(() => {
|
||||
if (!detectionResult.value?.data?.accounts) return []
|
||||
|
||||
const accounts = [...detectionResult.value.data.accounts]
|
||||
const currentAccountName = detectionResult.value.data?.current_account?.current_account
|
||||
|
||||
if (!currentAccountName) return accounts
|
||||
|
||||
// 将当前登录账号移到第一位
|
||||
const sorted = accounts.sort((a, b) => {
|
||||
if (a.account_name === currentAccountName) return -1
|
||||
if (b.account_name === currentAccountName) return 1
|
||||
return 0
|
||||
})
|
||||
|
||||
return sorted
|
||||
})
|
||||
|
||||
// 开始检测
|
||||
const startDetection = async () => {
|
||||
loading.value = true
|
||||
@@ -209,8 +242,28 @@ const startDetection = async () => {
|
||||
if (customPath.value && customPath.value.trim()) {
|
||||
params.data_root_path = customPath.value.trim()
|
||||
}
|
||||
|
||||
// 检测微信安装信息
|
||||
const result = await detectWechat(params)
|
||||
detectionResult.value = result
|
||||
|
||||
// 如果检测成功,同时检测当前登录账号
|
||||
if (result.status === 'success') {
|
||||
try {
|
||||
const currentAccountResult = await detectCurrentAccount(params)
|
||||
if (currentAccountResult.status === 'success') {
|
||||
// 保存当前账号信息到状态管理
|
||||
appStore.setCurrentAccount(currentAccountResult.data)
|
||||
|
||||
// 同时更新检测结果中的当前账号信息
|
||||
if (detectionResult.value.data) {
|
||||
detectionResult.value.data.current_account = currentAccountResult.data
|
||||
}
|
||||
}
|
||||
} catch (accountErr) {
|
||||
console.error('检测当前登录账号失败:', accountErr)
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('检测过程中发生错误:', err)
|
||||
detectionResult.value = {
|
||||
@@ -237,6 +290,36 @@ const goToDecrypt = (account) => {
|
||||
navigateTo('/decrypt')
|
||||
}
|
||||
|
||||
// 判断是否为当前登录账号
|
||||
const isCurrentAccount = (accountName) => {
|
||||
if (!detectionResult.value?.data?.current_account) {
|
||||
return false
|
||||
}
|
||||
return detectionResult.value.data.current_account.current_account === accountName
|
||||
}
|
||||
|
||||
// 获取当前登录账号信息
|
||||
const getCurrentAccountInfo = () => {
|
||||
return detectionResult.value?.data?.current_account
|
||||
}
|
||||
|
||||
// 格式化时间显示
|
||||
const formatTime = (timeString) => {
|
||||
if (!timeString) return ''
|
||||
try {
|
||||
const date = new Date(timeString)
|
||||
return date.toLocaleString('zh-CN', {
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
})
|
||||
} catch {
|
||||
return timeString
|
||||
}
|
||||
}
|
||||
|
||||
// 页面加载时自动检测
|
||||
onMounted(() => {
|
||||
startDetection()
|
||||
|
||||
@@ -9,6 +9,9 @@ export const useAppStore = defineStore('app', {
|
||||
// 最近的检测结果
|
||||
lastDetectionResult: null,
|
||||
|
||||
// 当前登录账号信息
|
||||
currentAccount: null,
|
||||
|
||||
// 全局加载状态
|
||||
globalLoading: false,
|
||||
|
||||
@@ -28,6 +31,11 @@ export const useAppStore = defineStore('app', {
|
||||
this.lastDetectionResult = result
|
||||
},
|
||||
|
||||
// 设置当前登录账号
|
||||
setCurrentAccount(account) {
|
||||
this.currentAccount = account
|
||||
},
|
||||
|
||||
// 设置全局加载状态
|
||||
setGlobalLoading(loading) {
|
||||
this.globalLoading = loading
|
||||
|
||||
@@ -277,9 +277,13 @@ async def detect_wechat_detailed(data_root_path: Optional[str] = None):
|
||||
"""详细检测微信安装信息,包括版本、路径、消息目录等。"""
|
||||
logger.info("开始执行微信检测")
|
||||
try:
|
||||
from .wechat_detection import detect_wechat_installation
|
||||
from .wechat_detection import detect_wechat_installation, detect_current_logged_in_account
|
||||
info = detect_wechat_installation(data_root_path=data_root_path)
|
||||
|
||||
# 检测当前登录账号
|
||||
current_account_info = detect_current_logged_in_account(data_root_path)
|
||||
info['current_account'] = current_account_info
|
||||
|
||||
# 添加一些统计信息
|
||||
stats = {
|
||||
'total_databases': len(info['databases']),
|
||||
@@ -306,6 +310,29 @@ async def detect_wechat_detailed(data_root_path: Optional[str] = None):
|
||||
}
|
||||
|
||||
|
||||
@app.get("/api/current-account", summary="检测当前登录账号")
|
||||
async def detect_current_account(data_root_path: Optional[str] = None):
|
||||
"""检测当前登录的微信账号"""
|
||||
logger.info("开始检测当前登录账号")
|
||||
try:
|
||||
from .wechat_detection import detect_current_logged_in_account
|
||||
result = detect_current_logged_in_account(data_root_path)
|
||||
|
||||
logger.info(f"当前账号检测完成: {result.get('message', '无结果')}")
|
||||
|
||||
return {
|
||||
'status': 'success',
|
||||
'data': result
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error(f"当前账号检测失败: {str(e)}")
|
||||
return {
|
||||
'status': 'error',
|
||||
'error': str(e),
|
||||
'data': None
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import ctypes
|
||||
from pathlib import Path
|
||||
from typing import List, Dict, Any, Union
|
||||
from ctypes import wintypes
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
|
||||
@@ -421,6 +422,135 @@ def detect_wechat_accounts_from_backup(backup_base_path: str = None) -> List[Dic
|
||||
return accounts
|
||||
|
||||
|
||||
def _resolve_login_paths_from_base(provided_path: str) -> Dict[str, str]:
|
||||
"""
|
||||
根据用户提供的路径推断 base_path 和 login_dir。
|
||||
|
||||
兼容三种传入:
|
||||
- 直接传 xwechat_files 根目录
|
||||
- 传 xwechat_files/all_users
|
||||
- 传 xwechat_files/all_users/login
|
||||
"""
|
||||
base_path = provided_path
|
||||
login_dir = os.path.join(provided_path, "all_users", "login")
|
||||
|
||||
try:
|
||||
norm = os.path.normpath(provided_path)
|
||||
last = os.path.basename(norm).lower()
|
||||
parent = os.path.dirname(norm)
|
||||
parent_last = os.path.basename(parent).lower() if parent else ""
|
||||
|
||||
if last == "login" and parent_last == "all_users":
|
||||
# .../xwechat_files/all_users/login -> base_path 为 xwechat_files
|
||||
base_path = os.path.dirname(parent)
|
||||
login_dir = norm
|
||||
elif last == "all_users":
|
||||
# .../xwechat_files/all_users -> login_dir 追加 login
|
||||
base_path = os.path.dirname(norm)
|
||||
login_dir = os.path.join(norm, "login")
|
||||
else:
|
||||
# 认为传的是 xwechat_files 根
|
||||
base_path = norm
|
||||
login_dir = os.path.join(norm, "all_users", "login")
|
||||
except Exception:
|
||||
# 兜底:保持初始推断
|
||||
pass
|
||||
|
||||
return {"base_path": base_path, "login_dir": login_dir}
|
||||
|
||||
|
||||
def detect_wechat_accounts_from_login(login_base_path: str = None) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
通过登录信息目录检测微信账号,并映射到实际数据目录。
|
||||
|
||||
Args:
|
||||
login_base_path: 可选的微信数据根目录。
|
||||
|
||||
Returns:
|
||||
账号信息列表(与 Backup 检测返回结构一致)
|
||||
"""
|
||||
accounts: List[Dict[str, Any]] = []
|
||||
|
||||
# 若用户提供路径,则优先按该路径推断
|
||||
if login_base_path:
|
||||
paths = _resolve_login_paths_from_base(login_base_path)
|
||||
base_path = paths["base_path"]
|
||||
login_dir = paths["login_dir"]
|
||||
|
||||
if not os.path.exists(login_dir):
|
||||
return accounts
|
||||
else:
|
||||
# 自动检测:遍历候选根目录,寻找登录信息目录
|
||||
base_path = None
|
||||
login_dir = None
|
||||
detected_dirs = auto_detect_wechat_data_dirs()
|
||||
for detected_dir in detected_dirs:
|
||||
try:
|
||||
test_login = os.path.join(detected_dir, "all_users", "login")
|
||||
if os.path.exists(test_login):
|
||||
base_path = detected_dir
|
||||
login_dir = test_login
|
||||
break
|
||||
|
||||
# 也检查一层子目录
|
||||
for sub in os.listdir(detected_dir):
|
||||
sub_path = os.path.join(detected_dir, sub)
|
||||
if not os.path.isdir(sub_path):
|
||||
continue
|
||||
test_login = os.path.join(sub_path, "all_users", "login")
|
||||
if os.path.exists(test_login):
|
||||
base_path = sub_path
|
||||
login_dir = test_login
|
||||
break
|
||||
if base_path:
|
||||
break
|
||||
except (PermissionError, OSError):
|
||||
continue
|
||||
|
||||
if not base_path or not login_dir:
|
||||
return accounts
|
||||
|
||||
# 枚举 login 目录下的子项,每个子项代表一个账号标识(可能是文件或文件夹)
|
||||
try:
|
||||
for item in os.listdir(login_dir):
|
||||
account_name = item
|
||||
account_login_item_path = os.path.join(login_dir, item)
|
||||
# 无论是文件还是文件夹,都视为一个账号标识
|
||||
if not os.path.exists(account_login_item_path):
|
||||
continue
|
||||
|
||||
# 在 base_path 下查找以 {account_name}_ 开头的数据目录(与 Backup 规则一致)
|
||||
data_dir = None
|
||||
try:
|
||||
for data_item in os.listdir(base_path):
|
||||
data_item_path = os.path.join(base_path, data_item)
|
||||
if (
|
||||
os.path.isdir(data_item_path)
|
||||
and data_item.startswith(f"{account_name}_")
|
||||
and data_item not in ["Backup", "all_users"]
|
||||
):
|
||||
data_dir = data_item_path
|
||||
break
|
||||
except (PermissionError, OSError):
|
||||
pass
|
||||
|
||||
databases = collect_account_databases(data_dir, account_name) if data_dir else []
|
||||
|
||||
accounts.append(
|
||||
{
|
||||
"account_name": account_name,
|
||||
"backup_dir": None,
|
||||
"data_dir": data_dir,
|
||||
"databases": databases,
|
||||
"database_count": len(databases),
|
||||
}
|
||||
)
|
||||
except (PermissionError, OSError):
|
||||
# 无权限访问时返回已收集的账号
|
||||
return accounts
|
||||
|
||||
return accounts
|
||||
|
||||
def collect_account_databases(data_dir: str, account_name: str) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
收集指定账号数据目录下的所有数据库文件
|
||||
@@ -474,7 +604,7 @@ def collect_account_databases(data_dir: str, account_name: str) -> List[Dict[str
|
||||
return databases
|
||||
|
||||
|
||||
def detect_wechat_installation() -> Dict[str, Any]:
|
||||
def detect_wechat_installation(data_root_path: str | None = None) -> Dict[str, Any]:
|
||||
"""
|
||||
检测微信安装情况 - 改进的多账户检测逻辑
|
||||
"""
|
||||
@@ -528,47 +658,92 @@ def detect_wechat_installation() -> Dict[str, Any]:
|
||||
if not result["is_running"]:
|
||||
result["detection_methods"].append("未检测到微信进程")
|
||||
|
||||
# 2. 使用新的账号检测逻辑
|
||||
result["detection_methods"].append("多账户检测")
|
||||
# 2. 使用新的账号检测逻辑:同时支持 Backup 与登录信息目录,并合并结果
|
||||
result["detection_methods"].append("多账户检测(多来源合并)")
|
||||
try:
|
||||
# 检测指定路径下的微信账号
|
||||
accounts = detect_wechat_accounts_from_backup()
|
||||
# 支持前端兜底路径:若提供 data_root_path,则两种方式都以该路径为基准
|
||||
accounts_from_backup = detect_wechat_accounts_from_backup(
|
||||
backup_base_path=data_root_path
|
||||
)
|
||||
accounts_from_login = detect_wechat_accounts_from_login(
|
||||
login_base_path=data_root_path
|
||||
)
|
||||
|
||||
# 合并账号:按 account_name 去重,优先保留信息更完整者
|
||||
account_map: Dict[str, Dict[str, Any]] = {}
|
||||
|
||||
def _merge_account(acc: Dict[str, Any]):
|
||||
name = acc.get("account_name")
|
||||
if not name:
|
||||
return
|
||||
if name not in account_map:
|
||||
account_map[name] = {
|
||||
"account_name": name,
|
||||
"backup_dir": acc.get("backup_dir"),
|
||||
"data_dir": acc.get("data_dir"),
|
||||
"databases": list(acc.get("databases", [])),
|
||||
"database_count": int(acc.get("database_count", 0)),
|
||||
}
|
||||
else:
|
||||
existing = account_map[name]
|
||||
if not existing.get("backup_dir") and acc.get("backup_dir"):
|
||||
existing["backup_dir"] = acc.get("backup_dir")
|
||||
if not existing.get("data_dir") and acc.get("data_dir"):
|
||||
existing["data_dir"] = acc.get("data_dir")
|
||||
# 合并数据库(按 path 去重)
|
||||
seen_paths = {d.get("path") for d in existing.get("databases", [])}
|
||||
for db in acc.get("databases", []):
|
||||
if db.get("path") not in seen_paths:
|
||||
existing.setdefault("databases", []).append(db)
|
||||
seen_paths.add(db.get("path"))
|
||||
existing["database_count"] = len(existing.get("databases", []))
|
||||
|
||||
for acc in accounts_from_backup:
|
||||
_merge_account(acc)
|
||||
for acc in accounts_from_login:
|
||||
_merge_account(acc)
|
||||
|
||||
accounts = list(account_map.values())
|
||||
result["accounts"] = accounts
|
||||
result["total_accounts"] = len(accounts)
|
||||
|
||||
# 统计总数据库数量
|
||||
total_db_count = sum(account["database_count"] for account in accounts)
|
||||
total_db_count = sum(account.get("database_count", 0) for account in accounts)
|
||||
result["total_databases"] = total_db_count
|
||||
|
||||
if accounts:
|
||||
result["detection_methods"].append(f"在指定路径检测到 {len(accounts)} 个微信账户")
|
||||
result["detection_methods"].append(
|
||||
f"检测到 {len(accounts)} 个微信账户(已合并两种来源)"
|
||||
)
|
||||
result["detection_methods"].append(f"总计 {total_db_count} 个数据库文件")
|
||||
|
||||
# 为每个账户添加详细信息
|
||||
for account in accounts:
|
||||
account_name = account["account_name"]
|
||||
db_count = account["database_count"]
|
||||
data_dir_status = "已找到" if account["data_dir"] else "未找到"
|
||||
result["detection_methods"].append(f"账户 {account_name}: {db_count} 个数据库, 数据目录{data_dir_status}")
|
||||
account_name = account.get("account_name")
|
||||
db_count = account.get("database_count", 0)
|
||||
data_dir_status = "已找到" if account.get("data_dir") else "未找到"
|
||||
result["detection_methods"].append(
|
||||
f"账户 {account_name}: {db_count} 个数据库, 数据目录{data_dir_status}"
|
||||
)
|
||||
else:
|
||||
result["detection_methods"].append("未在指定路径检测到微信账户")
|
||||
result["detection_methods"].append("未检测到微信账户")
|
||||
|
||||
# 填充向后兼容性字段
|
||||
for account in accounts:
|
||||
if account["data_dir"]:
|
||||
if account.get("data_dir"):
|
||||
result["wechat_data_dirs"].append(account["data_dir"])
|
||||
result["message_dirs"].append(account["data_dir"])
|
||||
result["user_accounts"].append(account["account_name"])
|
||||
result["user_accounts"].append(account.get("account_name"))
|
||||
|
||||
# 添加数据库到兼容性列表
|
||||
for db in account["databases"]:
|
||||
for db in account.get("databases", []):
|
||||
result["databases"].append({
|
||||
"path": db["path"],
|
||||
"name": db["name"],
|
||||
"type": db["type"],
|
||||
"size": db["size"],
|
||||
"user": account["account_name"],
|
||||
"user_dir": account["data_dir"]
|
||||
"user": account.get("account_name"),
|
||||
"user_dir": account.get("data_dir"),
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
@@ -624,6 +799,129 @@ def detect_wechat_installation() -> Dict[str, Any]:
|
||||
return result
|
||||
|
||||
|
||||
def detect_current_logged_in_account(base_path: str = None) -> Dict[str, Any]:
|
||||
"""
|
||||
通过key_info.db文件时间检测当前登录的微信账号
|
||||
|
||||
Args:
|
||||
base_path: 微信数据根目录,如果为None则自动检测
|
||||
|
||||
Returns:
|
||||
当前登录账号信息
|
||||
"""
|
||||
current_account = None
|
||||
latest_time = None
|
||||
|
||||
# 添加调试信息
|
||||
print(f"[DEBUG] 开始检测当前登录账号,提供的base_path: {base_path}")
|
||||
|
||||
# 如果没有指定路径,尝试自动检测
|
||||
if base_path is None:
|
||||
detected_dirs = auto_detect_wechat_data_dirs()
|
||||
print(f"[DEBUG] 自动检测到的目录: {detected_dirs}")
|
||||
if not detected_dirs:
|
||||
return {
|
||||
"current_account": None,
|
||||
"latest_time": None,
|
||||
"message": "未检测到微信数据目录"
|
||||
}
|
||||
base_path = detected_dirs[0]
|
||||
|
||||
print(f"[DEBUG] 使用的base_path: {base_path}")
|
||||
|
||||
# 查找登录信息目录 - 尝试多个可能的路径
|
||||
possible_login_paths = [
|
||||
os.path.join(base_path, "all_users", "login"), # 标准路径
|
||||
os.path.join(base_path, "login"), # 备选路径1
|
||||
]
|
||||
|
||||
# 也尝试在子目录中查找
|
||||
try:
|
||||
for item in os.listdir(base_path):
|
||||
item_path = os.path.join(base_path, item)
|
||||
if os.path.isdir(item_path):
|
||||
possible_login_paths.extend([
|
||||
os.path.join(item_path, "all_users", "login"), # 子目录中的标准路径
|
||||
os.path.join(item_path, "login"), # 子目录中的备选路径
|
||||
])
|
||||
except (PermissionError, OSError):
|
||||
pass
|
||||
|
||||
login_dir = None
|
||||
for path in possible_login_paths:
|
||||
print(f"[DEBUG] 检查路径: {path}")
|
||||
if os.path.exists(path):
|
||||
login_dir = path
|
||||
print(f"[DEBUG] 找到登录目录: {login_dir}")
|
||||
break
|
||||
|
||||
if not login_dir:
|
||||
return {
|
||||
"current_account": None,
|
||||
"latest_time": None,
|
||||
"message": f"未找到登录信息目录,尝试的路径: {possible_login_paths}"
|
||||
}
|
||||
|
||||
try:
|
||||
# 遍历登录目录下的所有账号文件夹
|
||||
items = os.listdir(login_dir)
|
||||
print(f"[DEBUG] 登录目录内容: {items}")
|
||||
|
||||
for item in items:
|
||||
item_path = os.path.join(login_dir, item)
|
||||
print(f"[DEBUG] 检查项目: {item}, 路径: {item_path}, 是否为目录: {os.path.isdir(item_path)}")
|
||||
|
||||
if not os.path.isdir(item_path):
|
||||
continue
|
||||
|
||||
# 检查key_info.db文件
|
||||
key_info_path = os.path.join(item_path, "key_info.db")
|
||||
print(f"[DEBUG] 检查key_info.db文件: {key_info_path}, 是否存在: {os.path.exists(key_info_path)}")
|
||||
|
||||
if not os.path.exists(key_info_path):
|
||||
continue
|
||||
|
||||
# 获取文件修改时间
|
||||
try:
|
||||
file_time = os.path.getmtime(key_info_path)
|
||||
file_datetime = datetime.fromtimestamp(file_time)
|
||||
print(f"[DEBUG] 找到key_info.db文件: {key_info_path}, 修改时间: {file_datetime}")
|
||||
|
||||
# 更新最新登录的账号
|
||||
if latest_time is None or file_time > latest_time:
|
||||
latest_time = file_time
|
||||
current_account = item
|
||||
print(f"[DEBUG] 更新最新登录账号: {current_account}, 时间: {file_datetime}")
|
||||
|
||||
except OSError as e:
|
||||
print(f"[DEBUG] 无法获取文件时间: {key_info_path}, 错误: {e}")
|
||||
continue
|
||||
|
||||
except (PermissionError, OSError) as e:
|
||||
print(f"[DEBUG] 无法访问登录目录: {login_dir}, 错误: {e}")
|
||||
return {
|
||||
"current_account": None,
|
||||
"latest_time": None,
|
||||
"message": f"无法访问登录目录: {e}"
|
||||
}
|
||||
|
||||
if current_account:
|
||||
print(f"[DEBUG] 最终结果: 当前登录账号 {current_account}, 时间 {latest_time}")
|
||||
return {
|
||||
"current_account": current_account,
|
||||
"latest_time": latest_time,
|
||||
"latest_time_formatted": datetime.fromtimestamp(latest_time).isoformat() if latest_time else None,
|
||||
"message": f"检测到当前登录账号: {current_account}"
|
||||
}
|
||||
else:
|
||||
print(f"[DEBUG] 最终结果: 未检测到当前登录账号")
|
||||
return {
|
||||
"current_account": None,
|
||||
"latest_time": None,
|
||||
"message": "未检测到当前登录账号"
|
||||
}
|
||||
|
||||
|
||||
def get_wechat_info() -> Dict[str, Any]:
|
||||
"""获取微信安装和数据库信息
|
||||
|
||||
|
||||
Reference in New Issue
Block a user