import hashlib import hmac import json import os.path import time import logging import requests from urllib import parse app_code = '4ca99fa6b56cc2ba' token_env = os.environ.get('TOKEN') header = { 'cred': '', 'User-Agent': 'Skland/1.0.1 (com.hypergryph.skland; build:100001014; Android 31; ) Okhttp/4.11.0', 'Accept-Encoding': 'gzip', 'Connection': 'close' } header_login = { 'User-Agent': 'Skland/1.0.1 (com.hypergryph.skland; build:100001014; Android 31; ) Okhttp/4.11.0', 'Accept-Encoding': 'gzip', 'Connection': 'close' } # 签名请求头一定要这个顺序,否则失败 # timestamp是必填的,其它三个随便填,不要为none即可 header_for_sign = { 'platform': '', 'timestamp': '', 'dId': '', 'vName': '' } # 签到url sign_url = "https://zonai.skland.com/api/v1/game/attendance" # 绑定的角色url binding_url = "https://zonai.skland.com/api/v1/game/player/binding" # 使用token获得认证代码 grant_code_url = "https://as.hypergryph.com/user/oauth2/v2/grant" # 使用认证代码获得cred cred_code_url = "https://zonai.skland.com/api/v1/user/auth/generate_cred_by_code" def generate_signature(token: str, path, body_or_query): """ 获得签名头 接口地址+方法为Get请求?用query否则用body+时间戳+ 请求头的四个重要参数(dId,platform,timestamp,vName).toJSON() 将此字符串做HMAC加密,算法为SHA-256,密钥token为请求cred接口会返回的一个token值 再将加密后的字符串做MD5即得到sign :param token: 拿cred时候的token :param path: 请求路径(不包括网址) :param body_or_query: 如果是GET,则是它的query。POST则为它的body :return: 计算完毕的sign """ # 总是说请勿修改设备时间,怕不是yj你的服务器有问题吧,所以这里特地-2 t = str(int(time.time()) - 2) token = token.encode('utf-8') header_ca = json.loads(json.dumps(header_for_sign)) header_ca['timestamp'] = t header_ca_str = json.dumps(header_ca, separators=(',', ':')) s = path + body_or_query + t + header_ca_str hex_s = hmac.new(token, s.encode('utf-8'), hashlib.sha256).hexdigest() md5 = hashlib.md5(hex_s.encode('utf-8')).hexdigest().encode('utf-8').decode('utf-8') return md5, header_ca def get_sign_header(url: str, method, body, old_header, local_s_token): h = json.loads(json.dumps(old_header)) p = parse.urlparse(url) if method.lower() == 'get': h['sign'], header_ca = generate_signature(local_s_token, p.path, p.query) else: h['sign'], header_ca = generate_signature(local_s_token, p.path, json.dumps(body)) for i in header_ca: h[i] = header_ca[i] return h def get_cred_by_token(token): grant_code = get_grant_code(token) return get_cred(grant_code) def get_grant_code(token): response = requests.post(grant_code_url, json={ 'appCode': app_code, 'token': token, 'type': 0 }, headers=header_login) resp = response.json() if response.status_code != 200: raise Exception(f'获得认证代码失败:{resp}') if resp.get('status') != 0: raise Exception(f'获得认证代码失败:{resp["msg"]}') return resp['data']['code'] def get_cred(grant): resp = requests.post(cred_code_url, json={ 'code': grant, 'kind': 1 }, headers=header_login).json() if resp['code'] != 0: raise Exception(f'获得cred失败:{resp["message"]}') return resp['data'] def get_binding_list(s_token): error_message, error_code = 'Success', 0 result_list = [] header_dict = get_sign_header(binding_url, 'get', None, header, s_token) resp = requests.get(binding_url, headers=header_dict).json() if resp['code'] != 0: error_message = f"请求角色列表出现问题:{resp['message']}" error_code = -1 return error_message, error_code, [] for i in resp['data']['list']: if i.get('appCode') != 'arknights': continue result_list.extend(i.get('bindingList')) return error_message, error_code, result_list def single_sign(cred_resp): s_token = cred_resp['token'] header['cred'] = cred_resp['cred'] msg, code, characters = get_binding_list(s_token) if code != 0 or not characters: return msg, code content = characters[0] body = {'gameId': 1, 'uid': content.get('uid')} resp = requests.post(sign_url, headers=get_sign_header(sign_url, 'post', body, header,s_token), json=body).json() if resp['code'] != 0: msg = f'角色{content.get("nickName")}({content.get("channelName")})签到失败了!原因:{resp.get("message")}' code = -1 return msg, code awards = resp['data']['awards'] for j in awards: res = j['resource'] msg = f'角色{content.get("nickName")}({content.get("channelName")})签到成功,获得{res["name"]}×{j.get("count") or 1}' code = 0 return msg, code def new_start(): result_list = [] token_list = ['fqyRkfJrLlkuax8SzFffxc0W', 'i//Ozb2bFsXjxF9ZKgAgVi6K'] for i in token_list: try: credit_dict = get_cred_by_token(i) msg, code = single_sign(credit_dict) except Exception as ex: print(f'签到失败,原因:{str(ex)}') print("签到完成!") if __name__ == '__main__': new_start()