├── requirements.txt ├── .gitattributes ├── docker-compose.yml ├── docker_entrypoint.sh ├── Dockerfile ├── install.sh ├── app.py └── signapi.py /requirements.txt: -------------------------------------------------------------------------------- 1 | Flask==2.0.1 2 | werkzeug==2.0.1 3 | requests==2.26.0 4 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | WeChatSetup_3.2.1.121.exe filter=lfs diff=lfs merge=lfs -text 2 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "2.0" 2 | services: 3 | jd_sign: 4 | image: jd_sign:latest 5 | container_name: jd_sign 6 | restart: always 7 | hostname: jd_sign 8 | ports: 9 | - 8840:8840 10 | -------------------------------------------------------------------------------- /docker_entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | #获取配置的自定义参数 5 | if [ -n "$1" ]; then 6 | run_cmd=$1 7 | fi 8 | 9 | ( 10 | if [ -f "/jd_sign/pull.lock" ]; then 11 | echo "存在更新锁定文件,跳过git pull操作..." 12 | else 13 | echo "设定远程仓库地址..." 14 | cd /jd_sign 15 | git remote set-url origin "$REPO_URL" 16 | git reset --hard 17 | echo "git pull拉取最新代码..." 18 | git -C /jd_sign pull --rebase 19 | fi 20 | ) || exit 0 21 | 22 | 23 | echo "--------------------------------------------------开启python service---------------------------------------------------" 24 | 25 | echo "启动python service服务..." 26 | 27 | python3 /jd_sign/signapi.py 28 | 29 | echo "python service服务任务执行结束。" 30 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.12-rc-alpine3.16 2 | LABEL AUTHOR="hc" \ 3 | TAG=V1 \ 4 | VERSION=1.0.0 5 | 6 | ENV REPO_URL=https://github.com/hyyds/sign.git \ 7 | REPO_BRANCH=main 8 | 9 | RUN set -ex \ 10 | && apk update \ 11 | && apk upgrade \ 12 | && apk add --no-cache bash tzdata git moreutils curl jq openssh-client \ 13 | && rm -rf /var/cache/apk/* \ 14 | && ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ 15 | && echo "Asia/Shanghai" > /etc/timezone \ 16 | && git clone -b $REPO_BRANCH $REPO_URL /jd_sign \ 17 | && cd /jd_sign\ 18 | && pip3 install flask -i https://mirrors.ustc.edu.cn/pypi/web/simple \ 19 | && cp /jd_sign/docker_entrypoint.sh /usr/local/bin \ 20 | && chmod +x /usr/local/bin/docker_entrypoint.sh 21 | 22 | WORKDIR /jd_sign 23 | 24 | ENTRYPOINT ["docker_entrypoint.sh"] 25 | 26 | #CMD ["pm2-runtime","/jd_bus/ecosystem.config.js"] 27 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | /sbin/iptables -I INPUT -p tcp --dport 8840 -j ACCEPT 3 | echo 4 | echo "第一步:下载docker脚本" 5 | echo 6 | 7 | curl https://get.docker.com/ > install-docker.sh 8 | 9 | echo 10 | echo "已下载docker安装脚本" 11 | echo 12 | 13 | echo 14 | echo "第二步:docker安装" 15 | echo 16 | 17 | sh install-docker.sh 18 | 19 | echo 20 | echo "docker安装完成" 21 | 22 | echo 23 | echo "第三步:设置docker开机自启动" 24 | echo 25 | 26 | systemctl enable docker 27 | systemctl start docker 28 | 29 | echo 30 | echo "docker开机自启动设置完成" 31 | echo 32 | 33 | echo 34 | echo "第四步:安装docker-compose" 35 | echo 36 | 37 | curl -L https://get.daocloud.io/docker/compose/releases/download/1.32.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose 38 | 39 | chmod +x /usr/local/bin/docker-compose 40 | 41 | echo 42 | echo "docker-compose安装完成" 43 | echo 44 | 45 | echo 46 | echo "第五步:构建本地镜像文件" 47 | echo 48 | 49 | docker image build ./ -t jd_sign:latest 50 | 51 | echo 52 | echo "本地镜像文件构建成功" 53 | echo 54 | 55 | echo 56 | echo "第六步:使用docker-compose启动容器" 57 | echo 58 | 59 | docker-compose up -d 60 | 61 | echo 62 | echo "容器启动成功" 63 | echo 64 | 65 | 66 | echo 67 | echo "第七步:输出容器日志" 68 | echo 69 | 70 | docker logs -f jd_sign 71 | 72 | echo 73 | echo "容器日志输出成功" 74 | echo 75 | 76 | 77 | echo 78 | echo "第八步:退出程序" 79 | echo 80 | 81 | exit 82 | 83 | 84 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | import flask 2 | import json 3 | import os 4 | from flask import request 5 | import base64 6 | import hashlib 7 | import time 8 | import uuid 9 | import logging 10 | from urllib.parse import quote 11 | from requests import post, get 12 | from urllib3 import disable_warnings 13 | 14 | disable_warnings() 15 | 16 | log = logging.getLogger('werkzeug') 17 | log.setLevel(logging.ERROR) 18 | 19 | os.environ['FLASK_ENV']="development" 20 | 21 | server = flask.Flask(__name__) 22 | 23 | 24 | def bytes2bin(bytes): 25 | arr = [] 26 | for v in [m for m in bytes]: 27 | arr.append( 28 | [(v & 128) >> 7, (v & 64) >> 6, (v & 32) >> 5, (v & 16) >> 4, (v & 8) >> 3, (v & 4) >> 2, (v & 2) >> 1, v & 1]) 29 | return [i for j in arr for i in j] 30 | 31 | 32 | def bin2bytes(arr): 33 | length = len(arr) // 8 34 | arr1 = [0 for _ in range(length)] 35 | for j in range(length): 36 | arr1[j] = arr[j * 8] << 7 | arr[j * 8 + 1] << 6 | arr[j * 8 + 2] << 5 | arr[j * 8 + 3] << 4 | arr[j * 8 + 4] << 3 | arr[j * 8 + 5] << 2 | arr[j * 8 + 6] << 1 | arr[j * 8 + 7] 37 | return bytes(arr1) 38 | 39 | 40 | def sub_12ECC(input): 41 | arr = [0x37, 0x92, 0x44, 0x68, 0xA5, 0x3D, 0xCC, 0x7F, 0xBB, 0xF, 0xD9, 0x88, 0xEE, 0x9A, 0xE9, 0x5A] 42 | key2 = b"80306f4370b39fd5630ad0529f77adb6" 43 | arr1 = [0 for _ in range(len(input))] 44 | for i in range(len(input)): 45 | r0 = int(input[i]) 46 | r2 = arr[i & 0xf] 47 | r4 = int(key2[i & 7]) 48 | r0 = r2 ^ r0 49 | r0 = r0 ^ r4 50 | r0 = r0 + r2 51 | r2 = r2 ^ r0 52 | r1 = int(key2[i & 7]) 53 | r2 = r2 ^ r1 54 | arr1[i] = r2 & 0xff 55 | return bytes(arr1) 56 | 57 | 58 | def sub_10EA4(input): 59 | table = [[0, 0], [1, 4], [2, 61], [3, 15], [4, 56], [5, 40], [6, 6], [7, 59], [8, 62], [9, 58], [10, 17], [11, 2], [12, 12], [13, 8], [14, 32], [15, 60], [16, 13], [17, 45], [18, 34], [19, 14], [20, 36], [21, 21], [22, 22], [23, 39], [24, 23], [25, 25], [26, 26], [27, 20], [28, 1], [29, 33], [30, 46], [31, 55], [32, 35], [33, 24], [34, 57], [35, 19], [36, 53], [37, 37], [38, 38], [39, 5], [40, 30], [41, 41], [42, 42], [43, 18], [44, 47], [45, 27], [46, 9], [47, 44], [48, 51], [49, 7], [50, 49], [51, 63], [52, 28], [53, 43], [54, 54], [55, 52], [56, 31], [57, 10], [ 58, 29], [59, 11], [60, 3], [61, 16], [62, 50], [63, 48]] 60 | arr = bytes2bin(input) 61 | arr1 = [0 for _ in range(len(arr))] 62 | for i in range(len(table)): 63 | arr1[table[i][1]] = arr[table[i][0]] 64 | return bin2bytes(arr1) 65 | 66 | 67 | def sub_4B7C(input): 68 | table = [[0, 6, 0, 1], [1, 4, 1, 0], [2, 5, 0, 1], [3, 0, 0, 1], [4, 2, 0, 1], [5, 3, 0, 1], [6, 1, 1, 0], [7, 7, 0, 1]] 69 | arr = bytes2bin(input) 70 | arr1 = [0 for _ in range(8)] 71 | for i in range(8): 72 | if arr[i] == 0: 73 | arr1[table[i][1]] = table[i][2] 74 | else: 75 | arr1[table[i][1]] = table[i][3] 76 | return bin2bytes(arr1) 77 | 78 | 79 | def sub_10D70(input): 80 | if len(input) == 1: 81 | return sub_4B7C(input) 82 | return b"" 83 | 84 | 85 | def sub_12510(input): 86 | output = bytes() 87 | for i in range(len(input) // 8): 88 | output += sub_10EA4(input[i * 8:(i + 1) * 8]) 89 | output += sub_10D70(input[-(len(input) % 8):]) 90 | return output 91 | 92 | 93 | def sub_126AC(input, random1, random2): 94 | arr = [0, 1, 2] 95 | if random2 == 1: 96 | arr = [1, 2, 0] 97 | if random2 == 2: 98 | arr = [2, 0, 1] 99 | version = arr[random1] 100 | if version == 0: 101 | return sub_12510(input) 102 | if version == 2: 103 | return sub_12ECC(input) 104 | if version == 1: 105 | print("错误的类型") 106 | 107 | 108 | def get_sign(functionId, body, uuid, client, clientVersion): 109 | st = str(int(time.time() * 1000)) 110 | random1, random2 = 2, 0 111 | sv = f"{random1}{random2}" 112 | string = f"functionId={functionId}&body={body}&uuid={uuid}&client={client}&clientVersion={clientVersion}&st={st}&sv=1{sv}" 113 | ret_bytes = sub_126AC(str.encode(string), random1, random2) 114 | sign = f"client={client}&clientVersion={clientVersion}&uuid={uuid}&st={st}&sign={hashlib.md5(base64.b64encode(ret_bytes)).hexdigest()}&sv=1{sv}" 115 | return sign 116 | 117 | 118 | def get_cookie(sign, body, key): 119 | url = f"https://api.m.jd.com/client.action?functionId=genToken&{sign}" 120 | headers = { 121 | "cookie": key, 122 | 'user-agent': "JD4iPhone/167774 (iPhone; iOS 14.6; Scale/2.00)", 123 | 'accept-language': 'zh-Hans-CN;q=1, en-CN;q=0.9', 124 | 'content-type': 'application/x-www-form-urlencoded;' 125 | } 126 | try: 127 | res = post(url, headers=headers, data=body, verify=False) 128 | token = res.json()['tokenKey'] 129 | except Exception as error: 130 | return False 131 | url = 'https://un.m.jd.com/cgi-bin/app/appjmp' 132 | params = { 133 | 'tokenKey': token, 134 | 'to': 'https://plogin.m.jd.com/cgi-bin/m/thirdapp_auth_page', 135 | 'client_type': 'android', 136 | 'appid': 879, 137 | 'appup_type': 1, 138 | } 139 | try: 140 | res = get(url=url, params=params, verify=False, allow_redirects=False).cookies.get_dict() 141 | except Exception as error: 142 | return False 143 | if "app_open" in res['pt_key']: 144 | cookie = f"pt_key={res['pt_key']};pt_pin={res['pt_pin']};" 145 | return cookie 146 | else: 147 | return False 148 | 149 | 150 | @server.route('/getSign', methods=['post']) 151 | def main(): 152 | fn = request.values.get('fn') or request.get_json()['fn'] 153 | body = request.values.get('body') or request.get_json()['body'] 154 | wskey = request.values.get('wskey') 155 | if fn: 156 | sign = get_sign(fn, body, "".join(str(uuid.uuid4()).split("-")), "apple", "11.1.4") 157 | res = {"code": 200, "data": {"sign": f'body={quote(body)}&{sign}'}} 158 | else: 159 | res = {"code": 400, "data": "请传入url参数!"} 160 | if fn: 161 | print(res) 162 | return json.dumps(res, ensure_ascii=False) 163 | if wskey and "pin" in wskey and "wskey" in wskey: 164 | url = "https://plogin.m.jd.com/jd-mlogin/static/html/appjmp_blank.html" 165 | body = '{"to":"%s"}' % url 166 | sign = get_sign("genToken", body, "".join(str(uuid.uuid4()).split("-")), "apple", "11.1.4") 167 | body = f'body={quote(body)}' 168 | cookie = get_cookie(sign, body, wskey) 169 | if cookie: 170 | res = {"code": 200, "data": { "cookie": cookie}} 171 | print(res['data']['wskey']) 172 | else: 173 | res = {"code": 400, "data": "获取cookie失败!"} 174 | else: 175 | res = {"code": 400, "data": "请传入正确的wskey值!"} 176 | if wskey: 177 | print(res) 178 | return json.dumps(res, ensure_ascii=False) 179 | 180 | 181 | if __name__ == '__main__': 182 | server.run(host='127.0.0.1', port=9000, debug=False) 183 | -------------------------------------------------------------------------------- /signapi.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf8 -*- 2 | import base64 3 | import hashlib 4 | import json 5 | import random 6 | import time 7 | from urllib.parse import quote 8 | 9 | import flask 10 | 11 | server = flask.Flask(__name__) 12 | 13 | 14 | # 食用方法 15 | # 0. 容器内执行 16 | # 1. pip3 install flask -i https://mirrors.ustc.edu.cn/pypi/web/simple 17 | # 2. pm2 start signapi.py -x --interpreter python3 18 | # 3. curl http://127.0.0.1:17840/sign ,确定sign正常运行,有结果输出 19 | # 4. 添加变量 export M_API_SCAN_SIGN_URL="http://127.0.0.1:17840/sign" 20 | # 5. 查看日志 pm2 log signapi 21 | 22 | 23 | def bytes2bin(bytes): 24 | arr = [] 25 | for v in [m for m in bytes]: 26 | arr.append( 27 | [(v & 128) >> 7, (v & 64) >> 6, (v & 32) >> 5, (v & 16) >> 4, (v & 8) >> 3, (v & 4) >> 2, (v & 2) >> 1, 28 | v & 1]) 29 | print([i for j in arr for i in j]) 30 | return [i for j in arr for i in j] 31 | 32 | 33 | def bin2bytes(arr): 34 | length = len(arr) // 8 35 | arr1 = [0 for i in range(length)] 36 | for j in range(length): 37 | arr1[j] = arr[j * 8] << 7 | arr[j * 8 + 1] << 6 | arr[j * 8 + 2] << 5 | arr[j * 8 + 3] << 4 | arr[ 38 | j * 8 + 4] << 3 | arr[j * 8 + 5] << 2 | arr[j * 8 + 6] << 1 | arr[j * 8 + 7] 39 | print(bytes(arr1)) 40 | return bytes(arr1) 41 | 42 | 43 | def sub_10EA4(input): 44 | table = [[0, 0], [1, 4], [2, 61], [3, 15], [4, 56], [5, 40], [6, 6], [7, 59], [8, 62], [9, 58], [10, 17], [11, 2], 45 | [12, 12], [13, 8], [14, 32], [15, 60], [16, 13], [17, 45], [18, 34], [19, 14], [20, 36], [21, 21], 46 | [22, 22], [23, 39], [24, 23], [25, 25], [26, 26], [27, 20], [28, 1], [29, 33], [30, 46], [31, 55], 47 | [32, 35], [33, 24], [34, 57], [35, 19], [36, 53], [37, 37], [38, 38], [39, 5], [40, 30], [41, 41], 48 | [42, 42], [43, 18], [44, 47], [45, 27], [46, 9], [47, 44], [48, 51], [49, 7], [50, 49], [51, 63], [52, 28], 49 | [53, 43], [54, 54], [55, 52], [56, 31], [57, 10], [58, 29], [59, 11], [60, 3], [61, 16], [62, 50], 50 | [63, 48]] 51 | arr = bytes2bin(input) 52 | arr1 = [0 for i in range(len(arr))] 53 | for i in range(len(table)): 54 | arr1[table[i][1]] = arr[table[i][0]] 55 | print(arr1) 56 | return bin2bytes(arr1) 57 | 58 | 59 | def sub_4B7C(input): 60 | table = [[0, 6, 0, 1], [1, 4, 1, 0], [2, 5, 0, 1], [3, 0, 0, 1], [4, 2, 0, 1], [5, 3, 0, 1], [6, 1, 1, 0], 61 | [7, 7, 0, 1]] 62 | arr = bytes2bin(input) 63 | arr1 = [0 for i in range(8)] 64 | for i in range(8): 65 | if arr[i] == 0: 66 | arr1[table[i][1]] = table[i][2] 67 | else: 68 | arr1[table[i][1]] = table[i][3] 69 | print(arr1) 70 | return bin2bytes(arr1) 71 | 72 | 73 | def sub_10D70(input): 74 | if len(input) == 1: 75 | return sub_4B7C(input) 76 | 77 | 78 | def sub_v1(input): 79 | output = bytes() 80 | for i in range(len(input) // 8): 81 | output += sub_10EA4(input[i * 8:(i + 1) * 8]) 82 | output += sub_10D70(input[-(len(input) % 8):]) 83 | return output 84 | 85 | 86 | def sub_v2(input): 87 | arr = [0x37, 0x92, 0x44, 0x68, 0xA5, 0x3D, 0xCC, 0x7F, 0xBB, 0xF, 0xD9, 0x88, 0xEE, 0x9A, 0xE9, 0x5A] 88 | key2 = b"80306f4370b39fd5630ad0529f77adb6" 89 | arr1 = [0 for _ in range(len(input))] 90 | for i in range(len(input)): 91 | r0 = int(input[i]) 92 | r2 = arr[i & 0xf] 93 | r4 = int(key2[i & 7]) 94 | r0 = r2 ^ r0 95 | r0 = r0 ^ r4 96 | r0 = r0 + r2 97 | r2 = r2 ^ r0 98 | r1 = int(key2[i & 7]) 99 | r2 = r2 ^ r1 100 | arr1[i] = r2 & 0xff 101 | return bytes(arr1) 102 | 103 | 104 | def sub_126AC(input, random1, random2): 105 | arr = [0, 1, 2] 106 | if random2 == 1: 107 | arr = [1, 2, 0] 108 | if random2 == 2: 109 | arr = [2, 0, 1] 110 | version = arr[random1] 111 | if version == 0: 112 | return sub_v1(input) 113 | if version == 2: 114 | return sub_v2(input) 115 | 116 | 117 | def base64Encode(string): 118 | oldBin = "" 119 | tempStr = [] 120 | result = "" 121 | base64_list = 'KLMNOPQRSTABCDEFGHIJUVWXYZabcdopqrstuvwxefghijklmnyz0123456789+/' 122 | for ch in string: 123 | oldBin += "{:08}".format(int(str(bin(ord(ch))).replace("0b", ""))) 124 | for i in range(0, len(oldBin), 6): 125 | tempStr.append("{:<06}".format(oldBin[i:i + 6])) 126 | for item in tempStr: 127 | result = result + base64_list[int(item, 2)] 128 | if len(result) % 4 == 2: 129 | result += "==" 130 | elif len(result) % 4 == 3: 131 | result += "=" 132 | return result 133 | 134 | 135 | def base64Decode(string): 136 | result = [] 137 | string = string.strip("=") 138 | binstr = "" 139 | bin6list = [] 140 | bin8list = [] 141 | base64_list = "KLMNOPQRSTABCDEFGHIJUVWXYZabcdopqrstuvwxefghijklmnyz0123456789+/" 142 | for ch in string: 143 | bin6list.append("{:>06}".format(str(bin(base64_list.index(ch)).replace("0b", "")))) 144 | binstr = "".join(bin6list) 145 | for i in range(0, len(binstr), 8): 146 | bin8list.append(binstr[i:i + 8]) 147 | for item in range(len(bin8list) - 1): 148 | result.append(chr(int(bin8list[item], 2))) 149 | return "".join(result) 150 | 151 | 152 | def get_sign(functionId, body, uuid, client, clientVersion): 153 | st = str(int(time.time()) * 1000) 154 | version = [[0, 2], [1, 1], [2, 0]] 155 | r1r2 = random.choice(version) 156 | r1 = r1r2[0] 157 | r2 = r1r2[1] 158 | sv = "1%s%s" % (r1, r2) 159 | input = "functionId=%s&body=%s&uuid=%s&client=%s&clientVersion=%s&st=%s&sv=%s" % ( 160 | functionId, body, uuid, client, clientVersion, st, sv) 161 | ret_bytes = sub_126AC(str.encode(input), r1, r2) 162 | sign = hashlib.md5(base64.b64encode(ret_bytes)).hexdigest() 163 | return sv, st, sign 164 | 165 | 166 | def task(func_id, body_json): 167 | body_str = (body_json).strip() 168 | client = "android" 169 | client_version = "10.4.0" 170 | uuid = ''.join(random.sample('0123456789abcdef0123456789abcdef0123456789abcdef', 40)) 171 | d_model = random.choice( 172 | ["HUAWEI(NOH-AN00)", "Xiaomi(MI 9 Transparent Edition)", "Meizu(16T)", "HTC U-3w", "Redmi K20 Pro Premium Edition"]) 173 | osVersion = random.choice(["10", "11", "12"]) 174 | area = ''.join(random.sample('0123456789', 2)) + '_' + ''.join(random.sample('0123456789', 4)) + '_' + ''.join( 175 | random.sample('0123456789', 5)) + '_' + ''.join(random.sample('0123456789', 4)) 176 | wifiBssid = "TP_LINK_".join(random.sample('0123456789ABCDEFG', 6)) 177 | screen = random.choice(["640x1136", "750x1334", "1080x1920"]) 178 | randomeid = ''.join(random.sample('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', 20)) 179 | eid = f'eidAaf8081218as20a2GM${randomeid}7FnfQYOecyDYLcd0rfzm3Fy2ePY4UJJOeV0Ub840kG8C7lmIqt3DTlc11fB/s4qsAP8gtPTSoxu' 180 | ext = quote('{"prstate":"0","pvcStu":"1"}') 181 | 182 | sv, st, sign = get_sign(func_id, body_str, uuid, client, client_version) 183 | 184 | ep = json.dumps({ 185 | "hdid": "JM9F1ywUPwflvMIpYPok0tt5k9kW4ArJEU3lfLhxBqw=", 186 | "ts": st, 187 | "ridx": -1, 188 | "cipher": {"screen": base64Encode(screen), "wifiBssid": base64Encode(wifiBssid), "osVersion": base64Encode(osVersion), 189 | "area": base64Encode(area), "openudid": base64Encode(uuid), "uuid": base64Encode(uuid)}, 190 | "ciphertype": 5, 191 | "version": "1.0.3", 192 | "appname": "com.360buy.jdmobile", 193 | }).replace(" ", "") 194 | 195 | body_str = quote(body_str) 196 | ep = quote(ep) 197 | data_str = f"body={body_str}&build=168069&client={client}&clientVersion={client_version}&d_brand=android&d_model={d_model}&ef=1&eid={eid}&ep={ep}&ext={ext}&isBackground=N&joycious=124&lang=zh_CN&networkType=wifi&networklibtype=JDNetworkBaseAF&partner=android&rfs=0000&scope=11&st={st}&sv={sv}&sign={sign}" 198 | return {"fn": func_id, "body": data_str} 199 | 200 | 201 | @server.route('/sign', methods=['post']) 202 | def sign(): 203 | try: 204 | data = flask.request.data 205 | data = json.loads(data.decode('utf-8')) 206 | data = task(data['fn'], json.dumps(data['body'])) 207 | return data 208 | except Exception as e: 209 | print(e) 210 | return 'sign error' 211 | 212 | 213 | if __name__ == '__main__': 214 | server.run(host='0.0.0.0', port=8840) 215 | --------------------------------------------------------------------------------