wxq 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- wxq-1.0.0/LICENSE +21 -0
- wxq-1.0.0/PKG-INFO +286 -0
- wxq-1.0.0/README.md +250 -0
- wxq-1.0.0/pyproject.toml +69 -0
- wxq-1.0.0/setup.cfg +4 -0
- wxq-1.0.0/src/wxq/__init__.py +3 -0
- wxq-1.0.0/src/wxq/bin/find_all_keys_macos.arm64 +0 -0
- wxq-1.0.0/src/wxq/bin/find_all_keys_macos.c +319 -0
- wxq-1.0.0/src/wxq/cli.py +82 -0
- wxq-1.0.0/src/wxq/commands/__init__.py +1 -0
- wxq-1.0.0/src/wxq/commands/contacts.py +102 -0
- wxq-1.0.0/src/wxq/commands/export.py +118 -0
- wxq-1.0.0/src/wxq/commands/favorites.py +155 -0
- wxq-1.0.0/src/wxq/commands/history.py +104 -0
- wxq-1.0.0/src/wxq/commands/init.py +69 -0
- wxq-1.0.0/src/wxq/commands/members.py +72 -0
- wxq-1.0.0/src/wxq/commands/new_messages.py +173 -0
- wxq-1.0.0/src/wxq/commands/search.py +151 -0
- wxq-1.0.0/src/wxq/commands/sessions.py +89 -0
- wxq-1.0.0/src/wxq/commands/stats.py +93 -0
- wxq-1.0.0/src/wxq/commands/unread.py +91 -0
- wxq-1.0.0/src/wxq/core/__init__.py +1 -0
- wxq-1.0.0/src/wxq/core/config.py +225 -0
- wxq-1.0.0/src/wxq/core/contacts.py +239 -0
- wxq-1.0.0/src/wxq/core/context.py +69 -0
- wxq-1.0.0/src/wxq/core/crypto.py +170 -0
- wxq-1.0.0/src/wxq/core/db_cache.py +131 -0
- wxq-1.0.0/src/wxq/core/key_utils.py +63 -0
- wxq-1.0.0/src/wxq/exceptions.py +77 -0
- wxq-1.0.0/src/wxq/keys/__init__.py +47 -0
- wxq-1.0.0/src/wxq/keys/common.py +256 -0
- wxq-1.0.0/src/wxq/keys/scanner_linux.py +275 -0
- wxq-1.0.0/src/wxq/keys/scanner_macos.py +263 -0
- wxq-1.0.0/src/wxq/keys/scanner_windows.py +246 -0
- wxq-1.0.0/src/wxq/mcp/__init__.py +1 -0
- wxq-1.0.0/src/wxq/mcp/server.py +465 -0
- wxq-1.0.0/src/wxq/models/__init__.py +23 -0
- wxq-1.0.0/src/wxq/models/config.py +27 -0
- wxq-1.0.0/src/wxq/models/contact.py +85 -0
- wxq-1.0.0/src/wxq/models/keys.py +25 -0
- wxq-1.0.0/src/wxq/models/message.py +150 -0
- wxq-1.0.0/src/wxq/models/session.py +31 -0
- wxq-1.0.0/src/wxq/output/__init__.py +1 -0
- wxq-1.0.0/src/wxq/output/formatter.py +41 -0
- wxq-1.0.0/src/wxq/py.typed +0 -0
- wxq-1.0.0/src/wxq/services/__init__.py +1 -0
- wxq-1.0.0/src/wxq/services/message_parser.py +354 -0
- wxq-1.0.0/src/wxq/services/message_service.py +706 -0
- wxq-1.0.0/src/wxq.egg-info/PKG-INFO +286 -0
- wxq-1.0.0/src/wxq.egg-info/SOURCES.txt +68 -0
- wxq-1.0.0/src/wxq.egg-info/dependency_links.txt +1 -0
- wxq-1.0.0/src/wxq.egg-info/entry_points.txt +3 -0
- wxq-1.0.0/src/wxq.egg-info/requires.txt +12 -0
- wxq-1.0.0/src/wxq.egg-info/top_level.txt +1 -0
- wxq-1.0.0/tests/test_adversarial.py +150 -0
- wxq-1.0.0/tests/test_cli_integration.py +153 -0
- wxq-1.0.0/tests/test_cli_more.py +124 -0
- wxq-1.0.0/tests/test_config.py +103 -0
- wxq-1.0.0/tests/test_contacts.py +115 -0
- wxq-1.0.0/tests/test_crypto.py +123 -0
- wxq-1.0.0/tests/test_db_cache.py +108 -0
- wxq-1.0.0/tests/test_exceptions.py +65 -0
- wxq-1.0.0/tests/test_key_utils.py +70 -0
- wxq-1.0.0/tests/test_mcp_server.py +180 -0
- wxq-1.0.0/tests/test_message_parser.py +108 -0
- wxq-1.0.0/tests/test_message_parser_xml.py +231 -0
- wxq-1.0.0/tests/test_message_service.py +281 -0
- wxq-1.0.0/tests/test_models.py +160 -0
- wxq-1.0.0/tests/test_output.py +45 -0
- wxq-1.0.0/tests/test_skill_doc.py +100 -0
wxq-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 wxq contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
wxq-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: wxq
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: 微信本地聊天记录查询工具 — WeChat local chat history query, CLI + MCP server for AI agents
|
|
5
|
+
Author: sakya
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/vpcoderli/wxq
|
|
8
|
+
Project-URL: Repository, https://github.com/vpcoderli/wxq
|
|
9
|
+
Project-URL: Issues, https://github.com/vpcoderli/wxq/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/vpcoderli/wxq/releases
|
|
11
|
+
Keywords: wechat,weixin,微信,chat-history,chat-export,chatlog,mcp,mcp-server,claude,ai-agents,cli,sqlcipher,sqlite,decryption
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Communications :: Chat
|
|
21
|
+
Classifier: Typing :: Typed
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Requires-Dist: click<9,>=8.1
|
|
26
|
+
Requires-Dist: pycryptodome<4,>=3.19
|
|
27
|
+
Requires-Dist: zstandard<1,>=0.22
|
|
28
|
+
Provides-Extra: mcp
|
|
29
|
+
Requires-Dist: mcp<2,>=1.0; extra == "mcp"
|
|
30
|
+
Provides-Extra: dev
|
|
31
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
32
|
+
Requires-Dist: pytest-cov>=5.0; extra == "dev"
|
|
33
|
+
Requires-Dist: mypy>=1.10; extra == "dev"
|
|
34
|
+
Requires-Dist: pyyaml>=6.0; extra == "dev"
|
|
35
|
+
Dynamic: license-file
|
|
36
|
+
|
|
37
|
+
# wxq — 微信本地聊天记录查询工具
|
|
38
|
+
|
|
39
|
+
[](https://github.com/vpcoderli/wxq/actions/workflows/ci.yml)
|
|
40
|
+

|
|
41
|
+
[](https://github.com/vpcoderli/wxq/blob/main/LICENSE)
|
|
42
|
+
|
|
43
|
+
> WeChat local chat history query — CLI + MCP server for AI agents
|
|
44
|
+
> 微信聊天记录 · 本地数据库解密 · 命令行查询 · MCP 服务
|
|
45
|
+
|
|
46
|
+
`wxq` reads the encrypted WeChat SQLite databases on your machine, decrypts them locally, and
|
|
47
|
+
exposes messages, contacts, sessions, and statistics through a clean CLI and a Model Context
|
|
48
|
+
Protocol (MCP) server. Nothing leaves your machine.
|
|
49
|
+
|
|
50
|
+
Python-native by design: `pip install`-able, `import`-able, and typed — so it can be embedded
|
|
51
|
+
directly into Python agent frameworks rather than shelled out to as a binary.
|
|
52
|
+
|
|
53
|
+
## Features
|
|
54
|
+
|
|
55
|
+
- **SQLCipher 4 decryption** — AES-256-CBC with HMAC-SHA512 verification, WAL support
|
|
56
|
+
- **Automatic key extraction** — scan WeChat process memory on macOS, Windows, and Linux
|
|
57
|
+
- **CLI with 11 subcommands** — sessions, history, search, contacts, stats, export, and more
|
|
58
|
+
- **MCP server mode** — expose WeChat data as 8 read-only tools for AI agents (Claude, etc.)
|
|
59
|
+
- **Incremental message tracking** — `new-messages` shows only what's arrived since last check
|
|
60
|
+
- **Time range filtering** — query by date/datetime across all commands
|
|
61
|
+
- **Message type filtering** — filter by text, image, video, voice, file, link, sticker, system
|
|
62
|
+
- **Group chat support** — member lists, per-sender stats, hourly activity breakdown
|
|
63
|
+
- **zstd decompression** — handles WCDB compressed content transparently
|
|
64
|
+
- **Mtime-based DB cache** — decrypted databases are cached and refreshed only when the source changes
|
|
65
|
+
- **Typed** — ships `py.typed`; `mypy --strict` passes clean
|
|
66
|
+
|
|
67
|
+
## Requirements
|
|
68
|
+
|
|
69
|
+
- Python 3.10+
|
|
70
|
+
- WeChat desktop app (macOS, Windows, or Linux)
|
|
71
|
+
- WeChat must have been logged in at least once (so the local databases exist)
|
|
72
|
+
|
|
73
|
+
## Installation
|
|
74
|
+
|
|
75
|
+
From source (works today):
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
git clone https://github.com/vpcoderli/wxq.git
|
|
79
|
+
cd wxq
|
|
80
|
+
pip install -e ".[mcp]"
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Once published to PyPI:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
pip install wxq # core
|
|
87
|
+
pip install "wxq[mcp]" # with MCP server support
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
For development, see [Testing](#testing) below.
|
|
91
|
+
|
|
92
|
+
## Quick Start
|
|
93
|
+
|
|
94
|
+
### 1. Extract encryption keys
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
wxq init
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
This scans the running WeChat process memory to extract database encryption keys and writes them
|
|
101
|
+
to `~/.wxq/`. On macOS and Linux this may require `sudo`.
|
|
102
|
+
|
|
103
|
+
### 2. Query your data
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
# Recent chat sessions
|
|
107
|
+
wxq sessions
|
|
108
|
+
|
|
109
|
+
# Unread messages
|
|
110
|
+
wxq unread
|
|
111
|
+
|
|
112
|
+
# Chat history with a contact
|
|
113
|
+
wxq history "Alice" --limit 50
|
|
114
|
+
|
|
115
|
+
# Search messages globally
|
|
116
|
+
wxq search "meeting notes"
|
|
117
|
+
|
|
118
|
+
# Search within a specific chat
|
|
119
|
+
wxq search "project" --chat "Work Group"
|
|
120
|
+
|
|
121
|
+
# Time-filtered history
|
|
122
|
+
wxq history "Alice" --start-time "2024-01-01" --end-time "2024-06-30"
|
|
123
|
+
|
|
124
|
+
# Contact list
|
|
125
|
+
wxq contacts --query "Li"
|
|
126
|
+
|
|
127
|
+
# Contact details
|
|
128
|
+
wxq contacts --detail "Alice"
|
|
129
|
+
|
|
130
|
+
# Group members
|
|
131
|
+
wxq members "Work Group"
|
|
132
|
+
|
|
133
|
+
# Chat statistics
|
|
134
|
+
wxq stats "Work Group"
|
|
135
|
+
|
|
136
|
+
# Export chat to file
|
|
137
|
+
wxq export "Alice" -o alice_chat.txt
|
|
138
|
+
|
|
139
|
+
# Incremental new messages (since last check)
|
|
140
|
+
wxq new-messages
|
|
141
|
+
|
|
142
|
+
# Favorites
|
|
143
|
+
wxq favorites
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### 3. Output format
|
|
147
|
+
|
|
148
|
+
All commands return JSON by default; pass `--format text` for human-readable output:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
wxq sessions --format json
|
|
152
|
+
wxq history "Alice" --format text --limit 100
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Exit codes: `1` = target not found / no data, `2` = invalid arguments, `3` = decryption failure.
|
|
156
|
+
|
|
157
|
+
## MCP Server
|
|
158
|
+
|
|
159
|
+
The MCP server exposes WeChat data as read-only tools, allowing AI agents to query your messages
|
|
160
|
+
and contacts.
|
|
161
|
+
|
|
162
|
+
### Setup with Claude Desktop
|
|
163
|
+
|
|
164
|
+
Add to your Claude Desktop `claude_desktop_config.json`:
|
|
165
|
+
|
|
166
|
+
```json
|
|
167
|
+
{
|
|
168
|
+
"mcpServers": {
|
|
169
|
+
"wxq": {
|
|
170
|
+
"command": "wxq-mcp"
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Available MCP Tools
|
|
177
|
+
|
|
178
|
+
| Tool | Description |
|
|
179
|
+
|------|-------------|
|
|
180
|
+
| `get_sessions` | List recent chat sessions with last message preview |
|
|
181
|
+
| `get_unread` | List sessions with unread messages |
|
|
182
|
+
| `get_contacts` | Search or list contacts |
|
|
183
|
+
| `get_contact_detail` | Detailed info for a specific contact |
|
|
184
|
+
| `get_chat_history` | Retrieve message history with time/type filtering |
|
|
185
|
+
| `search_messages` | Search messages by keyword, optionally within a chat |
|
|
186
|
+
| `get_chat_stats` | Message count, type breakdown, top senders, hourly activity |
|
|
187
|
+
| `get_group_members` | List members of a group chat |
|
|
188
|
+
|
|
189
|
+
## Architecture
|
|
190
|
+
|
|
191
|
+
```
|
|
192
|
+
src/wxq/
|
|
193
|
+
cli.py # Click CLI entry point
|
|
194
|
+
exceptions.py # Exception hierarchy
|
|
195
|
+
core/
|
|
196
|
+
config.py # Configuration loading
|
|
197
|
+
context.py # AppContext — shared application state
|
|
198
|
+
crypto.py # SQLCipher 4 decryption (AES-256-CBC + HMAC-SHA512)
|
|
199
|
+
db_cache.py # Mtime-based decrypted DB cache
|
|
200
|
+
contacts.py # ContactStore — name resolution and contact queries
|
|
201
|
+
key_utils.py # Key file parsing and path safety
|
|
202
|
+
keys/
|
|
203
|
+
common.py # Cross-platform key scanning interface
|
|
204
|
+
scanner_macos.py # macOS: task_for_pid / mach_vm_read
|
|
205
|
+
scanner_windows.py # Windows: kernel32.ReadProcessMemory
|
|
206
|
+
scanner_linux.py # Linux: /proc/pid/mem
|
|
207
|
+
models/
|
|
208
|
+
contact.py # Contact, ContactDetail, GroupInfo dataclasses
|
|
209
|
+
message.py # Message, ChatContext, ChatStats, type enums
|
|
210
|
+
config.py # Configuration model
|
|
211
|
+
session.py # Session model
|
|
212
|
+
keys.py # Key metadata model
|
|
213
|
+
services/
|
|
214
|
+
message_service.py # Message querying, pagination, stats aggregation
|
|
215
|
+
message_parser.py # zstd decompression, type splitting, content parsing
|
|
216
|
+
commands/ # CLI subcommand implementations
|
|
217
|
+
mcp/
|
|
218
|
+
server.py # MCP server with 8 tools
|
|
219
|
+
output/
|
|
220
|
+
formatter.py # JSON / text output formatting
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
The CLI and the MCP server are two thin front ends over the same service layer
|
|
224
|
+
(`services/message_service.py`), so both surfaces always expose identical behavior.
|
|
225
|
+
|
|
226
|
+
## How Decryption Works
|
|
227
|
+
|
|
228
|
+
WeChat stores its data in SQLCipher 4 encrypted SQLite databases. The decryption process:
|
|
229
|
+
|
|
230
|
+
1. **Key extraction** — The encryption key is stored in WeChat's process memory. `wxq init` scans
|
|
231
|
+
the process to find and verify the 32-byte key using HMAC-SHA512 page authentication.
|
|
232
|
+
|
|
233
|
+
2. **Page-level decryption** — Each 4096-byte page is decrypted independently with AES-256-CBC.
|
|
234
|
+
The first 16 bytes of the 80-byte reserve area are the IV; the remaining 64 bytes are the
|
|
235
|
+
HMAC-SHA512 signature.
|
|
236
|
+
|
|
237
|
+
3. **WAL handling** — Write-Ahead Log frames are decrypted and patched back into the main database
|
|
238
|
+
for a consistent view.
|
|
239
|
+
|
|
240
|
+
4. **Caching** — Decrypted databases are cached in a temp directory, keyed by MD5 of the relative
|
|
241
|
+
path. The cache is invalidated when the source file's mtime changes.
|
|
242
|
+
|
|
243
|
+
## Configuration
|
|
244
|
+
|
|
245
|
+
State lives in `~/.wxq/` — `config.json`, `all_keys.json`, and `last_check.json`. It is created
|
|
246
|
+
automatically by `wxq init`. Set `WXQ_CONFIG` (or pass `--config`) to override the config path.
|
|
247
|
+
|
|
248
|
+
> **Upgrading from `wechat-query`?** If `~/.wechat-cli/config.json` exists and `~/.wxq/` does not,
|
|
249
|
+
> `wxq` keeps reading the old location, so existing installs work without re-running `init`.
|
|
250
|
+
> Nothing is moved or deleted. The `WECHAT_QUERY_CONFIG` environment variable is still honored as
|
|
251
|
+
> a fallback. To migrate for real, just `mv ~/.wechat-cli ~/.wxq`.
|
|
252
|
+
|
|
253
|
+
## Testing
|
|
254
|
+
|
|
255
|
+
This project uses a `src/` layout, so an editable install is required before the tests can import
|
|
256
|
+
the package:
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
pip install -e ".[dev,mcp]" # required first — a bare pytest will fail to import wxq
|
|
260
|
+
pytest # run the suite
|
|
261
|
+
pytest tests/test_crypto.py # a single file
|
|
262
|
+
pytest tests/test_crypto.py::TestFullDecrypt::test_single_page_roundtrip # a single test
|
|
263
|
+
pytest --cov=wxq # with coverage
|
|
264
|
+
mypy src/wxq --strict # static type check (passes clean)
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
248 tests covering decryption (including corrupt/truncated/wrong-key cases), the SQLCipher
|
|
268
|
+
key-length guard, contacts, XML app-message and media parsing, the XXE safety guard,
|
|
269
|
+
SQL-injection-safe table handling, path-traversal rejection, the DB cache's mtime invalidation,
|
|
270
|
+
config loading, every CLI command end-to-end, and the MCP server handlers. The type checker runs
|
|
271
|
+
in `--strict` mode with no errors.
|
|
272
|
+
|
|
273
|
+
Uncovered code is concentrated in the platform-specific process-memory scanners (`keys/`), which
|
|
274
|
+
require a live WeChat process and OS-level memory access and so cannot run in CI.
|
|
275
|
+
|
|
276
|
+
CI runs the suite on Python 3.10–3.13 (Linux) plus one job each on macOS and Windows, then
|
|
277
|
+
`mypy --strict`, then a wheel build that asserts `py.typed` and the `bin/` scanner are packaged.
|
|
278
|
+
|
|
279
|
+
## License
|
|
280
|
+
|
|
281
|
+
MIT
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
<sub>Keywords: 微信 聊天记录 导出 查询 解密 · WeChat chat history export, WeChat database decrypt,
|
|
286
|
+
SQLCipher, MCP server, chatlog, wxq</sub>
|
wxq-1.0.0/README.md
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
# wxq — 微信本地聊天记录查询工具
|
|
2
|
+
|
|
3
|
+
[](https://github.com/vpcoderli/wxq/actions/workflows/ci.yml)
|
|
4
|
+

|
|
5
|
+
[](https://github.com/vpcoderli/wxq/blob/main/LICENSE)
|
|
6
|
+
|
|
7
|
+
> WeChat local chat history query — CLI + MCP server for AI agents
|
|
8
|
+
> 微信聊天记录 · 本地数据库解密 · 命令行查询 · MCP 服务
|
|
9
|
+
|
|
10
|
+
`wxq` reads the encrypted WeChat SQLite databases on your machine, decrypts them locally, and
|
|
11
|
+
exposes messages, contacts, sessions, and statistics through a clean CLI and a Model Context
|
|
12
|
+
Protocol (MCP) server. Nothing leaves your machine.
|
|
13
|
+
|
|
14
|
+
Python-native by design: `pip install`-able, `import`-able, and typed — so it can be embedded
|
|
15
|
+
directly into Python agent frameworks rather than shelled out to as a binary.
|
|
16
|
+
|
|
17
|
+
## Features
|
|
18
|
+
|
|
19
|
+
- **SQLCipher 4 decryption** — AES-256-CBC with HMAC-SHA512 verification, WAL support
|
|
20
|
+
- **Automatic key extraction** — scan WeChat process memory on macOS, Windows, and Linux
|
|
21
|
+
- **CLI with 11 subcommands** — sessions, history, search, contacts, stats, export, and more
|
|
22
|
+
- **MCP server mode** — expose WeChat data as 8 read-only tools for AI agents (Claude, etc.)
|
|
23
|
+
- **Incremental message tracking** — `new-messages` shows only what's arrived since last check
|
|
24
|
+
- **Time range filtering** — query by date/datetime across all commands
|
|
25
|
+
- **Message type filtering** — filter by text, image, video, voice, file, link, sticker, system
|
|
26
|
+
- **Group chat support** — member lists, per-sender stats, hourly activity breakdown
|
|
27
|
+
- **zstd decompression** — handles WCDB compressed content transparently
|
|
28
|
+
- **Mtime-based DB cache** — decrypted databases are cached and refreshed only when the source changes
|
|
29
|
+
- **Typed** — ships `py.typed`; `mypy --strict` passes clean
|
|
30
|
+
|
|
31
|
+
## Requirements
|
|
32
|
+
|
|
33
|
+
- Python 3.10+
|
|
34
|
+
- WeChat desktop app (macOS, Windows, or Linux)
|
|
35
|
+
- WeChat must have been logged in at least once (so the local databases exist)
|
|
36
|
+
|
|
37
|
+
## Installation
|
|
38
|
+
|
|
39
|
+
From source (works today):
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
git clone https://github.com/vpcoderli/wxq.git
|
|
43
|
+
cd wxq
|
|
44
|
+
pip install -e ".[mcp]"
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Once published to PyPI:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pip install wxq # core
|
|
51
|
+
pip install "wxq[mcp]" # with MCP server support
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
For development, see [Testing](#testing) below.
|
|
55
|
+
|
|
56
|
+
## Quick Start
|
|
57
|
+
|
|
58
|
+
### 1. Extract encryption keys
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
wxq init
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
This scans the running WeChat process memory to extract database encryption keys and writes them
|
|
65
|
+
to `~/.wxq/`. On macOS and Linux this may require `sudo`.
|
|
66
|
+
|
|
67
|
+
### 2. Query your data
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# Recent chat sessions
|
|
71
|
+
wxq sessions
|
|
72
|
+
|
|
73
|
+
# Unread messages
|
|
74
|
+
wxq unread
|
|
75
|
+
|
|
76
|
+
# Chat history with a contact
|
|
77
|
+
wxq history "Alice" --limit 50
|
|
78
|
+
|
|
79
|
+
# Search messages globally
|
|
80
|
+
wxq search "meeting notes"
|
|
81
|
+
|
|
82
|
+
# Search within a specific chat
|
|
83
|
+
wxq search "project" --chat "Work Group"
|
|
84
|
+
|
|
85
|
+
# Time-filtered history
|
|
86
|
+
wxq history "Alice" --start-time "2024-01-01" --end-time "2024-06-30"
|
|
87
|
+
|
|
88
|
+
# Contact list
|
|
89
|
+
wxq contacts --query "Li"
|
|
90
|
+
|
|
91
|
+
# Contact details
|
|
92
|
+
wxq contacts --detail "Alice"
|
|
93
|
+
|
|
94
|
+
# Group members
|
|
95
|
+
wxq members "Work Group"
|
|
96
|
+
|
|
97
|
+
# Chat statistics
|
|
98
|
+
wxq stats "Work Group"
|
|
99
|
+
|
|
100
|
+
# Export chat to file
|
|
101
|
+
wxq export "Alice" -o alice_chat.txt
|
|
102
|
+
|
|
103
|
+
# Incremental new messages (since last check)
|
|
104
|
+
wxq new-messages
|
|
105
|
+
|
|
106
|
+
# Favorites
|
|
107
|
+
wxq favorites
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### 3. Output format
|
|
111
|
+
|
|
112
|
+
All commands return JSON by default; pass `--format text` for human-readable output:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
wxq sessions --format json
|
|
116
|
+
wxq history "Alice" --format text --limit 100
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Exit codes: `1` = target not found / no data, `2` = invalid arguments, `3` = decryption failure.
|
|
120
|
+
|
|
121
|
+
## MCP Server
|
|
122
|
+
|
|
123
|
+
The MCP server exposes WeChat data as read-only tools, allowing AI agents to query your messages
|
|
124
|
+
and contacts.
|
|
125
|
+
|
|
126
|
+
### Setup with Claude Desktop
|
|
127
|
+
|
|
128
|
+
Add to your Claude Desktop `claude_desktop_config.json`:
|
|
129
|
+
|
|
130
|
+
```json
|
|
131
|
+
{
|
|
132
|
+
"mcpServers": {
|
|
133
|
+
"wxq": {
|
|
134
|
+
"command": "wxq-mcp"
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Available MCP Tools
|
|
141
|
+
|
|
142
|
+
| Tool | Description |
|
|
143
|
+
|------|-------------|
|
|
144
|
+
| `get_sessions` | List recent chat sessions with last message preview |
|
|
145
|
+
| `get_unread` | List sessions with unread messages |
|
|
146
|
+
| `get_contacts` | Search or list contacts |
|
|
147
|
+
| `get_contact_detail` | Detailed info for a specific contact |
|
|
148
|
+
| `get_chat_history` | Retrieve message history with time/type filtering |
|
|
149
|
+
| `search_messages` | Search messages by keyword, optionally within a chat |
|
|
150
|
+
| `get_chat_stats` | Message count, type breakdown, top senders, hourly activity |
|
|
151
|
+
| `get_group_members` | List members of a group chat |
|
|
152
|
+
|
|
153
|
+
## Architecture
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
src/wxq/
|
|
157
|
+
cli.py # Click CLI entry point
|
|
158
|
+
exceptions.py # Exception hierarchy
|
|
159
|
+
core/
|
|
160
|
+
config.py # Configuration loading
|
|
161
|
+
context.py # AppContext — shared application state
|
|
162
|
+
crypto.py # SQLCipher 4 decryption (AES-256-CBC + HMAC-SHA512)
|
|
163
|
+
db_cache.py # Mtime-based decrypted DB cache
|
|
164
|
+
contacts.py # ContactStore — name resolution and contact queries
|
|
165
|
+
key_utils.py # Key file parsing and path safety
|
|
166
|
+
keys/
|
|
167
|
+
common.py # Cross-platform key scanning interface
|
|
168
|
+
scanner_macos.py # macOS: task_for_pid / mach_vm_read
|
|
169
|
+
scanner_windows.py # Windows: kernel32.ReadProcessMemory
|
|
170
|
+
scanner_linux.py # Linux: /proc/pid/mem
|
|
171
|
+
models/
|
|
172
|
+
contact.py # Contact, ContactDetail, GroupInfo dataclasses
|
|
173
|
+
message.py # Message, ChatContext, ChatStats, type enums
|
|
174
|
+
config.py # Configuration model
|
|
175
|
+
session.py # Session model
|
|
176
|
+
keys.py # Key metadata model
|
|
177
|
+
services/
|
|
178
|
+
message_service.py # Message querying, pagination, stats aggregation
|
|
179
|
+
message_parser.py # zstd decompression, type splitting, content parsing
|
|
180
|
+
commands/ # CLI subcommand implementations
|
|
181
|
+
mcp/
|
|
182
|
+
server.py # MCP server with 8 tools
|
|
183
|
+
output/
|
|
184
|
+
formatter.py # JSON / text output formatting
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
The CLI and the MCP server are two thin front ends over the same service layer
|
|
188
|
+
(`services/message_service.py`), so both surfaces always expose identical behavior.
|
|
189
|
+
|
|
190
|
+
## How Decryption Works
|
|
191
|
+
|
|
192
|
+
WeChat stores its data in SQLCipher 4 encrypted SQLite databases. The decryption process:
|
|
193
|
+
|
|
194
|
+
1. **Key extraction** — The encryption key is stored in WeChat's process memory. `wxq init` scans
|
|
195
|
+
the process to find and verify the 32-byte key using HMAC-SHA512 page authentication.
|
|
196
|
+
|
|
197
|
+
2. **Page-level decryption** — Each 4096-byte page is decrypted independently with AES-256-CBC.
|
|
198
|
+
The first 16 bytes of the 80-byte reserve area are the IV; the remaining 64 bytes are the
|
|
199
|
+
HMAC-SHA512 signature.
|
|
200
|
+
|
|
201
|
+
3. **WAL handling** — Write-Ahead Log frames are decrypted and patched back into the main database
|
|
202
|
+
for a consistent view.
|
|
203
|
+
|
|
204
|
+
4. **Caching** — Decrypted databases are cached in a temp directory, keyed by MD5 of the relative
|
|
205
|
+
path. The cache is invalidated when the source file's mtime changes.
|
|
206
|
+
|
|
207
|
+
## Configuration
|
|
208
|
+
|
|
209
|
+
State lives in `~/.wxq/` — `config.json`, `all_keys.json`, and `last_check.json`. It is created
|
|
210
|
+
automatically by `wxq init`. Set `WXQ_CONFIG` (or pass `--config`) to override the config path.
|
|
211
|
+
|
|
212
|
+
> **Upgrading from `wechat-query`?** If `~/.wechat-cli/config.json` exists and `~/.wxq/` does not,
|
|
213
|
+
> `wxq` keeps reading the old location, so existing installs work without re-running `init`.
|
|
214
|
+
> Nothing is moved or deleted. The `WECHAT_QUERY_CONFIG` environment variable is still honored as
|
|
215
|
+
> a fallback. To migrate for real, just `mv ~/.wechat-cli ~/.wxq`.
|
|
216
|
+
|
|
217
|
+
## Testing
|
|
218
|
+
|
|
219
|
+
This project uses a `src/` layout, so an editable install is required before the tests can import
|
|
220
|
+
the package:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
pip install -e ".[dev,mcp]" # required first — a bare pytest will fail to import wxq
|
|
224
|
+
pytest # run the suite
|
|
225
|
+
pytest tests/test_crypto.py # a single file
|
|
226
|
+
pytest tests/test_crypto.py::TestFullDecrypt::test_single_page_roundtrip # a single test
|
|
227
|
+
pytest --cov=wxq # with coverage
|
|
228
|
+
mypy src/wxq --strict # static type check (passes clean)
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
248 tests covering decryption (including corrupt/truncated/wrong-key cases), the SQLCipher
|
|
232
|
+
key-length guard, contacts, XML app-message and media parsing, the XXE safety guard,
|
|
233
|
+
SQL-injection-safe table handling, path-traversal rejection, the DB cache's mtime invalidation,
|
|
234
|
+
config loading, every CLI command end-to-end, and the MCP server handlers. The type checker runs
|
|
235
|
+
in `--strict` mode with no errors.
|
|
236
|
+
|
|
237
|
+
Uncovered code is concentrated in the platform-specific process-memory scanners (`keys/`), which
|
|
238
|
+
require a live WeChat process and OS-level memory access and so cannot run in CI.
|
|
239
|
+
|
|
240
|
+
CI runs the suite on Python 3.10–3.13 (Linux) plus one job each on macOS and Windows, then
|
|
241
|
+
`mypy --strict`, then a wheel build that asserts `py.typed` and the `bin/` scanner are packaged.
|
|
242
|
+
|
|
243
|
+
## License
|
|
244
|
+
|
|
245
|
+
MIT
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
<sub>Keywords: 微信 聊天记录 导出 查询 解密 · WeChat chat history export, WeChat database decrypt,
|
|
250
|
+
SQLCipher, MCP server, chatlog, wxq</sub>
|
wxq-1.0.0/pyproject.toml
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "wxq"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "微信本地聊天记录查询工具 — WeChat local chat history query, CLI + MCP server for AI agents"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
authors = [{ name = "sakya" }]
|
|
12
|
+
requires-python = ">=3.10"
|
|
13
|
+
keywords = [
|
|
14
|
+
"wechat", "weixin", "微信", "chat-history", "chat-export", "chatlog",
|
|
15
|
+
"mcp", "mcp-server", "claude", "ai-agents",
|
|
16
|
+
"cli", "sqlcipher", "sqlite", "decryption",
|
|
17
|
+
]
|
|
18
|
+
classifiers = [
|
|
19
|
+
"Development Status :: 4 - Beta",
|
|
20
|
+
"Environment :: Console",
|
|
21
|
+
"Intended Audience :: Developers",
|
|
22
|
+
"Programming Language :: Python :: 3",
|
|
23
|
+
"Programming Language :: Python :: 3.10",
|
|
24
|
+
"Programming Language :: Python :: 3.11",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
"Programming Language :: Python :: 3.13",
|
|
27
|
+
"Topic :: Communications :: Chat",
|
|
28
|
+
"Typing :: Typed",
|
|
29
|
+
]
|
|
30
|
+
dependencies = [
|
|
31
|
+
"click>=8.1,<9",
|
|
32
|
+
"pycryptodome>=3.19,<4",
|
|
33
|
+
"zstandard>=0.22,<1",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
[project.optional-dependencies]
|
|
37
|
+
mcp = ["mcp>=1.0,<2"]
|
|
38
|
+
dev = [
|
|
39
|
+
"pytest>=8.0",
|
|
40
|
+
"pytest-cov>=5.0",
|
|
41
|
+
"mypy>=1.10",
|
|
42
|
+
"pyyaml>=6.0",
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
[project.urls]
|
|
46
|
+
Homepage = "https://github.com/vpcoderli/wxq"
|
|
47
|
+
Repository = "https://github.com/vpcoderli/wxq"
|
|
48
|
+
Issues = "https://github.com/vpcoderli/wxq/issues"
|
|
49
|
+
Changelog = "https://github.com/vpcoderli/wxq/releases"
|
|
50
|
+
|
|
51
|
+
[project.scripts]
|
|
52
|
+
wxq = "wxq.cli:main"
|
|
53
|
+
wxq-mcp = "wxq.mcp.server:main"
|
|
54
|
+
|
|
55
|
+
[tool.setuptools.packages.find]
|
|
56
|
+
where = ["src"]
|
|
57
|
+
|
|
58
|
+
[tool.setuptools.package-data]
|
|
59
|
+
wxq = ["py.typed", "bin/*"]
|
|
60
|
+
|
|
61
|
+
[tool.mypy]
|
|
62
|
+
python_version = "3.10"
|
|
63
|
+
strict = true
|
|
64
|
+
warn_return_any = true
|
|
65
|
+
warn_unused_configs = true
|
|
66
|
+
|
|
67
|
+
[tool.pytest.ini_options]
|
|
68
|
+
testpaths = ["tests"]
|
|
69
|
+
addopts = "-v --tb=short"
|
wxq-1.0.0/setup.cfg
ADDED
|
Binary file
|