diff --git a/CHANGELOG.md b/CHANGELOG.md index 4746ea8..0602550 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +### Changed + +- Accept WeChat 4.1.7 and newer for key extraction instead of maintaining a fixed version-prefix allowlist. + ## [0.7.4] - 2026-07-22 ### Features diff --git a/CHANGELOG.zh-CN.md b/CHANGELOG.zh-CN.md index a477e1c..fa91187 100644 --- a/CHANGELOG.zh-CN.md +++ b/CHANGELOG.zh-CN.md @@ -4,6 +4,10 @@ ## [未发布] +### 变更 + +- 密钥提取改为支持 WeChat 4.1.7 及以上版本,不再维护固定版本前缀白名单。 + ## [0.7.4] - 2026-07-22 ### 功能 diff --git a/README.md b/README.md index 76e4ad8..1936a35 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ wx-cli 提供了最关键的两样东西:完整的历史上下文,以及持 ## 支持范围 - **平台**:macOS(arm64 / Apple Silicon) -- **WeChat 版本**:4.1.7.x / 4.1.8.x +- **WeChat 版本**:4.1.7 及以上 ## 前置条件 @@ -265,4 +265,4 @@ wx-cli/ - `wx-cli key list` 确认密钥正确 - `wx-cli info ` 检查文件是否为加密状态 -- 确认 WeChat 版本在 4.1.7.x / 4.1.8.x 范围内 +- 确认 WeChat 版本不低于 4.1.7 diff --git a/crates/wx-keychain/src/error.rs b/crates/wx-keychain/src/error.rs index 97b2ad9..1865fbc 100644 --- a/crates/wx-keychain/src/error.rs +++ b/crates/wx-keychain/src/error.rs @@ -20,7 +20,9 @@ pub enum KeychainError { #[error("WeChat is not running")] WeChatNotRunning, - #[error("WeChat version {version} is not supported for key extraction (requires 4.1.7.x or 4.1.8.x)")] + #[error( + "WeChat version {version} is not supported for key extraction (requires 4.1.7 or newer)" + )] UnsupportedVersion { version: String }, #[error("could not detect WeChat account directory")] diff --git a/crates/wx-keychain/src/process.rs b/crates/wx-keychain/src/process.rs index ee3ed04..f548cea 100644 --- a/crates/wx-keychain/src/process.rs +++ b/crates/wx-keychain/src/process.rs @@ -3,17 +3,30 @@ use std::process::Command; use crate::error::KeychainError; -pub const SUPPORTED_VERSION: &str = "4.1.8.21"; +pub const SUPPORTED_VERSION: &str = "4.1.7+"; -/// Version prefixes accepted for LLDB key extraction. -/// Encryption params (PBKDF2-HMAC-SHA512, 256K iterations) are identical across these versions. -const EXTRACTION_VERSION_PREFIXES: &[&str] = &["4.1.7", "4.1.8"]; +/// Minimum version accepted for key extraction. +/// Encryption params (PBKDF2-HMAC-SHA512, 256K iterations) are identical from this version onward. +const MIN_EXTRACTION_VERSION: (u64, u64, u64) = (4, 1, 7); /// Check whether a version string is compatible with our LLDB key extraction. fn is_extraction_compatible(version: &str) -> bool { - EXTRACTION_VERSION_PREFIXES - .iter() - .any(|prefix| version == *prefix || version.starts_with(&format!("{prefix}."))) + let mut components = version.split('.'); + let Some(major) = components.next().and_then(|value| value.parse().ok()) else { + return false; + }; + let Some(minor) = components.next().and_then(|value| value.parse().ok()) else { + return false; + }; + let Some(patch) = components.next().and_then(|value| value.parse().ok()) else { + return false; + }; + + if components.any(|value| value.is_empty() || value.parse::().is_err()) { + return false; + } + + (major, minor, patch) >= MIN_EXTRACTION_VERSION } #[derive(Debug, Clone)] @@ -354,6 +367,28 @@ fn tiebreak_by_wal_mtime<'a>(accounts: &[&'a AccountDirInfo]) -> Option<&'a Acco mod tests { use super::*; + #[test] + fn test_extraction_version_accepts_4_1_7_and_newer() { + for version in [ + "4.1.7", "4.1.7.31", "4.1.8", "4.1.9", "4.1.13", "4.2.0", "5.0.0", + ] { + assert!( + is_extraction_compatible(version), + "expected {version} to be supported" + ); + } + } + + #[test] + fn test_extraction_version_rejects_older_and_invalid_versions() { + for version in ["4.1.6.99", "4.0.99", "3.9.9", "4.1", "4.1.beta", ""] { + assert!( + !is_extraction_compatible(version), + "expected {version:?} to be rejected" + ); + } + } + #[test] fn test_extract_base_wxid_with_suffix() { assert_eq!(