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.