Initial
This commit is contained in:
4
src_mac/ipatool-py/.gitignore
vendored
Executable file
4
src_mac/ipatool-py/.gitignore
vendored
Executable file
@@ -0,0 +1,4 @@
|
||||
.idea
|
||||
__pycache__
|
||||
venv/
|
||||
downloaded/
|
||||
112
src_mac/ipatool-py/README.md
Executable file
112
src_mac/ipatool-py/README.md
Executable file
@@ -0,0 +1,112 @@
|
||||
# IPATool-py
|
||||
|
||||
Python version of IPATool!
|
||||
|
||||
**Now Supports**:
|
||||
- **Purchasing App via `--purchase`**
|
||||
- **Downloading Old IPA via iTunes Server**
|
||||
|
||||
## Installation
|
||||
|
||||
```
|
||||
pip3 install -r requirements.txt
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
There're three commands: lookup, historyver, download. Each command's usage can be found by `-h` option.
|
||||
|
||||
You can also chain multiple command, last command's output will be passed to next command (so you don't need to supply some arguments like appVerId)
|
||||
|
||||
### Download Newest Version
|
||||
|
||||
Download an app using bundleID (-o can be omited)
|
||||
```
|
||||
python3 main.py lookup -b com.touchingapp.potatsolite -c JP download -e APPLE_EMAIL -p APPLE_PWD -o DIR
|
||||
```
|
||||
|
||||
Or appID (`XXXXX` in the `apps.apple.com/app/xxxx/idXXXXXX`)
|
||||
```
|
||||
python3 main.py download -i XXXXX
|
||||
```
|
||||
|
||||
You can also purchase apps when downloading using `--purchase`:
|
||||
```
|
||||
python3 main.py lookup -b com.touchingapp.potatsolite -c JP download --purchase -e APPLE_EMAIL -p APPLE_PWD -o DIR
|
||||
```
|
||||
|
||||
### Download OLD Version
|
||||
|
||||
Old versions must be downloaded together with `iTunes Server`. You can get `iTunes Server` in several ways:
|
||||
- Using [action-ipadown](https://github.com/NyaMisty/action-ipadown) directly, which integrated this tool
|
||||
- NOTE: this method does not support 2FA
|
||||
- Manually way with Windows: (supports 2FA)
|
||||
- download this repo: https://github.com/NyaMisty/actions-iTunes-header
|
||||
- install iTunes 12.6.5.3, from https://secure-appldnld.apple.com/itunes12/091-87819-20180912-69177170-B085-11E8-B6AB-C1D03409AD2A6/iTunes64Setup.exe
|
||||
- patch the iTunes using `actions-iTunes-header/workflow_helper/iTunesInstall/patch_itunes.py`
|
||||
- install frida: `pip3 install frida`
|
||||
- open iTunes, sign out & re-login your account
|
||||
- run: `actions-iTunes-header/workflow_helper/iTunesDownload/get_header.py`
|
||||
- Manually way with jailbroken iOS device: (supports 2FA)
|
||||
- download [KbsyncTool](https://github.com/Lessica/KbsyncTool/releases)
|
||||
- install `com.darwindev.kbsync_XXX.deb` on your jailbroken device
|
||||
- exec `kbsynctool -s 9000` on your jailbroken device
|
||||
- you will find log `Using -s http://192.168.100.227:9000/...`, use it as server address in next step
|
||||
|
||||
After setting up the server, you can run this tool to download a specific version
|
||||
```
|
||||
python3 main.py lookup -b com.touchingapp.potatsolite -c JP download -s http://127.0.0.1:9000 --appVerId 833889087
|
||||
```
|
||||
|
||||
NOTE: Some users are reporting that you need to **authorize computer** and make first purchase in iTunes with marked "do not ask for password" before using the iTunes server. (See #26)
|
||||
|
||||
### Get History Ver (usually used together with JSON)
|
||||
|
||||
Get all appVerId of app from Apple
|
||||
```
|
||||
python3 main.py lookup -b com.touchingapp.potatsolite -c JP historyver -e APPLE_EMAIL -p APPLE_PWD
|
||||
```
|
||||
|
||||
### Lookup (usually used together with JSON)
|
||||
|
||||
Query app basic information:
|
||||
- By bundleID: `python3 main.py lookup -b com.touchingapp.potatsolite -c JP`
|
||||
- By appID: `python3 main.py lookup -i 1239860606 -c JP`
|
||||
|
||||
Query appVerId:
|
||||
```
|
||||
python3 main.py lookup -b com.touchingapp.potatsolite -c JP --get-verid
|
||||
```
|
||||
|
||||
### Headless Usage
|
||||
|
||||
For each command you can use `--json` switch to get result of command in JSON
|
||||
|
||||
```
|
||||
python3 main.py --json lookup -b com.touchingapp.potatsolite -c JP --get-verid
|
||||
python3 main.py --json lookup -b com.touchingapp.potatsolite -c JP historyver -e APPLE_EMAIL -p APPLE_PWD
|
||||
```
|
||||
|
||||
### For Large Scale Scraping
|
||||
|
||||
You can download all versions of an app like this:
|
||||
```
|
||||
python3 main.py --json download --itunes-server http://XXX.XXX.XXX.XXX:9000 --appId 414478124 --purchase --downloadAllVersion
|
||||
```
|
||||
|
||||
- In this mode, errors will only be logged instead of interrupting the whole process
|
||||
- For each downloaded app version, it will output a line of json in stdout like this:
|
||||
```
|
||||
{"appName": "WeChat", "appBundleId": "com.tencent.xin", "appVer": "6.5.13.34", "appId": 414478124, "appVerId": 822899148, "downloadedIPA": "wechat\\com.tencent.xin-6.5.13.34-414478124-822899148.ipa", "downloadedVerId": 822899148}
|
||||
```
|
||||
Logs will only be printed to stderr, so you can parse this line for automation.
|
||||
|
||||
|
||||
## Development
|
||||
|
||||
- All requests' reqBody and respBody are modeled using modified JSONSchema2PoPo2 (see my NyaMisty/JSONSchema2PoPo2), you can regenerate the binding by cd into `reqs/schemas` and execute `python3 -m schema_defs`
|
||||
- See more information on how to generate schema in reqs/schemas directory
|
||||
|
||||
## Credit
|
||||
|
||||
- Thanks @majd's ipatool, which is written in swift
|
||||
567
src_mac/ipatool-py/main.py
Executable file
567
src_mac/ipatool-py/main.py
Executable file
@@ -0,0 +1,567 @@
|
||||
#!/usr/bin/python3
|
||||
import os
|
||||
import pickle
|
||||
import sys
|
||||
import time
|
||||
import zipfile
|
||||
|
||||
from requests.adapters import HTTPAdapter
|
||||
from urllib3 import Retry
|
||||
|
||||
from reqs.itunes import *
|
||||
from reqs.store import *
|
||||
import reprlib
|
||||
|
||||
reprlib.aRepr.maxstring = 200
|
||||
|
||||
import argparse
|
||||
|
||||
import logging
|
||||
from rich.logging import RichHandler
|
||||
from rich.console import Console
|
||||
import rich
|
||||
|
||||
rich.get_console().file = sys.stderr
|
||||
if rich.get_console().width < 100:
|
||||
rich.get_console().width = 100
|
||||
|
||||
logging_handler = RichHandler(rich_tracebacks=True)
|
||||
logging.basicConfig(
|
||||
level="INFO",
|
||||
format="%(message)s",
|
||||
datefmt="[%X]",
|
||||
handlers=[logging_handler]
|
||||
)
|
||||
logging.getLogger('urllib3').setLevel(logging.WARNING)
|
||||
retryLogger = logging.getLogger('urllib3.util.retry')
|
||||
retryLogger.setLevel(logging.DEBUG)
|
||||
retryLogger.handlers = [logging_handler]
|
||||
retryLogger.propagate = False
|
||||
|
||||
logger = logging.getLogger('main')
|
||||
|
||||
import requests
|
||||
|
||||
def get_zipinfo_datetime(timestamp=None):
|
||||
# Some applications need reproducible .whl files, but they can't do this without forcing
|
||||
# the timestamp of the individual ZipInfo objects. See issue #143.
|
||||
timestamp = int(timestamp or time.time())
|
||||
return time.gmtime(timestamp)[0:6]
|
||||
|
||||
def downloadFile(url, outfile, retries=10):
|
||||
for retry in range(retries):
|
||||
try:
|
||||
_downloadFile(url, outfile)
|
||||
break
|
||||
except Exception as e:
|
||||
logger.info("Error during downloading %s (retry %d/%d), error %s", url, retry, retries, e)
|
||||
os.remove(outfile)
|
||||
logger.info("Download success in retry %d", retry)
|
||||
|
||||
download_sess = requests.Session()
|
||||
download_sess.headers = {"User-Agent": CONFIGURATOR_UA}
|
||||
DOWNLOAD_READ_TIMEOUT = 25.0
|
||||
def _downloadFile(url, outfile):
|
||||
with download_sess.get(url, stream=True, timeout=DOWNLOAD_READ_TIMEOUT) as r:
|
||||
if not r.headers.get('Content-Length'):
|
||||
raise Exception("server is not returning Content-Length!")
|
||||
totalLen = int(r.headers.get('Content-Length', '0'))
|
||||
downLen = 0
|
||||
r.raise_for_status()
|
||||
try:
|
||||
with open(outfile, 'wb') as f:
|
||||
lastLen = 0
|
||||
for chunk in r.iter_content(chunk_size=1 * 1024 * 1024):
|
||||
# If you have chunk encoded response uncomment if
|
||||
# and set chunk_size parameter to None.
|
||||
# if chunk:
|
||||
f.write(chunk)
|
||||
downLen += len(chunk)
|
||||
if totalLen and downLen - lastLen > totalLen * 0.05:
|
||||
logger.info("Download progress: %3.2f%% (%5.1fM /%5.1fM)" % (
|
||||
downLen / totalLen * 100, downLen / 1024 / 1024, totalLen / 1024 / 1024))
|
||||
lastLen = downLen
|
||||
finally:
|
||||
if downLen != totalLen: # ensure no partial downloaded files exists
|
||||
os.unlink(outfile)
|
||||
if downLen != totalLen:
|
||||
raise Exception("failed to completely download the IPA file")
|
||||
|
||||
return outfile
|
||||
|
||||
class IPATool(object):
|
||||
def __init__(self):
|
||||
self.sess = requests.Session()
|
||||
|
||||
retry_strategy = Retry(
|
||||
connect=4,
|
||||
read=4,
|
||||
# total=8,
|
||||
status=20,
|
||||
allowed_methods=None,
|
||||
status_forcelist=[429, 502, 503],
|
||||
backoff_factor=1.0,
|
||||
respect_retry_after_header=False,
|
||||
)
|
||||
self.sess.mount("https://", HTTPAdapter(max_retries=retry_strategy))
|
||||
self.sess.mount("http://", HTTPAdapter(max_retries=retry_strategy))
|
||||
IPATOOL_PROXY = os.getenv("IPATOOL_PROXY")
|
||||
if IPATOOL_PROXY is not None:
|
||||
self.sess.proxies.update(
|
||||
{'http': IPATOOL_PROXY, 'https': IPATOOL_PROXY})
|
||||
# self.sess.headers = {}
|
||||
self.sess.headers = {"Connection": "close"}
|
||||
self.sess.keep_alive = False
|
||||
|
||||
self.appId = None
|
||||
# self.appInfo = None
|
||||
self.appVerId = None
|
||||
self.appVerIds = None
|
||||
|
||||
self.jsonOut = None
|
||||
|
||||
def tool_main(self):
|
||||
commparser = argparse.ArgumentParser(description='IPATool-Python Commands.', add_help=False)
|
||||
subp = commparser.add_subparsers(dest='command', required=True)
|
||||
lookup_p = subp.add_parser('lookup')
|
||||
id_group = lookup_p.add_mutually_exclusive_group(required=True)
|
||||
id_group.add_argument('--bundle-id', '-b', dest='bundle_id')
|
||||
id_group.add_argument('--appId', '-i', dest='appId')
|
||||
lookup_p.add_argument('--country', '-c', dest='country', required=True)
|
||||
lookup_p.add_argument('--get-verid', dest='get_verid', action='store_true')
|
||||
lookup_p.set_defaults(func=self.handleLookup)
|
||||
|
||||
def add_auth_options(p):
|
||||
auth_p = p.add_argument_group('Auth Options', 'Must specify either Apple ID & Password, or iTunes Server URL')
|
||||
appleid = auth_p.add_argument('--appleid', '-e')
|
||||
passwd = auth_p.add_argument('--password', '-p')
|
||||
sessdir = auth_p.add_argument('--session-dir', dest='session_dir', default=None)
|
||||
|
||||
itunessrv = auth_p.add_argument('--itunes-server', '-s', dest='itunes_server')
|
||||
|
||||
## Multiple hack here just to achieve (appleid & password) || itunes_server
|
||||
# p._optionals.conflict_handler = 'ignore'
|
||||
# p._optionals._handle_conflict_ignore = lambda *args: None
|
||||
auth_p = p.add_mutually_exclusive_group(required=True)
|
||||
auth_p._group_actions.append(appleid)
|
||||
auth_p._group_actions.append(itunessrv)
|
||||
# auth_p._group_actions.append(sessdir)
|
||||
|
||||
auth_p = p.add_mutually_exclusive_group(required=True)
|
||||
auth_p._group_actions.append(passwd)
|
||||
auth_p._group_actions.append(itunessrv)
|
||||
|
||||
purchase_p = subp.add_parser('purchase')
|
||||
add_auth_options(purchase_p)
|
||||
purchase_p.add_argument('--appId', '-i', dest='appId')
|
||||
purchase_p.set_defaults(func=self.handlePurchase)
|
||||
|
||||
down_p = subp.add_parser('download')
|
||||
add_auth_options(down_p)
|
||||
down_p.add_argument('--appId', '-i', dest='appId')
|
||||
down_p.add_argument('--appVerId', dest='appVerId')
|
||||
down_p.add_argument('--purchase', action='store_true')
|
||||
down_p.add_argument('--downloadAllVersion', action='store_true')
|
||||
down_p.add_argument('--output-dir', '-o', dest='output_dir', default='.')
|
||||
down_p.set_defaults(func=self.handleDownload)
|
||||
|
||||
his_p = subp.add_parser('historyver')
|
||||
his_p.add_argument('--appId', '-i', dest='appId')
|
||||
his_p.add_argument('--purchase', action='store_true')
|
||||
his_p.add_argument('--output-dir', '-o', dest='output_dir', default='.')
|
||||
add_auth_options(his_p)
|
||||
his_p.set_defaults(func=self.handleHistoryVersion)
|
||||
|
||||
parser = argparse.ArgumentParser(description='IPATool-Python.', parents=[commparser])
|
||||
parser.add_argument('--log-level', '-l', dest='log_level', default='info',
|
||||
help='output level (default: info)')
|
||||
parser.add_argument('--json', dest='out_json', action='store_true',
|
||||
help='output json in stdout (log will always be put into stderr)')
|
||||
|
||||
# parse global flags & first comm's arguments
|
||||
args, rest = parser.parse_known_args()
|
||||
logging.getLogger().setLevel(args.log_level.upper())
|
||||
outJson = args.out_json
|
||||
|
||||
while True:
|
||||
args.func(args)
|
||||
if not rest:
|
||||
break
|
||||
args, rest = commparser.parse_known_args(rest)
|
||||
|
||||
if outJson and self.jsonOut:
|
||||
print(json.dumps(self.jsonOut, ensure_ascii=False))
|
||||
|
||||
def _outputJson(self, obj):
|
||||
self.jsonOut = obj
|
||||
|
||||
def handleLookup(self, args):
|
||||
if args.bundle_id:
|
||||
s = 'BundleID %s' % args.bundle_id
|
||||
else:
|
||||
s = 'AppID %s' % args.appId
|
||||
logger.info('Looking up app in country %s with BundleID %s' % (args.country, s))
|
||||
iTunes = iTunesClient(self.sess)
|
||||
appInfos = iTunes.lookup(bundleId=args.bundle_id, appId=args.appId, country=args.country)
|
||||
if appInfos.resultCount != 1:
|
||||
logger.fatal("Failed to find app in country %s with %s" % (args.country, s))
|
||||
return
|
||||
appInfo = appInfos.results[0]
|
||||
logger.info("Found app:\n\tName: %s\n\tVersion: %s\n\tbundleId: %s\n\tappId: %s" % (appInfo.trackName, appInfo.version, appInfo.bundleId, appInfo.trackId))
|
||||
self.appId = appInfo.trackId
|
||||
# self.appInfo = appInfo
|
||||
|
||||
ret = {
|
||||
"name": appInfo.trackName,
|
||||
"version": appInfo.version,
|
||||
"appId": appInfo.trackId,
|
||||
"bundleId": appInfo.bundleId,
|
||||
}
|
||||
|
||||
if args.get_verid:
|
||||
logger.info("Retrieving verId using iTunes webpage...")
|
||||
verId = iTunes.getAppVerId(self.appId, args.country)
|
||||
logger.info("Got current verId using iTunes webpage: %s" % verId)
|
||||
ret["appVerId"] = verId
|
||||
|
||||
self._outputJson(ret)
|
||||
|
||||
storeClientCache = {}
|
||||
def _get_StoreClient(self, args):
|
||||
cachekey = args.itunes_server or args.appleid
|
||||
store, lastseen = self.storeClientCache.get(cachekey, (None, None,))
|
||||
if store:
|
||||
if time.time() - lastseen < 30.0:
|
||||
return store
|
||||
del self.storeClientCache[cachekey]
|
||||
|
||||
newSess = pickle.loads(pickle.dumps(self.sess))
|
||||
Store = StoreClient(newSess)
|
||||
|
||||
if args.itunes_server:
|
||||
logger.info("Using iTunes interface %s to download app!" % args.itunes_server)
|
||||
servUrl = args.itunes_server
|
||||
def handle_iTunes_provider(url):
|
||||
startTime = time.time()
|
||||
r = requests.get(servUrl, params={
|
||||
'url': url
|
||||
})
|
||||
logger.debug("got itunes header in %.2f seconds", time.time() - startTime)
|
||||
|
||||
ret = r.json()
|
||||
kbsync = bytes.fromhex(ret.pop('kbsync'))
|
||||
guid = ret.pop('guid')
|
||||
retHdrs = ret.pop('headers')
|
||||
handled = {
|
||||
'headers': retHdrs,
|
||||
'kbsync': kbsync,
|
||||
'guid': guid,
|
||||
}
|
||||
if 'sbsync' in ret:
|
||||
handled['sbsync'] = bytes.fromhex(ret.pop('sbsync'))
|
||||
if 'afds' in ret:
|
||||
handled['afds'] = ret.pop('afds')
|
||||
return handled
|
||||
Store.iTunes_provider = handle_iTunes_provider
|
||||
else:
|
||||
appleid = args.appleid
|
||||
applepass = args.password
|
||||
|
||||
needLogin = True
|
||||
session_cache = os.path.join(args.session_dir, args.appleid) if args.session_dir else None
|
||||
if session_cache and os.path.exists(session_cache):
|
||||
needLogin = False
|
||||
try:
|
||||
# inside try in case the file format changed
|
||||
with open(session_cache, "r") as f:
|
||||
content = f.read()
|
||||
Store.authenticate_load_session(content)
|
||||
except Exception as e:
|
||||
logger.warning(f"Error loading session {session_cache}")
|
||||
os.unlink(session_cache)
|
||||
needLogin = True
|
||||
else:
|
||||
logger.info('Loaded session for %s' % (str(Store.authInfo)))
|
||||
if needLogin:
|
||||
logger.info("Logging into iTunes as %s ..." % appleid)
|
||||
|
||||
Store.authenticate(appleid, applepass)
|
||||
logger.info('Logged in as %s' % (str(Store.authInfo)))
|
||||
|
||||
if session_cache:
|
||||
with open(session_cache, "w") as f:
|
||||
f.write(Store.authenticate_save_session())
|
||||
|
||||
def authedPost(*args, **kwargs):
|
||||
if 'MZFinance.woa/wa/authenticate' in args[0]:
|
||||
return Store.sess.original_post(*args, **kwargs)
|
||||
for i in range(3):
|
||||
r = Store.sess.original_post(*args, **kwargs)
|
||||
isAuthFail = False
|
||||
try:
|
||||
d = plistlib.loads(r.content)
|
||||
if str(d['failureType']) in ("2034", "1008"):
|
||||
isAuthFail = True
|
||||
except:
|
||||
return r
|
||||
if not isAuthFail:
|
||||
return r
|
||||
Store.authenticate(appleid, applepass)
|
||||
if session_cache:
|
||||
with open(session_cache, "w") as f:
|
||||
f.write(Store.authenticate_save_session())
|
||||
continue
|
||||
Store.sess.original_post = Store.sess.post
|
||||
Store.sess.post = authedPost
|
||||
|
||||
self.storeClientCache[cachekey] = (Store, time.time(),)
|
||||
return Store
|
||||
|
||||
def _handleStoreException(self, _e):
|
||||
e = _e # type: StoreException
|
||||
logger.fatal("Store %s failed! Message: %s%s" % (e.req, e.errMsg, " (errorType %s)" % e.errType if e.errType else ''))
|
||||
logger.fatal(" Raw Response: %s" % (e.resp))
|
||||
|
||||
def handlePurchase(self, args):
|
||||
Store = self._get_StoreClient(args)
|
||||
logger.info('Try to purchase appId %s' % (self.appId))
|
||||
try:
|
||||
Store.purchase(self.appId)
|
||||
except StoreException as e:
|
||||
if e.errMsg == 'purchased_before':
|
||||
logger.warning('You have already purchased appId %s before' % (self.appId))
|
||||
else:
|
||||
raise
|
||||
|
||||
def handleHistoryVersion(self, args, caches=True):
|
||||
if args.appId:
|
||||
self.appId = args.appId
|
||||
|
||||
if not self.appId:
|
||||
logger.fatal("appId not supplied!")
|
||||
return
|
||||
|
||||
versionsJsonPath = args.output_dir + f"/historyver_{self.appId}.json"
|
||||
if caches:
|
||||
if os.path.exists(versionsJsonPath):
|
||||
cacheContent = None
|
||||
try:
|
||||
with open(versionsJsonPath) as f:
|
||||
cacheContent = json.load(f)
|
||||
except:
|
||||
pass
|
||||
if cacheContent is not None:
|
||||
logger.info('Loaded history version cache for appId %s' % self.appId)
|
||||
self.appVerIds = cacheContent['appVerIds']
|
||||
return
|
||||
|
||||
logger.info('Retrieving history version for appId %s' % self.appId)
|
||||
|
||||
try:
|
||||
Store = self._get_StoreClient(args)
|
||||
|
||||
logger.info('Retrieving download info for appId %s' % (self.appId))
|
||||
if args.purchase:
|
||||
logger.info('Purchasing appId %s' % (self.appId))
|
||||
# We have already successfully purchased, so don't purchase again :)
|
||||
self.handlePurchase(args)
|
||||
args.purchase = False
|
||||
|
||||
downResp = Store.download(self.appId, '', isRedownload=not args.purchase)
|
||||
logger.debug('Got download info: %s', downResp)
|
||||
if args.purchase:
|
||||
# We have already successfully purchased, so don't purchase again :)
|
||||
args.purchase = False
|
||||
|
||||
if not downResp.songList:
|
||||
logger.fatal("failed to get app download info!")
|
||||
raise StoreException('download', downResp, 'no songList')
|
||||
downInfo = downResp.songList[0]
|
||||
logger.info('Got available version ids %s', downInfo.metadata.softwareVersionExternalIdentifiers)
|
||||
self._outputJson({
|
||||
"appVerIds": downInfo.metadata.softwareVersionExternalIdentifiers
|
||||
})
|
||||
self.appVerIds = downInfo.metadata.softwareVersionExternalIdentifiers
|
||||
if caches:
|
||||
with open(versionsJsonPath, 'w') as f:
|
||||
json.dump({
|
||||
'appVerIds': self.appVerIds,
|
||||
}, f)
|
||||
except StoreException as e:
|
||||
self._handleStoreException(e)
|
||||
if not e.errMsg.startswith('http error status') and not e.errMsg.startswith(
|
||||
'We are temporarily unable to process your request') and not e.errMsg.startswith(
|
||||
"License not found"):
|
||||
# this error is persistent (e.g. app deleted)
|
||||
self.appVerIds = []
|
||||
if caches:
|
||||
with open(versionsJsonPath, 'w') as f:
|
||||
json.dump({
|
||||
'appVerIds': self.appVerIds,
|
||||
'error': str(e),
|
||||
'errorResp': str(e.resp),
|
||||
}, f)
|
||||
|
||||
def handleDownload(self, args):
|
||||
os.makedirs(args.output_dir, exist_ok=True)
|
||||
if args.downloadAllVersion:
|
||||
if os.path.exists(args.output_dir + "/all_done"):
|
||||
logger.info('Already fully finished, skipping!')
|
||||
return
|
||||
self.handleHistoryVersion(args, caches=True)
|
||||
if not self.appVerIds:
|
||||
logger.fatal('failed to retrive history versions for appId %s', args.appId)
|
||||
return
|
||||
everything_succ = True
|
||||
for appVerId in self.appVerIds:
|
||||
self.jsonOut = None
|
||||
stateFile = args.output_dir + '/' + str(appVerId) + '.finish'
|
||||
if os.path.exists(stateFile):
|
||||
logger.info('Skipping already downloaded')
|
||||
continue
|
||||
try:
|
||||
self.appVerId = appVerId
|
||||
self.downloadOne(args)
|
||||
if args.out_json and self.jsonOut:
|
||||
print(json.dumps(self.jsonOut, ensure_ascii=False))
|
||||
if self.jsonOut is not None: # successfully finished
|
||||
with open(stateFile, 'w') as f:
|
||||
f.write('1')
|
||||
except Exception as e:
|
||||
logger.fatal("error during downloading appVerId %s", appVerId, exc_info=1)
|
||||
everything_succ = False
|
||||
finally:
|
||||
self.jsonOut = None
|
||||
if everything_succ:
|
||||
with open(args.output_dir + "/all_done", 'w') as f:
|
||||
f.write("1")
|
||||
else:
|
||||
self.downloadOne(args)
|
||||
|
||||
def downloadOne(self, args):
|
||||
if args.appId:
|
||||
self.appId = args.appId
|
||||
if args.appVerId:
|
||||
self.appVerId = args.appVerId
|
||||
|
||||
if not self.appId:
|
||||
logger.fatal("appId not supplied!")
|
||||
return
|
||||
|
||||
logger.info("Downloading appId %s appVerId %s", self.appId, self.appVerId)
|
||||
try:
|
||||
appleid = args.appleid
|
||||
Store = self._get_StoreClient(args)
|
||||
|
||||
if args.purchase:
|
||||
self.handlePurchase(args)
|
||||
|
||||
logger.info('Retrieving download info for appId %s%s' % (self.appId, " with versionId %s" % self.appVerId if self.appVerId else ""))
|
||||
|
||||
downResp = Store.download(self.appId, self.appVerId, isRedownload=not args.purchase)
|
||||
logger.debug('Got download info: %s', downResp.as_dict())
|
||||
|
||||
if not downResp.songList:
|
||||
logger.fatal("failed to get app download info!")
|
||||
raise StoreException('download', downResp, 'no songList')
|
||||
downInfo = downResp.songList[0]
|
||||
|
||||
appName = downInfo.metadata.bundleDisplayName
|
||||
appId = downInfo.songId
|
||||
appBundleId = downInfo.metadata.softwareVersionBundleId
|
||||
appVerId = downInfo.metadata.softwareVersionExternalIdentifier
|
||||
# when downloading history versions, bundleShortVersionString will always give a wrong version number (the newest one)
|
||||
# should use bundleVersion in these cases
|
||||
appVer = downInfo.metadata.bundleShortVersionString if not self.appVerId else downInfo.metadata.bundleVersion
|
||||
|
||||
logger.info(f'Downloading app {appName} ({appBundleId}) with appId {appId} (version {appVer}, versionId {appVerId})')
|
||||
|
||||
# if self.appInfo:
|
||||
filename = '%s-%s-%s-%s.ipa' % (appBundleId,
|
||||
appVer,
|
||||
appId,
|
||||
appVerId)
|
||||
# else:
|
||||
# filename = '%s-%s.ipa' % (self.appId, appVerId)
|
||||
|
||||
filepath = os.path.join(args.output_dir, filename)
|
||||
logger.info("Downloading ipa to %s" % filepath)
|
||||
downloadFile(downInfo.URL, filepath)
|
||||
metadata = downInfo.metadata.as_dict()
|
||||
if appleid:
|
||||
metadata["apple-id"] = appleid
|
||||
metadata["userName"] = appleid
|
||||
logger.info("Writing out iTunesMetadata.plist...")
|
||||
if zipfile.is_zipfile(filepath):
|
||||
with zipfile.ZipFile(filepath, 'a') as ipaFile:
|
||||
logger.debug("Writing iTunesMetadata.plist")
|
||||
ipaFile.writestr(zipfile.ZipInfo("iTunesMetadata.plist", get_zipinfo_datetime()), plistlib.dumps(metadata))
|
||||
logger.debug("Writing IPAToolInfo.plist")
|
||||
ipaFile.writestr(zipfile.ZipInfo("IPAToolInfo.plist", get_zipinfo_datetime()), plistlib.dumps(downResp.as_dict()))
|
||||
|
||||
def findAppContentPath(c):
|
||||
if not c.startswith('Payload/'):
|
||||
return False
|
||||
pathparts = c.strip('/').split('/')
|
||||
if len(pathparts) != 2:
|
||||
return False
|
||||
if not pathparts[1].endswith(".app"):
|
||||
return False
|
||||
return True
|
||||
appContentDirChoices = [c for c in ipaFile.namelist() if findAppContentPath(c)]
|
||||
if len(appContentDirChoices) != 1:
|
||||
raise Exception("failed to find appContentDir, choices %s", appContentDirChoices)
|
||||
appContentDir = appContentDirChoices[0].rstrip('/')
|
||||
|
||||
processedSinf = False
|
||||
if (appContentDir + '/SC_Info/Manifest.plist') in ipaFile.namelist():
|
||||
#Try to get the Manifest.plist file, since it doesn't always exist.
|
||||
scManifestData = ipaFile.read(appContentDir + '/SC_Info/Manifest.plist')
|
||||
logger.debug("Got SC_Info/Manifest.plist: %s", scManifestData)
|
||||
scManifest = plistlib.loads(scManifestData)
|
||||
sinfs = {c.id: c.sinf for c in downInfo.sinfs}
|
||||
if 'SinfPaths' in scManifest:
|
||||
for i, sinfPath in enumerate(scManifest['SinfPaths']):
|
||||
logger.debug("Writing sinf to %s", sinfPath)
|
||||
ipaFile.writestr(appContentDir + '/' + sinfPath, sinfs[i])
|
||||
processedSinf = True
|
||||
if not processedSinf:
|
||||
logger.info('Manifest.plist does not exist! Assuming it is an old app without one...')
|
||||
infoListData = ipaFile.read(appContentDir + '/Info.plist') #Is this not loaded anywhere yet?
|
||||
infoList = plistlib.loads(infoListData)
|
||||
sinfPath = appContentDir + '/SC_Info/'+infoList['CFBundleExecutable']+".sinf"
|
||||
logger.debug("Writing sinf to %s", sinfPath)
|
||||
#Assuming there is only one .sinf file, hence the 0
|
||||
ipaFile.writestr(sinfPath, downInfo.sinfs[0].sinf)
|
||||
processedSinf = True
|
||||
|
||||
logger.info("Downloaded ipa to %s" % filename)
|
||||
else:
|
||||
plist = filepath[:-4]+".info.plist"
|
||||
with open(plist, "wb") as f:
|
||||
f.write(plistlib.dumps(downResp.as_dict()))
|
||||
plist = filepath[:-4]+".plist"
|
||||
with open(plist, "wb") as f:
|
||||
f.write(plistlib.dumps(metadata))
|
||||
logger.info("Downloaded ipa to %s and plist to %s" % (filename, plist))
|
||||
|
||||
self._outputJson({
|
||||
"appName": appName,
|
||||
"appBundleId": appBundleId,
|
||||
"appVer": appVer,
|
||||
"appId": appId,
|
||||
"appVerId": appVerId,
|
||||
|
||||
"downloadedIPA": filepath,
|
||||
"downloadedVerId": appVerId,
|
||||
"downloadURL": downInfo.URL,
|
||||
})
|
||||
except StoreException as e:
|
||||
self._handleStoreException(e)
|
||||
|
||||
def main():
|
||||
tool = IPATool()
|
||||
tool.tool_main()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
0
src_mac/ipatool-py/reqs/__init__.py
Executable file
0
src_mac/ipatool-py/reqs/__init__.py
Executable file
47
src_mac/ipatool-py/reqs/itunes.py
Executable file
47
src_mac/ipatool-py/reqs/itunes.py
Executable file
@@ -0,0 +1,47 @@
|
||||
__all__ = ['iTunesClient']
|
||||
|
||||
import json
|
||||
import re
|
||||
|
||||
from reqs.schemas.itunes_lookup_resp import ItunesLookupResp
|
||||
import requests
|
||||
|
||||
STORE_TABLE = {"AE":"143481-2,32","AG":"143540-2,32","AI":"143538-2,32","AL":"143575-2,32","AM":"143524-2,32","AO":"143564-2,32","AR":"143505-28,32","AT":"143445-4,32","AU":"143460-27,32","AZ":"143568-2,32","BB":"143541-2,32","BE":"143446-2,32","BF":"143578-2,32","BG":"143526-2,32","BH":"143559-2,32","BJ":"143576-2,32","BM":"143542-2,32","BN":"143560-2,32","BO":"143556-28,32","BR":"143503-15,32","BS":"143539-2,32","BT":"143577-2,32","BW":"143525-2,32","BY":"143565-2,32","BZ":"143555-2,32","CA":"143455-6,32","CG":"143582-2,32","CH":"143459-57,32","CL":"143483-28,32","CN":"143465-19,32","CO":"143501-28,32","CR":"143495-28,32","CV":"143580-2,32","CY":"143557-2,32","CZ":"143489-2,32","DE":"143443-4,32","DK":"143458-2,32","DM":"143545-2,32","DO":"143508-28,32","DZ":"143563-2,32","EC":"143509-28,32","EE":"143518-2,32","EG":"143516-2,32","ES":"143454-8,32","FI":"143447-2,32","FJ":"143583-2,32","FM":"143591-2,32","FR":"143442-3,32","GB":"143444-2,32","GD":"143546-2,32","GH":"143573-2,32","GM":"143584-2,32","GR":"143448-2,32","GT":"143504-28,32","GW":"143585-2,32","GY":"143553-2,32","HK":"143463-45,32","HN":"143510-28,32","HR":"143494-2,32","HU":"143482-2,32","ID":"143476-2,32","IE":"143449-2,32","IL":"143491-2,32","IN":"143467-2,32","IS":"143558-2,32","IT":"143450-7,32","JM":"143511-2,32","JO":"143528-2,32","JP":"143462-9,32","KE":"143529-2,32","KG":"143586-2,32","KH":"143579-2,32","KN":"143548-2,32","KR":"143466-13,32","KW":"143493-2,32","KY":"143544-2,32","KZ":"143517-2,32","LA":"143587-2,32","LB":"143497-2,32","LC":"143549-2,32","LK":"143486-2,32","LR":"143588-2,32","LT":"143520-2,32","LU":"143451-2,32","LV":"143519-2,32","MD":"143523-2,32","MG":"143531-2,32","MK":"143530-2,32","ML":"143532-2,32","MN":"143592-2,32","MO":"143515-45,32","MR":"143590-2,32","MS":"143547-2,32","MT":"143521-2,32","MU":"143533-2,32","MW":"143589-2,32","MX":"143468-28,32","MY":"143473-2,32","MZ":"143593-2,32","NA":"143594-2,32","NE":"143534-2,32","NG":"143561-2,32","NI":"143512-28,32","NL":"143452-10,32","NO":"143457-2,32","NP":"143484-2,32","NZ":"143461-27,32","OM":"143562-2,32","PA":"143485-28,32","PE":"143507-28,32","PG":"143597-2,32","PH":"143474-2,32","PK":"143477-2,32","PL":"143478-2,32","PT":"143453-24,32","PW":"143595-2,32","PY":"143513-28,32","QA":"143498-2,32","RO":"143487-2,32","RU":"143469-16,32","SA":"143479-2,32","SB":"143601-2,32","SC":"143599-2,32","SE":"143456-17,32","SG":"143464-19,32","SI":"143499-2,32","SK":"143496-2,32","SL":"143600-2,32","SN":"143535-2,32","SR":"143554-2,32","ST":"143598-2,32","SV":"143506-28,32","SZ":"143602-2,32","TC":"143552-2,32","TD":"143581-2,32","TH":"143475-2,32","TJ":"143603-2,32","TM":"143604-2,32","TN":"143536-2,32","TR":"143480-2,32","TT":"143551-2,32","TW":"143470-18,32","TZ":"143572-2,32","UA":"143492-2,32","UG":"143537-2,32","US":"143441-1,32","UY":"143514-2,32","UZ":"143566-2,32","VC":"143550-2,32","VE":"143502-28,32","VG":"143543-2,32","VN":"143471-2,32","YE":"143571-2,32","ZA":"143472-2,32","ZW":"143605-2,32"}
|
||||
|
||||
|
||||
class iTunesClient(object):
|
||||
def __init__(self, sess: requests.Session):
|
||||
self.sess = sess
|
||||
|
||||
# curl -k -X GET \
|
||||
# -H "Content-Type: application/x-www-form-urlencoded" \
|
||||
# https://itunes.apple.com/lookup?bundleId=com.touchingapp.potatsolite&limit=1&media=software
|
||||
def lookup(self, bundleId=None, appId=None, term=None, country="US", limit=1, media="software") -> ItunesLookupResp:
|
||||
r = self.sess.get("https://itunes.apple.com/lookup?",
|
||||
params={
|
||||
"bundleId": bundleId,
|
||||
"id": appId,
|
||||
"term": term,
|
||||
"country": country,
|
||||
"limit": limit,
|
||||
"media": media,
|
||||
},
|
||||
headers={
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
})
|
||||
return ItunesLookupResp.from_dict(r.json())
|
||||
|
||||
def getAppVerId(self, appId, country):
|
||||
if not ',' in country:
|
||||
storeFront = STORE_TABLE[country.upper()]
|
||||
else:
|
||||
storeFront = country
|
||||
appInfo = requests.get("https://apps.apple.com/app/id%s" % appId, headers={"X-Apple-Store-Front": storeFront}).text
|
||||
try:
|
||||
appParam = re.findall(r'"buyParams":"(.*?)"', appInfo)[0]
|
||||
except:
|
||||
appParam = re.findall(r'buy-params="(.*?)"', appInfo)[0]
|
||||
appParam = appParam.replace('&', '&')
|
||||
appParamDict = dict((c.split('=') for c in json.loads('"%s"' % appParam).split('&')))
|
||||
appVer = appParamDict['appExtVrsId']
|
||||
return appVer
|
||||
18
src_mac/ipatool-py/reqs/schemas/README.md
Executable file
18
src_mac/ipatool-py/reqs/schemas/README.md
Executable file
@@ -0,0 +1,18 @@
|
||||
# Schema Definitions for ipatool-py
|
||||
|
||||
In this directory, JSON Schema Definition files are stored in `schema_defs`, with corresponding plist examples in `schema_examples`
|
||||
|
||||
## How to generate schema from plist
|
||||
|
||||
1. Convert plist to corresponding JSON, using either `plistlib` or online tools
|
||||
2. Use https://www.liquid-technologies.com/online-json-to-schema-converter to convert JSON to schema
|
||||
- You have to switch the `Array Rules` option to `List Validation`
|
||||
3. Merge different request / response body's schema manually
|
||||
- Usually the "required" field can help you merging the json schema
|
||||
|
||||
## Regenerate schema bindings
|
||||
|
||||
Run this in current folder:
|
||||
```
|
||||
python3 -m schema_defs
|
||||
```
|
||||
0
src_mac/ipatool-py/reqs/schemas/__init__.py
Executable file
0
src_mac/ipatool-py/reqs/schemas/__init__.py
Executable file
1593
src_mac/ipatool-py/reqs/schemas/itunes_lookup_resp.py
Executable file
1593
src_mac/ipatool-py/reqs/schemas/itunes_lookup_resp.py
Executable file
File diff suppressed because it is too large
Load Diff
0
src_mac/ipatool-py/reqs/schemas/schema_defs/__init__.py
Executable file
0
src_mac/ipatool-py/reqs/schemas/schema_defs/__init__.py
Executable file
12
src_mac/ipatool-py/reqs/schemas/schema_defs/__main__.py
Executable file
12
src_mac/ipatool-py/reqs/schemas/schema_defs/__main__.py
Executable file
@@ -0,0 +1,12 @@
|
||||
import os
|
||||
import os.path as path
|
||||
import subprocess
|
||||
|
||||
curpath = path.dirname(__file__)
|
||||
outpath = path.dirname(curpath)
|
||||
for p in os.listdir(curpath):
|
||||
if not p.endswith('.json'):
|
||||
continue
|
||||
#subprocess.call(["jsonschema2popo2", "--translate-properties", "--use-types", "-o", path.join(outpath, p.split('.')[0] + '.py'), path.join(curpath, p)])
|
||||
print("Converting %s" % p)
|
||||
subprocess.call(["jsonschema2popo2", "--use-types", "-o", path.join(outpath, p.split('.')[0] + '.py'), path.join(curpath, p)])
|
||||
222
src_mac/ipatool-py/reqs/schemas/schema_defs/itunes_lookup_resp.json
Executable file
222
src_mac/ipatool-py/reqs/schemas/schema_defs/itunes_lookup_resp.json
Executable file
@@ -0,0 +1,222 @@
|
||||
{
|
||||
"title": "iTunes Lookup Resp",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"resultCount": {
|
||||
"type": "integer"
|
||||
},
|
||||
"results": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"appletvScreenshotUrls": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": ["number","string","boolean","object","array", "null"]
|
||||
}
|
||||
},
|
||||
"screenshotUrls": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"ipadScreenshotUrls": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"artworkUrl60": {
|
||||
"type": "string"
|
||||
},
|
||||
"artworkUrl512": {
|
||||
"type": "string"
|
||||
},
|
||||
"artworkUrl100": {
|
||||
"type": "string"
|
||||
},
|
||||
"artistViewUrl": {
|
||||
"type": "string"
|
||||
},
|
||||
"supportedDevices": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"advisories": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": ["number","string","boolean","object","array", "null"]
|
||||
}
|
||||
},
|
||||
"isGameCenterEnabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"kind": {
|
||||
"type": "string"
|
||||
},
|
||||
"features": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"minimumOsVersion": {
|
||||
"type": "string"
|
||||
},
|
||||
"trackCensoredName": {
|
||||
"type": "string"
|
||||
},
|
||||
"languageCodesISO2A": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"fileSizeBytes": {
|
||||
"type": "string"
|
||||
},
|
||||
"formattedPrice": {
|
||||
"type": "string"
|
||||
},
|
||||
"contentAdvisoryRating": {
|
||||
"type": "string"
|
||||
},
|
||||
"averageUserRatingForCurrentVersion": {
|
||||
"type": "number"
|
||||
},
|
||||
"userRatingCountForCurrentVersion": {
|
||||
"type": "integer"
|
||||
},
|
||||
"averageUserRating": {
|
||||
"type": "number"
|
||||
},
|
||||
"trackViewUrl": {
|
||||
"type": "string"
|
||||
},
|
||||
"trackContentRating": {
|
||||
"type": "string"
|
||||
},
|
||||
"releaseDate": {
|
||||
"type": "string"
|
||||
},
|
||||
"genreIds": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"primaryGenreName": {
|
||||
"type": "string"
|
||||
},
|
||||
"trackId": {
|
||||
"type": "integer"
|
||||
},
|
||||
"trackName": {
|
||||
"type": "string"
|
||||
},
|
||||
"sellerName": {
|
||||
"type": "string"
|
||||
},
|
||||
"isVppDeviceBasedLicensingEnabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"currentVersionReleaseDate": {
|
||||
"type": "string"
|
||||
},
|
||||
"releaseNotes": {
|
||||
"type": "string"
|
||||
},
|
||||
"primaryGenreId": {
|
||||
"type": "integer"
|
||||
},
|
||||
"currency": {
|
||||
"type": "string"
|
||||
},
|
||||
"version": {
|
||||
"type": "string"
|
||||
},
|
||||
"wrapperType": {
|
||||
"type": "string"
|
||||
},
|
||||
"artistId": {
|
||||
"type": "integer"
|
||||
},
|
||||
"artistName": {
|
||||
"type": "string"
|
||||
},
|
||||
"genres": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"price": {
|
||||
"type": "number"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"bundleId": {
|
||||
"type": "string"
|
||||
},
|
||||
"userRatingCount": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"appletvScreenshotUrls",
|
||||
"screenshotUrls",
|
||||
"ipadScreenshotUrls",
|
||||
"artworkUrl60",
|
||||
"artworkUrl512",
|
||||
"artworkUrl100",
|
||||
"artistViewUrl",
|
||||
"supportedDevices",
|
||||
"advisories",
|
||||
"isGameCenterEnabled",
|
||||
"kind",
|
||||
"features",
|
||||
"minimumOsVersion",
|
||||
"trackCensoredName",
|
||||
"languageCodesISO2A",
|
||||
"fileSizeBytes",
|
||||
"formattedPrice",
|
||||
"contentAdvisoryRating",
|
||||
"averageUserRatingForCurrentVersion",
|
||||
"userRatingCountForCurrentVersion",
|
||||
"averageUserRating",
|
||||
"trackViewUrl",
|
||||
"trackContentRating",
|
||||
"releaseDate",
|
||||
"genreIds",
|
||||
"primaryGenreName",
|
||||
"trackId",
|
||||
"trackName",
|
||||
"sellerName",
|
||||
"isVppDeviceBasedLicensingEnabled",
|
||||
"currentVersionReleaseDate",
|
||||
"releaseNotes",
|
||||
"primaryGenreId",
|
||||
"currency",
|
||||
"version",
|
||||
"wrapperType",
|
||||
"artistId",
|
||||
"artistName",
|
||||
"genres",
|
||||
"price",
|
||||
"description",
|
||||
"bundleId",
|
||||
"userRatingCount"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"resultCount",
|
||||
"results"
|
||||
]
|
||||
}
|
||||
37
src_mac/ipatool-py/reqs/schemas/schema_defs/store_authenticate_req.json
Executable file
37
src_mac/ipatool-py/reqs/schemas/schema_defs/store_authenticate_req.json
Executable file
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"title": "Store Authenticate Req",
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"appleId": {
|
||||
"type": "string"
|
||||
},
|
||||
"attempt": {
|
||||
"type": "string"
|
||||
},
|
||||
"createSession": {
|
||||
"type": "string"
|
||||
},
|
||||
"guid": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
},
|
||||
"rmp": {
|
||||
"type": "string"
|
||||
},
|
||||
"why": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"appleId",
|
||||
"attempt",
|
||||
"createSession",
|
||||
"guid",
|
||||
"password",
|
||||
"rmp",
|
||||
"why"
|
||||
]
|
||||
}
|
||||
324
src_mac/ipatool-py/reqs/schemas/schema_defs/store_authenticate_resp.json
Executable file
324
src_mac/ipatool-py/reqs/schemas/schema_defs/store_authenticate_resp.json
Executable file
@@ -0,0 +1,324 @@
|
||||
{
|
||||
"title": "Store Authenticate Resp",
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"pings": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": ["number","string","boolean","object","array", "null"]
|
||||
}
|
||||
},
|
||||
"cancel-purchase-batch": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"customerMessage": {
|
||||
"type": "string"
|
||||
},
|
||||
"failureType": {
|
||||
"type": "string"
|
||||
},
|
||||
"accountInfo": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"appleId": {
|
||||
"type": "string"
|
||||
},
|
||||
"address": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"firstName": {
|
||||
"type": "string"
|
||||
},
|
||||
"lastName": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"firstName",
|
||||
"lastName"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"appleId",
|
||||
"address"
|
||||
]
|
||||
},
|
||||
"passwordToken": {
|
||||
"type": "string"
|
||||
},
|
||||
"clearToken": {
|
||||
"type": "string"
|
||||
},
|
||||
"m-allowed": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"is-cloud-enabled": {
|
||||
"type": "string"
|
||||
},
|
||||
"dsPersonId": {
|
||||
"type": "string"
|
||||
},
|
||||
"creditDisplay": {
|
||||
"type": "string"
|
||||
},
|
||||
"creditBalance": {
|
||||
"type": "string"
|
||||
},
|
||||
"freeSongBalance": {
|
||||
"type": "string"
|
||||
},
|
||||
"isManagedStudent": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"action": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"kind": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"kind"
|
||||
]
|
||||
},
|
||||
"subscriptionStatus": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"terms": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"latestTerms": {
|
||||
"type": "integer"
|
||||
},
|
||||
"agreedToTerms": {
|
||||
"type": "integer"
|
||||
},
|
||||
"source": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"type",
|
||||
"latestTerms",
|
||||
"agreedToTerms",
|
||||
"source"
|
||||
]
|
||||
}
|
||||
},
|
||||
"account": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"isMinor": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"suspectUnderage": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"isMinor",
|
||||
"suspectUnderage"
|
||||
]
|
||||
},
|
||||
"family": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"hasFamily": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"hasFamily"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"terms",
|
||||
"account",
|
||||
"family"
|
||||
]
|
||||
},
|
||||
"accountFlags": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"personalization": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"underThirteen": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"identityLastVerified": {
|
||||
"type": "integer"
|
||||
},
|
||||
"verifiedExpirationDate": {
|
||||
"type": "integer"
|
||||
},
|
||||
"retailDemo": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"autoPlay": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"isDisabledAccount": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"isRestrictedAccount": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"isManagedAccount": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"isInRestrictedRegion": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"accountFlagsVersion": {
|
||||
"type": "integer"
|
||||
},
|
||||
"hasAgreedToTerms": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"hasAgreedToAppClipTerms": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"hasWatchHardwareOffer": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"isInFamily": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"hasSubscriptionFamilySharingEnabled": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"personalization",
|
||||
"underThirteen",
|
||||
"identityLastVerified",
|
||||
"verifiedExpirationDate",
|
||||
"retailDemo",
|
||||
"autoPlay",
|
||||
"isDisabledAccount",
|
||||
"isRestrictedAccount",
|
||||
"isManagedAccount",
|
||||
"isInRestrictedRegion",
|
||||
"accountFlagsVersion",
|
||||
"hasAgreedToTerms",
|
||||
"hasAgreedToAppClipTerms",
|
||||
"hasWatchHardwareOffer",
|
||||
"isInFamily",
|
||||
"hasSubscriptionFamilySharingEnabled"
|
||||
]
|
||||
},
|
||||
"status": {
|
||||
"type": "integer"
|
||||
},
|
||||
"download-queue-info": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"download-queue-item-count": {
|
||||
"type": "integer"
|
||||
},
|
||||
"dsid": {
|
||||
"type": "integer"
|
||||
},
|
||||
"is-auto-download-machine": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"download-queue-item-count",
|
||||
"dsid",
|
||||
"is-auto-download-machine"
|
||||
]
|
||||
},
|
||||
"privacyAcknowledgement": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"com.apple.onboarding.appstore": {
|
||||
"type": "integer"
|
||||
},
|
||||
"com.apple.onboarding.applemusic": {
|
||||
"type": "integer"
|
||||
},
|
||||
"com.apple.onboarding.videos": {
|
||||
"type": "integer"
|
||||
},
|
||||
"com.apple.onboarding.itunesstore": {
|
||||
"type": "integer"
|
||||
},
|
||||
"com.apple.onboarding.itunesu": {
|
||||
"type": "integer"
|
||||
},
|
||||
"com.apple.onboarding.applearcade": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"com.apple.onboarding.appstore",
|
||||
"com.apple.onboarding.applemusic",
|
||||
"com.apple.onboarding.videos",
|
||||
"com.apple.onboarding.itunesstore",
|
||||
"com.apple.onboarding.itunesu",
|
||||
"com.apple.onboarding.applearcade"
|
||||
]
|
||||
},
|
||||
"dialog": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"m-allowed": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"explanation": {
|
||||
"type": "string"
|
||||
},
|
||||
"defaultButton": {
|
||||
"type": "string"
|
||||
},
|
||||
"okButtonString": {
|
||||
"type": "string"
|
||||
},
|
||||
"initialCheckboxValue": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"m-allowed",
|
||||
"message",
|
||||
"explanation",
|
||||
"defaultButton",
|
||||
"okButtonString",
|
||||
"initialCheckboxValue"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"pings",
|
||||
"accountInfo",
|
||||
"passwordToken",
|
||||
"clearToken",
|
||||
"m-allowed",
|
||||
"is-cloud-enabled",
|
||||
"dsPersonId",
|
||||
"creditDisplay",
|
||||
"creditBalance",
|
||||
"freeSongBalance",
|
||||
"isManagedStudent",
|
||||
"action",
|
||||
"subscriptionStatus",
|
||||
"accountFlags",
|
||||
"status",
|
||||
"download-queue-info",
|
||||
"privacyAcknowledgement",
|
||||
"dialog"
|
||||
]
|
||||
}
|
||||
120
src_mac/ipatool-py/reqs/schemas/schema_defs/store_buyproduct_req.json
Executable file
120
src_mac/ipatool-py/reqs/schemas/schema_defs/store_buyproduct_req.json
Executable file
@@ -0,0 +1,120 @@
|
||||
{
|
||||
"title": "Store BuyProduct Req",
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"ageCheck": {
|
||||
"type": "string"
|
||||
},
|
||||
"appExtVrsId": {
|
||||
"type": "string"
|
||||
},
|
||||
"guid": {
|
||||
"type": "string"
|
||||
},
|
||||
"hasBeenAuthedForBuy": {
|
||||
"type": "string"
|
||||
},
|
||||
"isInApp": {
|
||||
"type": "string"
|
||||
},
|
||||
"kbsync": {
|
||||
"type": "string"
|
||||
},
|
||||
"sbsync": {
|
||||
"type": "string"
|
||||
},
|
||||
"afds": {
|
||||
"type": "string"
|
||||
},
|
||||
"machineName": {
|
||||
"type": "string"
|
||||
},
|
||||
"mtApp": {
|
||||
"type": "string"
|
||||
},
|
||||
"mtClientId": {
|
||||
"type": "string"
|
||||
},
|
||||
"mtEventTime": {
|
||||
"type": "string"
|
||||
},
|
||||
"mtPageId": {
|
||||
"type": "string"
|
||||
},
|
||||
"mtPageType": {
|
||||
"type": "string"
|
||||
},
|
||||
"mtPrevPage": {
|
||||
"type": "string"
|
||||
},
|
||||
"mtRequestId": {
|
||||
"type": "string"
|
||||
},
|
||||
"mtTopic": {
|
||||
"type": "string"
|
||||
},
|
||||
"needDiv": {
|
||||
"type": "string"
|
||||
},
|
||||
"pg": {
|
||||
"type": "string"
|
||||
},
|
||||
"price": {
|
||||
"type": "string"
|
||||
},
|
||||
"pricingParameters": {
|
||||
"type": "string"
|
||||
},
|
||||
"productType": {
|
||||
"type": "string"
|
||||
},
|
||||
"salableAdamId": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
"hasAskedToFulfillPreorder": {
|
||||
"type": "string"
|
||||
},
|
||||
"buyWithoutAuthorization": {
|
||||
"type": "string"
|
||||
},
|
||||
"hasDoneAgeCheck": {
|
||||
"type": "string"
|
||||
},
|
||||
"hasConfirmedPaymentSheet": {
|
||||
"type": "string"
|
||||
},
|
||||
"asn": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"guid",
|
||||
"kbsync",
|
||||
"price",
|
||||
"pricingParameters",
|
||||
"productType",
|
||||
"salableAdamId",
|
||||
"appExtVrsId"
|
||||
],
|
||||
"optional": [
|
||||
"ageCheck",
|
||||
"hasBeenAuthedForBuy",
|
||||
"hasConfirmedPaymentSheet",
|
||||
"asn",
|
||||
"isInApp",
|
||||
|
||||
"machineName",
|
||||
"mtApp",
|
||||
"mtClientId",
|
||||
"mtEventTime",
|
||||
"mtPageId",
|
||||
"mtPageType",
|
||||
"mtPrevPage",
|
||||
"mtRequestId",
|
||||
"mtTopic",
|
||||
"needDiv",
|
||||
"pg"
|
||||
]
|
||||
}
|
||||
732
src_mac/ipatool-py/reqs/schemas/schema_defs/store_buyproduct_resp.json
Executable file
732
src_mac/ipatool-py/reqs/schemas/schema_defs/store_buyproduct_resp.json
Executable file
@@ -0,0 +1,732 @@
|
||||
{
|
||||
"title": "Store BuyProduct Resp",
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"pings": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": ["number","string","boolean","object","array", "null"]
|
||||
}
|
||||
},
|
||||
"jingleDocType": {
|
||||
"type": "string"
|
||||
},
|
||||
"jingleAction": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "integer"
|
||||
},
|
||||
"dsPersonId": {
|
||||
"type": "string"
|
||||
},
|
||||
"creditDisplay": {
|
||||
"type": "string"
|
||||
},
|
||||
"creditBalance": {
|
||||
"type": "string"
|
||||
},
|
||||
"freeSongBalance": {
|
||||
"type": "string"
|
||||
},
|
||||
"creditDisplayInternal": {
|
||||
"type": "string"
|
||||
},
|
||||
"authorized": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"download-queue-item-count": {
|
||||
"type": "integer"
|
||||
},
|
||||
"songList": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"songId": {
|
||||
"type": "integer"
|
||||
},
|
||||
"URL": {
|
||||
"type": "string"
|
||||
},
|
||||
"downloadKey": {
|
||||
"type": "string"
|
||||
},
|
||||
"artworkURL": {
|
||||
"type": "string"
|
||||
},
|
||||
"artwork-urls": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"image-type": {
|
||||
"type": "string"
|
||||
},
|
||||
"default": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"url": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"url"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"image-type",
|
||||
"default"
|
||||
]
|
||||
},
|
||||
"md5": {
|
||||
"type": "string"
|
||||
},
|
||||
"chunks": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"chunkSize": {
|
||||
"type": "integer"
|
||||
},
|
||||
"hashes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"chunkSize",
|
||||
"hashes"
|
||||
]
|
||||
},
|
||||
"isStreamable": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"uncompressedSize": {
|
||||
"type": "integer"
|
||||
},
|
||||
"sinfs": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"sinf": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"sinf"
|
||||
]
|
||||
}
|
||||
},
|
||||
"purchaseDate": {
|
||||
"type": "string"
|
||||
},
|
||||
"download-id": {
|
||||
"type": "string"
|
||||
},
|
||||
"is-in-queue": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"asset-info": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"file-size": {
|
||||
"type": "integer"
|
||||
},
|
||||
"flavor": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"file-size",
|
||||
"flavor"
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"MacUIRequiredDeviceCapabilities": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"arm64": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"arm64"
|
||||
]
|
||||
},
|
||||
"UIRequiredDeviceCapabilities": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"arm64": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"arm64"
|
||||
]
|
||||
},
|
||||
"WKRunsIndependentlyOfCompanionApp": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"WKWatchOnly": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"appleWatchEnabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"artistId": {
|
||||
"type": "integer"
|
||||
},
|
||||
"artistName": {
|
||||
"type": "string"
|
||||
},
|
||||
"bundleDisplayName": {
|
||||
"type": "string"
|
||||
},
|
||||
"bundleShortVersionString": {
|
||||
"type": "string"
|
||||
},
|
||||
"bundleVersion": {
|
||||
"type": "string"
|
||||
},
|
||||
"copyright": {
|
||||
"type": "string"
|
||||
},
|
||||
"fileExtension": {
|
||||
"type": "string"
|
||||
},
|
||||
"gameCenterEnabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"gameCenterEverEnabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"genre": {
|
||||
"type": "string"
|
||||
},
|
||||
"genreId": {
|
||||
"type": "integer"
|
||||
},
|
||||
"itemId": {
|
||||
"type": "integer"
|
||||
},
|
||||
"itemName": {
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"type": "string"
|
||||
},
|
||||
"nameTranscriptions": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"zh-Hans-CN": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"zh-Hans-CN"
|
||||
]
|
||||
},
|
||||
"playlistName": {
|
||||
"type": "string"
|
||||
},
|
||||
"product-type": {
|
||||
"type": "string"
|
||||
},
|
||||
"rating": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"content": {
|
||||
"type": "string"
|
||||
},
|
||||
"label": {
|
||||
"type": "string"
|
||||
},
|
||||
"rank": {
|
||||
"type": "integer"
|
||||
},
|
||||
"system": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"content",
|
||||
"label",
|
||||
"rank",
|
||||
"system"
|
||||
]
|
||||
},
|
||||
"releaseDate": {
|
||||
"type": "string"
|
||||
},
|
||||
"requiresRosetta": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"runsOnAppleSilicon": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"runsOnIntel": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"s": {
|
||||
"type": "integer"
|
||||
},
|
||||
"software-platform": {
|
||||
"type": "string"
|
||||
},
|
||||
"softwareIcon57x57URL": {
|
||||
"type": "string"
|
||||
},
|
||||
"softwareIconNeedsShine": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"softwareSupportedDeviceIds": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"softwareVersionBundleId": {
|
||||
"type": "string"
|
||||
},
|
||||
"softwareVersionExternalIdentifier": {
|
||||
"type": "integer"
|
||||
},
|
||||
"softwareVersionExternalIdentifiers": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"vendorId": {
|
||||
"type": "integer"
|
||||
},
|
||||
"drmVersionNumber": {
|
||||
"type": "integer"
|
||||
},
|
||||
"versionRestrictions": {
|
||||
"type": "integer"
|
||||
},
|
||||
"storeCohort": {
|
||||
"type": "string"
|
||||
},
|
||||
"hasOrEverHasHadIAP": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"MacUIRequiredDeviceCapabilities",
|
||||
"UIRequiredDeviceCapabilities",
|
||||
"WKRunsIndependentlyOfCompanionApp",
|
||||
"WKWatchOnly",
|
||||
"appleWatchEnabled",
|
||||
"artistId",
|
||||
"artistName",
|
||||
"bundleDisplayName",
|
||||
"bundleShortVersionString",
|
||||
"bundleVersion",
|
||||
"copyright",
|
||||
"fileExtension",
|
||||
"gameCenterEnabled",
|
||||
"gameCenterEverEnabled",
|
||||
"genre",
|
||||
"genreId",
|
||||
"itemId",
|
||||
"itemName",
|
||||
"kind",
|
||||
"nameTranscriptions",
|
||||
"playlistName",
|
||||
"product-type",
|
||||
"rating",
|
||||
"releaseDate",
|
||||
"requiresRosetta",
|
||||
"runsOnAppleSilicon",
|
||||
"runsOnIntel",
|
||||
"s",
|
||||
"software-platform",
|
||||
"softwareIcon57x57URL",
|
||||
"softwareIconNeedsShine",
|
||||
"softwareSupportedDeviceIds",
|
||||
"softwareVersionBundleId",
|
||||
"softwareVersionExternalIdentifier",
|
||||
"softwareVersionExternalIdentifiers",
|
||||
"vendorId",
|
||||
"drmVersionNumber",
|
||||
"versionRestrictions",
|
||||
"storeCohort",
|
||||
"hasOrEverHasHadIAP"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"songId",
|
||||
"URL",
|
||||
"downloadKey",
|
||||
"artworkURL",
|
||||
"artwork-urls",
|
||||
"md5",
|
||||
"chunks",
|
||||
"isStreamable",
|
||||
"uncompressedSize",
|
||||
"sinfs",
|
||||
"purchaseDate",
|
||||
"download-id",
|
||||
"is-in-queue",
|
||||
"asset-info",
|
||||
"metadata"
|
||||
]
|
||||
}
|
||||
},
|
||||
"download-queue-info": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"download-queue-item-count": {
|
||||
"type": "integer"
|
||||
},
|
||||
"dsid": {
|
||||
"type": "integer"
|
||||
},
|
||||
"is-auto-download-machine": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"download-queue-item-count",
|
||||
"dsid",
|
||||
"is-auto-download-machine"
|
||||
]
|
||||
},
|
||||
"metrics": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"itemIds": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"price": {
|
||||
"type": "integer"
|
||||
},
|
||||
"priceType": {
|
||||
"type": "string"
|
||||
},
|
||||
"productTypes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"mtApp": {
|
||||
"type": "string"
|
||||
},
|
||||
"mtClientId": {
|
||||
"type": "string"
|
||||
},
|
||||
"mtEventTime": {
|
||||
"type": "string"
|
||||
},
|
||||
"mtPageId": {
|
||||
"type": "string"
|
||||
},
|
||||
"mtPageType": {
|
||||
"type": "string"
|
||||
},
|
||||
"mtPrevPage": {
|
||||
"type": "string"
|
||||
},
|
||||
"mtRequestId": {
|
||||
"type": "string"
|
||||
},
|
||||
"mtTopic": {
|
||||
"type": "string"
|
||||
},
|
||||
"currency": {
|
||||
"type": "string"
|
||||
},
|
||||
"exchangeRateToUSD": {
|
||||
"type": "number"
|
||||
},
|
||||
"commerceEvent_purchase_priceType": {
|
||||
"type": "string"
|
||||
},
|
||||
"commerceEvent_storeFrontId": {
|
||||
"type": "string"
|
||||
},
|
||||
"commerceEvent_result_resultType": {
|
||||
"type": "integer"
|
||||
},
|
||||
"commerceEvent_flowType": {
|
||||
"type": "integer"
|
||||
},
|
||||
"commerceEvent_flowStep": {
|
||||
"type": "integer"
|
||||
},
|
||||
|
||||
"dialogId": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"messageCode": {
|
||||
"type": "string"
|
||||
},
|
||||
"options": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"actionUrl": {
|
||||
"type": "string"
|
||||
},
|
||||
"asnState": {
|
||||
"type": "integer"
|
||||
},
|
||||
"eventType": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"mtApp",
|
||||
"mtClientId",
|
||||
"mtEventTime",
|
||||
"mtPageId",
|
||||
"mtPageType",
|
||||
"mtPrevPage",
|
||||
"mtRequestId",
|
||||
"mtTopic"
|
||||
],
|
||||
"optional": [
|
||||
"itemIds",
|
||||
"price",
|
||||
"priceType",
|
||||
"productTypes",
|
||||
"currency",
|
||||
"exchangeRateToUSD",
|
||||
"commerceEvent_purchase_priceType",
|
||||
"commerceEvent_storeFrontId",
|
||||
"commerceEvent_result_resultType",
|
||||
"commerceEvent_flowType",
|
||||
"commerceEvent_flowStep",
|
||||
|
||||
"dialogId",
|
||||
"message",
|
||||
"messageCode",
|
||||
"options",
|
||||
"actionUrl",
|
||||
"asnState",
|
||||
"eventType"
|
||||
]
|
||||
},
|
||||
"duAnonymousPings": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"subscriptionStatus": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"music": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"reason": {
|
||||
"type": "string"
|
||||
},
|
||||
"isAdmin": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"isNotEligibleForFreeTrial": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"status",
|
||||
"reason",
|
||||
"isAdmin",
|
||||
"isNotEligibleForFreeTrial"
|
||||
]
|
||||
},
|
||||
"terms": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"latestTerms": {
|
||||
"type": "integer"
|
||||
},
|
||||
"agreedToTerms": {
|
||||
"type": "integer"
|
||||
},
|
||||
"source": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"type",
|
||||
"latestTerms",
|
||||
"agreedToTerms",
|
||||
"source"
|
||||
]
|
||||
}
|
||||
},
|
||||
"account": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"isMinor": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"suspectUnderage": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"isMinor",
|
||||
"suspectUnderage"
|
||||
]
|
||||
},
|
||||
"family": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"hasFamily": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"hasFamily"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"music",
|
||||
"terms",
|
||||
"account",
|
||||
"family"
|
||||
]
|
||||
},
|
||||
"cancel-purchase-batch": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"failureType": {
|
||||
"type": "string"
|
||||
},
|
||||
"customerMessage": {
|
||||
"type": "string"
|
||||
},
|
||||
"m-allowed": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"dialog": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"kind": {
|
||||
"type": "string"
|
||||
},
|
||||
"m-allowed": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"use-keychain": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"isFree": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"explanation": {
|
||||
"type": "string"
|
||||
},
|
||||
"defaultButton": {
|
||||
"type": "string"
|
||||
},
|
||||
"okButtonString": {
|
||||
"type": "string"
|
||||
},
|
||||
"okButtonAction": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"kind": {
|
||||
"type": "string"
|
||||
},
|
||||
"buyParams": {
|
||||
"type": "string"
|
||||
},
|
||||
"itemName": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"kind",
|
||||
"buyParams",
|
||||
"itemName"
|
||||
]
|
||||
},
|
||||
"cancelButtonString": {
|
||||
"type": "string"
|
||||
},
|
||||
"initialCheckboxValue": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"kind",
|
||||
"m-allowed",
|
||||
"use-keychain",
|
||||
"isFree",
|
||||
"message",
|
||||
"explanation",
|
||||
"defaultButton",
|
||||
"okButtonString",
|
||||
"okButtonAction",
|
||||
"cancelButtonString",
|
||||
"initialCheckboxValue"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"pings",
|
||||
"metrics"
|
||||
],
|
||||
"optional": [
|
||||
"jingleDocType",
|
||||
"jingleAction",
|
||||
"status",
|
||||
"dsPersonId",
|
||||
"creditDisplay",
|
||||
"creditBalance",
|
||||
"freeSongBalance",
|
||||
"creditDisplayInternal",
|
||||
"authorized",
|
||||
"download-queue-item-count",
|
||||
"songList",
|
||||
"download-queue-info",
|
||||
"duAnonymousPings",
|
||||
"subscriptionStatus",
|
||||
|
||||
"failureType",
|
||||
"customerMessage",
|
||||
"m-allowed",
|
||||
"dialog",
|
||||
"cancel-purchase-batch"
|
||||
]
|
||||
}
|
||||
24
src_mac/ipatool-py/reqs/schemas/schema_defs/store_download_req.json
Executable file
24
src_mac/ipatool-py/reqs/schemas/schema_defs/store_download_req.json
Executable file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"title": "Store Download Req",
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"creditDisplay": {
|
||||
"type": "string"
|
||||
},
|
||||
"guid": {
|
||||
"type": "string"
|
||||
},
|
||||
"salableAdamId": {
|
||||
"type": "string"
|
||||
},
|
||||
"appExtVrsId": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"creditDisplay",
|
||||
"guid",
|
||||
"salableAdamId"
|
||||
]
|
||||
}
|
||||
497
src_mac/ipatool-py/reqs/schemas/schema_defs/store_download_resp.json
Executable file
497
src_mac/ipatool-py/reqs/schemas/schema_defs/store_download_resp.json
Executable file
@@ -0,0 +1,497 @@
|
||||
{
|
||||
"title": "Store Download Resp",
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"pings": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": ["number","string","boolean","object","array", "null"]
|
||||
}
|
||||
},
|
||||
"cancel-purchase-batch": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"customerMessage": {
|
||||
"type": "string"
|
||||
},
|
||||
"failureType": {
|
||||
"type": "string"
|
||||
},
|
||||
"jingleDocType": {
|
||||
"type": "string"
|
||||
},
|
||||
"jingleAction": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "integer"
|
||||
},
|
||||
"dsPersonId": {
|
||||
"type": "string"
|
||||
},
|
||||
"creditDisplay": {
|
||||
"type": "string"
|
||||
},
|
||||
"creditBalance": {
|
||||
"type": "string"
|
||||
},
|
||||
"freeSongBalance": {
|
||||
"type": "string"
|
||||
},
|
||||
"authorized": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"download-queue-item-count": {
|
||||
"type": "integer"
|
||||
},
|
||||
"songList": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"songId": {
|
||||
"type": "integer"
|
||||
},
|
||||
"URL": {
|
||||
"type": "string"
|
||||
},
|
||||
"downloadKey": {
|
||||
"type": "string"
|
||||
},
|
||||
"artworkURL": {
|
||||
"type": "string"
|
||||
},
|
||||
"artwork-urls": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"image-type": {
|
||||
"type": "string"
|
||||
},
|
||||
"default": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"url": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"url"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"image-type",
|
||||
"default"
|
||||
]
|
||||
},
|
||||
"md5": {
|
||||
"type": "string"
|
||||
},
|
||||
"chunks": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"chunkSize": {
|
||||
"type": "integer"
|
||||
},
|
||||
"hashes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"chunkSize",
|
||||
"hashes"
|
||||
]
|
||||
},
|
||||
"isStreamable": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"uncompressedSize": {
|
||||
"type": "string"
|
||||
},
|
||||
"sinfs": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"sinf": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"sinf"
|
||||
]
|
||||
}
|
||||
},
|
||||
"purchaseDate": {
|
||||
"type": "string"
|
||||
},
|
||||
"download-id": {
|
||||
"type": "string"
|
||||
},
|
||||
"is-in-queue": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"asset-info": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"file-size": {
|
||||
"type": "integer"
|
||||
},
|
||||
"flavor": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"file-size",
|
||||
"flavor"
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"MacUIRequiredDeviceCapabilities": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"arm64": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"gamekit": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"metal": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"arm64",
|
||||
"gamekit",
|
||||
"metal"
|
||||
]
|
||||
},
|
||||
"UIRequiredDeviceCapabilities": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"arm64": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"gamekit": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"metal": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"arm64",
|
||||
"gamekit",
|
||||
"metal"
|
||||
]
|
||||
},
|
||||
"artistId": {
|
||||
"type": "integer"
|
||||
},
|
||||
"artistName": {
|
||||
"type": "string"
|
||||
},
|
||||
"bundleDisplayName": {
|
||||
"type": "string"
|
||||
},
|
||||
"bundleShortVersionString": {
|
||||
"type": "string"
|
||||
},
|
||||
"bundleVersion": {
|
||||
"type": "string"
|
||||
},
|
||||
"copyright": {
|
||||
"type": "string"
|
||||
},
|
||||
"fileExtension": {
|
||||
"type": "string"
|
||||
},
|
||||
"gameCenterEnabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"gameCenterEverEnabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"genre": {
|
||||
"type": "string"
|
||||
},
|
||||
"genreId": {
|
||||
"type": "integer"
|
||||
},
|
||||
"itemId": {
|
||||
"type": "integer"
|
||||
},
|
||||
"itemName": {
|
||||
"type": "string"
|
||||
},
|
||||
"kind": {
|
||||
"type": "string"
|
||||
},
|
||||
"playlistName": {
|
||||
"type": "string"
|
||||
},
|
||||
"product-type": {
|
||||
"type": "string"
|
||||
},
|
||||
"rating": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"content": {
|
||||
"type": "string"
|
||||
},
|
||||
"label": {
|
||||
"type": "string"
|
||||
},
|
||||
"rank": {
|
||||
"type": "integer"
|
||||
},
|
||||
"system": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"content",
|
||||
"label",
|
||||
"rank",
|
||||
"system"
|
||||
]
|
||||
},
|
||||
"releaseDate": {
|
||||
"type": "string"
|
||||
},
|
||||
"requiresRosetta": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"runsOnAppleSilicon": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"runsOnIntel": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"s": {
|
||||
"type": "integer"
|
||||
},
|
||||
"software-platform": {
|
||||
"type": "string"
|
||||
},
|
||||
"softwareIcon57x57URL": {
|
||||
"type": "string"
|
||||
},
|
||||
"softwareIconNeedsShine": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"softwareSupportedDeviceIds": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"softwareVersionBundleId": {
|
||||
"type": "string"
|
||||
},
|
||||
"softwareVersionExternalIdentifier": {
|
||||
"type": "integer"
|
||||
},
|
||||
"softwareVersionExternalIdentifiers": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"subgenres": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"genre": {
|
||||
"type": "string"
|
||||
},
|
||||
"genreId": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"genre",
|
||||
"genreId"
|
||||
]
|
||||
}
|
||||
},
|
||||
"vendorId": {
|
||||
"type": "integer"
|
||||
},
|
||||
"drmVersionNumber": {
|
||||
"type": "integer"
|
||||
},
|
||||
"versionRestrictions": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"MacUIRequiredDeviceCapabilities",
|
||||
"UIRequiredDeviceCapabilities",
|
||||
"artistId",
|
||||
"artistName",
|
||||
"bundleDisplayName",
|
||||
"bundleShortVersionString",
|
||||
"bundleVersion",
|
||||
"copyright",
|
||||
"fileExtension",
|
||||
"gameCenterEnabled",
|
||||
"gameCenterEverEnabled",
|
||||
"genre",
|
||||
"genreId",
|
||||
"itemId",
|
||||
"itemName",
|
||||
"kind",
|
||||
"playlistName",
|
||||
"product-type",
|
||||
"rating",
|
||||
"releaseDate",
|
||||
"requiresRosetta",
|
||||
"runsOnAppleSilicon",
|
||||
"runsOnIntel",
|
||||
"s",
|
||||
"software-platform",
|
||||
"softwareIcon57x57URL",
|
||||
"softwareIconNeedsShine",
|
||||
"softwareSupportedDeviceIds",
|
||||
"softwareVersionBundleId",
|
||||
"softwareVersionExternalIdentifier",
|
||||
"softwareVersionExternalIdentifiers",
|
||||
"subgenres",
|
||||
"vendorId",
|
||||
"drmVersionNumber",
|
||||
"versionRestrictions"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"songId",
|
||||
"URL",
|
||||
"downloadKey",
|
||||
"artworkURL",
|
||||
"artwork-urls",
|
||||
"md5",
|
||||
"chunks",
|
||||
"isStreamable",
|
||||
"uncompressedSize",
|
||||
"sinfs",
|
||||
"purchaseDate",
|
||||
"download-id",
|
||||
"is-in-queue",
|
||||
"asset-info",
|
||||
"metadata"
|
||||
]
|
||||
}
|
||||
},
|
||||
"metrics": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"itemIds": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"currency": {
|
||||
"type": "string"
|
||||
},
|
||||
"exchangeRateToUSD": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"itemIds",
|
||||
"currency",
|
||||
"exchangeRateToUSD"
|
||||
]
|
||||
},
|
||||
"subscriptionStatus": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"terms": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"latestTerms": {
|
||||
"type": "integer"
|
||||
},
|
||||
"agreedToTerms": {
|
||||
"type": "integer"
|
||||
},
|
||||
"source": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"type",
|
||||
"latestTerms",
|
||||
"agreedToTerms",
|
||||
"source"
|
||||
]
|
||||
}
|
||||
},
|
||||
"account": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"isMinor": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"suspectUnderage": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"isMinor",
|
||||
"suspectUnderage"
|
||||
]
|
||||
},
|
||||
"family": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"hasFamily": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"hasFamily"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"terms",
|
||||
"account",
|
||||
"family"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"pings",
|
||||
"jingleDocType",
|
||||
"jingleAction",
|
||||
"status",
|
||||
"dsPersonId",
|
||||
"creditDisplay",
|
||||
"creditBalance",
|
||||
"freeSongBalance",
|
||||
"authorized",
|
||||
"download-queue-item-count",
|
||||
"songList",
|
||||
"metrics",
|
||||
"subscriptionStatus"
|
||||
]
|
||||
}
|
||||
13
src_mac/ipatool-py/reqs/schemas/schema_examples/itunes_lookup_resp.log
Executable file
13
src_mac/ipatool-py/reqs/schemas/schema_examples/itunes_lookup_resp.log
Executable file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"resultCount":1,
|
||||
"results": [
|
||||
{
|
||||
"screenshotUrls":["https://is1-ssl.mzstatic.com/image/thumb/Purple123/v4/c7/9d/5a/c79d5ac9-4543-e9d7-acb3-4753704f1488/pr_source.png/392x696bb.png", "https://is5-ssl.mzstatic.com/image/thumb/Purple123/v4/e4/38/3a/e4383af3-d9ed-3d0c-9c80-ca0d413c0f06/pr_source.png/392x696bb.png", "https://is5-ssl.mzstatic.com/image/thumb/Purple123/v4/08/b2/39/08b23995-3c76-3e74-5af4-3edb4914dc4c/pr_source.png/392x696bb.png"],
|
||||
"ipadScreenshotUrls":["https://is5-ssl.mzstatic.com/image/thumb/Purple113/v4/67/74/39/6774390f-7a12-3d9f-ded7-392b9af90663/pr_source.png/576x768bb.png", "https://is4-ssl.mzstatic.com/image/thumb/Purple123/v4/88/62/85/886285f0-b1c2-ad6b-3ab3-2a5ee70d7c9d/pr_source.png/576x768bb.png", "https://is4-ssl.mzstatic.com/image/thumb/Purple123/v4/29/39/68/29396836-1b94-1561-4bd1-cde929ae5baa/pr_source.png/576x768bb.png"], "appletvScreenshotUrls":[],
|
||||
"artworkUrl60":"https://is3-ssl.mzstatic.com/image/thumb/Purple123/v4/6b/ed/31/6bed31bd-42d1-5ae9-04fd-a04c865af27d/AppIcon-0-0-1x_U007emarketing-0-0-0-7-0-0-sRGB-0-0-0-GLES2_U002c0-512MB-85-220-0-0.png/60x60bb.jpg",
|
||||
"artworkUrl512":"https://is3-ssl.mzstatic.com/image/thumb/Purple123/v4/6b/ed/31/6bed31bd-42d1-5ae9-04fd-a04c865af27d/AppIcon-0-0-1x_U007emarketing-0-0-0-7-0-0-sRGB-0-0-0-GLES2_U002c0-512MB-85-220-0-0.png/512x512bb.jpg",
|
||||
"artworkUrl100":"https://is3-ssl.mzstatic.com/image/thumb/Purple123/v4/6b/ed/31/6bed31bd-42d1-5ae9-04fd-a04c865af27d/AppIcon-0-0-1x_U007emarketing-0-0-0-7-0-0-sRGB-0-0-0-GLES2_U002c0-512MB-85-220-0-0.png/100x100bb.jpg", "artistViewUrl":"https://apps.apple.com/us/developer/potatso-lab-ltd/id1267906737?uo=4",
|
||||
"supportedDevices":["iPhone5s-iPhone5s", "iPadAir-iPadAir", "iPadAirCellular-iPadAirCellular", "iPadMiniRetina-iPadMiniRetina", "iPadMiniRetinaCellular-iPadMiniRetinaCellular", "iPhone6-iPhone6", "iPhone6Plus-iPhone6Plus", "iPadAir2-iPadAir2", "iPadAir2Cellular-iPadAir2Cellular", "iPadMini3-iPadMini3", "iPadMini3Cellular-iPadMini3Cellular", "iPodTouchSixthGen-iPodTouchSixthGen", "iPhone6s-iPhone6s", "iPhone6sPlus-iPhone6sPlus", "iPadMini4-iPadMini4", "iPadMini4Cellular-iPadMini4Cellular", "iPadPro-iPadPro", "iPadProCellular-iPadProCellular", "iPadPro97-iPadPro97", "iPadPro97Cellular-iPadPro97Cellular", "iPhoneSE-iPhoneSE", "iPhone7-iPhone7", "iPhone7Plus-iPhone7Plus", "iPad611-iPad611", "iPad612-iPad612", "iPad71-iPad71", "iPad72-iPad72", "iPad73-iPad73", "iPad74-iPad74", "iPhone8-iPhone8", "iPhone8Plus-iPhone8Plus", "iPhoneX-iPhoneX", "iPad75-iPad75", "iPad76-iPad76", "iPhoneXS-iPhoneXS", "iPhoneXSMax-iPhoneXSMax", "iPhoneXR-iPhoneXR", "iPad812-iPad812", "iPad834-iPad834", "iPad856-iPad856", "iPad878-iPad878", "iPadMini5-iPadMini5", "iPadMini5Cellular-iPadMini5Cellular", "iPadAir3-iPadAir3", "iPadAir3Cellular-iPadAir3Cellular", "iPodTouchSeventhGen-iPodTouchSeventhGen", "iPhone11-iPhone11", "iPhone11Pro-iPhone11Pro", "iPadSeventhGen-iPadSeventhGen", "iPadSeventhGenCellular-iPadSeventhGenCellular", "iPhone11ProMax-iPhone11ProMax", "iPhoneSESecondGen-iPhoneSESecondGen", "iPadProSecondGen-iPadProSecondGen", "iPadProSecondGenCellular-iPadProSecondGenCellular", "iPadProFourthGen-iPadProFourthGen", "iPadProFourthGenCellular-iPadProFourthGenCellular", "iPhone12Mini-iPhone12Mini", "iPhone12-iPhone12", "iPhone12Pro-iPhone12Pro", "iPhone12ProMax-iPhone12ProMax", "iPadAir4-iPadAir4", "iPadAir4Cellular-iPadAir4Cellular", "iPadEighthGen-iPadEighthGen", "iPadEighthGenCellular-iPadEighthGenCellular", "iPadProThirdGen-iPadProThirdGen", "iPadProThirdGenCellular-iPadProThirdGenCellular", "iPadProFifthGen-iPadProFifthGen", "iPadProFifthGenCellular-iPadProFifthGenCellular", "iPhone13Pro-iPhone13Pro", "iPhone13ProMax-iPhone13ProMax", "iPhone13Mini-iPhone13Mini", "iPhone13-iPhone13", "iPadMiniSixthGen-iPadMiniSixthGen", "iPadMiniSixthGenCellular-iPadMiniSixthGenCellular", "iPadNinthGen-iPadNinthGen", "iPadNinthGenCellular-iPadNinthGenCellular", "iPhoneSEThirdGen-iPhoneSEThirdGen", "iPadAirFifthGen-iPadAirFifthGen", "iPadAirFifthGenCellular-iPadAirFifthGenCellular"], "features":["iosUniversal"], "advisories":[], "isGameCenterEnabled":false, "kind":"software", "minimumOsVersion":"13.0", "trackCensoredName":"Potatso Lite", "languageCodesISO2A":["EN", "ZH"], "fileSizeBytes":"18907136", "sellerUrl":"https://potatso.com/en", "formattedPrice":"Free", "contentAdvisoryRating":"4+", "averageUserRatingForCurrentVersion":4.595620000000000260342858382500708103179931640625, "userRatingCountForCurrentVersion":2923, "averageUserRating":4.595620000000000260342858382500708103179931640625, "trackViewUrl":"https://apps.apple.com/us/app/potatso-lite/id1239860606?uo=4", "trackContentRating":"4+", "trackId":1239860606, "trackName":"Potatso Lite", "bundleId":"com.touchingapp.potatsolite", "primaryGenreName":"Utilities", "releaseDate":"2017-06-01T02:34:35Z", "genreIds":["6002", "6007"], "isVppDeviceBasedLicensingEnabled":true, "sellerName":"Potatso Lab LTD", "currentVersionReleaseDate":"2019-12-16T23:27:27Z",
|
||||
"releaseNotes":"With this update, we're bringing you some exciting new features and changes. \n\n=====================\n===== What's New =====\n=====================\n\n• The app will support iOS 13+ from now on.\n• We're introducing the brand new logo with clarity and simplicity.\n• We've redeisnged the whole UI to improve your using experience.\n• Some other internal performance improvements and bug fixes.", "primaryGenreId":6002, "currency":"USD", "version":"2.5.0", "wrapperType":"software", "artistId":1267906737, "artistName":"Potatso Lab LTD", "genres":["Utilities", "Productivity"], "price":0.00,
|
||||
"description":"Potatso Lite is a powerful network tool which empowers your phone to have fully customized network environment. It's friendly for both beginners and power users. \n\nPotatso now supports Shadowsocks, ShadowsocksR, HTTP and Socks5 proxies. You can either setup one by yourself or buy from any proxy providers.\n\nEmbedded smart rouing feature for Chinese users is super helpful which can cost less data in proxy servers and speed up domestic network traffic.\n\n=== Features ===\n- Custom proxy supports Shadowsocks, ShadowsocksR, HTTP and Socks5 \n- Run in the background sustainably without interrupting you\n- Both cellular and Wi-Fi are supported\n- Custom DNS support\n- Smart Routing for Chinese users \n\n=== Privacy ===\nWe respect your privacy so NO confidential data will be uploaded or shared with third parties\n\n=== Feedback ===\nPlease contact on hi@potatso.com", "userRatingCount":2923}]
|
||||
}
|
||||
107
src_mac/ipatool-py/reqs/schemas/schema_examples/store_buyproduct_req.log
Executable file
107
src_mac/ipatool-py/reqs/schemas/schema_examples/store_buyproduct_req.log
Executable file
@@ -0,0 +1,107 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>appExtVrsId</key>
|
||||
<string>848463733</string>
|
||||
<key>guid</key>
|
||||
<string>22330C8C.C2E39C5C.06C40B91.D0990F95.9A890F9D.AB7F7EB4.56507025</string>
|
||||
<key>kbsync</key>
|
||||
<data>
|
||||
AAQAA5nBc3Q7ETi+TD1x8AM4wbw9sqWglXBaXwuIrlMR9OnAPY89zaoTvbe6PneuS1x1
|
||||
31NxVIqrAsIZLmxy5be8dQtq8je/rtYTRlxduU9NwW4DBcplBx6vs9qhS3Y8B45Zz4T5
|
||||
dkmDG4UnS7xnAPwew7jEX/uY38zZhtKu4IN+sl/Whvyh2SkZg/5vGCtjav17CGbP8ZWo
|
||||
Ci3FhEqAByOL0g6zhPdTHyqF84Apg9fh395tGpzzAWB8mYsRQXJcUHH1cuJjO/qMTkZ4
|
||||
ZxIJqfMaDJpS20nFq+/Bfg9FvC/83AOPnDfXZTsol3PFKqQ6sLgz6dKIho4Qd2UPABnj
|
||||
kBx4TFPeYBlm2T6GKfi8tr+rDhsMrbNczpnaUS+3cesIOvDsE3YCX4isOmMtg5yrJ5pi
|
||||
2GHuofHD2I7Dj6fOh79I7F5OZb71PUvbeABjxvS5b57LGNICSBc/GJ0CEja27kpYals+
|
||||
bgYG0rVm+vqlAHwRpka5jzeK8DLrvTr22vtBLv62LpTVpVVglr5nbk99BcXG5gA=
|
||||
</data>
|
||||
<key>machineName</key>
|
||||
<string>DESKTOP-697LVJS</string>
|
||||
<key>mtApp</key>
|
||||
<string>com.apple.iTunes</string>
|
||||
<key>mtClientId</key>
|
||||
<string>3z21abvCzFDuz5CYz9bdz19maFVKge</string>
|
||||
<key>mtEventTime</key>
|
||||
<string>1652006678827</string>
|
||||
<key>mtPageId</key>
|
||||
<string>ccfce0ef-4ac8-4d5a-8e5f-79876ac474a4</string>
|
||||
<key>mtPageType</key>
|
||||
<string>Search</string>
|
||||
<key>mtPrevPage</key>
|
||||
<string>Purchases</string>
|
||||
<key>mtRequestId</key>
|
||||
<string>3z21abvCzFDuz5CYz9bdz19maFVKgezL2X64FFVz1MGG</string>
|
||||
<key>mtTopic</key>
|
||||
<string>xp_its_main</string>
|
||||
<key>needDiv</key>
|
||||
<string>0</string>
|
||||
<key>pg</key>
|
||||
<string>default</string>
|
||||
<key>price</key>
|
||||
<string>0</string>
|
||||
<key>pricingParameters</key>
|
||||
<string>STDQ</string>
|
||||
<key>productType</key>
|
||||
<string>C</string>
|
||||
<key>salableAdamId</key>
|
||||
<string>444934666</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>ageCheck</key>
|
||||
<string>true</string>
|
||||
<key>appExtVrsId</key>
|
||||
<string>848463733</string>
|
||||
<key>guid</key>
|
||||
<string>22330C8C.C2E39C5C.06C40B91.D0990F95.9A890F9D.AB7F7EB4.56507025</string>
|
||||
<key>hasBeenAuthedForBuy</key>
|
||||
<string>true</string>
|
||||
<key>isInApp</key>
|
||||
<string>false</string>
|
||||
<key>kbsync</key>
|
||||
<data>
|
||||
AAQAA1c+HfGD4vNLZJYBMpBucSo1bxeaeTEZ3FGUKLq0skmzTxVik6IGoQMGaP6OWsJU
|
||||
lBoDb3hxaacD57bkiAgRXc/vr21/CipX55hKLoTE53yah3DwBR9tS1cG7oaHFLIh1Vmn
|
||||
RV7G9LJCQqwSAbr4ugEIVmLULkqaHDfTm8VNDXxYej1p8ghKggMcBT0se5cpDqpVn/bE
|
||||
qehnOl6QsupUNjjLzDm58bmERm/AjGJVBHQveG+4Y+Y4e1eUO6QQcntmypjmSLDqhI60
|
||||
31rCV3zwTTZrHmmXEwsZiGgYlSVHR3ne+O9BE+LIPiQxDwIMvjfV6SrzoOUOLlOKvBsk
|
||||
kI29+6H0QNyMUXojWPQf7bfr+9NBTMgJoDNJd5hEGHqiSKnp9V1ALU8S8QwcYzi3ZDPu
|
||||
A36lMtgMOFEnYibnGnP5S8i2t43ZSBglExE9LGTGO0/IEWX9gEhKjvMDuIwMt9zdtpye
|
||||
CXO8siqHY4MtmLlfwZZc/480ZSHfRF8ZQHBa0J0/pgByNQiNe9KMihz+QN7cQI4=
|
||||
</data>
|
||||
<key>machineName</key>
|
||||
<string>DESKTOP-697LVJS</string>
|
||||
<key>mtApp</key>
|
||||
<string>com.apple.iTunes</string>
|
||||
<key>mtClientId</key>
|
||||
<string>3z21abvCzFDuz5CYz9bdz19maFVKge</string>
|
||||
<key>mtEventTime</key>
|
||||
<string>1652006678827</string>
|
||||
<key>mtPageId</key>
|
||||
<string>ccfce0ef-4ac8-4d5a-8e5f-79876ac474a4</string>
|
||||
<key>mtPageType</key>
|
||||
<string>Search</string>
|
||||
<key>mtPrevPage</key>
|
||||
<string>Purchases</string>
|
||||
<key>mtRequestId</key>
|
||||
<string>3z21abvCzFDuz5CYz9bdz19maFVKgezL2X64FFVz1MGG</string>
|
||||
<key>mtTopic</key>
|
||||
<string>xp_its_main</string>
|
||||
<key>needDiv</key>
|
||||
<string>0</string>
|
||||
<key>pg</key>
|
||||
<string>default</string>
|
||||
<key>price</key>
|
||||
<string>0</string>
|
||||
<key>pricingParameters</key>
|
||||
<string>STDQ</string>
|
||||
<key>productType</key>
|
||||
<string>C</string>
|
||||
<key>salableAdamId</key>
|
||||
<string>444934666</string>
|
||||
</dict>
|
||||
</plist>
|
||||
561
src_mac/ipatool-py/reqs/schemas/schema_examples/store_buyproduct_resp.log
Executable file
561
src_mac/ipatool-py/reqs/schemas/schema_examples/store_buyproduct_resp.log
Executable file
@@ -0,0 +1,561 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>pings</key>
|
||||
<array><string>https://xp.apple.com/report/2/xp_its_main?app=com.apple.iTunes&code=MZCommerce.ASN.ExpiredPasswordToken&buttons=%E8%8E%B7%E5%8F%96%3A%E5%8F%96%E6%B6%88&baseVersion=1&dsId=16916646015&eventVersion=1&storeFrontHeader=143465-19%2C32&eventTime=1652006682067&eventType=dialog&message=%E9%9C%80%E8%A6%81%E7%99%BB%E5%BD%95</string>
|
||||
</array>
|
||||
<key>metrics</key>
|
||||
<dict>
|
||||
<key>dialogId</key><string>MZCommerce.ASN.ExpiredPasswordToken</string>
|
||||
<key>message</key><string>éè¦ç»å½</string>
|
||||
<key>messageCode</key><string>2072</string>
|
||||
<key>options</key>
|
||||
<array>
|
||||
<string>Get</string>
|
||||
<string>Cancel</string>
|
||||
</array>
|
||||
<key>actionUrl</key><string>p36-buy.itunes.apple.com/WebObjects/MZBuy.woa/wa/buyProduct</string>
|
||||
<key>asnState</key><integer>2</integer>
|
||||
<key>mtApp</key><string>com.apple.iTunes</string>
|
||||
<key>mtClientId</key><string>3z21abvCzFDuz5CYz9bdz19maFVKge</string>
|
||||
<key>mtEventTime</key><string>2022-05-08 10:44:38 Etc/GMT</string>
|
||||
<key>mtPageId</key><string>ccfce0ef-4ac8-4d5a-8e5f-79876ac474a4</string>
|
||||
<key>mtPageType</key><string>Search</string>
|
||||
<key>mtPrevPage</key><string>Purchases</string>
|
||||
<key>mtRequestId</key><string>3z21abvCzFDuz5CYz9bdz19maFVKgezL2X64FFVz1MGG</string>
|
||||
<key>mtTopic</key><string>xp_its_main</string>
|
||||
<key>eventType</key><string>dialog</string>
|
||||
</dict>
|
||||
<key>failureType</key><string>2072</string>
|
||||
<key>customerMessage</key><string>éè¦ç»å½</string>
|
||||
<key>m-allowed</key><true/>
|
||||
<key>dialog</key>
|
||||
<dict><key>kind</key><string>authorization</string>
|
||||
<key>m-allowed</key><true/>
|
||||
<key>use-keychain</key><true/>
|
||||
<key>isFree</key><true/>
|
||||
<key>message</key><string>éè¦ç»å½</string>
|
||||
<key>explanation</key><string>å¦ææ¨æ Apple ID åå¯ç ï¼è¯·å¨æ¤å¤è¾å
¥ãä¾å¦ï¼å¦ææ¨ä½¿ç¨è¿ iTunes Store æ iCloudï¼é£ä¹æ¨å·²æ Apple IDã</string>
|
||||
<key>defaultButton</key><string>ok</string>
|
||||
<key>okButtonString</key><string>è·å</string>
|
||||
<key>okButtonAction</key><dict><key>kind</key><string>Buy</string>
|
||||
<key>buyParams</key><string>mtEventTime=1652006678827&salableAdamId=444934666&mtRequestId=3z21abvCzFDuz5CYz9bdz19maFVKgezL2X64FFVz1MGG&appExtVrsId=848463733&mtTopic=xp_its_main&guid=22330C8C.C2E39C5C.06C40B91.D0990F95.9A890F9D.AB7F7EB4.56507025&hasBeenAuthedForBuy=true&isInApp=false&price=0&mtClientId=3z21abvCzFDuz5CYz9bdz19maFVKge&productType=C&mtPageType=Search&mtPageId=ccfce0ef-4ac8-4d5a-8e5f-79876ac474a4&machineName=DESKTOP-697LVJS&ageCheck=true&pg=default&mtApp=com.apple.iTunes&needDiv=0&mtPrevPage=Purchases&pricingParameters=STDQ</string>
|
||||
<key>itemName</key><string>QQ</string>
|
||||
</dict>
|
||||
<key>cancelButtonString</key><string>åæ¶</string>
|
||||
<key>initialCheckboxValue</key><true/></dict>
|
||||
<key>cancel-purchase-batch</key><true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>pings</key>
|
||||
<array></array>
|
||||
<key>jingleDocType</key><string>purchaseSuccess</string>
|
||||
<key>jingleAction</key><string>purchaseProduct</string>
|
||||
<key>status</key><integer>0</integer>
|
||||
|
||||
<key>dsPersonId</key><string>10964418715</string>
|
||||
<key>creditDisplay</key><string></string>
|
||||
<key>creditBalance</key><string>1311811</string>
|
||||
<key>freeSongBalance</key><string>1311811</string>
|
||||
|
||||
<key>authorized</key><false/><key>download-queue-item-count</key><integer>0</integer>
|
||||
<key>songList</key>
|
||||
<array>
|
||||
</array>
|
||||
<key>metrics</key>
|
||||
<dict>
|
||||
|
||||
<key>itemIds</key>
|
||||
<array>
|
||||
<integer>580311103</integer>
|
||||
</array>
|
||||
<key>price</key><real>0.00</real>
|
||||
<key>priceType</key><string>STDQ</string>
|
||||
<key>productTypes</key>
|
||||
<array>
|
||||
<string>C</string>
|
||||
</array>
|
||||
<key>currency</key><string>JPY</string>
|
||||
<key>exchangeRateToUSD</key><real>0.0076722418</real>
|
||||
<key>commerceEvent_purchase_priceType</key><string>STDQ</string>
|
||||
<key>commerceEvent_storeFrontId</key><string>143462</string>
|
||||
<key>commerceEvent_result_resultType</key><integer>0</integer>
|
||||
<key>commerceEvent_flowType</key><integer>4</integer>
|
||||
<key>commerceEvent_flowStep</key><integer>6</integer>
|
||||
</dict>
|
||||
|
||||
<key>duAnonymousPings</key>
|
||||
<array>
|
||||
<string>https://xp.apple.com/report/2/xp_app_buy?clientId=0&sf=143462&adamId=580311103</string>
|
||||
</array>
|
||||
<key>subscriptionStatus</key>
|
||||
<dict>
|
||||
<key>terms</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>type</key><string>Store</string>
|
||||
<key>latestTerms</key><integer>28</integer>
|
||||
<key>agreedToTerms</key><integer>31</integer>
|
||||
<key>source</key><string>account</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>account</key>
|
||||
<dict>
|
||||
<key>isMinor</key><false/>
|
||||
<key>suspectUnderage</key><false/>
|
||||
</dict>
|
||||
<key>family</key>
|
||||
<dict>
|
||||
<key>hasFamily</key><false/>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>pings</key>
|
||||
<array></array>
|
||||
<key>jingleDocType</key><string>purchaseSuccess</string>
|
||||
<key>jingleAction</key><string>purchaseProduct</string>
|
||||
<key>status</key><integer>0</integer>
|
||||
|
||||
<key>dsPersonId</key><string>16916646015</string>
|
||||
<key>creditDisplay</key><string></string>
|
||||
<key>creditBalance</key><string>1311811</string>
|
||||
<key>freeSongBalance</key><string>1311811</string>
|
||||
<key>creditDisplayInternal</key><string>Â¥0.00+0+0+0+0+0</string>
|
||||
|
||||
<key>authorized</key><true/>
|
||||
|
||||
<key>download-queue-item-count</key><integer>1</integer>
|
||||
<key>songList</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>songId</key><integer>444934666</integer>
|
||||
<key>URL</key><string>https://iosapps.itunes.apple.com/itunes-assets/Purple112/v4/8c/5d/34/8c5d343a-2132-8690-c6b1-866ec2f6b2f6/extDirwkazoqouvdywwgjk.lc.14519290919268642.5LAVFF7SAES2W.signed.dpkg.ipa?accessKey=1652201151_1282442801256894451_c%2FtMyevC%2FbCtPTcx3kpjPzNcDfSmgpz1CnzuNFgB%2F1n13VEU1IYDwlq1Xie8WXNHq4U4t341RRlyT3J1OI1Doy1%2FKOG8Pk4u38Kn30NHbCnmgCRC2r9lGlND9ZjU7AxGCQeVb5iHc74Vf5i7Exbg3hq5UfUddWq%2BBe7s3VEyvOX9Rikq0Hzj4OkYUkklrks95yuvrEhXjMFYO8YpQAr0tCjKoyU2rvjS%2BwnPYk5U0Hy6DnusEJ3JmJpJKC6EiLvb</string>
|
||||
<key>downloadKey</key><string></string><key>artworkURL</key><string>https://is5-ssl.mzstatic.com/image/thumb/Purple112/v4/b9/ac/4e/b9ac4ef3-0152-fa92-872f-fe773d799117/AppIcon-1-0-0-1x_U007emarketing-0-0-0-7-0-0-sRGB-0-0-0-GLES2_U002c0-512MB-85-220-0-0.png/2000x2000bb.jpg</string><key>artwork-urls</key>
|
||||
<dict>
|
||||
<key>image-type</key><string>download-queue-item</string>
|
||||
<key>default</key>
|
||||
<dict>
|
||||
<key>url</key>
|
||||
<string>https://is4-ssl.mzstatic.com/image/thumb/Purple112/v4/b9/ac/4e/b9ac4ef3-0152-fa92-872f-fe773d799117/AppIcon-1-0-0-1x_U007emarketing-0-0-0-7-0-0-sRGB-0-0-0-GLES2_U002c0-512MB-85-220-0-0.png/57x57bb.jpg</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>md5</key><string>cb3a13a60ac4c9f507b0fefa351e0351</string><key>chunks</key>
|
||||
<dict>
|
||||
<key>chunkSize</key><integer>10485760</integer>
|
||||
<key>hashes</key>
|
||||
<array>
|
||||
<string>a9c3b17b7fd5ce1380580c6f063c469b</string>
|
||||
<string>8dfa7efed3cccca58987ec5fb5aad752</string>
|
||||
<string>c636e4bfcdc17f5ce23a8ef104a44fa3</string>
|
||||
<string>90911e7b4d63bf8d4fc1c0bb2756211b</string>
|
||||
<string>0c7ae0bfa13df1a3cb25d18eccf79083</string>
|
||||
<string>4edbba71a6baabeba209cbe495144017</string>
|
||||
<string>2b915fa08b532ef007787f3cf9ed68e6</string>
|
||||
<string>e8ae486763cd40c730a6f2008bb212df</string>
|
||||
<string>a91b20af08349a115d318a3c1a9ac69c</string>
|
||||
<string>001a0a9e6f0f779365fd1a9e08993afa</string>
|
||||
<string>d9c965a523b445f662aac8eb49fa271e</string>
|
||||
<string>22f61327c32a4569a4d81f29ae93f238</string>
|
||||
<string>3caf910c1da7640a89a51c2ae33e8a3b</string>
|
||||
<string>70fcd6e5517144b1298848bd964f4dcc</string>
|
||||
<string>9fb4924aed5006d2c7037be6532d1652</string>
|
||||
<string>fb341fcaaf6027182f885628e15542f6</string>
|
||||
<string>a0999c33fa684fa21cf2d8c8a4d45e27</string>
|
||||
<string>28025c9522f1dc05360e36a9e6da508b</string>
|
||||
<string>ea980ee5fae29238778cdd16a1f0a2fa</string>
|
||||
<string>699c2c8bcd5b4b9353bba25a58bb45f8</string>
|
||||
<string>10423be39910d01b9e763cc1514fef05</string>
|
||||
<string>3da83694d61846e91a0a21981e88652a</string>
|
||||
<string>937391e158c46e385bf1ebd2f17501aa</string>
|
||||
<string>18a12b305b3a0086d76d4f9c72764a00</string>
|
||||
<string>c19f2b5c1eeb909db77b5d715e023511</string>
|
||||
<string>80552d4ed44472cf0f307bc6e6e4180c</string>
|
||||
<string>9af9bebfb73a15084186032efd64f95b</string>
|
||||
<string>bdc8305c863637d6031c079f3438b2b2</string>
|
||||
<string>406fff31a2d714ffa1eb7c417232c478</string>
|
||||
<string>f29550bd0e718ca8588d13654a14e669</string>
|
||||
<string>ea916c4a8e8f772610bd4de2549ec891</string>
|
||||
<string>9ff8f440fb8260ffe7e39e17215e8e9f</string>
|
||||
<string>b596fe96037d6e0e52401676b87fc6c0</string>
|
||||
<string>1be6f6b3141c80d2b3ad952db9e92ebb</string>
|
||||
<string>4a9061c50a209184f7d4a54f80ce61ef</string>
|
||||
<string>e6505a456ca2273700dcad1dead1f625</string>
|
||||
<string>9ac28b8e7dd43be5fd309f16403afef8</string>
|
||||
<string>5088792cdb4928532714a7023df1275d</string>
|
||||
<string>c0b0d04fd38919c8688c5e793b33d5e4</string>
|
||||
<string>a87331d5e314e6708f6cc67075e36c56</string>
|
||||
<string>63ea3257f99d04b44730924cb4a0d553</string>
|
||||
<string>b3d953d072a3b0e8e264c16d96cebeaf</string>
|
||||
<string>5eff58a53e7f7e87f57fcb038a4ad0a4</string>
|
||||
<string>e37467e9f2c7d336c3742b63ee70b4ab</string>
|
||||
<string>abfcdd0ba248ee9c5bc1b4bf8ab03c15</string>
|
||||
<string>7c4d4ccfcaaef4708f3d1b0fce994294</string>
|
||||
<string>927273c03da6f0fcdc674b40224c0a6d</string>
|
||||
<string>648761edcf4c3d69e147b3671abee7a8</string>
|
||||
<string>146e363283ed83bfd72a8c4d6b8fa7ac</string>
|
||||
<string>69c8e188357d463d00bd7f8134786b1c</string>
|
||||
<string>babbb9b2f0c3d31a4d9e0e0d77852f5e</string>
|
||||
<string>ae46925c45e689783c38f065a9d1e7ea</string>
|
||||
<string>c7f4967cb830f008417c02009ae2196a</string>
|
||||
<string>9b8f17524eb05a512c26bb9e2b89220b</string>
|
||||
<string>11cdc44dd07fe5d9fa3eaba0a179704c</string>
|
||||
<string>d0f17891f1c141e39cfcacfb58c1bb3c</string>
|
||||
<string>3273d004f5971ebee5625868d4978f69</string>
|
||||
<string>0aa895b7d15ad0760156b3062fb6deeb</string>
|
||||
<string>7b27b6e73b0731b307399aa4da837df9</string>
|
||||
</array>
|
||||
</dict>
|
||||
<key>isStreamable</key><true/>
|
||||
<key>uncompressedSize</key><integer>795979776</integer>
|
||||
<key>sinfs</key><array> <dict> <key>id</key> <integer>0</integer> <key>sinf</key> <data>AAAEIHNpbmYAAAAMZnJtYWdhbWUAAAAUc2NobQAAAABpdHVuAAAAAAAAA3BzY2hpAAAADHVzZXLwT4h/AAAADGNyZHTenU/fAAAADGFzZHQAAAAAAAAADGtleSAAAAACAAAAGGl2aXaD6ySnLt5l3Pdp75fJ0mjxAAAAWHJpZ2h2ZUlEAAEOnHBsYXQAAAABYXZlcgEBAQB0cmFu3p1P33NpbmcAAAAAc29uZxqFKgp0b29sUDYwNG1lZGkAAACAbW9kZQAAIABoaTMyAAAAAwAAAQhuYW1l5q63IOWmueS7jQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcBwcml2eDOeoQvqIT8I9Y9+tU7xixDGAGJI8TvGWPhI2r7kjf9vKy/JunWkBOLN7Ft3eFaFidNSVs3VTlvYSulf3VT0QAc0+3/pFznoHsNC5pMpQ6y0HdBW+8nG+JbiLjeTU3Nj2akunI45wVAiE2IWr1mERJwFG5CavbGOvHM9JBxkHaczFWUUm60zUHuMiBGZiZVDbVI4Oilxdn0vRb3c2P0zDrhOyxez9B7ppEMzJpFkDa2ieFSE0peNxsx8xi+BLWqQ88IZiCpCrLma3P5Wj40hb0nXclQY2t9Zvnw54A2DC/NHEUEDq1T/cZvAi16AdDRB0/GWOTLf7RNf1R8glahArjoD+fddyk9MuVwEN63YqCH/bNh1L7+hpk0Vh2tDGuEy/KDA30kZgF9Z2FED9LAQpCmx1BHUc60NDq++mCImFNiO528OnwirxjZoMWCZWsyCBL+RDTLcNLZOVDwKJcCqP+xLhbbSD8yoQhug/5reFOIUieODiQHGnfVmUmVe9sDuoJmEME3MHMwUHIpGkVfXVE6SPxA2eoN6EReeKwVwbDeLsp/r/dA8jX7BWW9WSjjfAAAAAAAAAAAAAACIc2lnbggl0CkIwRg6tBbdAWQKT2ZlMkYC2bZvWrsyeLzUy+BSYJAs7v2jr1DkRH/xdJbaDjvmkCvS75EUlCXU0oJYT8BydxZzTpJNMALVfwuJNELOkm8sqlCN1/zP1KM3XOeEMu/k6MmtV4nG3zOtLRcKHg5YRz17WcccdTSz251J2Ugn</data> </dict></array><key>purchaseDate</key><string>2022-05-08T10:45:51Z</string>
|
||||
<key>download-id</key><string>501382282407089488</string>
|
||||
<key>is-in-queue</key><true/>
|
||||
|
||||
<key>asset-info</key>
|
||||
<dict>
|
||||
<key>file-size</key><integer>611092999</integer>
|
||||
<key>flavor</key><string>10:purple</string>
|
||||
</dict>
|
||||
<key>metadata</key><dict>
|
||||
|
||||
<key>MacUIRequiredDeviceCapabilities</key>
|
||||
<dict>
|
||||
<key>arm64</key><true/>
|
||||
</dict>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<dict>
|
||||
<key>arm64</key><true/>
|
||||
</dict>
|
||||
<key>WKRunsIndependentlyOfCompanionApp</key><false/>
|
||||
<key>WKWatchOnly</key><false/>
|
||||
<key>appleWatchEnabled</key><true/>
|
||||
<key>artistId</key><integer>292374531</integer>
|
||||
<key>artistName</key><string>Tencent Technology (Shenzhen) Company Limited</string>
|
||||
<key>bundleDisplayName</key><string>QQ</string>
|
||||
<key>bundleShortVersionString</key><string>8.8.88</string>
|
||||
<key>bundleVersion</key><string>8.8.88.662</string>
|
||||
<key>copyright</key><string>Copyright © 1998- 2022 Tencent. All Rights Reserved</string>
|
||||
<key>fileExtension</key><string>.app</string>
|
||||
<key>gameCenterEnabled</key><false/>
|
||||
<key>gameCenterEverEnabled</key><false/>
|
||||
<key>genre</key><string>社交</string>
|
||||
<key>genreId</key><integer>6005</integer>
|
||||
<key>itemId</key><integer>444934666</integer>
|
||||
<key>itemName</key><string>QQ</string>
|
||||
<key>kind</key><string>software</string>
|
||||
<key>nameTranscriptions</key>
|
||||
<dict>
|
||||
<key>zh-Hans-CN</key>
|
||||
<array>
|
||||
<string>QQ</string>
|
||||
</array>
|
||||
</dict>
|
||||
<key>playlistName</key><string>Tencent Technology (Shenzhen) Company Limited</string>
|
||||
<key>product-type</key><string>ios-app</string>
|
||||
<key>rating</key>
|
||||
<dict>
|
||||
<key>content</key><string>å¶å°/轻微çè²æ
å
容æè£¸é² , Advisory.NO.GAMBLING_CONTESTS , å¶å°/轻微çæäººææ§æç¤ºé¢æ , Advisory.NO.UNRESTRICTED_WEB_ACCESS and Advisory.NO.TRUE_GAMBLING</string>
|
||||
<key>label</key><string>12+</string>
|
||||
<key>rank</key><integer>300</integer>
|
||||
<key>system</key><string>itunes-games</string>
|
||||
</dict>
|
||||
<key>releaseDate</key><string>2011-06-23T03:33:55Z</string>
|
||||
<key>requiresRosetta</key><false/>
|
||||
<key>runsOnAppleSilicon</key><true/>
|
||||
<key>runsOnIntel</key><false/>
|
||||
<key>s</key><integer>143465</integer>
|
||||
<key>software-platform</key><string>ios</string>
|
||||
<key>softwareIcon57x57URL</key><string>https://is4-ssl.mzstatic.com/image/thumb/Purple112/v4/b9/ac/4e/b9ac4ef3-0152-fa92-872f-fe773d799117/AppIcon-1-0-0-1x_U007emarketing-0-0-0-7-0-0-sRGB-0-0-0-GLES2_U002c0-512MB-85-220-0-0.png/114x114bb.jpg</string>
|
||||
<key>softwareIconNeedsShine</key><false/>
|
||||
<key>softwareSupportedDeviceIds</key>
|
||||
<array>
|
||||
<integer>2</integer>
|
||||
<integer>9</integer>
|
||||
<integer>4</integer>
|
||||
</array>
|
||||
<key>softwareVersionBundleId</key><string>com.tencent.mqq</string>
|
||||
<key>softwareVersionExternalIdentifier</key><integer>848463733</integer>
|
||||
<key>softwareVersionExternalIdentifiers</key>
|
||||
<array>
|
||||
<integer>3843900</integer>
|
||||
<integer>3876776</integer>
|
||||
<integer>3941034</integer>
|
||||
<integer>3973775</integer>
|
||||
<integer>4070873</integer>
|
||||
<integer>4135846</integer>
|
||||
<integer>4321059</integer>
|
||||
<integer>4492645</integer>
|
||||
<integer>4917185</integer>
|
||||
<integer>5632593</integer>
|
||||
<integer>6232232</integer>
|
||||
<integer>6860432</integer>
|
||||
<integer>7792605</integer>
|
||||
<integer>9642362</integer>
|
||||
<integer>11556077</integer>
|
||||
<integer>11818464</integer>
|
||||
<integer>12638046</integer>
|
||||
<integer>13422327</integer>
|
||||
<integer>14959445</integer>
|
||||
<integer>15410008</integer>
|
||||
<integer>15765932</integer>
|
||||
<integer>15854719</integer>
|
||||
<integer>16122679</integer>
|
||||
<integer>31562763</integer>
|
||||
<integer>275882650</integer>
|
||||
<integer>385122645</integer>
|
||||
<integer>580102645</integer>
|
||||
<integer>595393136</integer>
|
||||
<integer>608133076</integer>
|
||||
<integer>629072654</integer>
|
||||
<integer>687502658</integer>
|
||||
<integer>747082669</integer>
|
||||
<integer>811253584</integer>
|
||||
<integer>811445779</integer>
|
||||
<integer>811179715</integer>
|
||||
<integer>811445780</integer>
|
||||
<integer>811590055</integer>
|
||||
<integer>811669050</integer>
|
||||
<integer>812133257</integer>
|
||||
<integer>812375519</integer>
|
||||
<integer>812625692</integer>
|
||||
<integer>812972631</integer>
|
||||
<integer>813031156</integer>
|
||||
<integer>813192464</integer>
|
||||
<integer>813298393</integer>
|
||||
<integer>813463229</integer>
|
||||
<integer>813961231</integer>
|
||||
<integer>813962159</integer>
|
||||
<integer>814174262</integer>
|
||||
<integer>814318376</integer>
|
||||
<integer>814527796</integer>
|
||||
<integer>814531991</integer>
|
||||
<integer>814639613</integer>
|
||||
<integer>814754396</integer>
|
||||
<integer>814882132</integer>
|
||||
<integer>815144899</integer>
|
||||
<integer>815147083</integer>
|
||||
<integer>815188393</integer>
|
||||
<integer>815573881</integer>
|
||||
<integer>815574602</integer>
|
||||
<integer>815607136</integer>
|
||||
<integer>815810968</integer>
|
||||
<integer>815897122</integer>
|
||||
<integer>815938087</integer>
|
||||
<integer>815938591</integer>
|
||||
<integer>816130933</integer>
|
||||
<integer>816210673</integer>
|
||||
<integer>816305041</integer>
|
||||
<integer>816356364</integer>
|
||||
<integer>816843896</integer>
|
||||
<integer>816912335</integer>
|
||||
<integer>817028549</integer>
|
||||
<integer>817235792</integer>
|
||||
<integer>817473714</integer>
|
||||
<integer>817549698</integer>
|
||||
<integer>817788181</integer>
|
||||
<integer>817933532</integer>
|
||||
<integer>818110324</integer>
|
||||
<integer>818431910</integer>
|
||||
<integer>818825180</integer>
|
||||
<integer>818979113</integer>
|
||||
<integer>819096686</integer>
|
||||
<integer>819416223</integer>
|
||||
<integer>819489902</integer>
|
||||
<integer>819842838</integer>
|
||||
<integer>819893353</integer>
|
||||
<integer>820113905</integer>
|
||||
<integer>820199943</integer>
|
||||
<integer>820442929</integer>
|
||||
<integer>820548304</integer>
|
||||
<integer>820595060</integer>
|
||||
<integer>821268583</integer>
|
||||
<integer>821341311</integer>
|
||||
<integer>821500924</integer>
|
||||
<integer>821954014</integer>
|
||||
<integer>822037007</integer>
|
||||
<integer>822096329</integer>
|
||||
<integer>822279520</integer>
|
||||
<integer>822523036</integer>
|
||||
<integer>822895308</integer>
|
||||
<integer>822957820</integer>
|
||||
<integer>823194852</integer>
|
||||
<integer>823309872</integer>
|
||||
<integer>823713346</integer>
|
||||
<integer>824097583</integer>
|
||||
<integer>824171129</integer>
|
||||
<integer>824301257</integer>
|
||||
<integer>824389600</integer>
|
||||
<integer>825024981</integer>
|
||||
<integer>825145808</integer>
|
||||
<integer>825307653</integer>
|
||||
<integer>825347730</integer>
|
||||
<integer>825611268</integer>
|
||||
<integer>825729315</integer>
|
||||
<integer>825895542</integer>
|
||||
<integer>825933124</integer>
|
||||
<integer>826313718</integer>
|
||||
<integer>826632543</integer>
|
||||
<integer>826837026</integer>
|
||||
<integer>827460275</integer>
|
||||
<integer>828106847</integer>
|
||||
<integer>828385681</integer>
|
||||
<integer>828600919</integer>
|
||||
<integer>828666943</integer>
|
||||
<integer>828716670</integer>
|
||||
<integer>828897691</integer>
|
||||
<integer>829301009</integer>
|
||||
<integer>829496800</integer>
|
||||
<integer>829679760</integer>
|
||||
<integer>829821912</integer>
|
||||
<integer>830133231</integer>
|
||||
<integer>830530856</integer>
|
||||
<integer>830742895</integer>
|
||||
<integer>831337375</integer>
|
||||
<integer>831405629</integer>
|
||||
<integer>831472755</integer>
|
||||
<integer>831824011</integer>
|
||||
<integer>832139548</integer>
|
||||
<integer>832542612</integer>
|
||||
<integer>832827329</integer>
|
||||
<integer>833393416</integer>
|
||||
<integer>833855517</integer>
|
||||
<integer>834104017</integer>
|
||||
<integer>834138755</integer>
|
||||
<integer>834768091</integer>
|
||||
<integer>834880993</integer>
|
||||
<integer>834939578</integer>
|
||||
<integer>835135459</integer>
|
||||
<integer>835524672</integer>
|
||||
<integer>835716180</integer>
|
||||
<integer>835976856</integer>
|
||||
<integer>836375483</integer>
|
||||
<integer>836825545</integer>
|
||||
<integer>836945925</integer>
|
||||
<integer>837334930</integer>
|
||||
<integer>837735298</integer>
|
||||
<integer>837835768</integer>
|
||||
<integer>837881604</integer>
|
||||
<integer>838238560</integer>
|
||||
<integer>839235987</integer>
|
||||
<integer>839700113</integer>
|
||||
<integer>840003771</integer>
|
||||
<integer>840041841</integer>
|
||||
<integer>840921423</integer>
|
||||
<integer>841227891</integer>
|
||||
<integer>841968948</integer>
|
||||
<integer>842099251</integer>
|
||||
<integer>842166600</integer>
|
||||
<integer>842303496</integer>
|
||||
<integer>842463280</integer>
|
||||
<integer>842670770</integer>
|
||||
<integer>842892434</integer>
|
||||
<integer>843105491</integer>
|
||||
<integer>843416604</integer>
|
||||
<integer>843638409</integer>
|
||||
<integer>843881653</integer>
|
||||
<integer>844115468</integer>
|
||||
<integer>844170367</integer>
|
||||
<integer>844356613</integer>
|
||||
<integer>844638728</integer>
|
||||
<integer>844786323</integer>
|
||||
<integer>844986204</integer>
|
||||
<integer>845375859</integer>
|
||||
<integer>846332674</integer>
|
||||
<integer>846748317</integer>
|
||||
<integer>847332305</integer>
|
||||
<integer>847747163</integer>
|
||||
<integer>848017318</integer>
|
||||
<integer>848463733</integer>
|
||||
</array>
|
||||
<key>vendorId</key><integer>69276</integer>
|
||||
|
||||
<key>drmVersionNumber</key><integer>0</integer>
|
||||
<key>versionRestrictions</key><integer>16843008</integer>
|
||||
<key>storeCohort</key><string>10|date=1652005800000&sf=143465&pgtp=Search&pgid=ccfce0ef-4ac8-4d5a-8e5f-79876ac474a4&prpg=Purchases</string>
|
||||
<key>hasOrEverHasHadIAP</key><true/>
|
||||
</dict>
|
||||
|
||||
</dict>
|
||||
</array>
|
||||
|
||||
<key>download-queue-info</key>
|
||||
<dict>
|
||||
<key>download-queue-item-count</key><integer>0</integer>
|
||||
<key>dsid</key><integer>16916646015</integer>
|
||||
<key>is-auto-download-machine</key><false/>
|
||||
|
||||
</dict>
|
||||
<key>metrics</key>
|
||||
<dict>
|
||||
|
||||
<key>itemIds</key>
|
||||
<array>
|
||||
<integer>444934666</integer>
|
||||
</array>
|
||||
<key>price</key><real>0.00</real>
|
||||
<key>priceType</key><string>STDQ</string>
|
||||
<key>productTypes</key>
|
||||
<array>
|
||||
<string>C</string>
|
||||
</array>
|
||||
<key>mtApp</key><string>com.apple.iTunes</string>
|
||||
<key>mtClientId</key><string>3z21abvCzFDuz5CYz9bdz19maFVKge</string>
|
||||
<key>mtEventTime</key><string>2022-05-08 10:44:38 Etc/GMT</string>
|
||||
<key>mtPageId</key><string>ccfce0ef-4ac8-4d5a-8e5f-79876ac474a4</string>
|
||||
<key>mtPageType</key><string>Search</string>
|
||||
<key>mtPrevPage</key><string>Purchases</string>
|
||||
<key>mtRequestId</key><string>3z21abvCzFDuz5CYz9bdz19maFVKgezL2X64FFVz1MGG</string>
|
||||
<key>mtTopic</key><string>xp_its_main</string>
|
||||
<key>currency</key><string>CNY</string>
|
||||
<key>exchangeRateToUSD</key><real>0.1490268546</real>
|
||||
<key>commerceEvent_purchase_priceType</key><string>STDQ</string>
|
||||
<key>commerceEvent_storeFrontId</key><string>143465</string>
|
||||
<key>commerceEvent_result_resultType</key><integer>0</integer>
|
||||
<key>commerceEvent_flowType</key><integer>4</integer>
|
||||
<key>commerceEvent_flowStep</key><integer>6</integer>
|
||||
</dict>
|
||||
|
||||
<key>duAnonymousPings</key>
|
||||
<array>
|
||||
<string>https://xp.apple.com/report/2/xp_app_buy?clientId=0&sf=143465&adamId=444934666</string>
|
||||
</array>
|
||||
<key>subscriptionStatus</key>
|
||||
<dict>
|
||||
<key>music</key>
|
||||
<dict>
|
||||
<key>status</key><string>Disabled</string>
|
||||
<key>reason</key><string></string>
|
||||
<key>isAdmin</key><false/>
|
||||
<key>isNotEligibleForFreeTrial</key><false/>
|
||||
</dict>
|
||||
<key>terms</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>type</key><string>Store</string>
|
||||
<key>latestTerms</key><integer>22</integer>
|
||||
<key>agreedToTerms</key><integer>22</integer>
|
||||
<key>source</key><string>account</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>account</key>
|
||||
<dict>
|
||||
<key>isMinor</key><false/>
|
||||
<key>suspectUnderage</key><false/>
|
||||
</dict>
|
||||
<key>family</key>
|
||||
<dict>
|
||||
<key>hasFamily</key><false/>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
250
src_mac/ipatool-py/reqs/schemas/store_authenticate_req.py
Executable file
250
src_mac/ipatool-py/reqs/schemas/store_authenticate_req.py
Executable file
@@ -0,0 +1,250 @@
|
||||
from reprlib import repr as limitedRepr
|
||||
|
||||
|
||||
class StoreAuthenticateReq:
|
||||
|
||||
_types_map = {
|
||||
"appleId": {"type": str, "subtype": None},
|
||||
"attempt": {"type": str, "subtype": None},
|
||||
"createSession": {"type": str, "subtype": None},
|
||||
"guid": {"type": str, "subtype": None},
|
||||
"password": {"type": str, "subtype": None},
|
||||
"rmp": {"type": str, "subtype": None},
|
||||
"why": {"type": str, "subtype": None},
|
||||
}
|
||||
_formats_map = {}
|
||||
_validations_map = {
|
||||
"appleId": {
|
||||
"required": True,
|
||||
},
|
||||
"attempt": {
|
||||
"required": True,
|
||||
},
|
||||
"createSession": {
|
||||
"required": True,
|
||||
},
|
||||
"guid": {
|
||||
"required": True,
|
||||
},
|
||||
"password": {
|
||||
"required": True,
|
||||
},
|
||||
"rmp": {
|
||||
"required": True,
|
||||
},
|
||||
"why": {
|
||||
"required": True,
|
||||
},
|
||||
}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
appleId: str = None,
|
||||
attempt: str = None,
|
||||
createSession: str = None,
|
||||
guid: str = None,
|
||||
password: str = None,
|
||||
rmp: str = None,
|
||||
why: str = None,
|
||||
):
|
||||
pass
|
||||
self.__appleId = appleId
|
||||
self.__attempt = attempt
|
||||
self.__createSession = createSession
|
||||
self.__guid = guid
|
||||
self.__password = password
|
||||
self.__rmp = rmp
|
||||
self.__why = why
|
||||
|
||||
def _get_appleId(self):
|
||||
return self.__appleId
|
||||
|
||||
def _set_appleId(self, value):
|
||||
if not isinstance(value, str):
|
||||
raise TypeError("appleId must be str")
|
||||
|
||||
self.__appleId = value
|
||||
|
||||
appleId = property(_get_appleId, _set_appleId)
|
||||
|
||||
def _get_attempt(self):
|
||||
return self.__attempt
|
||||
|
||||
def _set_attempt(self, value):
|
||||
if not isinstance(value, str):
|
||||
raise TypeError("attempt must be str")
|
||||
|
||||
self.__attempt = value
|
||||
|
||||
attempt = property(_get_attempt, _set_attempt)
|
||||
|
||||
def _get_createSession(self):
|
||||
return self.__createSession
|
||||
|
||||
def _set_createSession(self, value):
|
||||
if not isinstance(value, str):
|
||||
raise TypeError("createSession must be str")
|
||||
|
||||
self.__createSession = value
|
||||
|
||||
createSession = property(_get_createSession, _set_createSession)
|
||||
|
||||
def _get_guid(self):
|
||||
return self.__guid
|
||||
|
||||
def _set_guid(self, value):
|
||||
if not isinstance(value, str):
|
||||
raise TypeError("guid must be str")
|
||||
|
||||
self.__guid = value
|
||||
|
||||
guid = property(_get_guid, _set_guid)
|
||||
|
||||
def _get_password(self):
|
||||
return self.__password
|
||||
|
||||
def _set_password(self, value):
|
||||
if not isinstance(value, str):
|
||||
raise TypeError("password must be str")
|
||||
|
||||
self.__password = value
|
||||
|
||||
password = property(_get_password, _set_password)
|
||||
|
||||
def _get_rmp(self):
|
||||
return self.__rmp
|
||||
|
||||
def _set_rmp(self, value):
|
||||
if not isinstance(value, str):
|
||||
raise TypeError("rmp must be str")
|
||||
|
||||
self.__rmp = value
|
||||
|
||||
rmp = property(_get_rmp, _set_rmp)
|
||||
|
||||
def _get_why(self):
|
||||
return self.__why
|
||||
|
||||
def _set_why(self, value):
|
||||
if not isinstance(value, str):
|
||||
raise TypeError("why must be str")
|
||||
|
||||
self.__why = value
|
||||
|
||||
why = property(_get_why, _set_why)
|
||||
|
||||
@staticmethod
|
||||
def from_dict(d):
|
||||
v = {}
|
||||
if "appleId" in d:
|
||||
v["appleId"] = (
|
||||
str.from_dict(d["appleId"])
|
||||
if hasattr(str, "from_dict")
|
||||
else d["appleId"]
|
||||
)
|
||||
if "attempt" in d:
|
||||
v["attempt"] = (
|
||||
str.from_dict(d["attempt"])
|
||||
if hasattr(str, "from_dict")
|
||||
else d["attempt"]
|
||||
)
|
||||
if "createSession" in d:
|
||||
v["createSession"] = (
|
||||
str.from_dict(d["createSession"])
|
||||
if hasattr(str, "from_dict")
|
||||
else d["createSession"]
|
||||
)
|
||||
if "guid" in d:
|
||||
v["guid"] = (
|
||||
str.from_dict(d["guid"]) if hasattr(str, "from_dict") else d["guid"]
|
||||
)
|
||||
if "password" in d:
|
||||
v["password"] = (
|
||||
str.from_dict(d["password"])
|
||||
if hasattr(str, "from_dict")
|
||||
else d["password"]
|
||||
)
|
||||
if "rmp" in d:
|
||||
v["rmp"] = (
|
||||
str.from_dict(d["rmp"]) if hasattr(str, "from_dict") else d["rmp"]
|
||||
)
|
||||
if "why" in d:
|
||||
v["why"] = (
|
||||
str.from_dict(d["why"]) if hasattr(str, "from_dict") else d["why"]
|
||||
)
|
||||
return StoreAuthenticateReq(**v)
|
||||
|
||||
def as_dict(self):
|
||||
d = {}
|
||||
if self.__appleId is not None:
|
||||
d["appleId"] = (
|
||||
self.__appleId.as_dict()
|
||||
if hasattr(self.__appleId, "as_dict")
|
||||
else self.__appleId
|
||||
)
|
||||
if self.__attempt is not None:
|
||||
d["attempt"] = (
|
||||
self.__attempt.as_dict()
|
||||
if hasattr(self.__attempt, "as_dict")
|
||||
else self.__attempt
|
||||
)
|
||||
if self.__createSession is not None:
|
||||
d["createSession"] = (
|
||||
self.__createSession.as_dict()
|
||||
if hasattr(self.__createSession, "as_dict")
|
||||
else self.__createSession
|
||||
)
|
||||
if self.__guid is not None:
|
||||
d["guid"] = (
|
||||
self.__guid.as_dict()
|
||||
if hasattr(self.__guid, "as_dict")
|
||||
else self.__guid
|
||||
)
|
||||
if self.__password is not None:
|
||||
d["password"] = (
|
||||
self.__password.as_dict()
|
||||
if hasattr(self.__password, "as_dict")
|
||||
else self.__password
|
||||
)
|
||||
if self.__rmp is not None:
|
||||
d["rmp"] = (
|
||||
self.__rmp.as_dict() if hasattr(self.__rmp, "as_dict") else self.__rmp
|
||||
)
|
||||
if self.__why is not None:
|
||||
d["why"] = (
|
||||
self.__why.as_dict() if hasattr(self.__why, "as_dict") else self.__why
|
||||
)
|
||||
return d
|
||||
|
||||
def __repr__(self):
|
||||
return "<Class StoreAuthenticateReq. appleId: {}, attempt: {}, createSession: {}, guid: {}, password: {}, rmp: {}, why: {}>".format(
|
||||
limitedRepr(
|
||||
self.__appleId[:20]
|
||||
if isinstance(self.__appleId, bytes)
|
||||
else self.__appleId
|
||||
),
|
||||
limitedRepr(
|
||||
self.__attempt[:20]
|
||||
if isinstance(self.__attempt, bytes)
|
||||
else self.__attempt
|
||||
),
|
||||
limitedRepr(
|
||||
self.__createSession[:20]
|
||||
if isinstance(self.__createSession, bytes)
|
||||
else self.__createSession
|
||||
),
|
||||
limitedRepr(
|
||||
self.__guid[:20] if isinstance(self.__guid, bytes) else self.__guid
|
||||
),
|
||||
limitedRepr(
|
||||
self.__password[:20]
|
||||
if isinstance(self.__password, bytes)
|
||||
else self.__password
|
||||
),
|
||||
limitedRepr(
|
||||
self.__rmp[:20] if isinstance(self.__rmp, bytes) else self.__rmp
|
||||
),
|
||||
limitedRepr(
|
||||
self.__why[:20] if isinstance(self.__why, bytes) else self.__why
|
||||
),
|
||||
)
|
||||
2638
src_mac/ipatool-py/reqs/schemas/store_authenticate_resp.py
Executable file
2638
src_mac/ipatool-py/reqs/schemas/store_authenticate_resp.py
Executable file
File diff suppressed because it is too large
Load Diff
956
src_mac/ipatool-py/reqs/schemas/store_buyproduct_req.py
Executable file
956
src_mac/ipatool-py/reqs/schemas/store_buyproduct_req.py
Executable file
@@ -0,0 +1,956 @@
|
||||
from reprlib import repr as limitedRepr
|
||||
|
||||
|
||||
class StoreBuyproductReq:
|
||||
|
||||
_types_map = {
|
||||
"ageCheck": {"type": str, "subtype": None},
|
||||
"appExtVrsId": {"type": str, "subtype": None},
|
||||
"guid": {"type": str, "subtype": None},
|
||||
"hasBeenAuthedForBuy": {"type": str, "subtype": None},
|
||||
"isInApp": {"type": str, "subtype": None},
|
||||
"kbsync": {"type": str, "subtype": None},
|
||||
"sbsync": {"type": str, "subtype": None},
|
||||
"afds": {"type": str, "subtype": None},
|
||||
"machineName": {"type": str, "subtype": None},
|
||||
"mtApp": {"type": str, "subtype": None},
|
||||
"mtClientId": {"type": str, "subtype": None},
|
||||
"mtEventTime": {"type": str, "subtype": None},
|
||||
"mtPageId": {"type": str, "subtype": None},
|
||||
"mtPageType": {"type": str, "subtype": None},
|
||||
"mtPrevPage": {"type": str, "subtype": None},
|
||||
"mtRequestId": {"type": str, "subtype": None},
|
||||
"mtTopic": {"type": str, "subtype": None},
|
||||
"needDiv": {"type": str, "subtype": None},
|
||||
"pg": {"type": str, "subtype": None},
|
||||
"price": {"type": str, "subtype": None},
|
||||
"pricingParameters": {"type": str, "subtype": None},
|
||||
"productType": {"type": str, "subtype": None},
|
||||
"salableAdamId": {"type": str, "subtype": None},
|
||||
"hasAskedToFulfillPreorder": {"type": str, "subtype": None},
|
||||
"buyWithoutAuthorization": {"type": str, "subtype": None},
|
||||
"hasDoneAgeCheck": {"type": str, "subtype": None},
|
||||
"hasConfirmedPaymentSheet": {"type": str, "subtype": None},
|
||||
"asn": {"type": str, "subtype": None},
|
||||
}
|
||||
_formats_map = {}
|
||||
_validations_map = {
|
||||
"ageCheck": {
|
||||
"required": False,
|
||||
},
|
||||
"appExtVrsId": {
|
||||
"required": True,
|
||||
},
|
||||
"guid": {
|
||||
"required": True,
|
||||
},
|
||||
"hasBeenAuthedForBuy": {
|
||||
"required": False,
|
||||
},
|
||||
"isInApp": {
|
||||
"required": False,
|
||||
},
|
||||
"kbsync": {
|
||||
"required": True,
|
||||
},
|
||||
"sbsync": {
|
||||
"required": False,
|
||||
},
|
||||
"afds": {
|
||||
"required": False,
|
||||
},
|
||||
"machineName": {
|
||||
"required": False,
|
||||
},
|
||||
"mtApp": {
|
||||
"required": False,
|
||||
},
|
||||
"mtClientId": {
|
||||
"required": False,
|
||||
},
|
||||
"mtEventTime": {
|
||||
"required": False,
|
||||
},
|
||||
"mtPageId": {
|
||||
"required": False,
|
||||
},
|
||||
"mtPageType": {
|
||||
"required": False,
|
||||
},
|
||||
"mtPrevPage": {
|
||||
"required": False,
|
||||
},
|
||||
"mtRequestId": {
|
||||
"required": False,
|
||||
},
|
||||
"mtTopic": {
|
||||
"required": False,
|
||||
},
|
||||
"needDiv": {
|
||||
"required": False,
|
||||
},
|
||||
"pg": {
|
||||
"required": False,
|
||||
},
|
||||
"price": {
|
||||
"required": True,
|
||||
},
|
||||
"pricingParameters": {
|
||||
"required": True,
|
||||
},
|
||||
"productType": {
|
||||
"required": True,
|
||||
},
|
||||
"salableAdamId": {
|
||||
"required": True,
|
||||
},
|
||||
"hasAskedToFulfillPreorder": {
|
||||
"required": False,
|
||||
},
|
||||
"buyWithoutAuthorization": {
|
||||
"required": False,
|
||||
},
|
||||
"hasDoneAgeCheck": {
|
||||
"required": False,
|
||||
},
|
||||
"hasConfirmedPaymentSheet": {
|
||||
"required": False,
|
||||
},
|
||||
"asn": {
|
||||
"required": False,
|
||||
},
|
||||
}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
ageCheck: str = None,
|
||||
appExtVrsId: str = None,
|
||||
guid: str = None,
|
||||
hasBeenAuthedForBuy: str = None,
|
||||
isInApp: str = None,
|
||||
kbsync: str = None,
|
||||
sbsync: str = None,
|
||||
afds: str = None,
|
||||
machineName: str = None,
|
||||
mtApp: str = None,
|
||||
mtClientId: str = None,
|
||||
mtEventTime: str = None,
|
||||
mtPageId: str = None,
|
||||
mtPageType: str = None,
|
||||
mtPrevPage: str = None,
|
||||
mtRequestId: str = None,
|
||||
mtTopic: str = None,
|
||||
needDiv: str = None,
|
||||
pg: str = None,
|
||||
price: str = None,
|
||||
pricingParameters: str = None,
|
||||
productType: str = None,
|
||||
salableAdamId: str = None,
|
||||
hasAskedToFulfillPreorder: str = None,
|
||||
buyWithoutAuthorization: str = None,
|
||||
hasDoneAgeCheck: str = None,
|
||||
hasConfirmedPaymentSheet: str = None,
|
||||
asn: str = None,
|
||||
):
|
||||
pass
|
||||
self.__ageCheck = ageCheck
|
||||
self.__appExtVrsId = appExtVrsId
|
||||
self.__guid = guid
|
||||
self.__hasBeenAuthedForBuy = hasBeenAuthedForBuy
|
||||
self.__isInApp = isInApp
|
||||
self.__kbsync = kbsync
|
||||
self.__sbsync = sbsync
|
||||
self.__afds = afds
|
||||
self.__machineName = machineName
|
||||
self.__mtApp = mtApp
|
||||
self.__mtClientId = mtClientId
|
||||
self.__mtEventTime = mtEventTime
|
||||
self.__mtPageId = mtPageId
|
||||
self.__mtPageType = mtPageType
|
||||
self.__mtPrevPage = mtPrevPage
|
||||
self.__mtRequestId = mtRequestId
|
||||
self.__mtTopic = mtTopic
|
||||
self.__needDiv = needDiv
|
||||
self.__pg = pg
|
||||
self.__price = price
|
||||
self.__pricingParameters = pricingParameters
|
||||
self.__productType = productType
|
||||
self.__salableAdamId = salableAdamId
|
||||
self.__hasAskedToFulfillPreorder = hasAskedToFulfillPreorder
|
||||
self.__buyWithoutAuthorization = buyWithoutAuthorization
|
||||
self.__hasDoneAgeCheck = hasDoneAgeCheck
|
||||
self.__hasConfirmedPaymentSheet = hasConfirmedPaymentSheet
|
||||
self.__asn = asn
|
||||
|
||||
def _get_ageCheck(self):
|
||||
return self.__ageCheck
|
||||
|
||||
def _set_ageCheck(self, value):
|
||||
if value is not None and not isinstance(value, str):
|
||||
raise TypeError("ageCheck must be str")
|
||||
|
||||
self.__ageCheck = value
|
||||
|
||||
ageCheck = property(_get_ageCheck, _set_ageCheck)
|
||||
|
||||
def _get_appExtVrsId(self):
|
||||
return self.__appExtVrsId
|
||||
|
||||
def _set_appExtVrsId(self, value):
|
||||
if not isinstance(value, str):
|
||||
raise TypeError("appExtVrsId must be str")
|
||||
|
||||
self.__appExtVrsId = value
|
||||
|
||||
appExtVrsId = property(_get_appExtVrsId, _set_appExtVrsId)
|
||||
|
||||
def _get_guid(self):
|
||||
return self.__guid
|
||||
|
||||
def _set_guid(self, value):
|
||||
if not isinstance(value, str):
|
||||
raise TypeError("guid must be str")
|
||||
|
||||
self.__guid = value
|
||||
|
||||
guid = property(_get_guid, _set_guid)
|
||||
|
||||
def _get_hasBeenAuthedForBuy(self):
|
||||
return self.__hasBeenAuthedForBuy
|
||||
|
||||
def _set_hasBeenAuthedForBuy(self, value):
|
||||
if value is not None and not isinstance(value, str):
|
||||
raise TypeError("hasBeenAuthedForBuy must be str")
|
||||
|
||||
self.__hasBeenAuthedForBuy = value
|
||||
|
||||
hasBeenAuthedForBuy = property(_get_hasBeenAuthedForBuy, _set_hasBeenAuthedForBuy)
|
||||
|
||||
def _get_isInApp(self):
|
||||
return self.__isInApp
|
||||
|
||||
def _set_isInApp(self, value):
|
||||
if value is not None and not isinstance(value, str):
|
||||
raise TypeError("isInApp must be str")
|
||||
|
||||
self.__isInApp = value
|
||||
|
||||
isInApp = property(_get_isInApp, _set_isInApp)
|
||||
|
||||
def _get_kbsync(self):
|
||||
return self.__kbsync
|
||||
|
||||
def _set_kbsync(self, value):
|
||||
if not isinstance(value, str):
|
||||
raise TypeError("kbsync must be str")
|
||||
|
||||
self.__kbsync = value
|
||||
|
||||
kbsync = property(_get_kbsync, _set_kbsync)
|
||||
|
||||
def _get_sbsync(self):
|
||||
return self.__sbsync
|
||||
|
||||
def _set_sbsync(self, value):
|
||||
if not isinstance(value, str):
|
||||
raise TypeError("sbsync must be str")
|
||||
|
||||
self.__sbsync = value
|
||||
|
||||
sbsync = property(_get_sbsync, _set_sbsync)
|
||||
|
||||
def _get_afds(self):
|
||||
return self.__afds
|
||||
|
||||
def _set_afds(self, value):
|
||||
if not isinstance(value, str):
|
||||
raise TypeError("afds must be str")
|
||||
|
||||
self.__afds = value
|
||||
|
||||
afds = property(_get_afds, _set_afds)
|
||||
|
||||
def _get_machineName(self):
|
||||
return self.__machineName
|
||||
|
||||
def _set_machineName(self, value):
|
||||
if value is not None and not isinstance(value, str):
|
||||
raise TypeError("machineName must be str")
|
||||
|
||||
self.__machineName = value
|
||||
|
||||
machineName = property(_get_machineName, _set_machineName)
|
||||
|
||||
def _get_mtApp(self):
|
||||
return self.__mtApp
|
||||
|
||||
def _set_mtApp(self, value):
|
||||
if value is not None and not isinstance(value, str):
|
||||
raise TypeError("mtApp must be str")
|
||||
|
||||
self.__mtApp = value
|
||||
|
||||
mtApp = property(_get_mtApp, _set_mtApp)
|
||||
|
||||
def _get_mtClientId(self):
|
||||
return self.__mtClientId
|
||||
|
||||
def _set_mtClientId(self, value):
|
||||
if value is not None and not isinstance(value, str):
|
||||
raise TypeError("mtClientId must be str")
|
||||
|
||||
self.__mtClientId = value
|
||||
|
||||
mtClientId = property(_get_mtClientId, _set_mtClientId)
|
||||
|
||||
def _get_mtEventTime(self):
|
||||
return self.__mtEventTime
|
||||
|
||||
def _set_mtEventTime(self, value):
|
||||
if value is not None and not isinstance(value, str):
|
||||
raise TypeError("mtEventTime must be str")
|
||||
|
||||
self.__mtEventTime = value
|
||||
|
||||
mtEventTime = property(_get_mtEventTime, _set_mtEventTime)
|
||||
|
||||
def _get_mtPageId(self):
|
||||
return self.__mtPageId
|
||||
|
||||
def _set_mtPageId(self, value):
|
||||
if value is not None and not isinstance(value, str):
|
||||
raise TypeError("mtPageId must be str")
|
||||
|
||||
self.__mtPageId = value
|
||||
|
||||
mtPageId = property(_get_mtPageId, _set_mtPageId)
|
||||
|
||||
def _get_mtPageType(self):
|
||||
return self.__mtPageType
|
||||
|
||||
def _set_mtPageType(self, value):
|
||||
if value is not None and not isinstance(value, str):
|
||||
raise TypeError("mtPageType must be str")
|
||||
|
||||
self.__mtPageType = value
|
||||
|
||||
mtPageType = property(_get_mtPageType, _set_mtPageType)
|
||||
|
||||
def _get_mtPrevPage(self):
|
||||
return self.__mtPrevPage
|
||||
|
||||
def _set_mtPrevPage(self, value):
|
||||
if value is not None and not isinstance(value, str):
|
||||
raise TypeError("mtPrevPage must be str")
|
||||
|
||||
self.__mtPrevPage = value
|
||||
|
||||
mtPrevPage = property(_get_mtPrevPage, _set_mtPrevPage)
|
||||
|
||||
def _get_mtRequestId(self):
|
||||
return self.__mtRequestId
|
||||
|
||||
def _set_mtRequestId(self, value):
|
||||
if value is not None and not isinstance(value, str):
|
||||
raise TypeError("mtRequestId must be str")
|
||||
|
||||
self.__mtRequestId = value
|
||||
|
||||
mtRequestId = property(_get_mtRequestId, _set_mtRequestId)
|
||||
|
||||
def _get_mtTopic(self):
|
||||
return self.__mtTopic
|
||||
|
||||
def _set_mtTopic(self, value):
|
||||
if value is not None and not isinstance(value, str):
|
||||
raise TypeError("mtTopic must be str")
|
||||
|
||||
self.__mtTopic = value
|
||||
|
||||
mtTopic = property(_get_mtTopic, _set_mtTopic)
|
||||
|
||||
def _get_needDiv(self):
|
||||
return self.__needDiv
|
||||
|
||||
def _set_needDiv(self, value):
|
||||
if value is not None and not isinstance(value, str):
|
||||
raise TypeError("needDiv must be str")
|
||||
|
||||
self.__needDiv = value
|
||||
|
||||
needDiv = property(_get_needDiv, _set_needDiv)
|
||||
|
||||
def _get_pg(self):
|
||||
return self.__pg
|
||||
|
||||
def _set_pg(self, value):
|
||||
if value is not None and not isinstance(value, str):
|
||||
raise TypeError("pg must be str")
|
||||
|
||||
self.__pg = value
|
||||
|
||||
pg = property(_get_pg, _set_pg)
|
||||
|
||||
def _get_price(self):
|
||||
return self.__price
|
||||
|
||||
def _set_price(self, value):
|
||||
if not isinstance(value, str):
|
||||
raise TypeError("price must be str")
|
||||
|
||||
self.__price = value
|
||||
|
||||
price = property(_get_price, _set_price)
|
||||
|
||||
def _get_pricingParameters(self):
|
||||
return self.__pricingParameters
|
||||
|
||||
def _set_pricingParameters(self, value):
|
||||
if not isinstance(value, str):
|
||||
raise TypeError("pricingParameters must be str")
|
||||
|
||||
self.__pricingParameters = value
|
||||
|
||||
pricingParameters = property(_get_pricingParameters, _set_pricingParameters)
|
||||
|
||||
def _get_productType(self):
|
||||
return self.__productType
|
||||
|
||||
def _set_productType(self, value):
|
||||
if not isinstance(value, str):
|
||||
raise TypeError("productType must be str")
|
||||
|
||||
self.__productType = value
|
||||
|
||||
productType = property(_get_productType, _set_productType)
|
||||
|
||||
def _get_salableAdamId(self):
|
||||
return self.__salableAdamId
|
||||
|
||||
def _set_salableAdamId(self, value):
|
||||
if not isinstance(value, str):
|
||||
raise TypeError("salableAdamId must be str")
|
||||
|
||||
self.__salableAdamId = value
|
||||
|
||||
salableAdamId = property(_get_salableAdamId, _set_salableAdamId)
|
||||
|
||||
def _get_hasAskedToFulfillPreorder(self):
|
||||
return self.__hasAskedToFulfillPreorder
|
||||
|
||||
def _set_hasAskedToFulfillPreorder(self, value):
|
||||
if value is not None and not isinstance(value, str):
|
||||
raise TypeError("hasAskedToFulfillPreorder must be str")
|
||||
|
||||
self.__hasAskedToFulfillPreorder = value
|
||||
|
||||
hasAskedToFulfillPreorder = property(
|
||||
_get_hasAskedToFulfillPreorder, _set_hasAskedToFulfillPreorder
|
||||
)
|
||||
|
||||
def _get_buyWithoutAuthorization(self):
|
||||
return self.__buyWithoutAuthorization
|
||||
|
||||
def _set_buyWithoutAuthorization(self, value):
|
||||
if value is not None and not isinstance(value, str):
|
||||
raise TypeError("buyWithoutAuthorization must be str")
|
||||
|
||||
self.__buyWithoutAuthorization = value
|
||||
|
||||
buyWithoutAuthorization = property(
|
||||
_get_buyWithoutAuthorization, _set_buyWithoutAuthorization
|
||||
)
|
||||
|
||||
def _get_hasDoneAgeCheck(self):
|
||||
return self.__hasDoneAgeCheck
|
||||
|
||||
def _set_hasDoneAgeCheck(self, value):
|
||||
if value is not None and not isinstance(value, str):
|
||||
raise TypeError("hasDoneAgeCheck must be str")
|
||||
|
||||
self.__hasDoneAgeCheck = value
|
||||
|
||||
hasDoneAgeCheck = property(_get_hasDoneAgeCheck, _set_hasDoneAgeCheck)
|
||||
|
||||
def _get_hasConfirmedPaymentSheet(self):
|
||||
return self.__hasConfirmedPaymentSheet
|
||||
|
||||
def _set_hasConfirmedPaymentSheet(self, value):
|
||||
if value is not None and not isinstance(value, str):
|
||||
raise TypeError("hasConfirmedPaymentSheet must be str")
|
||||
|
||||
self.__hasConfirmedPaymentSheet = value
|
||||
|
||||
hasConfirmedPaymentSheet = property(_get_hasConfirmedPaymentSheet, _set_hasConfirmedPaymentSheet)
|
||||
|
||||
def _get_asn(self):
|
||||
return self.__asn
|
||||
|
||||
def _set_asn(self, value):
|
||||
if value is not None and not isinstance(value, str):
|
||||
raise TypeError("asn must be str")
|
||||
|
||||
self.__asn = value
|
||||
|
||||
asn = property(_get_asn, _set_asn)
|
||||
|
||||
@staticmethod
|
||||
def from_dict(d):
|
||||
v = {}
|
||||
if "ageCheck" in d:
|
||||
v["ageCheck"] = (
|
||||
str.from_dict(d["ageCheck"])
|
||||
if hasattr(str, "from_dict")
|
||||
else d["ageCheck"]
|
||||
)
|
||||
if "appExtVrsId" in d:
|
||||
v["appExtVrsId"] = (
|
||||
str.from_dict(d["appExtVrsId"])
|
||||
if hasattr(str, "from_dict")
|
||||
else d["appExtVrsId"]
|
||||
)
|
||||
if "guid" in d:
|
||||
v["guid"] = (
|
||||
str.from_dict(d["guid"]) if hasattr(str, "from_dict") else d["guid"]
|
||||
)
|
||||
if "hasBeenAuthedForBuy" in d:
|
||||
v["hasBeenAuthedForBuy"] = (
|
||||
str.from_dict(d["hasBeenAuthedForBuy"])
|
||||
if hasattr(str, "from_dict")
|
||||
else d["hasBeenAuthedForBuy"]
|
||||
)
|
||||
if "isInApp" in d:
|
||||
v["isInApp"] = (
|
||||
str.from_dict(d["isInApp"])
|
||||
if hasattr(str, "from_dict")
|
||||
else d["isInApp"]
|
||||
)
|
||||
if "kbsync" in d:
|
||||
v["kbsync"] = (
|
||||
str.from_dict(d["kbsync"]) if hasattr(str, "from_dict") else d["kbsync"]
|
||||
)
|
||||
if "sbsync" in d:
|
||||
v["sbsync"] = (
|
||||
str.from_dict(d["sbsync"]) if hasattr(str, "from_dict") else d["sbsync"]
|
||||
)
|
||||
if "afds" in d:
|
||||
v["afds"] = (
|
||||
str.from_dict(d["afds"]) if hasattr(str, "from_dict") else d["afds"]
|
||||
)
|
||||
if "machineName" in d:
|
||||
v["machineName"] = (
|
||||
str.from_dict(d["machineName"])
|
||||
if hasattr(str, "from_dict")
|
||||
else d["machineName"]
|
||||
)
|
||||
if "mtApp" in d:
|
||||
v["mtApp"] = (
|
||||
str.from_dict(d["mtApp"]) if hasattr(str, "from_dict") else d["mtApp"]
|
||||
)
|
||||
if "mtClientId" in d:
|
||||
v["mtClientId"] = (
|
||||
str.from_dict(d["mtClientId"])
|
||||
if hasattr(str, "from_dict")
|
||||
else d["mtClientId"]
|
||||
)
|
||||
if "mtEventTime" in d:
|
||||
v["mtEventTime"] = (
|
||||
str.from_dict(d["mtEventTime"])
|
||||
if hasattr(str, "from_dict")
|
||||
else d["mtEventTime"]
|
||||
)
|
||||
if "mtPageId" in d:
|
||||
v["mtPageId"] = (
|
||||
str.from_dict(d["mtPageId"])
|
||||
if hasattr(str, "from_dict")
|
||||
else d["mtPageId"]
|
||||
)
|
||||
if "mtPageType" in d:
|
||||
v["mtPageType"] = (
|
||||
str.from_dict(d["mtPageType"])
|
||||
if hasattr(str, "from_dict")
|
||||
else d["mtPageType"]
|
||||
)
|
||||
if "mtPrevPage" in d:
|
||||
v["mtPrevPage"] = (
|
||||
str.from_dict(d["mtPrevPage"])
|
||||
if hasattr(str, "from_dict")
|
||||
else d["mtPrevPage"]
|
||||
)
|
||||
if "mtRequestId" in d:
|
||||
v["mtRequestId"] = (
|
||||
str.from_dict(d["mtRequestId"])
|
||||
if hasattr(str, "from_dict")
|
||||
else d["mtRequestId"]
|
||||
)
|
||||
if "mtTopic" in d:
|
||||
v["mtTopic"] = (
|
||||
str.from_dict(d["mtTopic"])
|
||||
if hasattr(str, "from_dict")
|
||||
else d["mtTopic"]
|
||||
)
|
||||
if "needDiv" in d:
|
||||
v["needDiv"] = (
|
||||
str.from_dict(d["needDiv"])
|
||||
if hasattr(str, "from_dict")
|
||||
else d["needDiv"]
|
||||
)
|
||||
if "pg" in d:
|
||||
v["pg"] = str.from_dict(d["pg"]) if hasattr(str, "from_dict") else d["pg"]
|
||||
if "price" in d:
|
||||
v["price"] = (
|
||||
str.from_dict(d["price"]) if hasattr(str, "from_dict") else d["price"]
|
||||
)
|
||||
if "pricingParameters" in d:
|
||||
v["pricingParameters"] = (
|
||||
str.from_dict(d["pricingParameters"])
|
||||
if hasattr(str, "from_dict")
|
||||
else d["pricingParameters"]
|
||||
)
|
||||
if "productType" in d:
|
||||
v["productType"] = (
|
||||
str.from_dict(d["productType"])
|
||||
if hasattr(str, "from_dict")
|
||||
else d["productType"]
|
||||
)
|
||||
if "salableAdamId" in d:
|
||||
v["salableAdamId"] = (
|
||||
str.from_dict(d["salableAdamId"])
|
||||
if hasattr(str, "from_dict")
|
||||
else d["salableAdamId"]
|
||||
)
|
||||
if "hasAskedToFulfillPreorder" in d:
|
||||
v["hasAskedToFulfillPreorder"] = (
|
||||
str.from_dict(d["hasAskedToFulfillPreorder"])
|
||||
if hasattr(str, "from_dict")
|
||||
else d["hasAskedToFulfillPreorder"]
|
||||
)
|
||||
if "buyWithoutAuthorization" in d:
|
||||
v["buyWithoutAuthorization"] = (
|
||||
str.from_dict(d["buyWithoutAuthorization"])
|
||||
if hasattr(str, "from_dict")
|
||||
else d["buyWithoutAuthorization"]
|
||||
)
|
||||
if "hasDoneAgeCheck" in d:
|
||||
v["hasDoneAgeCheck"] = (
|
||||
str.from_dict(d["hasDoneAgeCheck"])
|
||||
if hasattr(str, "from_dict")
|
||||
else d["hasDoneAgeCheck"]
|
||||
)
|
||||
if "hasConfirmedPaymentSheet" in d:
|
||||
v["hasConfirmedPaymentSheet"] = (
|
||||
str.from_dict(d["hasConfirmedPaymentSheet"])
|
||||
if hasattr(str, "from_dict")
|
||||
else d["hasConfirmedPaymentSheet"]
|
||||
)
|
||||
if "asn" in d:
|
||||
v["asn"] = (
|
||||
str.from_dict(d["asn"])
|
||||
if hasattr(str, "from_dict")
|
||||
else d["asn"]
|
||||
)
|
||||
return StoreBuyproductReq(**v)
|
||||
|
||||
def as_dict(self):
|
||||
d = {}
|
||||
if self.__ageCheck is not None:
|
||||
d["ageCheck"] = (
|
||||
self.__ageCheck.as_dict()
|
||||
if hasattr(self.__ageCheck, "as_dict")
|
||||
else self.__ageCheck
|
||||
)
|
||||
if self.__appExtVrsId is not None:
|
||||
d["appExtVrsId"] = (
|
||||
self.__appExtVrsId.as_dict()
|
||||
if hasattr(self.__appExtVrsId, "as_dict")
|
||||
else self.__appExtVrsId
|
||||
)
|
||||
if self.__guid is not None:
|
||||
d["guid"] = (
|
||||
self.__guid.as_dict()
|
||||
if hasattr(self.__guid, "as_dict")
|
||||
else self.__guid
|
||||
)
|
||||
if self.__hasBeenAuthedForBuy is not None:
|
||||
d["hasBeenAuthedForBuy"] = (
|
||||
self.__hasBeenAuthedForBuy.as_dict()
|
||||
if hasattr(self.__hasBeenAuthedForBuy, "as_dict")
|
||||
else self.__hasBeenAuthedForBuy
|
||||
)
|
||||
if self.__isInApp is not None:
|
||||
d["isInApp"] = (
|
||||
self.__isInApp.as_dict()
|
||||
if hasattr(self.__isInApp, "as_dict")
|
||||
else self.__isInApp
|
||||
)
|
||||
if self.__kbsync is not None:
|
||||
d["kbsync"] = (
|
||||
self.__kbsync.as_dict()
|
||||
if hasattr(self.__kbsync, "as_dict")
|
||||
else self.__kbsync
|
||||
)
|
||||
if self.__sbsync is not None:
|
||||
d["sbsync"] = (
|
||||
self.__sbsync.as_dict()
|
||||
if hasattr(self.__sbsync, "as_dict")
|
||||
else self.__sbsync
|
||||
)
|
||||
if self.__afds is not None:
|
||||
d["afds"] = (
|
||||
self.__afds.as_dict()
|
||||
if hasattr(self.__afds, "as_dict")
|
||||
else self.__afds
|
||||
)
|
||||
if self.__machineName is not None:
|
||||
d["machineName"] = (
|
||||
self.__machineName.as_dict()
|
||||
if hasattr(self.__machineName, "as_dict")
|
||||
else self.__machineName
|
||||
)
|
||||
if self.__mtApp is not None:
|
||||
d["mtApp"] = (
|
||||
self.__mtApp.as_dict()
|
||||
if hasattr(self.__mtApp, "as_dict")
|
||||
else self.__mtApp
|
||||
)
|
||||
if self.__mtClientId is not None:
|
||||
d["mtClientId"] = (
|
||||
self.__mtClientId.as_dict()
|
||||
if hasattr(self.__mtClientId, "as_dict")
|
||||
else self.__mtClientId
|
||||
)
|
||||
if self.__mtEventTime is not None:
|
||||
d["mtEventTime"] = (
|
||||
self.__mtEventTime.as_dict()
|
||||
if hasattr(self.__mtEventTime, "as_dict")
|
||||
else self.__mtEventTime
|
||||
)
|
||||
if self.__mtPageId is not None:
|
||||
d["mtPageId"] = (
|
||||
self.__mtPageId.as_dict()
|
||||
if hasattr(self.__mtPageId, "as_dict")
|
||||
else self.__mtPageId
|
||||
)
|
||||
if self.__mtPageType is not None:
|
||||
d["mtPageType"] = (
|
||||
self.__mtPageType.as_dict()
|
||||
if hasattr(self.__mtPageType, "as_dict")
|
||||
else self.__mtPageType
|
||||
)
|
||||
if self.__mtPrevPage is not None:
|
||||
d["mtPrevPage"] = (
|
||||
self.__mtPrevPage.as_dict()
|
||||
if hasattr(self.__mtPrevPage, "as_dict")
|
||||
else self.__mtPrevPage
|
||||
)
|
||||
if self.__mtRequestId is not None:
|
||||
d["mtRequestId"] = (
|
||||
self.__mtRequestId.as_dict()
|
||||
if hasattr(self.__mtRequestId, "as_dict")
|
||||
else self.__mtRequestId
|
||||
)
|
||||
if self.__mtTopic is not None:
|
||||
d["mtTopic"] = (
|
||||
self.__mtTopic.as_dict()
|
||||
if hasattr(self.__mtTopic, "as_dict")
|
||||
else self.__mtTopic
|
||||
)
|
||||
if self.__needDiv is not None:
|
||||
d["needDiv"] = (
|
||||
self.__needDiv.as_dict()
|
||||
if hasattr(self.__needDiv, "as_dict")
|
||||
else self.__needDiv
|
||||
)
|
||||
if self.__pg is not None:
|
||||
d["pg"] = (
|
||||
self.__pg.as_dict() if hasattr(self.__pg, "as_dict") else self.__pg
|
||||
)
|
||||
if self.__price is not None:
|
||||
d["price"] = (
|
||||
self.__price.as_dict()
|
||||
if hasattr(self.__price, "as_dict")
|
||||
else self.__price
|
||||
)
|
||||
if self.__pricingParameters is not None:
|
||||
d["pricingParameters"] = (
|
||||
self.__pricingParameters.as_dict()
|
||||
if hasattr(self.__pricingParameters, "as_dict")
|
||||
else self.__pricingParameters
|
||||
)
|
||||
if self.__productType is not None:
|
||||
d["productType"] = (
|
||||
self.__productType.as_dict()
|
||||
if hasattr(self.__productType, "as_dict")
|
||||
else self.__productType
|
||||
)
|
||||
if self.__salableAdamId is not None:
|
||||
d["salableAdamId"] = (
|
||||
self.__salableAdamId.as_dict()
|
||||
if hasattr(self.__salableAdamId, "as_dict")
|
||||
else self.__salableAdamId
|
||||
)
|
||||
if self.__hasAskedToFulfillPreorder is not None:
|
||||
d["hasAskedToFulfillPreorder"] = (
|
||||
self.__hasAskedToFulfillPreorder.as_dict()
|
||||
if hasattr(self.__hasAskedToFulfillPreorder, "as_dict")
|
||||
else self.__hasAskedToFulfillPreorder
|
||||
)
|
||||
if self.__buyWithoutAuthorization is not None:
|
||||
d["buyWithoutAuthorization"] = (
|
||||
self.__buyWithoutAuthorization.as_dict()
|
||||
if hasattr(self.__buyWithoutAuthorization, "as_dict")
|
||||
else self.__buyWithoutAuthorization
|
||||
)
|
||||
if self.__hasDoneAgeCheck is not None:
|
||||
d["hasDoneAgeCheck"] = (
|
||||
self.__hasDoneAgeCheck.as_dict()
|
||||
if hasattr(self.__hasDoneAgeCheck, "as_dict")
|
||||
else self.__hasDoneAgeCheck
|
||||
)
|
||||
if self.__hasConfirmedPaymentSheet is not None:
|
||||
d["hasConfirmedPaymentSheet"] = (
|
||||
self.__hasConfirmedPaymentSheet.as_dict()
|
||||
if hasattr(self.__hasConfirmedPaymentSheet, "as_dict")
|
||||
else self.__hasConfirmedPaymentSheet
|
||||
)
|
||||
if self.__asn is not None:
|
||||
d["asn"] = (
|
||||
self.__asn.as_dict()
|
||||
if hasattr(self.__asn, "as_dict")
|
||||
else self.__asn
|
||||
)
|
||||
return d
|
||||
|
||||
def __repr__(self):
|
||||
return "<Class StoreBuyproductReq. ageCheck: {}, appExtVrsId: {}, guid: {}, hasBeenAuthedForBuy: {}, isInApp: {}, kbsync: {}, sbsync: {}, afds: {}, machineName: {}, mtApp: {}, mtClientId: {}, mtEventTime: {}, mtPageId: {}, mtPageType: {}, mtPrevPage: {}, mtRequestId: {}, mtTopic: {}, needDiv: {}, pg: {}, price: {}, pricingParameters: {}, productType: {}, salableAdamId: {}, hasAskedToFulfillPreorder: {}, buyWithoutAuthorization: {}, hasDoneAgeCheck: {}>".format(
|
||||
limitedRepr(
|
||||
self.__ageCheck[:20]
|
||||
if isinstance(self.__ageCheck, bytes)
|
||||
else self.__ageCheck
|
||||
),
|
||||
limitedRepr(
|
||||
self.__appExtVrsId[:20]
|
||||
if isinstance(self.__appExtVrsId, bytes)
|
||||
else self.__appExtVrsId
|
||||
),
|
||||
limitedRepr(
|
||||
self.__guid[:20] if isinstance(self.__guid, bytes) else self.__guid
|
||||
),
|
||||
limitedRepr(
|
||||
self.__hasBeenAuthedForBuy[:20]
|
||||
if isinstance(self.__hasBeenAuthedForBuy, bytes)
|
||||
else self.__hasBeenAuthedForBuy
|
||||
),
|
||||
limitedRepr(
|
||||
self.__isInApp[:20]
|
||||
if isinstance(self.__isInApp, bytes)
|
||||
else self.__isInApp
|
||||
),
|
||||
limitedRepr(
|
||||
self.__kbsync[:20]
|
||||
if isinstance(self.__kbsync, bytes)
|
||||
else self.__kbsync
|
||||
),
|
||||
limitedRepr(
|
||||
self.__sbsync[:20]
|
||||
if isinstance(self.__sbsync, bytes)
|
||||
else self.__sbsync
|
||||
),
|
||||
limitedRepr(
|
||||
self.__afds[:20]
|
||||
if isinstance(self.__afds, bytes)
|
||||
else self.__afds
|
||||
),
|
||||
limitedRepr(
|
||||
self.__machineName[:20]
|
||||
if isinstance(self.__machineName, bytes)
|
||||
else self.__machineName
|
||||
),
|
||||
limitedRepr(
|
||||
self.__mtApp[:20] if isinstance(self.__mtApp, bytes) else self.__mtApp
|
||||
),
|
||||
limitedRepr(
|
||||
self.__mtClientId[:20]
|
||||
if isinstance(self.__mtClientId, bytes)
|
||||
else self.__mtClientId
|
||||
),
|
||||
limitedRepr(
|
||||
self.__mtEventTime[:20]
|
||||
if isinstance(self.__mtEventTime, bytes)
|
||||
else self.__mtEventTime
|
||||
),
|
||||
limitedRepr(
|
||||
self.__mtPageId[:20]
|
||||
if isinstance(self.__mtPageId, bytes)
|
||||
else self.__mtPageId
|
||||
),
|
||||
limitedRepr(
|
||||
self.__mtPageType[:20]
|
||||
if isinstance(self.__mtPageType, bytes)
|
||||
else self.__mtPageType
|
||||
),
|
||||
limitedRepr(
|
||||
self.__mtPrevPage[:20]
|
||||
if isinstance(self.__mtPrevPage, bytes)
|
||||
else self.__mtPrevPage
|
||||
),
|
||||
limitedRepr(
|
||||
self.__mtRequestId[:20]
|
||||
if isinstance(self.__mtRequestId, bytes)
|
||||
else self.__mtRequestId
|
||||
),
|
||||
limitedRepr(
|
||||
self.__mtTopic[:20]
|
||||
if isinstance(self.__mtTopic, bytes)
|
||||
else self.__mtTopic
|
||||
),
|
||||
limitedRepr(
|
||||
self.__needDiv[:20]
|
||||
if isinstance(self.__needDiv, bytes)
|
||||
else self.__needDiv
|
||||
),
|
||||
limitedRepr(self.__pg[:20] if isinstance(self.__pg, bytes) else self.__pg),
|
||||
limitedRepr(
|
||||
self.__price[:20] if isinstance(self.__price, bytes) else self.__price
|
||||
),
|
||||
limitedRepr(
|
||||
self.__pricingParameters[:20]
|
||||
if isinstance(self.__pricingParameters, bytes)
|
||||
else self.__pricingParameters
|
||||
),
|
||||
limitedRepr(
|
||||
self.__productType[:20]
|
||||
if isinstance(self.__productType, bytes)
|
||||
else self.__productType
|
||||
),
|
||||
limitedRepr(
|
||||
self.__salableAdamId[:20]
|
||||
if isinstance(self.__salableAdamId, bytes)
|
||||
else self.__salableAdamId
|
||||
),
|
||||
limitedRepr(
|
||||
self.__hasAskedToFulfillPreorder[:20]
|
||||
if isinstance(self.__hasAskedToFulfillPreorder, bytes)
|
||||
else self.__hasAskedToFulfillPreorder
|
||||
),
|
||||
limitedRepr(
|
||||
self.__buyWithoutAuthorization[:20]
|
||||
if isinstance(self.__buyWithoutAuthorization, bytes)
|
||||
else self.__buyWithoutAuthorization
|
||||
),
|
||||
limitedRepr(
|
||||
self.__hasDoneAgeCheck[:20]
|
||||
if isinstance(self.__hasDoneAgeCheck, bytes)
|
||||
else self.__hasDoneAgeCheck
|
||||
),
|
||||
limitedRepr(
|
||||
self.__hasConfirmedPaymentSheet[:20]
|
||||
if isinstance(self.__hasConfirmedPaymentSheet, bytes)
|
||||
else self.__hasConfirmedPaymentSheet
|
||||
),
|
||||
limitedRepr(
|
||||
self.__asn[:20]
|
||||
if isinstance(self.__asn, bytes)
|
||||
else self.__asn
|
||||
),
|
||||
)
|
||||
5758
src_mac/ipatool-py/reqs/schemas/store_buyproduct_resp.py
Executable file
5758
src_mac/ipatool-py/reqs/schemas/store_buyproduct_resp.py
Executable file
File diff suppressed because it is too large
Load Diff
160
src_mac/ipatool-py/reqs/schemas/store_download_req.py
Executable file
160
src_mac/ipatool-py/reqs/schemas/store_download_req.py
Executable file
@@ -0,0 +1,160 @@
|
||||
from reprlib import repr as limitedRepr
|
||||
|
||||
|
||||
class StoreDownloadReq:
|
||||
|
||||
_types_map = {
|
||||
"creditDisplay": {"type": str, "subtype": None},
|
||||
"guid": {"type": str, "subtype": None},
|
||||
"salableAdamId": {"type": str, "subtype": None},
|
||||
"appExtVrsId": {"type": str, "subtype": None},
|
||||
}
|
||||
_formats_map = {}
|
||||
_validations_map = {
|
||||
"creditDisplay": {
|
||||
"required": True,
|
||||
},
|
||||
"guid": {
|
||||
"required": True,
|
||||
},
|
||||
"salableAdamId": {
|
||||
"required": True,
|
||||
},
|
||||
"appExtVrsId": {
|
||||
"required": False,
|
||||
},
|
||||
}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
creditDisplay: str = None,
|
||||
guid: str = None,
|
||||
salableAdamId: str = None,
|
||||
appExtVrsId: str = None,
|
||||
):
|
||||
pass
|
||||
self.__creditDisplay = creditDisplay
|
||||
self.__guid = guid
|
||||
self.__salableAdamId = salableAdamId
|
||||
self.__appExtVrsId = appExtVrsId
|
||||
|
||||
def _get_creditDisplay(self):
|
||||
return self.__creditDisplay
|
||||
|
||||
def _set_creditDisplay(self, value):
|
||||
if not isinstance(value, str):
|
||||
raise TypeError("creditDisplay must be str")
|
||||
|
||||
self.__creditDisplay = value
|
||||
|
||||
creditDisplay = property(_get_creditDisplay, _set_creditDisplay)
|
||||
|
||||
def _get_guid(self):
|
||||
return self.__guid
|
||||
|
||||
def _set_guid(self, value):
|
||||
if not isinstance(value, str):
|
||||
raise TypeError("guid must be str")
|
||||
|
||||
self.__guid = value
|
||||
|
||||
guid = property(_get_guid, _set_guid)
|
||||
|
||||
def _get_salableAdamId(self):
|
||||
return self.__salableAdamId
|
||||
|
||||
def _set_salableAdamId(self, value):
|
||||
if not isinstance(value, str):
|
||||
raise TypeError("salableAdamId must be str")
|
||||
|
||||
self.__salableAdamId = value
|
||||
|
||||
salableAdamId = property(_get_salableAdamId, _set_salableAdamId)
|
||||
|
||||
def _get_appExtVrsId(self):
|
||||
return self.__appExtVrsId
|
||||
|
||||
def _set_appExtVrsId(self, value):
|
||||
if value is not None and not isinstance(value, str):
|
||||
raise TypeError("appExtVrsId must be str")
|
||||
|
||||
self.__appExtVrsId = value
|
||||
|
||||
appExtVrsId = property(_get_appExtVrsId, _set_appExtVrsId)
|
||||
|
||||
@staticmethod
|
||||
def from_dict(d):
|
||||
v = {}
|
||||
if "creditDisplay" in d:
|
||||
v["creditDisplay"] = (
|
||||
str.from_dict(d["creditDisplay"])
|
||||
if hasattr(str, "from_dict")
|
||||
else d["creditDisplay"]
|
||||
)
|
||||
if "guid" in d:
|
||||
v["guid"] = (
|
||||
str.from_dict(d["guid"]) if hasattr(str, "from_dict") else d["guid"]
|
||||
)
|
||||
if "salableAdamId" in d:
|
||||
v["salableAdamId"] = (
|
||||
str.from_dict(d["salableAdamId"])
|
||||
if hasattr(str, "from_dict")
|
||||
else d["salableAdamId"]
|
||||
)
|
||||
if "appExtVrsId" in d:
|
||||
v["appExtVrsId"] = (
|
||||
str.from_dict(d["appExtVrsId"])
|
||||
if hasattr(str, "from_dict")
|
||||
else d["appExtVrsId"]
|
||||
)
|
||||
return StoreDownloadReq(**v)
|
||||
|
||||
def as_dict(self):
|
||||
d = {}
|
||||
if self.__creditDisplay is not None:
|
||||
d["creditDisplay"] = (
|
||||
self.__creditDisplay.as_dict()
|
||||
if hasattr(self.__creditDisplay, "as_dict")
|
||||
else self.__creditDisplay
|
||||
)
|
||||
if self.__guid is not None:
|
||||
d["guid"] = (
|
||||
self.__guid.as_dict()
|
||||
if hasattr(self.__guid, "as_dict")
|
||||
else self.__guid
|
||||
)
|
||||
if self.__salableAdamId is not None:
|
||||
d["salableAdamId"] = (
|
||||
self.__salableAdamId.as_dict()
|
||||
if hasattr(self.__salableAdamId, "as_dict")
|
||||
else self.__salableAdamId
|
||||
)
|
||||
if self.__appExtVrsId is not None:
|
||||
d["appExtVrsId"] = (
|
||||
self.__appExtVrsId.as_dict()
|
||||
if hasattr(self.__appExtVrsId, "as_dict")
|
||||
else self.__appExtVrsId
|
||||
)
|
||||
return d
|
||||
|
||||
def __repr__(self):
|
||||
return "<Class StoreDownloadReq. creditDisplay: {}, guid: {}, salableAdamId: {}, appExtVrsId: {}>".format(
|
||||
limitedRepr(
|
||||
self.__creditDisplay[:20]
|
||||
if isinstance(self.__creditDisplay, bytes)
|
||||
else self.__creditDisplay
|
||||
),
|
||||
limitedRepr(
|
||||
self.__guid[:20] if isinstance(self.__guid, bytes) else self.__guid
|
||||
),
|
||||
limitedRepr(
|
||||
self.__salableAdamId[:20]
|
||||
if isinstance(self.__salableAdamId, bytes)
|
||||
else self.__salableAdamId
|
||||
),
|
||||
limitedRepr(
|
||||
self.__appExtVrsId[:20]
|
||||
if isinstance(self.__appExtVrsId, bytes)
|
||||
else self.__appExtVrsId
|
||||
),
|
||||
)
|
||||
3910
src_mac/ipatool-py/reqs/schemas/store_download_resp.py
Executable file
3910
src_mac/ipatool-py/reqs/schemas/store_download_resp.py
Executable file
File diff suppressed because it is too large
Load Diff
254
src_mac/ipatool-py/reqs/store.py
Executable file
254
src_mac/ipatool-py/reqs/store.py
Executable file
@@ -0,0 +1,254 @@
|
||||
import hashlib
|
||||
import json
|
||||
import pickle
|
||||
import plistlib
|
||||
import requests
|
||||
from reqs.schemas.store_authenticate_req import StoreAuthenticateReq
|
||||
from reqs.schemas.store_authenticate_resp import StoreAuthenticateResp
|
||||
from reqs.schemas.store_buyproduct_req import StoreBuyproductReq
|
||||
from reqs.schemas.store_buyproduct_resp import StoreBuyproductResp
|
||||
from reqs.schemas.store_download_req import StoreDownloadReq
|
||||
from reqs.schemas.store_download_resp import StoreDownloadResp
|
||||
|
||||
class StoreException(Exception):
|
||||
def __init__(self, req, resp, errMsg, errType=None):
|
||||
self.req = req
|
||||
self.resp = resp # type: StoreDownloadResp
|
||||
self.errMsg = errMsg
|
||||
self.errType = errType
|
||||
super().__init__(
|
||||
"Store %s error: %s" % (self.req, self.errMsg) if not self.errType else
|
||||
"Store %s error: %s, errorType: %s" % (self.req, self.errMsg, self.errType)
|
||||
)
|
||||
|
||||
#CONFIGURATOR_UA = "Configurator/2.0 (Macintosh; OS X 10.12.6; 16G29) AppleWebKit/2603.3.8"
|
||||
CONFIGURATOR_UA = 'Configurator/2.0 (Macintosh; OS X 10.12.6; 16G29) AppleWebKit/2603.3.8 iOS/14.2 hwp/t8020'
|
||||
|
||||
class StoreClientAuth(object):
|
||||
def __init__(self, appleId=None, password=None):
|
||||
self.appleId = appleId
|
||||
self.password = password
|
||||
self.guid = None # the guid will not be used in itunes server mode
|
||||
self.accountName = None
|
||||
self.authHeaders = None
|
||||
self.authCookies = None
|
||||
|
||||
def __str__(self):
|
||||
return f"<{self.accountName} [{self.guid}]>"
|
||||
|
||||
def _generateGuid(self, appleId):
|
||||
'''
|
||||
Derive a GUID for an appleId. For each appleId, the GUID will always remain the same
|
||||
:param appleId:
|
||||
:return:
|
||||
'''
|
||||
DEFAULT_GUID = '000C2941396B' # this GUID is blocked
|
||||
# number of chars to use from DEFAULT_GUID as prefix (0..12)
|
||||
GUID_DEFAULT_PREFIX = 2
|
||||
# something unique
|
||||
GUID_SEED = 'CAFEBABE'
|
||||
# something between 0 and 30
|
||||
GUID_POS = 10
|
||||
|
||||
# generate a unique guid out of the appleId
|
||||
h = hashlib.sha1((GUID_SEED + appleId + GUID_SEED).encode("utf-8")).hexdigest()
|
||||
defaultPart = DEFAULT_GUID[:GUID_DEFAULT_PREFIX]
|
||||
hashPart = h[GUID_POS: GUID_POS + (len(DEFAULT_GUID) - GUID_DEFAULT_PREFIX)]
|
||||
guid = (defaultPart + hashPart).upper()
|
||||
return guid
|
||||
|
||||
def login(self, sess):
|
||||
if not self.guid:
|
||||
self.guid = self._generateGuid(self.appleId)
|
||||
|
||||
req = StoreAuthenticateReq(appleId=self.appleId, password=self.password, attempt='4', createSession="true",
|
||||
guid=self.guid, rmp='0', why='signIn')
|
||||
url = "https://p46-buy.itunes.apple.com/WebObjects/MZFinance.woa/wa/authenticate?guid=%s" % self.guid
|
||||
while True:
|
||||
r = sess.post(url,
|
||||
headers={
|
||||
"Accept": "*/*",
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
"User-Agent": CONFIGURATOR_UA,
|
||||
}, data=plistlib.dumps(req.as_dict()), allow_redirects=False)
|
||||
if r.status_code == 302:
|
||||
url = r.headers['Location']
|
||||
continue
|
||||
break
|
||||
d = plistlib.loads(r.content)
|
||||
resp = StoreAuthenticateResp.from_dict(d)
|
||||
if not resp.m_allowed:
|
||||
raise StoreException("authenticate", d, resp.customerMessage, resp.failureType)
|
||||
|
||||
self.authHeaders = {}
|
||||
self.authHeaders['X-Dsid'] = self.authHeaders['iCloud-Dsid'] = str(resp.download_queue_info.dsid)
|
||||
self.authHeaders['X-Apple-Store-Front'] = r.headers.get('x-set-apple-store-front')
|
||||
self.authHeaders['X-Token'] = resp.passwordToken
|
||||
self.authCookies = pickle.dumps(sess.cookies).hex()
|
||||
|
||||
self.accountName = resp.accountInfo.address.firstName + " " + resp.accountInfo.address.lastName
|
||||
def save(self):
|
||||
return json.dumps(self.__dict__)
|
||||
|
||||
@classmethod
|
||||
def load(cls, j):
|
||||
obj = json.loads(j)
|
||||
ret = cls()
|
||||
ret.__dict__.update(obj)
|
||||
return ret
|
||||
|
||||
class StoreClient(object):
|
||||
def __init__(self, sess: requests.Session):
|
||||
self.sess = sess
|
||||
self.iTunes_provider = None
|
||||
self.authInfo = None
|
||||
|
||||
def authenticate_load_session(self, sessionContent):
|
||||
self.authInfo = StoreClientAuth.load(sessionContent)
|
||||
if self.authInfo.authHeaders is None or self.authInfo.authCookies is None:
|
||||
raise Exception("invalid auth session")
|
||||
self.sess.headers = dict(self.authInfo.authHeaders)
|
||||
self.sess.cookies = pickle.loads(bytes.fromhex(self.authInfo.authCookies))
|
||||
|
||||
def authenticate_save_session(self):
|
||||
return self.authInfo.save()
|
||||
|
||||
def authenticate(self, appleId, password):
|
||||
if not self.authInfo:
|
||||
self.authInfo = StoreClientAuth(appleId, password)
|
||||
self.authInfo.login(self.sess)
|
||||
self.sess.headers = dict(self.authInfo.authHeaders)
|
||||
self.sess.cookies = pickle.loads(bytes.fromhex(self.authInfo.authCookies))
|
||||
|
||||
# ==> 🛠 [Verbose] Performing request: curl -k -X POST \
|
||||
# -H "iCloud-DSID: 12263680861" \
|
||||
# -H "Content-Type: application/x-www-form-urlencoded" \
|
||||
# -H "User-Agent: Configurator/2.0 (Macintosh; OS X 10.12.6; 16G29) AppleWebKit/2603.3.8" \
|
||||
# -H "X-Dsid: 12263680861" \
|
||||
# -d '<?xml version="1.0" encoding="UTF-8"?>
|
||||
# <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
# <plist version="1.0">
|
||||
# <dict>
|
||||
# <key>creditDisplay</key>
|
||||
# <string></string>
|
||||
# <key>guid</key>
|
||||
# <string>000C2941396B</string>
|
||||
# <key>salableAdamId</key>
|
||||
# <string>1239860606</string>
|
||||
# </dict>
|
||||
# </plist>
|
||||
# ' \
|
||||
# https://p25-buy.itunes.apple.com/WebObjects/MZFinance.woa/wa/volumeStoreDownloadProduct?guid=000C2941396Bk
|
||||
def volumeStoreDownloadProduct(self, appId, appVerId=""):
|
||||
req = StoreDownloadReq(creditDisplay="", guid=self.authInfo.guid, salableAdamId=appId, appExtVrsId=appVerId)
|
||||
hdrs = {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
"User-Agent": CONFIGURATOR_UA,
|
||||
}
|
||||
url = "https://p25-buy.itunes.apple.com/WebObjects/MZFinance.woa/wa/volumeStoreDownloadProduct?guid=%s" % self.authInfo.guid
|
||||
payload = req.as_dict()
|
||||
r = self.sess.post(url,
|
||||
headers=hdrs,
|
||||
data=plistlib.dumps(payload))
|
||||
d = plistlib.loads(r.content)
|
||||
resp = StoreDownloadResp.from_dict(d)
|
||||
if resp.cancel_purchase_batch:
|
||||
raise StoreException("volumeStoreDownloadProduct", d, resp.customerMessage, '%s-%s' % (resp.failureType, resp.metrics))
|
||||
return resp
|
||||
|
||||
def buyProduct(self, appId, appVer='', productType='C', pricingParameters='STDQ'):
|
||||
# STDQ - buy, STDRDL - redownload, SWUPD - update
|
||||
url = "https://p25-buy.itunes.apple.com/WebObjects/MZBuy.woa/wa/buyProduct"
|
||||
|
||||
itunes_internal = self.iTunes_provider(url)
|
||||
hdrs = itunes_internal.pop('headers')
|
||||
guid = itunes_internal.pop('guid')
|
||||
kbsync = itunes_internal.pop('kbsync')
|
||||
|
||||
if not appVer:
|
||||
from reqs.itunes import iTunesClient
|
||||
iTunes = iTunesClient(self.sess)
|
||||
appVer = iTunes.getAppVerId(appId, hdrs['X-Apple-Store-Front'])
|
||||
|
||||
req = StoreBuyproductReq(
|
||||
guid=guid,
|
||||
salableAdamId=str(appId),
|
||||
appExtVrsId=str(appVer) if appVer else None,
|
||||
|
||||
price='0',
|
||||
productType=productType,
|
||||
pricingParameters=pricingParameters,
|
||||
|
||||
ageCheck='true',
|
||||
hasBeenAuthedForBuy='true',
|
||||
isInApp='false',
|
||||
hasConfirmedPaymentSheet='true',
|
||||
asn='1',
|
||||
)
|
||||
payload = req.as_dict()
|
||||
payload['kbsync'] = kbsync # kbsync is bytes, but json schema does not support it, so we have to assign it
|
||||
if 'sbsync' in itunes_internal:
|
||||
payload['sbsync'] = itunes_internal.pop('sbsync') # sbsync is the same as kbsync
|
||||
if 'afds' in itunes_internal:
|
||||
payload['afds'] = itunes_internal.pop('afds')
|
||||
|
||||
hdrs = dict(hdrs)
|
||||
hdrs["Content-Type"] = "application/x-apple-plist"
|
||||
|
||||
r = self.sess.post(url,
|
||||
headers=hdrs,
|
||||
data=plistlib.dumps(payload)
|
||||
)
|
||||
|
||||
d = plistlib.loads(r.content)
|
||||
resp = StoreBuyproductResp.from_dict(d)
|
||||
if resp.cancel_purchase_batch:
|
||||
raise StoreException("buyProduct", d, resp.customerMessage, '%s-%s' % (resp.failureType, resp.metrics))
|
||||
return resp
|
||||
|
||||
def buyProduct_purchase(self, appId, productType='C'):
|
||||
url = "https://buy.itunes.apple.com/WebObjects/MZBuy.woa/wa/buyProduct"
|
||||
req = StoreBuyproductReq(
|
||||
guid=self.authInfo.guid,
|
||||
salableAdamId=str(appId),
|
||||
appExtVrsId='0',
|
||||
|
||||
price='0',
|
||||
productType=productType,
|
||||
pricingParameters='STDQ',
|
||||
|
||||
hasAskedToFulfillPreorder='true',
|
||||
buyWithoutAuthorization='true',
|
||||
hasDoneAgeCheck='true',
|
||||
hasConfirmedPaymentSheet='true',
|
||||
)
|
||||
payload = req.as_dict()
|
||||
|
||||
r = self.sess.post(url,
|
||||
headers={
|
||||
"Content-Type": "application/x-apple-plist",
|
||||
"User-Agent": "Configurator/2.15 (Macintosh; OS X 11.0.0; 16G29) AppleWebKit/2603.3.8",
|
||||
},
|
||||
data=plistlib.dumps(payload))
|
||||
|
||||
if r.status_code == 500:
|
||||
raise StoreException("buyProduct_purchase", None, 'purchased_before')
|
||||
|
||||
d = plistlib.loads(r.content)
|
||||
resp = StoreBuyproductResp.from_dict(d)
|
||||
if resp.status != 0 or resp.jingleDocType != 'purchaseSuccess':
|
||||
raise StoreException("buyProduct_purchase", d, resp.customerMessage,
|
||||
'%s-%s' % (resp.status, resp.jingleDocType))
|
||||
return resp
|
||||
|
||||
def purchase(self, appId):
|
||||
if self.iTunes_provider:
|
||||
return None # iTunes mode will automatically purchase the app if not purchased
|
||||
else:
|
||||
return self.buyProduct_purchase(appId)
|
||||
|
||||
def download(self, appId, appVer='', isRedownload=True):
|
||||
if self.iTunes_provider:
|
||||
return self.buyProduct(appId, appVer, pricingParameters='STDRDL' if isRedownload else 'STDQ')
|
||||
else:
|
||||
return self.volumeStoreDownloadProduct(appId, appVer)
|
||||
2
src_mac/ipatool-py/requirements.txt
Executable file
2
src_mac/ipatool-py/requirements.txt
Executable file
@@ -0,0 +1,2 @@
|
||||
rich>=10.2.2
|
||||
requests>=2.25.0
|
||||
Reference in New Issue
Block a user