Skip to content

feat(wechat): add wechat_allowed_users gating, mirror QQ adapter pattern#97

Open
shaun0927 wants to merge 1 commit intolsdefine:mainfrom
shaun0927:fix/wechat-allowed-users
Open

feat(wechat): add wechat_allowed_users gating, mirror QQ adapter pattern#97
shaun0927 wants to merge 1 commit intolsdefine:mainfrom
shaun0927:fix/wechat-allowed-users

Conversation

@shaun0927
Copy link
Copy Markdown
Contributor

Closes #95.

Problem

frontends/wechatapp.py is the only chat adapter that does not look at
an allow-list. Every other adapter under frontends/ reads
<platform>_allowed_users from mykey.py and rejects unknown senders:

Adapter Allow-list key
tgapp.py tg_allowed_users (non-empty required)
fsapp.py fs_allowed_users
qqapp.py qq_allowed_users
dingtalkapp.py dingtalk_allowed_users
wecomapp.py wecom_allowed_users
wechatapp.py (none)

After python frontends/wechatapp.py scans the QR code, anyone who
messages the bound personal WeChat account drives the agent — every
tool the agent has (code_run, file_read, file_write, web control)
is reachable to any contact, with no logging or rejection path.

Fix

Mirror the QQ adapter pattern that PR #25 established:

ALLOWED = {str(x).strip() for x in mykeys.get('wechat_allowed_users', []) if str(x).strip()}
...
if not public_access(ALLOWED) and uid not in ALLOWED:
    print(f'[WX] unauthorized user: {uid}', file=sys.__stdout__)
    return

Three deliberate decisions:

  1. Reuse chatapp_common.public_access() rather than inlining
    not allowed or '*' in allowed, so the semantics stay locked to
    the same definition the other adapters use. If public_access
    ever changes, wechat picks it up for free.
  2. Default behavior is unchanged — existing setups that don't set
    wechat_allowed_users get ALLOWED == set(), public_access()
    returns True, and every message still reaches the agent. This
    matches qq/dingtalk/wecom/fs exactly. (Telegram is the
    stricter exception that hard-fails on empty; not adopted here to
    avoid breaking existing wechat installs without warning.)
  3. Log line format matches qq/dingtalk: [WX] unauthorized user: <uid>, so a user grepping temp/wechatapp.log sees the
    same shape as the other adapters' logs.

mykey_template.py gets the matching # wechat_allowed_users = ['from_user_id']
comment line in the existing chat-platform block so the option is
discoverable.

Verification

  • python -m py_compile frontends/wechatapp.py mykey_template.py — passes.
  • Existing wechat installs (no wechat_allowed_users in mykey) keep working
    unchanged because ALLOWED is empty → public_access(ALLOWED) is True
    → the new check is skipped.
  • New installs that opt in via wechat_allowed_users = ['<from_user_id>']
    get the same allow-list semantics as qqapp.py (uid must be in the set).

Diff size: +8 / -0 across 2 files.

Closes lsdefine#95.

wechatapp.py was the only adapter under frontends/ without an
allowed_users gate, while every other adapter (tg, fs, qq, dingtalk,
wecom) reads <platform>_allowed_users from mykey.py and rejects
unknown senders.

Mirror the QQ adapter's pattern (introduced in PR lsdefine#25):

  - Read 'wechat_allowed_users' via mykeys, normalize via the same
    'set comprehension that keeps non-empty stripped strings' idiom.
  - Use the existing chatapp_common.public_access() helper so the
    semantics ('empty or ["*"] means public') match the rest of the
    ecosystem; this preserves backward compatibility for existing
    setups that have no wechat_allowed_users key.
  - Drop unauthorized senders with the same '[<Adapter>] unauthorized
    user: <id>' log message convention used by qq/dingtalk.

Add the optional knob to mykey_template.py next to the other
allowed_users entries so users can copy the comment block.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

wechatapp.py has no allowed_users gating, unlike every other adapter

1 participant