qwen-code/packages/channels
Mr-Maidong f4a9f7bfd7
feat(weixin): add image sending support via CDN upload (#3781)
* feat(weixin): add image sending support via CDN upload

* fix(weixin): address PR review — path validation, encoding, timeout, error handling

Critical fixes from wenshao's review of feat/weixin-image-send:

1. File read vulnerability: add validateImagePath() in send.ts with
   directory allowlist, extension filter, magic-byte check, 20MB cap,
   and realpath resolution. Pass workspace cwd as allowed dir.

2. aes_key encoding: change from base64(hex-ascii) to base64(raw 16B)
   to match the protocol expectation (images use raw bytes, not hex).

3. uploadToCdn timeout: add AbortController + 40s timeout per retry
   attempt to prevent hanging on stalled CDN connections.

4. Unhandled rejection: wrap fallback sendText() in catch block with
   its own try/catch to prevent process crash on double failure.

5. Default instructions merge: append image capability guide when
   custom instructions lack [IMAGE:], instead of silently dropping it.

6. Dead code: remove unused imagePaths parameter from sendMessage().

7. Regex hardening: strip code blocks before [IMAGE:] extraction,
   filter empty paths to prevent confusing readFileSync('') errors.

8. URL validation: reject http:// URLs and validate CDN hostname in
   uploadToCdn (SSRF prevention).

Tests: replace identity mock with real encryptAesEcb/computeMd5 so
padding mismatches are caught; fix partial node:crypto mock.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(weixin): address 2nd round PR review — 10 issues

Critical fixes:
1. detectImageMime: add JPEG magic bytes (0xFF 0xD8 0xFF), throw on
   unrecognized format instead of defaulting to image/jpeg
2. getUploadUrl retry: pass errcode to WeixinApiError, add ret field
   check in isRetryableError so actual API errors trigger retries
3. ALLOWED_DIRS: add realpathSync('/tmp/') and realpathSync(tmpdir())
   to handle macOS symlink resolution (/tmp → /private/tmp)
4. [IMAGE:] stripping: only replace markers that were actually parsed,
   preserving [IMAGE:] inside code blocks in displayed text
5. TOCTOU fix: use openSync/readSync(16B) for magic-byte check instead
   of reading the entire file twice
6. sendMessage: check both ret and errcode fields for error detection

Suggestions:
7. connect(): avoid mutating this.config.instructions on reconnect
8. Fix duplicate Step 2 comment numbering
9. Replace errcode=${undefined} with errcode=${resp.errcode ?? '(none)'}
10. stderr: log structured (status=, ret=) instead of raw errmsg

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(weixin): 3rd round PR review — errcode checks, error logging, timeout, path resolution

- api.ts: add errcode check in getUploadUrl (align with sendMessage)
- api.ts: pass ret/errcode from CDN error to WeixinApiError
- send.ts: resolve workspace dirs with realpathSync
- WeixinAdapter.ts: include errcode and err.message in error log
- media.ts: add 40s timeout to downloadAndDecrypt fetch
- send.test.ts: add 12 tests covering detectImageMime and validateImagePath error branches

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

---------

Co-authored-by: Maidong <408097061@qq.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-05-06 01:49:26 +08:00
..
base chore(release): v0.15.6 (#3766) 2026-04-30 15:59:35 +08:00
dingtalk chore(release): v0.15.6 (#3766) 2026-04-30 15:59:35 +08:00
plugin-example chore(release): v0.15.6 (#3766) 2026-04-30 15:59:35 +08:00
telegram chore(release): v0.15.6 (#3766) 2026-04-30 15:59:35 +08:00
weixin feat(weixin): add image sending support via CDN upload (#3781) 2026-05-06 01:49:26 +08:00