OfpayHelper.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. # -*- coding: utf-8 -*-
  2. import os
  3. import re
  4. import sys
  5. import time
  6. import pymysql
  7. import logging
  8. # import jwt
  9. import json
  10. from datetime import datetime
  11. from mitmproxy import flowfilter
  12. from mitmproxy import http
  13. from mitmproxy import ctx
  14. sys.path.append('../')
  15. import utils.Utils as Utils
  16. sys.path.pop()
  17. """
  18. #http.HTTPFlow 实例 flow
  19. flow.request.http_version #HTTP 版本
  20. flow.request.headers #获取所有头信息,包含Host、User-Agent、Content-type等字段
  21. flow.request.cookies #cookie头
  22. flow.request.url #完整的请求地址,包含域名及请求参数,但是不包含放在body里面的请求参数
  23. flow.request.pretty_url #同flow.request.url目前没看出什么差别
  24. flow.request.host #域名
  25. flow.request.port #请求的目标端口
  26. flow.request.method #请求方式。POST、GET等
  27. flow.request.scheme #什么请求 ,如https
  28. flow.request.path # 请求的路径,url除域名之外的内容
  29. flow.request.get_text() #请求中body内容,有一些http会把请求参数放在body里面,那么可通过此方法获取,返回字典类型
  30. flow.request.replace() # 使用正则替换content中的内容
  31. flow.request.query #返回MultiDictView类型的数据,url直接带的键值参数
  32. flow.request.get_content()#bytes,结果如flow.request.get_text()
  33. flow.request.raw_content #bytes,结果如flow.request.get_content()
  34. flow.request.urlencoded_form #MultiDictView,content-type:application/x-www-form-urlencoded时的请求参数,不包含url直接带的键值参数
  35. flow.request.multipart_form #MultiDictView,content-type:multipart/form-data
  36. flow.request.timestamp_start #请求开始的时间戳
  37. flow.request.timestamp_end #请求结束的时间戳
  38. 时的请求参数,不包含url直接带的键值参数
  39. #以上均为获取request信息的一些常用方法,对于response,同理
  40. flow.response.status_code #状态码
  41. flow.response.headers #获取所有头信息
  42. flow.response.cookies #cookie头
  43. flow.response.text#返回内容,已解码
  44. flow.response.content #返回内容,二进制
  45. flow.response.set_text() #修改返回内容,不需要转码
  46. flow.response.replace() # 使用正则替换content中的内容
  47. flow.response.timestamp_start #响应开始的时间戳
  48. flow.response.timestamp_end #响应结束的时间戳
  49. """
  50. class OfpayHelper:
  51. order_simple_data = {
  52. "awardId": "W1155090378949787660",
  53. "activityId": "A923605206137307136",
  54. "activityName": "采集",
  55. "activityState": "2",
  56. "activityStartTime": "2024-01-01 00:00",
  57. "activityEndTime": "2888-12-31 23:59",
  58. "businessType": "4005",
  59. "outActivityCode": "eCoffee",
  60. "mobile": "",
  61. "prizeId": "sku14117",
  62. "prizeName": "数据采集成功",
  63. "prizeAlias": "",
  64. "prizeDesc": None,
  65. "prizeDescUrl": "https://mstatic.ofpay.com/marketing/upload/ca2ed3a05b2846b7909debf2df8e3495.png",
  66. "prizeBannerUrl": "https://mstatic.ofpay.com/marketing/upload/c4d1a0b94b50462eb0f040306a9badf4.png",
  67. "categoryId": "1",
  68. "rechargeType": "09",
  69. "goodsScene": "0",
  70. "goodsList": [],
  71. "orderNum": 1,
  72. "createTime": None,
  73. "imgUrl": "https://mstatic.ofpay.com/marketing/upload/7e21faea6ba94379bf16968c246cb044.png",
  74. "orderStatus": "3",
  75. "detailId": "T123456789",
  76. "clientAccount": "13430389115",
  77. "redeemCode": "",
  78. "redeemCodeStatus": "",
  79. "dynamicCodeSign": "1",
  80. "startEffectTime": "",
  81. "endEffectTime": None,
  82. "toExpireFlag": "0",
  83. "faceVal": "",
  84. "orderId": "T240226090160697",
  85. "tenantId": "0000000191",
  86. "price": "",
  87. "awardPrice": "0.0",
  88. "salePrice": "0.0",
  89. "rechargeId": "R1211608194317672448",
  90. "rechargeTime": "2024-01-01 00:00:00",
  91. "payStatus": "2",
  92. "discountPrice": "",
  93. "activityPrice": "",
  94. "customerInfo": "{\"device_id\":\"D29ED082-549A-4882-98FC-8BB881D1552B\",\"loginType\":\"interactiveIGoChoose\",\"gameAccount\":\"13430389115\",\"city_code\":\"440100\",\"cisno\":\"ZbHv0CEM2cGjx0DB9DXVJg==\",\"isNewUser\":\"0\",\"marketId\":\"M923156289016692736\",\"city_name\":\"广州市\",\"phone\":\"13430389115\",\"fromEntry\":\"APP\",\"currentTimeMillis\":\"1709515975349\",\"userUuid\":\"Pfd6kjTSmjCfQ8boswe1PpAmfgZW0acz\",\"cust_id\":\"Pfd6kjTSmjCfQ8boswe1PpAmfgZW0acz\",\"invitationCode\":\"BGCKWC\"}",
  95. "callbackOrder": "",
  96. "activityRechargeEffectStartTime": "",
  97. "activityRechargeEffectEndTime": "",
  98. "accountType": "",
  99. "payFlag": "1",
  100. "activityPayFlag": True,
  101. "thirdInfo": "{\"faceValue\":\"20.00\",\"customGatewayId\":\"ZDY_ICBC_NJFH\",\"showSign\":\"1\",\"xcxShowSign\":\"2\",\"order\":\"24\",\"toBPrice\":\"19.20\",\"appId\":\"gh_58e6ebeaa1ea\",\"showFlag\":\"eCoffee-Tims\",\"showPhone\":\"1\",\"pointActivity\":\"HD046012y3VGiMMHzP\",\"stockShowSign\":\"2\"}",
  102. "vendorVoucher": "",
  103. "productUseMsg": "",
  104. "proof": "",
  105. "amount": 1,
  106. "parentActivityNo": "",
  107. "parentDetailId": "",
  108. "subOrderExt": "{\"orderStatus\":\"\",\"payStatus\":\"\"}",
  109. "logisticsNo": "",
  110. "company": "",
  111. "promoteId": "",
  112. "version": 1,
  113. "gateWayId": "",
  114. "payType": "",
  115. "needRechargeNum": "0"
  116. }
  117. def __init__(self):
  118. self.domain_name = 'market-web.ofpay.com';
  119. self.host_ip = None;
  120. ip_address = Utils.get_ip_address(self.domain_name);
  121. if ip_address:
  122. self.host_ip = ip_address;
  123. self.db_conn = None;
  124. self.connect_mysql();
  125. def connect_mysql(self):
  126. config = {
  127. 'host':'47.106.225.136',
  128. 'port':3306,
  129. 'user':'root',
  130. 'passwd':'sjojo123456',
  131. 'database':'mitmproxy',
  132. 'charset':'utf8'
  133. };
  134. db_conn = None;
  135. while True:
  136. try:
  137. db_conn = pymysql.connect(**config);
  138. db_conn.ping(reconnect=True);
  139. except pymysql.OperationalError as e:
  140. print(e);
  141. print('连接断开,正在尝试重新连接...');
  142. if db_conn:
  143. db_conn.close();
  144. db_conn = pymysql.connect(**config);
  145. time.sleep(1);
  146. else:
  147. break;
  148. self.db_conn = db_conn;
  149. def check_mysql_connect(self):
  150. try:
  151. with self.db_conn.cursor() as cursor:
  152. cursor.execute('SELECT 1');
  153. except pymysql.MySQLError as e:
  154. print(e);
  155. self.db_conn.close();
  156. print('mysql重连...');
  157. self.connect_mysql();
  158. def check_host_pass(self, host):
  159. if self.host_ip:
  160. if host != self.host_ip and host != self.domain_name:
  161. return False;
  162. else:
  163. if host != self.domain_name:
  164. return False;
  165. return True;
  166. def request(self, flow: http.HTTPFlow):
  167. if not self.check_host_pass(flow.request.host):
  168. return;
  169. url = flow.request.url;
  170. path = flow.request.path;
  171. request = flow.request;
  172. def response(self, flow: http.HTTPFlow):
  173. if not self.check_host_pass(flow.request.host):
  174. return;
  175. url = flow.request.url;
  176. path = flow.request.path;
  177. print("###[OfpayHelper]path=%s"%path);
  178. if path.startswith('/h5/union/api/interactiveIGoChoose/indexConfigRebuild'):
  179. self.handle_activitylist(flow);
  180. elif path.startswith('/h5/union/api/interactiveIGoChoose/orderList'):
  181. self.handle_orderlist(flow);
  182. def get_jwt_token_data(self, flow: http.HTTPFlow):
  183. request = flow.request;
  184. headers = dict(request.headers);
  185. jwt_data = None;
  186. try:
  187. jwt_str = None;
  188. if 'Authorization' in headers:
  189. jwt_str = headers['Authorization'];
  190. else:
  191. cookies = dict(request.cookies);
  192. if 'unionToken_interactiveIGoChoose' in cookies:
  193. jwt_str = cookies['unionToken_interactiveIGoChoose'];
  194. if jwt_str:
  195. jwt_data = Utils.parse_jwt(jwt_str);
  196. except jwt.PyJWTError as e:
  197. print('jwt token解析失败');
  198. else:
  199. pass
  200. finally:
  201. pass
  202. if jwt_data:
  203. payload = jwt_data['payload'];
  204. if 'customerInfo' in payload:
  205. info_str = payload['customerInfo'];
  206. customer_info = json.loads(info_str);
  207. payload['customerInfo'] = customer_info;
  208. return jwt_data;
  209. def handle_activitylist(self, flow: http.HTTPFlow):
  210. ctx.log.info('###handle_activitylist###');
  211. request = flow.request;
  212. response = flow.response;
  213. jwt_data = self.get_jwt_token_data(flow);
  214. if not jwt_data:
  215. return;
  216. payload = jwt_data['payload'];
  217. if 'customerInfo' not in payload:
  218. return;
  219. account = payload['customerInfo']['phone'];
  220. if not account:
  221. return;
  222. if account != '13430389115':
  223. return;
  224. rsp_params = json.loads(response.get_text());
  225. if rsp_params['code'] != 'success':
  226. return;
  227. rsp_data = rsp_params['data'];
  228. sql_activity_query = f'''
  229. CALL UpdateElifeActivities(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s);
  230. ''';
  231. sql_activity_params = [];
  232. sql_award_query = f'''
  233. CALL UpdateElifeActivityAwards(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s);
  234. ''';
  235. sql_award_params = [];
  236. activity_list = rsp_params['data'];
  237. for activity_info in activity_list:
  238. sql_activity_params.append(('1',
  239. activity_info['activityId'], activity_info['activityAlias'], activity_info['outActivityCode'],
  240. activity_info['activityTitle'], activity_info['activityState'], activity_info['activityIcon'],
  241. activity_info['activityLink'], activity_info['activityBanner'], activity_info['subLoginType'],
  242. activity_info['subActivityId'] if 'subActivityId' in activity_info else '', activity_info['activityDesc']));
  243. award_list = activity_info['awardList'];
  244. for award_info in award_list:
  245. # print(award_info)
  246. sql_award_params.append((
  247. award_info['awardId'], award_info['prizeName'], award_info['activityId'],
  248. award_info['prizeId'], award_info['prizeDesc'], award_info['prizeBannerUrl'],
  249. award_info['prizeDescUrl'], award_info['imgUrl'], int(award_info['stockNum']),
  250. float(award_info['price']), award_info['categoryType'], award_info['goodsScene'],
  251. award_info['rechargeType'], int(award_info['useStock']), int(award_info['remainStock']),
  252. int(award_info['cycleStock']), int(award_info['cycleRemainStock']), int(award_info['orderNum']),
  253. award_info['payFlag'], award_info['thirdInfo'], award_info['awardType'],
  254. int(award_info['firstSignAward']), int(award_info['renewSignAward']), award_info['prizeAlias'] if 'prizeAlias' in award_info else '',
  255. award_info['parentAwardId'] if 'parentAwardId' in award_info else ''));
  256. try:
  257. self.check_mysql_connect();
  258. cursor = self.db_conn.cursor();
  259. cursor.executemany(sql_activity_query, sql_activity_params);
  260. cursor.executemany(sql_award_query, sql_award_params);
  261. self.db_conn.commit();
  262. cursor.close();
  263. except pymysql.OperationalError as e:
  264. print(e);
  265. def handle_orderlist(self, flow: http.HTTPFlow):
  266. ctx.log.info('###handle_orderlist###');
  267. request = flow.request;
  268. response = flow.response;
  269. cookies = dict(request.cookies) # 转换cookies格式为dict
  270. # if 'unionToken_interactiveIGoChoose' not in cookies:
  271. # return;
  272. # account = None;
  273. # try:
  274. # jwt_str = cookies['unionToken_interactiveIGoChoose'];
  275. # # payload = jwt.decode(jwt_str, '', algorithms=['HS256'], verify=False, options={'verify_signature':False});
  276. # # info_str = payload.get('customerInfo');
  277. # # 不依赖库,简单方法解析
  278. # jwt_data = Utils.parse_jwt(jwt_str);
  279. # if jwt_data:
  280. # payload = jwt_data['payload'];
  281. # info_str = payload['customerInfo'];
  282. # customer_info = json.loads(info_str);
  283. # account = customer_info['phone'];
  284. # except jwt.PyJWTError as e:
  285. # print('jwt token解析失败');
  286. # else:
  287. # pass
  288. # finally:
  289. # pass
  290. jwt_data = self.get_jwt_token_data(flow);
  291. if not jwt_data:
  292. return;
  293. payload = jwt_data['payload'];
  294. if 'customerInfo' not in payload:
  295. return;
  296. account = payload['customerInfo']['phone'];
  297. if not account:
  298. return;
  299. headers = dict(request.headers);
  300. uuid = headers['UUID'];
  301. authorization = headers['Authorization'];
  302. user_agent = headers['User-Agent'];
  303. market_id = request.query.get('marketId');
  304. event_visitor_id = request.query.get('eventVisitorId');
  305. clientAccount = account if account else '13400000000';
  306. # create_time = '2024-01-01 00:00:00';
  307. create_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S');
  308. capture_code = Utils.generate_random_code(6);
  309. simple_data = OfpayHelper.order_simple_data;
  310. simple_data['prizeDesc'] = capture_code;
  311. simple_data['createTime'] = create_time;
  312. simple_data['endEffectTime'] = create_time;
  313. simple_data['clientAccount'] = clientAccount;
  314. rsp_params = json.loads(response.get_text());
  315. if rsp_params['code'] == 'success':
  316. rsp_data = rsp_params['data'];
  317. rsp_data['list'].insert(0, simple_data);
  318. update_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S');
  319. sql_query = f'''
  320. CALL UpdateElifeAccountData(%s, %s, %s, %s, %s, %s, %s, %s, %s);
  321. ''';
  322. sql_params = (account, uuid, authorization, repr(cookies), user_agent, market_id, event_visitor_id, capture_code , update_time);
  323. try:
  324. self.check_mysql_connect();
  325. cursor = self.db_conn.cursor();
  326. cursor.execute(sql_query, sql_params);
  327. self.db_conn.commit();
  328. cursor.close();
  329. simple_data['prizeName'] = '数据采集成功';
  330. except pymysql.OperationalError as e:
  331. print(e);
  332. simple_data['prizeName'] = '数据采集失败';
  333. simple_data['prizeDesc'] = '';
  334. response.set_text(json.dumps(rsp_params));
  335. sql_activity_params = [('1', 'A923605206137307136', '活动1-首单', 'eCoffee', 'e起喝咖啡(首次)', '2', '', '', 'https://mstatic.ofpay.com/marketing/upload/e4fb2100868347c0bc39cb9ac08ad485.png', 'subChoose', 'A923613706510925824', ''), ('1', 'A923620157585358848', '活动1-首单', 'eTea', 'e起下午茶(首次)', '2', '', '', 'https://mstatic.ofpay.com/marketing/upload/0c9b274ba4ff4f2e81d18fb7db2b15b1.png', 'subChoose', 'A923622289227120640', ''), ('1', 'A1190335340494454784', '活动1-首单', 'eFood', 'e起享美 味', '2', '', '', '', 'subChoose', 'A1190350499677995008', ''), ('1', 'A1190947451528544256', '活动1-首单', 'eSupermarket', 'e起逛超市', '2', '', '', '', 'choose', '', ''), ('1', 'A1190954239447531520', '活动1-首单', 'eTravel', 'e起乐出行', '2', '', '', '', 'subChoose', 'A1190956349283106816', ''), ('1', 'A923939556410261504', '活动1-首单', 'eMovie', 'e起追 热剧', '2', '', '', 'https://mstatic.ofpay.com/marketing/upload/7254fbe94dd041d5b8c63ba4a9a5505e.png', 'choose', '', ''), ('1', 'A923939562252926976', '活动1-首单', 'eBicycle', 'e起骑单车(首次)', '2', '', '', 'https://mstatic.ofpay.com/marketing/upload/c8550391b1324e32b7b537d35523196c.png', 'choose', '', ''), ('1', 'A1091037106664636416', '活动1-首单', 'eOffice', 'e起长知识', '2', '', '', 'https://mstatic.ofpay.com/marketing/upload/1eed1bbb39044cf992a7cdb13d771538.png', 'choose', '', '')]