diff --git a/Api_Server/Api_Server_Main.py b/Api_Server/Api_Server_Main.py new file mode 100644 index 0000000..796173a --- /dev/null +++ b/Api_Server/Api_Server_Main.py @@ -0,0 +1,526 @@ +# -*- encoding=UTF-8 -*- +from Output.output import output +from urllib.parse import quote +import feedparser +import requests +import urllib3 +import random +import time +import yaml +import os +import re + + +class Api_Server_Main: + def __init__(self): + # 全局header头 + self.headers = { + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36", + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", + "Accept-Language": "zh-CN,zh;q=0.9", + "Accept-Encoding": "gzip, deflate, br", + # 'Connection':'keep-alive' ,#默认时链接一次,多次爬取之后不能产生新的链接就会产生报错Max retries exceeded with url + "Upgrade-Insecure-Requests": "1", + "Pragma": "no-cache", + "Cache-Control": "no-cache", + "Connection": "close", # 解决Max retries exceeded with url报错 + } + # 忽略HTTPS告警 + urllib3.disable_warnings() + # 获取当前文件路径 + current_path = os.path.dirname(__file__) + + # 配置缓存文件夹路径 + current_list_path = current_path.split('\\') + current_list_path.pop() + self.Cache_path = '/'.join(current_list_path) + '/Cache' + # 初始化读取配置文件 + config = yaml.load(open(current_path + '/../Config/config.yaml', encoding='UTF-8'), yaml.Loader) + self.system_copyright = config['System_Config']['System_Copyright'] + + # 配置文章变量 + self.news_list = '' + + # 读取配置文件 + config = yaml.load(open(current_path + '/../Config/config.yaml', encoding='UTF-8'), yaml.Loader) + self.appid = config['Api_Server']['Api_Config']['Appid'] + self.appsecret = config['Api_Server']['Api_Config']['Appsecret'] + self.key = config['Api_Server']['Api_Config']['Key'] + self.threatbook_key = config['Api_Server']['Api_Config']['ThreatBook_Key'] + + self.pic_apis = config['Api_Server']['Pic_Api'] + self.video_apis = config['Api_Server']['Video_Api'] + self.icp_api = config['Api_Server']['Icp_Api'] + self.extensions_api = config['Api_Server']['Extensions_Api'] + self.attribution_api = config['Api_Server']['Attribution_Api'] + self.whois_api = config['Api_Server']['Whois_Api'] + self.fish_api = config['Api_Server']['Fish_Api'] + self.wether_api = config['Api_Server']['Wether_Api'] + self.dog_api = config['Api_Server']['Dog_Api'] + self.constellation_api = config['Api_Server']['Constellation_Api'] + self.morning_api = config['Api_Server']['Morning_Api'] + self.threatbook_url = config['Api_Server']['ThreatBook_Api'] + + # AI对话接口 + def get_ai(self, keyword): + output('[-]:正在调用AI对话API接口... ...') + url = 'https://v1.apigpt.cn/?q={keyword}&apitype=sql'.format(keyword=keyword.replace(' ', '')) + try: + resp = requests.get(url=url, timeout=120).json() + msg = resp['ChatGPT_Answer'].strip() + except Exception as e: + msg = f'[ERROR]:AI对话接口错误,错误信息:{e}' + return msg + + # 美女图片接口 + def get_pic(self): + output('[-]:正在调用美女图片API接口... ...') + url = random.choice(self.pic_apis) + try: + pic_data = requests.get(url=url, headers=self.headers, timeout=30).content + save_path = self.Cache_path + '/Pic_Cache/' + str(int(time.time() * 1000)) + '.jpg' + with open(file=save_path, mode='wb') as pd: + pd.write(pic_data) + except Exception as e: + msg = f'[ERROR]:美女图片API接口出现错误,错误信息:{e}' + output(msg) + return msg + return save_path + + # 美女视频接口 + def get_video(self): + output('[-]:正在调用美女视频API接口... ...') + url = random.choice(self.video_apis) + # url = 'https://zj.v.api.aa1.cn/api/video_dyv2/' + try: + try: + resp = requests.get(url=url, headers=self.headers, timeout=80).json() + if 'url' in resp: + src = resp['url'] + else: + src = resp['mp4'] + except requests.exceptions.JSONDecodeError: + src = re.findall('src="(.*?)"', requests.get(url=url, headers=self.headers, timeout=20).text)[0] + # print(src) + mp4_url = src + if 'http' not in src: + mp4_url = 'http:' + src + video_data = requests.get(url=mp4_url, headers=self.headers).content + save_path = self.Cache_path + '/Video_Cache/' + str(int(time.time() * 1000)) + '.mp4' + with open(file=save_path, mode='wb') as vd: + vd.write(video_data) + except Exception as e: + msg = f'[ERROR]:美女视频API接口出现错误,错误信息:{e}' + output(msg) + return msg + return save_path + + # 备案查询接口 + def get_icp(self, keyword): + try: + domain = re.findall(r' (\w+.\w+)', keyword)[0] + except Exception as e: + msg = '语法格式:\nICP查询 qq.com' + output(f'[ERROR]:备案查询接口出现错误,错误信息:{e}') + return msg + url = self.icp_api.format(domain) + try: + data = requests.get(url=url, headers=self.headers, timeout=10).json() + except Exception as e: + msg = f'[ERROR]:备案查询接口超时,错误信息:{e}' + output(msg) + return msg + if data['icp'] == '未备案': + return '该域名未备案!' + msg = f'======== 查询信息 ========\nICP备案号:{data["icp"]}\n备案主体:{data["name"]}\n备案类型:{data["tyle"]}\n{"By: #" + self.system_copyright if self.system_copyright else ""}\n========================' + return msg.strip() + + # 后缀名查询接口 + def get_suffix(self, keyword): + try: + word = re.findall(r' (\w+)', keyword)[0] + except Exception as e: + msg = '语法格式:\n后缀名查询 EXE' + output(f'\n[ERROR]:后缀名查询接口出现错误,错误信息:{e}') + return msg + url = self.extensions_api.format(self.key, word) + try: + data = requests.get(url=url, headers=self.headers).json() + except TimeoutError as e: + msg = f'\n[ERROR]:后缀名查询接口超时,错误信息:{e}' + output(msg) + return msg + if data['code'] != 200: + msg = '查询结果为空!' + else: + msg = f'\n======== 查询后缀:{word} ========\n查询结果:{data["result"]["notes"]}\n{"By: #" + self.system_copyright if self.system_copyright else ""}\n============================' + return msg + + # 归属地查询 + def get_attribution(self, keyword): + try: + phone = re.findall(r' (\d+)', keyword)[0] + except Exception as e: + msg = '语法格式:\n归属查询 110' + output(f'\n[ERROR]:归属查询接口出现错误,错误信息:{e}') + return msg + url = self.attribution_api.format(phone) + try: + data = requests.get(url=url, headers=self.headers).json() + except TimeoutError as e: + msg = f'\n[ERROR]:归属查询接口超时,错误信息:{e}' + output(msg) + return msg + if not data['data']['province']: + msg = '查询结果为空!' + else: + msg = f'\n===== 查询信息 =====\n手机号码:{phone}\n省份:{data["data"]["province"]}\n城市:{data["data"]["city"]}\n运营商:{data["data"]["sp"]}\n{"By: #" + self.system_copyright if self.system_copyright else ""}\n=================' + return msg + + # Whois查询接口 + def get_whois(self, keyword): + try: + domain = re.findall(r' (\w+.\w+)', keyword)[0] + except Exception as e: + msg = '语法格式:\nWHOIS查询 qq.com' + output(f'[ERROR]:WHOIS查询接口出现错误,错误信息:{e}') + return msg + url = self.whois_api.format(domain) + try: + source_data = requests.get(url=url, headers=self.headers).text + except TimeoutError as e: + msg = f'\n[ERROR]:WHOIS查询接口超时,错误信息:{e}' + output(msg) + return msg + msg = '\n' + source_data.strip().split('For more information')[0].strip('
').strip() + f"\n{'By: #' + self.system_copyright if self.system_copyright else ''}" + return msg + + # 微步ip查询接口 + def get_threatbook_ip(self, keyword): + try: + keyword = keyword.split(' ')[-1] + except Exception as e: + output(f'[ERROR]:微步ip查询接口出现错误,错误信息:{e}') + reg = r"((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})(\.((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})){3}" + ip_result = re.match(reg, keyword.replace(' ', '').strip()) + if ip_result is None: + msg = "语法格式: \nIP查询 xx.xx.xx.xx" + return msg + elif len(keyword) > 0 and ip_result.group(): + search_ip = ip_result.group() + ips = str(search_ip).split('.') + continuous_bool = True if [i for i in ips if ips[0] != i] else False + if ips[0] in ['127', '192', '0', '224', '240', '255'] or \ + search_ip in ['1.1.1.1', '2.2.2.2', '3.3.3.3', '4.4.4.4', '5.5.5.5', '6.6.6.6', '7.7.7.7', + '8.8.8.8', '9.9.9.9', '10.10.10.10'] or \ + '.'.join(ips[0:2]) in ['169.254', '100.64', '198.51', '198.18', '172.16'] or \ + '.'.join(ips[0:3]) in ['203.0.113'] or \ + ips[-1] in ['255', '254']: + msg = "[微笑]暂不支持查询该地址!" + return msg + if not continuous_bool: + msg = "[微笑]暂不支持查询该地址!" + return msg + try: + + data = { + "apikey": self.threatbook_key, + "resource": search_ip, + } + + resp = requests.post( + self.threatbook_url, + data=data, + timeout=10, + verify=False, + ) + if resp.status_code == 200 and resp.json()["response_code"] == 0: + # 查风险等级 + sec_level = resp.json()["data"]["{}".format(search_ip)]["severity"] + # 查是否恶意IP + is_malicious = resp.json()["data"]["{}".format(search_ip)]["is_malicious"] + # 查可信度 + confidence_level = resp.json()["data"]["{}".format(search_ip)]["confidence_level"] + # 查IP归属国家 + country = resp.json()["data"]["{}".format(search_ip)]["basic"]["location"][ + "country" + ] + # 查IP归属省份 + province = resp.json()["data"]["{}".format(search_ip)]["basic"]["location"][ + "province" + ] + # 查IP归属城市 + city = resp.json()["data"]["{}".format(search_ip)]["basic"]["location"]["city"] + # 将IP归属的国家、省份、城市合并成一个字符串 + location = country + "-" + province + "-" + city + # 查威胁类型 + judgments = "" + for j in resp.json()["data"]["{}".format(search_ip)]["judgments"]: + judgments += j + " " + if is_malicious: + is_malicious_msg = "是" + else: + is_malicious_msg = "否" + msg = f"\n===================\n[+]ip:{search_ip}\n[+]风险等级:{sec_level}\n[+]是否为恶意ip:{is_malicious_msg}\n[+]可信度:{confidence_level}\n[+]威胁类型:{str(judgments)}\n[+]ip归属地:{location}\n更新时间:{resp.json()['data']['{}'.format(search_ip)]['update_time']}\n{'By: #' + self.system_copyright if self.system_copyright else ''}\n===================" + else: + msg = f"[ERROR]:查询失败,返回信息:{resp.json()['verbose_msg']}" + output(msg) + except Exception as e: + output(f"[ERROR]:微步IP查询出错,错误信息:{e}") + msg = f"[ERROR]:查询出错请稍后重试,错误信息:{e}" + return msg + + # 摸鱼日记接口 + def get_fish(self): + output('[-]:正在调用摸鱼日记API接口... ...') + try: + pic_data = requests.get(url=self.fish_api, headers=self.headers, timeout=10).content + save_path = self.Cache_path + '/Fish_Cache/' + str(int(time.time() * 1000)) + '.jpg' + with open(file=save_path, mode='wb') as pd: + pd.write(pic_data) + except Exception as e: + msg = f'[ERROR]:摸鱼日记API接口出现错误,错误信息:{e}' + output(msg) + return msg + return save_path + + # 天气查询接口 + def get_wether(self, keyword): + try: + city = re.findall(r' (\w+)', keyword)[0] + except Exception as e: + msg = '语法格式:\n天气查询 北京' + output(f'\n[ERROR]:天气查询接口出现错误,错误信息:{e}') + return msg + url = self.wether_api.format(self.appid, self.appsecret, city) + try: + data = requests.get(url=url, headers=self.headers).json() + except TimeoutError as e: + msg = f'\n[ERROR]:天气查询接口超时,错误信息:{e}' + output(msg) + return msg + try: + if city != data['city']: + msg = f'城市中不存在:{data["city"]}' + return msg + else: + msg = f'\n今日{data["city"]}天气:{data["wea"]}\n日期:{data["date"]}\n当前温度:{data["tem"]}\n最低温度:{data["tem_day"]}\n风向:{data["win"] + data["win_speed"]}\n风速:{data["win_meter"]}\n湿度:{data["humidity"]}\n{"By: #" + self.system_copyright if self.system_copyright else ""}' + return msg + except Exception as e: + output(f'[ERROR]:天气查询接口出现错误出现错误,错误信息:{e}') + msg = f'城市中不存在:{city}' + return msg + + # 舔狗日记 + def get_dog(self): + url = self.dog_api.format(self.key) + try: + data = requests.get(url=url, headers=self.headers).json() + except TimeoutError as e: + msg = f'\n[ERROR]:舔狗日记接口超时,错误信息:{e}' + output(msg) + return msg + try: + msg = data['newslist'][0]['content'].strip() + except Exception as e: + msg = f'[ERROR]:舔狗日记接口出现错误出现错误,错误信息:{e}' + output(msg) + return msg + + # 星座查询接口 + def get_constellation(self, keyword): + msg = '' + try: + constellation = re.findall(r' (\w+)', keyword)[0] + if '座' not in constellation: + constellation += '座' + except Exception as e: + msg = '语法格式:\n星座查询 白羊座' + output(f'\n[ERROR]:星座查询接口出现错误,错误信息:{e}') + return msg + url = self.constellation_api.format(self.key, constellation) + try: + data = requests.get(url=url, headers=self.headers).json() + except TimeoutError as e: + msg = f'\n[ERROR]:星座查询接口超时,错误信息:{e}' + output(msg) + return msg + for news in data['newslist']: + msg += news['type'] + ':' + news['content'] + '\n' + msg = f'\n星座:{constellation}\n' + msg.strip() + f"\n{'By: #' + self.system_copyright if self.system_copyright else ''}" + return msg + + # 早安寄语 + def get_morning(self): + url = self.morning_api.format(self.key) + try: + data = requests.get(url=url, headers=self.headers).json() + except TimeoutError as e: + msg = f'\n[ERROR]:早安寄语接口超时,错误信息:{e}' + output(msg) + return msg + msg = f'{data["result"]["content"]}' + return msg + + # 早报推送 + def get_freebuf_news(self, ): + morning_time = time.strftime("%a, %d %b %Y", time.localtime()) + str_list = "#FreeBuf早报\n" + try: + rs1 = feedparser.parse('https://www.freebuf.com/feed') + # print(rs1['entries']) + for ent in rs1['entries']: + if morning_time in ent['published']: + title = ent['title'] + link = ent['link'] + str_list += '\n' + title + '\n' + link + '\n' + if 'http' not in str_list: + str_list += '\n 今日暂无文章' + except Exception as e: + link6 = "\n今日暂无文章" + str_list += link6 + output("ERROR:获取FreeBuf早报出错,错误信息: {}".format(e)) + str_list += f"\n{self.system_copyright + '整理分享,更多内容请戳 #' + self.system_copyright if self.system_copyright else ''}\n{time.strftime('%Y-%m-%d %X')}" + return str_list + + # 获取先知社区文章 + def get_xz_news(self, ): + str_list = "#先知社区" + try: + rs1 = feedparser.parse('https://xz.aliyun.com/feed') + length = len(rs1.entries) + for buf in range(length): + try: + if str(time.strftime("%Y-%m-%d")) in str(rs1.entries[buf]["published"]): + url_f = rs1.entries[buf]["link"] + title_f = rs1.entries[buf]["title_detail"]["value"] + link4 = "\n" + title_f + "\n" + url_f + "\n" + str_list += link4 + else: + pass + except Exception as e: + output("[ERROR]:获取先知社区文章出现错误,错误信息:{}".format(e)) + break + if len(str_list) > 10: + self.news_list += str_list + else: + link6 = "#先知社区\n今日暂无文章" + self.news_list += link6 + except Exception as e: + link6 = "#先知社区\n今日暂无文章" + self.news_list += link6 + output("ERROR:先知社区 {}".format(e)) + return f'[-]:爬取先知社区文章出错,错误信息:{e}' + + # 获取奇安信攻防社区文章 + def get_qax_news(self, ): + str_list = "\n#奇安信攻防社区" + try: + rs1 = feedparser.parse('https://forum.butian.net/Rss') + length = len(rs1.entries) + for buf in range(length): + try: + if str(time.strftime("%Y-%m-%d")) in str(rs1.entries[buf]["published"]): + url_f = rs1.entries[buf]["link"] + title_f = rs1.entries[buf]["title_detail"]["value"] + link4 = "\n" + title_f + "\n" + url_f + "\n" + str_list += link4 + else: + pass + except Exception as e: + output("[ERROR]:爬取奇安信攻防社区文章出错,错误信息:{}".format(e)) + break + if len(str_list) > 10: + self.news_list += str_list + else: + link6 = "\n#奇安信攻防社区\n今日暂无文章" + self.news_list += link6 + except Exception as e: + link6 = "\n#奇安信攻防社区\n今日暂无文章" + self.news_list += link6 + output("[ERROR]:奇安信攻防社区 {}".format(e)) + return f"[-]:爬取奇安信攻防社区文章出错,错误信息:{e}" + + # 获取安全客文章 + def get_anquanke_news(self, ): + str_list = "" + str_list += "\n#安全客" + try: + rs1 = requests.get('https://www.anquanke.com/knowledge', timeout=5, verify=False) + rs1.encoding = "utf-8" + resp_text = ( + rs1.text.replace("\xa9", "") + .replace("\n", "") + .replace(">", "") + .replace(" ", "") + .replace(" ", "") + .replace(" ", "") + ) + newlist = re.findall( + '(.*?) ', + resp_text, + re.S, + ) + timelist = re.findall( + ' (.*?)', + resp_text, + re.S, + ) + for a in range(len(timelist)): + try: + if time.strftime("%Y-%m-%d") in timelist[a]: + link1 = str(newlist[a][1]) + link2 = "https://www.anquanke.com" + str(newlist[a][0]) + link3 = "\n" + str(link1) + "\n" + str(link2) + "\n" + str_list += link3 + else: + pass + except Exception as e: + output("爬取安全客文章出错,错误信息:{}".format(e)) + break + if len(str_list) > 6: + self.news_list += str_list + else: + link6 = "\n#安全客\n今日暂无文章" + self.news_list += link6 + except Exception as e: + link6 = "\n#安全客\n今日暂无文章" + self.news_list += link6 + output("[ERROR]:爬取安全客文章出错,错误信息:{}".format(e)) + return f"[-]:爬取安全客文章出错,错误信息:{e}" + + # 获取各平台安全文章 + def get_safety_news(self, ): + self.news_list = '' + output("[+]:正在爬取安全新闻... ...") + self.get_xz_news() + self.get_qax_news() + self.get_anquanke_news() + output("[+]:获取成功") + self.news_list += f"\n{self.system_copyright + '整理分享,更多内容请戳 #' + self.system_copyright if self.system_copyright else ''}\n{time.strftime('%Y-%m-%d %X')}" + return self.news_list.strip() + + # 测试专用 + def demo(self): + # url = 'https://tucdn.wpon.cn/api-girl/' + # data = requests.get(url=url, headers=self.headers).json() + # print(data) + domain = 'qq.com' + text = 'https://v.api.aa1.cn/api/icp/index.php?url={domain}'.format(domain=domain) + print(text) + + +if __name__ == '__main__': + Asm = Api_Server_Main() + # Asm.get_ai('你好') + # Asm.get_pic() + # Asm.demo() + Asm.get_video() + # Asm.icp_query(keyword='ICP查询 qq.com') + # Asm.get_suffix(keyword='icp查询 apk') + # Asm.get_attribution(keyword='归属查询 17371963534') + # Asm.get_whois(keyword='whois查询 qq.com') + # Asm.get_wether(keyword='天气查询 123') + # Asm.get_dog() + # Asm.get_constellation('星座查询 白羊座') + # print(Asm.get_freebuf_news()) diff --git a/BotServer/MainServer.py b/BotServer/MainServer.py new file mode 100644 index 0000000..e10f288 --- /dev/null +++ b/BotServer/MainServer.py @@ -0,0 +1,250 @@ +from Recv_Msg_Dispose.FriendMsg_dispose import FriendMsg_dispose +from Recv_Msg_Dispose.RoomMsg_dispose import RoomMsg_disposes +from Push_Server.Push_Main_Server import Push_Main_Server +from Db_Server.Db_User_Server import Db_User_Server +from concurrent.futures import ThreadPoolExecutor +from BotServer.SendServer import SendServer +from bs4 import BeautifulSoup +from Output.output import * +import websocket +import yaml +import json +import os + + +class MainServers: + + def __init__(self): + # 初始化读取配置文件 + current_path = os.path.dirname(__file__) + config = yaml.load(open(current_path + '/../Config/config.yaml', encoding='UTF-8'), yaml.Loader) + self.ip = config['BotServer']['IP'] + self.port = config['BotServer']['PORT'] + self.system_copyright = config['System_Config']['System_Copyright'] + + # 配置HOOK信息类型 + self.SERVER = f"ws://{self.ip}:{self.port}" + self.HEART_BEAT = 5005 + self.RECV_TXT_MSG = 1 + self.RECV_TXT_CITE_MSG = 49 + self.RECV_PIC_MSG = 3 + self.USER_LIST = 5000 + self.GET_USER_LIST_SUCCSESS = 5001 + self.GET_USER_LIST_FAIL = 5002 + self.TXT_MSG = 555 + self.PIC_MSG = 500 + self.AT_MSG = 550 + self.CHATROOM_MEMBER = 5010 + self.CHATROOM_MEMBER_NICK = 5020 + self.PERSONAL_INFO = 6500 + self.DEBUG_SWITCH = 6000 + self.PERSONAL_DETAIL = 6550 + self.DESTROY_ALL = 9999 + self.JOIN_ROOM = 10000 + self.ATTATCH_FILE = 5003 + + # 启动机器人 + self.ws = websocket.WebSocketApp( + self.SERVER, on_open=self.on_open, on_message=self.on_message, on_error=self.on_error, + on_close=self.on_close + ) + + # 实例化消息服务 + self.Ss = SendServer() + + # 实例化群消息处理类 + self.Rmd = RoomMsg_disposes() + + # 实例化好友消息处理 + self.Fmd = FriendMsg_dispose() + + # 实例化用户数据服务类 + self.Dus = Db_User_Server() + + # Robot初始化执行 + def on_open(self, ws): + # 实例化实时监控类 + self.Pms = Push_Main_Server(ws=self.ws) + pool = ThreadPoolExecutor(5) + pool.submit(self.Pms.run) + self.get_personal_info() + + # Robot 启动函数 + def Bot_start(self, ): + self.ws.run_forever() + + # Robot 关闭执行 + def on_close(self, ws): + output("The Robot is Closed...") + + # Robot 错误输出 + def on_error(self, ws, error): + output(f"[ERROR]:出现错误,错误信息:{error}") + + # 启动完成输出 + def handle_wxuser_list(self): + output("Bot is Start!") + + # Robot 心跳输出 + def heartbeat(self, msgJson): + output(f'[*]:{msgJson["content"]}') + + # DEBUG选择HOOK信息类型 + def debug_switch(self, ): + qs = { + "id": self.Ss.get_id(), + "type": self.DEBUG_SWITCH, + "content": "off", + "wxid": "ROOT", + } + return json.dumps(qs) + + # 处理缺口 + def handle_nick(self, j): + data = j.content + i = 0 + for d in data: + output(f"nickname:{d.nickname}") + i += 1 + + # 处理所有Roomid + def hanle_memberlist(self, j): + data = j.content + i = 0 + for d in data: + output(f"roomid:{d.roomid}") + i += 1 + + # 销毁全部接口 + def destroy_all(self, ): + qs = { + "id": self.Ss.get_id(), + "type": self.DESTROY_ALL, + "content": "none", + "wxid": "node", + } + return json.dumps(qs) + + # 处理带引用的文字消息 + def handleMsg_cite(self, msgJson): + msgXml = ( + msgJson["content"]["content"] + .replace("&", "&") + .replace("<", "<") + .replace(">", ">") + ) + soup = BeautifulSoup(msgXml, "xml") + msgJson = { + "content": soup.select_one("title").text, + "id": msgJson["id"], + "id1": msgJson["content"]["id2"], + "id2": "wxid_fys2fico9put22", + "id3": "", + "srvid": msgJson["srvid"], + "time": msgJson["time"], + "type": msgJson["type"], + "wxid": msgJson["content"]["id1"], + } + self.handle_recv_msg(msgJson) + + # 选择消息类型 + def on_message(self, ws, message): + j = json.loads(message) + resp_type = j["type"] + # switch结构 + action = { + self.CHATROOM_MEMBER_NICK: self.handle_nick, + self.PERSONAL_DETAIL: self.handle_recv_msg, + self.AT_MSG: self.handle_recv_msg, + self.DEBUG_SWITCH: self.handle_recv_msg, + self.PERSONAL_INFO: self.handle_recv_msg, + self.TXT_MSG: self.handle_recv_msg, + self.PIC_MSG: self.handle_recv_msg, + self.CHATROOM_MEMBER: self.hanle_memberlist, + self.RECV_PIC_MSG: self.handle_recv_msg, + self.RECV_TXT_MSG: self.handle_recv_msg, + self.RECV_TXT_CITE_MSG: self.handleMsg_cite, + self.HEART_BEAT: self.heartbeat, + self.USER_LIST: self.handle_wxuser_list, + self.GET_USER_LIST_SUCCSESS: self.handle_wxuser_list, + self.GET_USER_LIST_FAIL: self.handle_wxuser_list, + self.JOIN_ROOM: self.welcome_join, + } + action.get(resp_type, print)(j) + + # 获取获取微信通讯录用户名字和wxid,好友列表 + def get_wx_user_list(self, ): + qs = { + "id": self.Ss.get_id(), + "type": self.USER_LIST, + "content": "user list", + "wxid": "null", + } + # Output(qs) + return json.dumps(qs) + + def get_personal_info(self, ): + # 获取本机器人的信息 + uri = "/api/get_personal_info" + data = { + "id": self.Ss.get_id(), + "type": self.PERSONAL_INFO, + "content": "op:personal info", + "wxid": "null", + } + respJson = self.Ss.send(uri, data) + wechatBotInfo = f""" + + NGCBot登录信息 + + 微信昵称:{json.loads(respJson["content"])['wx_name']} + 微信号:{json.loads(respJson["content"])['wx_code']} + 微信id:{json.loads(respJson["content"])['wx_id']} + 启动时间:{respJson['time']} + {'By: ' + self.system_copyright if self.system_copyright else ''} + """ + output(wechatBotInfo.strip()) + + # 入群欢迎函数 + def welcome_join(self, msgJson): + output(f"收到消息:{msgJson}") + if "邀请" in msgJson["content"]["content"]: + roomid = msgJson["content"]["id1"] + nickname = msgJson["content"]["content"].split('"')[-2] + msg = '\n欢迎新进群的小可爱[烟花]' + if roomid in self.Dus.show_white_room(): + self.ws.send(self.Ss.send_msg(msg=msg, roomid=roomid, wxid='null', + nickname=nickname)) + + # 消息接收函数 + def handle_recv_msg(self, msgJson): + if "wxid" not in msgJson and msgJson["status"] == "SUCCSESSED": + output(f"[*]:消息发送成功!") + return + output(f"收到消息:{msgJson}") + msg = "" + # 判断群聊消息还是私人消息 + if "@chatroom" in msgJson["wxid"]: + # 获取群ID + roomid = msgJson["wxid"] + # 获取发送人ID + senderid = msgJson["id1"] + else: + roomid = None + nickname = "null" + # 获取发送人ID + senderid = msgJson["wxid"] + + # 获取发送者的名字 + nickname = self.Ss.get_member_nick(roomid, senderid) + if roomid: + # 处理微信群消息 + self.Rmd.get_information(msgJson=msgJson, roomid=roomid, senderid=senderid, nickname=nickname, ws=self.ws) + else: + # 处理通讯录好友发送的消息 + self.Fmd.get_information(msgJson=msgJson, senderid=senderid, ws=self.ws) + + +if __name__ == '__main__': + Ms = MainServers() + Ms.Bot_start() diff --git a/BotServer/SendServer.py b/BotServer/SendServer.py new file mode 100644 index 0000000..33d6728 --- /dev/null +++ b/BotServer/SendServer.py @@ -0,0 +1,144 @@ +from Output.output import output +import requests +import time +import json +import yaml +import os + + +class SendServer: + + def __init__(self): + # 初始化读取配置文件 + current_path = os.path.dirname(__file__) + config = yaml.load(open(current_path + '/../config/config.yaml', encoding='UTF-8'), yaml.Loader) + self.ip = config['BotServer']['IP'] + self.port = config['BotServer']['PORT'] + + # 配置HOOK信息类型 + self.SERVER = f"ws://{self.ip}:{self.port}" + self.HEART_BEAT = 5005 + self.RECV_TXT_MSG = 1 + self.RECV_TXT_CITE_MSG = 49 + self.RECV_PIC_MSG = 3 + self.USER_LIST = 5000 + self.GET_USER_LIST_SUCCSESS = 5001 + self.GET_USER_LIST_FAIL = 5002 + self.TXT_MSG = 555 + self.PIC_MSG = 500 + self.AT_MSG = 550 + self.CHATROOM_MEMBER = 5010 + self.CHATROOM_MEMBER_NICK = 5020 + self.PERSONAL_INFO = 6500 + self.DEBUG_SWITCH = 6000 + self.PERSONAL_DETAIL = 6550 + self.DESTROY_ALL = 9999 + self.JOIN_ROOM = 10000 + self.ATTATCH_FILE = 5003 + + # 通用消息发送函数 + def send(self, uri, data): + base_data = { + "id": self.get_id(), + "type": "null", + "roomid": "null", + "wxid": "null", + "content": "null", + "nickname": "null", + "ext": "null", + } + base_data.update(data) + url = f'http://{self.ip}:{self.port}/{uri}' + res = requests.post(url, json={"para": base_data}, timeout=5) + return res.json() + + # 定义信息ID + def get_id(self): + return time.strftime("%Y-%m-%d %H:%M:%S") + + # 发送文本消息函数 + def send_msg(self, msg, wxid="null", roomid='null', nickname="null"): + if roomid != 'null': + msg_type = self.AT_MSG + else: + msg_type = self.TXT_MSG + qs = { + "id": self.get_id(), + "type": msg_type, + "roomid": roomid, + "wxid": wxid, + "content": msg, + "nickname": nickname, + "ext": "null", + } + output(f"[*]:发送消息: {qs}") + return json.dumps(qs) + + # 通用文件发送函数 + def send_file_room(self, file, roomid): + output("[+]:文件发送中... ...") + data = { + "id": self.get_id(), + "type": self.ATTATCH_FILE, + "roomid": "null", + "content": file, + "wxid": roomid, + "nickname": "null", + "ext": "null", + } + url = f"http://{self.ip}:{self.port}/api/sendattatch" + res = requests.post(url, json={"para": data}, timeout=5) + if res.status_code == 200 and res.json()["status"] == "SUCCSESSED": + output("[*]:文件发送成功") + else: + output(f"[ERROR]:出现错误,错误信息:{res.text}") + + # 图片发送函数 + def send_img_room(self, msg, roomid): + output("[+]:图片发送中... ...") + data = { + "id": self.get_id(), + "type": self.PIC_MSG, + "roomid": "null", + "content": msg, + "wxid": roomid, + "nickname": "null", + "ext": "null", + } + url = f"http://{self.ip}:{self.port}/api/sendpic" + res = requests.post(url, json={"para": data}, timeout=5) + if res.status_code == 200 and res.json()["status"] == "SUCCSESSED": + output("[*]:图片发送成功!") + else: + output(f"[ERROR]:出现错误,错误信息:{res.text}") + + # 获取所有群的wxid + def get_memberid(self, ): + uri = 'api/getmemberid' + data = { + 'type': self.CHATROOM_MEMBER, + 'content': 'op:list member' + } + output(self.send(uri, data)) + + # 获取@昵称 或 微信好友的昵称 + def get_member_nick(self, roomid, wxid): + uri = "api/getmembernick" + data = {"type": self.CHATROOM_MEMBER_NICK, "wxid": wxid, "roomid": roomid or "null"} + respJson = self.send(uri, data) + return json.loads(respJson["content"])["nick"] + + # 获取机器人微信ID和微信名字 + def get_bot_info(self, ): + uri = "/api/get_personal_info" + data = { + "id": self.get_id(), + "type": self.PERSONAL_INFO, + "content": "op:personal info", + "wxid": "null", + } + respJson = self.send(uri, data) + bot_wxid = json.loads(respJson["content"])['wx_id'] + return bot_wxid + + diff --git a/Cache/Cache_Server.py b/Cache/Cache_Server.py new file mode 100644 index 0000000..8753a72 --- /dev/null +++ b/Cache/Cache_Server.py @@ -0,0 +1,54 @@ +from Output.output import output +import os + + +class Cache_Server: + + def __init__(self): + # 配置缓存文件存放路径 + current_path = os.path.dirname(__file__) + self.video_cache = current_path + '/Video_Cache' + self.fish_cache = current_path + '/Fish_Cache' + self.pic_cache = current_path + '/Pic_Cache' + self.create_folder() + + def delete_file(self): + output('[+]:缓存清除功能工作中... ...') + if os.path.exists(self.video_cache): + try: + file_lists = list() + file_lists += [self.video_cache + '/' + file for file in os.listdir(self.video_cache)] + file_lists += [self.fish_cache + '/' + file for file in os.listdir(self.fish_cache)] + file_lists += [self.pic_cache + '/' + file for file in os.listdir(self.pic_cache)] + for rm_file in file_lists: + os.remove(rm_file) + except Exception as e: + msg = "[ERROR]:清除缓存时出错,错误信息:{}".format(e) + output(msg) + return msg + msg = "缓存文件已清除!" + return msg + else: + msg = "[-]:缓存文件夹未创建,正在创建缓存文件夹... ..." + output(msg) + self.create_folder() + + def create_folder(self): + if not os.path.exists(self.video_cache): + try: + os.mkdir(self.video_cache) + os.mkdir(self.pic_cache) + os.mkdir(self.fish_cache) + except Exception as e: + msg = '[ERROR]:创建文件夹出错,错误信息:{}'.format(e) + output(msg) + else: + msg = '[+]:缓存文件夹已创建!' + output(msg) + + +if __name__ == '__main__': + Fs = Cache_Server() + # # Fs.create_folder() + Fs.delete_file() + diff --git a/Config/config.yaml b/Config/config.yaml new file mode 100644 index 0000000..a944f61 --- /dev/null +++ b/Config/config.yaml @@ -0,0 +1,195 @@ +## 机器人服务配置 +BotServer: + IP: 127.0.0.1 + PORT: 5555 + +## 超级管理员配置 +Administrators: + - '' + +## 关键词配置 +Key_Word: + # 触发美女图片关键词 + Pic_Word: + - '图片' + - '美女图片' + # 触发美女视频关键词 + Video_Word: + - '视频' + - '美女视频' + # 触发备案查询关键词 + Icp_Word: + - '备案查询' + - 'ICP查询' + - 'icp查询' + # 触发后缀名查询关键词 + Suffix_Word: + - '后缀名查询' + - '后缀查询' + # 触发归属查询关键词 + Attribution_Word: + - '归属查询' + - '归属地查询' + # 触发WHOIS查询关键词 + Whois_Word: + - 'whois查询' + - 'WHOIS查询' + # 触发摸鱼日记关键词 + Fish_Word: + - '摸鱼日记' + - '摸鱼日历' + # 触发天气查询关键词 + Weather_Word: + - '天气查询' + - '查询天气' + # 触发舔狗日记关键词 + Dog_Word: + - '舔狗日记' + - '舔我' + # 触发星座查询关键词 + Constellation_Word: + - '星座查询' + - '查询星座' + - '运势查询' + - '查询运势' + # 触发早安寄语关键词 + Morning_Word: + - '早安' + # 触发微步IP查询关键词 + ThreatBook_Word: + - 'ip查询' + - 'IP查询' + - '查询ip' + - '查询IP' + - '微步查询' + # 新增管理员关键词 + Add_Admin_Word: + - '添加管理员' + - '添加管理' + - '新增管理员' + # 删除管理员关键词 + Del_Admin_Word: + - '删除管理员' + - '删除管理' + - '移除管理员' + # 新增黑名单群聊关键词 + Add_BlackRoom_Word: + - '拉黑群聊' + - '添加黑名单' + # 移出黑名单群聊关键词 + Del_BlackRoom_Word: + - '解除拉黑' + - '移出黑名单' + # 查看白名单群聊关键词 + Show_WhiteRoom_Word: + - '查看群聊' + - '查看推送群聊' + # 新增白名单群聊关键词 + Add_WhiteRoom_Word: + - '拉白' + - '添加白名单' + - '开启推送服务' + - '开启推送功能' + # 移出白名单群聊关键词 + Del_WhiteRoom_Word: + - '关闭推送服务' + - '关闭推送功能' + - '移出白名单' + # 触发早报关键词 + Morning_Page: + - '早报' + - '早间咨询' + # 触发晚报关键词 + Evening_Page: + - '晚报' + - '晚间咨询' + +## API接口服务配置 +Api_Server: + Api_Config: + Appid: '45279436' + Appsecret: 'lohAjD4R' + Key: '' + ThreatBook_Key: '' + # 扩展名查询API + Extensions_Api: 'https://apis.tianapi.com/targa/index?key={}&word={}' + # 天气查询API + Wether_Api: 'https://www.tianqiapi.com/free/day?appid={}&appsecret={}&city={}' + # 舔狗日记API + Dog_Api: 'http://api.tianapi.com/tiangou/index?key={}' + # 星座查询API + Constellation_Api: 'http://api.tianapi.com/star/index?key={}&astro={}' + # 早安寄语API + Morning_Api: 'https://apis.tianapi.com/zaoan/index?key={}' + # 微步查询API + ThreatBook_Api: 'https://api.threatbook.cn/v3/scene/ip_reputation' + + # 摸鱼日记API + Fish_Api: 'https://api.vvhan.com/api/moyu' + # Whois查询API + Whois_Api: 'https://v.api.aa1.cn/api/whois/index.php?domain={}' + # 归属地查询API + Attribution_Api: 'https://v.api.aa1.cn/api/phone/guishu-api.php?phone={}' + # 备案查询API配置 + Icp_Api: 'https://v.api.aa1.cn/api/icp/index.php?url={}' + # 图片API配置 + Pic_Api: + - 'https://api.vvhan.com/api/girl' + - 'https://v.api.aa1.cn/api/pc-girl_bz/index.php?wpon=ro38d57y8rhuwur3788y3rd' + - 'https://api.vvhan.com/api/mobil.girl' + # 视频API配置 + Video_Api: + - 'https://tucdn.wpon.cn/api-girl/' + - 'https://v.api.aa1.cn/api/api-dy-girl/index.php?aa1=json' + - 'https://v.api.aa1.cn/api/api-girl-11-02/index.php?type=json' + - 'https://zj.v.api.aa1.cn/api/video_dyv2/' + +## 积分功能配置 +Point_Function: + # 签到口令 + Sign_Keyword: '签到:NGC660安全实验室祝大家天天得0day!' + # 签到积分配置 + Sign_Point: 10 + # 积分功能配置 + Function: + ThreatBook_Point: 8 + # 增加积分关键词 + Add_Point_Word: + - '加' + - '+' + # 扣除积分关键词 + Del_Point_Word: + - '减' + - '-' + # 赠送积分关键词 + Give_Point_Word: + - '送' + # 查看积分关键词 + Query_Point: + - '查看积分' + - '积分查询' + +## 定时推送配置 +Timed_Push: + # 早报推送时间 + Morning_Page_Time: '08:00' + # 晚报推送时间 + Evening_Page_Time: '17:00' + # 摸鱼日记推送时间 + Fish_Time: '10:00' + # 下班消息推送时间 + Off_Work_Time: '18:00' + +## 系统相关配置 +System_Config: + # 缓存清除关键词配置 + Cache_Config_Word: + - '清除缓存' + - '清空缓存' + # 版权信息配置 + System_Copyright: 'NGC660安全实验室' + # 帮助菜单关键词配置 + Help_Menu: + - '帮助菜单' + - 'help' + - 'HELP' \ No newline at end of file diff --git a/Db_Server/Db_Point_Server.py b/Db_Server/Db_Point_Server.py new file mode 100644 index 0000000..aa8a4bc --- /dev/null +++ b/Db_Server/Db_Point_Server.py @@ -0,0 +1,172 @@ +from Output.output import output +import sqlite3 +import yaml +import os + + +class Db_Point_Server: + def __init__(self): + current_path = os.path.dirname(__file__) + # 数据库存放地址 + self.db_file = current_path + '/../Config/Point_db.db' + self.judge_init() + config = yaml.load(open(current_path + '/../Config/config.yaml', encoding='UTF-8'), yaml.Loader) + + # 读取积分配置 + self.sign_point = config['Point_Function']['Sign_Point'] + + # 打开数据库 + def open_db(self): + conn = sqlite3.connect(database=self.db_file, ) + cursor = conn.cursor() + return conn, cursor + + # 关闭数据库 + def close_db(self, conn, cursor): + cursor.close() + conn.close() + + # 判断数据库是否初始化 + def judge_init(self, ): + conn, cursor = self.open_db() + judge_table_sql = '''SELECT name FROM sqlite_master;''' + cursor.execute(judge_table_sql) + data = cursor.fetchall() + if not data: + msg = '[+]:检测到积分数据库未初始化,正在初始化数据库' + self.init_db() + output(msg) + self.close_db(conn, cursor) + + + # 初始化数据库 + def init_db(self): + conn, cursor = self.open_db() + create_point_table_sql = '''CREATE TABLE IF NOT EXISTS points + (wx_id varchar(255), + wx_name varchar(255), + point int(20));''' + create_sign_table_sql = '''CREATE TABLE IF NOT EXISTS sign (wx_id varchar(255), wx_name varchar(255));''' + cursor.execute(create_point_table_sql) + cursor.execute(create_sign_table_sql) + self.close_db(conn, cursor) + output('[*]:积分服务初始化成功!') + + # 初始化新用户 + def init_user(self, wx_id, wx_name): + conn, cursor = self.open_db() + add_user_sql = f'''INSERT INTO points VALUES ('{wx_id}', '{wx_name}', 0);''' + cursor.execute(add_user_sql) + conn.commit() + self.close_db(conn, cursor) + + # 判断用户是否存在 + def judge_user(self, wx_id, sign_bool=False): + conn, cursor = self.open_db() + judge_user_sql = f'''SELECT wx_id FROM points WHERE wx_id='{wx_id}';''' + if sign_bool: + judge_user_sql = f'''SELECT wx_id FROM sign WHERE wx_id='{wx_id}';''' + cursor.execute(judge_user_sql) + data = cursor.fetchall() + if data: + return True + else: + return False + + # 增加积分 + def add_point(self, wx_id, point): + conn, cursor = self.open_db() + add_point_sql = f'''UPDATE points SET point=point+{point} WHERE wx_id='{wx_id}';''' + cursor.execute(add_point_sql) + conn.commit() + self.close_db(conn, cursor) + msg = f'\n基于你的优越表现,+{point}分\n当前未使用积分:{self.query_point(wx_id=wx_id, )}分' + return msg + + # 扣除积分 + def del_point(self, wx_id, point): + conn, cursor = self.open_db() + add_point_sql = f'''UPDATE points SET point=point-{point} WHERE wx_id='{wx_id}';''' + cursor.execute(add_point_sql) + conn.commit() + self.close_db(conn, cursor) + msg = f'\n介于你的近期表现,-{point}分\n当前未使用积分:{self.query_point(wx_id=wx_id, )}分' + return msg + + # 查询积分 + def query_point(self, wx_id, wx_name=None): + conn, cursor = self.open_db() + query_point_sql = f'''SELECT point,wx_id FROM points WHERE wx_id='{wx_id}';''' + cursor.execute(query_point_sql) + if not cursor.fetchone(): + self.init_user(wx_id=wx_id, wx_name=wx_name) + cursor.execute(query_point_sql) + data = cursor.fetchone() + return data[0] + + # 签到功能 + def sign(self, wx_id, wx_name): + conn, cursor = self.open_db() + sign_sql = f'''INSERT INTO sign VALUES ('{wx_id}', '{wx_name}');''' + self.add_point(wx_id=wx_id, point=self.sign_point) + cursor.execute(sign_sql) + conn.commit() + self.close_db(conn, cursor) + msg = f'签到成功 + {self.sign_point} 分\n当前可用积分:{self.query_point(wx_id=wx_id)}' + return msg + + # 清空签到表 + def clear_sign(self): + conn, cursor = self.open_db() + clear_sign_sql = 'DELETE FROM sign' + cursor.execute(clear_sign_sql) + conn.commit() + self.close_db(conn, cursor) + + # 积分赠送 + def give_point(self, wx_id, wx_name, at_wx_id, at_wx_name, point): + if self.query_point(wx_id=wx_id) >= self.query_point(wx_id=at_wx_id): + # 赠送人扣除积分 + self.judge_main(wx_id=wx_id, wx_name=wx_name, point=point, del_bool=True) + # 被赠送人增加积分 + self.judge_main(wx_id=at_wx_id, wx_name=at_wx_name, point=point, add_bool=True) + msg = f'\n您已给予 {at_wx_name} {point}分 \n当前可用积分 {self.query_point(wx_id=wx_id)}分' + else: + msg = f'\n您当前的余额不足\n当前可用积分:{self.query_point(wx_id=wx_id)} 分' + give_bool = True + return msg, give_bool + + # 主判断 + def judge_main(self, wx_id, wx_name, point=None, add_bool=False, del_bool=False, sign_bool=False): + msg = '' + if sign_bool: + if not self.judge_user(wx_id=wx_id, sign_bool=True): + if self.judge_user(wx_id=wx_id, ): + msg = self.sign(wx_id=wx_id, wx_name=wx_name, ) + else: + output('[+]:当前用户不存在,正在初始化该用户... ...') + self.init_user(wx_id=wx_id, wx_name=wx_name) + msg = self.sign(wx_id=wx_id, wx_name=wx_name) + elif add_bool: + if self.judge_user(wx_id=wx_id): + msg = self.add_point(wx_id=wx_id, point=point) + else: + output('[+]:当前用户不存在,正在初始化该用户... ...') + self.init_user(wx_id=wx_id, wx_name=wx_name) + msg = self.add_point(wx_id=wx_id, point=point) + elif del_bool: + if self.judge_user(wx_id=wx_id): + msg = self.del_point(wx_id=wx_id, point=point) + else: + output('[+]:当前用户不存在,正在初始化该用户... ...') + self.init_user(wx_id=wx_id, wx_name=wx_name) + msg = self.del_point(wx_id=wx_id, point=point) + return msg + + +if __name__ == '__main__': + Dps = Db_Point_Server() + # Dps.init_db() + msg = Dps.judge_main(wx_id='123123123', wx_name='123', sign_bool=True, point=230) + print(msg) + # Dps.query_point(wx_id='123') diff --git a/Db_Server/Db_User_Server.py b/Db_Server/Db_User_Server.py new file mode 100644 index 0000000..cf24126 --- /dev/null +++ b/Db_Server/Db_User_Server.py @@ -0,0 +1,222 @@ +from Output.output import output +import sqlite3 +import os + + +class Db_User_Server: + def __init__(self): + current_path = os.path.dirname(__file__) + # 数据库存放地址 + self.db_file = current_path + '/../Config/User_db.db' + self.judge_init() + + # 打开数据库 + def open_db(self): + conn = sqlite3.connect(database=self.db_file, ) + cursor = conn.cursor() + return conn, cursor + + # 关闭数据库 + def close_db(self, conn, cursor): + cursor.close() + conn.close() + + # 判断是否初始化 + def judge_init(self, ): + conn, cursor = self.open_db() + judge_table_sql = '''SELECT name FROM sqlite_master;''' + cursor.execute(judge_table_sql) + data = cursor.fetchall() + if not data: + msg = '[-]:检测到用户数据库未初始化,正在初始化数据库' + output(msg) + self.init_db() + self.close_db(conn, cursor) + + # 初始化数据库 + def init_db(self): + conn, cursor = self.open_db() + create_admin_table_sql = '''CREATE TABLE IF NOT EXISTS admins + (wx_id varchar(255), + wx_name varchar(255), + wx_roomid varchar(255), + wx_room_name varchar(255));''' + create_white_rooms = '''CREATE TABLE IF NOT EXISTS white_rooms + (wx_roomid varchar(255), + wx_room_name varchar(255));''' + create_black_rooms = '''CREATE TABLE IF NOT EXISTS black_rooms + (wx_roomid varchar(255), + wx_room_name varchar(255));''' + create_users_table = '''CREATE TABLE IF NOT EXISTS users + (wx_id varchar(255), + wx_name varchar(255));''' + + cursor.execute(create_admin_table_sql) + cursor.execute(create_white_rooms) + cursor.execute(create_black_rooms) + cursor.execute(create_users_table) + self.close_db(conn=conn, cursor=cursor) + output('[*]:用户数据库服务初始化成功!') + + # 查看用户WXID + def show_userid(self, wx_name): + data = self.judge_data(wx_name=wx_name, user_bool=True) + return data[0][0] + + # 添加用户数据(wx_name,wx_id) + def add_user(self, wx_id, wx_name): + if not self.judge_data(wx_name=wx_name, user_bool=True): + conn, cursor = self.open_db() + add_user_sql = f'''INSERT INTO users VALUES ("{wx_id}", "{wx_name}");''' + cursor.execute(add_user_sql) + conn.commit() + self.close_db(conn, cursor) + output(f'[+]:添加用户 {wx_name} 成功!') + + # 添加管理员 + def add_admin(self, wx_id, wx_roomid, wx_name, wx_room_name): + if not self.judge_data(wx_id=wx_id, wx_roomid=wx_roomid): + conn, cursor = self.open_db() + add_admin_sql = f'''INSERT INTO admins VALUES ( + '{wx_id}', '{wx_name}', '{wx_roomid}', '{wx_room_name}');''' + cursor.execute(add_admin_sql) + conn.commit() + self.close_db(conn=conn, cursor=cursor) + msg = f'添加管理员 {wx_name} 成功!' + else: + msg = f'管理员 {wx_name} 已存在!' + return msg + + # 删除管理员 + def del_admin(self, wx_id, wx_name, wx_roomid): + if self.judge_data(wx_id=wx_id, wx_roomid=wx_roomid): + conn, cursor = self.open_db() + del_admin_sql = f'''DELETE FROM admins WHERE wx_id='{wx_id}' and wx_roomid='{wx_roomid}';''' + cursor.execute(del_admin_sql) + conn.commit() + self.close_db(conn, cursor) + msg = f'移除管理员 {wx_name} 成功!' + else: + msg = f'管理员 {wx_name} 已移出!' + return msg + + # 查看所有管理员 + def show_admin(self): + conn, cursor = self.open_db() + show_admin_sql = '''SELECT wx_id, wx_roomid FROM admins;''' + cursor.execute(show_admin_sql) + data = cursor.fetchall() + self.close_db(conn, cursor) + msg = [] + for d in data: + msg.append({'wx_id': d[0], 'wx_roomid': d[1]}) + return msg + + # 添加黑名单群聊 + def add_black_room(self, wx_roomid, wx_room_name): + if not self.judge_data(black_bool=True, wx_roomid=wx_roomid): + conn, cursor = self.open_db() + add_black_room_sql = f'''INSERT INTO black_rooms VALUES ('{wx_roomid}', '{wx_room_name}');''' + cursor.execute(add_black_room_sql) + conn.commit() + self.close_db(conn, cursor) + msg = f'{wx_room_name} 群聊已拉黑! ' + else: + msg = '当前群聊已添加至黑名单' + return msg + + # 删除黑名单群聊 + def del_black_room(self, wx_roomid, wx_room_name): + if self.judge_data(wx_roomid=wx_roomid, black_bool=True): + conn, cursor = self.open_db() + del_black_room_sql = f'''DELETE FROM black_rooms WHERE wx_roomid='{wx_roomid}';''' + cursor.execute(del_black_room_sql) + conn.commit() + self.close_db(conn, cursor) + msg = f'移除黑名单群聊 {wx_room_name} 成功!' + else: + msg = '该群聊未被拉黑!' + return msg + + # 查看黑名单群聊 + def show_black_room(self): + conn, cursor = self.open_db() + show_black_room_sql = '''SELECT wx_roomid FROM black_rooms;''' + cursor.execute(show_black_room_sql) + data = cursor.fetchall() + self.close_db(conn, cursor) + msg = list() + for d in data: + msg.append({'wx_roomid': d[0]}) + return msg + + # 添加白名单群聊 + def add_white_room(self, wx_roomid, wx_room_name): + if not self.judge_data(wx_roomid=wx_roomid, white_bool=True): + conn, cursor = self.open_db() + add_white_room_sql = f'''INSERT INTO white_rooms VALUES ('{wx_roomid}', '{wx_room_name}');''' + cursor.execute(add_white_room_sql) + conn.commit() + self.close_db(conn, cursor) + msg = f'{wx_room_name} 群聊已开启推送服务!' + else: + msg = '该群聊已开启推送服务!' + return msg + + # 删除白名单群聊 + def del_white_room(self, wx_roomid, wx_room_name): + if self.judge_data(wx_roomid=wx_roomid, white_bool=True): + conn, cursor = self.open_db() + del_white_room_sql = f'''DELETE FROM white_rooms WHERE wx_roomid='{wx_roomid}';''' + cursor.execute(del_white_room_sql) + conn.commit() + self.close_db(conn, cursor) + msg = f'{wx_room_name} 群聊已关闭推送服务!' + else: + msg = '该群聊未开启推送服务!' + return msg + + # 查看白名单群聊 + def show_white_room(self, ): + conn, cursor = self.open_db() + show_white_room_sql = '''SELECT wx_roomid, wx_room_name FROM white_rooms;''' + cursor.execute(show_white_room_sql) + data = cursor.fetchall() + self.close_db(conn, cursor) + white_room_id = [] + white_room_name = [] + for d in data: + white_room_id.append(d[0]) + white_room_name.append(d[1]) + return white_room_id, white_room_name + + # 判断黑白表中数据是否存在 True False + def judge_data(self, wx_id=None, wx_name=None, wx_roomid=None, black_bool=False, white_bool=False, user_bool=False): + conn, cursor = self.open_db() + sql = '' + if wx_id and not user_bool: + sql = f'''SELECT wx_id FROM admins WHERE wx_id='{wx_id}' and wx_roomid='{wx_roomid}';''' + elif black_bool: + sql = f'''SELECT wx_roomid FROM black_rooms where wx_roomid='{wx_roomid}';''' + elif user_bool: + sql = f'''SELECT wx_id FROM users where wx_name="{wx_name}"''' + elif white_bool: + sql = f'''SELECT wx_roomid FROM white_rooms where wx_roomid='{wx_roomid}';''' + if sql: + cursor.execute(sql) + data = cursor.fetchall() + if data: + return data + else: + return False + + +if __name__ == '__main__': + Dus = Db_User_Server() + # Dus.init_db() + # Dus.add_admin(wx_id='yunyun', wx_name='云云', wx_roomid='123123', wx_room_name='测试') + # Dus.del_admin(wx_id='yunyun', wx_name='云云', wx_roomid='123123') + # Dus.show_admin() + # Dus.show_white_room() + # Dus.add_user('123', '云山') + Dus.show_userid('云山') diff --git a/Output/output.py b/Output/output.py new file mode 100644 index 0000000..9f78634 --- /dev/null +++ b/Output/output.py @@ -0,0 +1,17 @@ +from termcolor import cprint +import time + + +def output(msg): + if "error" in msg or "ERROR" in msg: + color = "red" + elif '[*]' in msg: + color = "cyan" + elif '[+]' in msg: + color = 'yellow' + else: + color = "magenta" + time_now = time.strftime("%Y-%m-%d %X") + cprint(f"[{time_now}]:{msg}", color) + +output('') diff --git a/Push_Server/Push_Main_Server.py b/Push_Server/Push_Main_Server.py new file mode 100644 index 0000000..c036570 --- /dev/null +++ b/Push_Server/Push_Main_Server.py @@ -0,0 +1,96 @@ +from Api_Server.Api_Server_Main import Api_Server_Main +from Db_Server.Db_Point_Server import Db_Point_Server +from Db_Server.Db_User_Server import Db_User_Server +from BotServer.SendServer import SendServer +from Output.output import output +from chinese_calendar import is_workday +import datetime +import schedule +import yaml +import os + + +class Push_Main_Server: + def __init__(self, ws): + current_path = os.path.dirname(__file__) + config = yaml.load(open(current_path + '/../Config/config.yaml', encoding='UTF-8'), yaml.Loader) + self.db_file = current_path + '/../Config/Point_db.db' + + # 实例化用户类 + self.Dus = Db_User_Server() + + # 实例化积分类 + self.Dps = Db_Point_Server() + + # 实例化发送消息服务 + self.Ss = SendServer() + + # 实例化API类 + self.Asm = Api_Server_Main() + + # 实例化ws + self.ws = ws + + self.morning_page_time = config['Timed_Push']['Morning_Page_Time'] + self.evening_page_time = config['Timed_Push']['Evening_Page_Time'] + self.off_work_time = config['Timed_Push']['Off_Work_Time'] + self.fish_time = config['Timed_Push']['Fish_Time'] + + # 早报推送 + def push_morning_page(self, ): + if is_workday(datetime.date.today()): + output('[+]:定时早报推送') + roomid_list, room_name_list = self.Dus.show_white_room() + msg = self.Asm.get_freebuf_news() + for roomid in roomid_list: + self.ws.send(self.Ss.send_msg(msg=msg, wxid=roomid)) + + # 晚报推送 + def push_evening_page(self, ): + if is_workday(datetime.date.today()): + output('[+]:定时晚间新闻推送') + roomid_list, room_name_list = self.Dus.show_white_room() + msg = self.Asm.get_safety_news() + for roomid in roomid_list: + self.ws.send(self.Ss.send_msg(msg=msg, wxid=roomid)) + + # 摸鱼日历推送 + def push_fish(self, ): + if is_workday(datetime.date.today()): + output('[+]:定时摸鱼日记推送') + roomid_list, room_name_list = self.Dus.show_white_room() + msg = self.Asm.get_fish() + for roomid in roomid_list: + self.Ss.send_img_room(msg=msg, roomid=roomid) + + # 下班信息推送 + def off_work_msg_push(self, ): + if is_workday(datetime.date.today()): + output('[+]:下班消息推送') + roomid_list, room_name_list = self.Dus.show_white_room() + msg = '各部门请注意,下班时间已到!!!请使用你最快的速度火速离开,\n不要浪费电费,记得打卡发日报!\n[旺财]over' + for roomid in roomid_list: + self.Ss.send_img_room(msg=msg, roomid=roomid) + + # 签到表清空 + def push_clear_sign(self): + output('[+]:定时签到表清空') + self.Dps.clear_sign() + + def run(self): + schedule.every().day.at(self.morning_page_time).do(self.push_morning_page) + schedule.every().day.at(self.evening_page_time).do(self.push_evening_page) + schedule.every().day.at(self.off_work_time).do(self.off_work_msg_push) + schedule.every().day.at(self.fish_time).do(self.push_fish) + schedule.every().day.at('00:00').do(self.push_clear_sign) + # schedule.every(1).seconds.do(self.push_morning_page) + output('[*]:已开启定时推送服务!') + while True: + # output('[*]:已开启定时推送服务!') + schedule.run_pending() + + +if __name__ == '__main__': + Psm = Push_Main_Server('1') + # Psm.push_fish() + Psm.push_morning_page() diff --git a/README.MD b/README.MD new file mode 100644 index 0000000..d733639 --- /dev/null +++ b/README.MD @@ -0,0 +1,609 @@ + +NGCBot +
+ +![image-20221212162417977](./README.assets/image-20221212162417977.png) + ++一个基于✨HOOK机制的微信机器人,支持🌱安全新闻定时推送【FreeBuf,先知,安全客,奇安信攻防社区】,👯后缀名查询,⚡备案查询,⚡手机号归属地查询,⚡WHOIS信息查询,🎉星座查询,⚡天气查询,🌱摸鱼日历⚡微步威胁情报查询, +🐛美女视频,⚡美女图片,👯帮助菜单。📫 支持积分功能,😄自定义程度丰富,小白也可轻松上手! +
+ + +## 目录 + +- **1、[介绍](#1、介绍)** +- **2、[项目结构](#2、项目结构)** +- **3、[使用帮助](#3、使用帮助)** +- **4、[功能介绍](#4、功能介绍)** +- **5、[配置文件说明](#5、配置文件说明)** +- **6、[后续优化计划](#6、后续优化计划)** +- **7、[后续开发计划](#7、后续开发计划)** +- **8、[更新日志](#8、更新日志)** +- **9、[特别鸣谢](#9、特别鸣谢)** + +### 1、介绍 + + NGCBot是一个基于HOOK拦截机制的微信机器人,用户高强度自定义,支持多种功能,代码逻辑清晰,因为其HOOK机制,目前仅支持Windows版本。目前支持多种功能功能调用,其功能🌱安全新闻定时推送【FreeBuf,先知,安全客,奇安信攻防社区】,👯后缀名查询,⚡备案查询,⚡手机号归属地查询,⚡WHOIS信息查询,🎉星座查询,⚡天气查询,🌱摸鱼日历⚡微步威胁情报查询,🐛美女视频,⚡美女图片,👯帮助菜单。📫 支持积分功能,😄自定义程度丰富,小白也可轻松上手! + + + +### 2、项目结构 + +``` +│ main.py -- 启动主文件,启动此文件运行 +│ README.MD -- README.MD,一个介绍说明文档 +│ requirements.txt -- 该项目所需要的所有第三方库 +│ +├─Api_Server -- API模块文件夹 +│ Api_Server_Main.py -- API模块文件 +│ +├─BotServer -- Bot收发接收处理消息文件夹【重要!】 +│ MainServer.py -- Bot运行主服务文件 【重要!】 +│ SendServer.py -- Bot收发消息处理服务文件 【重要!】 +│ +├─Cache -- 缓存文件文件夹 +│ │ Cache_Server.py -- 缓存文件处理服务文件 +│ │ +│ ├─Fish_Cache -- 摸鱼日记缓存文件夹 +│ ├─Pic_Cache -- 图片缓存文件夹 +│ └─Video_Cache -- 视频缓存文件夹 +├─Config -- Bot配置文件夹 +│ config.yaml -- Bot配置文件 【重要!】 +│ +├─Db_Server -- 数据库相关文件夹 +│ Db_Point_Server.py -- 积分相关数据库操作文件 +│ Db_User_Server.py -- 用户管理数据库操作文件 +│ +├─Output -- 消息输出模块文件夹 +│ output.py -- 消息输出模块 +│ +├─Push_Server -- 定时推送模块文件夹 +│ Push_Main_Server.py -- 定时推送操作文件 +│ +├─README.assets -- 介绍说明文档贴图文件 +│ image-20221212162417977.png -- 没啥用 +│ 关注.gif -- 没啥用 +│ +└─Recv_Msg_Dispose -- 群与好友消息处理模块文件夹 + FriendMsg_dispose.py -- 好友消息处理文件 + RoomMsg_dispose.py -- 群消息处理文件 +``` + + + +### 3、使用帮助 + +#### 3.1、第一次使用请看此处 + +**注意:此Bot只能在Windowns系统上运行!!!无法在Linux上运行安装** + +首先请克隆代码到本地,使用命令如下 + +```shell +git clone https://github.com/ngc660sec/NGCBot.git +``` + +也可直接DownLoad + +![image-20230305191526567](./README.assets/image-20230305191526567.png) + +下载后解压放在本地,再下载DLL注入器以及安装相关版本微信 + +![image-20230305191835360](./README.assets/image-20230305191835360.png) + +![image-20230305191853177](./README.assets/image-20230305191853177.png) + +下载安装后请先打开微信,并且打开注入器进行注入 + +![image-20230305192022516](./README.assets/image-20230305192022516.png) + +**注意:选择适合自己微信版本的DLL** + +注入后,直接启动main文件即可,命令如下 + +```shell +python main.py +``` + +![image-20230305192150988](./README.assets/image-20230305192150988.png) + +**出现此处显示,恭喜你🎉,机器人启动成功!不过不要高兴,你还需要进行下一步操作** + +与机器人私聊发送一条消息并且在`Config`目录下找到`config.yaml` + +找到`id2`,这是你的微信ID号,请牢记! + +![image-20230305231120081](./README.assets/image-20230305231120081.png) + +打开配置文件,将你的微信ID,填入其中! + +![image-20230305231212883](./README.assets/image-20230305231212883.png) + +这一步是添加超级管理员,如果你想知道超级管理员有什么功能,请往下看文档。 + +那么问题来了,我想添加多个超级管理员怎么办?请按我下面的格式写 + +![image-20230305231323334](./README.assets/image-20230305231323334.png) + +**恭喜你配置好了超级管理员,你已经可以完美使用此Bot了!恭喜🎉** + +**如想要深度专研,请看下文!** + + + +#### 3.2、相关BUG说明 + +##### 3.2.1、Bot的微信号必须修改,否则会报错! + +##### 3.2.2、其它Bug请提交iessus,我有时间就会回复😄 + +##### 3.3.3、建议服务器2H4G8M,配置太低可能带不动,会卡死!! + + + +### 4、功能介绍 + +#### 4.1、娱乐功能 + +##### 4.1.1、AI对话功能介绍 + +AI目前对接的是ChatGpt API接口,其AI算法强大,使用方法请看下图 + +![image-20230305194540725](./README.assets/image-20230305194540725.png) + +**此功能可私聊使用!**使用方法请看下图 + +![image-20230305194645867](./README.assets/image-20230305194645867.png) + +##### 4.1.2、美女图片功能介绍 + +图片功能,可在群内发送😍涩图,使用方法请看下图 + +![image-20230305194812168](./README.assets/image-20230305194812168.png) + +##### 4.1.3、美女视频功能介绍 + +美女视频功能,可在群类发送优质视频,使用方法请看下图 + +![image-20230305195314814](./README.assets/image-20230305195314814.png) + +若机器人发送的是如下文件,不要慌,只是接口问题而已,此问题只会偶尔出现,不用担心! + +![image-20230305195409045](./README.assets/image-20230305195409045.png) + +##### 4.1.4、备案查询功能介绍 + +此功能能查询网站备案信息,轻松获取逼站的备案主体,让社工跟进一步!使用方法请看下图 + +![image-20230305195433874](./README.assets/image-20230305195433874.png) + +##### 4.1.5、后缀名查询功能介绍 + +此功能能够查询任意后缀名,让文件不再陌生!使用方法请看下图 + +![image-20230305195530398](./README.assets/image-20230305195530398.png) + +##### 4.1.6、手机号归属地查询功能介绍 + +此功能能够查询任意手机号归属地,让你跟女神更进一步!使用方法请看下图 + +![image-20230305195628326](./README.assets/image-20230305195628326.png) + +**注意:手机号是我编的,不要尝试社工我!** + +##### 4.1.7、WHOIS查询功能介绍 + +此功能能够查询任意域名WHOIS信息,让你跟麻花腾跟进一步!使用方法请看下图 + +![image-20230305195801227](./README.assets/image-20230305195801227.png) + +##### 4.1.8、摸鱼日历功能介绍 + +此功能能够推送摸鱼日历,让您一天轻松摸鱼,把控摸鱼时长,打倒资本家!让资本家无话可说!使用方法请看下图 + +![image-20230305195945397](./README.assets/image-20230305195945397.png) + +**注意:此功能已开启定时推送,在工作日可定时推送,默认推送时间为10:00,可在配置文件中修改。如要修改配置文件,请看[配置文件说明](#5、配置文件说明)** + +##### 3.1.10、天气查询功能介绍 + +平平无奇的天气查询,轻松在群类掌握你本地的天气,让你约会更轻松!使用方法请看下图 + +![image-20230305204137643](./README.assets/image-20230305204137643.png) + +##### 3.1.11、舔狗日记功能介绍 + +舔狗的日常是怎样的?如何当一个舔狗?怎么去当舔狗?此功能让你专心学做当舔狗,让舔狗不再稀缺!使用方法请看下图 + +![image-20230305204308526](./README.assets/image-20230305204308526.png) + +##### 3.1.12、星座查询功能介绍 + +想知道你的星座运势?想明白今天该不该做什么?要知道今天适合干什么?此功能让你轻松把控星座运势,人生大事!使用方法请看下图 + +![image-20230305204511873](./README.assets/image-20230305204511873.png) + +##### 3.1.13、早安寄语功能介绍 + +一个人太孤单?早起没人说早安?想要每天的早安问候?此功能满足你的欲望!使用方法请看下图 + +![image-20230305204619914](./README.assets/image-20230305204619914.png) + +#### 4.2、积分功能 + +##### 4.2.1、微步威胁IP情报查询功能 + +你叫王大锤,是一个公司的唯一一个混子蓝队成员,某天你单位的服务器被黑客攻击了,还好公司的大牛迅速响应,实现毫秒级IP封锁,此时大佬交给你一个任务。 + +大佬:”大锤,你看看这个IP,是个跳板机还是黑客用的VPS“ + +你:”好,我看看...“ + +此时的你心中忐忑不安,因为你只是一个混子蓝队,VPS是什么,跳板机又是个什么,有什么用,你怎么会知道。于是你只能在群里求助各方大佬,突然某群的一位群友引起了你的注意,内容如下 + +![image-20230305205946424](./README.assets/image-20230305205946424.png) + +你敏锐的注意到了其中一点 —> ""是否为恶意IP:是",此时你更加确定了这台不是跳板机!此时大佬又交给了你一个任务,让你看看另一个IP,于是你也参考群友的格式来发送,但是却出现了下面的结果 + +![image-20230305214235159](./README.assets/image-20230305214235159.png) + +没有积分!怎么办!百度有用吗!我会百度吗!怎么搞积分!联系群主!对!联系群主,于是你赶紧联系了群主,让群主给你加积分,但是 + +![image-20230305214357922](./README.assets/image-20230305214357922.png) + +群主说了一句非常恐怖的话! + +![image-20230305214449681](./README.assets/image-20230305214449681.png) + +于是你只能含泪给群主转了50,让群主给你加了50积分,害,都怪自己没技术,你这样责备自己。我以后一定要好好学习,多多努力。做一名NGC660安全实验室的正式成员! + +![image-20230305220141174](./README.assets/image-20230305220141174.png) + +拥有了积分于是你又开始快乐的给大佬提交情报,又开始了新一天的混子生活。。。 + +编不下去了,目前只有这一个积分功能,其它想要加的可以提交iessus,或者自己添加即可! + +##### 4.2.2、签到功能 + +作为一名合格的超管,总不能让群员V你50才给他积分吧,所以请看签到功能 + +![image-20230305223211110](./README.assets/image-20230305223211110.png) + +但是总不能一天签到多次吧,群友嫖我积分怎么办? + +**放心,本作者有练习时长两年半的开发经验,一天只能签到一次,每日00.00清空签到表,请诸位放心🙂** + +##### 4.2.3、积分查询功能 + +什么?你居然忘记了你有多少积分?这还能忍,直接让管理员给你清零好不好!还好我贴心,给你们安排了这个功能 + +![image-20230305224247670](./README.assets/image-20230305224247670.png) + +**注意:虽然管理员使用积分功能免费,但是管理和超管还是有积分的** + +##### 4.2.4、赠送积分功能 + +普通群友使用此功能,可赠送对方积分🙂,管理员就可以不用,直接增加积分即可 + +![image-20230306101314509](./README.assets/image-20230306101314509.png) + +#### 4.3、定时推送功能 + +**注意:定时推送功能只有管理员或者超管开启才能使用** + +##### 4.3.1、开启推送服务 + +作为一名合格的管理员,当然要学会如何去开启推送服务,下面我来教你 + +![image-20230305222312844](./README.assets/image-20230305222312844.png) + +##### 4.3.2、关闭推送服务 + +作为一名拥有高情商的管理员,当然要去学会如何关闭推送服务,下面我来教你 + +![image-20230305222435542](./README.assets/image-20230305222435542.png) + +**什么?!你居然忘记了这个群有没有开服务?你真不是一个合格的管理员,还好有我在🙂** + +##### 4.3.3、查看推送服务 + +![image-20230305222721764](./README.assets/image-20230305222721764.png) + +**你都知道有推送服务了,推送服务能推送啥你不会不知道把!不会吧不会吧!** + +##### 4.3.4、推送服务介绍 + +推送服务,可在**工作日**定时推送**早报,晚报,摸鱼日历,下班提醒**。仅仅如此,如果你想定时推送比较哇塞的涩图,其实也不是不可以🙂 + +#### 4.4、超级管理员功能 + +**首先需要知道在本bot中,一共有三个权限,每个权限的功能都是不一样的,接下来我会逐一讲解每个权限的独有的功能,至于那些普通的通用的功能,基本上群友能用,管理、超管、都能用** + +##### 4.4.1、添加管理员 + +想要管理群聊更加轻松?让小弟帮你管理,输入这条命令让你的小弟变成管理员! + +![image-20230305223648781](./README.assets/image-20230305223648781.png) + +##### 4.4.2、删除管理 + +什么?你的小弟叛变了?!看来他这管理员的特权是不想要了,让我们把小弟的管理权限给踢掉! + +![image-20230305223804540](./README.assets/image-20230305223804540.png) + +**不同地方的小弟,只能负责他们所对应的区域。说人话就是【每个群的管理是不通用的】** + +什么?!你不知道你小弟有没有管理权限?!那不好意思,本作者没有写查看管理的功能,不过当你再次添加的时候,会有如下变化 + +![image-20230305223951890](./README.assets/image-20230305223951890.png) + +##### 4.4.3、机器人消息转发 + +**前女友给Bot发消息要复合你不知道?没有关系,有了这个功能再也不怕前女友给Bot发的消息收不到了!** + +![image-20230306085542234](./README.assets/image-20230306085542234.png) + +**注意:如果发起会话的是超级管理员,那么消息将不会转发,转发消息的接收者为超级管理员** + +##### 4.4.4、消息转发给好友 + +什么?你没有加你前女友,那你前女友怎么会有你Bot的微信?没关系,我也是经历过的人,我都懂,所以我贴心的撰写了消息转发给好友的功能 + +![image-20230306090537764](./README.assets/image-20230306090537764.png) + +![image-20230306090547336](./README.assets/image-20230306090547336.png) + +你说你女朋友是个非主流,喜欢用杀马特文?那不好意思,可能你的消息转发不了给你女朋友了! + +**注意:在最新的测试中,有些颜表情当名字的也可以转发,不过请复制对方名字!** + +##### 4.4.5、清除缓存功能 + +当你的群友调用了很多图片或者视频或者摸鱼日历功能,就会产生许多缓存,此时可以输入此条命令,会将缓存清空 + +![image-20230306101820442](./README.assets/image-20230306101820442.png) + + + +#### 4.5、管理员功能 + +##### 4.5.1、管理员功能介绍 + +作为一名合格的小弟,一定要知道管理员到底有个啥用,这样才能更好的帮助老大去进行管理,管理好了,步步高升。管理不好,可能小命不保🙂 + +作为一个合格的管理员,你掌握的功能有这么一些: + + 1、早报推送【手动早报推送】 + + 2、晚报推送【手动晚报推送】 + + 3、开启推送服务 + + 4、关闭推送服务 + + 5、拉黑群聊 + + 6、解除拉黑 + + 7、用户积分操作 + +但是你知道这些有啥用吗,别担心,听我慢慢讲述,故事还长,洗耳恭听! + +##### 4.5.2、早报推送 + +**注意:早报可以定时推送,也可以手动推送!** + +平平无奇的功能,无非就是爬虫了,我没有要讲述的亮点,而且也编不下去了,直接上图! + +![image-20230305224907222](./README.assets/image-20230305224907222.png) + +今天看来没有文章啊,可惜可惜🙂 + +##### 4.5.3、晚报推送 + +其实一样的,不过你是不是好奇怎么触发的,在下面[配置文件说明](#配置文件说明)一章中我们会讲到 + +![image-20230305225059253](./README.assets/image-20230305225059253.png) + +看来晚报文章不少啊,爬取的一些社区相信你们也是知道的,我就不介绍了,手都敲麻了... + +##### 4.5.4、开启推送服务 + +我讲过,没看到请[自行跳转](#4.3、定时推送功能) + +##### 4.5.5、关闭推送服务 + +我也讲过,没看到也[自行跳转](#4.3.2、关闭推送服务)去 + +##### 4.5.6、拉黑群聊功能 + +遇到傻逼天天发送图片、视频,消耗你服务器资源?这种人最可恨了,玛德!所以我在这里提供了拉黑群聊功能,让此群聊不能使用**娱乐功能** + +![image-20230305225932950](./README.assets/image-20230305225932950.png) + +**注意:即使拉黑了群聊,管理员以及超管仍然能够使用娱乐功能!** + +##### 4.5.7 、解除拉黑功能 + +啊?群主把傻逼踢了?求你解除拉黑?因为他要V你50?OK!马上解除! + +![image-20230305230219618](./README.assets/image-20230305230219618.png) + +##### 4.5.8、用户积分操作 + +既然你是小弟了,肯定是会收点保护费的,既然收了,那不得给人家加积分啊,什么?你不知道加积分? + +![image-20230305230345964](./README.assets/image-20230305230345964.png) + +什么?他骂你大傻逼? + +![image-20230305230427577](./README.assets/image-20230305230427577.png) + +#### 4.6、普通群友功能 + +**作为一名遵纪守法的好公民,当然是要正常使用Bot的相关功能,所以普通群友没有什么奇奇怪怪的操作,你不会用的话,请回复help,超级Bot就会马上帮助你!** + +##### 4.6、帮助功能 + +![image-20230305230611246](./README.assets/image-20230305230611246.png) + +什么?看不懂功能怎么用?本作者自有办法! + +回复help+相应编号即可! + +![image-20230305230716625](./README.assets/image-20230305230716625.png) + +**注意:私聊无法获取帮助信息,必须在群内发送HELP!** + + + +### 5、配置文件说明 + +##### 5.1、机器人服务配置 + +![image-20230305231636005](./README.assets/image-20230305231636005.png) + +此处别乱来,改了就GG + +##### 5.2、超级管理员配置 + +![image-20230305231701746](./README.assets/image-20230305231701746.png) + +添加超级管理员的地方,如果不会,[从头](#1、介绍)开始看文档! + +##### 5.3、关键词配置 + +![image-20230305231820468](./README.assets/image-20230305231820468.png) + +这个比较多,都是相应功能触发的关键词,比如说美女图片,如果你再多添加一个关键词,就可以换个关键词触发!来试试 + +![image-20230305231930846](./README.assets/image-20230305231930846.png) + +**注意:修改配置文件后需要重启Bot** + +其它的类似,相信自己!一定能调教好此Bot! + +##### 5.4、API接口服务配置 + +此处只需要获取相应的KEY + +打开此[网址](https://www.tianapi.com/source/e81d05c8b1) + +注册登录后,获取你的appid、key、appsecret + +![image-20230306091138533](./README.assets/image-20230306091138533.png) + +你要用什么功能,就开通什么接口,不过目前只接入了配置文件中的接口,相关接口请查看配置文件此处**【注意,此处展示的天气查询接口是旧版接口,如果你想使用这个旧版接口,那就不需要开启天气预报接口服务,直接打开如下网址】** + +![image-20230306091344261](./README.assets/image-20230306091344261.png) + +开通这些接口即可 + +![image-20230306091443104](./README.assets/image-20230306091443104.png) + +在此处搜索接口名称开通 + +![image-20230306091506855](./README.assets/image-20230306091506855.png) + +开通后你会获得一些配置,在此处查看 + +![image-20230306091542863](./README.assets/image-20230306091542863.png) + +这是你的Key,复制,粘贴到配置文件中 + +![image-20230306091621220](./README.assets/image-20230306091621220.png) + +**Appid与Appsecret,这两个是用于旧版天气查询接口,因为这个接口是免费的,所以采用了此API接口,如果你不想用,请自行修改天气查询的相关调用代码,如果你仍用旧版天气查询接口,请看此处** + +打开此[网站](https://www.tianqiapi.com/) + +![image-20230306092504776](./README.assets/image-20230306092504776.png) + +在此处将两个相关参数放到配置文件中即可! + +**微步Key:**这玩意自己去申请,我相信你混子蓝队的水准是能够自己申请的,申请key之后放入配置文件中即可 + +![image-20230306092645321](./README.assets/image-20230306092645321.png) + +**图片API和视频API:**这两玩意别乱改,调用的话是随机调用的,不会出现一直调用同一个接口的情况 + +##### 5.5、积分功能配置 + +很简单的配置,一张图概述 + +![image-20230306093225214](./README.assets/image-20230306093225214.png) + +赠送积分说明请[点击此处](#4.2.4、赠送积分功能) + +##### 5.6、定时推送配置 + +![image-20230306101510700](./README.assets/image-20230306101510700.png) + +**注意:如果是在早上8点,请输入`08:00`!注意格式!** + +##### 5.7、系统相关配置 + +![image-20230306101556676](./README.assets/image-20230306101556676.png) + +版权信息处,为使用各个功能时结尾处的信息 + +![image-20230306101933687](./README.assets/image-20230306101933687.png) + +其它的就不介绍了 + + + +### 6、后续优化计划 + +```shell +1. 优化群消息处理【已优化】 +2. 优化相关配置信息【已优化】 +3. 优化积分模块【已优化,可@多人加积分】 +4. 优化好友消息处理【已优化】 +5. 优化总体架构 +6. 好友消息转发【已优化】 +``` + + + +### 7、后续开发计划 + +``` +- Github工具 + CVE 实时推送【连接不上外国站,已阉割】 +- MD5解密【暂时没钱】 +- 开发Web端管理系统 +- ... ... +``` + + + +### 8、更新日志 + +``` +- 【2022.12.8】 推送Bot 1.0版本,为初始版本 +- 【2022.12.17】推送Bot 1.2版本,新增部分接口,重写部分代码,新增积分功能 +- 【2023.1.1】 推送Bot 1.3版本,重写部分代码,优化代码逻辑,优化积分功能,优化定时推送功能 +- 【2023.3.6】 推送Bot 1.4版本,总体代码优化,优化定时推送,优化积分功能,新增消息转发,维护API服务调用 +``` + +#### 最后,若在使用过程中有任何问题,也提交Iessus,或者关注微信公众号,后台回复消息 + +![关注](./README.assets/关注.gif) + + + +### 9、特别鸣谢 + +- https://github.com/cixingguangming55555/wechat-bot + +- https://github.com/zhizhuoshuma/WechatBot +- https://github.com/tom-snow/wechat-windows-versions diff --git a/README.assets/image-20221212162417977.png b/README.assets/image-20221212162417977.png new file mode 100644 index 0000000..eef3614 Binary files /dev/null and b/README.assets/image-20221212162417977.png differ diff --git a/README.assets/image-20230305191526567.png b/README.assets/image-20230305191526567.png new file mode 100644 index 0000000..be178f9 Binary files /dev/null and b/README.assets/image-20230305191526567.png differ diff --git a/README.assets/image-20230305191835360.png b/README.assets/image-20230305191835360.png new file mode 100644 index 0000000..40b87e3 Binary files /dev/null and b/README.assets/image-20230305191835360.png differ diff --git a/README.assets/image-20230305191853177.png b/README.assets/image-20230305191853177.png new file mode 100644 index 0000000..740f57e Binary files /dev/null and b/README.assets/image-20230305191853177.png differ diff --git a/README.assets/image-20230305192022516.png b/README.assets/image-20230305192022516.png new file mode 100644 index 0000000..5e203d6 Binary files /dev/null and b/README.assets/image-20230305192022516.png differ diff --git a/README.assets/image-20230305192150988.png b/README.assets/image-20230305192150988.png new file mode 100644 index 0000000..d5575b6 Binary files /dev/null and b/README.assets/image-20230305192150988.png differ diff --git a/README.assets/image-20230305194540725.png b/README.assets/image-20230305194540725.png new file mode 100644 index 0000000..3ec8037 Binary files /dev/null and b/README.assets/image-20230305194540725.png differ diff --git a/README.assets/image-20230305194645867.png b/README.assets/image-20230305194645867.png new file mode 100644 index 0000000..e6fa690 Binary files /dev/null and b/README.assets/image-20230305194645867.png differ diff --git a/README.assets/image-20230305194812168.png b/README.assets/image-20230305194812168.png new file mode 100644 index 0000000..f498868 Binary files /dev/null and b/README.assets/image-20230305194812168.png differ diff --git a/README.assets/image-20230305195314814.png b/README.assets/image-20230305195314814.png new file mode 100644 index 0000000..e1a5492 Binary files /dev/null and b/README.assets/image-20230305195314814.png differ diff --git a/README.assets/image-20230305195409045.png b/README.assets/image-20230305195409045.png new file mode 100644 index 0000000..21a5245 Binary files /dev/null and b/README.assets/image-20230305195409045.png differ diff --git a/README.assets/image-20230305195433874.png b/README.assets/image-20230305195433874.png new file mode 100644 index 0000000..524ea4c Binary files /dev/null and b/README.assets/image-20230305195433874.png differ diff --git a/README.assets/image-20230305195530398.png b/README.assets/image-20230305195530398.png new file mode 100644 index 0000000..3ff6a40 Binary files /dev/null and b/README.assets/image-20230305195530398.png differ diff --git a/README.assets/image-20230305195628326.png b/README.assets/image-20230305195628326.png new file mode 100644 index 0000000..b938ef5 Binary files /dev/null and b/README.assets/image-20230305195628326.png differ diff --git a/README.assets/image-20230305195801227.png b/README.assets/image-20230305195801227.png new file mode 100644 index 0000000..0043af3 Binary files /dev/null and b/README.assets/image-20230305195801227.png differ diff --git a/README.assets/image-20230305195945397.png b/README.assets/image-20230305195945397.png new file mode 100644 index 0000000..1e21be8 Binary files /dev/null and b/README.assets/image-20230305195945397.png differ diff --git a/README.assets/image-20230305204137643.png b/README.assets/image-20230305204137643.png new file mode 100644 index 0000000..a3e2a01 Binary files /dev/null and b/README.assets/image-20230305204137643.png differ diff --git a/README.assets/image-20230305204308526.png b/README.assets/image-20230305204308526.png new file mode 100644 index 0000000..a425760 Binary files /dev/null and b/README.assets/image-20230305204308526.png differ diff --git a/README.assets/image-20230305204511873.png b/README.assets/image-20230305204511873.png new file mode 100644 index 0000000..2e4c34a Binary files /dev/null and b/README.assets/image-20230305204511873.png differ diff --git a/README.assets/image-20230305204619914.png b/README.assets/image-20230305204619914.png new file mode 100644 index 0000000..9abbbf9 Binary files /dev/null and b/README.assets/image-20230305204619914.png differ diff --git a/README.assets/image-20230305205946424.png b/README.assets/image-20230305205946424.png new file mode 100644 index 0000000..2ea2829 Binary files /dev/null and b/README.assets/image-20230305205946424.png differ diff --git a/README.assets/image-20230305214235159.png b/README.assets/image-20230305214235159.png new file mode 100644 index 0000000..291404d Binary files /dev/null and b/README.assets/image-20230305214235159.png differ diff --git a/README.assets/image-20230305214357922.png b/README.assets/image-20230305214357922.png new file mode 100644 index 0000000..023b5ab Binary files /dev/null and b/README.assets/image-20230305214357922.png differ diff --git a/README.assets/image-20230305214449681.png b/README.assets/image-20230305214449681.png new file mode 100644 index 0000000..ac112e7 Binary files /dev/null and b/README.assets/image-20230305214449681.png differ diff --git a/README.assets/image-20230305220141174.png b/README.assets/image-20230305220141174.png new file mode 100644 index 0000000..c18f287 Binary files /dev/null and b/README.assets/image-20230305220141174.png differ diff --git a/README.assets/image-20230305222312844.png b/README.assets/image-20230305222312844.png new file mode 100644 index 0000000..3cdad65 Binary files /dev/null and b/README.assets/image-20230305222312844.png differ diff --git a/README.assets/image-20230305222435542.png b/README.assets/image-20230305222435542.png new file mode 100644 index 0000000..654ee44 Binary files /dev/null and b/README.assets/image-20230305222435542.png differ diff --git a/README.assets/image-20230305222721764.png b/README.assets/image-20230305222721764.png new file mode 100644 index 0000000..b1bd270 Binary files /dev/null and b/README.assets/image-20230305222721764.png differ diff --git a/README.assets/image-20230305223211110.png b/README.assets/image-20230305223211110.png new file mode 100644 index 0000000..b661122 Binary files /dev/null and b/README.assets/image-20230305223211110.png differ diff --git a/README.assets/image-20230305223648781.png b/README.assets/image-20230305223648781.png new file mode 100644 index 0000000..f134e50 Binary files /dev/null and b/README.assets/image-20230305223648781.png differ diff --git a/README.assets/image-20230305223804540.png b/README.assets/image-20230305223804540.png new file mode 100644 index 0000000..5e630cf Binary files /dev/null and b/README.assets/image-20230305223804540.png differ diff --git a/README.assets/image-20230305223951890.png b/README.assets/image-20230305223951890.png new file mode 100644 index 0000000..23abde7 Binary files /dev/null and b/README.assets/image-20230305223951890.png differ diff --git a/README.assets/image-20230305224247670.png b/README.assets/image-20230305224247670.png new file mode 100644 index 0000000..4beb3dc Binary files /dev/null and b/README.assets/image-20230305224247670.png differ diff --git a/README.assets/image-20230305224907222.png b/README.assets/image-20230305224907222.png new file mode 100644 index 0000000..a60a836 Binary files /dev/null and b/README.assets/image-20230305224907222.png differ diff --git a/README.assets/image-20230305225059253.png b/README.assets/image-20230305225059253.png new file mode 100644 index 0000000..d726cae Binary files /dev/null and b/README.assets/image-20230305225059253.png differ diff --git a/README.assets/image-20230305225932950.png b/README.assets/image-20230305225932950.png new file mode 100644 index 0000000..715fc85 Binary files /dev/null and b/README.assets/image-20230305225932950.png differ diff --git a/README.assets/image-20230305230219618.png b/README.assets/image-20230305230219618.png new file mode 100644 index 0000000..058c7b6 Binary files /dev/null and b/README.assets/image-20230305230219618.png differ diff --git a/README.assets/image-20230305230345964.png b/README.assets/image-20230305230345964.png new file mode 100644 index 0000000..df8dabd Binary files /dev/null and b/README.assets/image-20230305230345964.png differ diff --git a/README.assets/image-20230305230427577.png b/README.assets/image-20230305230427577.png new file mode 100644 index 0000000..e4a681e Binary files /dev/null and b/README.assets/image-20230305230427577.png differ diff --git a/README.assets/image-20230305230611246.png b/README.assets/image-20230305230611246.png new file mode 100644 index 0000000..3ff4fc9 Binary files /dev/null and b/README.assets/image-20230305230611246.png differ diff --git a/README.assets/image-20230305230716625.png b/README.assets/image-20230305230716625.png new file mode 100644 index 0000000..c62d1db Binary files /dev/null and b/README.assets/image-20230305230716625.png differ diff --git a/README.assets/image-20230305231120081.png b/README.assets/image-20230305231120081.png new file mode 100644 index 0000000..b10f874 Binary files /dev/null and b/README.assets/image-20230305231120081.png differ diff --git a/README.assets/image-20230305231212883.png b/README.assets/image-20230305231212883.png new file mode 100644 index 0000000..aa94ca1 Binary files /dev/null and b/README.assets/image-20230305231212883.png differ diff --git a/README.assets/image-20230305231323334.png b/README.assets/image-20230305231323334.png new file mode 100644 index 0000000..867fb9f Binary files /dev/null and b/README.assets/image-20230305231323334.png differ diff --git a/README.assets/image-20230305231636005.png b/README.assets/image-20230305231636005.png new file mode 100644 index 0000000..db65ebe Binary files /dev/null and b/README.assets/image-20230305231636005.png differ diff --git a/README.assets/image-20230305231701746.png b/README.assets/image-20230305231701746.png new file mode 100644 index 0000000..368b038 Binary files /dev/null and b/README.assets/image-20230305231701746.png differ diff --git a/README.assets/image-20230305231820468.png b/README.assets/image-20230305231820468.png new file mode 100644 index 0000000..efda003 Binary files /dev/null and b/README.assets/image-20230305231820468.png differ diff --git a/README.assets/image-20230305231930846.png b/README.assets/image-20230305231930846.png new file mode 100644 index 0000000..b7d40a2 Binary files /dev/null and b/README.assets/image-20230305231930846.png differ diff --git a/README.assets/image-20230306085542234.png b/README.assets/image-20230306085542234.png new file mode 100644 index 0000000..ed582c7 Binary files /dev/null and b/README.assets/image-20230306085542234.png differ diff --git a/README.assets/image-20230306090537764.png b/README.assets/image-20230306090537764.png new file mode 100644 index 0000000..5267f76 Binary files /dev/null and b/README.assets/image-20230306090537764.png differ diff --git a/README.assets/image-20230306090547336.png b/README.assets/image-20230306090547336.png new file mode 100644 index 0000000..8a284a1 Binary files /dev/null and b/README.assets/image-20230306090547336.png differ diff --git a/README.assets/image-20230306091138533.png b/README.assets/image-20230306091138533.png new file mode 100644 index 0000000..4b72d1a Binary files /dev/null and b/README.assets/image-20230306091138533.png differ diff --git a/README.assets/image-20230306091344261.png b/README.assets/image-20230306091344261.png new file mode 100644 index 0000000..c94a74c Binary files /dev/null and b/README.assets/image-20230306091344261.png differ diff --git a/README.assets/image-20230306091443104.png b/README.assets/image-20230306091443104.png new file mode 100644 index 0000000..c0ec761 Binary files /dev/null and b/README.assets/image-20230306091443104.png differ diff --git a/README.assets/image-20230306091506855.png b/README.assets/image-20230306091506855.png new file mode 100644 index 0000000..8858784 Binary files /dev/null and b/README.assets/image-20230306091506855.png differ diff --git a/README.assets/image-20230306091542863.png b/README.assets/image-20230306091542863.png new file mode 100644 index 0000000..4c629a4 Binary files /dev/null and b/README.assets/image-20230306091542863.png differ diff --git a/README.assets/image-20230306091621220.png b/README.assets/image-20230306091621220.png new file mode 100644 index 0000000..5838a63 Binary files /dev/null and b/README.assets/image-20230306091621220.png differ diff --git a/README.assets/image-20230306092504776.png b/README.assets/image-20230306092504776.png new file mode 100644 index 0000000..64f8c68 Binary files /dev/null and b/README.assets/image-20230306092504776.png differ diff --git a/README.assets/image-20230306092645321.png b/README.assets/image-20230306092645321.png new file mode 100644 index 0000000..f0aa91a Binary files /dev/null and b/README.assets/image-20230306092645321.png differ diff --git a/README.assets/image-20230306093225214.png b/README.assets/image-20230306093225214.png new file mode 100644 index 0000000..d4cd765 Binary files /dev/null and b/README.assets/image-20230306093225214.png differ diff --git a/README.assets/image-20230306101314509.png b/README.assets/image-20230306101314509.png new file mode 100644 index 0000000..0528776 Binary files /dev/null and b/README.assets/image-20230306101314509.png differ diff --git a/README.assets/image-20230306101510700.png b/README.assets/image-20230306101510700.png new file mode 100644 index 0000000..a9eb01d Binary files /dev/null and b/README.assets/image-20230306101510700.png differ diff --git a/README.assets/image-20230306101556676.png b/README.assets/image-20230306101556676.png new file mode 100644 index 0000000..b387e0b Binary files /dev/null and b/README.assets/image-20230306101556676.png differ diff --git a/README.assets/image-20230306101820442.png b/README.assets/image-20230306101820442.png new file mode 100644 index 0000000..2bcdf10 Binary files /dev/null and b/README.assets/image-20230306101820442.png differ diff --git a/README.assets/image-20230306101933687.png b/README.assets/image-20230306101933687.png new file mode 100644 index 0000000..e93e58c Binary files /dev/null and b/README.assets/image-20230306101933687.png differ diff --git "a/README.assets/\345\205\263\346\263\250.gif" "b/README.assets/\345\205\263\346\263\250.gif" new file mode 100644 index 0000000..20111ef Binary files /dev/null and "b/README.assets/\345\205\263\346\263\250.gif" differ diff --git a/Recv_Msg_Dispose/FriendMsg_dispose.py b/Recv_Msg_Dispose/FriendMsg_dispose.py new file mode 100644 index 0000000..4cd6990 --- /dev/null +++ b/Recv_Msg_Dispose/FriendMsg_dispose.py @@ -0,0 +1,110 @@ +from BotServer.SendServer import SendServer +from Api_Server.Api_Server_Main import Api_Server_Main +from Cache.Cache_Server import Cache_Server +from Db_Server.Db_User_Server import Db_User_Server +from Output import output +import yaml +import os +import re + + +class FriendMsg_dispose: + def __init__(self): + # 初始化核心参数 + self.senderid = 'null' + self.nickname = 'null' + self.msgJson = '' + self.sendmsg = '' + self.keyword = '' + + # 读取配置文件 + current_path = os.path.dirname(__file__) + config = yaml.load(open(current_path + '/../config/config.yaml', encoding='UTF-8'), yaml.Loader) + + # 读取超级管理员配置 + self.administrators = config['Administrators'] + + # 获取关键词 + self.cache_words = config['System_Config']['Cache_Config_Word'] + self.help_menu_words = config['System_Config']['Help_Menu'] + self.system_copyright = config['System_Config']['System_Copyright'] + self.show_white_room_words = config['Key_Word']['Show_WhiteRoom_Word'] + + # 实例化消息发送服务 + self.Ss = SendServer() + + # 实例化接口服务类 + self.Asm = Api_Server_Main() + + # 实例化缓存操作类 + self.Cs = Cache_Server() + + # 实例化用户操作类 + self.Dus = Db_User_Server() + + def get_information(self, msgJson, senderid, ws): + self.senderid = senderid + self.nickname = self.Ss.get_member_nick(wxid=senderid, roomid='null') + self.keyword = msgJson['content'].replace('\u2005', '') + self.process_information(ws) + + # 好友消息处理 + def process_information(self, ws): + # 注入消息转发给好友 + if self.senderid in self.administrators and self.keyword: + try: + patten = re.search(r'给(?P+ + + + + + ++.*?)发消息 (?P .*)', self.keyword) + print(patten) + msg = patten.group('msg') + nickname = patten.group('nickname') + recv_user = self.Dus.show_userid(wx_name=nickname.strip()) + if recv_user: + msg = f'—— 来自主人的消息 ——[庆祝]\n\n{msg}\n\n—— 来自主人的消息 ——[庆祝]' + ws.send(self.Ss.send_msg(msg=msg, wxid=recv_user)) + return + except AttributeError: + pass + + # 好友消息消息转发主人 + if self.senderid not in self.administrators and self.keyword: + for administrator in self.administrators: + msg = f'[太阳]收到来自【{self.nickname}】的消息\n\n{self.keyword}\n\n———— NGC BOT ————[爱心]' + ws.send(self.Ss.send_msg(msg=msg, wxid=administrator)) + + # 清除缓存 + if self.judge_keyword(keyword=self.keyword, + custom_keyword=self.cache_words, ) and self.senderid in self.administrators: + msg = self.Cs.delete_file() + ws.send(self.Ss.send_msg(msg=msg, wxid=self.senderid)) + return + # 查看白名单群聊 + elif self.judge_keyword(keyword=self.keyword, custom_keyword=self.show_white_room_words): + white_room_id, white_room_name = self.Dus.show_white_room() + msg = '[爱心]【已开启推送服务群聊列表】[爱心]\n' + for room_name in white_room_name: + msg += f'[庆祝]【{room_name}】\n' + ws.send(self.Ss.send_msg(msg=msg.strip(), wxid=self.senderid)) + # AI对话 + elif self.keyword: + self.Dus.add_user(wx_id=self.senderid, wx_name=self.nickname) + recv_msg = self.Asm.get_ai(keyword=self.keyword.strip().replace(' ', '')) + if not recv_msg: + recv_msg = '[嘿哈]本Bot听不懂你在说什么啦,不过我已经将消息通知给主人啦[转圈]' + msg = f'———— NGC BOT ————[爱心]\n\n{recv_msg}\n\n———— NGC BOT ————[爱心]\n更多功能回复【help】查看' + ws.send(self.Ss.send_msg(msg=msg, wxid=self.senderid)) + + # 判断关键词 + def judge_keyword(self, keyword, custom_keyword, split_bool=False, one_bool=False): + # 分割触发 + if split_bool: + keyword = keyword.split(' ') + for ckw in custom_keyword: + for kw in keyword: + if ckw == kw: + return True + # 单个触发 + elif one_bool: + return True if keyword.strip() == custom_keyword.strip() else False + # 单个循环触发 + elif keyword and custom_keyword and not split_bool and not one_bool: + return True if [ckw for ckw in custom_keyword if ckw == keyword] else False diff --git a/Recv_Msg_Dispose/RoomMsg_dispose.py b/Recv_Msg_Dispose/RoomMsg_dispose.py new file mode 100644 index 0000000..accdb84 --- /dev/null +++ b/Recv_Msg_Dispose/RoomMsg_dispose.py @@ -0,0 +1,424 @@ +from Api_Server.Api_Server_Main import Api_Server_Main +from Db_Server.Db_Point_Server import Db_Point_Server +from Db_Server.Db_User_Server import Db_User_Server +from BotServer.SendServer import SendServer +from Output.output import output +import yaml +import os +import re + + +class RoomMsg_disposes: + def __init__(self, ): + # 初始化核心参数 + self.bot_wxid = None + self.bot_name = None + self.room_name = None + self.at_nickname = None + self.at_wxid = None + self.roomid = 'null' + self.senderid = 'null' + self.nickname = 'null' + self.msgJson = '' + + # 处理过的接收的消息 + self.keyword = '' + + # 实例化消息服务 + self.Ss = SendServer() + + # 实例化接口服务类 + self.Asm = Api_Server_Main() + + # 实例化用户数据操作类 + self.Dus = Db_User_Server() + + # 实例化积分数据类 + self.Dps = Db_Point_Server() + + # 读取配置文件 + current_path = os.path.dirname(__file__) + config = yaml.load(open(current_path + '/../config/config.yaml', encoding='UTF-8'), yaml.Loader) + + # 读取超级管理员 + self.administrators = config['Administrators'] + + # 读取关键词配置 + self.pic_words = config['Key_Word']['Pic_Word'] + self.video_words = config['Key_Word']['Video_Word'] + self.icp_words = config['Key_Word']['Icp_Word'] + self.suffix_words = config['Key_Word']['Suffix_Word'] + self.attribution_words = config['Key_Word']['Attribution_Word'] + self.whois_words = config['Key_Word']['Whois_Word'] + self.fish_words = config['Key_Word']['Fish_Word'] + self.wether_words = config['Key_Word']['Weather_Word'] + self.dog_words = config['Key_Word']['Dog_Word'] + self.constellation_words = config['Key_Word']['Constellation_Word'] + self.morning_words = config['Key_Word']['Morning_Word'] + self.threatbook_words = config['Key_Word']['ThreatBook_Word'] + self.add_admin_words = config['Key_Word']['Add_Admin_Word'] + self.del_admin_words = config['Key_Word']['Del_Admin_Word'] + self.add_BlackRoom_words = config['Key_Word']['Add_BlackRoom_Word'] + self.del_BlackRoom_words = config['Key_Word']['Del_BlackRoom_Word'] + self.add_WhiteRoom_words = config['Key_Word']['Add_WhiteRoom_Word'] + self.del_WhiteRoom_words = config['Key_Word']['Del_WhiteRoom_Word'] + self.add_point_words = config['Point_Function']['Add_Point_Word'] + self.del_point_words = config['Point_Function']['Del_Point_Word'] + self.threatbook_point = config['Point_Function']['Function']['ThreatBook_Point'] + self.sign_keyword = config['Point_Function']['Sign_Keyword'] + self.query_point_words = config['Point_Function']['Query_Point'] + self.give_point_words = config['Point_Function']['Give_Point_Word'] + self.morning_page_words = config['Key_Word']['Morning_Page'] + self.evening_page_words = config['Key_Word']['Evening_Page'] + self.help_menu_words = config['System_Config']['Help_Menu'] + self.system_copyright = config['System_Config']['System_Copyright'] + + # 获取接收信息 + def get_information(self, msgJson, roomid, senderid, nickname, ws): + self.msgJson = msgJson + # 获取群聊ID + self.roomid = roomid + # 获取发送者微信ID + self.senderid = senderid + # 获取发送者名字 + self.nickname = nickname + + # 获取被@人的微信ID + + try: + self.at_wxid = re.findall(r" 20: + if not self.judge_admin(wxid=self.senderid, roomid=self.roomid): + if not self.senderid in self.administrators: + self.Dps.del_point(wx_id=self.senderid, point=self.threatbook_point) + point_msg = f'\n您使用了IP查询功能,扣除对应积分 {self.threatbook_point}分\n当前可用积分:{self.Dps.query_point(wx_id=self.senderid)}' + ws.send( + self.Ss.send_msg(msg=point_msg, wxid=self.senderid, roomid=self.roomid, + nickname=self.nickname)) + ws.send(self.Ss.send_msg(msg=msg, wxid=self.senderid, roomid=self.roomid, nickname=self.nickname)) + # 签到口令提醒 + elif self.judge_keyword(keyword=self.keyword, custom_keyword='签到', one_bool=True): + msg = f'签到口令已改为:{self.sign_keyword}' + ws.send(self.Ss.send_msg(msg=msg, wxid=self.senderid, nickname=self.nickname, roomid=self.roomid)) + # 签到功能 + elif self.judge_keyword(keyword=self.keyword, custom_keyword=self.sign_keyword, one_bool=True): + msg = self.Dps.judge_main(wx_id=self.senderid, wx_name=self.nickname, sign_bool=True) + if msg: + ws.send(self.Ss.send_msg(msg=msg, wxid=self.senderid, nickname=self.nickname, roomid=self.roomid)) + # 查询积分 + elif self.judge_keyword(keyword=self.keyword, custom_keyword=self.query_point_words): + msg = f'\n当前可用积分:{0 if not self.Dps.query_point(wx_id=self.senderid, wx_name=self.senderid) else self.Dps.query_point(wx_id=self.senderid, wx_name=self.nickname)}' + ws.send(self.Ss.send_msg(msg=msg, wxid=self.senderid, nickname=self.nickname, roomid=self.roomid)) + # 积分加减操作 + self.judge_operation(keyword=self.keyword, ws=ws) + + # 娱乐功能 + def Happy_Function(self, ws): + # AI对话 + if self.at_wxid == self.bot_wxid: + if '所有人' not in self.keyword: + keyword = self.keyword.replace('@', '').replace(self.bot_name, '').strip().replace(' ', '') + if keyword: + msg = self.Asm.get_ai(keyword=keyword) + ws.send(self.Ss.send_msg(msg=msg, wxid=self.senderid, nickname=self.nickname, roomid=self.roomid, )) + else: + return + # 美女图片 + elif self.judge_keyword(keyword=self.keyword, custom_keyword=self.pic_words): + msg = self.Asm.get_pic() + if '/' in msg: + self.Ss.send_img_room(msg=msg, roomid=self.roomid) + else: + ws.send(self.Ss.send_msg(msg=msg, roomid=self.roomid)) + # 美女视频 + elif self.judge_keyword(keyword=self.keyword, custom_keyword=self.video_words): + msg = self.Asm.get_video() + if '/' in msg: + self.Ss.send_file_room(file=msg, roomid=self.roomid) + else: + ws.send(self.Ss.send_msg(msg=msg, wxid=self.roomid)) + # icp查询 + elif self.judge_keyword(keyword=self.keyword, custom_keyword=self.icp_words, split_bool=True): + msg = self.Asm.get_icp(keyword=self.keyword) + ws.send(self.Ss.send_msg(msg=msg, wxid=self.senderid, roomid=self.roomid, nickname=self.nickname)) + # 后缀名查询 + elif self.judge_keyword(keyword=self.keyword, custom_keyword=self.suffix_words, split_bool=True): + msg = self.Asm.get_suffix(keyword=self.keyword) + ws.send(self.Ss.send_msg(msg=msg, wxid=self.senderid, roomid=self.roomid, nickname=self.nickname)) + # 归属查询 + elif self.judge_keyword(keyword=self.keyword, custom_keyword=self.attribution_words, split_bool=True): + msg = self.Asm.get_attribution(keyword=self.keyword) + ws.send(self.Ss.send_msg(msg=msg, wxid=self.senderid, roomid=self.roomid, nickname=self.nickname)) + # whois查询 + elif self.judge_keyword(keyword=self.keyword, custom_keyword=self.whois_words, split_bool=True): + msg = self.Asm.get_whois(keyword=self.keyword) + ws.send(self.Ss.send_msg(msg=msg, wxid=self.senderid, roomid=self.roomid, nickname=self.nickname)) + # 摸鱼日历 + elif self.judge_keyword(keyword=self.keyword, custom_keyword=self.fish_words): + msg = self.Asm.get_fish() + self.Ss.send_img_room(msg=msg, roomid=self.roomid) + # 天气查询 + elif self.judge_keyword(keyword=self.keyword, custom_keyword=self.wether_words, split_bool=True): + msg = self.Asm.get_wether(keyword=self.keyword) + ws.send(self.Ss.send_msg(msg=msg, wxid=self.senderid, roomid=self.roomid, nickname=self.nickname)) + # 舔狗日记 + elif self.judge_keyword(keyword=self.keyword, custom_keyword=self.dog_words): + msg = self.Asm.get_dog() + ws.send(self.Ss.send_msg(msg=msg, wxid=self.senderid, roomid=self.roomid, nickname=self.nickname)) + # 星座查询 + elif self.judge_keyword(keyword=self.keyword, custom_keyword=self.constellation_words, split_bool=True): + msg = self.Asm.get_constellation(keyword=self.keyword) + ws.send(self.Ss.send_msg(msg=msg, wxid=self.senderid, roomid=self.roomid, nickname=self.nickname)) + # 早安寄语 + elif self.judge_keyword(keyword=self.keyword, custom_keyword=self.morning_words): + msg = self.Asm.get_morning() + ws.send(self.Ss.send_msg(msg=msg, wxid=self.senderid, roomid=self.roomid, nickname=self.nickname)) + # 帮助菜单 + self.help_menu(ws=ws, keyword=self.keyword) + + # 帮助菜单 + def help_menu(self, ws, keyword): + if self.judge_keyword(keyword=self.keyword, custom_keyword=self.help_menu_words): + msg = f"[爱心] ———— NGCBot功能菜单 ———— [爱心]\n[庆祝]【一、积分功能】\n[庆祝]【1.1】、微步威胁IP查询\n\n您可在群内发送信息【WHOIS查询 qq.com】不需要@本Bot哦\n\n[烟花]【二、娱乐功能】\n" \ + f"[烟花]【2.1】、美女图片\n[烟花]【2.2】、美女视频\n[烟花]【2.3】、舔狗日记\n[烟花]【2.4】、摸鱼日历\n[烟花]【2.5】、星座查询\n[烟花]【2.6】、AI对话\n[烟花]【2.7】、手机号归属地查询\n[烟花]【2.8】、WHOIS信息查询\n" \ + f"[烟花]【2.9】、备案查询\n[烟花]【2.10】、后缀名查询\n\n您可以在群内发送消息【查询运势 白羊座】进行查询【其它功能类似】,或@本Bot进行AI对话哦\n\n需要调出帮助菜单,回复【帮助菜单】即可\n" \ + f"回复【help 2.1】可获取相应功能帮助[跳跳],其它功能帮助以此类推[爱心]\n" \ + f"{'By #' + self.system_copyright if self.system_copyright else ''}" + ws.send(self.Ss.send_msg(msg=msg, wxid=self.roomid)) + elif 'help' in self.keyword.lower(): + child_help = self.keyword.strip().split(' ')[1] + msg = '' + if child_help == '1.1': + msg = '[庆祝]【1.1】、微步威胁IP查询功能帮助\n\n[爱心]命令:【ip查询 x.x.x.x】' + elif child_help == '2.1': + msg = '[烟花]【2.1】、美女图片功能帮助\n\n[爱心]命令:【图片】【美女图片】' + elif child_help == '2.2': + msg = '[烟花]【2.2】、美女视频功能帮助\n\n[爱心]命令:【视频】【美女视频】' + elif child_help == '2.3': + msg = '[烟花]【2.3】、舔狗日记功能帮助\n\n[爱心]命令:【舔狗日记】' + elif child_help == '2.4': + msg = '[烟花]【2.4】、摸鱼日历功能帮助\n\n[爱心]命令:【摸鱼日历】\n\n[爱心]联系主人可开启定时发送哦[跳跳]' + elif child_help == '2.5': + msg = '[烟花]【2.5】、星座查询功能帮助\n\n[爱心]命令:【星座查询 白羊】' + elif child_help == '2.6': + msg = '[烟花]【2.6】、AI对话功能帮助\n\n[爱心]命令:【@机器人】直接提问即可哦[跳跳]' + elif child_help == '2.7': + msg = '[烟花]【2.7】、手机号归属地查询功能帮助\n\n[爱心]命令:【归属查询 110】' + elif child_help == '2.8': + msg = '[烟花]【2.8】、WHOIS信息查询功能帮助\n\n[爱心]命令:【whois查询 qq.com】' + elif child_help == '2.9': + msg = '[烟花]【2.9】、备案查询功能帮助\n\n[爱心]命令:【icp查询 qq.com】' + elif child_help == '2.10': + msg = '[烟花]【2.10】、后缀名查询功能帮助\n\n[爱心]命令:【后缀查询 apk】' + ws.send(self.Ss.send_msg(msg=msg, wxid=self.roomid)) + + # 判断关键词 + def judge_keyword(self, keyword, custom_keyword, split_bool=False, one_bool=False): + # 分割触发 + if split_bool: + keyword = keyword.split(' ') + for ckw in custom_keyword: + for kw in keyword: + if ckw == kw: + return True + # 单个触发 + elif one_bool: + return True if keyword.strip() == custom_keyword.strip() else False + # 单个循环触发 + elif keyword and custom_keyword and not split_bool and not one_bool: + # print(keyword, custom_keyword) + return True if [ckw for ckw in custom_keyword if ckw == keyword] else False + + # 判断管理员 + def judge_admin(self, wxid, roomid): + admin_list = self.Dus.show_admin() + for data in admin_list: + if wxid == data['wx_id'] and roomid == data['wx_roomid']: + return True + else: + return False + + # 判断黑名单 + def judge_black_room(self, roomid): + black_rooms = self.Dus.show_black_room() + for data in black_rooms: + if roomid == data['wx_roomid']: + return True + else: + return False + + # 判断积分余额 + def judge_point(self, ws, wxid, roomid, function_point): + user_point = self.Dps.query_point(wx_id=wxid, wx_name=self.nickname) + if user_point < function_point: + if not self.judge_admin(wxid=self.senderid, roomid=self.roomid): + if not self.senderid in self.administrators: + ws.send( + self.Ss.send_msg(msg=f'\n积分不足,当前可用积分:{user_point}\n功能积分:{function_point}', wxid=self.senderid, + roomid=roomid, nickname=self.nickname)) + return True if user_point >= function_point else False + + # 判断积分增减赠送 + def judge_operation(self, keyword, ws): + list_bool = False + at_wx_nickname_list = list() + at_wxid_list = list() + if self.at_wxid: + operations = re.search( + f'@{self.at_nickname.strip() if self.at_nickname.strip() else "xx"}(?P \w|\+|-)(?P \d+)', + keyword) + if ',' in self.at_wxid: + list_bool = True + at_wxid_list = self.at_wxid.split(',') + for at_wxid in at_wxid_list: + at_wx_nickname_list.append(self.Ss.get_member_nick(roomid=self.roomid, wxid=at_wxid)) + operations = re.search( + f'{"".join(at_wx_nickname_list) if "".join(at_wx_nickname_list) else "xx"}(?P \w|\+|-)(?P \d+)', + keyword.replace('@', '')) + try: + operation = operations.group('operation') + point = int(operations.group('point')) + except Exception as e: + output(f'[+]:小报错,问题不大:{e}') + return + + msg = '' + give_bool = False + # 增加积分 + if self.judge_keyword(keyword=operation, custom_keyword=self.add_point_words, ): + if self.judge_admin(wxid=self.senderid, roomid=self.roomid) or self.senderid in self.administrators: + if list_bool: + for wxid, wx_name in zip(at_wxid_list, at_wx_nickname_list): + msg = self.Dps.judge_main(wx_id=wxid, wx_name=wx_name, point=point, + add_bool=True) + ws.send( + self.Ss.send_msg(msg=msg, wxid=wxid, nickname=wx_name, roomid=self.roomid)) + else: + msg = self.Dps.judge_main(wx_id=self.at_wxid, wx_name=self.at_nickname, point=point, add_bool=True) + + # 扣除积分 + if self.judge_keyword(keyword=operation, custom_keyword=self.del_point_words): + if self.judge_admin(wxid=self.senderid, roomid=self.roomid) or self.senderid in self.administrators: + if list_bool: + for wxid, wx_name in zip(at_wxid_list, at_wx_nickname_list): + msg = self.Dps.judge_main(wx_id=wxid, wx_name=wx_name, point=point, + del_bool=True) + ws.send( + self.Ss.send_msg(msg=msg, wxid=wxid, nickname=wx_name, roomid=self.roomid)) + else: + msg = self.Dps.judge_main(wx_id=self.at_wxid, wx_name=self.at_nickname, point=point, del_bool=True) + # 赠送积分 + if self.judge_keyword(keyword=operation, custom_keyword=self.give_point_words): + if list_bool: + for wxid, wx_name in zip(at_wxid_list, at_wx_nickname_list): + msg, give_bool = self.Dps.give_point(wx_id=self.senderid, wx_name=self.nickname, + at_wx_id=wxid, at_wx_name=wx_name, + point=point) + ws.send( + self.Ss.send_msg(msg=msg, wxid=self.senderid, nickname=self.nickname, roomid=self.roomid)) + else: + msg, give_bool = self.Dps.give_point(wx_id=self.senderid, wx_name=self.nickname, + at_wx_id=self.at_wxid, at_wx_name=self.at_nickname, + point=point) + + # 赠送积分 + if msg and not list_bool and ',' not in self.at_wxid: + if give_bool: + self.at_wxid = self.senderid + self.at_nickname = self.nickname + ws.send(self.Ss.send_msg(msg=msg, wxid=self.at_wxid, nickname=self.at_nickname, roomid=self.roomid)) diff --git a/main.py b/main.py new file mode 100644 index 0000000..4df19dc --- /dev/null +++ b/main.py @@ -0,0 +1,15 @@ +from BotServer.MainServer import MainServers + + +class Main: + + def __init__(self): + self.Ms = MainServers() + + def run(self): + self.Ms.Bot_start() + + +if __name__ == '__main__': + Mn = Main() + Mn.run() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..993532b --- /dev/null +++ b/requirements.txt @@ -0,0 +1,9 @@ +beautifulsoup4==4.11.2 +chinese_calendar==1.8.0 +feedparser==6.0.10 +PyYAML==6.0 +requests==2.28.1 +schedule==1.1.0 +termcolor==1.1.0 +urllib3==1.26.13 +websocket_client==1.5.1 diff --git "a/\346\263\250\345\205\245\345\231\250.zip" "b/\346\263\250\345\205\245\345\231\250.zip" new file mode 100644 index 0000000..a9bd975 Binary files /dev/null and "b/\346\263\250\345\205\245\345\231\250.zip" differ