Initial commit: Add maimaiDX API web application with AimeDB scanning and logging features
This commit is contained in:
113
backend/API_AuthLiteDelivery.py
Normal file
113
backend/API_AuthLiteDelivery.py
Normal file
@@ -0,0 +1,113 @@
|
||||
# All.Net AuthLite 更新获取
|
||||
|
||||
from Crypto.Cipher import AES
|
||||
from Crypto.Util.Padding import pad, unpad
|
||||
import httpx
|
||||
from loguru import logger
|
||||
from urllib.parse import parse_qs
|
||||
import configparser as ini
|
||||
|
||||
LITE_AUTH_KEY = bytes(
|
||||
[47, 63, 106, 111, 43, 34, 76, 38, 92, 67, 114, 57, 40, 61, 107, 71]
|
||||
)
|
||||
LITE_AUTH_IV = bytes.fromhex("00000000000000000000000000000000")
|
||||
|
||||
|
||||
def auth_lite_encrypt(plaintext: str) -> bytes:
|
||||
# 构造数据:16字节头 + 16字节0前缀 + 明文
|
||||
content = bytes(32) + plaintext.encode("utf-8")
|
||||
data = content
|
||||
# 填充并加密
|
||||
padded_data = pad(data, AES.block_size)
|
||||
cipher = AES.new(LITE_AUTH_KEY, AES.MODE_CBC, LITE_AUTH_IV)
|
||||
return cipher.encrypt(padded_data)
|
||||
|
||||
|
||||
def auth_lite_decrypt(ciphertext: bytes) -> str:
|
||||
# 解密并去除填充
|
||||
cipher = AES.new(LITE_AUTH_KEY, AES.MODE_CBC, LITE_AUTH_IV)
|
||||
decrypted_data = unpad(cipher.decrypt(ciphertext), AES.block_size)
|
||||
# 提取内容并解码
|
||||
content = decrypted_data[16:] # 去除头部的16字节
|
||||
return content.decode("utf-8").strip()
|
||||
|
||||
|
||||
def getRawDelivery(title_ver: str = "1.51"):
|
||||
encrypted = auth_lite_encrypt(
|
||||
f"title_id=SDGB&title_ver={title_ver}&client_id=A63E01C2805"
|
||||
)
|
||||
r = httpx.post(
|
||||
"http://at.sys-allnet.cn/net/delivery/instruction",
|
||||
data=encrypted,
|
||||
headers={"User-Agent": "SDGB;Windows/Lite", "Pragma": "DFI"},
|
||||
)
|
||||
resp_data = r.content
|
||||
decrypted_str = auth_lite_decrypt(resp_data)
|
||||
# 过滤所有控制字符
|
||||
decrypted_str = "".join([i for i in decrypted_str if 31 < ord(i) < 127])
|
||||
logger.info(f"RAW Response: {decrypted_str}")
|
||||
|
||||
return decrypted_str
|
||||
|
||||
|
||||
def parseRawDelivery(deliveryStr):
|
||||
"""解析 RAW 的 Delivery 字符串,返回其中的有效的 instruction URL 的列表"""
|
||||
parsedResponseDict: dict[str, str] = {
|
||||
key: value[0] for key, value in parse_qs(deliveryStr).items()
|
||||
}
|
||||
urlList = parsedResponseDict["uri"].split("|")
|
||||
# 过滤掉空字符串和内容为 null 的情况
|
||||
urlList = [url for url in urlList if url and url != "null"]
|
||||
logger.info(f"Parsed URL List: {urlList}")
|
||||
validURLs = []
|
||||
for url in urlList:
|
||||
# 检查是否是 HTTPS 的 URL,以及是否是 txt 文件,否则忽略
|
||||
if not url.startswith("https://") or not url.endswith(".txt"):
|
||||
logger.warning(f"Invalid URL will be ignored: {url}")
|
||||
continue
|
||||
validURLs.append(url)
|
||||
logger.info(f"Verified Valid URLs: {validURLs}")
|
||||
return validURLs
|
||||
|
||||
|
||||
def getUpdateIniFromURL(url):
|
||||
# 发送请求
|
||||
response = httpx.get(
|
||||
url, headers={"User-Agent": "SDGB;Windows/Lite", "Pragma": "DFI"}
|
||||
)
|
||||
logger.info(f"成功自 {url} 获取更新信息")
|
||||
return response.text
|
||||
|
||||
|
||||
def parseUpdateIni(iniText):
|
||||
# 解析配置
|
||||
config = ini.ConfigParser(allow_no_value=True)
|
||||
config.read_string(iniText)
|
||||
logger.info(f"成功解析配置文件,包含的节有:{config.sections()}")
|
||||
|
||||
# 获取 COMMON 节的配置
|
||||
common = config["COMMON"]
|
||||
|
||||
game_desc = common.get("GAME_DESC", "").strip('"')
|
||||
release_time = common.get("RELEASE_TIME", "").replace("T", " ")
|
||||
main_file = common.get("INSTALL1", "")
|
||||
|
||||
optional_files = []
|
||||
if "OPTIONAL" in config:
|
||||
for key, url in config.items("OPTIONAL"):
|
||||
optional_files.append(f"{url.split('/')[-1]} {url}")
|
||||
|
||||
return {
|
||||
"game_desc": game_desc,
|
||||
"release_time": release_time,
|
||||
"main_file": main_file,
|
||||
"optional_files": optional_files,
|
||||
}
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raw = getRawDelivery("1.51")
|
||||
urlList = parseRawDelivery(raw)
|
||||
for url in urlList:
|
||||
iniText = getUpdateIniFromURL(url)
|
||||
message = parseUpdateIni(iniText)
|
||||
Reference in New Issue
Block a user