From ca4b9b0d50e13ec2500226f4d1560571f1acdb0b Mon Sep 17 00:00:00 2001 From: mukunda katta Date: Wed, 15 Apr 2026 00:12:06 -0700 Subject: [PATCH] Use getpass for secret prompts in auto-collectors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `input()` echoes characters to the terminal and leaves them in shell scrollback / session recordings — a real hazard when the prompt is for an API token, app secret, or user access token. Switch every secret prompt in the setup flows to `getpass.getpass()`: - dingtalk: AppSecret - slack: Bot User OAuth Token - feishu_auto_collector: App Secret, user_access_token - feishu_mcp_client: App Secret, User Access Token Public identifiers (App ID / AppKey / chat_id / mode selection) stay as `input()` since they're not sensitive. Also add a short note to CONTRIBUTING.md under Security so future collectors follow the same pattern. Fixes #113 --- CONTRIBUTING.md | 1 + tools/dingtalk_auto_collector.py | 3 ++- tools/feishu_auto_collector.py | 5 +++-- tools/feishu_mcp_client.py | 5 +++-- tools/slack_auto_collector.py | 3 ++- 5 files changed, 11 insertions(+), 6 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 81f6e820..cbf4faaa 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -91,6 +91,7 @@ Don't hit live APIs in CI. Mock with `unittest.mock` or the `responses` library. - **Never commit secrets, tokens, or personal data.** If you accidentally do, rotate the credential immediately and let a maintainer know. - Config files that hold credentials should be written to the user's home (e.g. `~/.colleague-skill/`) with permission `0600`. +- **Always use `getpass.getpass()` for secret prompts** (API tokens, passwords, app secrets). Plain `input()` echoes characters to the terminal and leaves them in shell scrollback and session recordings. Public identifiers like App ID / username / URL can stay as `input()`. - If you find a security issue, **do not open a public issue.** Email the maintainer or DM on Discord. --- diff --git a/tools/dingtalk_auto_collector.py b/tools/dingtalk_auto_collector.py index e2b38b6f..0b01ac13 100644 --- a/tools/dingtalk_auto_collector.py +++ b/tools/dingtalk_auto_collector.py @@ -31,6 +31,7 @@ import time import argparse import platform +from getpass import getpass from pathlib import Path from datetime import datetime, timezone from typing import Optional @@ -79,7 +80,7 @@ def setup_config() -> None: print() app_key = input("AppKey (ding_xxx): ").strip() - app_secret = input("AppSecret: ").strip() + app_secret = getpass("AppSecret: ").strip() config = {"app_key": app_key, "app_secret": app_secret} save_config(config) diff --git a/tools/feishu_auto_collector.py b/tools/feishu_auto_collector.py index dc35e8cf..730892d5 100644 --- a/tools/feishu_auto_collector.py +++ b/tools/feishu_auto_collector.py @@ -45,6 +45,7 @@ import sys import time import argparse +from getpass import getpass from pathlib import Path from datetime import datetime, timezone from typing import Optional @@ -107,12 +108,12 @@ def setup_config() -> None: print() app_id = input("App ID (cli_xxx): ").strip() - app_secret = input("App Secret: ").strip() + app_secret = getpass("App Secret: ").strip() config = {"app_id": app_id, "app_secret": app_secret} print("\n是否配置 user_access_token?(用于私聊消息采集,可跳过)") - user_token = input("user_access_token (留空跳过): ").strip() + user_token = getpass("user_access_token (留空跳过): ").strip() if user_token: config["user_access_token"] = user_token p2p_chat_id = input("私聊 chat_id (留空跳过): ").strip() diff --git a/tools/feishu_mcp_client.py b/tools/feishu_mcp_client.py index 13f39999..0763d1ed 100644 --- a/tools/feishu_mcp_client.py +++ b/tools/feishu_mcp_client.py @@ -38,6 +38,7 @@ import json import argparse import subprocess +from getpass import getpass from pathlib import Path from typing import Optional @@ -64,7 +65,7 @@ def setup_config() -> None: print("请前往飞书开放平台(open.feishu.cn)创建企业自建应用,获取以下信息:\n") app_id = input("App ID (cli_xxx): ").strip() - app_secret = input("App Secret: ").strip() + app_secret = getpass("App Secret: ").strip() print("\n配置方式选择:") print(" [1] App Token(应用权限,需要在飞书后台开通对应权限)") @@ -79,7 +80,7 @@ def setup_config() -> None: if mode == "2": print("\n获取 User Token:飞书开放平台 → OAuth 2.0 → 获取 user_access_token") - user_token = input("User Access Token (u-xxx):").strip() + user_token = getpass("User Access Token (u-xxx):").strip() config["user_token"] = user_token print("注意:User Token 有效期约 2 小时,过期后需要重新配置") diff --git a/tools/slack_auto_collector.py b/tools/slack_auto_collector.py index 59442f93..0ad07ce3 100644 --- a/tools/slack_auto_collector.py +++ b/tools/slack_auto_collector.py @@ -36,6 +36,7 @@ import sys import time import argparse +from getpass import getpass from pathlib import Path from datetime import datetime, timezone from typing import Optional @@ -128,7 +129,7 @@ def setup_config() -> None: print("步骤 3:Install to Workspace → 复制 Bot User OAuth Token(xoxb-...)") print("步骤 4:将 Bot 加入目标频道(/invite @your-bot-name)\n") - token = input("Bot User OAuth Token (xoxb-...): ").strip() + token = getpass("Bot User OAuth Token (xoxb-...): ").strip() if not token.startswith("xoxb-"): print("警告:Token 格式不对,应以 xoxb- 开头", file=sys.stderr)