tis-examshield-uwp
6.7.94.0-55
ExamShield est le navigateur sécurisé de PeopleCert, permettant aux candidats inscrits de passer leur examen PeopleCert surveillé en ligne
216 téléchargements
Voir le résultat de la construction Voir l'analyse de VirusTotal
Description
- package : tis-examshield-uwp
- name : ExamShield UWP
- version : 6.7.94.0-55
- categories : Education
- maintainer : WAPT Team,Tranquil IT,Jimmy PELÉ,Clément BAZIRET
- installed_size : 35585030
- editor : PeopleCert
- licence : proprietary_free,wapt_public
- signature_date : 2024-09-25T14:02:46.000000
- size : 83.55 Mo
- locale : all
- target_os : windows
- impacted_process : ExamShield
- architecture : all
- Page d'accueil : https://apps.microsoft.com/store/detail/9PP51VN0TM7H
control
package : tis-examshield-uwp
version : 6.7.94.0-55
architecture : all
section : base
priority : optional
name : ExamShield UWP
categories : Education
maintainer : WAPT Team,Tranquil IT,Jimmy PELÉ,Clément BAZIRET
description : ExamShield is PeopleCert's secure lockdown browser, allowing registered Candidates to take their PeopleCert online proctored exam
depends :
conflicts :
maturity : PROD
locale : all
target_os : windows
min_wapt_version : 2.3
sources : https://apps.microsoft.com/store/detail/9PP51VN0TM7H
installed_size : 35585030
impacted_process : ExamShield
description_fr : ExamShield est le navigateur sécurisé de PeopleCert, permettant aux candidats inscrits de passer leur examen PeopleCert surveillé en ligne
description_pl : ExamShield to bezpieczna przeglądarka PeopleCert, umożliwiająca zarejestrowanym kandydatom zdawanie egzaminów online pod nadzorem PeopleCert
description_de : ExamShield ist der sichere Browser von PeopleCert, mit dem registrierte Kandidaten ihre PeopleCert-Prüfung online ablegen können
description_es : ExamShield es el navegador de bloqueo seguro de PeopleCert, que permite a los candidatos registrados realizar su examen proctored en línea de PeopleCert
description_pt : O ExamShield é o navegador de bloqueio seguro da PeopleCert, que permite aos candidatos registados realizar o seu exame PeopleCert online supervisionado
description_it : ExamShield è il browser di blocco sicuro di PeopleCert, che consente ai candidati registrati di sostenere l'esame PeopleCert online con la supervisione di un medico
description_nl : ExamShield is PeopleCert's veilige lockdown browser, die geregistreerde kandidaten in staat stelt om hun PeopleCert online gesurveilleerde examen af te leggen
description_ru : ExamShield - это безопасный браузер PeopleCert, позволяющий зарегистрированным кандидатам сдавать прокетированные экзамены PeopleCert в режиме онлайн
audit_schedule :
editor : PeopleCert
keywords : examshield,peoplecert,secure,lockdown,browser,registered,candidates,online,proctored,exam
licence : proprietary_free,wapt_public
homepage : https://apps.microsoft.com/store/detail/9PP51VN0TM7H
package_uuid : 6163cbed-d875-4fd5-8c72-928984650a73
valid_from :
valid_until :
forced_install_on :
changelog :
min_os_version : 10.0.17763
max_os_version :
icon_sha256sum : c964594c0a3b13b1b9274511d769d52a896a970452be1f2593d41745d791010c
signer : Tranquil IT
signer_fingerprint: 8c5127a75392be9cc9afd0dbae1222a673072c308c14d88ab246e23832e8c6bb
signature_date : 2024-09-25T14:02:46.000000
signed_attributes : package,version,architecture,section,priority,name,categories,maintainer,description,depends,conflicts,maturity,locale,target_os,min_wapt_version,sources,installed_size,impacted_process,description_fr,description_pl,description_de,description_es,description_pt,description_it,description_nl,description_ru,audit_schedule,editor,keywords,licence,homepage,package_uuid,valid_from,valid_until,forced_install_on,changelog,min_os_version,max_os_version,icon_sha256sum,signer,signer_fingerprint,signature_date,signed_attributes
signature : yYDEsM/GtjxeIUVok/sLjPu6wsW47fz0+v6jTQaO0cB1YpylzF7R/jC0AHjVjHM4sbFa44E6Dc1j9CCIe/RRcu7gXzFEYD3oZwH3TUwViutqbc3FD41kFLEobciu5P5hrEXKSXR5JygoX8k4SOgvu+JvxN51ifPC85zih2qjIcUNykJegP376Vcvk5RkJYitOQLPil4y1RyI64cNNkN5b8w1wnEhiGvKNTwTXJ2O5xRrTnqitDYlKguqeoHtnpuWCvsZf/hAx3ngXIQhqbiUUdbUcCInQSx0L5fAaNs4daC4OuaxYNlVZLx93JV1TPfNjJnljSDuJ6QZ158OIPZG3Q==
Setup.py
# -*- coding: utf-8 -*-
from setuphelpers import *
appx_package_name = "PeoplecertInternationalLt.ExamShield"
appx_dir = makepath(programfiles, "WindowsAppsInstallers")
def install():
# Declare local variables
bins_dir = control.package.split("-", 1)[1]
old_appx_bins_dir = makepath(appx_dir, bins_dir)
appx_bins_dir = makepath(os.getcwd(), bins_dir)
# Removing sources because they are no longer needed
if isdir(old_appx_bins_dir):
print("Removing: %s" % (old_appx_bins_dir))
remove_tree(old_appx_bins_dir)
if dir_is_empty(appx_dir):
print("Removing: %s since it is empty" % (appx_dir))
remove_tree(appx_dir)
# Removing binaries of different architectures
for f in glob.glob(appx_bins_dir + "/*"):
fname = f.split(os.sep)[-1]
if control.architecture == "all":
if "x86" in glob.glob(makepath(appx_bins_dir, f"{appx_package_name}_*"))[0].split(os.sep)[-1]:
if not "x86" in fname and not "neutral" in fname:
remove_file(f)
else:
if not get_host_architecture() in fname and not "neutral" in fname:
remove_file(f)
else:
if not get_host_architecture() in fname and not "neutral" in fname:
remove_file(f)
bin_path = glob.glob(makepath(appx_bins_dir, f"{appx_package_name}_*"))[0]
dependencies_pathes = ",".join([f'"{a}"' for a in glob.glob(makepath(appx_bins_dir, "*")) if not appx_package_name in a])
# Installing Appx if needed
add_appx_cmd = f'Add-AppxProvisionedPackage -Online -PackagePath "{bin_path}" -SkipLicense'
if dependencies_pathes:
add_appx_cmd += f" -DependencyPackagePath {dependencies_pathes}"
appxprovisionedpackage = run_powershell(f'Get-AppXProvisionedPackage -Online | Where-Object DisplayName -Like "{appx_package_name}"')
if appxprovisionedpackage is None:
appxprovisionedpackage = {"Version": "0"}
if Version(appxprovisionedpackage["Version"], 4) < Version(control.get_software_version(), 4) or force:
print(f"Installing: {bin_path.split(os.sep)[-1]}")
run_powershell(add_appx_cmd)
else:
print(f'{appxprovisionedpackage["PackageName"]} is already installed and up-to-date.')
def uninstall():
# Declare local variables
bins_dir = control.package.split("-", 1)[1]
appx_bins_dir = makepath(appx_dir, bins_dir)
print(f"Removing AppX: {appx_package_name}")
remove_appx(appx_package_name)
def audit():
# Declaring local variables
audit_result = "OK"
audit_version = True
appxprovisionedpackage = run_powershell(f'Get-AppXProvisionedPackage -Online | Where-Object DisplayName -Like "{appx_package_name}"')
# Auditing software
if appxprovisionedpackage is None:
print(f"{appx_package_name} is not installed.")
audit_result = "ERROR"
elif audit_version:
if Version(appxprovisionedpackage.get("Version", "0"), 4) < Version(control.get_software_version(), 4):
print(
f'{appxprovisionedpackage["PackageName"]} is installed in version: {appxprovisionedpackage["Version"]} instead of: {control.get_software_version()}.'
)
audit_result = "WARNING"
else:
print(f'{appxprovisionedpackage["PackageName"]} is installed and up-to-date.')
else:
print(f'{appxprovisionedpackage["PackageName"]} is installed.')
return audit_result
def remove_appx(package, default_user=True):
"""Remove Windows AppX package from the computer environment, excluding NonRemovable packages.
Args:
package (str): AppX package name. You can use an asterisk (*) as a wildcard.
default_user (bool): Remove AppX package from the Windows image to prevent installation for new users.
.. versionadded:: 2.2
.. versionchanged:: 2.5
No longer try to remove NonRemovable AppX package
"""
if running_as_admin() or running_as_system():
if default_user:
run_powershell(
f'Get-AppXProvisionedPackage -Online | Where-Object DisplayName -Like "{package}" | Remove-AppxProvisionedPackage -Online -AllUsers'
)
run_powershell(f'Get-AppxPackage "{package}" -AllUsers | Where-Object {{ -not ($_.NonRemovable) }} | Remove-AppxPackage -AllUsers')
else:
run_powershell(f'Get-AppxPackage "{package}" | Where-Object {{ -not ($_.NonRemovable) }} | Remove-AppxPackage')
update_package.py
# -*- coding: utf-8 -*-
from setuphelpers import *
import requests
import re
import json
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
from setupdevhelpers import *
def update_package():
# Declaring local variables
package_updated = False
proxies = get_proxies()
if not proxies:
proxies = get_proxies_from_wapt_console()
microsoft_store_url = control.sources
if not microsoft_store_url:
store_id = ask_input(
control.package,
"Enter the application ProductId or the link from the Microsoft Store (web address: https://apps.microsoft.com/store/apps)",
microsoft_store_url,
raise_error=True,
).split("/")[-1]
else:
store_id = microsoft_store_url.split("/")[-1]
store_id = store_id.split("?")[0].split("#")[0]
if store_id:
microsoft_store_url = "https://apps.microsoft.com/store/detail/%s" % store_id
control.sources = microsoft_store_url
control.save_control_to_wapt()
package_prefix = control.package.split("-")[0]
selected = None
# check setup.py incase the package name does not match the installer file
appx_package_name = ""
with open("setup.py", "r", encoding="utf8") as f:
for line in f.readlines():
if line.startswith("appx_package_name"):
appx_package_name = line.split("=")[1].split('"')[1]
break
old_appx_package_name = appx_package_name
# Getting info from adguard api
res = requests.post(
"https://store.rg-adguard.net/api/GetFiles",
"type=ProductId&url=%s&ring=RP&lang=fr-FR" % store_id,
headers={"content-type": "application/x-www-form-urlencoded"},
proxies=proxies,
)
all_files = []
for bs_search in bs_find_all(res.text, "a"):
if not "BlockMap" in bs_search.text and not "eappxbundle" in bs_search.text and not "emsixbundle" in bs_search.text:
# bin_name = bs_search.text.replace("~", "_")
bin_name = str(bs_search.text)
if not get_file_extension(bin_name):
continue
version = bin_name.split("_")[1]
download_url = bs_search["href"]
pkg_splitted = re.split(r"_\d+\.", bin_name)[0]
package_name = package_prefix + "-" + pkg_splitted.split("_")[0].replace(".", "-").lower()
software_name = bin_name.split("_")[0].replace("-", " ").replace(".", " ")
package_arch = get_uwp_filename_arch(bin_name, appx_package_name)
file_dict = {
"version": version,
"bin_name": bin_name,
"package_name": package_name,
"software_name": software_name,
"package_arch": package_arch,
"download_url": download_url,
}
all_files.append(file_dict)
if (
"template-microsoft-store" in control.package
or not appx_package_name
or not len([a for a in all_files if appx_package_name in a["bin_name"]]) != 0
):
if not all_files:
error(f"API returned an empty list for URL: {microsoft_store_url}, please try again")
selected = ask_grid(
"Please select the App version that you want to package",
all_files,
"GRT_SELECTED",
'{"columns":[{"propertyname":"version","datatype":"String","required":false,"readonly":false,"width":130},{"propertyname":"bin_name","datatype":"String","required":false,"readonly":false,"width":420},{"propertyname":"package_name","datatype":"String","required":false,"readonly":false,"width":190},{"propertyname":"software_name","datatype":"String","required":false,"readonly":false,"width":172},{"propertyname":"package_arch","datatype":"String","required":false,"readonly":false,"width":88},{"propertyname":"download_url","datatype":"String","required":false,"readonly":false,"width":1472}]}',
)
appx_package_name = selected[0]["bin_name"].split("_")[0]
# Avoiding downloads loop and avoid keeping sources of other apps
bins_dir = control.package.split("-", 1)[1]
for dir_name in glob.glob("**/"):
dir_name = dir_name.split(os.sep)[0]
if dir_name in ["WAPT", "__pycache__"]:
continue
if dir_name == bins_dir:
for f in (
glob.glob(f"{dir_name}/*.appxbundle")
+ glob.glob(f"{dir_name}/*.msixbundle")
+ glob.glob(f"{dir_name}/*.appx")
+ glob.glob(f"{dir_name}/*.msix")
):
shutil.move(f, ".")
else:
remove_tree(dir_name)
if isfile("package.json"):
remove_file("package.json")
# Updating package.json ignored_versions list
if isfile("package.json"):
package_json = json_load_file("package.json")
else:
package_json = {"version_prefix": None, "ignored_versions": []}
if selected:
ignored_versions = list(
set(
package_json["ignored_versions"]
+ [v["version"] for v in all_files if appx_package_name in v["bin_name"] and v["version"] != selected[0]["version"]]
)
)
ignored_versions.sort()
package_json["ignored_versions"] = ignored_versions
json_write_file("package.json", package_json)
else:
ignored_versions = package_json["ignored_versions"]
version_prefix = package_json.get("version_prefix", None)
# Downloading app files
download_app_files(all_files, appx_package_name, proxies=proxies, ignored_versions=ignored_versions, version_prefix=version_prefix)
# # Import xmltodict for make_uwp_app_dict()
# if not isfile("xmltodict.py"):
# pip_download_xmltodict = "waptpython -m pip download xmltodict -d %s" % basedir
# if proxies:
# pip_download_xmltodict += " --proxy %s" % proxies["http"]
# run(pip_download_xmltodict)
# unzip(glob.glob("*.whl")[0], ".", "xmltodict.py")
# remove_file(glob.glob("*.whl")[0])
# Keep app files
uwp_app_dict = make_uwp_app_dict(appx_package_name)
newer_uwp_app = get_newer_uwp_app(uwp_app_dict, tdf_list=None)
version = newer_uwp_app["Version"]
# Downloading dependency files
dependencies_to_download = []
if newer_uwp_app["Dependencies"]:
for dependency in newer_uwp_app["Dependencies"]:
dependencies_to_download.append(get_newer_uwp_depency(dependency, all_files, min_version=dependency["MinVersion"]))
if dependencies_to_download:
for dependency_file in all_files:
latest_bin = dependency_file["bin_name"]
if not True in [d in latest_bin for d in dependencies_to_download]: # ignore unecessary dependencies
continue
if not "all" in ensure_list(control.architecture):
if not get_uwp_filename_arch(latest_bin) in ensure_list(control.architecture) and not "neutral" in latest_bin:
if isfile(latest_bin):
remove_file(latest_bin)
continue
if latest_bin.split(".")[-1].lower().startswith("e"): # ignore encrypted uwp apps
continue
download_url = dependency_file["download_url"]
if download_url.split("/")[2].endswith("microsoft.com"):
if not isfile(latest_bin):
print("Downloading: %s" % latest_bin)
wget(download_url, latest_bin, proxies=proxies)
else:
print("Binary is present: %s" % latest_bin)
else:
error("ERROR: The retrieved URL will not download from microsoft's servers")
# No dependencies since it will be contained
control.depends = ""
control.save_control_to_wapt()
# Applying or asking control informations once
if not old_appx_package_name or old_appx_package_name != appx_package_name:
# control.impacted_process and control.installed_size
if "b4:Dependencies" in newer_uwp_app:
if newer_uwp_app["b4:Dependencies"]:
appx_file = sorted(newer_uwp_app["b4:Dependencies"], key=lambda arch: ["x64", "x86", "arm64", "arm"].index(arch.get("Architecture")))[
0
]["FileName"]
appx_dir = appx_file.rsplit(".", 1)[0]
unzip(newer_uwp_app["FileName"], ".", appx_file)
unzip(appx_file)
else:
appx_dir = newer_uwp_app["FileName"].rsplit(".", 1)[0]
unzip(newer_uwp_app["FileName"])
complete_control_impacted_process(control, appx_dir)
control.installed_size = get_size(appx_dir)
if isdir(appx_dir):
remove_tree(appx_dir)
# control.architecture
control.architecture = get_uwp_architectures(newer_uwp_app)
if "," in control.architecture:
complete_control_min_wapt_version(control, "2.4", True)
# control.min_os_version and control.max_os_version
set_control_os_version_uwp_app(newer_uwp_app)
# control.name
bs_name = bs_find(str(bs_find(microsoft_store_url, "head").contents), "meta", "property", "og:title")["content"]
control_name = bs_name.split("Get ")[-1].split(" from the Microsoft Store")[0]
control_name = complete_control_name(control, control_name)
# control.package
control_package = package_prefix + "-" + control_name.lower()
complete_control_package(control, control_package, params.get("running_as_luti"))
# control.description
control_description = bs_find(str(bs_find(microsoft_store_url + "?hl=en-us&gl=us", "head").contents), "meta", "property", "og:description")[
"content"
]
complete_control_description(control, control_description, params.get("running_as_luti"), "update_package", 250)
# control.description_fr = (
# bs_find(str(bs_find(microsoft_store_url + "?hl=fr-fr&gl=fr", "head").contents), "meta", "property", "og:description")["content"]
# .split(". ")[0]
# .replace("’", "'")
# )
# control.categories
complete_control_categories(control)
# Updating setup.py appx_package_name variable
new_lines = []
with open("setup.py", "r", encoding="utf8") as f:
for line in f.readlines():
if line.startswith("appx_package_name"):
line = 'appx_package_name = "%s"\n' % appx_package_name
new_lines.append(line)
with open("setup.py", "w", encoding="utf8", newline="\n") as f:
f.writelines(new_lines)
# Get icon.png
icon_png = []
if "b4:Dependencies" in newer_uwp_app:
if newer_uwp_app["b4:Dependencies"]:
temp_appx = unzip(newer_uwp_app["FileName"], ".", newer_uwp_app["b4:Dependencies"][0]["FileName"], False)
icon_png = unzip(newer_uwp_app["b4:Dependencies"][0]["FileName"], ".", "*.targetsize-48_altform-unplated.png", False)
if not icon_png:
icon_png = unzip(newer_uwp_app["b4:Dependencies"][0]["FileName"], ".", "*.targetsize-48.png", False)
if not icon_png:
icon_png = unzip(newer_uwp_app["b4:Dependencies"][0]["FileName"], ".", "**/PkgSmallLogo.png", False)
if icon_png:
shutil.move(icon_png[0], "WAPT\\icon.png")
for f in temp_appx:
if isfile(f):
remove_file(f)
if not icon_png:
icon_png = unzip(newer_uwp_app["FileName"], ".", "*.targetsize-48_altform-unplated.png", False)
if not icon_png:
icon_png = unzip(newer_uwp_app["FileName"], ".", "*.targetsize-48.png", False)
if icon_png:
shutil.move(icon_png[0], "WAPT\\icon.png")
[remove_file(a) for a in glob.glob("*.png")]
# Placing binaries in a dir ["appxbundle", "msixbundle", "appx", "msix]
for f in glob.glob("*.part"):
remove_file(f)
bins_dir = control.package.split("-", 1)[1]
if isdir(bins_dir):
remove_tree(bins_dir)
mkdirs(bins_dir)
for uwp_file in glob.glob(f'{newer_uwp_app["Name"]}*{newer_uwp_app["Version"]}*.*'):
if not isfile(makepath(bins_dir, uwp_file)):
shutil.move(uwp_file, bins_dir)
if uwp_app_dict[newer_uwp_app["FileName"]]["Dependencies"] is not None:
for l in [glob.glob(a["Name"] + "_*") for a in uwp_app_dict[newer_uwp_app["FileName"]]["Dependencies"]]:
for f in l:
if not isfile(makepath(bins_dir, f)):
shutil.move(f, bins_dir)
# Removing remaining files ["appxbundle", "msixbundle", "appx", "msix]
for f in glob.glob("*.appxbundle") + glob.glob("*.msixbundle") + glob.glob("*.appx") + glob.glob("*.msix"):
remove_file(f)
# Changing version of the package and validating update-package-sources
return complete_control_version(control, version)
def json_write_file(json_file, data, indent=4, sort_keys=False, encoding="utf-8", newline="\n"):
"""
Write dictionary to a JSON file.
Args:
json_file (str): Path to the JSON file.
data (dict): Dictionary content.
indent (int or str): Tabulation size for indentation; default: 4 spaces.
sort_keys (bool): Sort the keys alphabetically or not; default: False.
encoding (str): File encoding; default: 'utf-8'.
newline (str): Newline character(s) to use; default: 'LF'.
"""
with open(json_file, "w", encoding=encoding, newline=newline) as write_file:
json.dump(data, write_file, sort_keys=sort_keys, indent=indent)
def download_app_files(all_files, appx_package_name, proxies=None, ignored_versions=[], version_prefix=None):
for app_file in all_files:
latest_bin = app_file["bin_name"]
if not latest_bin.startswith(f"{appx_package_name}_"): # ignore other files
continue
if latest_bin.split(".")[-1].lower().startswith("e"): # ignore encrypted UWP apps
continue
if version_prefix is not None and not Version(app_file["version"], len(version_prefix.split("."))) == Version(
version_prefix, len(version_prefix.split("."))
):
continue
if any(
Version(app_file["version"], len(ignored_version.split("."))) == Version(ignored_version, len(ignored_version.split(".")))
for ignored_version in ignored_versions
):
continue
download_url = app_file["download_url"]
if download_url.split("/")[2].endswith("microsoft.com"):
if not isfile(latest_bin):
print("Downloading: %s" % latest_bin)
wget(download_url, latest_bin, proxies=proxies)
else:
print("Binary is present: %s" % latest_bin)
else:
error("ERROR: The retrieved URL will not download from Microsoft's servers")
def get_uwp_architectures(newer_uwp_app):
"""
Returns a comma-separated string of compatible architectures extracted from the 'control.architecture'
within the provided 'newer_uwp_app' dictionary.
Args:
newer_uwp_app (dict): A dictionary representing a Universal Windows Platform (UWP) app.
Returns:
str: A comma-separated string of compatible architectures (e.g., "x64,arm64,x86,arm"). If no
compatible architectures are found, it returns "all".
"""
architecture_list = []
desired_order = ["x64", "x86", "arm64", "arm"]
if newer_uwp_app.get("b4:Dependencies", None):
for before_dependency in newer_uwp_app.get("b4:Dependencies"):
architecture_list.append(before_dependency["Architecture"])
sorted_architecture_list = sorted(architecture_list, key=lambda arch: desired_order.index(arch))
if sorted_architecture_list == ensure_list("x64,x86,arm64"):
sorted_architecture_list = ["all"]
return ",".join(sorted_architecture_list)
else:
return get_uwp_filename_arch(newer_uwp_app["FileName"], newer_uwp_app["Name"])
def get_uwp_filename_arch(appx_filename, appx_package_name=None):
"""
Returns the architecture of a Universal Windows Platform (UWP) app based on the provided 'appx_filename'
and optionally, the 'appx_package_name'.
Args:
appx_filename (str): The filename of the UWP app package.
appx_package_name (str, optional): The package name of the UWP app. Defaults to None.
Returns:
str: The architecture of the UWP app, which can be "x64", "arm64", "x86", or "all" (if no specific
architecture is detected).
"""
if not appx_package_name:
appx_package_name = None
if len(glob.glob(f'{appx_package_name}*{appx_filename.split("_")[1]}*')) > 1:
pass
elif "arm64" in appx_filename:
return "arm64"
elif "arm" in appx_filename:
return "arm"
elif "x64" in appx_filename:
return "x64"
if appx_filename is not None and "x86" in appx_filename and (appx_package_name is None or not appx_package_name in appx_filename):
return "x86"
return "all"
def get_newer_uwp_app(uwp_app_dict, version_prefix=None, min_version=None, max_version=None, tdf_list=["Windows.Universal", "Windows.Desktop"]):
"""Get the newer Universal Windows Platform (UWP) app from a dictionary of UWP apps based on specified criteria.
Args:
uwp_app_dict (dict): A dictionary containing UWP app information with app IDs as keys and app details as values.
version_prefix (str, optional): The prefix of the version number to filter the apps. Defaults to None.
min_version (str, optional): The minimum version of the UWP app. Defaults to None.
max_version (str, optional): The maximum version of the UWP app. Defaults to None.
tdf_list (list, optional): A list of target device families to filter the apps. Defaults to ["Windows.Universal", "Windows.Desktop"].
Returns:
dict or None: The dictionary containing the details of the newer UWP app that matches the specified criteria, or None if no app is found.
"""
newer_version = "0"
for uwp_app in uwp_app_dict.values():
to_skip = True
if version_prefix is not None and Version(uwp_app["Version"], len(version_prefix.split("."))) != Version(
version_prefix, len(version_prefix.split("."))
):
continue
if tdf_list is not None and uwp_app["TargetDeviceFamily"] is not None:
if not uwp_app["TargetDeviceFamily"]:
continue
for tdf in tdf_list:
for uwp_app_tdf in uwp_app["TargetDeviceFamily"]:
if (
tdf == uwp_app_tdf["Name"]
and (min_version is None or Version(min_version, 3) == Version(uwp_app_tdf["MinVersion"], 3))
and (max_version is None or Version(max_version, 3) == Version(uwp_app_tdf["MaxVersionTested"], 3))
):
to_skip = False
else:
to_skip = False
if to_skip:
continue
if control.max_os_version:
if not Version(uwp_app["MinVersion"], 3) < Version(control.max_os_version, 3):
continue
if Version(newer_version) < Version(uwp_app["Version"]):
newer_uwp_app = uwp_app
newer_version = newer_uwp_app["Version"]
return newer_uwp_app
def get_newer_uwp_depency(dependency_dict, all_files_dict, version_prefix=None, min_version=None):
"""Returns a list of the bin_name of the latest required dependencies"""
newer_version = "0"
for uwp_app in all_files_dict:
if not uwp_app["bin_name"].startswith(f'{dependency_dict["Name"]}_'):
continue
if version_prefix is not None and Version(uwp_app["version"], len(version_prefix.split("."))) != Version(
version_prefix, len(version_prefix.split("."))
):
continue
if Version(newer_version) < Version(uwp_app["version"]):
newer_uwp_depency = uwp_app
newer_version = uwp_app["version"]
return newer_uwp_depency["bin_name"].split(newer_version + "_")[0] + newer_version + "_"
def make_uwp_app_dict(appx_package_name):
import xmltodict
ms_app_db = {}
# for ms_app_file in (
# glob.glob("*.appxbundle")
# + glob.glob("*.msixbundle")
# + glob.glob("*.appx")
# + glob.glob("*.msix")
# ):
for ms_app_file in (
glob.glob(f"{appx_package_name}*.appxbundle")
+ glob.glob(f"{appx_package_name}*.msixbundle")
+ glob.glob(f"{appx_package_name}*.appx")
+ glob.glob(f"{appx_package_name}*.msix")
):
data_dict = {}
before_dependencies = []
sub_dependencies = []
dependency_data_dict = None
manifest = unzip(ms_app_file, ".", "AppxManifest.xml", False)
bundle_manifest = unzip(ms_app_file, ".", "AppxMetadata\\AppxBundleManifest.xml", False)
ms_app_info = {
"FileName": ms_app_file,
}
if not manifest:
if bundle_manifest:
with open(bundle_manifest[0], encoding="utf8") as xml_file:
data_dict = xmltodict.parse(xml_file.read(), attr_prefix="")
if type(data_dict["Bundle"]["Packages"]["Package"]) == dict:
data_dict["Bundle"]["Packages"]["Package"] = [dict(data_dict["Bundle"]["Packages"]["Package"])]
for app_pkg in list(data_dict["Bundle"]["Packages"]["Package"]):
if app_pkg["Type"] == "application":
before_dependency_info = {
"FileName": app_pkg["FileName"],
"Version": app_pkg["Version"],
"Architecture": app_pkg["Architecture"],
}
before_dependencies.append(before_dependency_info)
if before_dependencies:
for dependency in before_dependencies:
unzip(
ms_app_file,
".",
makepath(
dependency["FileName"],
),
False,
)
manifest = unzip(dependency["FileName"], ".", makepath("AppxManifest.xml"), False)
if isfile(dependency["FileName"]):
remove_file(dependency["FileName"])
with open(manifest[0], encoding="utf8") as xml_file:
dependency_data_dict = xmltodict.parse(xml_file.read(), attr_prefix="")
if dependency_data_dict["Package"].get("Dependencies"):
if dependency_data_dict["Package"]["Dependencies"].get("PackageDependency"):
sub_dependencies = list(dependency_data_dict["Package"]["Dependencies"]["PackageDependency"])
if type(dependency_data_dict["Package"]["Dependencies"]["PackageDependency"]) == dict:
sub_dependencies = [dict(dependency_data_dict["Package"]["Dependencies"]["PackageDependency"])]
if type(dependency_data_dict["Package"]["Dependencies"]["PackageDependency"]) == list:
sub_dependencies = dependency_data_dict["Package"]["Dependencies"]["PackageDependency"]
if dependency_data_dict["Package"]["Dependencies"].get("TargetDeviceFamily"):
if not "TargetDeviceFamily" in ms_app_info:
if type(dependency_data_dict["Package"]["Dependencies"]["TargetDeviceFamily"]) == dict:
ms_app_info["TargetDeviceFamily"] = [dict(dependency_data_dict["Package"]["Dependencies"]["TargetDeviceFamily"])]
if type(dependency_data_dict["Package"]["Dependencies"]["TargetDeviceFamily"]) == list:
ms_app_info["TargetDeviceFamily"] = dependency_data_dict["Package"]["Dependencies"]["TargetDeviceFamily"]
else:
error("nothing to parse")
else:
manifest = unzip(ms_app_file, ".", makepath("AppxManifest.xml"), False)
with open(manifest[0], encoding="utf8") as xml_file:
dependency_data_dict = xmltodict.parse(xml_file.read(), attr_prefix="")
if dependency_data_dict["Package"].get("Dependencies"):
if "PackageDependency" in dependency_data_dict["Package"]["Dependencies"]:
sub_dependencies = list(dependency_data_dict["Package"]["Dependencies"]["PackageDependency"])
if type(dependency_data_dict["Package"]["Dependencies"]["PackageDependency"]) == dict:
sub_dependencies = [dict(dependency_data_dict["Package"]["Dependencies"]["PackageDependency"])]
if type(dependency_data_dict["Package"]["Dependencies"]["PackageDependency"]) == list:
sub_dependencies = dependency_data_dict["Package"]["Dependencies"]["PackageDependency"]
if "TargetDeviceFamily" in dependency_data_dict["Package"]["Dependencies"]:
if not "TargetDeviceFamily" in ms_app_info:
if type(dependency_data_dict["Package"]["Dependencies"]["TargetDeviceFamily"]) == dict:
ms_app_info["TargetDeviceFamily"] = [dict(dependency_data_dict["Package"]["Dependencies"]["TargetDeviceFamily"])]
if type(dependency_data_dict["Package"]["Dependencies"]["TargetDeviceFamily"]) == list:
ms_app_info["TargetDeviceFamily"] = dependency_data_dict["Package"]["Dependencies"]["TargetDeviceFamily"]
else:
ms_app_info.update({"Dependencies": None})
if ms_app_info.get("TargetDeviceFamily"):
ms_app_info.update(
{
"MinVersion": ms_app_info["TargetDeviceFamily"][0]["MinVersion"],
"MaxVersionTested": ms_app_info["TargetDeviceFamily"][0]["MaxVersionTested"],
}
)
elif dependency_data_dict is not None and dependency_data_dict["Package"].get("Prerequisites"):
ms_app_info.update(
{
"MinVersion": dependency_data_dict["Package"]["Prerequisites"]["OSMinVersion"],
"MaxVersionTested": dependency_data_dict["Package"]["Prerequisites"]["OSMaxVersionTested"],
}
)
else:
ms_app_info.update({"TargetDeviceFamily": None})
if data_dict:
ms_app_info.update(data_dict["Bundle"]["Identity"])
else:
ms_app_info.update(dependency_data_dict["Package"]["Identity"])
if "ProcessorArchitecture" in ms_app_info:
ms_app_info.update({"Architecture": ms_app_info["ProcessorArchitecture"]})
if before_dependencies:
ms_app_info["b4:Dependencies"] = before_dependencies
else:
ms_app_info.update({"b4:Dependencies": None})
if sub_dependencies:
ms_app_info["Dependencies"] = sub_dependencies
else:
ms_app_info.update({"Dependencies": None})
ms_app_db[ms_app_file] = ms_app_info
for xml_file in glob.glob("AppxManifest.xml") + glob.glob("AppxBundleManifest.xml"):
remove_file(xml_file)
return ms_app_db
def set_control_os_version_uwp_app(
newer_uwp_app,
force_values=False,
priority_windows=WindowsVersions.Windows11,
eol_windows=WindowsVersions.Windows10v2004,
silent=False,
):
if newer_uwp_app.get("MinVersion") and newer_uwp_app.get("MaxVersionTested"):
control.min_os_version = ".".join(
newer_uwp_app["MinVersion"].split(".")[: 2 if ".".join(newer_uwp_app["MinVersion"].split(".")[:3]).endswith("0") else 3]
)
# MaxVersionTested value seems not reliable, now asking to change control.max_os_version
if not Version(newer_uwp_app["MaxVersionTested"], 3) <= eol_windows: # Ignore end-of-life Windows versions
if control.max_os_version != ".".join(newer_uwp_app["MaxVersionTested"].split(".")[:3]):
if force_values:
control.max_os_version = ".".join(newer_uwp_app["MaxVersionTested"].split(".")[:3])
else:
if not silent:
control_max_os_version = ask_input(
control.package,
f'INFO: You may wanna change "control.max_os_version" by "{".".join(newer_uwp_app["MaxVersionTested"].split(".")[:3])}" or "{newer_uwp_app["MaxVersionTested"]}"',
"",
raise_error=False,
)
if control_max_os_version or control_max_os_version == "":
control.max_os_version = control_max_os_version
else:
print(
f'INFO: You may wanna change "control.max_os_version" by "{".".join(newer_uwp_app["MaxVersionTested"].split(".")[:3])}"'
)
else:
if control.max_os_version != "":
if force_values:
control.max_os_version = ""
else:
if not silent:
control_max_os_version = ask_message(
control.package,
f'INFO: You may wanna erase "control.max_os_version : {control.max_os_version}"',
3 + 32,
raise_error=False,
)
if control_max_os_version == 6:
control.max_os_version = ""
control.save_control_to_wapt()
38d056ab130f7bf7c481c12636a4e9959de36561d3dfcbe54c6e3571bc0c1dc3 : WAPT/certificate.crt
7e083df776c1184461d97bc1b119f727f84cb6c740f49a073046eab8619522c2 : WAPT/control
c964594c0a3b13b1b9274511d769d52a896a970452be1f2593d41745d791010c : WAPT/icon.png
b33c87d60a9c868ec239b7e6a62575151628f29f45e4307ef4a17298dc185008 : examshield-uwp/Microsoft.NET.Native.Framework.2.2_2.2.29512.0_arm64__8wekyb3d8bbwe.appx
bdf9c70e4966a4f7ce00ca7fc5179962239514be879f2aa3c1794076b7ff9bc6 : examshield-uwp/Microsoft.NET.Native.Framework.2.2_2.2.29512.0_arm__8wekyb3d8bbwe.appx
c195047f4af9c3ff3d92c40e55a901cf7cfa08a679b8ca2543bb104bab2f7ff1 : examshield-uwp/Microsoft.NET.Native.Framework.2.2_2.2.29512.0_x64__8wekyb3d8bbwe.appx
e4c5dff287b59e27eb9da6ccd02ed1c76d3f6001eceb0f20e71eebd507b3aad2 : examshield-uwp/Microsoft.NET.Native.Framework.2.2_2.2.29512.0_x86__8wekyb3d8bbwe.appx
47de27af62a9a31d123a522c4a74056b8a10d15307de9ebead0adf684f3df45d : examshield-uwp/Microsoft.NET.Native.Runtime.2.2_2.2.28604.0_arm64__8wekyb3d8bbwe.appx
7ccf4ef1815d479570fdcf4e462bd7d80f1bc9ae3c39c93220fdb40cc0ebaca9 : examshield-uwp/Microsoft.NET.Native.Runtime.2.2_2.2.28604.0_arm__8wekyb3d8bbwe.appx
27fae660d8c609e020703bb463b6601e62811dc75db19975bcb7d68d959b527d : examshield-uwp/Microsoft.NET.Native.Runtime.2.2_2.2.28604.0_x64__8wekyb3d8bbwe.appx
ec7e811dca0cb511c69859c65aa1d94ccd5cc3cab3ec7f9d6bab95abb03149a8 : examshield-uwp/Microsoft.NET.Native.Runtime.2.2_2.2.28604.0_x86__8wekyb3d8bbwe.appx
831118f2f5cac8e29284e4ecc23bf4236436ccc2ea4a7c225c4946f8cfd29dd3 : examshield-uwp/Microsoft.VCLibs.140.00.UWPDesktop_14.0.33728.0_arm64__8wekyb3d8bbwe.appx
df3d87926a1d9780b7a76e145c3eae17f58e825fd7a9c1b2017608929da0d86f : examshield-uwp/Microsoft.VCLibs.140.00.UWPDesktop_14.0.33728.0_arm__8wekyb3d8bbwe.appx
077a3d1a5d0622bd3004dca85f5e192d6e98ec79b83d4aa06766759ea6c09c3d : examshield-uwp/Microsoft.VCLibs.140.00.UWPDesktop_14.0.33728.0_x64__8wekyb3d8bbwe.appx
596c7175c0b0fa27ed292a44f4681f687720a77e34e007bf6c403d1940e46005 : examshield-uwp/Microsoft.VCLibs.140.00.UWPDesktop_14.0.33728.0_x86__8wekyb3d8bbwe.appx
c73d0f55dda331f9dcbefc99ff5a420b62120773d2917387639382aa478533ee : examshield-uwp/Microsoft.VCLibs.140.00_14.0.33519.0_arm64__8wekyb3d8bbwe.appx
2c422523ff693689a84c109585cfa444143ac3b6b7a5cadf4858afc6a3cb750f : examshield-uwp/Microsoft.VCLibs.140.00_14.0.33519.0_arm__8wekyb3d8bbwe.appx
9c17b521f9d690a1f504da5108ed6eec5669eb3a8fd1331eef43e40d84e74283 : examshield-uwp/Microsoft.VCLibs.140.00_14.0.33519.0_x64__8wekyb3d8bbwe.appx
7ba6ea7bc32cd58b7e0683da588796086accfb74efb7a3e525e9f8014d2ad663 : examshield-uwp/Microsoft.VCLibs.140.00_14.0.33519.0_x86__8wekyb3d8bbwe.appx
3e33656b0b90e86fc51655e64b300ce3a350e6fafb0d864adf8e2a287775ce3e : examshield-uwp/PeoplecertInternationalLt.ExamShield_6.7.94.0_neutral_~_6n3jnjp1nhnze.msixbundle
5f325807a9925d7e4240f9af2bb8650aeadb3b1bdbf3e56e98e9868b9882a6b5 : luti.json
c262d5cfd55f9042782858f600812022b3b984658d2967a518cc9f29e9489c15 : package.json
e6d4219b02a107cb4a653d7eeefca9119cc473f97e3bb425a0387ae0b0c50212 : setup.py
2468a123904bc2c2f62ea7c61641a90b4650b9148917a3424ed324b231901858 : setupdevhelpers.py
d63a23313283519a456e4904c69289b7c0434daa1aebf72b0bccc03d0153a535 : update_package.py
364e01205533a0c6907fb9e8a8f70353985ae81ead35b71aade9a4253184f847 : xmltodict.py