MagiskOnWSALocal/scripts/generateWSALinks.py

172 lines
6.7 KiB
Python
Raw Normal View History

#!/usr/bin/python3
2022-08-26 00:20:49 +08:00
#
# This file is part of MagiskOnWSALocal.
#
# MagiskOnWSALocal is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# MagiskOnWSALocal is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with MagiskOnWSALocal. If not, see <https://www.gnu.org/licenses/>.
#
2023-01-11 17:05:56 +08:00
# Copyright (C) 2023 LSPosed Contributors
#
import html
2023-03-26 20:31:44 +08:00
import logging
import os
import re
import sys
2023-03-24 22:53:48 +08:00
from pathlib import Path
from threading import Thread
from typing import OrderedDict
from xml.dom import minidom
from requests import Session
class Prop(OrderedDict):
2023-03-26 20:31:44 +08:00
def __init__(self, props: str = ...) -> None:
super().__init__()
for i, line in enumerate(props.splitlines(False)):
if '=' in line:
2022-12-18 19:56:34 +08:00
k, v = line.split('=', 1)
self[k] = v
else:
self[f".{i}"] = line
def get(self, key: str) -> str:
return self[key]
2023-04-11 05:06:10 +08:00
2023-03-26 20:31:44 +08:00
logging.captureWarnings(True)
arch = sys.argv[1]
2022-08-30 23:47:09 +08:00
release_name_map = {"retail": "Retail", "RP": "Release Preview",
"WIS": "Insider Slow", "WIF": "Insider Fast"}
release_type = sys.argv[2] if sys.argv[2] != "" else "Retail"
release_name = release_name_map[release_type]
2023-03-26 20:31:44 +08:00
download_dir = Path.cwd().parent / \
"download" if sys.argv[3] == "" else Path(sys.argv[3])
ms_account_conf = download_dir/".ms_account"
tempScript = sys.argv[4]
cat_id = '858014f3-3934-4abe-8078-4aa193e74ca8'
user = ''
session = Session()
2023-03-26 20:31:44 +08:00
session.verify = False
if ms_account_conf.is_file():
with open(ms_account_conf, "r") as f:
conf = Prop(f.read())
user = conf.get('user_code')
print(f"Generating WSA download link: arch={arch} release_type={release_name}\n", flush=True)
with open(Path.cwd().parent / ("xml/GetCookie.xml"), "r") as f:
cookie_content = f.read().format(user)
out = session.post(
'https://fe3.delivery.mp.microsoft.com/ClientWebService/client.asmx',
data=cookie_content,
2023-03-26 20:31:44 +08:00
headers={'Content-Type': 'application/soap+xml; charset=utf-8'}
)
doc = minidom.parseString(out.text)
cookie = doc.getElementsByTagName('EncryptedData')[0].firstChild.nodeValue
with open(Path.cwd().parent / "xml/WUIDRequest.xml", "r") as f:
cat_id_content = f.read().format(user, cookie, cat_id, release_type)
out = session.post(
'https://fe3.delivery.mp.microsoft.com/ClientWebService/client.asmx',
data=cat_id_content,
2023-03-26 20:31:44 +08:00
headers={'Content-Type': 'application/soap+xml; charset=utf-8'}
)
doc = minidom.parseString(html.unescape(out.text))
filenames = {}
for node in doc.getElementsByTagName('ExtendedUpdateInfo')[0].getElementsByTagName('Updates')[0].getElementsByTagName('Update'):
node_xml = node.getElementsByTagName('Xml')[0]
node_files = node_xml.getElementsByTagName('Files')
if not node_files:
continue
else:
for node_file in node_files[0].getElementsByTagName('File'):
if node_file.hasAttribute('InstallerSpecificIdentifier') and node_file.hasAttribute('FileName'):
filenames[node.getElementsByTagName('ID')[0].firstChild.nodeValue] = (f"{node_file.attributes['InstallerSpecificIdentifier'].value}_{node_file.attributes['FileName'].value}",
2023-04-11 05:06:10 +08:00
node_xml.getElementsByTagName('ExtendedProperties')[0].attributes['PackageIdentityName'].value)
identities = {}
for node in doc.getElementsByTagName('NewUpdates')[0].getElementsByTagName('UpdateInfo'):
node_xml = node.getElementsByTagName('Xml')[0]
if not node_xml.getElementsByTagName('SecuredFragment'):
continue
else:
2023-04-11 05:06:10 +08:00
id = node.getElementsByTagName('ID')[0].firstChild.nodeValue
update_identity = node_xml.getElementsByTagName('UpdateIdentity')[0]
if id in filenames:
fileinfo = filenames[id]
if fileinfo[0] not in identities:
identities[fileinfo[0]] = ([update_identity.attributes['UpdateID'].value,
update_identity.attributes['RevisionNumber'].value], fileinfo[1])
with open(Path.cwd().parent / "xml/FE3FileUrl.xml", "r") as f:
FE3_file_content = f.read()
2022-09-17 21:15:44 +08:00
if not download_dir.is_dir():
download_dir.mkdir()
2023-03-26 20:31:44 +08:00
tmpdownlist = open(download_dir/tempScript, 'a')
2023-04-11 05:06:10 +08:00
2023-03-26 20:31:44 +08:00
def send_req(i, v, out_file, out_file_name):
out = session.post(
'https://fe3.delivery.mp.microsoft.com/ClientWebService/client.asmx/secured',
data=FE3_file_content.format(user, i, v, release_type),
2023-03-26 20:31:44 +08:00
headers={'Content-Type': 'application/soap+xml; charset=utf-8'}
)
doc = minidom.parseString(out.text)
for l in doc.getElementsByTagName("FileLocation"):
url = l.getElementsByTagName("Url")[0].firstChild.nodeValue
if len(url) != 99:
print(f"download link: {url}\npath: {out_file}\n", flush=True)
tmpdownlist.writelines(url + '\n')
tmpdownlist.writelines(f' dir={download_dir}\n')
tmpdownlist.writelines(f' out={out_file_name}\n')
2023-03-26 20:31:44 +08:00
2023-04-11 05:06:10 +08:00
threads = []
for filename, values in identities.items():
if re.match(f"Microsoft\.UI\.Xaml\..*_{arch}_.*\.appx", filename):
out_file_name = f"{values[1]}_{arch}.appx"
out_file = download_dir / out_file_name
elif re.match(f"Microsoft\.VCLibs\..+\.UWPDesktop_.*_{arch}_.*\.appx", filename):
out_file_name = f"{values[1]}_{arch}.appx"
out_file = download_dir / out_file_name
elif re.match(f"Microsoft\.VCLibs\..+_.*_{arch}_.*\.appx", filename):
out_file_name = f"{values[1]}_{arch}.appx"
out_file = download_dir / out_file_name
elif re.match(f"MicrosoftCorporationII\.WindowsSubsystemForAndroid_.*\.msixbundle", filename):
wsa_long_ver = re.search(u'\d{4}.\d{5}.\d{1,}.\d{1,}', filename).group()
print(f'WSA Version={wsa_long_ver}\n', flush=True)
main_ver = wsa_long_ver.split(".")[0]
with open(os.environ['WSA_WORK_ENV'], 'a') as environ_file:
environ_file.write(f"DOWN_WSA_VERSION={wsa_long_ver}\n")
environ_file.write(f"DOWN_WSA_MAIN_VERSION={main_ver}\n")
out_file_name = f"wsa-{release_type}.zip"
out_file = download_dir / out_file_name
else:
continue
th = Thread(target=send_req, args=(values[0][0], values[0][1], out_file, out_file_name))
threads.append(th)
th.daemon = True
th.start()
for th in threads:
th.join()
tmpdownlist.close()