在大佬的帖子下找到的ID 总结了一下,运行签到有点,有大佬研究过吗 帮忙看一下 签到积分?
https://linux.do/t/topic/210710
import argparse
import base64
import hashlib
import json
import os
import sys
import time
import uuid
from dataclasses import dataclass
from typing import Any, Dict
from __future__ import annotations
try:
import requests
except ImportError as exc:
raise SystemExit(
"缺少依赖 requests,请先安装: pip install requests"
) from exc
try:
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
except ImportError as exc:
raise SystemExit(
"缺少依赖 pycryptodome,请先安装: pip install pycryptodome"
) from exc
BASE_URL = "https://mina.bydoceanauto.com/Forward2Rights/integral"
APP_KEY = "seaMinaApi"
DEFAULT_AES_KEY = "5949577785312731"
DEFAULT_AES_IV = "uDEHPGzSIHIWBlNT"
@dataclass
class BydConfig:
session_id: str
service_dir: str
aes_key: str = DEFAULT_AES_KEY
aes_iv: str = DEFAULT_AES_IV
app_key: str = APP_KEY
timeout: int = 20
verify_ssl: bool = True
checksum: str | None = None
nonce: str | None = None
curtime: str | None = None
def aes_cbc_encrypt_b64(plain_text: str, key: str, iv: str) -> str:
cipher = AES.new(key.encode("utf-8"), AES.MODE_CBC, iv.encode("utf-8"))
encrypted = cipher.encrypt(pad(plain_text.encode("utf-8"), AES.block_size))
return base64.b64encode(encrypted).decode("utf-8")
def aes_cbc_decrypt_b64(cipher_text_b64: str, key: str, iv: str) -> str:
raw = base64.b64decode(cipher_text_b64)
cipher = AES.new(key.encode("utf-8"), AES.MODE_CBC, iv.encode("utf-8"))
plain = unpad(cipher.decrypt(raw), AES.block_size)
return plain.decode("utf-8")
def build_checksum(payload_b64: str, cfg: BydConfig) -> str:
"""
兜底签名策略:
1) 优先使用显式传入 checksum
2) 否则使用 sha256(加密后的 body 字符串)
"""
if cfg.checksum:
return cfg.checksum
return hashlib.sha256(payload_b64.encode("utf-8")).hexdigest()
def make_headers(payload_b64: str, cfg: BydConfig) -> Dict[str, str]:
nonce = cfg.nonce or uuid.uuid4().hex[:16]
curtime = cfg.curtime or str(int(time.time()))
headers = {
"Host": "mina.bydoceanauto.com",
"Connection": "keep-alive",
"x-clienttraceid": f"mina-{uuid.uuid4()}",
"Nonce": nonce,
"User-Agent": (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 "
"MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI "
"MiniProgramEnv/Windows WindowsWechat/WMPF "
"WindowsWechat(0x63090c0f)XWEB/11275"
),
"Content-Type": "application/json",
"Curtime": curtime,
"xweb_xhr": "1",
"Checksum": build_checksum(payload_b64, cfg),
"Appkey": cfg.app_key,
"Accept": "*/*",
"Referer": "https://servicewechat.com/wxf62054ec313d6f53/72/page-frame.html",
}
return headers
def build_url(service_dir: str) -> str:
return f"{BASE_URL}?&serviceDir={service_dir}"
def parse_json_maybe(text: str) -> Any:
try:
return json.loads(text)
except Exception:
return text
def call_api(cfg: BydConfig, payload_obj: Dict[str, Any]) -> Dict[str, Any]:
plain = json.dumps(payload_obj, ensure_ascii=False, separators=(",", ":"))
body_encrypted = aes_cbc_encrypt_b64(plain, cfg.aes_key, cfg.aes_iv)
body_json = json.dumps(body_encrypted, ensure_ascii=False)
headers = make_headers(body_encrypted, cfg)
url = build_url(cfg.service_dir)
resp = requests.post(
url=url,
headers=headers,
data=body_json.encode("utf-8"),
timeout=cfg.timeout,
verify=cfg.verify_ssl,
)
result: Dict[str, Any] = {
"url": url,
"status_code": resp.status_code,
"headers_sent": headers,
"request_body_plain": plain,
"request_body_encrypted": body_encrypted,
"response_raw": resp.text,
}
if resp.ok:
raw = parse_json_maybe(resp.text)
if isinstance(raw, str):
# 部分接口会直接返回加密字符串
try:
result["response_decrypted"] = aes_cbc_decrypt_b64(raw, cfg.aes_key, cfg.aes_iv)
except Exception:
pass
else:
result["response_json"] = raw
if isinstance(raw, str):
try:
result["response_decrypted"] = aes_cbc_decrypt_b64(raw, cfg.aes_key, cfg.aes_iv)
except Exception:
pass
elif isinstance(raw, dict):
# 常见结构 {"data":"xxxx"} 或 {"result":"xxxx"}
encrypted_field = None
for k in ("data", "result", "payload"):
if isinstance(raw.get(k), str):
encrypted_field = raw[k]
break
if encrypted_field:
try:
result["response_decrypted"] = aes_cbc_decrypt_b64(
encrypted_field, cfg.aes_key, cfg.aes_iv
)
except Exception:
pass
return result
def read_payload_from_env(session_id: str) -> Dict[str, Any]:
payload = os.getenv("BYD_PAYLOAD_JSON", "").strip()
if payload:
try:
return json.loads(payload)
except Exception as exc:
raise SystemExit(f"BYD_PAYLOAD_JSON 不是合法 JSON: {exc}") from exc
return {"session_id": session_id}
def build_config(args: argparse.Namespace) -> BydConfig:
session_id = os.getenv("BYD_SESSION_ID", "").strip()
if not session_id:
raise SystemExit("请先设置环境变量 BYD_SESSION_ID")
service_dir = args.service_dir
if args.action == "rank" and not args.service_dir_set:
service_dir = "/Experience/User/ranks"
if args.action == "sign" and not args.service_dir_set:
service_dir = "/Experience/User/signIn"
return BydConfig(
session_id=session_id,
service_dir=service_dir,
aes_key=os.getenv("BYD_AES_KEY", DEFAULT_AES_KEY),
aes_iv=os.getenv("BYD_AES_IV", DEFAULT_AES_IV),
app_key=os.getenv("BYD_APPKEY", APP_KEY),
timeout=args.timeout,
verify_ssl=not args.insecure,
checksum=os.getenv("BYD_CHECKSUM", "").strip() or None,
nonce=os.getenv("BYD_NONCE", "").strip() or None,
curtime=os.getenv("BYD_CURTIME", "").strip() or None,
)
def main() -> None:
parser = argparse.ArgumentParser(description="BYD 小程序接口签到脚本(手动 session 版)")
parser.add_argument("--action", choices=["rank", "sign"], default="rank")
parser.add_argument("--service-dir", default="/Experience/User/ranks")
parser.add_argument("--timeout", type=int, default=20)
parser.add_argument("--insecure", action="store_true", help="关闭 SSL 证书校验")
args = parser.parse_args()
args.service_dir_set = "--service-dir" in sys.argv
cfg = build_config(args)
payload_obj = read_payload_from_env(cfg.session_id)
try:
result = call_api(cfg, payload_obj)
except requests.RequestException as exc:
raise SystemExit(f"请求失败: {exc}") from exc
print(json.dumps(result, ensure_ascii=False, indent=2))
# 常见成功提示,方便脚本化判断
text = json.dumps(result, ensure_ascii=False)
if any(k in text for k in ("签到成功", "已签到", "already")):
raise SystemExit(0)
if result.get("status_code", 500) >= 400:
raise SystemExit(2)
if __name__ == "__main__":
main()