Simplify documentation and add repository development skill
This commit is contained in:
1 parent
3d8cf46a63
commit
5aaa31dc1a
10 files changed
+473
-239
No files matched your search
@@ -1,3 +1,9 @@
|
||||
# Project instructions
|
||||
|
||||
Use `whatsapp_suite/` as canonical source; regenerate `whatsapp.py` after source changes. Run source and portable offline tests. Keep default tests free of live side effects. Do not commit exports, profiles, real message/contact fixtures, credentials or research captures. Preserve explicit self-message recipient guards and native object checks and advisory compatibility reporting. Read `CONTRIBUTING.md` and `docs/VALIDATION.md` before changing native integration.
|
||||
Use `whatsapp_suite/` as canonical source. `whatsapp.py` is generated; rebuild it after changing Python, assets or tests. Documentation-only changes do not require rebuilding.
|
||||
|
||||
Start with [CONTRIBUTING.md](CONTRIBUTING.md) for the change workflow. Repository-specific agent guidance is in [skills/whatsapp-suite-development/SKILL.md](skills/whatsapp-suite-development/SKILL.md). Read [architecture](docs/ARCHITECTURE.md) and [validation](docs/VALIDATION.md) before changing native integration or making compatibility claims.
|
||||
|
||||
Run source and portable offline tests for implementation changes; inspect skips. Keep default tests free of live side effects. Preserve native object/ABI checks, advisory compatibility reporting, explicit self-message recipient guards, uncertain-send receipt handling and HTTP acknowledgement semantics.
|
||||
|
||||
Do not commit exports, real message/contact fixtures, profiles, credentials or research captures. Do not install tasks or send messages solely to verify documentation. User authorization determines live actions and publication scope.
|
||||
@@ -1,5 +1,12 @@
|
||||
# Changelog
|
||||
|
||||
## Documentation and development guide — 2026-10-11
|
||||
|
||||
- Rewrite the user entry point and CLI guide around practical tasks.
|
||||
- Explain bridge, delivery and restoration lifetimes with diagrams and a source map.
|
||||
- Add extension/build guidance, troubleshooting and a repository development skill.
|
||||
- Document the webhook event schema and complete task removal.
|
||||
|
||||
## Autonomous webhook and dynamic address discovery — 2026-10-11
|
||||
|
||||
- Resolve WebView function/vtable addresses by binary fingerprints instead of fixed module RVAs.
|
||||
|
||||
+103
-5
@@ -1,9 +1,107 @@
|
||||
# Development
|
||||
# Develop and extend the suite
|
||||
|
||||
The canonical implementation is `whatsapp_suite/`. Edit it rather than the encoded payload in `whatsapp.py`. Synthetic fixtures belong in `tests/`; never use captured messages or contacts as fixtures.
|
||||
The editable implementation is `whatsapp_suite/`. The single-file `whatsapp.py` is a generated distribution. Changes to the encoded payload will be overwritten by the builder.
|
||||
|
||||
Use Python 3.11+ and Node.js for the complete offline suite. Optional requirements are in `requirements-whatsapp-optional.txt`. Run source tests, rebuild with `python build_whatsapp_bundle.py`, and run the portable tests before committing. Check that unchanged inputs produce the same bundle hash.
|
||||
## Local workflow
|
||||
|
||||
Native sources are in `native/`; existing verified runtime DLLs are in `whatsapp_suite/assets/`. Changing native code requires rebuilding for Windows x64, updating asset hashes and conducting explicit build-specific live validation. Run `native\build.cmd` and `native\build_webhook.cmd` from an x64 MSVC Native Tools prompt to build the helpers (Windows SDK required). The recipes reproduce compilation; native PE bytes are not promised to be bit-identical across toolchain versions or timestamps. Update the Python helper hashes and `docs/runtime-assets.json` after a native rebuild. The Python builder packages existing DLLs and does not compile them.
|
||||
Clone the repository and run these commands from its root:
|
||||
|
||||
Document compatibility changes and distinguish synthetic checks from live checks. Keep send operations explicit, fixed-recipient guards intact, and default tests free of live side effects. Inspect `git diff --cached` and the tracked file list before publication.
|
||||
```powershell
|
||||
git clone https://tea.karlcom.de/karl/whatsapp_injector.git
|
||||
cd whatsapp_injector
|
||||
python -m whatsapp_suite --help
|
||||
python -m whatsapp_suite test
|
||||
```
|
||||
|
||||
Python 3.11+ is required. Install Node.js to run all JavaScript fixtures; check the test report for skipped checks. Core commands use Python's standard library. Install [optional packages](docs/CLI.md#optional-research-commands) only when working on those research tools.
|
||||
|
||||
After changing Python, JavaScript, runtime assets or tests:
|
||||
|
||||
```powershell
|
||||
python -m whatsapp_suite test
|
||||
python build_whatsapp_bundle.py
|
||||
python whatsapp.py test
|
||||
git diff --check
|
||||
```
|
||||
|
||||
The builder writes size and hash metadata to ignored `analysis/whatsapp-suite/bundle-build.json`. An unchanged input set must produce the same bundle hash. Commit maintained source and the regenerated bundle together. Documentation-only changes do not require rebuilding.
|
||||
|
||||
To verify portability, copy only `whatsapp.py` into an otherwise empty writable folder and run `python -I whatsapp.py test` there.
|
||||
|
||||
## Find the extension point
|
||||
|
||||
| Change | Start here |
|
||||
| --- | --- |
|
||||
| Register a command | `whatsapp_suite/cli.py` → `COMMANDS` |
|
||||
| Saved-export parsing/search | `whatsapp_suite/exports.py` |
|
||||
| Message ZIP export | `whatsapp_suite/zip_export.py`; shared database expression in `history.py` |
|
||||
| Contact export | `whatsapp_suite/contacts_export.py` |
|
||||
| Fixed self-message test | `whatsapp_suite/self_message.py` |
|
||||
| Listener configuration/restoration/receiver | `whatsapp_suite/webhook.py` |
|
||||
| Message event observation and decoding | `whatsapp_suite/assets/webhook_listener.js` |
|
||||
| Windows bridge orchestration and cleanup | `whatsapp_suite/live.py` |
|
||||
| App detection and advisory compatibility | `whatsapp_suite/desktop.py` |
|
||||
| Native address discovery | `native/core_discovery.h` |
|
||||
| Resident HTTP relay | `native/webhook_probe.cpp` |
|
||||
| Packaging | `build_whatsapp_bundle.py` and asset hashes |
|
||||
|
||||
For detailed transport behavior, read [architecture](docs/ARCHITECTURE.md). For demonstrated behavior, read [validation](docs/VALIDATION.md).
|
||||
|
||||
## Add a Python command
|
||||
|
||||
1. Add a module under `whatsapp_suite/` with `main(argv=None)`. Parse its own options with `argparse` and return an integer exit code.
|
||||
2. Register the command name, module and help description in `cli.COMMANDS`. Existing commands show the dispatch pattern.
|
||||
3. Reuse the existing bridge/export helpers when the operation needs Desktop JavaScript. Define a bounded operation with an explicit result contract; do not expose an arbitrary-script execution CLI as a shortcut.
|
||||
4. Add meaningful synthetic fixtures for new parsing, paging, response or lifecycle behavior. Keep live actions out of default tests.
|
||||
5. Update the CLI documentation, rebuild and verify the portable command's `--help`.
|
||||
|
||||
Top-level Python modules are embedded automatically. New runtime assets need an explicit entry in the builder's asset list; new fixture types may also need packaging support. JavaScript `.cjs` fixtures already have a packaging rule.
|
||||
|
||||
## Change listener JavaScript
|
||||
|
||||
The producer is `assets/webhook_listener.js`. Python substitutes the `__CONFIG__` placeholder with listener settings; transport credentials are kept out of the injected JavaScript. The producer observes collection events, decodes stored rows and queues bounded records.
|
||||
|
||||
Use `tests/webhook_listener.cjs` for synthetic collection/database fixtures. Preserve event IDs, sequence-based acknowledgements, text/queue bounds and stop behavior. If changing payload fields, update the [webhook schema](docs/WEBHOOKS.md) and receiver validation together.
|
||||
|
||||
The native relay polls the queue and removes entries only after HTTP 2xx. A target should deduplicate message IDs. Keep retry behavior distinguishable from exactly-once delivery.
|
||||
|
||||
## Change native code
|
||||
|
||||
Ordinary Python/JavaScript changes do not require compiling C++. Native changes need an x64 MSVC Native Tools prompt and the Windows SDK:
|
||||
|
||||
```bat
|
||||
native\build.cmd
|
||||
native\build_webhook.cmd
|
||||
```
|
||||
|
||||
The recipes write compiler output into ignored `native/build/`. Copy the rebuilt runtime DLLs into `whatsapp_suite/assets/`, then update:
|
||||
|
||||
| DLL | Expected hash |
|
||||
| --- | --- |
|
||||
| `math_probe.dll` | `live.EMBEDDED_SHA256` |
|
||||
| `search_probe.dll` | `native_search.EMBEDDED_PROBE_SHA256` |
|
||||
| `webhook_probe.dll` | `webhook.HELPER_SHA256` |
|
||||
|
||||
Also update `docs/runtime-assets.json`. The Python builder packages existing DLLs; it does not compile them. PE files are not promised to be byte-identical across compiler versions or build timestamps.
|
||||
|
||||
Native live validation must use the intended Desktop build and verify the operation and cleanup. A resident webhook DLL remains loaded after stop to protect pending callbacks; restart WhatsApp before testing a replacement helper. Preserve completed packet states when duplicate wake messages arrive.
|
||||
|
||||
Address fingerprints, object fields and ABI checks are deliberate compatibility boundaries. Do not replace an unsupported-layout failure with guessed addresses.
|
||||
|
||||
## Tests and live checks
|
||||
|
||||
Tests live in `tests/test_whatsapp_suite.py` and synthetic `.cjs` fixtures. The runner packages the Python tests as `_regression.py` for the portable file.
|
||||
|
||||
```powershell
|
||||
python whatsapp.py test
|
||||
python whatsapp.py test --live
|
||||
python whatsapp.py test --capabilities
|
||||
```
|
||||
|
||||
The latter two explicitly use running WhatsApp. Sending, exporting real data and installing a listener are separate actions; they are never implied by an offline test. Use the user's authorized scope for live validation. An uncertain self-send is inspected through its reserved receipt before any retry.
|
||||
|
||||
## Before submitting
|
||||
|
||||
Describe the concrete behavior change, relevant tests and remaining limits. Review `git diff --cached` and ensure no exports, real message/contact fixtures, profiles, session material, credentials or research captures are staged. Preserve the tested-versus-unverified distinction. No license change or external deployment is implied by a source change.
|
||||
|
||||
Coding agents should start with [AGENTS.md](AGENTS.md) and the [development skill](skills/whatsapp-suite-development/SKILL.md).
|
||||
@@ -1,82 +1,97 @@
|
||||
# WhatsApp Desktop Suite
|
||||
|
||||
A Windows toolkit for reading, searching and exporting local WhatsApp Desktop data, with a portable single-file Python distribution and an editable source package.
|
||||
Read, search and export local WhatsApp Desktop messages and contacts. Install a message listener that delivers events to an HTTPS webhook.
|
||||
|
||||
The core live commands execute JavaScript inside the signed-in Desktop WebView through a bundled native bridge. They require neither CDP nor UI automation. Separate optional research commands use CDP, Frida or process-memory inspection.
|
||||
The main commands run JavaScript inside the signed-in Windows Desktop app through a bundled native bridge. They use neither CDP nor UI automation. This is an independent, reverse-engineered toolkit; it is not an official WhatsApp API.
|
||||
|
||||
## Features
|
||||
## Start here
|
||||
|
||||
| Feature | Command | Scope |
|
||||
| --- | --- | --- |
|
||||
| Contact export | `contacts-export` | Local contact rows, including distinct PN/LID records |
|
||||
| Message ZIP export | `export-zip` | Local message rows, decoded text/captions and manifest; no media downloads |
|
||||
| Old message reading | `live --suite history-read` | Five oldest local records, including records outside loaded chats |
|
||||
| Desktop search | `desktop-search` | Bounded app search through the native bridge |
|
||||
| Saved export search | `search` | Unicode-aware literal search, filtering and optional redaction |
|
||||
| Message webhooks | `webhook` | In-process listener, direct HTTPS or loopback delivery, optional automatic restoration |
|
||||
| Self-message test | `send-self` | One fixed message to the signed-in account, with stored-text verification |
|
||||
| Inspection and diagnostics | `inventory`, `stats`, `live` | Storage inventory, export summaries and fixed probes |
|
||||
| Optional research tools | See [CLI reference](docs/CLI.md) | CDP history export, RAM tools, SQLite probes and pairing tools |
|
||||
|
||||
## Quick start
|
||||
|
||||
Copy `whatsapp.py` into a writable folder. Run with Python 3.11 or newer:
|
||||
**For users:** copy [whatsapp.py](whatsapp.py) into a writable folder. You need Python 3.11 or newer; live Desktop commands require Windows x64, 64-bit Python, and WhatsApp running and signed in. You do not need a C++ compiler or separate DLL files.
|
||||
|
||||
```powershell
|
||||
python whatsapp.py --help
|
||||
python whatsapp.py test
|
||||
python whatsapp.py contacts-export --output contacts.json
|
||||
python whatsapp.py export-zip --output messages.zip
|
||||
python whatsapp.py live --suite history-read
|
||||
```
|
||||
|
||||
Live bridge commands require **Windows x64 and 64-bit Python**. They were tested with WhatsApp Desktop **2.2639.100.0** and the recorded WebView component. Other versions are attempted with a compatibility warning rather than blocked. The helper discovers function/vtable locations from binary fingerprints rather than fixed module RVAs. It retains compiler/object-layout and ABI assumptions, so other versions remain unverified and incompatible patterns fail discovery. The core commands need only Python's standard library. Optional tools have [additional dependencies](docs/CLI.md#optional-dependencies); Node.js enables the JavaScript fixture tests.
|
||||
The default tests use synthetic data and do not send messages or install listeners. Node.js enables the JavaScript fixture checks; without it, inspect the reported skips.
|
||||
|
||||
`send-self` actually sends a message. It is never part of the default tests and does not retry automatically. ZIP exports cover the local database, not necessarily every message ever received. Contacts are local table rows, not a deduplicated phone address book.
|
||||
Choose the command for your task:
|
||||
|
||||
## Message listener with automatic restoration
|
||||
| I want to… | Command |
|
||||
| --- | --- |
|
||||
| Export contacts | `python whatsapp.py contacts-export --output exports/contacts.json` |
|
||||
| Export local messages as a ZIP | `python whatsapp.py export-zip --output exports/messages.zip` |
|
||||
| Read the five oldest local records | `python whatsapp.py live --suite history-read` |
|
||||
| Search the running app | `python whatsapp.py desktop-search "keyword" --limit 10` |
|
||||
| Search an extracted message export | `python whatsapp.py search messages.jsonl "keyword"` |
|
||||
| Test sending to my own account | `python whatsapp.py send-self` |
|
||||
| Deliver message events to a webhook | See the example below |
|
||||
|
||||
Supply your endpoint token through `WHATSAPP_INJECTOR_WEBHOOK_TOKEN` using your secret manager, then run:
|
||||
Exports and reports contain private data. Existing export files are refused: choose a new output name. A message ZIP contains decoded text records and a manifest, not downloaded media or guaranteed complete account history. Contact rows may contain separate PN/LID identities.
|
||||
|
||||
## Receive message events
|
||||
|
||||
Provide your endpoint token through the environment variable `WHATSAPP_INJECTOR_WEBHOOK_TOKEN`, preferably using your secret manager. Your endpoint must validate the `X-Webhook-Token` header.
|
||||
|
||||
```powershell
|
||||
python whatsapp.py webhook install --endpoint https://your-endpoint.example/events --auto-restore --config listener.json
|
||||
python whatsapp.py webhook install --endpoint https://your-endpoint.example/events --self-only --auto-restore --config listener.json
|
||||
python whatsapp.py webhook status
|
||||
```
|
||||
|
||||
`--endpoint` selects the HTTPS target; `--auto-restore` creates a per-user Windows task that checks every minute and restores the listener after WhatsApp restarts. Delivery runs inside WhatsApp, without CDP, UI automation, a local HTTP server or a continuously running Python process. Add `--self-only` for self-chat testing. The endpoint must authenticate the token header and accept message batches. See [setup, payload, limitations and full removal](docs/WEBHOOKS.md).
|
||||
- `--endpoint` selects the HTTPS target.
|
||||
- `--self-only` limits delivery to your self-chat for testing. Omit it to subscribe to qualifying events from other chats.
|
||||
- `--auto-restore` registers a per-user Windows task that restores the listener after WhatsApp restarts.
|
||||
- `--config` saves the listener settings and, for automatic restoration, a Windows-protected token.
|
||||
|
||||
## Development
|
||||
The installer exits. Delivery runs inside WhatsApp; no local HTTP server or continuous Python process is needed. The task performs a brief check every minute while your Windows user is logged in. Process memory does not survive restart: the task reinstalls the listener, with a polling gap.
|
||||
|
||||
`send-self` sends a real test message and verifies its stored plaintext. It never retries an uncertain send automatically. No AI summarizer or automatic replies are included.
|
||||
|
||||
See [webhook setup, payload and removal](docs/WEBHOOKS.md) before integration.
|
||||
|
||||
## How it works
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
P["Python CLI"] --> B["Bundled native bridge"]
|
||||
B --> W["WhatsApp WebView JavaScript"]
|
||||
W --> D["App database getters and decoder"]
|
||||
D --> E["JSON / ZIP exports"]
|
||||
W --> L["Message event queue"]
|
||||
L --> H["Native HTTPS relay"]
|
||||
H --> T["Your webhook endpoint"]
|
||||
```
|
||||
|
||||
Python orchestrates documented Windows APIs through `ctypes`. A temporary Windows hook loads a native helper into WhatsApp; the helper locates the existing WebView and calls its script-execution interface. The portable file bundles the C++ DLLs; Python does not replace them with a pure-Python implementation. Read [the architecture](docs/ARCHITECTURE.md) for lifetimes and compatibility boundaries.
|
||||
|
||||
## Compatibility and verification
|
||||
|
||||
Tested with WhatsApp Desktop **2.2639.100.0** on Windows x64. Other versions are attempted with a warning. Native addresses are discovered from binary fingerprints, but compiler layout and interface assumptions remain; support for other builds is unverified.
|
||||
|
||||
The verified bundle passed **41 offline tests**. Live checks covered contact export, old-message reading, search, message ZIP export, self-send, direct HTTPS delivery and task restoration after a WhatsApp restart. See [validation evidence and untested cases](docs/VALIDATION.md).
|
||||
|
||||
Optional CDP, Frida, RAM and QR research commands have separate dependencies and behavior. They are listed separately in the [CLI reference](docs/CLI.md).
|
||||
|
||||
## Develop and extend
|
||||
|
||||
```powershell
|
||||
python -m whatsapp_suite --help
|
||||
python -m whatsapp_suite test
|
||||
python build_whatsapp_bundle.py
|
||||
python whatsapp.py test
|
||||
```
|
||||
|
||||
The builder embeds the maintained modules, DLLs and fixtures. Modules load from memory; a verified DLL is extracted only when needed. The distribution is approximately 207 KiB. Keep source and bundle changes together.
|
||||
Edit `whatsapp_suite/`; `whatsapp.py` is generated. The portable file is about 207 KiB and embeds the maintained modules, runtime assets and tests.
|
||||
|
||||
## Project layout
|
||||
| Resource | Use it for |
|
||||
| --- | --- |
|
||||
| [CLI reference](docs/CLI.md) | Commands, options and output behavior |
|
||||
| [Webhook guide](docs/WEBHOOKS.md) | Setup, event schema, restart behavior and removal |
|
||||
| [Architecture](docs/ARCHITECTURE.md) | Understand the bridge and choose the right extension point |
|
||||
| [Contributing](CONTRIBUTING.md) | Add a command, change JavaScript, rebuild native helpers |
|
||||
| [Agent skill](skills/whatsapp-suite-development/SKILL.md) | Repository-specific guidance for coding agents |
|
||||
| [Troubleshooting](docs/TROUBLESHOOTING.md) | Resolve common setup and runtime problems |
|
||||
| [Validation](docs/VALIDATION.md) | Distinguish tested behavior from assumptions |
|
||||
| [Security](SECURITY.md) | Handle private data and credentials |
|
||||
| [Publishing](docs/PUBLISHING.md) | Review and upload the clean repository |
|
||||
|
||||
```text
|
||||
whatsapp.py Portable generated distribution
|
||||
whatsapp_suite/ Canonical Python implementations
|
||||
whatsapp_suite/assets/ Runtime DLLs and SQLite agent
|
||||
native/ Native helper C++ source
|
||||
tests/ Synthetic Python and JavaScript fixtures
|
||||
build_whatsapp_bundle.py Deterministic bundle builder
|
||||
docs/ Architecture, validation and publishing guide
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
- [CLI and export behavior](docs/CLI.md)
|
||||
- [Message webhooks and restart behavior](docs/WEBHOOKS.md)
|
||||
- [Architecture and native bridge](docs/ARCHITECTURE.md)
|
||||
- [Validation and limitations](docs/VALIDATION.md)
|
||||
- [Development and contributions](CONTRIBUTING.md)
|
||||
- [Publishing to tea.karlcom.de](docs/PUBLISHING.md)
|
||||
- [Handling private data](SECURITY.md)
|
||||
|
||||
## Project status
|
||||
|
||||
Repository: [karl/whatsapp_injector](https://tea.karlcom.de/karl/whatsapp_injector). It is independent of WhatsApp/Meta. No open-source license has been selected; see [licensing status](LICENSE.md).
|
||||
Repository: [karl/whatsapp_injector](https://tea.karlcom.de/karl/whatsapp_injector). No open-source license has been selected; see [licensing status](LICENSE.md).
|
||||
+84
-17
@@ -1,35 +1,102 @@
|
||||
# Architecture
|
||||
|
||||
## Execution path
|
||||
## Two ways to run the same code
|
||||
|
||||
The portable launcher verifies and decompresses its embedded payload, then imports the Python package directly from the in-memory ZIP. It uses the same CLI and modules as `python -m whatsapp_suite`.
|
||||
`python -m whatsapp_suite` runs the editable source package. `python whatsapp.py` runs its generated portable distribution through the same CLI.
|
||||
|
||||
For a core live operation, Python uses Windows APIs through `ctypes`. It verifies the helper DLL, records application/WebView compatibility, installs a temporary `WH_GETMESSAGE` hook on the Desktop UI thread, and passes a bounded JavaScript request through shared memory. The native helper discovers function/vtable locations from relocation-free binary fingerprints and locates the existing WebView object using those dynamically resolved addresses and calls its `ExecuteScriptAsync` interface. A thread message wakes the hook. Results return through the shared mapping; the hook, mapping and process handles are then released. Reports record cleanup outcomes.
|
||||
The builder stores the maintained modules, fixtures and selected assets in a compressed archive. The launcher verifies its payload, imports Python modules from memory, and extracts only the native helper needed for a live operation into a hash-verified cache beside the bundle. A C++ compiler is needed to change native code, not to run the portable file.
|
||||
|
||||
This still uses native C++ DLLs. Python packages their bytes; it does not replace their implementation with pure Python. The C++ source is for maintenance and is unnecessary on a machine running the portable file. SHA-256 checks verify embedded asset integrity, not publisher identity or authenticity of a downloaded file.
|
||||
## Live JavaScript execution
|
||||
|
||||
Message export uses the app's own JavaScript database getter and row decoder. It paginates a bounded range, streams decoded records into a ZIP and writes a manifest. The scan is not an atomic database snapshot. Failed decodes remain visible and cause failure status. Final publication refuses existing output and verifies ZIP CRCs.
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant CLI as Python CLI
|
||||
participant DLL as Native helper
|
||||
participant WV as Existing WhatsApp WebView
|
||||
CLI->>CLI: Detect host and UI thread; verify helper
|
||||
CLI->>DLL: Temporary Windows hook + shared request
|
||||
DLL->>DLL: Discover and validate native layout
|
||||
DLL->>WV: ExecuteScriptAsync
|
||||
WV-->>DLL: JavaScript result
|
||||
DLL-->>CLI: Shared result packet
|
||||
CLI->>CLI: Release hook, mappings and handles
|
||||
```
|
||||
|
||||
Contact export reads selected public fields from the local contact table. Sending is restricted to a fixed self-message test with recipient checks and persisted plaintext readback. No general-purpose arbitrary-recipient send CLI is provided.
|
||||
Python calls Windows APIs through `ctypes`. A `WH_GETMESSAGE` hook loads the helper on WhatsApp's UI thread. A thread message wakes it; a shared mapping carries a bounded request and result.
|
||||
|
||||
## Boundaries
|
||||
The helper scans the loaded WebView component for relocation-free code fingerprints and a matching vtable layout, then locates the existing object and validates its script-execution method. This avoids fixed module-relative function addresses. Compiler/object-field and interface ABI assumptions remain.
|
||||
|
||||
Live native operations were tested with Desktop build `2.2639.100.0`. Other versions are attempted with a warning. The helper resolves function and vtable addresses dynamically, but retains function fingerprints, an object field offset and the exact interface ABI derived from the tested WebView DLL. A changed layout may fail discovery or cause process instability; dynamic address discovery does not make all compiler/object layouts compatible. Updates require new evidence and validation to be considered tested. Core bridge commands do not use CDP or UI automation; optional legacy commands have their own transports and dependencies. RAM readers only see loaded models. Exported message text does not include media file downloads. Password or passkey private-key extraction is not an implemented feature.
|
||||
The hook is temporary. Normal exports and probes record cleanup of the hook, mapping, process handles and helper. Native failures are not evidence that a different layout is safe.
|
||||
|
||||
The repository includes only maintained source, synthetic fixtures and required runtime assets. Local profiles, extracted application code, credentials, messages, contacts and research dumps are excluded.
|
||||
## Read, search and send
|
||||
|
||||
## Security mechanism classification
|
||||
| Operation | Data path | Boundary |
|
||||
| --- | --- | --- |
|
||||
| ZIP export | App database getter → app row decoder → paginated records → ZIP | Local rows; no atomic snapshot, phone sync or media download |
|
||||
| Old-message read | Timestamp scan → five oldest rows → app decoder | Bounded scan; not limited to loaded chat models |
|
||||
| Contact export | Local contact table → selected identity/name/business fields | May contain separate PN/LID records |
|
||||
| Desktop search | Existing app message search → bounded metadata | Search scope comes from the app |
|
||||
| Saved-export search | Python JSON/JSONL parsing and normalization | Does not need the app |
|
||||
| Self-message | Resolve own identity → guarded send → stored readback | One fixed test message; no arbitrary-recipient CLI |
|
||||
|
||||
The observed implementation uses documented Windows hook loading and WebView script execution APIs. It does not demonstrate a memory-corruption exploit, privilege escalation or a cryptographic break. It obtains the running application's existing decrypted data through that application's internal getters under the current signed-in session.
|
||||
Database text is decoded through WhatsApp's own JavaScript methods under the signed-in session. Failed row decodes remain explicit. Export publication refuses existing outputs and checks ZIP CRCs.
|
||||
|
||||
However, loading a helper into another process and locating internal objects by memory layout is reverse-engineered process instrumentation. WhatsApp does not expose the internal module calls used here as a documented external automation API. Calling documented OS/WebView APIs does not establish that this overall integration is supported or intended by WhatsApp, nor is this observation a complete security audit.
|
||||
## Listener and delivery
|
||||
|
||||
References: [Microsoft SetWindowsHookExW](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowshookexw), [Microsoft WebView2 JavaScript execution](https://learn.microsoft.com/en-us/microsoft-edge/webview2/how-to/javascript).
|
||||
```mermaid
|
||||
flowchart LR
|
||||
M["Loaded message collection"] --> J["JS observer and decoded queue"]
|
||||
J --> N["UI-thread native timer"]
|
||||
N --> H["WinHTTP worker"]
|
||||
H --> T["HTTPS target or loopback receiver"]
|
||||
T --> A["HTTP 2xx"]
|
||||
A --> Q["Remove acknowledged queue entries"]
|
||||
R["Optional Windows minute task"] --> I["Restore after app restart"]
|
||||
I --> J
|
||||
```
|
||||
|
||||
## Autonomous webhook relay
|
||||
The JavaScript producer observes message collection events, obtains stored rows through the app decoder, and queues bounded message events. It does not contain transport credentials. A UI-thread timer executes short queue scripts; a worker performs HTTP delivery outside that UI thread.
|
||||
|
||||
The explicit `webhook install` command registers JavaScript message collection observers and installs a separate resident helper. A UI-thread timer runs short queue-peek scripts; a WinHTTP worker posts bounded batches to the configured HTTPS endpoint or `127.0.0.1:port/whatsapp-webhook`, without proxies or redirects. HTTPS uses certificate validation and a token header. Queue entries are removed after HTTP 2xx. The built-in loopback receiver acknowledges after SQLite commit and deduplicates message IDs.
|
||||
Direct HTTPS uses certificate validation and a token header. Loopback mode posts to a local receiver. Proxies and redirects are disabled. Native WinHTTP supplies the outbound transport; direct JavaScript localhost requests were blocked by WhatsApp's CSP during testing, and the implementation does not weaken CSP.
|
||||
|
||||
The installer exits and releases its temporary hooks. The webhook helper retains one module reference so native callbacks remain valid; stop cancels the timer and releases WebView references but leaves an idle DLL loaded until app exit. This is intentional and distinct from the short-lived test/export helpers' unload checks.
|
||||
HTTP 2xx triggers queue acknowledgement. Failures leave records for retry. A consumer must deduplicate IDs; this is not exactly-once delivery. The built-in local receiver commits SQLite data before acknowledgement.
|
||||
|
||||
App process exit destroys both the injected JavaScript and resident relay. For direct HTTPS, `--auto-restore` registers a per-user Windows task that runs a short `webhook ensure` check every minute. It uses a DPAPI-protected token and does not keep Python or a local server running between checks. Alternatively, a loopback receiver started with `--restore-config` checks every five seconds. Saved configuration persists; injected process memory does not. See [webhook guide](WEBHOOKS.md) for limits.
|
||||
The installer exits after setup. The native relay retains a module reference so timer/worker callbacks remain valid. Stop cancels observation/timers and releases WebView references; an idle DLL remains loaded until app exit.
|
||||
|
||||
## Restoration and configuration
|
||||
|
||||
WhatsApp process exit destroys the listener and native relay. Automatic restoration is a separate capability:
|
||||
|
||||
| Mode | Bootstrap | Lifetime |
|
||||
| --- | --- | --- |
|
||||
| Direct HTTPS with `--auto-restore` | Per-user Windows task invokes `webhook ensure` every minute | Short Python checks; no continuous local server |
|
||||
| Loopback receiver with `--restore-config` | Receiver checks every five seconds | Receiver must remain running |
|
||||
| Optional `watch` | Python restoration loop | Watcher remains running |
|
||||
|
||||
The task runs as the logged-in user with limited privileges. It stores paths to Python, the bundle and configuration; moving them breaks that registration. Direct restoration recovers a current-user DPAPI-protected token from the configuration. The bundle is portable, but that protected configuration is tied to the Windows user/machine.
|
||||
|
||||
Reinstallation reconciles qualifying loaded models since the saved start timestamp; it does not perform complete database catch-up. In-memory queues can be lost on exit, and messages in startup/polling gaps are not guaranteed to be delivered. See [the webhook guide](WEBHOOKS.md) for schema and limits.
|
||||
|
||||
## Source map
|
||||
|
||||
| Layer | Files |
|
||||
| --- | --- |
|
||||
| Command dispatch and tests | `cli.py`, `runner.py`, `tests/` |
|
||||
| Shared resources/cache | `common.py` |
|
||||
| Windows orchestration | `desktop.py`, `live.py`, `native_search.py` |
|
||||
| Data operations | `history.py`, `zip_export.py`, `contacts_export.py`, `exports.py`, `self_message.py` |
|
||||
| Listener orchestration | `webhook.py`, `assets/webhook_listener.js` |
|
||||
| Native implementations | `native/math_probe.cpp`, `search_probe.cpp`, `webhook_probe.cpp`, `core_discovery.h` |
|
||||
| Portable packaging | `build_whatsapp_bundle.py`, generated `whatsapp.py` |
|
||||
|
||||
All Python filenames above are under `whatsapp_suite/`. See [contributing](../CONTRIBUTING.md) for extension steps and hash updates.
|
||||
|
||||
## Compatibility and security boundaries
|
||||
|
||||
The tested Desktop build is `2.2639.100.0`. Other builds produce advisory metadata/warnings and are attempted, but dynamic address discovery does not imply compatibility with every future compiler/object layout. Changed layouts can fail or cause process instability.
|
||||
|
||||
The observed bridge uses documented Windows loading and WebView execution APIs. It does not demonstrate memory corruption, privilege escalation or broken encryption. The overall integration remains reverse-engineered process instrumentation: WhatsApp does not document these internal module calls as an external automation API. This is not a complete security audit.
|
||||
|
||||
Passwords/passkey private keys and media download are not implemented features. Core commands use no CDP or UI automation; optional research tools have separate transports. Hashes establish integrity, not publisher identity.
|
||||
|
||||
See [validation](VALIDATION.md) for evidence, [security](../SECURITY.md) for private-data handling, and [Microsoft's Windows hook](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowshookexw) and [WebView JavaScript](https://learn.microsoft.com/en-us/microsoft-edge/webview2/how-to/javascript) documentation for the public APIs.
|
||||
+67
-152
@@ -1,181 +1,96 @@
|
||||
# WhatsApp test suite
|
||||
# CLI reference
|
||||
|
||||
## Portable single-file bundle
|
||||
|
||||
Copy **`whatsapp.py`** to another writable folder. That one Python file includes
|
||||
all tools, the native helpers and the regression fixtures. No adjacent source
|
||||
package, DLLs, C++ compiler or build script is needed to run it.
|
||||
Use the portable file from a writable folder:
|
||||
|
||||
```powershell
|
||||
python whatsapp.py --help
|
||||
python whatsapp.py test
|
||||
python whatsapp.py <command> --help
|
||||
```
|
||||
|
||||
For development, replace `python whatsapp.py` with `python -m whatsapp_suite`. With no arguments, either entry point runs offline tests.
|
||||
|
||||
## Core commands
|
||||
|
||||
Live commands require signed-in Windows WhatsApp Desktop, x64 Windows and 64-bit Python 3.11+. The core path uses the Python standard library and bundled native helpers, without CDP or UI automation.
|
||||
|
||||
| Command | Result | Useful options |
|
||||
| --- | --- | --- |
|
||||
| `test` | Synthetic regression results | `--output`, explicit `--live` / `--capabilities` |
|
||||
| `contacts-export` | Selected fields from all local contact rows | `--output`, `--pid` |
|
||||
| `export-zip` | Local message records and manifest in ZIP | `--output`, `--batch-size`, `--redact-text`, `--pid` |
|
||||
| `live` | Fixed app probes and detailed report | `--suite`, `--output`, `--pid` |
|
||||
| `desktop-search QUERY` | App search results with message metadata | `--limit`, `--output`, `--pid` |
|
||||
| `send-self` | One actual self-message and verification receipt | `--output`, `--pid` |
|
||||
| `webhook` | Listener installation, status, delivery and restoration | See below |
|
||||
|
||||
```powershell
|
||||
python whatsapp.py contacts-export --output exports/contacts.json
|
||||
python whatsapp.py export-zip --output exports/messages.zip
|
||||
python whatsapp.py live --suite history-read
|
||||
python whatsapp.py contacts-export --output contacts.json
|
||||
python whatsapp.py export-zip --output messages.zip
|
||||
python whatsapp.py send-self
|
||||
python whatsapp.py desktop-search "keyword" --limit 10
|
||||
```
|
||||
|
||||
The bundle compresses the original modules and resources together with LZMA.
|
||||
It verifies its embedded payload and imports Python modules directly from memory.
|
||||
Only a native helper needed for a live command is materialized in a hash-verified
|
||||
cache beside the bundle. Keep the containing folder writable. Native helper
|
||||
bytes, native object checks, batch sizes and message read/send paths are unchanged.
|
||||
`live --suite` accepts `math`, `capabilities`, `all`, `message-json`, `contacts` and `history-read`. The latter reads the five oldest records after a bounded timestamp scan. It saves decoded body/caption text when present.
|
||||
|
||||
Core WebView commands use the standard library. Python 3.11+, Windows x64,
|
||||
64-bit Python are required for live Desktop operations. Other Desktop versions
|
||||
are attempted with a compatibility warning; only the recorded version was tested. Optional legacy CDP, Frida and QR tools retain the packages
|
||||
listed below. Node.js remains optional for JavaScript fixture tests.
|
||||
## Work with saved exports
|
||||
|
||||
The development package below remains the editable source. Rebuild the generated
|
||||
single-file distribution after changing it:
|
||||
These commands read existing JSON/JSONL files, without running WhatsApp:
|
||||
|
||||
```powershell
|
||||
python build_whatsapp_bundle.py
|
||||
python whatsapp.py stats messages.jsonl
|
||||
python whatsapp.py search messages.jsonl "keyword" --limit 20 --redact-text
|
||||
```
|
||||
|
||||
The build is deterministic and records size and SHA-256 in
|
||||
`analysis/whatsapp-suite/bundle-build.json`. The build file is not needed on a
|
||||
machine running the bundle.
|
||||
Extract `messages.jsonl` from a message ZIP before searching it; the search command does not read ZIP files directly. Search supports `--chat-id` and `--output`. `inventory` lists local storage files and sizes.
|
||||
|
||||
The WhatsApp scripts are consolidated in `whatsapp_suite/`, with one CLI and
|
||||
offline regression tests in `tests/`. Run commands from this workspace.
|
||||
## Webhook commands
|
||||
|
||||
```powershell
|
||||
python -m whatsapp_suite
|
||||
python -m whatsapp_suite --help
|
||||
python -m whatsapp_suite test --output analysis/whatsapp-suite/results.json
|
||||
python whatsapp.py webhook install --endpoint https://your-endpoint.example/events --self-only --auto-restore --config listener.json
|
||||
python whatsapp.py webhook status
|
||||
python whatsapp.py webhook stop --config listener.json
|
||||
```
|
||||
|
||||
`python whatsapp_tests.py` is an equivalent entry point. The default run uses
|
||||
fixtures and temporary files. It verifies saved-export parsing, Unicode search,
|
||||
chat filtering, text redaction, history pagination/decryption contracts, fixed
|
||||
probe responses, command dispatch, and bundled DLL hashes. Node.js runs the
|
||||
JavaScript history fixtures; that test is reported as skipped if Node is absent.
|
||||
Python 3.11 or newer is required.
|
||||
Set the endpoint token in the environment variable named by `--token-env` (default `WHATSAPP_INJECTOR_WEBHOOK_TOKEN`). Never place the token in the URL.
|
||||
|
||||
To test an already running WhatsApp Desktop installation:
|
||||
|
||||
```powershell
|
||||
python -m whatsapp_suite test --live
|
||||
python -m whatsapp_suite test --capabilities
|
||||
python -m whatsapp_suite live --suite math
|
||||
python -m whatsapp_suite live --suite capabilities
|
||||
python -m whatsapp_suite live --suite history-read --output analysis/whatsapp-suite/js-history-read.json
|
||||
python -m whatsapp_suite export-zip --output exports/whatsapp-messages.zip
|
||||
python -m whatsapp_suite contacts-export --output exports/contacts.json
|
||||
python -m whatsapp_suite send-self
|
||||
```
|
||||
|
||||
Live WebView probes require Windows x64 and 64-bit Python. Desktop build
|
||||
`2.2639.100.0` and its recorded WebView2 Core DLL were tested. Other versions or
|
||||
DLL hashes produce a warning and are attempted. The helper discovers function and vtable locations from binary fingerprints and checks native
|
||||
objects and methods before executing JavaScript; changed layouts can
|
||||
cause failure or process instability. The JSON report includes detected/tested
|
||||
compatibility metadata and cleanup status. `--pid` selects a Desktop host.
|
||||
|
||||
## Tools
|
||||
|
||||
Every command supports `--help` for its options.
|
||||
|
||||
| Command | Purpose |
|
||||
| Action | Behavior |
|
||||
| --- | --- |
|
||||
| `inventory` | List local Desktop storage files and sizes |
|
||||
| `stats EXPORT` | Summarize a saved JSON or JSONL export |
|
||||
| `search EXPORT QUERY` | Unicode-aware literal search of saved messages |
|
||||
| `desktop-search QUERY` | Bounded native app search through WebView2; metadata output |
|
||||
| `live --suite math\|capabilities\|all` | Fixed live WebView test suites |
|
||||
| `live --suite message-json\|contacts` | Explicit fixed message search/contact sample; saves private data |
|
||||
| `live --suite history-read` | Read the five oldest local message records through the JS database getter and decoder, without CDP |
|
||||
| `webview-test` | Arithmetic check in a separate WebView2 host; may download its SDK |
|
||||
| `analyze` | Storage analysis, optionally using an existing loopback CDP endpoint |
|
||||
| `history-export` | Export local history through Desktop's own database decryption |
|
||||
| `export-zip` | Export all local message rows to ZIP through JavaScript on WebView, without CDP or UI automation |
|
||||
| `webhook` | Install/status/stop, direct HTTPS or loopback relay, ensure/auto-restore and optional watch/serve; see [webhook guide](WEBHOOKS.md) |
|
||||
| `contacts-export` | Export all local contact rows to JSON through the app's JS database getter |
|
||||
| `send-self` | Send one fixed test message to the signed-in account itself and verify stored plaintext |
|
||||
| `ram-read` | Read loaded V8 message objects from process memory |
|
||||
| `ram-search QUERY` | Search RAM models with verified collection membership |
|
||||
| `native-search [QUERY]` | Experimental injected SQLite search, `--oldest --limit 5`, or `--export-index` |
|
||||
| `qr-memory` | Recover candidate Desktop pairing QR payloads from RAM |
|
||||
| `qr-window` | Save an already displayed Desktop linking QR |
|
||||
| `pairing` | Start an isolated browser and request an official linking QR |
|
||||
| `install` | Subscribe to message events and start the resident native relay; installer exits |
|
||||
| `install --restore --config FILE` | Reuse and re-enable an existing configuration |
|
||||
| `status` | Report listener and relay counters |
|
||||
| `stop --config FILE` | Stop the listener and disable restoration in that configuration |
|
||||
| `auto-restore --config FILE` | Register/enable the per-user minute task for a direct HTTPS listener |
|
||||
| `ensure --config FILE` | Check once and restore a missing configured listener |
|
||||
| `watch --config FILE` | Optional continuous restoration loop |
|
||||
| `serve --restore-config FILE --store FILE` | Run the optional loopback receiver with SQLite storage and restoration |
|
||||
|
||||
```powershell
|
||||
python -m whatsapp_suite search export.jsonl "keyword" --redact-text
|
||||
python -m whatsapp_suite desktop-search "keyword" --limit 10
|
||||
python -m whatsapp_suite history-export --help
|
||||
```
|
||||
Direct installation also accepts `--endpoint`, `--token-env`, `--self-only`, `--auto-restore`, `--config` and `--pid`. Loopback installation uses `--port` instead of `--endpoint`. Full setup, payload and task removal are in [the webhook guide](WEBHOOKS.md).
|
||||
|
||||
`history-read` uses the native WebView bridge to execute JavaScript in the running
|
||||
app. It scans at most 100,000 local record timestamps in a read-only transaction,
|
||||
then calls `WAWebSchemaMessage.getMessageTable().get` and
|
||||
`WAWebDBMessageSerialization.messageFromDbRow` for the five oldest records.
|
||||
It saves decoded body/caption text when present, including messages absent from
|
||||
the loaded conversation models. System events and media-only records can have
|
||||
no text. The live result includes page-state and native bridge cleanup status.
|
||||
This command requires neither CDP nor optional Python packages.
|
||||
## Output and failure behavior
|
||||
|
||||
`export-zip` uses the same native bridge and the app's JavaScript database getter
|
||||
and decoder. It paginates all local rows up to the initial upper primary key,
|
||||
streams them into `messages.jsonl`, and includes a `manifest.json` with row counts,
|
||||
decoding errors, scope, and bridge cleanup status. Rows include message IDs,
|
||||
chat IDs, timestamps, types, body and caption text; media files are not downloaded.
|
||||
This is a live scan, not an atomic database snapshot. Row decoding failures are
|
||||
preserved as error records and make the command return a failure status.
|
||||
`--batch-size` controls bounded reads (default 100); `--redact-text` omits body and
|
||||
caption text. Existing outputs are refused. Interrupted exports retain a
|
||||
`.zip.partial` file and a `.zip.report.json` diagnostic report. A completed ZIP
|
||||
is checked for CRC errors before publication.
|
||||
- Commands emit compact JSON summaries; exports and detailed reports are local files.
|
||||
- Success normally returns exit code 0; reported failures return a nonzero code. `webhook ensure` may exit 0 while waiting for WhatsApp: inspect its status file, not only the exit code.
|
||||
- ZIP exports contain `messages.jsonl` and `manifest.json`. They cover local rows up to the initial upper key, with no phone sync or media download.
|
||||
- The scan is not an atomic snapshot. Decode failures remain visible as error records and make the export fail.
|
||||
- Existing export outputs are refused. Interrupted ZIP exports retain `.zip.partial` and an adjacent `.zip.report.json`.
|
||||
- `send-self` reserves its receipt before sending. It verifies the recipient, stored plaintext and acknowledgement; an uncertain attempt is not retried automatically.
|
||||
- Live reports include compatibility and cleanup information. A version warning does not certify support for that build.
|
||||
|
||||
`contacts-export` reads the local contact table rather than the five-contact
|
||||
loaded-model sample. It exports selected identity, name, phone and business
|
||||
fields. Local records can include separate PN/LID entries and contacts outside
|
||||
the phone address book; this is not a deduplicated phone address-book export.
|
||||
Keep private outputs out of Git. See [troubleshooting](TROUBLESHOOTING.md) and [security](../SECURITY.md).
|
||||
|
||||
`send-self` resolves the signed-in account and checks both the selected chat and
|
||||
outgoing message recipient before invoking the app's text-send action. It sends
|
||||
one identifiable test message and reads it back through the message database
|
||||
decoder, recording ACK and exact plaintext equality in a receipt. An existing
|
||||
receipt is refused and sending is never retried automatically. Unlike the
|
||||
offline test suite, this command actually sends a WhatsApp message.
|
||||
## Optional research commands
|
||||
|
||||
The separate bulk `history-export` command requires an existing Desktop CDP endpoint. RAM tools only see
|
||||
loaded objects and cannot retrieve all history. Pairing commands are separate
|
||||
from the automated test run. The `runtime` module preserves the explicit
|
||||
temporary CDP context manager for research scripts; entering that context
|
||||
restarts Desktop and is never part of the default tests.
|
||||
These commands have distinct transports and are separate from the core no-CDP workflow. Always inspect their help before use.
|
||||
|
||||
## Optional dependencies
|
||||
|
||||
The default suite, saved-export tools, and native WebView probes need only the
|
||||
Python standard library (plus Node.js for the history fixture test).
|
||||
|
||||
| Tools | Additional Python packages |
|
||||
| Command | Purpose / dependency |
|
||||
| --- | --- |
|
||||
| CDP analysis and history export | `websockets` |
|
||||
| Injected SQLite search | `frida` |
|
||||
| QR from RAM | `qrcode[pil]` |
|
||||
| QR from Desktop window | `Pillow`, `zxing-cpp` |
|
||||
| Isolated browser pairing | `websockets`, `qrcode[pil]`; installed Chrome |
|
||||
| `webview-test` | Separate WebView2 host test; may download its SDK |
|
||||
| `analyze` | Storage inspection, optionally an existing CDP session; `websockets` for CDP |
|
||||
| `history-export` | Bulk history through an existing Desktop CDP endpoint; `websockets` |
|
||||
| `ram-read`, `ram-search` | Inspect loaded models in RAM; not complete history |
|
||||
| `native-search` | Experimental injected SQLite search/index export; `frida` |
|
||||
| `qr-memory` | Pairing QR candidates in RAM; `qrcode[pil]` |
|
||||
| `qr-window` | Capture an already displayed pairing QR; `Pillow`, `zxing-cpp` |
|
||||
| `pairing` | Isolated browser linking QR; Chrome, `websockets`, `qrcode[pil]` |
|
||||
|
||||
Install all optional packages into a virtual environment with:
|
||||
|
||||
```powershell
|
||||
python -m pip install -r requirements-whatsapp-optional.txt
|
||||
```
|
||||
|
||||
## Layout and migration
|
||||
|
||||
- `whatsapp_suite/`: canonical tool implementations, common normalization,
|
||||
storage paths, Desktop discovery, CLI, and test runner.
|
||||
- `whatsapp_suite/assets/`: verified native DLLs and the native SQLite agent.
|
||||
- `tests/`: synthetic Python regressions and the JavaScript history fixture.
|
||||
- `analysis/whatsapp-suite/results.json`: latest automated test result.
|
||||
|
||||
The former `whatsapp_tool.py` commands now use `python -m whatsapp_suite`;
|
||||
`whatsapp-search` is named `desktop-search`, and `whatsapp-test` is
|
||||
`live --suite math`. The former `whatsapp_math.py` options are available under
|
||||
`live`. Archived scripts have become package modules; the identical Desktop QR
|
||||
RAM scripts have one implementation (`qr_memory`). Research helpers now import
|
||||
these modules. Old script archive and portable script copies were removed.
|
||||
The clean Git project excludes research reports, extracted application code and browser profiles. The surrounding original workspace retains those local files.
|
||||
`requirements-whatsapp-optional.txt` lists optional Python packages. No optional research action, pairing operation or send is performed by default tests.
|
||||
+19
-10
@@ -1,17 +1,26 @@
|
||||
# Publish to tea.karlcom.de
|
||||
# Publishing
|
||||
|
||||
This directory is the clean repository root. The surrounding research workspace is not the repository and must not be uploaded.
|
||||
The canonical repository is [karl/whatsapp_injector](https://tea.karlcom.de/karl/whatsapp_injector). Publish from its clean Git root, not the surrounding research workspace.
|
||||
|
||||
1. The configured repository is `https://tea.karlcom.de/karl/whatsapp_injector.git`.
|
||||
2. Copy the SSH or HTTPS clone URL supplied by the server. Use your existing credential manager or SSH configuration; never embed tokens in the URL.
|
||||
3. From this directory, inspect the tracked file list and configure the remote:
|
||||
## Upload a reviewed change
|
||||
|
||||
Rebuild and test when source, assets or tests changed; use the [development workflow](../CONTRIBUTING.md). Documentation-only changes need accurate examples and valid links.
|
||||
|
||||
```powershell
|
||||
git ls-files
|
||||
git remote add origin https://tea.karlcom.de/karl/whatsapp_injector.git
|
||||
git push -u origin main
|
||||
git status --short
|
||||
git diff --cached
|
||||
git remote -v
|
||||
git push origin main
|
||||
```
|
||||
|
||||
The owner and remote URL were supplied by Karl. Repository visibility is controlled on the server. Never push the surrounding research workspace.
|
||||
Stage only maintained source, documentation, synthetic fixtures and required runtime assets. Review staged files before committing. Exports, profiles, credentials, protected listener configurations and research captures belong outside Git.
|
||||
|
||||
For a release, rebuild and test the bundle, then attach only `whatsapp.py` and a SHA-256 checksum to a server release. State the tested Desktop build and optional dependencies. Do not attach test exports or research reports. No server-specific CI workflow is included because runner availability and configuration have not been verified.
|
||||
An existing clone already has its remote configured. If moving a repository to a different server, configure the intended URL explicitly; never embed a token in it. Use an existing credential manager or SSH setup.
|
||||
|
||||
## Portable release
|
||||
|
||||
Build and test `whatsapp.py`, then attach that file and its SHA-256 checksum to a release. Include the tested Desktop build, Python/platform requirements, relevant live validation and untested cases.
|
||||
|
||||
The runtime file contains the native DLLs; users need no compiler. It must run from a writable folder. Do not attach private test outputs. Embedded hashes establish integrity, not a publisher signature.
|
||||
|
||||
Repository visibility is controlled on the server. No open-source license has been selected; see [licensing status](../LICENSE.md). No server-specific CI workflow is included because runner availability has not been verified.
|
||||
@@ -0,0 +1,22 @@
|
||||
# Troubleshooting
|
||||
|
||||
Start with `python whatsapp.py --help` or the specific command's `--help`. Commands report compact results; private detailed reports are written locally.
|
||||
|
||||
| Symptom | What to check |
|
||||
| --- | --- |
|
||||
| No running Desktop host found | Start the Windows WhatsApp app normally, sign in, and wait until it has loaded. Live commands require x64 Windows and 64-bit Python. |
|
||||
| Unsupported layout or compatibility warning | A warning means the build is untested; discovery still attempts it. A changed fingerprint/ABI can fail. Keep the detected version and a redacted report for investigation; do not force guessed offsets. |
|
||||
| Access denied or helper extraction fails | Keep the portable file in a writable folder. Check local security-software diagnostics before changing permissions. Running as administrator is not a routine requirement. |
|
||||
| Existing output/receipt/configuration | Choose a new export filename. Use `webhook install --restore --config listener.json` only when reusing that listener configuration. Inspect an uncertain send receipt before retrying. |
|
||||
| JavaScript tests skipped | Install Node.js and rerun the suite if complete fixture coverage is needed. A passing test run can still contain skips. |
|
||||
| Webhook token rejected | The direct token must contain 32–128 printable ASCII characters. Supply the named environment variable and ensure the target validates `X-Webhook-Token`. |
|
||||
| Direct webhook queue grows | Check HTTPS connectivity, certificates, token authentication and the target's HTTP status. Non-2xx responses leave records queued for retry. The relay disables proxies and redirects. |
|
||||
| Listener disappears after WhatsApp restart | Process exit destroys injected code. Enable `--auto-restore`, keep registered file paths stable, and allow up to about a minute after the app has loaded. |
|
||||
| Restore fails after moving configuration | DPAPI protection is tied to the Windows user/machine. Reconfigure with the endpoint token on the intended user/machine. |
|
||||
| Stop seems temporary | A restoring configuration can re-enable a listener. Use `webhook stop --config listener.json`; for full removal follow the task-removal steps in the [webhook guide](WEBHOOKS.md). |
|
||||
| ZIP contains fewer messages than expected | The export covers locally available rows, not guaranteed full account history or media downloads. Inspect `manifest.json` and the adjacent report. |
|
||||
| Export is interrupted | Keep the `.partial` and report for diagnosis. A new attempt requires a new filename; partial files are not resumed. |
|
||||
|
||||
For an automatically restored listener, the configuration records the exact task name. The adjacent `listener.status.json` reports the last scheduled check; Task Scheduler exposes its last result and next run. A successful scheduler exit alone does not prove message delivery.
|
||||
|
||||
When reporting a problem, include the command, Python/app versions and a redacted error/cleanup summary. Do not attach real exports or protected configuration. See [security](../SECURITY.md).
|
||||
@@ -1,5 +1,14 @@
|
||||
# Message webhooks
|
||||
|
||||
Use this guide to connect a message listener to your HTTP consumer. Start with direct HTTPS if you already have a webhook endpoint; the local receiver is optional. The listener observes messages surfaced in the Desktop app, rather than subscribing to WhatsApp's server history.
|
||||
|
||||
## Choose a delivery mode
|
||||
|
||||
| Mode | What runs locally | Use it for |
|
||||
| --- | --- | --- |
|
||||
| Direct HTTPS | Listener/relay in WhatsApp; optional brief scheduled Python checks | Your existing webhook service or Node-RED |
|
||||
| Loopback HTTP | Listener/relay plus a running Python receiver | Local testing and durable SQLite capture |
|
||||
|
||||
## Execution and restart behavior
|
||||
|
||||
`webhook install` is a one-shot command. JavaScript subscribes to message collection events inside WhatsApp and queues decoded records. A resident native helper posts them directly to an HTTPS endpoint or to a loopback HTTP receiver. Direct HTTPS needs no local server and no continuously running Python process. No CDP or UI automation is used. WhatsApp's CSP blocks direct JavaScript HTTP requests to localhost, so delivery uses native WinHTTP without weakening CSP.
|
||||
@@ -10,8 +19,17 @@ A WhatsApp process restart destroys injected code. For direct HTTPS, optional `-
|
||||
|
||||
For direct HTTPS, supply a 32–128 character printable ASCII token through the named environment variable using your secret manager, then run:
|
||||
|
||||
If you are setting it manually, this PowerShell prompt hides the input and avoids placing the token in the command text:
|
||||
|
||||
```powershell
|
||||
$env:WHATSAPP_INJECTOR_WEBHOOK_TOKEN = [System.Net.NetworkCredential]::new('', (Read-Host 'Webhook token' -AsSecureString)).Password
|
||||
```
|
||||
|
||||
Install the listener:
|
||||
|
||||
```powershell
|
||||
python whatsapp.py webhook install --endpoint https://your-endpoint.example/events --token-env WHATSAPP_INJECTOR_WEBHOOK_TOKEN --self-only --auto-restore --config listener.json
|
||||
Remove-Item Env:\WHATSAPP_INJECTOR_WEBHOOK_TOKEN
|
||||
```
|
||||
|
||||
The endpoint must authenticate `X-Webhook-Token` and accept the batch schema below. Certificate validation is enabled; credentials in URLs, query strings, fragments and redirects are rejected. Remove `--self-only` only when you intend to forward events from other chats. `webhook auto-restore --config listener.json` registers/enables restoration separately; `webhook ensure --config listener.json` performs one check. `webhook watch --config listener.json` is an optional continuously running alternative.
|
||||
@@ -60,6 +78,40 @@ The loopback endpoint is `POST /whatsapp-webhook` on `127.0.0.1`; direct HTTPS u
|
||||
|
||||
HTTP 2xx means the batch was accepted. The built-in receiver commits before acknowledgement and deduplicates message IDs. Failed HTTP delivery leaves queued records available for retry. Consumer side effects such as AI jobs should also deduplicate IDs. There is no exactly-once guarantee.
|
||||
|
||||
### Example batch
|
||||
|
||||
This is synthetic data. Message IDs are opaque strings; use `event_id` for deduplication rather than parsing its format.
|
||||
|
||||
```json
|
||||
{
|
||||
"listener_id": "91b17841-2106-4e73-97db-c38be6e9b269",
|
||||
"seqs": [1],
|
||||
"events": [{
|
||||
"seq": 1,
|
||||
"event_id": "synthetic-message-1",
|
||||
"type": "message",
|
||||
"message": {
|
||||
"id": "synthetic-message-1",
|
||||
"chat_id": "synthetic-chat",
|
||||
"timestamp": 1700000000,
|
||||
"from_me": true,
|
||||
"message_type": "chat",
|
||||
"body": "Hello",
|
||||
"caption": null,
|
||||
"text_truncated": false,
|
||||
"body_length": 5,
|
||||
"caption_length": 0
|
||||
}
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
`timestamp` is Unix seconds; sequence numbers identify queue entries within the current listener installation. Body/caption may be null. Text lengths count JavaScript UTF-16 code units. Batches contain up to 16 events and are additionally bounded by serialized size.
|
||||
|
||||
Your endpoint should authenticate `X-Webhook-Token`, validate the batch, deduplicate IDs, persist or enqueue accepted work, and only then return HTTP 2xx. No response-body schema is required by the relay. Use a non-2xx status when a retry is needed. TLS certificates must validate, and redirects are not followed.
|
||||
|
||||
For a summarizer, pass newly accepted message events to your own processing queue. This repository supplies delivery, not an AI provider, prompt, response policy or automatic message sender.
|
||||
|
||||
## Bounds and limitations
|
||||
|
||||
- This listens to the app's loaded message collection, not a server-side subscription. Messages not surfaced there can be missed.
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
---
|
||||
name: whatsapp-suite-development
|
||||
description: Maintain and extend this repository's WhatsApp Desktop Python suite, WebView bridge, message exports and webhook listener. Use for implementation, debugging, packaging or documentation in this project.
|
||||
---
|
||||
|
||||
# WhatsApp suite development
|
||||
|
||||
Use the repository containing this file. It has two distributions of the same code: editable `whatsapp_suite/` and generated portable `whatsapp.py`. The core path is Python ctypes → temporary Windows hook → bundled native DLL → existing WhatsApp WebView JavaScript. Core commands require no CDP or UI automation; separate research commands may use other transports.
|
||||
|
||||
## Route the work
|
||||
|
||||
- Read [CONTRIBUTING.md](../../CONTRIBUTING.md) for extension points, tests and native builds.
|
||||
- Read [architecture](../../docs/ARCHITECTURE.md) when changing bridge discovery, transport or lifetimes.
|
||||
- Read [webhooks](../../docs/WEBHOOKS.md) when changing event schema, delivery, restoration or removal.
|
||||
- Consult [validation](../../docs/VALIDATION.md) before claiming a build or live behavior is supported.
|
||||
|
||||
Prefer the existing module/helper for the requested change. Python commands are registered in `cli.COMMANDS`; top-level modules are packaged automatically. New assets need explicit builder entries. Do not edit encoded bundle contents.
|
||||
|
||||
## Preserve the contracts
|
||||
|
||||
- Native addresses are fingerprint-discovered, but object fields and ABI assumptions remain. Build metadata is advisory; unsupported native layouts fail discovery.
|
||||
- Exports use the app's database getter and decoder, preserve decode errors and refuse existing outputs. They are local scans, not atomic full-account snapshots.
|
||||
- The send CLI is a fixed self-message test with recipient checks and a reserved receipt. An uncertain send is not automatically retried.
|
||||
- Webhook events remain queued until HTTP 2xx; consumers deduplicate IDs. Queue memory is lost on app exit.
|
||||
- Restoration means automatic reinjection by a per-user task, not persistent app memory. Do not patch WhatsApp's package or silently install startup automation.
|
||||
- The task recovers a DPAPI-protected token; transport credentials stay out of listener JavaScript, CLI arguments, reports and Git.
|
||||
- Short-lived bridge cleanup and resident webhook lifetime differ. A stopped webhook helper remains loaded until app exit; restart the app before testing a replacement DLL.
|
||||
|
||||
## Complete the change
|
||||
|
||||
For code/assets/tests, run source tests, rebuild, then run portable tests:
|
||||
|
||||
```powershell
|
||||
python -m whatsapp_suite test
|
||||
python build_whatsapp_bundle.py
|
||||
python whatsapp.py test
|
||||
```
|
||||
|
||||
Inspect skips; Node.js enables the JavaScript fixtures. Verify a new command's portable help. Native changes additionally need x64 compilation, updated Python/asset hashes and relevant authorized live validation. Document what was actually tested.
|
||||
|
||||
Documentation-only edits need accurate CLI examples and valid links, not a bundle rebuild. Keep tests synthetic and live side effects explicit. Existing user authorization controls the scope; this skill does not authorize sending messages, installing tasks, publishing, or changing remote services.
|
||||
|
||||
Review staged files before publication. Keep exports, real fixtures, profiles, credentials and research captures out of Git. Commit source and generated bundle together when their inputs change.
|
||||
Reference in new issue
Block a user