feat(attachment): scaffold module + V1 decoders + resource resolver

Lays down the skeleton for聊天附件 (chat attachment) extraction. This commit
introduces the `attachment` module with:

- `attachment_id`: opaque base64url(json) round-trip handle for CLI/IPC. Carries
  `(chat, local_id, create_time, kind)` — `local_id` alone is not unique
  (实测同 chat 内最多 7 条同 local_id 的记录), so create_time is required for
  disambiguation.
- `decoder/`: dispatch by 6B header magic. Three branches:
  - `V2_MAGIC` → AES-128-ECB + raw + XOR (need image AES key)
  - `V1_MAGIC` → AES-128-ECB with fixed key `cfcd208495d565ef` (= md5("0")[:16])
  - else → legacy single-byte XOR with magic auto-detect
  Manual ECB + PKCS7 unpad to avoid pulling in another crate.
- `resolver`: `message_resource.db` lookup chain
  `username → ChatName2Id.rowid → MessageResourceInfo.packed_info → md5`
  + on-disk `.dat` selection (full > _h > _t) under
  `<wxchat_base>/msg/attach/<md5(chat)>/<YYYY-MM>/Img/<md5>[_t|_h].dat`.
  Honors `message_local_type % 2^32` to strip the high flag bits, and orders by
  `message_create_time DESC` to handle local_id reuse.
- `image_key/`: stub trait + macOS / Windows placeholders. To be filled by
  codex with the V2 image key extraction (kvcomm + brute-force on macOS, memory
  scan on Windows).

V1 decoder ships with 6 unit tests covering every supported magic + the BMP
extra validation; resolver ships with packed_info parser + dat-file selection
tests; v2 decoder ships with header validation tests. 21 tests pass.

`cargo check` and `cargo check --target x86_64-pc-windows-gnu` both clean.
This commit is contained in:
jackwener
2026-05-14 18:25:32 +08:00
parent 5c001b18be
commit 14fdfde1d3
12 changed files with 1017 additions and 0 deletions
Generated
+7
View File
@@ -105,6 +105,12 @@ version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
name = "base64"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "bitflags"
version = "2.11.1"
@@ -1311,6 +1317,7 @@ version = "0.1.11"
dependencies = [
"aes",
"anyhow",
"base64",
"cbc",
"chrono",
"clap",