# WeChat Work Callback Debugging Reference

## Two Critical Code Bugs (utils.py)

### Bug 1: AES IV Wrong (line 321 & 372)
```python
# ❌ WRONG — uses first 16 bytes of ciphertext as IV
iv = encrypted_bytes[:16]
cipher_text = encrypted_bytes[16:]

# ✅ CORRECT — 企微 spec: IV = first 16 bytes of AES key
iv = aes_key[:16]
cipher_text = encrypted_bytes
```

### Bug 2: echostr URL Parsing (webhook_receiver.py line 103)
```python
# ❌ WRONG — Flask's request.args treats + in query string as space
echo = request.args.get("echostr", "")

# ✅ CORRECT — parse raw query string manually, unquote preserves +
from urllib.parse import unquote
raw_qs = request.query_string.decode("utf-8", errors="replace")
params = {}
for pair in raw_qs.split("&"):
    if "=" in pair:
        k, v = pair.split("=", 1)
        params[k] = unquote(v)
echo = params.get("echostr", "")
```

Symptom of Bug 2: `Echo decryption failed: Invalid base64-encoded string: number of data characters (5) cannot be 1 more than a multiple of 4`

## Diagnostic Flow

1. **Check if request arrived at all**: `sudo tail -20 /var/log/nginx/access.log` — look for non-127.0.0.1 entries with `/wx-callback` in path
2. **If no external entries**: firewall is blocking → Tencent Cloud 轻量服务器 → 防火墙 → ensure TCP port is allowed
3. **If request arrived but failed**: check TWO log files:
   - `webhook_receiver.log` — shows "Failed to decrypt echostr"
   - `article-maker.log` — shows detailed exception (Echo decryption failed: ...)
4. **Agent curl tests appear as 127.0.0.1 in Nginx logs** — don't mistake them for 企微 requests

## WeChat Work Callback Verification Flow

1. 企微 sends GET with: `msg_signature`, `timestamp`, `nonce`, `echostr`
2. Server must: decrypt echostr (AES-256-CBC, IV = AES key[:16]) and return plaintext
3. `decrypt_wx_echo()` in utils.py handles this

## Common Error Messages

| Error | Cause |
|-------|-------|
| `openapi回调地址请求不通过` | Network unreachable (firewall/port) |
| `decrypt failed` / `403` | Code bug (IV wrong or URL parsing truncation) |
| `echostr required` / `400` | GET request missing echostr parameter |
