diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9035b61c..2cf44dd5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -12,4 +12,9 @@ repos: hooks: - id: isort name: isort (python) +- repo: https://github.com/PyCQA/bandit + rev: 1.7.7 + hooks: + - id: bandit + args: ['-c', 'pyproject.toml'] diff --git a/README.md b/README.md index 9c84b696..f5bb07fa 100644 --- a/README.md +++ b/README.md @@ -178,7 +178,8 @@ python3 -m wechatter | --- | --- | --- | --- | | `message_forwarding_enabled` | | 功能开关,是否开启消息转发 | 默认为 `False` | | `message_forwarding_rule_list` | | 消息规则列表,每个规则包含三个字段:`from_list`、`to_person_list` 和 `to_group_list` | | -| | `from_list` | 消息转发来源列表,即消息发送者 | 可以填多个用户名称或群名称 | +| | `from_list` | 消息转发来源列表,即消息发送者 | 可以填多个用户名称或群名称,若要转发所有消息则使用 `["%ALL"]` | +| | `from_list_exclude` | 消息转发来源排除列表,不转发此列表的用户和群 | 只在 `from_list` 为 `["%ALL"]` 时生效 | | | `to_person_list` | 消息转发目标用户列表,即消息接收用户 | 可以填多个用户名称或为空列表 | | | `to_group_list` | 消息转发目标群列表,即消息接收群 | 可以填多个群名称或为空列表 | @@ -189,7 +190,6 @@ python3 -m wechatter | `all_task_cron_enabled` | 所有定时任务的总开关 | 默认为 `True` | | `task_cron_list` | 定时任务列表,每个任务包含四个字段:`task`、`enabled`、`cron` 和 `commands` | | -[//]: # (引导用户查看定时任务配置详细docs/task_cron_config_detail) 关于定时任务配置详细请参阅[定时任务配置详细](docs/task_cron_config_detail.md)。 ### ⚙️ Custom Command Key 配置 diff --git a/config.yaml.example b/config.yaml.example index d7431ff8..6be404eb 100644 --- a/config.yaml.example +++ b/config.yaml.example @@ -30,11 +30,15 @@ github_webhook_receive_person_list: [ ] github_webhook_receive_group_list: [ ] # Message Forwarding:消息转发 -message_forwarding_enabled: True +message_forwarding_enabled: False message_forwarding_rule_list: - - from_list: [ "缘" ] - to_person_list: [ ] - to_group_list: [ "WeChatter" ] + - from_list: [ "%ALL" ] + from_list_exclude: [ "You" ] + to_person_list: [ "You" ] + to_group_list: [ ] + - from_list: [ "Jay", "Tom" ] + to_person_list: [ "Cassius" ] + to_group_list: [ "Team" ] # Task Cron:定时任务 # 配置说明:https://github.com/Cassius0924/WeChatter/blob/master/docs/task_cron_config_detail.md diff --git a/pyproject.toml b/pyproject.toml index 22d2b53b..3728edef 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,3 +13,8 @@ line_length = 88 multi_line_output = 3 include_trailing_comma = true combine_as_imports = true + + +# bandit +[tool.bandit] +skips = ["B101"] diff --git a/wechatter/commands/_commands/trivia.py b/wechatter/commands/_commands/trivia.py index 6d0f0afa..8bd613fd 100644 --- a/wechatter/commands/_commands/trivia.py +++ b/wechatter/commands/_commands/trivia.py @@ -19,7 +19,7 @@ desc="获取冷知识。", ) def trivia_command_handler(to: Union[str, SendTo], message: str = "") -> None: - random_number = random.randint(1, 917) + random_number = random.randint(1, 917) # nosec try: response = get_request( url=f"http://www.quzhishi.com/shiwangelengzhishi/{random_number}.html" diff --git a/wechatter/message/message_forwarder.py b/wechatter/message/message_forwarder.py index 498b5bd5..e3710e15 100644 --- a/wechatter/message/message_forwarder.py +++ b/wechatter/message/message_forwarder.py @@ -1,4 +1,4 @@ -from typing import List +from typing import Dict, List from loguru import logger @@ -10,38 +10,85 @@ from wechatter.sender import sender +def _forwarding_by_rule(message_obj: Message, rule: Dict): + """ + 根据规则转发消息 + :param message_obj: 消息对象 + :param rule: 规则 + """ + # 应用 exclude 规则 + # 开始转发消息 + to_person_list = rule["to_person_list"] + if message_obj.sender_name in rule.get("from_list_exclude", []): + return + if to_person_list: + msg = _construct_forwarding_message(message_obj) + sender.mass_send_msg(to_person_list, msg, is_group=False) + logger.info(f"转发消息:{message_obj.sender_name} -> {to_person_list}") + to_group_list = rule["to_group_list"] + if to_group_list: + msg = _construct_forwarding_message(message_obj) + sender.mass_send_msg(to_group_list, msg, is_group=True) + logger.info(f"转发消息:{message_obj.sender_name} -> {to_group_list}") + + class MessageForwarder: """ 消息转发器类 """ def __init__(self, rule_list: List): - self.rule_list = rule_list + """ + 初始化 + :param rule_list: 转发规则列表 + """ + self.all_message_rule = { + "from_list_exclude": [], + "to_group_list": [], + "to_person_list": [], + } + self.specific_message_rules = {} + + for rule in rule_list: + if "%ALL" in rule["from_list"]: + self.all_message_rule["from_list_exclude"].extend( + rule.get("from_list_exclude", []) + ) + self.all_message_rule["to_group_list"].extend( + rule.get("to_group_list", []) + ) + self.all_message_rule["to_person_list"].extend( + rule.get("to_person_list", []) + ) + else: + for from_name in rule["from_list"]: + if from_name not in self.specific_message_rules: + self.specific_message_rules[from_name] = { + "to_group_list": [], + "to_person_list": [], + } + self.specific_message_rules[from_name]["to_group_list"].extend( + rule.get("to_group_list", []) + ) + self.specific_message_rules[from_name]["to_person_list"].extend( + rule.get("to_person_list", []) + ) - def forward_message(self, message_obj: Message): + def forwarding(self, message_obj: Message): """ 消息转发 :param message_obj: 消息对象 """ # TODO: 转发文件 - from_name = message_obj.sender_name - # TODO: from_list 支持通配符 + # 判断消息来源是否符合转发规则 + if self.all_message_rule: + rule = self.all_message_rule + _forwarding_by_rule(message_obj, rule) - # 判断消息是否符合转发规则 - for rule in self.rule_list: - # 判断消息来源是否符合转发规则 - if from_name in rule["from_list"]: - # 构造转发消息 - msg = _construct_forwarding_message(message_obj) - to_person_list = rule.get("to_person_list") - if to_person_list: - logger.info(f"转发消息:{from_name} -> {to_person_list}") - sender.mass_send_msg(to_person_list, msg, is_group=False) - to_group_list = rule.get("to_group_list") - if to_group_list: - logger.info(f"转发消息:{from_name} -> {to_group_list}") - sender.mass_send_msg(to_group_list, msg, is_group=True) + if message_obj.sender_name in self.specific_message_rules.keys(): + rule = self.specific_message_rules[message_obj.sender_name] + _forwarding_by_rule(message_obj, rule) @staticmethod def reply_forwarded_message(message_obj: Message): diff --git a/wechatter/message/message_handler.py b/wechatter/message/message_handler.py index ad265be4..f530bdff 100644 --- a/wechatter/message/message_handler.py +++ b/wechatter/message/message_handler.py @@ -74,6 +74,9 @@ def _get_quoted_response(quotable_id: str) -> QuotedResponse: return quoted_response +message_forwarder = MessageForwarder(config["message_forwarding_rule_list"]) + + class MessageHandler: """ 消息处理器,用于处理用户发来的消息 @@ -94,8 +97,7 @@ def handle_message(self, message_obj: Message): """ if config["message_forwarding_enabled"]: - message_forwarder = MessageForwarder(config["message_forwarding_rule_list"]) - message_forwarder.forward_message(message_obj) + message_forwarder.forwarding(message_obj) if message_obj.forwarded_source: message_forwarder.reply_forwarded_message(message_obj) diff --git a/wechatter/models/wechat/message.py b/wechatter/models/wechat/message.py index ca4d28b0..3a2e9d4d 100644 --- a/wechatter/models/wechat/message.py +++ b/wechatter/models/wechat/message.py @@ -192,7 +192,7 @@ def forwarded_source(self) -> Optional[Tuple[str, bool]]: group_format = GROUP_FORWARDING_MESSAGE_FORMAT.replace("[", "\[").replace( "]", "\]" ) - pattern = re.compile(f'{group_format % ("(.+)", "(.+)")}') + pattern = re.compile(f'{group_format % ("(.*)", "(.+)")}') try: # 将名字和该名字是否为群都返回,便于在回复时判断 return re.search(pattern, self.content).group(2), True diff --git a/wechatter/wechatter.py b/wechatter/wechatter.py index 613d3ae3..8a4f72ab 100644 --- a/wechatter/wechatter.py +++ b/wechatter/wechatter.py @@ -30,7 +30,7 @@ def main(): # 启动uvicorn port = config["wechatter_port"] - uvicorn.run(app, host="0.0.0.0", port=port) + uvicorn.run(app, host="0.0.0.0", port=port) # nosec if __name__ == "__main__":