mirror of
https://git.oceanpay.cc/danial/kami_itunes_third_api.git
synced 2025-12-18 22:20:08 +00:00
feat: ✨ 继续编写后续
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.idea
|
||||
22
main.py
22
main.py
@@ -1,11 +1,17 @@
|
||||
from src.models.apple import AppleAccountModel
|
||||
from src.models.apple_six import AppleAccountModel
|
||||
from src.service.login import SixClient
|
||||
from src.utils.utils import decode_and_decompress
|
||||
|
||||
if __name__ == "__main__":
|
||||
six_client = SixClient()
|
||||
six_client.login()
|
||||
six_client.check_is_login()
|
||||
print(six_client.login_remote_apple_account(AppleAccountModel(
|
||||
account="williamz5nvke@hotmail.com",
|
||||
password="Eq991155",
|
||||
)))
|
||||
# six_client = SixClient()
|
||||
# six_client.login()
|
||||
# six_client.check_is_login()
|
||||
# print(six_client.login_remote_apple_account(AppleAccountModel(
|
||||
# account="williamz5nvke@hotmail.com",
|
||||
# password="Eq991155",
|
||||
# )))
|
||||
print(
|
||||
decode_and_decompress(
|
||||
"H4sIAAAAAAAEADVT266rNhD9la1IR2qldh8DSbpz+hTuIcEJxjbEb4BRAAOhCeFW9d/rqKd+GWtp1sya0ay/V83ztvqxAvKtfls9y1ub9K9HLqGLuVun0XjjDZ0ztR7SCpR+uB4PpV6nDRyYU7/YAkpKkXPCt/KyrI8Xw7YwgCSiun1w9WcSQ3CwdRqIyQvmfXkKv4Yg1sfUIcMJIIIMPcBWjamxn07VXmL0fCj3ZeIikJn34aRxjc+bIpO1WLipUhUMyEZWNu+CrNmNLPZATqYu04L+re3UIMCMwzc1NapJdqkXbuiqzFqSaPe6hId3l/Jyu39J9RU310cDTw8WC8mQM7ZpqSzXeN9nKgVcxmtLGybnvxi7n1nGTUiuDa5YcomNEqsXyNiFidaBpOkPidt5nPhTHnlrJjY9srsWWj3mMdLymkW5y040UhaG7XNe1RPB6AAbr2I0m4+KP/CYm9zmUPZRjipUeYMOIalt3+1eIUUbLiBJNZ6cKWxC2unHRX/gqHOZ2P3luzqIcP3ICbewUswhuM4ohjOJuiYU8Mpd/5E53Qj3dw+adZ85BcOEPZkarFPBCaX1Ftd3za+DAca2FWpeQdWpTR2+pSrc+GQcE0vZQgIr5kxuJqwhVZmHF+aTmvZyZpqS53svEXG9ErfQo1Wxhia106q44AVhqdcLFEZ9s9hgU2x4xbeEdhYyCzN1LDWLpS6xOV5jT48aBTKNLWGFrn5D71cVbuVeNsxGJW1gwo2v0RdijAjXEKEm1sQYNqMa2UWFXd1O2/0M1R5hFT4R8J6h20VUsBbH/sO37Hto6/W18SxK9eFs1lv/JvcSe+gaTXPa7FjkwJZRT+Nt7fhmncCIjYnDu9DauIFQJlplSkBsPSCKzkEBUlH71yXbIEyfuU0h0erEx1CJLO8B56+jEXkkFDs9N1F50jqBrYMWOfSVAYVBdbJIbI3MtU8o3IlzrA/QgSyZ+83ZmcycFHPi1BgLWIYVUVgTaMliizyUdfE4/H+T8lJFEkHwvvGT9p8D5f+bxt/2zh9D/jhw6W71bfeE8/yhrH4o2peibcFuC35i6urH73+sla2qbNcSe0ni/pa3vST6SbbvurC/P/Lv6if4+EUCZdvfn8WfH+fwI/5Q1E8F/Pohk+o8ytNj2X/fAvCpfGqfa2X1z78u5LbUcgQAAA=="
|
||||
)
|
||||
)
|
||||
|
||||
@@ -10,9 +10,10 @@ import requests
|
||||
|
||||
from src.config.config import Config
|
||||
from src.crypto.crypto import encrypt_cbc_base64, encrypt
|
||||
from src.models.apple_six import AppleSixResponseModel
|
||||
|
||||
|
||||
def do_post(postData, type_, retry=False):
|
||||
def do_post(post_data, type_, retry=False) -> AppleSixResponseModel:
|
||||
req_count = random.randint(0, 90) + 1
|
||||
text = (str(int(time.time()) + req_count) + str(0).zfill(4) + str(req_count)).zfill(
|
||||
16
|
||||
@@ -24,11 +25,13 @@ def do_post(postData, type_, retry=False):
|
||||
key = "7a588e60045849a1"
|
||||
text2 = "90e7b0dc3ef2134c"
|
||||
text3 = encrypt_cbc_base64(
|
||||
encrypt(json.dumps(postData, separators=(",", ":")), key, text, False, text2),
|
||||
encrypt(json.dumps(post_data, separators=(",", ":")), key, text, False, text2),
|
||||
text,
|
||||
text2,
|
||||
).strip()
|
||||
md5_2 = hashlib.md5((text3 + type_ + md5_ + "by六月的风_联系qq:1023092054").encode("utf-8")).hexdigest()
|
||||
md5_2 = hashlib.md5(
|
||||
(text3 + type_ + md5_ + "by六月的风_联系qq:1023092054").encode("utf-8")
|
||||
).hexdigest()
|
||||
headers = {
|
||||
"timestamp": text,
|
||||
"mac": md5_,
|
||||
@@ -39,7 +42,8 @@ def do_post(postData, type_, retry=False):
|
||||
}
|
||||
if Config.user_info.token:
|
||||
headers["token"] = base64.b64encode(
|
||||
encrypt_cbc_base64(Config.user_info.token, text, text2).encode("utf-8"))
|
||||
encrypt_cbc_base64(Config.user_info.token, text, text2).encode("utf-8")
|
||||
)
|
||||
response = requests.post(
|
||||
"http://43.241.16.229:6113/AppleClientApi/requestApi",
|
||||
data={
|
||||
@@ -61,4 +65,4 @@ def do_post(postData, type_, retry=False):
|
||||
!= response.headers["sign"]
|
||||
):
|
||||
raise Exception("签名错误")
|
||||
return response.json().get("Data")
|
||||
return AppleSixResponseModel(**response.json())
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import hashlib
|
||||
|
||||
from src.models.model import UserInfo
|
||||
from src.models.model import LoginUserInfo
|
||||
from src.utils.utils import MachineCode
|
||||
|
||||
|
||||
@@ -11,4 +11,4 @@ class Config:
|
||||
new_saff_mac = hashlib.md5(
|
||||
(MachineCode().get_machine_code_string(True) + "LiuYue_Acbse").encode("utf-8")
|
||||
).hexdigest()
|
||||
user_info = UserInfo()
|
||||
user_info = LoginUserInfo()
|
||||
|
||||
@@ -1,116 +0,0 @@
|
||||
from typing import Any
|
||||
from xml.etree import ElementTree
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class Cookis(BaseModel):
|
||||
wosid: str = Field(None, alias='wosid')
|
||||
woinst: str = Field(None, alias='woinst')
|
||||
ns_mzf_inst: str = Field(..., alias='ns-mzf-inst')
|
||||
mzf_in: str = Field(None, alias='mzf_in')
|
||||
mzf_dr: str = Field(None, alias='mzf_dr')
|
||||
hsaccnt: str = Field(None, alias='hsaccnt')
|
||||
session_store_id: str = Field(..., alias='session-store-id')
|
||||
X_Dsid: str = Field(..., alias='X-Dsid')
|
||||
mz_at0_135096725: str = Field(..., alias='mz_at0-135096725')
|
||||
ampsc: str = Field(None, alias='ampsc')
|
||||
mz_at_ssl_135096725: str = Field(..., alias='mz_at_ssl-135096725')
|
||||
mz_at_mau_135096725: str = Field(..., alias='mz_at_mau-135096725')
|
||||
pldfltcid: str = Field(None, alias='pldfltcid')
|
||||
tv_pldfltcid: str = Field(..., alias='tv-pldfltcid')
|
||||
wosid_lite: str = Field(..., alias='wosid-lite')
|
||||
itspod: str = Field(None, alias='itspod')
|
||||
|
||||
|
||||
class RemoteCookieModel(BaseModel):
|
||||
msg: str = Field(..., alias='msg')
|
||||
Balance: str = Field(..., alias='Balance')
|
||||
Area: str = Field(..., alias='Area')
|
||||
UserAgent: str = Field(..., alias='UserAgent')
|
||||
cookis: Cookis = Field(..., alias='cookis')
|
||||
xtoken: str = Field(..., alias='xtoken')
|
||||
dsis: str = Field(..., alias='dsis')
|
||||
Kbsync: Any = Field(..., alias='Kbsync')
|
||||
software: str = Field(..., alias='software')
|
||||
Guid: str = Field(..., alias='Guid')
|
||||
ServerId: str = Field(..., alias='ServerId')
|
||||
isDisabledAccount: str = Field(..., alias='isDisabledAccount')
|
||||
|
||||
|
||||
class CheckIsLoginModel(BaseModel):
|
||||
integral: int = Field(..., alias='integral')
|
||||
userType: str = Field(..., alias='userType')
|
||||
userNumber: str = Field(..., alias='userNumber')
|
||||
userTypeName: str = Field(..., alias='userTypeName')
|
||||
expirationTime: str = Field(..., alias='expirationTime')
|
||||
freezeIntegral: int = Field(..., alias='freezeIntegral')
|
||||
|
||||
|
||||
class AppleAccountModel(BaseModel):
|
||||
account: str = Field(default="")
|
||||
password: str = Field(default="")
|
||||
|
||||
|
||||
class ItunesLoginModel(BaseModel):
|
||||
server_id: int = Field(default=0)
|
||||
dsis: int = Field(default=0)
|
||||
guid: str = Field(default="")
|
||||
|
||||
|
||||
class ItunesRedeemModel(BaseModel):
|
||||
attempt_count: int = Field(default=0)
|
||||
camera_recognized_code: bool = Field(default=False)
|
||||
cl: str = Field(default="iTunes")
|
||||
code: str = Field(default="")
|
||||
ds_personId: str = Field(default="")
|
||||
guid: str = Field(default="")
|
||||
has_4gb_limit: bool = Field(default=False)
|
||||
kbsync: str = Field(default="")
|
||||
pg: str = Field(default="")
|
||||
response_content_type: str = Field(default="application/json")
|
||||
|
||||
def to_xml(self):
|
||||
root = ElementTree.Element("plist", attrib={"version": "1.0"})
|
||||
child1 = ElementTree.SubElement(root, "dict")
|
||||
child2 = ElementTree.SubElement(child1, "key")
|
||||
child2.value = "attemptCount"
|
||||
child3 = ElementTree.SubElement(child1, "string")
|
||||
child3.value = self.attempt_count
|
||||
child4 = ElementTree.SubElement(child1, "key")
|
||||
child4.value = "cameraReCOGnizedCode"
|
||||
child5 = ElementTree.SubElement(child1, "string")
|
||||
child5.value = self.camera_recognized_code
|
||||
child6 = ElementTree.SubElement(child1, "key")
|
||||
child6.value = "cl"
|
||||
child7 = ElementTree.SubElement(child1, "string")
|
||||
child7.value = self.cl
|
||||
child8 = ElementTree.SubElement(child1, "key")
|
||||
child8.value = "code"
|
||||
child9 = ElementTree.SubElement(child1, "string")
|
||||
child9.value = self.code
|
||||
child10 = ElementTree.SubElement(child1, "key")
|
||||
child10.value = "dsPersonId"
|
||||
child11 = ElementTree.SubElement(child1, "string")
|
||||
child11.value = self.ds_personId
|
||||
child12 = ElementTree.SubElement(child1, "key")
|
||||
child12.value = "guid"
|
||||
child13 = ElementTree.SubElement(child1, "string")
|
||||
child13.value = self.guid
|
||||
child14 = ElementTree.SubElement(child1, "key")
|
||||
child14.value = "has4GBLimit"
|
||||
child15 = ElementTree.SubElement(child1, "string")
|
||||
child15.value = self.has_4gb_limit
|
||||
child16 = ElementTree.SubElement(child1, "key")
|
||||
child16.value = "kbsync"
|
||||
child17 = ElementTree.SubElement(child1, "string")
|
||||
child18 = ElementTree.SubElement(child1, "key")
|
||||
child18.value = "pg"
|
||||
child19 = ElementTree.SubElement(child1, "string")
|
||||
child19.value = self.pg
|
||||
child20 = ElementTree.SubElement(child1, "key")
|
||||
child20.value = "response-content-type"
|
||||
child21 = ElementTree.SubElement(child1, "string")
|
||||
child21.value = self.response_content_type
|
||||
# 将XML元素树转换为字符串
|
||||
return ElementTree.tostring(root)
|
||||
5
src/models/apple_client.py
Normal file
5
src/models/apple_client.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class SignSapSetup(BaseModel):
|
||||
sign_sap_setup_buffer = Field(alias="sign-sap-setup-buffer")
|
||||
159
src/models/apple_six.py
Normal file
159
src/models/apple_six.py
Normal file
@@ -0,0 +1,159 @@
|
||||
from datetime import datetime
|
||||
from typing import Any, TypeVar
|
||||
from xml.etree import ElementTree
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class LoginUserInfo(BaseModel):
|
||||
token: str = Field(default="")
|
||||
userName: str = Field(default="")
|
||||
userPwd: str = Field(default="")
|
||||
integral: int = Field(default=0)
|
||||
freezeIntegral: int = Field(default=0)
|
||||
userNumber: str = Field(default="")
|
||||
guid: str = Field(default="")
|
||||
|
||||
|
||||
class LoginSessionInfo(BaseModel):
|
||||
integral: int = Field(default=0)
|
||||
userType: str = Field(default="")
|
||||
userNumber: str = Field(default="")
|
||||
userTypeName: str = Field(default="")
|
||||
expirationTime: datetime = Field(default=datetime.now())
|
||||
freezeIntegral: int = Field(default=0)
|
||||
serverIndex: int = Field(default=0)
|
||||
|
||||
|
||||
class Cookis(BaseModel):
|
||||
wosid: str = Field(None, alias="wosid")
|
||||
woinst: str = Field(None, alias="woinst")
|
||||
ns_mzf_inst: str = Field(..., alias="ns-mzf-inst")
|
||||
mzf_in: str = Field(None, alias="mzf_in")
|
||||
mzf_dr: str = Field(None, alias="mzf_dr")
|
||||
hsaccnt: str = Field(None, alias="hsaccnt")
|
||||
session_store_id: str = Field(..., alias="session-store-id")
|
||||
X_Dsid: str = Field(..., alias="X-Dsid")
|
||||
mz_at0_135096725: str = Field(..., alias="mz_at0-135096725")
|
||||
ampsc: str = Field(None, alias="ampsc")
|
||||
mz_at_ssl_135096725: str = Field(..., alias="mz_at_ssl-135096725")
|
||||
mz_at_mau_135096725: str = Field(..., alias="mz_at_mau-135096725")
|
||||
pldfltcid: str = Field(None, alias="pldfltcid")
|
||||
tv_pldfltcid: str = Field(..., alias="tv-pldfltcid")
|
||||
wosid_lite: str = Field(..., alias="wosid-lite")
|
||||
itspod: str = Field(None, alias="itspod")
|
||||
|
||||
|
||||
class RemoteCookieModel(BaseModel):
|
||||
msg: str = Field(..., alias="msg")
|
||||
Balance: str = Field(..., alias="Balance")
|
||||
Area: str = Field(..., alias="Area")
|
||||
UserAgent: str = Field(..., alias="UserAgent")
|
||||
cookis: Cookis = Field(..., alias="cookis")
|
||||
xtoken: str = Field(..., alias="xtoken")
|
||||
dsis: str = Field(..., alias="dsis")
|
||||
Kbsync: Any = Field(..., alias="Kbsync")
|
||||
software: str = Field(..., alias="software")
|
||||
Guid: str = Field(..., alias="Guid")
|
||||
ServerId: str = Field(..., alias="ServerId")
|
||||
isDisabledAccount: str = Field(..., alias="isDisabledAccount")
|
||||
|
||||
|
||||
class LoginSignatureModel(BaseModel):
|
||||
msg: str = Field(..., alias="msg")
|
||||
signature: str = Field(..., alias="signature")
|
||||
serverId: str = Field(..., alias="serverId")
|
||||
adder1: int = Field(..., alias="adder1")
|
||||
adder2: int = Field(..., alias="adder2")
|
||||
userAgent: str = Field(..., alias="userAgent")
|
||||
|
||||
|
||||
class AppleAccountModel(BaseModel):
|
||||
account: str = Field(default="")
|
||||
password: str = Field(default="")
|
||||
|
||||
|
||||
class ItunesLoginModel(BaseModel):
|
||||
server_id: int = Field(default=0)
|
||||
dsis: int = Field(default=0)
|
||||
guid: str = Field(default="")
|
||||
|
||||
|
||||
# 泛型
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
class AppleSixResponseModel(BaseModel):
|
||||
Code: str = Field(default="")
|
||||
Message: str = Field(default="")
|
||||
Data: T = Field(default="")
|
||||
serverIndex: int = Field(default=0)
|
||||
extend: str = Field(default="")
|
||||
authenUserInfo: str = Field(default="")
|
||||
platformName: str = Field(default="")
|
||||
|
||||
|
||||
class AuthenticateModel(BaseModel):
|
||||
msg: str = Field(..., alias="msg")
|
||||
post: str = Field(..., alias="post")
|
||||
signature: str = Field(..., alias="signature")
|
||||
userAgent: str = Field(..., alias="userAgent")
|
||||
guid: str = Field(..., alias="guid")
|
||||
|
||||
|
||||
class ItunesRedeemModel(BaseModel):
|
||||
attempt_count: int = Field(default=0)
|
||||
camera_recognized_code: bool = Field(default=False)
|
||||
cl: str = Field(default="iTunes")
|
||||
code: str = Field(default="")
|
||||
ds_personId: int = Field(default=0)
|
||||
guid: str = Field(default="")
|
||||
has_4gb_limit: bool = Field(default=False)
|
||||
kbsync: str = Field(default="")
|
||||
pg: str = Field(default="")
|
||||
response_content_type: str = Field(default="application/json")
|
||||
|
||||
def to_xml(self):
|
||||
root = ElementTree.Element("plist", attrib={"version": "1.0"})
|
||||
child1 = ElementTree.SubElement(root, "dict")
|
||||
child2 = ElementTree.SubElement(child1, "key")
|
||||
child2.value = "attemptCount"
|
||||
child3 = ElementTree.SubElement(child1, "string")
|
||||
child3.value = self.attempt_count
|
||||
child4 = ElementTree.SubElement(child1, "key")
|
||||
child4.value = "cameraReCOGnizedCode"
|
||||
child5 = ElementTree.SubElement(child1, "string")
|
||||
child5.value = self.camera_recognized_code
|
||||
child6 = ElementTree.SubElement(child1, "key")
|
||||
child6.value = "cl"
|
||||
child7 = ElementTree.SubElement(child1, "string")
|
||||
child7.value = self.cl
|
||||
child8 = ElementTree.SubElement(child1, "key")
|
||||
child8.value = "code"
|
||||
child9 = ElementTree.SubElement(child1, "string")
|
||||
child9.value = self.code
|
||||
child10 = ElementTree.SubElement(child1, "key")
|
||||
child10.value = "dsPersonId"
|
||||
child11 = ElementTree.SubElement(child1, "string")
|
||||
child11.value = self.ds_personId
|
||||
child12 = ElementTree.SubElement(child1, "key")
|
||||
child12.value = "guid"
|
||||
child13 = ElementTree.SubElement(child1, "string")
|
||||
child13.value = self.guid
|
||||
child14 = ElementTree.SubElement(child1, "key")
|
||||
child14.value = "has4GBLimit"
|
||||
child15 = ElementTree.SubElement(child1, "string")
|
||||
child15.value = self.has_4gb_limit
|
||||
child16 = ElementTree.SubElement(child1, "key")
|
||||
child16.value = "kbsync"
|
||||
child17 = ElementTree.SubElement(child1, "string")
|
||||
child18 = ElementTree.SubElement(child1, "key")
|
||||
child18.value = "pg"
|
||||
child19 = ElementTree.SubElement(child1, "string")
|
||||
child19.value = self.pg
|
||||
child20 = ElementTree.SubElement(child1, "key")
|
||||
child20.value = "response-content-type"
|
||||
child21 = ElementTree.SubElement(child1, "string")
|
||||
child21.value = self.response_content_type
|
||||
# 将XML元素树转换为字符串
|
||||
return ElementTree.tostring(root)
|
||||
@@ -1,11 +1,3 @@
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class UserInfo(BaseModel):
|
||||
token: str = Field(default="")
|
||||
userName: str = Field(default="")
|
||||
userPwd: str = Field(default="")
|
||||
integral: int = Field(default=0)
|
||||
freezeIntegral: int = Field(default=0)
|
||||
userNumber: str = Field(default="")
|
||||
guid: str = Field(default="")
|
||||
|
||||
@@ -1,13 +1,23 @@
|
||||
import base64
|
||||
import json
|
||||
from xml.dom import minidom
|
||||
from xml.etree import ElementTree
|
||||
|
||||
import requests
|
||||
|
||||
from src.client.post import do_post
|
||||
from src.config.config import Config
|
||||
from src.models.apple import AppleAccountModel, ItunesLoginModel, ItunesRedeemModel, RemoteCookieModel, \
|
||||
CheckIsLoginModel
|
||||
from src.models.model import UserInfo
|
||||
from xml.etree import ElementTree
|
||||
from src.models.apple_client import SignSapSetup
|
||||
from src.models.apple_six import (
|
||||
AppleAccountModel,
|
||||
ItunesLoginModel,
|
||||
ItunesRedeemModel,
|
||||
RemoteCookieModel,
|
||||
CheckIsLoginModel,
|
||||
LoginSignatureModel, AppleSixResponseModel, LoginUserInfo, LoginSessionInfo, AuthenticateModel,
|
||||
)
|
||||
|
||||
from src.utils.utils import decode_and_decompress, xml_to_dict
|
||||
|
||||
|
||||
class SixClient:
|
||||
@@ -16,45 +26,169 @@ class SixClient:
|
||||
{"account": "q905262752", "pwd": "Aa112211"},
|
||||
"ApiLogin",
|
||||
)
|
||||
Config.user_info = UserInfo(**response)
|
||||
Config.user_info = LoginUserInfo(**response.Data)
|
||||
|
||||
def check_is_login(self):
|
||||
def check_is_login(self) -> LoginSessionInfo:
|
||||
response = do_post(
|
||||
{"token": Config.user_info.token, "type": 9},
|
||||
"ApiIsLogin",
|
||||
)
|
||||
m = CheckIsLoginModel(**response)
|
||||
# 147570 已经登录
|
||||
return LoginSessionInfo(**response.Data)
|
||||
|
||||
def login_remote_apple_account(self, account: AppleAccountModel) -> RemoteCookieModel:
|
||||
response = do_post({
|
||||
"token": Config.user_info.token,
|
||||
"account": account.account,
|
||||
"pwd": account.password,
|
||||
"isStore": 2,
|
||||
"guid": "",
|
||||
"serviceIpIndex": -1,
|
||||
},
|
||||
def login_remote_apple_account(
|
||||
self, account: AppleAccountModel
|
||||
) -> RemoteCookieModel:
|
||||
response = do_post(
|
||||
{
|
||||
"token": Config.user_info.token,
|
||||
"account": account.account,
|
||||
"pwd": account.password,
|
||||
"isStore": 2,
|
||||
"guid": "",
|
||||
"serviceIpIndex": -1,
|
||||
},
|
||||
"ApiItunesLogin",
|
||||
)
|
||||
print(RemoteCookieModel.model_validate(json.loads(response)))
|
||||
return RemoteCookieModel.model_validate(json.loads(response.Data))
|
||||
|
||||
def get_sign_sap_setup(self):
|
||||
pass
|
||||
def get_sign_sap_setup(self) -> AppleSixResponseModel[LoginSignatureModel]:
|
||||
response = do_post(
|
||||
{
|
||||
"gZip": 1,
|
||||
"type": "GetSignsapsetup",
|
||||
"userAgent": "MacAppStore/2.0 (Macintosh; OS X 12.10) AppleWebKit/600.1.3.41",
|
||||
},
|
||||
"ApiServiceSend",
|
||||
)
|
||||
response.Data = json.loads(decode_and_decompress(response))
|
||||
response = AppleSixResponseModel[LoginSignatureModel].model_validate(response.model_dump())
|
||||
return response
|
||||
|
||||
def get_sign_sap_setup_cert(
|
||||
self, account: AppleAccountModel, sign: LoginSignatureModel, sign_sap_setup: str
|
||||
) -> AppleSixResponseModel[AuthenticateModel]:
|
||||
response = do_post(
|
||||
{
|
||||
"signSap": base64.b64encode(sign_sap_setup.encode()).decode(),
|
||||
"appleId": account.account,
|
||||
"guid": "",
|
||||
"applePwd": account.password,
|
||||
"intptr_": sign.adder1,
|
||||
"intPtr": sign.adder2,
|
||||
"idType": 1,
|
||||
"gZip": "1",
|
||||
"type": "GetSignsapsetupCert",
|
||||
},
|
||||
"ApiServiceSend"
|
||||
)
|
||||
response.Data = json.loads(decode_and_decompress(response))
|
||||
response = AppleSixResponseModel[AuthenticateModel].model_validate(response.model_dump())
|
||||
return response
|
||||
|
||||
|
||||
class AppleClient:
|
||||
def redeem(self, code: str, itunes: ItunesLoginModel):
|
||||
def query_sign_sap_setup(self, signature: LoginSignatureModel) -> str:
|
||||
headers = {
|
||||
"X-Apple-Store-Front": "1433465-19,17",
|
||||
"X-Apple-Partner": "origin.0",
|
||||
"X-Apple-Client-Application": "Software",
|
||||
"X-Apple-Connection-Type": "WiFi",
|
||||
"X-Apple-Client-Versions": "GameCenter/2.0",
|
||||
"X-Token-T": "M",
|
||||
"X-Apple-Tz": "28800",
|
||||
"Content-Type": "application/x-apple-plist; Charset=UTF-8",
|
||||
}
|
||||
# 生成cookie
|
||||
cookies = {
|
||||
"mzf_in": "07281",
|
||||
"s_vi": "",
|
||||
"itsMetricsR": "Genre-CN-Mobile Software Applications-29099@@Mobile Software Applications-main@@@@",
|
||||
"s_vnum_n2_us": "0|1",
|
||||
}
|
||||
# base64解码
|
||||
if signature.serverId != "0":
|
||||
cookies["pod"] = signature.serverId
|
||||
cookies["itspod"] = signature.serverId
|
||||
response = requests.post(
|
||||
"https://play.itunes.apple.com/WebObjects/MZPlay.woa/wa/signSapSetup",
|
||||
data=base64.b64decode(signature.signature).decode(),
|
||||
headers=headers,
|
||||
cookies=cookies
|
||||
)
|
||||
return response.text
|
||||
|
||||
def login(self, code: str, itunes: ItunesLoginModel, sign_map: AuthenticateModel) -> dict:
|
||||
url = f"https://p{itunes.server_id}-buy.itunes.apple.com/WebObjects/MZFinance.woa/wa/authenticate"
|
||||
params = {}
|
||||
if itunes.server_id:
|
||||
params = {
|
||||
"Pod": 47,
|
||||
"PRH": 47
|
||||
}
|
||||
headers = {
|
||||
"X-Apple-Store-Front": "1433465-19,17",
|
||||
"X-Apple-Partner": "origin.0",
|
||||
"X-Apple-Client-Application": "Software",
|
||||
"X-Apple-Connection-Type": "WiFi",
|
||||
"X-Apple-Client-Versions": "GameCenter/2.0",
|
||||
"X-Token-T": "M",
|
||||
"X-Apple-ActionSignature": sign_map.signature,
|
||||
"X-Apple-Tz": "28800",
|
||||
"User-Agent": sign_map.userAgent,
|
||||
"Content-Type": "application/x-apple-plist; Charset=UTF-8",
|
||||
}
|
||||
# 生成cookie
|
||||
cookies = {
|
||||
"mzf_in": "07281",
|
||||
"s_vi": "",
|
||||
"itsMetricsR": "Genre-CN-Mobile Software Applications-29099@@Mobile Software Applications-main@@@@",
|
||||
"s_vnum_n2_us": "0|1",
|
||||
}
|
||||
# base64解码
|
||||
if itunes.server_id != "0":
|
||||
cookies["pod"] = itunes.server_id
|
||||
cookies["itspod"] = itunes.server_id
|
||||
response = requests.post(
|
||||
url,
|
||||
params=params,
|
||||
headers=headers,
|
||||
data=sign_map.post,
|
||||
cookies=cookies
|
||||
)
|
||||
d = xml_to_dict(ElementTree.fromstring(response.text))
|
||||
return d
|
||||
|
||||
def redeem(self, code: str, itunes: ItunesLoginModel, sign_map: AuthenticateModel):
|
||||
url = f"https://p{itunes.server_id}-buy.itunes.apple.com/WebObjects/MZFinance.woa/wa/com.apple.jingle.app.finance.DirectAction/redeemCode?cl=iTunes&pg=Music"
|
||||
response = requests.post(url, data=ItunesRedeemModel(
|
||||
attempt_count=1,
|
||||
camera_recognized_code=False,
|
||||
cl="iTunes",
|
||||
code=code,
|
||||
ds_personId=itunes.dsis,
|
||||
guid=itunes.guid,
|
||||
kbsync="",
|
||||
pg="Music",
|
||||
response_content_type="application/json",
|
||||
has_4gb_limit=False,
|
||||
).to_xml())
|
||||
headers = {
|
||||
"X-Dsid": "",
|
||||
"X-Token": "",
|
||||
"X-Apple-Store-Front": "1433465-19,17",
|
||||
"X-Apple-Partner": "origin.0",
|
||||
"X-Apple-Client-Application": "Software",
|
||||
"X-Apple-Connection-Type": "WiFi",
|
||||
"X-Apple-Client-Versions": "GameCenter/2.0",
|
||||
"X-Token-T": "M",
|
||||
"X-Apple-ActionSignature": sign_map.signature,
|
||||
"X-Apple-Tz": "28800",
|
||||
"User-Agent": sign_map.userAgent,
|
||||
"Content-Type": "application/x-apple-plist; Charset=UTF-8",
|
||||
}
|
||||
response = requests.post(
|
||||
url,
|
||||
data=ItunesRedeemModel(
|
||||
attempt_count=1,
|
||||
camera_recognized_code=False,
|
||||
cl="iTunes",
|
||||
code=code,
|
||||
ds_personId=itunes.dsis,
|
||||
guid=itunes.guid,
|
||||
kbsync="",
|
||||
pg="Music",
|
||||
response_content_type="application/json",
|
||||
has_4gb_limit=False,
|
||||
).to_xml(),
|
||||
headers=headers
|
||||
)
|
||||
print(response.json())
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
import base64
|
||||
import gzip
|
||||
import zlib
|
||||
from xml.etree import ElementTree
|
||||
|
||||
import brotli
|
||||
import wmi
|
||||
|
||||
|
||||
@@ -9,7 +15,7 @@ class MachineCode:
|
||||
try:
|
||||
if not self.machineCodeString:
|
||||
self.machineCodeString = (
|
||||
"PC." + self.get_cpu_info() + "." + self.get_hd_id() + "."
|
||||
"PC." + self.get_cpu_info() + "." + self.get_hd_id() + "."
|
||||
)
|
||||
return self.machineCodeString + self.get_mo_address(mo_address)
|
||||
except Exception as e:
|
||||
@@ -60,3 +66,29 @@ class MachineCode:
|
||||
except Exception as e:
|
||||
print(f"An error occurred: {e}")
|
||||
return ""
|
||||
|
||||
|
||||
def decode_and_decompress(encoded_data, method="gzip"):
|
||||
decoded_data = base64.b64decode(encoded_data)
|
||||
|
||||
if method == "gzip":
|
||||
decompressed_data = gzip.decompress(decoded_data)
|
||||
elif method == "deflate":
|
||||
decompressed_data = zlib.decompress(decoded_data, -zlib.MAX_WBITS)
|
||||
elif method == "brotli":
|
||||
decompressed_data = brotli.decompress(decoded_data)
|
||||
else:
|
||||
raise ValueError("Unsupported compression method.")
|
||||
return decompressed_data.decode("utf-8")
|
||||
|
||||
|
||||
def xml_to_dict(element: ElementTree) -> dict:
|
||||
result = {}
|
||||
key = None
|
||||
for child in element:
|
||||
if child.tag == 'key':
|
||||
key = child.text
|
||||
elif child.tag == 'data' and key:
|
||||
result[key] = child.text
|
||||
key = None
|
||||
return result
|
||||
|
||||
Reference in New Issue
Block a user