From 894259da8539a0c6b246a90eaa3e75926cf99b08 Mon Sep 17 00:00:00 2001 From: AdminWhaleFall Date: Sun, 3 Apr 2022 21:10:11 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20=E5=AE=8C=E6=88=90FlaskAPP?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api.json | 26 +++ apiback/api_back_2022_04_03_21_02_12.json | 1 + flask_app/README.md | 3 + flask_app/__pycache__/utils.cpython-38.pyc | Bin 0 -> 3074 bytes flask_app/app.py | 113 ++++++++++++ flask_app/templates/admin.html | 205 +++++++++++++++++++++ flask_app/utils.py | 86 +++++++++ smsboom.py | 8 +- 8 files changed, 439 insertions(+), 3 deletions(-) create mode 100644 apiback/api_back_2022_04_03_21_02_12.json create mode 100644 flask_app/README.md create mode 100644 flask_app/__pycache__/utils.cpython-38.pyc create mode 100644 flask_app/app.py create mode 100644 flask_app/templates/admin.html create mode 100644 flask_app/utils.py diff --git a/api.json b/api.json index e8f4024..5937965 100644 --- a/api.json +++ b/api.json @@ -12,5 +12,31 @@ "phone_num": "{phone}", "area_code": "86" } + }, + { + "desc": "彩云小译", + "url": "https://biz.caiyunapp.com/v1/send_sms_code", + "method": "POST", + "header": { + "Referer": "https://fanyi.caiyunapp.com/", + "Cy-Token": "token 9876032166" + }, + "data": { + "phone_num": "{phone}", + "area_code": "86" + } + }, + { + "desc": "彩云小译", + "url": "https://biz.caiyunapp.com/v1/send_sms_code", + "method": "POST", + "header": { + "Referer": "https://fanyi.caiyunapp.com/", + "Cy-Token": "token 9876032166" + }, + "data": { + "phone_num": "{phone}", + "area_code": "86" + } } ] \ No newline at end of file diff --git a/apiback/api_back_2022_04_03_21_02_12.json b/apiback/api_back_2022_04_03_21_02_12.json new file mode 100644 index 0000000..2fae989 --- /dev/null +++ b/apiback/api_back_2022_04_03_21_02_12.json @@ -0,0 +1 @@ +[{"desc": "С", "url": "https://biz.caiyunapp.com/v1/send_sms_code", "method": "POST", "header": {"Referer": "https://fanyi.caiyunapp.com/", "Cookie": "UM_distinctid=17fd5c7a9ba69a-0200a7005bf45a-56171958-146d15-17fd5c7a9bb749; _gid=GA1.2.2046680529.1648971157; _gat_gtag_UA_185151443_2=1; _ga=GA1.2.44459633.1648559084; _ga_65TZCJSDBD=GS1.1.1648971156.4.1.1648971164.0; _ga_R9YPR75N68=GS1.1.1648971156.4.1.1648971164.52", "Cy-Token": "token 9876032166"}, "data": {"phone_num": "{phone}", "area_code": "86"}}, {"desc": "С", "url": "https://biz.caiyunapp.com/v1/send_sms_code", "method": "POST", "header": {"Referer": "https://fanyi.caiyunapp.com/", "Cy-Token": "token 9876032166"}, "data": {"phone_num": "{phone}", "area_code": "86"}}, {"desc": "С", "url": "https://biz.caiyunapp.com/v1/send_sms_code", "method": "POST", "header": {"Referer": "https://fanyi.caiyunapp.com/", "Cy-Token": "token 9876032166"}, "data": {"phone_num": "{phone}", "area_code": "86"}}] \ No newline at end of file diff --git a/flask_app/README.md b/flask_app/README.md new file mode 100644 index 0000000..8f6235b --- /dev/null +++ b/flask_app/README.md @@ -0,0 +1,3 @@ +# Flask APP For SMSBoom + +用于添加测试更改短信接口的 Flask 项目,方便短信接口的维护. \ No newline at end of file diff --git a/flask_app/__pycache__/utils.cpython-38.pyc b/flask_app/__pycache__/utils.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..38f49c512aa65dae12c085d7966d0140bc043f55 GIT binary patch literal 3074 zcmZ`*>u()L72nz2yZ7PiXF}^V1#LCYR)>u@?i&I*cQ(JAiII-O2tY;?6WqA_E+o0-c!G)r^v zJ<_(2f@9!_18*Xc0%WlXm&UdGeA*yJ^o| zjrK5W-EjI@KkHaNMtdLXw2vOSYdTL+V^%92-2uzA5>e*Mo~**x3gV?D#%D^p%AfZH zn~o_9RQ{$H_|%gz2YT+Mn)Kty3shzFI%s z7i~}4moHC*;e-%tQ-i6HJz!4->?RA&+(|ybNT-JwArrz|V*9M?CGfTIqZMT>#ys?- zldHr*%>4#)@(W&NMRKpg8ac1#mzPBxHNN)(^!B13FguE+&2IZb3fqrt$`-wPAZ_Y% zRsqviPwWtIMx!t%7#}#d#3I@FY&vfELEsIJm51z8FZxma_M|;GX`hQIk9}$n4^7&Q z>Odu$w5NTT+2`wiKnJf~y*6APK0Q1a(>{C}S zU!Q*QSv&Aon0<*=R^pQVD&qn?IyefaU8wRnWP{_U%R}Xn)1zbM;n8t>I$l6SX1zs^ z`+GaR?tAgHKRE5z{qsD&1=YaBRSP0bcPGbWO4W2Gd-G>I?|s&O=eO-&ZEpSYQTxN+eBSz_%2cJS31#A^@iZu6hjk%sAw4d| zEnik`IHT7Jm*OQ8I?frJ~-%i8pregdy-AeS7Pc%OY^hSv*+VD zoL>w)vEq8Q+I(I5fhgBj)svAIG8a#DD{&+}KXOG4u>Kv`LSU)Vj4qNRjpN|8^4G|M zURhiW*j5&2vd*IlI%ltCV1QdC&Uym|65J)py3QxSZF)<)sQvWhyuN0vnN4%Uprom{ zbolB`ZNqG7Exk#afSntC(KE@)46K}om0uxAU}tc-G1JK2sa4~Mtu;E5ssVlrYilJ- z6@18Zm_-!^!SyRrWqip(p|YIS0%hLF6JQKn$QB0mn=t4y-9GFI5C z%0LmTv&7?RcMK(pyL-8ao@ap~FeDl&kRDPbx@J8t8in1FsW*DixrdjO2!9&nD_A=A z8jdm35-%Qwfz%|C;HOsNrFF87mXrFofVKV4_qTriLHqv4?fZY)`tZT$e|YqtzyG=Y z;BPw*K5qZ~FQp8B285L1N0R4~Q54@&`F*?L_-_OG3s&(HKpTfwB$=Q$dQt8DMd++A z<;cFmGqA3yEklm17`z8V>%x4401d(mA=X?BH_naSxgkxMWuyh+enDn8ayV;&gqvw< z805xG!QO2XHII9t4GK-z5Oo~b3vknfc+(t6rQn?S8aCWlFU?-(U7%_y&%5Enzl&Wj zcAeOL6T2Sl5(k=i7pP1SdsLM4)MqD=i_ty=heFkhXuw?1Y7#gCPtY<2VgVcw5M89v zg}yuxn<@3Goa-hD=c>v|E~MIK(G!gUkXeK$Gm5*8Lw$$+BNMJ?RBk*KP8#EfaBVKeQSI3eiHvQN4DO(xAp1! z2|{);1bU|cIl#^?CrSGWyZwu|+7Cb7diRrb)gGp>O5e7(H$Q2A^yb#)Kej(=l@oy- z%rGpGX$YXuV9LaGSu#_MJqP?0UI?@=Q?Y)OI+Bp2m&I*mT?l-rwtNJaCZJ3(ih;p8 zcB2mUE8RQ+D`FS+9Ytxxr?M)^dS!AZYKP*S6tBF5)h=*uTme~ug-El~%2gz$We-fC-e)RpI1ntJI66U*QOX1a-=it2MZw z_yHn+h&=QdN3-!d3FDg#&_v-*7LtPBFfs7Y3zETtv dict: + '''解析请求数据并以字典的形式返回''' + if req_data.method == 'POST': + data = req_data.form + + elif req_data.method == 'GET': + data = req_data.args + + return dict(data) + + +class BaseResponse(BaseModel): + """返回的响应""" + status: int = 0 # 状态码 0-->成功 1-->失败 + msg: str = "前端显示的简短信息" + data: Optional[str] + + @property + def resp(self): + '''BaseModel类型返回json''' + response = make_response( + json.dumps( + self.dict(), + ensure_ascii=False, + sort_keys=False + ), + ) + response.mimetype = 'application/json' + # 跨域设置 + response.headers['Access-Control-Allow-Origin'] = '*' + response.headers['Access-Control-Allow-Methods'] = 'OPTIONS,HEAD,GET,POST' + response.headers['Access-Control-Allow-Headers'] = 'x-requested-with' + return response + + +@app.route("/testapi/", methods=['POST']) +def testapi(): + brs = BaseResponse() + # 需要传入 json 数据 + try: + jsonData = request.get_json() + api = API(**jsonData) + phone = jsonData.get('phone') + if not phone: + raise ValueError("参数 phone 没有!") + try: + resp = test_resq(api, phone) + brs.status = 0 + brs.msg = f"请求成功!{resp}" + brs.data = resp.text + except Exception as why: + brs.status = 1 + brs.msg = f"请求失败:{why}" + except Exception as why: + brs.status = 1 + brs.msg = f"参数有误:{why}" + return brs.resp + + +@app.route("/submitapi/", methods=['POST']) +def submitapi(): + """提交API到json文件""" + # 需要传入 json 数据 + jsonData = request.get_json() + api = API(**jsonData) + data = json.loads(json_path.read_text(encoding='utf8')) + with open(json_path, mode="w", encoding="utf8") as j: + try: + data.append(api.dict()) + json.dump(data, j, ensure_ascii=False, sort_keys=False) + return BaseResponse(status=0, msg="写入成功!").resp + except Exception as why: + return BaseResponse(status=1, msg=f"写入失败!{why}").resp + + +@app.route("/backapi/", methods=['GET']) +def backjson(): + """备份json文件""" + try: + timeStruct = time.localtime(int(time.time())) + strTime = time.strftime("%Y_%m_%d_%H_%M_%S", timeStruct) + Path.mkdir(Path(json_path.parent, 'apiback', exist_ok=True)) + json_back_path = Path(json_path.parent, 'apiback', + f"api_back_{strTime}.json") + with open(json_back_path, mode="w") as j: + j_data = json.loads(json_path.read_text(encoding='utf8')) + json.dump(j_data, j, ensure_ascii=False, sort_keys=False) + return BaseResponse(status=0, msg="备份成功!").resp + except Exception as why: + return BaseResponse(status=1, msg=f"备份失败{why}").resp + +@app.route("/downloadapi/", methods=['GET']) +def downloadapi(): + """下载接口文件""" + return json_path.read_text(encoding='utf8') + + +app.run(host="0.0.0.0", port=1098, debug=True) diff --git a/flask_app/templates/admin.html b/flask_app/templates/admin.html new file mode 100644 index 0000000..5dea57a --- /dev/null +++ b/flask_app/templates/admin.html @@ -0,0 +1,205 @@ + + + + + + + + 短信轰炸接口调试工具. + + + + + + + + + + + + + +
+ + + + +
+ URL: + + + + +
+
+ + +
+ + +
+ + + + + +
+
+
+ Type:视频 + Type:图文 +
+
+
+
+ 文案: {{ resp.data.title }} +
+
+
+
+ 作者: {{ resp.data.author }} +
+
+
+
+ 音乐:(点击下载) +
+
+ + +
+ +
+
+ 点击图片即可下载! +
+
+ + 加载失败 + +
+ +
+
+
+
+
+
+
+ 视频链接: + (点击下载) +
+
+ +
+ +
+
+
+
+ +
+ +
+ +
+ +
+
+ + + + \ No newline at end of file diff --git a/flask_app/utils.py b/flask_app/utils.py new file mode 100644 index 0000000..845b83e --- /dev/null +++ b/flask_app/utils.py @@ -0,0 +1,86 @@ +# encoding=utf8 +from pathlib import Path +from loguru import logger +import sys +from pydantic import BaseModel, validator +from typing import Optional, Union +import httpx +from datetime import datetime +import json + +# logger config +logger.remove() +logger.add( + sink=sys.stdout, + format="{time:YYYY-MM-DD at HH:mm:ss} - {level} - {message}", + colorize=True, + backtrace=True +) + +json_path = Path(Path(__file__).parent.parent, "api.json") +if not json_path.exists(): + logger.error("Json file not exists in default directory!") + sys.exit(1) + +default_header = { + "User-Agent": "Mozilla/5.0 (Linux; U; Android 10; zh-cn; Mi 10 Build/QKQ1.191117.002) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/79.0.3945.147 Mobile Safari/537.36 XiaoMi/MiuiBrowser/13.5.40" +} + + +class API(BaseModel): + desc: str = "Default" + url: str + method: str = "GET" + header: Optional[Union[str, dict]] = default_header + data: Optional[Union[str, dict]] + + @validator('url') + def name_must_contain_space(cls, v: str): + """验证链接是否正确""" + if not v.startswith('https' or 'http'): + raise ValueError('url must startswith http(s)!') + return v + + def replace_data(self, content: Union[str, dict], phone) -> str: + if isinstance(content, dict): + for key, value in content.items(): + content[key] = value.replace("{phone}", phone).replace( + "{timestamp}", self.timestamp_new()) + else: + if isinstance(content, str): + content.replace("{phone}", phone).replace( + "{timestamp}", self.timestamp_new()) + return content + + def timestamp_new(self) -> str: + """返回整数字符串时间戳""" + return str(int(datetime.now().timestamp())) + + def handle_API(self, phone): + """ + :param API: one API basemodel + :return: API basemodel + """ + if self.method != "POST": + self.method = "GET" + self.data = self.replace_data(self.data, phone) + self.url = self.replace_data(self.url, phone) + if isinstance(self.header, str): + self.header = json.loads(self.header) + return self + + +def test_resq(api: API, phone) -> httpx.Response: + """测试 API 返回响应 + :param api: API model + :param phone: 手机号 + :return: httpx 请求对象. + """ + api = api.handle_API(phone) + with httpx.Client(headers=default_header, timeout=8) as client: + if not isinstance(api.data, dict): + client.request(method=api.method, headers=api.header, + url=api.url, data=api.data) + resp = client.request( + method=api.method, headers=api.header, url=api.url, json=api.data) + return resp diff --git a/smsboom.py b/smsboom.py index c114404..5a3856b 100644 --- a/smsboom.py +++ b/smsboom.py @@ -1,4 +1,4 @@ -# coding=utf-8 +# encoding=utf8 import httpx import json import sys @@ -79,8 +79,10 @@ def replace_data(content: Union[str, dict]) -> str: content[key] = value.replace("{phone}", phone).replace( "{timestamp}", timestamp_new()) else: - content.replace("{phone}", phone).replace( - "{timestamp}", timestamp_new()) + # fix: add str判断 + if isinstance(content, str): + content.replace("{phone}", phone).replace( + "{timestamp}", timestamp_new()) return content