MagiskOnWSALocal/scripts/generateWSALinks.py

193 lines
7.4 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 Any, OrderedDict
from xml.dom import minidom
from requests import Session
from packaging import version
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 __setattr__(self, __name: str, __value: Any) -> None:
self[__name] = __value
def __repr__(self):
return '\n'.join(f'{item}={self[item]}' for item in self)
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')
download_files = {}
2023-04-11 05:06:10 +08:00
def send_req(i, v, 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:
download_files[out_file_name] = url
2023-03-26 20:31:44 +08:00
2023-04-11 05:06:10 +08:00
threads = []
wsa_build_ver = 0
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):
tmp_wsa_build_ver = re.search(u'\d{4}.\d{5}.\d{1,}.\d{1,}', filename).group()
if(wsa_build_ver == 0):
wsa_build_ver = tmp_wsa_build_ver
else:
if version.parse(wsa_build_ver) < version.parse(tmp_wsa_build_ver):
wsa_build_ver = tmp_wsa_build_ver
else:
continue
version_splited = wsa_build_ver.split(".")
major_ver = version_splited[0]
minor_ver = version_splited[1]
build_ver = version_splited[2]
revision_ver = version_splited[3]
with open(os.environ['WSA_WORK_ENV'], 'r') as environ_file:
env = Prop(environ_file.read())
env.WSA_VER = wsa_build_ver
env.WSA_MAJOR_VER = major_ver
with open(os.environ['WSA_WORK_ENV'], 'w') as environ_file:
environ_file.write(str(env))
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_name))
threads.append(th)
th.daemon = True
th.start()
for th in threads:
th.join()
print(f'WSA Build Version={wsa_build_ver}\n', flush=True)
for key, value in download_files.items():
print(f"download link: {value}\npath: {download_dir / key}\n", flush=True)
tmpdownlist.writelines(value + '\n')
tmpdownlist.writelines(f' dir={download_dir}\n')
tmpdownlist.writelines(f' out={key}\n')
tmpdownlist.close()