trivial: reformat all python code with black

This commit is contained in:
Mario Limonciello 2021-04-08 09:17:22 -05:00 committed by Mario Limonciello
parent b5555003bb
commit 6d1afc3e87
28 changed files with 768 additions and 1270 deletions

View File

@ -7,72 +7,72 @@ import shutil
def prepare(target): def prepare(target):
# clone the flatpak json # clone the flatpak json
cmd = ['git', 'submodule', 'update', '--remote', 'contrib/flatpak'] cmd = ["git", "submodule", "update", "--remote", "contrib/flatpak"]
subprocess.run(cmd, check=True) subprocess.run(cmd, check=True)
# clone the submodules for that # clone the submodules for that
cmd = ['git', 'submodule', 'update', '--init', '--remote', 'shared-modules/'] cmd = ["git", "submodule", "update", "--init", "--remote", "shared-modules/"]
subprocess.run(cmd, cwd='contrib/flatpak', check=True) subprocess.run(cmd, cwd="contrib/flatpak", check=True)
# parse json # parse json
if os.path.isdir('build'): if os.path.isdir("build"):
shutil.rmtree('build') shutil.rmtree("build")
data = {} data = {}
with open('contrib/flatpak/org.freedesktop.fwupd.json', 'r') as rfd: with open("contrib/flatpak/org.freedesktop.fwupd.json", "r") as rfd:
data = json.load(rfd, strict=False) data = json.load(rfd, strict=False)
platform = 'runtime/%s/x86_64/%s' % (data['runtime'], data['runtime-version']) platform = "runtime/%s/x86_64/%s" % (data["runtime"], data["runtime-version"])
sdk = 'runtime/%s/x86_64/%s' % (data['sdk'], data['runtime-version']) sdk = "runtime/%s/x86_64/%s" % (data["sdk"], data["runtime-version"])
num_modules = len(data['modules']) num_modules = len(data["modules"])
# update to build from master # update to build from master
data["branch"] = "master" data["branch"] = "master"
for index in range(0, num_modules): for index in range(0, num_modules):
module = data['modules'][index] module = data["modules"][index]
if type(module) != dict or not 'name' in module: if type(module) != dict or not "name" in module:
continue continue
name = module['name'] name = module["name"]
if not 'fwupd' in name: if not "fwupd" in name:
continue continue
data['modules'][index]['sources'][0].pop('url') data["modules"][index]["sources"][0].pop("url")
data['modules'][index]['sources'][0].pop('sha256') data["modules"][index]["sources"][0].pop("sha256")
data['modules'][index]['sources'][0]['type'] = 'dir' data["modules"][index]["sources"][0]["type"] = "dir"
data['modules'][index]['sources'][0]['skip'] = [".git"] data["modules"][index]["sources"][0]["skip"] = [".git"]
data['modules'][index]['sources'][0]['path'] = ".." data["modules"][index]["sources"][0]["path"] = ".."
# write json # write json
os.mkdir('build') os.mkdir("build")
with open(target, 'w') as wfd: with open(target, "w") as wfd:
json.dump(data, wfd, indent=4) json.dump(data, wfd, indent=4)
os.symlink('../contrib/flatpak/shared-modules', 'build/shared-modules') os.symlink("../contrib/flatpak/shared-modules", "build/shared-modules")
# install the runtimes (parsed from json!) # install the runtimes (parsed from json!)
repo = 'flathub' repo = "flathub"
repo_url = 'https://dl.flathub.org/repo/flathub.flatpakrepo' repo_url = "https://dl.flathub.org/repo/flathub.flatpakrepo"
print("Installing dependencies") print("Installing dependencies")
cmd = ['flatpak', 'remote-add', '--if-not-exists', repo, repo_url] cmd = ["flatpak", "remote-add", "--if-not-exists", repo, repo_url]
subprocess.run(cmd, check=True) subprocess.run(cmd, check=True)
cmd = ['flatpak', 'install', '--assumeyes', repo, sdk] cmd = ["flatpak", "install", "--assumeyes", repo, sdk]
subprocess.run(cmd, check=True) subprocess.run(cmd, check=True)
cmd = ['flatpak', 'install', '--assumeyes', repo, platform] cmd = ["flatpak", "install", "--assumeyes", repo, platform]
subprocess.run(cmd, check=True) subprocess.run(cmd, check=True)
def build(target): def build(target):
cmd = [ cmd = [
'flatpak-builder', "flatpak-builder",
'--repo=repo', "--repo=repo",
'--force-clean', "--force-clean",
'--disable-rofiles-fuse', "--disable-rofiles-fuse",
'build-dir', "build-dir",
target, target,
] ]
subprocess.run(cmd, check=True) subprocess.run(cmd, check=True)
cmd = ['flatpak', 'build-bundle', 'repo', 'fwupd.flatpak', 'org.freedesktop.fwupd'] cmd = ["flatpak", "build-bundle", "repo", "fwupd.flatpak", "org.freedesktop.fwupd"]
subprocess.run(cmd, check=True) subprocess.run(cmd, check=True)
if __name__ == '__main__': if __name__ == "__main__":
t = os.path.join('build', 'org.freedesktop.fwupd.json') t = os.path.join("build", "org.freedesktop.fwupd.json")
prepare(t) prepare(t)
build(t) build(t)

View File

@ -10,25 +10,25 @@ import xml.etree.ElementTree as etree
def parse_control_dependencies(requested_type): def parse_control_dependencies(requested_type):
TARGET = os.getenv('OS') TARGET = os.getenv("OS")
QUBES = os.getenv('QUBES') QUBES = os.getenv("QUBES")
deps = [] deps = []
dep = '' dep = ""
if TARGET == '': if TARGET == "":
print("Missing OS environment variable") print("Missing OS environment variable")
sys.exit(1) sys.exit(1)
OS = TARGET OS = TARGET
SUBOS = '' SUBOS = ""
if TARGET: if TARGET:
split = TARGET.split('-') split = TARGET.split("-")
if len(split) >= 2: if len(split) >= 2:
OS = split[0] OS = split[0]
SUBOS = split[1] SUBOS = split[1]
else: else:
import lsb_release import lsb_release
OS = lsb_release.get_distro_information()['ID'].lower() OS = lsb_release.get_distro_information()["ID"].lower()
import platform import platform
SUBOS = platform.machine() SUBOS = platform.machine()
@ -49,33 +49,33 @@ def parse_control_dependencies(requested_type):
packages = distro.findall("package") packages = distro.findall("package")
for package in packages: for package in packages:
if SUBOS: if SUBOS:
if not 'variant' in package.attrib: if not "variant" in package.attrib:
continue continue
if package.attrib['variant'] != SUBOS: if package.attrib["variant"] != SUBOS:
continue continue
if package.text: if package.text:
dep = package.text dep = package.text
else: else:
dep = child.attrib["id"] dep = child.attrib["id"]
if child.attrib["type"] == requested_type and dep: if child.attrib["type"] == requested_type and dep:
version = control.find('version') version = control.find("version")
if version is not None: if version is not None:
dep = "%s %s" % (dep, version.text) dep = "%s %s" % (dep, version.text)
inclusions = control.findall('inclusive') inclusions = control.findall("inclusive")
if inclusions: if inclusions:
for i in range(0, len(inclusions)): for i in range(0, len(inclusions)):
prefix = '' prefix = ""
suffix = ' ' suffix = " "
if i == 0: if i == 0:
prefix = " [" prefix = " ["
if i == len(inclusions) - 1: if i == len(inclusions) - 1:
suffix = "]" suffix = "]"
dep = "%s%s%s%s" % (dep, prefix, inclusions[i].text, suffix) dep = "%s%s%s%s" % (dep, prefix, inclusions[i].text, suffix)
exclusions = control.findall('exclusive') exclusions = control.findall("exclusive")
if exclusions: if exclusions:
for i in range(0, len(exclusions)): for i in range(0, len(exclusions)):
prefix = '!' prefix = "!"
suffix = ' ' suffix = " "
if i == 0: if i == 0:
prefix = " [!" prefix = " [!"
if i == len(exclusions) - 1: if i == len(exclusions) - 1:
@ -86,26 +86,26 @@ def parse_control_dependencies(requested_type):
def update_debian_control(target): def update_debian_control(target):
control_in = os.path.join(target, 'control.in') control_in = os.path.join(target, "control.in")
control_out = os.path.join(target, 'control') control_out = os.path.join(target, "control")
if not os.path.exists(control_in): if not os.path.exists(control_in):
print("Missing file %s" % control_in) print("Missing file %s" % control_in)
sys.exit(1) sys.exit(1)
with open(control_in, 'r') as rfd: with open(control_in, "r") as rfd:
lines = rfd.readlines() lines = rfd.readlines()
deps, QUBES = parse_control_dependencies("build") deps, QUBES = parse_control_dependencies("build")
deps.sort() deps.sort()
if QUBES: if QUBES:
lines += '\n' lines += "\n"
control_qubes_in = os.path.join(target, 'control.qubes.in') control_qubes_in = os.path.join(target, "control.qubes.in")
with open(control_qubes_in, 'r') as rfd: with open(control_qubes_in, "r") as rfd:
lines += rfd.readlines() lines += rfd.readlines()
with open(control_out, 'w') as wfd: with open(control_out, "w") as wfd:
for line in lines: for line in lines:
if line.startswith("Build-Depends: %%%DYNAMIC%%%"): if line.startswith("Build-Depends: %%%DYNAMIC%%%"):
wfd.write("Build-Depends:\n") wfd.write("Build-Depends:\n")
@ -118,8 +118,8 @@ def update_debian_control(target):
def update_debian_copyright(directory): def update_debian_copyright(directory):
copyright_in = os.path.join(directory, 'copyright.in') copyright_in = os.path.join(directory, "copyright.in")
copyright_out = os.path.join(directory, 'copyright') copyright_out = os.path.join(directory, "copyright")
if not os.path.exists(copyright_in): if not os.path.exists(copyright_in):
print("Missing file %s" % copyright_in) print("Missing file %s" % copyright_in)
@ -127,14 +127,14 @@ def update_debian_copyright(directory):
# Assume all files are remaining LGPL-2.1+ # Assume all files are remaining LGPL-2.1+
copyrights = [] copyrights = []
for root, dirs, files in os.walk('.'): for root, dirs, files in os.walk("."):
for file in files: for file in files:
target = os.path.join(root, file) target = os.path.join(root, file)
# skip translations and license file # skip translations and license file
if target.startswith('./po/') or file == "COPYING": if target.startswith("./po/") or file == "COPYING":
continue continue
try: try:
with open(target, 'r') as rfd: with open(target, "r") as rfd:
# read about the first few lines of the file only # read about the first few lines of the file only
lines = rfd.readlines(220) lines = rfd.readlines(220)
except UnicodeDecodeError: except UnicodeDecodeError:
@ -142,17 +142,17 @@ def update_debian_copyright(directory):
except FileNotFoundError: except FileNotFoundError:
continue continue
for line in lines: for line in lines:
if 'Copyright (C) ' in line: if "Copyright (C) " in line:
parts = line.split('Copyright (C)')[ parts = line.split("Copyright (C)")[
1 1
].strip() # split out the copyright header ].strip() # split out the copyright header
partition = parts.partition(' ')[2] # remove the year string partition = parts.partition(" ")[2] # remove the year string
copyrights += ["%s" % partition] copyrights += ["%s" % partition]
copyrights = "\n\t ".join(sorted(set(copyrights))) copyrights = "\n\t ".join(sorted(set(copyrights)))
with open(copyright_in, 'r') as rfd: with open(copyright_in, "r") as rfd:
lines = rfd.readlines() lines = rfd.readlines()
with open(copyright_out, 'w') as wfd: with open(copyright_out, "w") as wfd:
for line in lines: for line in lines:
if line.startswith("%%%DYNAMIC%%%"): if line.startswith("%%%DYNAMIC%%%"):
wfd.write("Files: *\n") wfd.write("Files: *\n")
@ -163,6 +163,6 @@ def update_debian_copyright(directory):
wfd.write(line) wfd.write(line)
directory = os.path.join(os.getcwd(), 'debian') directory = os.path.join(os.getcwd(), "debian")
update_debian_control(directory) update_debian_control(directory)
update_debian_copyright(directory) update_debian_copyright(directory)

View File

@ -13,7 +13,7 @@ import xml.etree.ElementTree as etree
def parse_dependencies(OS, SUBOS, requested_type): def parse_dependencies(OS, SUBOS, requested_type):
deps = [] deps = []
dep = '' dep = ""
directory = os.path.dirname(sys.argv[0]) directory = os.path.dirname(sys.argv[0])
tree = etree.parse(os.path.join(directory, "dependencies.xml")) tree = etree.parse(os.path.join(directory, "dependencies.xml"))
root = tree.getroot() root = tree.getroot()
@ -28,9 +28,9 @@ def parse_dependencies(OS, SUBOS, requested_type):
packages = distro.findall("package") packages = distro.findall("package")
for package in packages: for package in packages:
if SUBOS: if SUBOS:
if 'variant' not in package.attrib: if "variant" not in package.attrib:
continue continue
if package.attrib['variant'] != SUBOS: if package.attrib["variant"] != SUBOS:
continue continue
if package.text: if package.text:
dep = package.text dep = package.text
@ -41,7 +41,7 @@ def parse_dependencies(OS, SUBOS, requested_type):
return deps return deps
if __name__ == '__main__': if __name__ == "__main__":
try: try:
import distro import distro
@ -60,15 +60,15 @@ if __name__ == '__main__':
) )
args = parser.parse_args() args = parser.parse_args()
target = os.getenv('OS', args.os) target = os.getenv("OS", args.os)
if target is None: if target is None:
print("Missing OS environment variable") print("Missing OS environment variable")
sys.exit(1) sys.exit(1)
_os = target.lower() _os = target.lower()
_sub_os = '' _sub_os = ""
split = target.split('-') split = target.split("-")
if len(split) >= 2: if len(split) >= 2:
_os, _sub_os = split[:2] _os, _sub_os = split[:2]
dependencies = parse_dependencies(_os, _sub_os, "build") dependencies = parse_dependencies(_os, _sub_os, "build")
print(*dependencies, sep='\n') print(*dependencies, sep="\n")

View File

@ -12,23 +12,23 @@ from generate_dependencies import parse_dependencies
def get_container_cmd(): def get_container_cmd():
'''return docker or podman as container manager''' """return docker or podman as container manager"""
if shutil.which('docker'): if shutil.which("docker"):
return 'docker' return "docker"
if shutil.which('podman'): if shutil.which("podman"):
return 'podman' return "podman"
directory = os.path.dirname(sys.argv[0]) directory = os.path.dirname(sys.argv[0])
TARGET = os.getenv('OS') TARGET = os.getenv("OS")
if TARGET is None: if TARGET is None:
print("Missing OS environment variable") print("Missing OS environment variable")
sys.exit(1) sys.exit(1)
OS = TARGET OS = TARGET
SUBOS = '' SUBOS = ""
split = TARGET.split('-') split = TARGET.split("-")
if len(split) >= 2: if len(split) >= 2:
OS = split[0] OS = split[0]
SUBOS = split[1] SUBOS = split[1]
@ -40,19 +40,19 @@ if not os.path.exists(input):
print("Missing input file %s for %s" % (input, OS)) print("Missing input file %s for %s" % (input, OS))
sys.exit(1) sys.exit(1)
with open(input, 'r') as rfd: with open(input, "r") as rfd:
lines = rfd.readlines() lines = rfd.readlines()
with open('Dockerfile', 'w') as wfd: with open("Dockerfile", "w") as wfd:
for line in lines: for line in lines:
if line.startswith("FROM %%%ARCH_PREFIX%%%"): if line.startswith("FROM %%%ARCH_PREFIX%%%"):
if (OS == "debian" or OS == "ubuntu") and SUBOS == "i386": if (OS == "debian" or OS == "ubuntu") and SUBOS == "i386":
replace = SUBOS + "/" replace = SUBOS + "/"
else: else:
replace = '' replace = ""
wfd.write(line.replace("%%%ARCH_PREFIX%%%", replace)) wfd.write(line.replace("%%%ARCH_PREFIX%%%", replace))
elif line == "%%%INSTALL_DEPENDENCIES_COMMAND%%%\n": elif line == "%%%INSTALL_DEPENDENCIES_COMMAND%%%\n":
if OS == "fedora" or OS == 'flatpak': if OS == "fedora" or OS == "flatpak":
wfd.write("RUN dnf --enablerepo=updates-testing -y install \\\n") wfd.write("RUN dnf --enablerepo=updates-testing -y install \\\n")
elif OS == "centos": elif OS == "centos":
wfd.write("RUN yum -y install \\\n") wfd.write("RUN yum -y install \\\n")
@ -75,19 +75,19 @@ with open('Dockerfile', 'w') as wfd:
'RUN cat /etc/apt/sources.list | sed "s/deb/deb-src/" >> /etc/apt/sources.list\n' 'RUN cat /etc/apt/sources.list | sed "s/deb/deb-src/" >> /etc/apt/sources.list\n'
) )
# add new architecture # add new architecture
wfd.write('RUN dpkg --add-architecture %s\n' % SUBOS) wfd.write("RUN dpkg --add-architecture %s\n" % SUBOS)
elif line == "%%%OS%%%\n": elif line == "%%%OS%%%\n":
wfd.write("ENV OS %s\n" % TARGET) wfd.write("ENV OS %s\n" % TARGET)
else: else:
wfd.write(line) wfd.write(line)
wfd.flush() wfd.flush()
if len(sys.argv) == 2 and sys.argv[1] == 'build': if len(sys.argv) == 2 and sys.argv[1] == "build":
cmd = get_container_cmd() cmd = get_container_cmd()
args = [cmd, "build", "-t", "fwupd-%s" % TARGET] args = [cmd, "build", "-t", "fwupd-%s" % TARGET]
if 'http_proxy' in os.environ: if "http_proxy" in os.environ:
args += ['--build-arg=http_proxy=%s' % os.environ['http_proxy']] args += ["--build-arg=http_proxy=%s" % os.environ["http_proxy"]]
if 'https_proxy' in os.environ: if "https_proxy" in os.environ:
args += ['--build-arg=https_proxy=%s' % os.environ['https_proxy']] args += ["--build-arg=https_proxy=%s" % os.environ["https_proxy"]]
args += ["-f", "./Dockerfile", "."] args += ["-f", "./Dockerfile", "."]
subprocess.check_call(args) subprocess.check_call(args)

View File

@ -119,14 +119,7 @@ class Builder:
if not os.path.exists(fullsrc): if not os.path.exists(fullsrc):
fullsrc = os.path.join(self.builddir, src) fullsrc = os.path.join(self.builddir, src)
dst = os.path.basename(src).replace(".c", ".o") dst = os.path.basename(src).replace(".c", ".o")
argv.extend( argv.extend(["-c", fullsrc, "-o", os.path.join(self.builddir, dst)])
[
"-c",
fullsrc,
"-o",
os.path.join(self.builddir, dst),
]
)
print("building {} into {}".format(src, dst)) print("building {} into {}".format(src, dst))
try: try:
subprocess.run(argv, cwd=self.srcdir, check=True) subprocess.run(argv, cwd=self.srcdir, check=True)
@ -169,11 +162,9 @@ class Builder:
def makezip(self, dst: str, globstr: str) -> None: def makezip(self, dst: str, globstr: str) -> None:
""" create a zip file archive from a glob """ """ create a zip file archive from a glob """
argv = [ argv = ["zip", "--junk-paths", os.path.join(self.installdir, dst)] + glob.glob(
"zip", os.path.join(self.srcdir, globstr)
"--junk-paths", )
os.path.join(self.installdir, dst),
] + glob.glob(os.path.join(self.srcdir, globstr))
print("assembling {}".format(dst)) print("assembling {}".format(dst))
subprocess.run(argv, cwd=self.srcdir, check=True) subprocess.run(argv, cwd=self.srcdir, check=True)
@ -240,16 +231,10 @@ def _build(bld: Builder) -> None:
# JSON-GLib # JSON-GLib
src = bld.checkout_source( src = bld.checkout_source(
"json-glib", "json-glib", url="https://gitlab.gnome.org/GNOME/json-glib.git"
url="https://gitlab.gnome.org/GNOME/json-glib.git",
) )
bld.build_meson_project( bld.build_meson_project(
src, src, ["-Dgtk_doc=disabled", "-Dtests=false", "-Dintrospection=disabled"]
[
"-Dgtk_doc=disabled",
"-Dtests=false",
"-Dintrospection=disabled",
],
) )
bld.add_work_includedir("include/json-glib-1.0/json-glib") bld.add_work_includedir("include/json-glib-1.0/json-glib")
bld.add_work_includedir("include/json-glib-1.0") bld.add_work_includedir("include/json-glib-1.0")
@ -258,12 +243,7 @@ def _build(bld: Builder) -> None:
# libxmlb # libxmlb
src = bld.checkout_source("libxmlb", url="https://github.com/hughsie/libxmlb.git") src = bld.checkout_source("libxmlb", url="https://github.com/hughsie/libxmlb.git")
bld.build_meson_project( bld.build_meson_project(
src, src, ["-Dgtkdoc=false", "-Dintrospection=false", "-Dtests=false"]
[
"-Dgtkdoc=false",
"-Dintrospection=false",
"-Dtests=false",
],
) )
bld.add_work_includedir("include/libxmlb-2") bld.add_work_includedir("include/libxmlb-2")
bld.add_work_includedir("include/libxmlb-2/libxmlb") bld.add_work_includedir("include/libxmlb-2/libxmlb")

View File

@ -24,26 +24,26 @@ def add_header(infile, outfile, gd, fl=None):
import struct import struct
try: try:
with open(infile, 'rb') as f: with open(infile, "rb") as f:
bin_data = f.read() bin_data = f.read()
except FileNotFoundError as e: except FileNotFoundError as e:
print(e) print(e)
return 1 return 1
# check if already has header # check if already has header
hdrsz = struct.calcsize('<16sIII') hdrsz = struct.calcsize("<16sIII")
if len(bin_data) >= hdrsz: if len(bin_data) >= hdrsz:
hdr = struct.unpack('<16sIII', bin_data[:hdrsz]) hdr = struct.unpack("<16sIII", bin_data[:hdrsz])
imgsz = hdr[3] imgsz = hdr[3]
if imgsz == len(bin_data): if imgsz == len(bin_data):
print('Replacing existing CAPSULE_HEADER of:') print("Replacing existing CAPSULE_HEADER of:")
guid_mixed = uuid.UUID(bytes_le=hdr[0]) guid_mixed = uuid.UUID(bytes_le=hdr[0])
hdrsz_old = hdr[1] hdrsz_old = hdr[1]
flags = hdr[2] flags = hdr[2]
print('GUID: %s' % guid_mixed) print("GUID: %s" % guid_mixed)
print('HdrSz: 0x%04x' % hdrsz_old) print("HdrSz: 0x%04x" % hdrsz_old)
print('Flags: 0x%04x' % flags) print("Flags: 0x%04x" % flags)
print('PayloadSz: 0x%04x' % imgsz) print("PayloadSz: 0x%04x" % imgsz)
bin_data = bin_data[hdrsz_old:] bin_data = bin_data[hdrsz_old:]
# set header flags # set header flags
@ -59,24 +59,24 @@ def add_header(infile, outfile, gd, fl=None):
hdrsz = 4096 hdrsz = 4096
imgsz = hdrsz + len(bin_data) imgsz = hdrsz + len(bin_data)
hdr = ctypes.create_string_buffer(hdrsz) hdr = ctypes.create_string_buffer(hdrsz)
struct.pack_into('<16sIII', hdr, 0, guid.bytes_le, hdrsz, flags, imgsz) struct.pack_into("<16sIII", hdr, 0, guid.bytes_le, hdrsz, flags, imgsz)
with open(outfile, 'wb') as f: with open(outfile, "wb") as f:
f.write(hdr) f.write(hdr)
f.write(bin_data) f.write(bin_data)
print('Wrote capsule %s' % outfile) print("Wrote capsule %s" % outfile)
print('GUID: %s' % guid) print("GUID: %s" % guid)
print('HdrSz: 0x%04x' % hdrsz) print("HdrSz: 0x%04x" % hdrsz)
print('Flags: 0x%04x' % flags) print("Flags: 0x%04x" % flags)
print('PayloadSz: 0x%04x' % imgsz) print("PayloadSz: 0x%04x" % imgsz)
return 0 return 0
if __name__ == '__main__': if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Add capsule header on firmware') parser = argparse.ArgumentParser(description="Add capsule header on firmware")
parser.add_argument('--guid', help='GUID of the device', required=True) parser.add_argument("--guid", help="GUID of the device", required=True)
parser.add_argument('--bin', help='Path to the .bin file', required=True) parser.add_argument("--bin", help="Path to the .bin file", required=True)
parser.add_argument('--cap', help='Output capsule file path', required=True) parser.add_argument("--cap", help="Output capsule file path", required=True)
parser.add_argument('--flags', help='Flags, e.g. 0x40000', default=None) parser.add_argument("--flags", help="Flags, e.g. 0x40000", default=None)
args = parser.parse_args() args = parser.parse_args()
sys.exit(add_header(args.bin, args.cap, args.guid, args.flags)) sys.exit(add_header(args.bin, args.cap, args.guid, args.flags))

View File

@ -13,43 +13,43 @@ import argparse
def main(bin_fn, dfu_fn, pad, vid, pid, rev): def main(bin_fn, dfu_fn, pad, vid, pid, rev):
# read binary file # read binary file
with open(bin_fn, 'rb') as f: with open(bin_fn, "rb") as f:
blob = f.read() blob = f.read()
# pad blob to a specific size # pad blob to a specific size
if pad: if pad:
while len(blob) < int(pad, 16): while len(blob) < int(pad, 16):
blob += b'\0' blob += b"\0"
# create DFU footer with checksum # create DFU footer with checksum
blob += struct.pack( blob += struct.pack(
'<HHHH3sB', "<HHHH3sB",
int(rev, 16), # version int(rev, 16), # version
int(pid, 16), # PID int(pid, 16), # PID
int(vid, 16), # VID int(vid, 16), # VID
0x0100, # DFU version 0x0100, # DFU version
b'UFD', # signature b"UFD", # signature
0x10, 0x10,
) # hdrlen ) # hdrlen
crc32 = zlib.crc32(blob) ^ 0xFFFFFFFF crc32 = zlib.crc32(blob) ^ 0xFFFFFFFF
blob += struct.pack('<L', crc32) blob += struct.pack("<L", crc32)
# write binary file # write binary file
with open(dfu_fn, 'wb') as f: with open(dfu_fn, "wb") as f:
f.write(blob) f.write(blob)
if __name__ == "__main__": if __name__ == "__main__":
# parse args # parse args
parser = argparse.ArgumentParser(description='Add DFU footer on firmware') parser = argparse.ArgumentParser(description="Add DFU footer on firmware")
parser.add_argument('--bin', help='Path to the .bin file', required=True) parser.add_argument("--bin", help="Path to the .bin file", required=True)
parser.add_argument('--dfu', help='Output DFU file path', required=True) parser.add_argument("--dfu", help="Output DFU file path", required=True)
parser.add_argument( parser.add_argument(
'--pad', help='Pad to a specific size, e.g. 0x4000', default=None "--pad", help="Pad to a specific size, e.g. 0x4000", default=None
) )
parser.add_argument('--vid', help='Vendor ID, e.g. 0x273f', required=True) parser.add_argument("--vid", help="Vendor ID, e.g. 0x273f", required=True)
parser.add_argument('--pid', help='Product ID, e.g. 0x1002', required=True) parser.add_argument("--pid", help="Product ID, e.g. 0x1002", required=True)
parser.add_argument('--rev', help='Revision, e.g. 0x1000', required=True) parser.add_argument("--rev", help="Revision, e.g. 0x1000", required=True)
args = parser.parse_args() args = parser.parse_args()
main(args.bin, args.dfu, args.pad, args.vid, args.pid, args.rev) main(args.bin, args.dfu, args.pad, args.vid, args.pid, args.rev)

View File

@ -57,107 +57,107 @@ def make_firmware_metainfo(firmware_info, dst):
**local_info, timestamp=time.time() **local_info, timestamp=time.time()
) )
with open(os.path.join(dst, 'firmware.metainfo.xml'), 'w') as f: with open(os.path.join(dst, "firmware.metainfo.xml"), "w") as f:
f.write(firmware_metainfo) f.write(firmware_metainfo)
def extract_exe(exe, dst): def extract_exe(exe, dst):
command = ['7z', 'x', '-o{}'.format(dst), exe] command = ["7z", "x", "-o{}".format(dst), exe]
subprocess.check_call(command, stdout=subprocess.DEVNULL) subprocess.check_call(command, stdout=subprocess.DEVNULL)
def get_firmware_bin(root, bin_path, dst): def get_firmware_bin(root, bin_path, dst):
with cd(root): with cd(root):
shutil.copy(bin_path, os.path.join(dst, 'firmware.bin')) shutil.copy(bin_path, os.path.join(dst, "firmware.bin"))
def create_firmware_cab(exe, folder): def create_firmware_cab(exe, folder):
with cd(folder): with cd(folder):
if os.name == "nt": if os.name == "nt":
directive = os.path.join(folder, "directive") directive = os.path.join(folder, "directive")
with open(directive, 'w') as wfd: with open(directive, "w") as wfd:
wfd.write('.OPTION EXPLICIT\r\n') wfd.write(".OPTION EXPLICIT\r\n")
wfd.write('.Set CabinetNameTemplate=firmware.cab\r\n') wfd.write(".Set CabinetNameTemplate=firmware.cab\r\n")
wfd.write('.Set DiskDirectory1=.\r\n') wfd.write(".Set DiskDirectory1=.\r\n")
wfd.write('firmware.bin\r\n') wfd.write("firmware.bin\r\n")
wfd.write('firmware.metainfo.xml\r\n') wfd.write("firmware.metainfo.xml\r\n")
command = ['makecab.exe', '/f', directive] command = ["makecab.exe", "/f", directive]
else: else:
command = [ command = [
'gcab', "gcab",
'--create', "--create",
'firmware.cab', "firmware.cab",
'firmware.bin', "firmware.bin",
'firmware.metainfo.xml', "firmware.metainfo.xml",
] ]
subprocess.check_call(command) subprocess.check_call(command)
def main(args): def main(args):
with tempfile.TemporaryDirectory() as dir: with tempfile.TemporaryDirectory() as dir:
print('Using temp directory {}'.format(dir)) print("Using temp directory {}".format(dir))
if args.exe: if args.exe:
print('Extracting firmware exe') print("Extracting firmware exe")
extract_exe(args.exe, dir) extract_exe(args.exe, dir)
print('Locating firmware bin') print("Locating firmware bin")
get_firmware_bin(dir, args.bin, dir) get_firmware_bin(dir, args.bin, dir)
print('Creating metainfo') print("Creating metainfo")
make_firmware_metainfo(args, dir) make_firmware_metainfo(args, dir)
print('Creating cabinet file') print("Creating cabinet file")
create_firmware_cab(args, dir) create_firmware_cab(args, dir)
print('Done') print("Done")
shutil.copy(os.path.join(dir, 'firmware.cab'), args.out) shutil.copy(os.path.join(dir, "firmware.cab"), args.out)
if __name__ == '__main__': if __name__ == "__main__":
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description='Create fwupd packaged from windows executables' description="Create fwupd packaged from windows executables"
) )
parser.add_argument( parser.add_argument(
'--firmware-name', "--firmware-name",
help='Name of the firmware package can be customized (e.g. DellTBT)', help="Name of the firmware package can be customized (e.g. DellTBT)",
required=True, required=True,
) )
parser.add_argument( parser.add_argument(
'--firmware-summary', help='One line description of the firmware package' "--firmware-summary", help="One line description of the firmware package"
) )
parser.add_argument( parser.add_argument(
'--firmware-description', help='Longer description of the firmware package' "--firmware-description", help="Longer description of the firmware package"
) )
parser.add_argument( parser.add_argument(
'--device-guid', "--device-guid",
help='GUID of the device this firmware will run on, this *must* match the output of one of the GUIDs in `fwupdmgr get-devices`', help="GUID of the device this firmware will run on, this *must* match the output of one of the GUIDs in `fwupdmgr get-devices`",
required=True, required=True,
) )
parser.add_argument('--firmware-homepage', help='Website for the firmware provider') parser.add_argument("--firmware-homepage", help="Website for the firmware provider")
parser.add_argument( parser.add_argument(
'--contact-info', help='Email address of the firmware developer' "--contact-info", help="Email address of the firmware developer"
) )
parser.add_argument( parser.add_argument(
'--developer-name', help='Name of the firmware developer', required=True "--developer-name", help="Name of the firmware developer", required=True
) )
parser.add_argument( parser.add_argument(
'--release-version', "--release-version",
help='Version number of the firmware package', help="Version number of the firmware package",
required=True, required=True,
) )
parser.add_argument( parser.add_argument(
'--release-description', help='Description of the firmware release' "--release-description", help="Description of the firmware release"
) )
parser.add_argument( parser.add_argument(
'--exe', help='(optional) Executable file to extract firmware from' "--exe", help="(optional) Executable file to extract firmware from"
) )
parser.add_argument( parser.add_argument(
'--bin', "--bin",
help='Path to the .bin file (Relative if inside the executable; Absolute if outside) to use as the firmware image', help="Path to the .bin file (Relative if inside the executable; Absolute if outside) to use as the firmware image",
required=True, required=True,
) )
parser.add_argument('--out', help='Output cab file path', required=True) parser.add_argument("--out", help="Output cab file path", required=True)
args = parser.parse_args() args = parser.parse_args()
main(args) main(args)

View File

@ -11,7 +11,7 @@ import tempfile
import gi import gi
try: try:
gi.require_version('Fwupd', '2.0') gi.require_version("Fwupd", "2.0")
except ValueError: except ValueError:
print("Missing gobject-introspection packages. Try to install gir1.2-fwupd-2.0.") print("Missing gobject-introspection packages. Try to install gir1.2-fwupd-2.0.")
sys.exit(1) sys.exit(1)
@ -39,8 +39,8 @@ def parse_args():
import argparse import argparse
parser = argparse.ArgumentParser(description="Interact with fwupd daemon") parser = argparse.ArgumentParser(description="Interact with fwupd daemon")
parser.add_argument('exe', nargs='?', help='exe file') parser.add_argument("exe", nargs="?", help="exe file")
parser.add_argument('deviceid', nargs='?', help='DeviceID to operate on(optional)') parser.add_argument("deviceid", nargs="?", help="DeviceID to operate on(optional)")
args = parser.parse_args() args = parser.parse_args()
return args return args
@ -72,7 +72,7 @@ def find_uefi_device(client, deviceid):
if not item.has_flag(1 << 8): if not item.has_flag(1 << 8):
continue continue
# return the first hit for UEFI plugin # return the first hit for UEFI plugin
if item.get_plugin() == 'uefi' or item.get_plugin() == 'uefi_capsule': if item.get_plugin() == "uefi" or item.get_plugin() == "uefi_capsule":
print("Installing to %s" % item.get_name()) print("Installing to %s" % item.get_name())
return item.get_guid_default(), item.get_id(), item.get_version() return item.get_guid_default(), item.get_id(), item.get_version()
print("Couldn't find any UEFI devices") print("Couldn't find any UEFI devices")
@ -83,19 +83,19 @@ def prompt_reboot():
print("An update requires a reboot to complete") print("An update requires a reboot to complete")
while True: while True:
res = input("Restart now? (Y/N) ") res = input("Restart now? (Y/N) ")
if res.lower() == 'n': if res.lower() == "n":
print("Reboot your machine manually to finish the update.") print("Reboot your machine manually to finish the update.")
break break
if res.lower() != 'y': if res.lower() != "y":
continue continue
# reboot using logind # reboot using logind
obj = dbus.SystemBus().get_object( obj = dbus.SystemBus().get_object(
'org.freedesktop.login1', '/org/freedesktop/login1' "org.freedesktop.login1", "/org/freedesktop/login1"
) )
obj.Reboot(True, dbus_interface='org.freedesktop.login1.Manager') obj.Reboot(True, dbus_interface="org.freedesktop.login1.Manager")
if __name__ == '__main__': if __name__ == "__main__":
ARGS = parse_args() ARGS = parse_args()
CLIENT = Fwupd.Client() CLIENT = Fwupd.Client()
CLIENT.connect() CLIENT.connect()

View File

@ -6,7 +6,7 @@ import os
import gi import gi
from gi.repository import GLib from gi.repository import GLib
gi.require_version('Fwupd', '2.0') gi.require_version("Fwupd", "2.0")
from gi.repository import Fwupd # pylint: disable=wrong-import-position from gi.repository import Fwupd # pylint: disable=wrong-import-position
@ -35,14 +35,14 @@ class Progress:
status_str = "[" status_str = "["
for i in range(0, 50): for i in range(0, 50):
if i < percent / 2: if i < percent / 2:
status_str += '*' status_str += "*"
else: else:
status_str += ' ' status_str += " "
status_str += "] %d%% %s" % (percent, status) status_str += "] %d%% %s" % (percent, status)
self.erase = len(status_str) self.erase = len(status_str)
sys.stdout.write(status_str) sys.stdout.write(status_str)
sys.stdout.flush() sys.stdout.flush()
if 'idle' in status: if "idle" in status:
sys.stdout.write("\n") sys.stdout.write("\n")
@ -66,8 +66,8 @@ def parse_args():
choices=["get-devices", "get-details", "install", "refresh"], choices=["get-devices", "get-details", "install", "refresh"],
help="What to do", help="What to do",
) )
parser.add_argument('cab', nargs='?', help='CAB file') parser.add_argument("cab", nargs="?", help="CAB file")
parser.add_argument('deviceid', nargs='?', help='DeviceID to operate on(optional)') parser.add_argument("deviceid", nargs="?", help="DeviceID to operate on(optional)")
args = parser.parse_args() args = parser.parse_args()
return args return args
@ -114,7 +114,7 @@ def install(client, cab, target, older, reinstall):
"""Use fwupd client to install CAB file to applicable devices""" """Use fwupd client to install CAB file to applicable devices"""
# FWUPD_DEVICE_ID_ANY # FWUPD_DEVICE_ID_ANY
if not target: if not target:
target = '*' target = "*"
flags = Fwupd.InstallFlags.NONE flags = Fwupd.InstallFlags.NONE
if older: if older:
flags |= Fwupd.InstallFlags.ALLOW_OLDER flags |= Fwupd.InstallFlags.ALLOW_OLDER
@ -122,13 +122,13 @@ def install(client, cab, target, older, reinstall):
flags |= Fwupd.InstallFlags.ALLOW_REINSTALL flags |= Fwupd.InstallFlags.ALLOW_REINSTALL
progress = Progress() progress = Progress()
parent = super(client.__class__, client) parent = super(client.__class__, client)
parent.connect('device-changed', device_changed, progress) parent.connect("device-changed", device_changed, progress)
parent.connect('notify::percentage', status_changed, progress) parent.connect("notify::percentage", status_changed, progress)
parent.connect('notify::status', status_changed, progress) parent.connect("notify::status", status_changed, progress)
try: try:
client.install(target, cab, flags, None) client.install(target, cab, flags, None)
except GLib.Error as glib_err: # pylint: disable=catching-non-exception except GLib.Error as glib_err: # pylint: disable=catching-non-exception
progress.status_changed(0, 'idle') progress.status_changed(0, "idle")
print("%s" % glib_err) print("%s" % glib_err)
sys.exit(1) sys.exit(1)
print("\n") print("\n")
@ -144,7 +144,7 @@ def check_exists(cab):
sys.exit(1) sys.exit(1)
if __name__ == '__main__': if __name__ == "__main__":
ARGS = parse_args() ARGS = parse_args()
CLIENT = Fwupd.Client() CLIENT = Fwupd.Client()
CLIENT.connect() CLIENT.connect()

View File

@ -8,13 +8,13 @@ import subprocess
def _do_msgattrib(fn): def _do_msgattrib(fn):
argv = [ argv = [
'msgattrib', "msgattrib",
'--no-location', "--no-location",
'--translated', "--translated",
'--no-wrap', "--no-wrap",
'--sort-output', "--sort-output",
fn, fn,
'--output-file=' + fn, "--output-file=" + fn,
] ]
ret = subprocess.run(argv) ret = subprocess.run(argv)
if ret.returncode != 0: if ret.returncode != 0:
@ -33,7 +33,7 @@ def _do_nukeheader(fn):
if line.startswith('"Last-Translator:'): if line.startswith('"Last-Translator:'):
continue continue
clean_lines.append(line) clean_lines.append(line)
with open(fn, 'w') as f: with open(fn, "w") as f:
f.writelines(clean_lines) f.writelines(clean_lines)
@ -42,15 +42,15 @@ def _process_file(fn):
_do_nukeheader(fn) _do_nukeheader(fn)
if __name__ == '__main__': if __name__ == "__main__":
if len(sys.argv) == 1: if len(sys.argv) == 1:
print('path required') print("path required")
sys.exit(1) sys.exit(1)
try: try:
dirname = sys.argv[1] dirname = sys.argv[1]
for fn in os.listdir(dirname): for fn in os.listdir(dirname):
if fn.endswith('.po'): if fn.endswith(".po"):
_process_file(os.path.join(dirname, fn)) _process_file(os.path.join(dirname, fn))
except NotADirectoryError as _: except NotADirectoryError as _:
print('path required') print("path required")
sys.exit(2) sys.exit(2)

View File

@ -11,8 +11,8 @@ import xml.etree.ElementTree as ET
from pkg_resources import parse_version from pkg_resources import parse_version
XMLNS = '{http://www.gtk.org/introspection/core/1.0}' XMLNS = "{http://www.gtk.org/introspection/core/1.0}"
XMLNS_C = '{http://www.gtk.org/introspection/c/1.0}' XMLNS_C = "{http://www.gtk.org/introspection/c/1.0}"
def usage(return_code): def usage(return_code):
@ -34,15 +34,15 @@ class LdVersionScript:
self.overrides = {} self.overrides = {}
def _add_node(self, node): def _add_node(self, node):
identifier = node.attrib[XMLNS_C + 'identifier'] identifier = node.attrib[XMLNS_C + "identifier"]
introspectable = int(node.get('introspectable', 1)) introspectable = int(node.get("introspectable", 1))
version = node.get('version', None) version = node.get("version", None)
if introspectable and not version: if introspectable and not version:
print('No version for', identifier) print("No version for", identifier)
sys.exit(1) sys.exit(1)
if not version: if not version:
return None return None
version = node.attrib['version'] version = node.attrib["version"]
if version not in self.releases: if version not in self.releases:
self.releases[version] = [] self.releases[version] = []
release = self.releases[version] release = self.releases[version]
@ -53,14 +53,14 @@ class LdVersionScript:
def _add_cls(self, cls): def _add_cls(self, cls):
# add all class functions # add all class functions
for node in cls.findall(XMLNS + 'function'): for node in cls.findall(XMLNS + "function"):
self._add_node(node) self._add_node(node)
# choose the lowest version method for the _get_type symbol # choose the lowest version method for the _get_type symbol
version_lowest = None version_lowest = None
# add all class methods # add all class methods
for node in cls.findall(XMLNS + 'method'): for node in cls.findall(XMLNS + "method"):
version_tmp = self._add_node(node) version_tmp = self._add_node(node)
if version_tmp: if version_tmp:
if not version_lowest or parse_version(version_tmp) < parse_version( if not version_lowest or parse_version(version_tmp) < parse_version(
@ -69,7 +69,7 @@ class LdVersionScript:
version_lowest = version_tmp version_lowest = version_tmp
# add the constructor # add the constructor
for node in cls.findall(XMLNS + 'constructor'): for node in cls.findall(XMLNS + "constructor"):
version_tmp = self._add_node(node) version_tmp = self._add_node(node)
if version_tmp: if version_tmp:
if not version_lowest or parse_version(version_tmp) < parse_version( if not version_lowest or parse_version(version_tmp) < parse_version(
@ -77,9 +77,9 @@ class LdVersionScript:
): ):
version_lowest = version_tmp version_lowest = version_tmp
if '{http://www.gtk.org/introspection/glib/1.0}get-type' not in cls.attrib: if "{http://www.gtk.org/introspection/glib/1.0}get-type" not in cls.attrib:
return return
type_name = cls.attrib['{http://www.gtk.org/introspection/glib/1.0}get-type'] type_name = cls.attrib["{http://www.gtk.org/introspection/glib/1.0}get-type"]
# finally add the get_type symbol # finally add the get_type symbol
version = self.overrides.get(type_name, version_lowest) version = self.overrides.get(type_name, version_lowest)
@ -89,12 +89,12 @@ class LdVersionScript:
def import_gir(self, filename): def import_gir(self, filename):
tree = ET.parse(filename) tree = ET.parse(filename)
root = tree.getroot() root = tree.getroot()
for ns in root.findall(XMLNS + 'namespace'): for ns in root.findall(XMLNS + "namespace"):
for node in ns.findall(XMLNS + 'function'): for node in ns.findall(XMLNS + "function"):
self._add_node(node) self._add_node(node)
for cls in ns.findall(XMLNS + 'record'): for cls in ns.findall(XMLNS + "record"):
self._add_cls(cls) self._add_cls(cls)
for cls in ns.findall(XMLNS + 'class'): for cls in ns.findall(XMLNS + "class"):
self._add_cls(cls) self._add_cls(cls)
def render(self): def render(self):
@ -105,32 +105,28 @@ class LdVersionScript:
versions.append(version) versions.append(version)
# output the version data to a file # output the version data to a file
verout = '# generated automatically, do not edit!\n' verout = "# generated automatically, do not edit!\n"
oldversion = None oldversion = None
for version in sorted(versions, key=parse_version): for version in sorted(versions, key=parse_version):
symbols = sorted(self.releases[version]) symbols = sorted(self.releases[version])
verout += '\n%s_%s {\n' % (self.library_name, version) verout += "\n%s_%s {\n" % (self.library_name, version)
verout += ' global:\n' verout += " global:\n"
for symbol in symbols: for symbol in symbols:
verout += ' %s;\n' % symbol verout += " %s;\n" % symbol
verout += ' local: *;\n' verout += " local: *;\n"
if oldversion: if oldversion:
verout += '} %s_%s;\n' % (self.library_name, oldversion) verout += "} %s_%s;\n" % (self.library_name, oldversion)
else: else:
verout += '};\n' verout += "};\n"
oldversion = version oldversion = version
return verout return verout
if __name__ == '__main__': if __name__ == "__main__":
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument( parser.add_argument(
'-r', "-r", "--override", action="append", nargs=2, metavar=("symbol", "version")
'--override',
action='append',
nargs=2,
metavar=('symbol', 'version'),
) )
args, argv = parser.parse_known_args() args, argv = parser.parse_known_args()
if len(argv) != 3: if len(argv) != 3:
@ -141,4 +137,4 @@ if __name__ == '__main__':
for override_symbol, override_version in args.override: for override_symbol, override_version in args.override:
ld.overrides[override_symbol] = override_version ld.overrides[override_symbol] = override_version
ld.import_gir(argv[1]) ld.import_gir(argv[1])
open(argv[2], 'w').write(ld.render()) open(argv[2], "w").write(ld.render())

View File

@ -20,26 +20,14 @@ FWUPD_DOM0_DIR = "/root/.cache/fwupd"
FWUPD_DOM0_UPDATES_DIR = os.path.join(FWUPD_DOM0_DIR, "updates") FWUPD_DOM0_UPDATES_DIR = os.path.join(FWUPD_DOM0_DIR, "updates")
FWUPD_DOM0_UNTRUSTED_DIR = os.path.join(FWUPD_DOM0_UPDATES_DIR, "untrusted") FWUPD_DOM0_UNTRUSTED_DIR = os.path.join(FWUPD_DOM0_UPDATES_DIR, "untrusted")
FWUPD_DOM0_METADATA_DIR = os.path.join(FWUPD_DOM0_DIR, "metadata") FWUPD_DOM0_METADATA_DIR = os.path.join(FWUPD_DOM0_DIR, "metadata")
FWUPD_DOM0_METADATA_FILE = os.path.join( FWUPD_DOM0_METADATA_FILE = os.path.join(FWUPD_DOM0_METADATA_DIR, "firmware.xml.gz")
FWUPD_DOM0_METADATA_DIR, FWUPD_DOM0_METADATA_JCAT = os.path.join(FWUPD_DOM0_METADATA_DIR, "firmware.xml.gz.jcat")
"firmware.xml.gz"
)
FWUPD_DOM0_METADATA_JCAT = os.path.join(
FWUPD_DOM0_METADATA_DIR,
"firmware.xml.gz.jcat"
)
FWUPD_VM_DIR = "/home/user/.cache/fwupd" FWUPD_VM_DIR = "/home/user/.cache/fwupd"
FWUPD_VM_UPDATES_DIR = os.path.join(FWUPD_VM_DIR, "updates") FWUPD_VM_UPDATES_DIR = os.path.join(FWUPD_VM_DIR, "updates")
FWUPD_VM_METADATA_DIR = os.path.join(FWUPD_VM_DIR, "metadata") FWUPD_VM_METADATA_DIR = os.path.join(FWUPD_VM_DIR, "metadata")
FWUPD_VM_METADATA_FILE = os.path.join( FWUPD_VM_METADATA_FILE = os.path.join(FWUPD_VM_METADATA_DIR, "firmware.xml.gz")
FWUPD_VM_METADATA_DIR, FWUPD_VM_METADATA_JCAT = os.path.join(FWUPD_VM_METADATA_DIR, "firmware.xml.gz.jcat")
"firmware.xml.gz"
)
FWUPD_VM_METADATA_JCAT = os.path.join(
FWUPD_VM_METADATA_DIR,
"firmware.xml.gz.jcat"
)
FWUPD_PKI = "/etc/pki/fwupd" FWUPD_PKI = "/etc/pki/fwupd"
FWUPD_DOWNLOAD_PREFIX = "https://fwupd.org/downloads/" FWUPD_DOWNLOAD_PREFIX = "https://fwupd.org/downloads/"
FWUPD_METADATA_FLAG_REGEX = re.compile(r"^metaflag") FWUPD_METADATA_FLAG_REGEX = re.compile(r"^metaflag")
@ -47,7 +35,7 @@ FWUPD_METADATA_FILES_REGEX = re.compile(
r"^firmware[a-z0-9\[\]\@\<\>\.\"\-]{0,128}.xml.gz.?[aj]?[sc]?[ca]?t?$" r"^firmware[a-z0-9\[\]\@\<\>\.\"\-]{0,128}.xml.gz.?[aj]?[sc]?[ca]?t?$"
) )
HEADS_UPDATES_DIR = "/boot/updates" HEADS_UPDATES_DIR = "/boot/updates"
WARNING_COLOR = '\033[93m' WARNING_COLOR = "\033[93m"
class FwupdReceiveUpdates: class FwupdReceiveUpdates:
@ -58,7 +46,7 @@ class FwupdReceiveUpdates:
file_path -- absolute path to the file file_path -- absolute path to the file
sha -- SHA256 checksum of the file sha -- SHA256 checksum of the file
""" """
with open(file_path, 'rb') as f: with open(file_path, "rb") as f:
c_sha = hashlib.sha256(f.read()).hexdigest() c_sha = hashlib.sha256(f.read()).hexdigest()
if c_sha != sha: if c_sha != sha:
self.clean_cache() self.clean_cache()
@ -71,13 +59,11 @@ class FwupdReceiveUpdates:
Keyword argument: Keyword argument:
updatevm - domain to be checked updatevm - domain to be checked
""" """
cmd = ['qubes-prefs', '--force-root', 'updatevm'] cmd = ["qubes-prefs", "--force-root", "updatevm"]
p = subprocess.check_output(cmd) p = subprocess.check_output(cmd)
source = p.decode('ascii').rstrip() source = p.decode("ascii").rstrip()
if source != updatevm and "sys-whonix" != updatevm: if source != updatevm and "sys-whonix" != updatevm:
raise Exception( raise Exception(f"Domain {updatevm} not allowed to send dom0 updates")
f'Domain {updatevm} not allowed to send dom0 updates'
)
def _verify_received(self, files_path, regex_pattern, updatevm): def _verify_received(self, files_path, regex_pattern, updatevm):
"""Checks if sent files match regex filename pattern. """Checks if sent files match regex filename pattern.
@ -90,14 +76,14 @@ class FwupdReceiveUpdates:
""" """
for untrusted_f in os.listdir(files_path): for untrusted_f in os.listdir(files_path):
if not regex_pattern.match(untrusted_f): if not regex_pattern.match(untrusted_f):
raise Exception(f'Domain {updatevm} sent unexpected file') raise Exception(f"Domain {updatevm} sent unexpected file")
f = untrusted_f f = untrusted_f
assert '/' not in f assert "/" not in f
assert '\0' not in f assert "\0" not in f
assert '\x1b' not in f assert "\x1b" not in f
path_f = os.path.join(files_path, f) path_f = os.path.join(files_path, f)
if os.path.islink(path_f) or not os.path.isfile(path_f): if os.path.islink(path_f) or not os.path.isfile(path_f):
raise Exception(f'Domain {updatevm} sent not regular file') raise Exception(f"Domain {updatevm} sent not regular file")
def _create_dirs(self, *args): def _create_dirs(self, *args):
"""Method creates directories. """Method creates directories.
@ -105,7 +91,7 @@ class FwupdReceiveUpdates:
Keyword arguments: Keyword arguments:
*args -- paths to be created *args -- paths to be created
""" """
qubes_gid = grp.getgrnam('qubes').gr_gid qubes_gid = grp.getgrnam("qubes").gr_gid
self.old_umask = os.umask(0o002) self.old_umask = os.umask(0o002)
if args is None: if args is None:
raise Exception("Creating directories failed, no paths given.") raise Exception("Creating directories failed, no paths given.")
@ -128,19 +114,12 @@ class FwupdReceiveUpdates:
archive_path -- absolute path to archive file archive_path -- absolute path to archive file
output_path -- absolute path to the output directory output_path -- absolute path to the output directory
""" """
cmd_extract = [ cmd_extract = ["gcab", "-x", f"--directory={output_path}", f"{archive_path}"]
"gcab",
"-x",
f"--directory={output_path}",
f"{archive_path}"
]
shutil.copy(archive_path, FWUPD_DOM0_UPDATES_DIR) shutil.copy(archive_path, FWUPD_DOM0_UPDATES_DIR)
p = subprocess.Popen(cmd_extract, stdout=subprocess.PIPE) p = subprocess.Popen(cmd_extract, stdout=subprocess.PIPE)
p.communicate()[0].decode('ascii') p.communicate()[0].decode("ascii")
if p.returncode != 0: if p.returncode != 0:
raise Exception( raise Exception(f"gcab: Error while extracting {archive_path}.")
f'gcab: Error while extracting {archive_path}.'
)
def _jcat_verification(self, file_path, file_directory): def _jcat_verification(self, file_path, file_directory):
"""Verifies sha1 and sha256 checksum, GPG signature, """Verifies sha1 and sha256 checksum, GPG signature,
@ -150,25 +129,16 @@ class FwupdReceiveUpdates:
file_path -- absolute path to jcat file file_path -- absolute path to jcat file
file_directory -- absolute path to the directory to jcat file location file_directory -- absolute path to the directory to jcat file location
""" """
cmd_jcat = [ cmd_jcat = ["jcat-tool", "verify", f"{file_path}", "--public-keys", FWUPD_PKI]
"jcat-tool",
"verify",
f"{file_path}",
"--public-keys",
FWUPD_PKI
]
p = subprocess.Popen( p = subprocess.Popen(
cmd_jcat, cmd_jcat, cwd=file_directory, stdout=subprocess.PIPE, stderr=subprocess.PIPE
cwd=file_directory,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
) )
stdout, __ = p.communicate() stdout, __ = p.communicate()
verification = stdout.decode('utf-8') verification = stdout.decode("utf-8")
print(verification) print(verification)
if p.returncode != 0: if p.returncode != 0:
self.clean_cache() self.clean_cache()
raise Exception('jcat-tool: Verification failed') raise Exception("jcat-tool: Verification failed")
def handle_fw_update(self, updatevm, sha, filename): def handle_fw_update(self, updatevm, sha, filename):
"""Copies firmware update archives from the updateVM. """Copies firmware update archives from the updateVM.
@ -179,45 +149,31 @@ class FwupdReceiveUpdates:
filename -- name of the firmware update archive filename -- name of the firmware update archive
""" """
fwupd_firmware_file_regex = re.compile(filename) fwupd_firmware_file_regex = re.compile(filename)
dom0_firmware_untrusted_path = os.path.join( dom0_firmware_untrusted_path = os.path.join(FWUPD_DOM0_UNTRUSTED_DIR, filename)
FWUPD_DOM0_UNTRUSTED_DIR, updatevm_firmware_file_path = os.path.join(FWUPD_VM_UPDATES_DIR, filename)
filename
)
updatevm_firmware_file_path = os.path.join(
FWUPD_VM_UPDATES_DIR,
filename
)
self._check_domain(updatevm) self._check_domain(updatevm)
if os.path.exists(FWUPD_DOM0_UNTRUSTED_DIR): if os.path.exists(FWUPD_DOM0_UNTRUSTED_DIR):
shutil.rmtree(FWUPD_DOM0_UNTRUSTED_DIR) shutil.rmtree(FWUPD_DOM0_UNTRUSTED_DIR)
self._create_dirs(FWUPD_DOM0_UPDATES_DIR, FWUPD_DOM0_UNTRUSTED_DIR) self._create_dirs(FWUPD_DOM0_UPDATES_DIR, FWUPD_DOM0_UNTRUSTED_DIR)
cmd_copy = 'qvm-run --pass-io %s %s > %s' % ( cmd_copy = "qvm-run --pass-io %s %s > %s" % (
updatevm, updatevm,
"'cat %s'" % updatevm_firmware_file_path, "'cat %s'" % updatevm_firmware_file_path,
dom0_firmware_untrusted_path dom0_firmware_untrusted_path,
) )
p = subprocess.Popen(cmd_copy, shell=True) p = subprocess.Popen(cmd_copy, shell=True)
p.wait() p.wait()
if p.returncode != 0: if p.returncode != 0:
raise Exception('qvm-run: Copying firmware file failed!!') raise Exception("qvm-run: Copying firmware file failed!!")
self._verify_received( self._verify_received(
FWUPD_DOM0_UNTRUSTED_DIR, FWUPD_DOM0_UNTRUSTED_DIR, fwupd_firmware_file_regex, updatevm
fwupd_firmware_file_regex,
updatevm
) )
self._check_shasum(dom0_firmware_untrusted_path, sha) self._check_shasum(dom0_firmware_untrusted_path, sha)
untrusted_dir_name = filename.replace(".cab", "") untrusted_dir_name = filename.replace(".cab", "")
self._extract_archive( self._extract_archive(dom0_firmware_untrusted_path, FWUPD_DOM0_UNTRUSTED_DIR)
dom0_firmware_untrusted_path, signature_name = os.path.join(FWUPD_DOM0_UNTRUSTED_DIR, "firmware*.jcat")
FWUPD_DOM0_UNTRUSTED_DIR
)
signature_name = os.path.join(
FWUPD_DOM0_UNTRUSTED_DIR,
"firmware*.jcat"
)
file_path = glob.glob(signature_name) file_path = glob.glob(signature_name)
if not file_path: if not file_path:
raise FileNotFoundError("jcat file not found!") raise FileNotFoundError("jcat file not found!")
@ -227,10 +183,7 @@ class FwupdReceiveUpdates:
untrusted_dir_name = "trusted" untrusted_dir_name = "trusted"
verified_file = os.path.join(FWUPD_DOM0_UPDATES_DIR, filename) verified_file = os.path.join(FWUPD_DOM0_UPDATES_DIR, filename)
self.arch_name = "trusted.cab" self.arch_name = "trusted.cab"
self.arch_path = os.path.join( self.arch_path = os.path.join(FWUPD_DOM0_UPDATES_DIR, self.arch_name)
FWUPD_DOM0_UPDATES_DIR,
self.arch_name
)
shutil.move(verified_file, self.arch_path) shutil.move(verified_file, self.arch_path)
else: else:
self.arch_path = os.path.join(FWUPD_DOM0_UPDATES_DIR, filename) self.arch_path = os.path.join(FWUPD_DOM0_UPDATES_DIR, filename)
@ -245,59 +198,46 @@ class FwupdReceiveUpdates:
updatevm -- update VM name updatevm -- update VM name
""" """
if metadata_url: if metadata_url:
metadata_name = metadata_url.replace( metadata_name = metadata_url.replace(FWUPD_DOWNLOAD_PREFIX, "")
FWUPD_DOWNLOAD_PREFIX, self.metadata_file = os.path.join(FWUPD_DOM0_METADATA_DIR, metadata_name)
"" self.metadata_file_jcat = self.metadata_file + ".jcat"
)
self.metadata_file = os.path.join(
FWUPD_DOM0_METADATA_DIR,
metadata_name
)
self.metadata_file_jcat = self.metadata_file + '.jcat'
else: else:
self.metadata_file = FWUPD_DOM0_METADATA_FILE self.metadata_file = FWUPD_DOM0_METADATA_FILE
self.metadata_file_jcat = FWUPD_DOM0_METADATA_JCAT self.metadata_file_jcat = FWUPD_DOM0_METADATA_JCAT
self.metadata_file_updatevm = self.metadata_file.replace( self.metadata_file_updatevm = self.metadata_file.replace(
FWUPD_DOM0_METADATA_DIR, FWUPD_DOM0_METADATA_DIR, FWUPD_VM_METADATA_DIR
FWUPD_VM_METADATA_DIR
) )
self.metadata_file_jcat_updatevm = self.metadata_file_jcat.replace( self.metadata_file_jcat_updatevm = self.metadata_file_jcat.replace(
FWUPD_DOM0_METADATA_DIR, FWUPD_DOM0_METADATA_DIR, FWUPD_VM_METADATA_DIR
FWUPD_VM_METADATA_DIR
) )
self._check_domain(updatevm) self._check_domain(updatevm)
self._create_dirs(FWUPD_DOM0_METADATA_DIR) self._create_dirs(FWUPD_DOM0_METADATA_DIR)
cmd_file = "'cat %s'" % self.metadata_file_updatevm cmd_file = "'cat %s'" % self.metadata_file_updatevm
cmd_jcat = "'cat %s'" % self.metadata_file_jcat_updatevm cmd_jcat = "'cat %s'" % self.metadata_file_jcat_updatevm
cmd_copy_metadata_file = 'qvm-run --pass-io %s %s > %s' % ( cmd_copy_metadata_file = "qvm-run --pass-io %s %s > %s" % (
updatevm, updatevm,
cmd_file, cmd_file,
self.metadata_file self.metadata_file,
) )
cmd_copy_metadata_jcat = 'qvm-run --pass-io %s %s > %s' % ( cmd_copy_metadata_jcat = "qvm-run --pass-io %s %s > %s" % (
updatevm, updatevm,
cmd_jcat, cmd_jcat,
self.metadata_file_jcat self.metadata_file_jcat,
) )
p = subprocess.Popen(cmd_copy_metadata_file, shell=True) p = subprocess.Popen(cmd_copy_metadata_file, shell=True)
p.wait() p.wait()
if p.returncode != 0: if p.returncode != 0:
raise Exception('qvm-run: Copying metadata file failed!!') raise Exception("qvm-run: Copying metadata file failed!!")
p = subprocess.Popen(cmd_copy_metadata_jcat, shell=True) p = subprocess.Popen(cmd_copy_metadata_jcat, shell=True)
p.wait() p.wait()
if p.returncode != 0: if p.returncode != 0:
raise Exception('qvm-run": Copying metadata jcat failed!!') raise Exception('qvm-run": Copying metadata jcat failed!!')
self._verify_received( self._verify_received(
FWUPD_DOM0_METADATA_DIR, FWUPD_DOM0_METADATA_DIR, FWUPD_METADATA_FILES_REGEX, updatevm
FWUPD_METADATA_FILES_REGEX,
updatevm
)
self._jcat_verification(
self.metadata_file_jcat,
FWUPD_DOM0_METADATA_DIR
) )
self._jcat_verification(self.metadata_file_jcat, FWUPD_DOM0_METADATA_DIR)
os.umask(self.old_umask) os.umask(self.old_umask)
def clean_cache(self, usbvm=False): def clean_cache(self, usbvm=False):

View File

@ -18,20 +18,13 @@ FWUPDTOOL = "/bin/fwupdtool"
BOOT = "/boot" BOOT = "/boot"
HEADS_UPDATES_DIR = os.path.join(BOOT, "updates") HEADS_UPDATES_DIR = os.path.join(BOOT, "updates")
EXIT_CODES = { EXIT_CODES = {"ERROR": 1, "SUCCESS": 0, "NOTHING_TO_DO": 2}
"ERROR": 1,
"SUCCESS": 0,
"NOTHING_TO_DO": 2,
}
class FwupdHeads: class FwupdHeads:
def _get_hwids(self): def _get_hwids(self):
cmd_hwids = [FWUPDTOOL, "hwids"] cmd_hwids = [FWUPDTOOL, "hwids"]
p = subprocess.Popen( p = subprocess.Popen(cmd_hwids, stdout=subprocess.PIPE)
cmd_hwids,
stdout=subprocess.PIPE
)
self.dom0_hwids_info = p.communicate()[0].decode() self.dom0_hwids_info = p.communicate()[0].decode()
if p.returncode != 0: if p.returncode != 0:
raise Exception("fwudp-qubes: Getting hwids info failed") raise Exception("fwudp-qubes: Getting hwids info failed")
@ -46,12 +39,8 @@ class FwupdHeads:
for line in hwids: for line in hwids:
if line.startswith("BiosVersion: CBET4000 "): if line.startswith("BiosVersion: CBET4000 "):
self.heads_version = line.replace( self.heads_version = line.replace(
"BiosVersion: CBET4000 ", "BiosVersion: CBET4000 ", ""
"" ).replace(" heads", "")
).replace(
" heads",
""
)
else: else:
print("Device is not running under the heads firmware!!") print("Device is not running under the heads firmware!!")
print("Exiting...") print("Exiting...")
@ -62,10 +51,7 @@ class FwupdHeads:
Parse metadata info. Parse metadata info.
""" """
cmd_metadata = ["zcat", metadata_file] cmd_metadata = ["zcat", metadata_file]
p = subprocess.Popen( p = subprocess.Popen(cmd_metadata, stdout=subprocess.PIPE)
cmd_metadata,
stdout=subprocess.PIPE
)
self.metadata_info = p.communicate()[0].decode() self.metadata_info = p.communicate()[0].decode()
if p.returncode != 0: if p.returncode != 0:
raise Exception("fwudp-qubes: Parsing metadata failed") raise Exception("fwudp-qubes: Parsing metadata failed")
@ -90,14 +76,18 @@ class FwupdHeads:
return EXIT_CODES["NOTHING_TO_DO"] return EXIT_CODES["NOTHING_TO_DO"]
for release in heads_metadata_info.find("releases").findall("release"): for release in heads_metadata_info.find("releases").findall("release"):
release_ver = release.get("version") release_ver = release.get("version")
if (self.heads_version == "heads" or if self.heads_version == "heads" or l_ver(release_ver) > l_ver(
l_ver(release_ver) > l_ver(self.heads_version)): self.heads_version
if (not self.heads_update_version or ):
l_ver(release_ver) > l_ver(self.heads_update_version)): if not self.heads_update_version or l_ver(release_ver) > l_ver(
self.heads_update_version
):
self.heads_update_url = release.find("location").text self.heads_update_url = release.find("location").text
for sha in release.findall("checksum"): for sha in release.findall("checksum"):
if (".cab" in sha.attrib["filename"] if (
and sha.attrib["type"] == "sha256"): ".cab" in sha.attrib["filename"]
and sha.attrib["type"] == "sha256"
):
self.heads_update_sha = sha.text self.heads_update_sha = sha.text
self.heads_update_version = release_ver self.heads_update_version = release_ver
if self.heads_update_url: if self.heads_update_url:
@ -110,23 +100,14 @@ class FwupdHeads:
""" """
Copies heads update to the boot path Copies heads update to the boot path
""" """
heads_boot_path = os.path.join( heads_boot_path = os.path.join(HEADS_UPDATES_DIR, self.heads_update_version)
HEADS_UPDATES_DIR,
self.heads_update_version
)
update_path = arch_path.replace(".cab", "/firmware.rom") update_path = arch_path.replace(".cab", "/firmware.rom")
heads_update_path = os.path.join( heads_update_path = os.path.join(heads_boot_path, "firmware.rom")
heads_boot_path,
"firmware.rom"
)
if not os.path.exists(HEADS_UPDATES_DIR): if not os.path.exists(HEADS_UPDATES_DIR):
os.mkdir(HEADS_UPDATES_DIR) os.mkdir(HEADS_UPDATES_DIR)
if os.path.exists(heads_update_path): if os.path.exists(heads_update_path):
print( print(f"Heads Update == {self.heads_update_version} " "already downloaded.")
f"Heads Update == {self.heads_update_version} "
"already downloaded."
)
return EXIT_CODES["NOTHING_TO_DO"] return EXIT_CODES["NOTHING_TO_DO"]
else: else:
os.mkdir(heads_boot_path) os.mkdir(heads_boot_path)

View File

@ -17,10 +17,10 @@ FWUPD_VM_DOWNLOAD = "/usr/libexec/qubes-fwupd/fwupd_download_updates.py"
FWUPD_DOM0_UPDATES_DIR = os.path.join(FWUPD_DOM0_DIR, "updates") FWUPD_DOM0_UPDATES_DIR = os.path.join(FWUPD_DOM0_DIR, "updates")
FWUPD_DOWNLOAD_PREFIX = "https://fwupd.org/downloads/" FWUPD_DOWNLOAD_PREFIX = "https://fwupd.org/downloads/"
SPECIAL_CHAR_REGEX = re.compile(r'%20|&|\||#') SPECIAL_CHAR_REGEX = re.compile(r"%20|&|\||#")
UPDATEVM_REGEX = re.compile(r'^sys-') UPDATEVM_REGEX = re.compile(r"^sys-")
WARNING_COLOR = '\033[93m' WARNING_COLOR = "\033[93m"
class FwupdUpdate: class FwupdUpdate:
@ -30,7 +30,7 @@ class FwupdUpdate:
Keyword arguments: Keyword arguments:
*args -- paths to be created *args -- paths to be created
""" """
qubes_gid = grp.getgrnam('qubes').gr_gid qubes_gid = grp.getgrnam("qubes").gr_gid
self.old_umask = os.umask(0o002) self.old_umask = os.umask(0o002)
if args is None: if args is None:
raise Exception("Creating directories failed, no paths given.") raise Exception("Creating directories failed, no paths given.")
@ -46,15 +46,8 @@ class FwupdUpdate:
) )
def _specify_updatevm(self): def _specify_updatevm(self):
cmd_updatevm = [ cmd_updatevm = ["qubes-prefs", "--force-root", "updatevm"]
"qubes-prefs", p = subprocess.Popen(cmd_updatevm, stdout=subprocess.PIPE)
"--force-root",
"updatevm",
]
p = subprocess.Popen(
cmd_updatevm,
stdout=subprocess.PIPE
)
self.updatevm = p.communicate()[0].decode().split("\n")[0] self.updatevm = p.communicate()[0].decode().split("\n")[0]
if p.returncode != 0 and not UPDATEVM_REGEX.match(self.updatevm): if p.returncode != 0 and not UPDATEVM_REGEX.match(self.updatevm):
self.updatevm = None self.updatevm = None
@ -62,14 +55,8 @@ class FwupdUpdate:
def _check_updatevm(self): def _check_updatevm(self):
"""Checks if usbvm is running""" """Checks if usbvm is running"""
cmd_xl_list = [ cmd_xl_list = ["xl", "list"]
"xl", p = subprocess.Popen(cmd_xl_list, stdout=subprocess.PIPE)
"list"
]
p = subprocess.Popen(
cmd_xl_list,
stdout=subprocess.PIPE
)
output = p.communicate()[0].decode() output = p.communicate()[0].decode()
if p.returncode != 0: if p.returncode != 0:
raise Exception("fwudp-qubes: Firmware downgrade failed") raise Exception("fwudp-qubes: Firmware downgrade failed")
@ -112,10 +99,10 @@ class FwupdUpdate:
"--pass-io", "--pass-io",
self.updatevm, self.updatevm,
( (
'script --quiet --return --command ' "script --quiet --return --command "
f'"{FWUPD_VM_DOWNLOAD} --metadata' f'"{FWUPD_VM_DOWNLOAD} --metadata'
f' --url={metadata_url}"' f' --url={metadata_url}"'
) ),
] ]
else: else:
cmd_metadata = [ cmd_metadata = [
@ -123,9 +110,9 @@ class FwupdUpdate:
"--pass-io", "--pass-io",
self.updatevm, self.updatevm,
( (
'script --quiet --return --command ' "script --quiet --return --command "
f'"{FWUPD_VM_DOWNLOAD} --metadata"' f'"{FWUPD_VM_DOWNLOAD} --metadata"'
) ),
] ]
p = subprocess.Popen(cmd_metadata) p = subprocess.Popen(cmd_metadata)
p.wait() p.wait()
@ -155,10 +142,10 @@ class FwupdUpdate:
"--pass-io", "--pass-io",
self.updatevm, self.updatevm,
( (
'script --quiet --return --command ' "script --quiet --return --command "
f'"{FWUPD_VM_DOWNLOAD} --url={self.enc_url}' f'"{FWUPD_VM_DOWNLOAD} --url={self.enc_url}'
f' --sha={sha}"' f' --sha={sha}"'
) ),
] ]
p = subprocess.Popen(cmd_firmware_download) p = subprocess.Popen(cmd_firmware_download)
p.wait() p.wait()

View File

@ -32,42 +32,25 @@ try:
from fwupd_receive_updates import FwupdReceiveUpdates from fwupd_receive_updates import FwupdReceiveUpdates
except ModuleNotFoundError: except ModuleNotFoundError:
raise ModuleNotFoundError( raise ModuleNotFoundError(
"qubes-fwupd modules not found. " "qubes-fwupd modules not found. " "You may need to reinstall package."
"You may need to reinstall package."
) )
FWUPD_DOM0_DIR = "/root/.cache/fwupd" FWUPD_DOM0_DIR = "/root/.cache/fwupd"
FWUPD_DOM0_METADATA_DIR = os.path.join(FWUPD_DOM0_DIR, "metadata") FWUPD_DOM0_METADATA_DIR = os.path.join(FWUPD_DOM0_DIR, "metadata")
FWUPD_DOM0_UPDATES_DIR = os.path.join(FWUPD_DOM0_DIR, "updates") FWUPD_DOM0_UPDATES_DIR = os.path.join(FWUPD_DOM0_DIR, "updates")
FWUPD_DOM0_METADATA_SIGNATURE = os.path.join( FWUPD_DOM0_METADATA_SIGNATURE = os.path.join(
FWUPD_DOM0_METADATA_DIR, FWUPD_DOM0_METADATA_DIR, "firmware.xml.gz.asc"
"firmware.xml.gz.asc"
)
FWUPD_DOM0_METADATA_FILE = os.path.join(
FWUPD_DOM0_METADATA_DIR,
"firmware.xml.gz"
)
FWUPD_DOM0_METADATA_JCAT = os.path.join(
FWUPD_DOM0_METADATA_DIR,
"firmware.xml.gz.jcat"
) )
FWUPD_DOM0_METADATA_FILE = os.path.join(FWUPD_DOM0_METADATA_DIR, "firmware.xml.gz")
FWUPD_DOM0_METADATA_JCAT = os.path.join(FWUPD_DOM0_METADATA_DIR, "firmware.xml.gz.jcat")
FWUPD_VM_LOG = os.path.join(FWUPD_DOM0_DIR, "usbvm-devices.log") FWUPD_VM_LOG = os.path.join(FWUPD_DOM0_DIR, "usbvm-devices.log")
FWUPD_VM_VALIDATE = "/usr/libexec/qubes-fwupd/fwupd_usbvm_validate.py" FWUPD_VM_VALIDATE = "/usr/libexec/qubes-fwupd/fwupd_usbvm_validate.py"
FWUPD_VM_DIR = "/home/user/.cache/fwupd" FWUPD_VM_DIR = "/home/user/.cache/fwupd"
FWUPD_VM_UPDATES_DIR = os.path.join(FWUPD_VM_DIR, "updates") FWUPD_VM_UPDATES_DIR = os.path.join(FWUPD_VM_DIR, "updates")
FWUPD_VM_METADATA_DIR = os.path.join(FWUPD_VM_DIR, "metadata") FWUPD_VM_METADATA_DIR = os.path.join(FWUPD_VM_DIR, "metadata")
FWUPD_VM_METADATA_SIGNATURE = os.path.join( FWUPD_VM_METADATA_SIGNATURE = os.path.join(FWUPD_VM_METADATA_DIR, "firmware.xml.gz.asc")
FWUPD_VM_METADATA_DIR, FWUPD_VM_METADATA_FILE = os.path.join(FWUPD_VM_METADATA_DIR, "firmware.xml.gz")
"firmware.xml.gz.asc" FWUPD_VM_METADATA_JCAT = os.path.join(FWUPD_VM_METADATA_DIR, "firmware.xml.gz.jcat")
)
FWUPD_VM_METADATA_FILE = os.path.join(
FWUPD_VM_METADATA_DIR,
"firmware.xml.gz"
)
FWUPD_VM_METADATA_JCAT = os.path.join(
FWUPD_VM_METADATA_DIR,
"firmware.xml.gz.jcat"
)
FWUPD_DOWNLOAD_PREFIX = "https://fwupd.org/downloads/" FWUPD_DOWNLOAD_PREFIX = "https://fwupd.org/downloads/"
FWUPDMGR = "/bin/fwupdmgr" FWUPDMGR = "/bin/fwupdmgr"
@ -78,11 +61,9 @@ USBVM_N = "sys-usb"
BIOS_UPDATE_FLAG = os.path.join(FWUPD_DOM0_DIR, "bios_update") BIOS_UPDATE_FLAG = os.path.join(FWUPD_DOM0_DIR, "bios_update")
LVFS_TESTING_DOM0_FLAG = os.path.join(FWUPD_DOM0_DIR, "lvfs_testing") LVFS_TESTING_DOM0_FLAG = os.path.join(FWUPD_DOM0_DIR, "lvfs_testing")
LVFS_TESTING_USBVM_FLAG = os.path.join(FWUPD_VM_DIR, "lvfs_testing") LVFS_TESTING_USBVM_FLAG = os.path.join(FWUPD_VM_DIR, "lvfs_testing")
METADATA_REFRESH_REGEX = re.compile( METADATA_REFRESH_REGEX = re.compile(r"^Successfully refreshed metadata manually$")
r"^Successfully refreshed metadata manually$"
)
SPECIAL_CHAR_REGEX = re.compile(r'%20|&|\||#') SPECIAL_CHAR_REGEX = re.compile(r"%20|&|\||#")
HELP = { HELP = {
@ -100,28 +81,20 @@ HELP = {
"update": "Update chosen device to latest firmware version", "update": "Update chosen device to latest firmware version",
"update-heads": "Updates heads firmware to the latest version", "update-heads": "Updates heads firmware to the latest version",
"downgrade": "Downgrade chosen device to chosen firmware version", "downgrade": "Downgrade chosen device to chosen firmware version",
"clean": "Delete all cached update files\n" "clean": "Delete all cached update files\n",
} }
], ],
"Flags": [ "Flags": [
{ {
"--whonix": "Download firmware updates via Tor", "--whonix": "Download firmware updates via Tor",
"--device": "Specify device for heads update (default - x230)", "--device": "Specify device for heads update (default - x230)",
"--url": "Address of the custom metadata remote server\n" "--url": "Address of the custom metadata remote server\n",
}
],
"Help": [
{
"-h --help": "Show help options\n"
} }
], ],
"Help": [{"-h --help": "Show help options\n"}],
} }
EXIT_CODES = { EXIT_CODES = {"ERROR": 1, "SUCCESS": 0, "NOTHING_TO_DO": 2}
"ERROR": 1,
"SUCCESS": 0,
"NOTHING_TO_DO": 2,
}
class QubesFwupdmgr(FwupdHeads, FwupdUpdate, FwupdReceiveUpdates): class QubesFwupdmgr(FwupdHeads, FwupdUpdate, FwupdReceiveUpdates):
@ -143,7 +116,7 @@ class QubesFwupdmgr(FwupdHeads, FwupdUpdate, FwupdReceiveUpdates):
"qvm-run", "qvm-run",
"--pass-io", "--pass-io",
USBVM_N, USBVM_N,
f'script --quiet --return --command "{FWUPD_VM_VALIDATE} dirs"' f'script --quiet --return --command "{FWUPD_VM_VALIDATE} dirs"',
] ]
p = subprocess.Popen(cmd_validate_dirs) p = subprocess.Popen(cmd_validate_dirs)
p.wait() p.wait()
@ -158,7 +131,7 @@ class QubesFwupdmgr(FwupdHeads, FwupdUpdate, FwupdReceiveUpdates):
"qvm-run", "qvm-run",
"--pass-io", "--pass-io",
USBVM_N, USBVM_N,
f'script --quiet --return --command "{arch_validate}"' f'script --quiet --return --command "{arch_validate}"',
] ]
p = subprocess.Popen(cmd_validate_arch) p = subprocess.Popen(cmd_validate_arch)
p.wait() p.wait()
@ -168,18 +141,17 @@ class QubesFwupdmgr(FwupdHeads, FwupdUpdate, FwupdReceiveUpdates):
def _copy_usbvm_metadata(self): def _copy_usbvm_metadata(self):
"""Copies metadata files to usbvm.""" """Copies metadata files to usbvm."""
self.metadata_file_usbvm = self.metadata_file.replace( self.metadata_file_usbvm = self.metadata_file.replace(
FWUPD_DOM0_METADATA_DIR, FWUPD_DOM0_METADATA_DIR, FWUPD_VM_METADATA_DIR
FWUPD_VM_METADATA_DIR
) )
self.metadata_file_jcat_usbvm = self.metadata_file_usbvm + ".jcat" self.metadata_file_jcat_usbvm = self.metadata_file_usbvm + ".jcat"
cat_file = f"cat > {self.metadata_file_usbvm}" cat_file = f"cat > {self.metadata_file_usbvm}"
cmd_copy_file = ( cmd_copy_file = (
f'cat {self.metadata_file} | ' f"cat {self.metadata_file} | "
f'qvm-run --nogui --pass-io {USBVM_N} "{cat_file}"' f'qvm-run --nogui --pass-io {USBVM_N} "{cat_file}"'
) )
cat_jcat = f"cat > {self.metadata_file_jcat_usbvm}" cat_jcat = f"cat > {self.metadata_file_jcat_usbvm}"
cmd_copy_jcat = ( cmd_copy_jcat = (
f'cat {self.metadata_file_jcat} | ' f"cat {self.metadata_file_jcat} | "
f'qvm-run --nogui --pass-io {USBVM_N} "{cat_jcat}"' f'qvm-run --nogui --pass-io {USBVM_N} "{cat_jcat}"'
) )
p = subprocess.Popen(cmd_copy_file, shell=True) p = subprocess.Popen(cmd_copy_file, shell=True)
@ -195,15 +167,12 @@ class QubesFwupdmgr(FwupdHeads, FwupdUpdate, FwupdReceiveUpdates):
"""Checks GPG signature of metadata files in usbvm.""" """Checks GPG signature of metadata files in usbvm."""
usbvm_cmd = f'"{FWUPD_VM_VALIDATE} metadata"' usbvm_cmd = f'"{FWUPD_VM_VALIDATE} metadata"'
if metadata_url: if metadata_url:
usbvm_cmd = ( usbvm_cmd = f'"{FWUPD_VM_VALIDATE} metadata --url={metadata_url}"'
f'"{FWUPD_VM_VALIDATE} metadata --url={metadata_url}"'
)
cmd_validate_metadata = [ cmd_validate_metadata = [
"qvm-run", "qvm-run",
"--pass-io", "--pass-io",
USBVM_N, USBVM_N,
'script --quiet --return --command' "script --quiet --return --command" f" {usbvm_cmd}",
f' {usbvm_cmd}'
] ]
p = subprocess.Popen(cmd_validate_metadata) p = subprocess.Popen(cmd_validate_metadata)
p.wait() p.wait()
@ -218,10 +187,10 @@ class QubesFwupdmgr(FwupdHeads, FwupdUpdate, FwupdReceiveUpdates):
"--pass-io", "--pass-io",
USBVM_N, USBVM_N,
( (
'script --quiet --return --command ' "script --quiet --return --command "
f'"{FWUPDMGR} refresh {self.metadata_file_usbvm} ' f'"{FWUPDMGR} refresh {self.metadata_file_usbvm} '
f'{sig_metadata_file} {self.lvfs}"' f'{sig_metadata_file} {self.lvfs}"'
) ),
] ]
p = subprocess.Popen(cmd_refresh_metadata) p = subprocess.Popen(cmd_refresh_metadata)
p.wait() p.wait()
@ -238,8 +207,7 @@ class QubesFwupdmgr(FwupdHeads, FwupdUpdate, FwupdReceiveUpdates):
output_path = os.path.join(FWUPD_VM_UPDATES_DIR, arch_name) output_path = os.path.join(FWUPD_VM_UPDATES_DIR, arch_name)
cat_file = f"cat > {output_path}" cat_file = f"cat > {output_path}"
cmd_copy_file = ( cmd_copy_file = (
f'cat {arch_path} | ' f"cat {arch_path} | " f'qvm-run --nogui --pass-io {USBVM_N} "{cat_file}"'
f'qvm-run --nogui --pass-io {USBVM_N} "{cat_file}"'
) )
p = subprocess.Popen(cmd_copy_file, shell=True) p = subprocess.Popen(cmd_copy_file, shell=True)
p.wait() p.wait()
@ -257,8 +225,8 @@ class QubesFwupdmgr(FwupdHeads, FwupdUpdate, FwupdReceiveUpdates):
"qvm-run", "qvm-run",
"--pass-io", "--pass-io",
USBVM_N, USBVM_N,
f'script --quiet --return --command' f"script --quiet --return --command"
f' "{FWUPDMGR} install {arch_path}" /dev/null' f' "{FWUPDMGR} install {arch_path}" /dev/null',
] ]
p = subprocess.Popen(CMD_update) p = subprocess.Popen(CMD_update)
p.wait() p.wait()
@ -276,8 +244,8 @@ class QubesFwupdmgr(FwupdHeads, FwupdUpdate, FwupdReceiveUpdates):
"qvm-run", "qvm-run",
"--pass-io", "--pass-io",
USBVM_N, USBVM_N,
f'script --quiet --return --command' f"script --quiet --return --command"
f' "{FWUPDMGR} --allow-older install {arch_path}" /dev/null' f' "{FWUPDMGR} --allow-older install {arch_path}" /dev/null',
] ]
p = subprocess.Popen(CMD_downgrade) p = subprocess.Popen(CMD_downgrade)
p.wait() p.wait()
@ -290,7 +258,7 @@ class QubesFwupdmgr(FwupdHeads, FwupdUpdate, FwupdReceiveUpdates):
"qvm-run", "qvm-run",
"--pass-io", "--pass-io",
USBVM_N, USBVM_N,
f'script --quiet --return --command "{FWUPD_VM_VALIDATE} clean"' f'script --quiet --return --command "{FWUPD_VM_VALIDATE} clean"',
] ]
p = subprocess.Popen(cmd_clean) p = subprocess.Popen(cmd_clean)
p.wait() p.wait()
@ -299,12 +267,7 @@ class QubesFwupdmgr(FwupdHeads, FwupdUpdate, FwupdReceiveUpdates):
def _enable_lvfs_testing_dom0(self): def _enable_lvfs_testing_dom0(self):
"""Checks and enable lvfs-testing for custom metadata in dom0""" """Checks and enable lvfs-testing for custom metadata in dom0"""
cmd_lvfs_testing = [ cmd_lvfs_testing = [FWUPDMGR, "enable-remote", "-y", "lvfs-testing"]
FWUPDMGR,
"enable-remote",
"-y",
"lvfs-testing"
]
if not os.path.exists(LVFS_TESTING_DOM0_FLAG): if not os.path.exists(LVFS_TESTING_DOM0_FLAG):
p = subprocess.Popen(cmd_lvfs_testing) p = subprocess.Popen(cmd_lvfs_testing)
p.wait() p.wait()
@ -321,27 +284,24 @@ class QubesFwupdmgr(FwupdHeads, FwupdUpdate, FwupdReceiveUpdates):
"--pass-io", "--pass-io",
USBVM_N, USBVM_N,
( (
'script --quiet --return --command ' "script --quiet --return --command "
f'"{FWUPDMGR} enable-remote -y lvfs-testing"' f'"{FWUPDMGR} enable-remote -y lvfs-testing"'
) ),
] ]
cmd_validate_flag = [ cmd_validate_flag = [
"qvm-run", "qvm-run",
"--pass-io", "--pass-io",
USBVM_N, USBVM_N,
( (
'script --quiet --return --command ' "script --quiet --return --command "
f'"ls {LVFS_TESTING_USBVM_FLAG} &>/dev/null"' f'"ls {LVFS_TESTING_USBVM_FLAG} &>/dev/null"'
) ),
] ]
cmd_touch_flag = [ cmd_touch_flag = [
"qvm-run", "qvm-run",
"--pass-io", "--pass-io",
USBVM_N, USBVM_N,
( ("script --quiet --return --command " f'"touch {LVFS_TESTING_USBVM_FLAG}"'),
'script --quiet --return --command '
f'"touch {LVFS_TESTING_USBVM_FLAG}"'
)
] ]
flag = subprocess.Popen(cmd_validate_flag) flag = subprocess.Popen(cmd_validate_flag)
flag.wait() flag.wait()
@ -365,11 +325,8 @@ class QubesFwupdmgr(FwupdHeads, FwupdUpdate, FwupdReceiveUpdates):
""" """
if metadata_url: if metadata_url:
metadata_name = metadata_url.replace(FWUPD_DOWNLOAD_PREFIX, "") metadata_name = metadata_url.replace(FWUPD_DOWNLOAD_PREFIX, "")
self.metadata_file = os.path.join( self.metadata_file = os.path.join(FWUPD_DOM0_METADATA_DIR, metadata_name)
FWUPD_DOM0_METADATA_DIR, self.metadata_file_jcat = self.metadata_file + ".jcat"
metadata_name
)
self.metadata_file_jcat = self.metadata_file + '.jcat'
self.lvfs = "lvfs-testing" self.lvfs = "lvfs-testing"
self._enable_lvfs_testing_dom0() self._enable_lvfs_testing_dom0()
self._enable_lvfs_testing_usbvm(usbvm=usbvm) self._enable_lvfs_testing_usbvm(usbvm=usbvm)
@ -388,12 +345,9 @@ class QubesFwupdmgr(FwupdHeads, FwupdUpdate, FwupdReceiveUpdates):
"refresh", "refresh",
self.metadata_file, self.metadata_file,
self.metadata_file_jcat, self.metadata_file_jcat,
self.lvfs self.lvfs,
] ]
p = subprocess.Popen( p = subprocess.Popen(cmd_refresh, stdout=subprocess.PIPE)
cmd_refresh,
stdout=subprocess.PIPE
)
self.output = p.communicate()[0].decode() self.output = p.communicate()[0].decode()
print(self.output) print(self.output)
if p.returncode != 0: if p.returncode != 0:
@ -403,14 +357,8 @@ class QubesFwupdmgr(FwupdHeads, FwupdUpdate, FwupdReceiveUpdates):
def _get_dom0_updates(self): def _get_dom0_updates(self):
"""Gathers infromations about available updates.""" """Gathers infromations about available updates."""
cmd_get_dom0_updates = [ cmd_get_dom0_updates = [FWUPDAGENT, "get-updates"]
FWUPDAGENT, p = subprocess.Popen(cmd_get_dom0_updates, stdout=subprocess.PIPE)
"get-updates"
]
p = subprocess.Popen(
cmd_get_dom0_updates,
stdout=subprocess.PIPE
)
self.dom0_updates_info = p.communicate()[0].decode() self.dom0_updates_info = p.communicate()[0].decode()
if p.returncode != 0 and p.returncode != 2: if p.returncode != 0 and p.returncode != 2:
raise Exception("fwudp-qubes: Getting available updates failed") raise Exception("fwudp-qubes: Getting available updates failed")
@ -431,10 +379,12 @@ class QubesFwupdmgr(FwupdHeads, FwupdUpdate, FwupdReceiveUpdates):
"Version": update["Version"], "Version": update["Version"],
"Url": update["Uri"], "Url": update["Uri"],
"Checksum": update["Checksum"][-1], "Checksum": update["Checksum"][-1],
"Description": update["Description"] "Description": update["Description"],
} for update in device["Releases"] }
] for update in device["Releases"]
} for device in self.dom0_updates_info_dict["Devices"] ],
}
for device in self.dom0_updates_info_dict["Devices"]
] ]
def _download_firmware_updates(self, url, sha, whonix=False): def _download_firmware_updates(self, url, sha, whonix=False):
@ -476,16 +426,14 @@ class QubesFwupdmgr(FwupdHeads, FwupdUpdate, FwupdReceiveUpdates):
self._updates_crawler(updates_dict["dom0"]) self._updates_crawler(updates_dict["dom0"])
if usbvm: if usbvm:
self._updates_crawler( self._updates_crawler(
updates_dict["usbvm"], updates_dict["usbvm"], usbvm=True, prefix=dom0_updates_num
usbvm=True,
prefix=dom0_updates_num
) )
while True: while True:
try: try:
print("If you want to abandon process press 'N'.") print("If you want to abandon process press 'N'.")
choice = input("Otherwise choose a device number: ") choice = input("Otherwise choose a device number: ")
if choice == 'N' or choice == 'n': if choice == "N" or choice == "n":
return EXIT_CODES["NOTHING_TO_DO"] return EXIT_CODES["NOTHING_TO_DO"]
device_num = int(choice) - 1 device_num = int(choice) - 1
if 0 <= device_num < len(updates_list): if 0 <= device_num < len(updates_list):
@ -519,7 +467,7 @@ class QubesFwupdmgr(FwupdHeads, FwupdUpdate, FwupdReceiveUpdates):
print(f" Description:{description}") print(f" Description:{description}")
print("If you want to abandon downgrade process press N.") print("If you want to abandon downgrade process press N.")
choice = input("Otherwise choose downgrade number: ") choice = input("Otherwise choose downgrade number: ")
if choice == 'N' or choice == 'n': if choice == "N" or choice == "n":
return EXIT_CODES["NOTHING_TO_DO"] return EXIT_CODES["NOTHING_TO_DO"]
downgrade_num = int(choice) - 1 downgrade_num = int(choice) - 1
if 0 <= downgrade_num < len(releases): if 0 <= downgrade_num < len(releases):
@ -555,11 +503,7 @@ class QubesFwupdmgr(FwupdHeads, FwupdUpdate, FwupdReceiveUpdates):
Keywords arguments: Keywords arguments:
arch_path - absolute path to firmware update archive arch_path - absolute path to firmware update archive
""" """
cmd_install = [ cmd_install = [FWUPDMGR, "install", arch_path]
FWUPDMGR,
"install",
arch_path
]
p = subprocess.Popen(cmd_install) p = subprocess.Popen(cmd_install)
p.wait() p.wait()
if p.returncode != 0: if p.returncode != 0:
@ -567,19 +511,11 @@ class QubesFwupdmgr(FwupdHeads, FwupdUpdate, FwupdReceiveUpdates):
def _read_dmi(self): def _read_dmi(self):
"""Reads BIOS information from DMI.""" """Reads BIOS information from DMI."""
cmd_dmidecode_version = [ cmd_dmidecode_version = ["dmidecode", "-s", "bios-version"]
"dmidecode",
"-s",
"bios-version"
]
p = subprocess.Popen(cmd_dmidecode_version, stdout=subprocess.PIPE) p = subprocess.Popen(cmd_dmidecode_version, stdout=subprocess.PIPE)
p.wait() p.wait()
self.dmi_version = p.communicate()[0].decode() self.dmi_version = p.communicate()[0].decode()
cmd_dmidecode = [ cmd_dmidecode = ["dmidecode", "-t", "bios"]
"dmidecode",
"-t",
"bios"
]
p = subprocess.Popen(cmd_dmidecode, stdout=subprocess.PIPE) p = subprocess.Popen(cmd_dmidecode, stdout=subprocess.PIPE)
p.wait() p.wait()
if p.returncode != 0: if p.returncode != 0:
@ -604,20 +540,12 @@ class QubesFwupdmgr(FwupdHeads, FwupdUpdate, FwupdReceiveUpdates):
if vendor not in dmi_info: if vendor not in dmi_info:
raise ValueError("Wrong firmware provider.") raise ValueError("Wrong firmware provider.")
if not downgrade and l_ver(version) <= l_ver(self.dmi_version): if not downgrade and l_ver(version) <= l_ver(self.dmi_version):
raise ValueError( raise ValueError(f"{version} < {self.dmi_version} Downgrade not allowed")
f"{version} < {self.dmi_version} Downgrade not allowed"
)
def _get_dom0_devices(self): def _get_dom0_devices(self):
"""Gathers information about devices connected in dom0.""" """Gathers information about devices connected in dom0."""
cmd_get_dom0_devices = [ cmd_get_dom0_devices = [FWUPDAGENT, "get-devices"]
FWUPDAGENT, p = subprocess.Popen(cmd_get_dom0_devices, stdout=subprocess.PIPE)
"get-devices"
]
p = subprocess.Popen(
cmd_get_dom0_devices,
stdout=subprocess.PIPE
)
self.dom0_devices_info = p.communicate()[0].decode() self.dom0_devices_info = p.communicate()[0].decode()
if p.returncode != 0: if p.returncode != 0:
raise Exception("fwudp-qubes: Getting devices info failed") raise Exception("fwudp-qubes: Getting devices info failed")
@ -629,15 +557,11 @@ class QubesFwupdmgr(FwupdHeads, FwupdUpdate, FwupdReceiveUpdates):
usbvm_cmd = f'"{FWUPDAGENT} get-devices"' usbvm_cmd = f'"{FWUPDAGENT} get-devices"'
log_file = f" > {FWUPD_VM_LOG}" log_file = f" > {FWUPD_VM_LOG}"
cmd_get_usbvm_devices = ( cmd_get_usbvm_devices = (
f'qvm-run --nogui --pass-io {USBVM_N} {usbvm_cmd}{log_file}' f"qvm-run --nogui --pass-io {USBVM_N} {usbvm_cmd}{log_file}"
)
p = subprocess.Popen(
cmd_get_usbvm_devices,
shell=True
) )
p = subprocess.Popen(cmd_get_usbvm_devices, shell=True)
p.wait() p.wait()
if (p.returncode != 0 and p.returncode != 2 if p.returncode != 0 and p.returncode != 2 and not os.path.exists(FWUPD_VM_LOG):
and not os.path.exists(FWUPD_VM_LOG)):
raise Exception("fwudp-qubes: Getting usbvm devices info failed") raise Exception("fwudp-qubes: Getting usbvm devices info failed")
if not os.path.exists(FWUPD_VM_LOG): if not os.path.exists(FWUPD_VM_LOG):
raise Exception("usbvm device info log does not exist") raise Exception("usbvm device info log does not exist")
@ -658,7 +582,7 @@ class QubesFwupdmgr(FwupdHeads, FwupdUpdate, FwupdReceiveUpdates):
{ {
"Name": device["Name"], "Name": device["Name"],
"Version": device["Version"], "Version": device["Version"],
"Releases": [] "Releases": [],
} }
) )
current_version = device["Version"] current_version = device["Version"]
@ -669,7 +593,7 @@ class QubesFwupdmgr(FwupdHeads, FwupdUpdate, FwupdReceiveUpdates):
"Version": update["Version"], "Version": update["Version"],
"Url": update["Uri"], "Url": update["Uri"],
"Checksum": update["Checksum"][-1], "Checksum": update["Checksum"][-1],
"Description": update["Description"] "Description": update["Description"],
} }
) )
if not self.usbvm_updates_list[-1]["Releases"]: if not self.usbvm_updates_list[-1]["Releases"]:
@ -691,13 +615,11 @@ class QubesFwupdmgr(FwupdHeads, FwupdUpdate, FwupdReceiveUpdates):
self._parse_usbvm_updates(raw) self._parse_usbvm_updates(raw)
update_dict = { update_dict = {
"usbvm": self.usbvm_updates_list, "usbvm": self.usbvm_updates_list,
"dom0": self.dom0_updates_list "dom0": self.dom0_updates_list,
} }
ret_input = self._user_input(update_dict, usbvm=True) ret_input = self._user_input(update_dict, usbvm=True)
else: else:
update_dict = { update_dict = {"dom0": self.dom0_updates_list}
"dom0": self.dom0_updates_list
}
ret_input = self._user_input(update_dict) ret_input = self._user_input(update_dict)
if ret_input == EXIT_CODES["NOTHING_TO_DO"]: if ret_input == EXIT_CODES["NOTHING_TO_DO"]:
exit(EXIT_CODES["NOTHING_TO_DO"]) exit(EXIT_CODES["NOTHING_TO_DO"])
@ -741,10 +663,11 @@ class QubesFwupdmgr(FwupdHeads, FwupdUpdate, FwupdReceiveUpdates):
"Version": downgrade["Version"], "Version": downgrade["Version"],
"Description": downgrade["Description"], "Description": downgrade["Description"],
"Url": downgrade["Uri"], "Url": downgrade["Uri"],
"Checksum": downgrade["Checksum"][-1] "Checksum": downgrade["Checksum"][-1],
} for downgrade in device["Releases"] }
for downgrade in device["Releases"]
if l_ver(downgrade["Version"]) < l_ver(version) if l_ver(downgrade["Version"]) < l_ver(version)
] ],
} }
) )
return downgrades return downgrades
@ -755,12 +678,7 @@ class QubesFwupdmgr(FwupdHeads, FwupdUpdate, FwupdReceiveUpdates):
Keywords arguments: Keywords arguments:
arch_path - absolute path to firmware downgrade archive arch_path - absolute path to firmware downgrade archive
""" """
cmd_install = [ cmd_install = [FWUPDMGR, "--allow-older", "install", arch_path]
FWUPDMGR,
"--allow-older",
"install",
arch_path
]
p = subprocess.Popen(cmd_install) p = subprocess.Popen(cmd_install)
p.wait() p.wait()
if p.returncode != 0: if p.returncode != 0:
@ -780,19 +698,10 @@ class QubesFwupdmgr(FwupdHeads, FwupdUpdate, FwupdReceiveUpdates):
with open(FWUPD_VM_LOG) as usbvm_device_info: with open(FWUPD_VM_LOG) as usbvm_device_info:
raw = usbvm_device_info.read() raw = usbvm_device_info.read()
usbvm_downgrades = self._parse_downgrades(raw) usbvm_downgrades = self._parse_downgrades(raw)
downgrade_dict = { downgrade_dict = {"usbvm": usbvm_downgrades, "dom0": dom0_downgrades}
"usbvm": usbvm_downgrades, ret_input = self._user_input(downgrade_dict, downgrade=True, usbvm=True)
"dom0": dom0_downgrades
}
ret_input = self._user_input(
downgrade_dict,
downgrade=True,
usbvm=True
)
else: else:
downgrade_dict = { downgrade_dict = {"dom0": dom0_downgrades}
"dom0": dom0_downgrades
}
ret_input = self._user_input(downgrade_dict, downgrade=True) ret_input = self._user_input(downgrade_dict, downgrade=True)
if ret_input == EXIT_CODES["NOTHING_TO_DO"]: if ret_input == EXIT_CODES["NOTHING_TO_DO"]:
exit(EXIT_CODES["NOTHING_TO_DO"]) exit(EXIT_CODES["NOTHING_TO_DO"])
@ -800,18 +709,14 @@ class QubesFwupdmgr(FwupdHeads, FwupdUpdate, FwupdReceiveUpdates):
releases = downgrade_dict[vm_name][device_choice]["Releases"] releases = downgrade_dict[vm_name][device_choice]["Releases"]
downgrade_url = releases[downgrade_choice]["Url"] downgrade_url = releases[downgrade_choice]["Url"]
downgrade_sha = releases[downgrade_choice]["Checksum"] downgrade_sha = releases[downgrade_choice]["Checksum"]
self._download_firmware_updates( self._download_firmware_updates(downgrade_url, downgrade_sha, whonix=whonix)
downgrade_url,
downgrade_sha,
whonix=whonix
)
if downgrade_dict[vm_name][device_choice]["Name"] == "System Firmware": if downgrade_dict[vm_name][device_choice]["Name"] == "System Firmware":
Path(BIOS_UPDATE_FLAG).touch(mode=0o644, exist_ok=True) Path(BIOS_UPDATE_FLAG).touch(mode=0o644, exist_ok=True)
extracted_path = self.arch_path.replace(".cab", "") extracted_path = self.arch_path.replace(".cab", "")
self._verify_dmi( self._verify_dmi(
extracted_path, extracted_path,
downgrade_dict[vm_name][device_choice]["Version"], downgrade_dict[vm_name][device_choice]["Version"],
downgrade=True downgrade=True,
) )
if vm_name == "dom0": if vm_name == "dom0":
self._install_dom0_firmware_downgrade(self.arch_path) self._install_dom0_firmware_downgrade(self.arch_path)
@ -828,13 +733,14 @@ class QubesFwupdmgr(FwupdHeads, FwupdUpdate, FwupdReceiveUpdates):
updev_dict -- update/device information dictionary updev_dict -- update/device information dictionary
level -- level of the tree level -- level of the tree
""" """
def _tabs(key_word): def _tabs(key_word):
return key_word + '\t'*(4 - int(len(key_word)/8)) return key_word + "\t" * (4 - int(len(key_word) / 8))
decorator = "===================================" decorator = "==================================="
print(2 * decorator) print(2 * decorator)
for updev_key in updev_dict: for updev_key in updev_dict:
style = '\t'*level style = "\t" * level
output = style + _tabs(updev_key + ":") output = style + _tabs(updev_key + ":")
if len(updev_key) > 12: if len(updev_key) > 12:
continue continue
@ -853,9 +759,9 @@ class QubesFwupdmgr(FwupdHeads, FwupdUpdate, FwupdReceiveUpdates):
elif isinstance(updev_dict[updev_key][0], str): elif isinstance(updev_dict[updev_key][0], str):
for i, data in enumerate(updev_dict[updev_key]): for i, data in enumerate(updev_dict[updev_key]):
if i == 0: if i == 0:
print(output + u'\u00B7' + data) print(output + "\u00B7" + data)
continue continue
print(style + _tabs(' ') + u'\u00B7' + data) print(style + _tabs(" ") + "\u00B7" + data)
elif isinstance(updev_dict[updev_key][0], dict): elif isinstance(updev_dict[updev_key][0], dict):
if level == 0 and help_f is True: if level == 0 and help_f is True:
print(output) print(output)
@ -899,10 +805,7 @@ class QubesFwupdmgr(FwupdHeads, FwupdUpdate, FwupdReceiveUpdates):
print(f" Current firmware version:\t {device['Version']}") print(f" Current firmware version:\t {device['Version']}")
for update in device["Releases"]: for update in device["Releases"]:
print(decorator) print(decorator)
print( print(" Firmware update " f"version:\t {update['Version']}")
" Firmware update "
f"version:\t {update['Version']}"
)
print(f" URL:\t {update['Url']}") print(f" URL:\t {update['Url']}")
print(f" SHA256 checksum:\t {update['Checksum']}") print(f" SHA256 checksum:\t {update['Checksum']}")
description = update["Description"].replace("<p>", "") description = update["Description"].replace("<p>", "")
@ -960,14 +863,8 @@ class QubesFwupdmgr(FwupdHeads, FwupdUpdate, FwupdReceiveUpdates):
def check_usbvm(self): def check_usbvm(self):
"""Checks if usbvm is running""" """Checks if usbvm is running"""
cmd_xl_list = [ cmd_xl_list = ["xl", "list"]
"xl", p = subprocess.Popen(cmd_xl_list, stdout=subprocess.PIPE)
"list"
]
p = subprocess.Popen(
cmd_xl_list,
stdout=subprocess.PIPE
)
self.output = p.communicate()[0].decode() self.output = p.communicate()[0].decode()
if p.returncode != 0: if p.returncode != 0:
raise Exception("fwudp-qubes: Firmware downgrade failed") raise Exception("fwudp-qubes: Firmware downgrade failed")
@ -1011,13 +908,9 @@ class QubesFwupdmgr(FwupdHeads, FwupdUpdate, FwupdReceiveUpdates):
""" """
self._check_fwupdtool_version() self._check_fwupdtool_version()
if metadata_url: if metadata_url:
custom_metadata_name = metadata_url.replace( custom_metadata_name = metadata_url.replace(FWUPD_DOWNLOAD_PREFIX, "")
FWUPD_DOWNLOAD_PREFIX,
""
)
self.metadata_file = os.path.join( self.metadata_file = os.path.join(
FWUPD_DOM0_METADATA_DIR, FWUPD_DOM0_METADATA_DIR, custom_metadata_name
custom_metadata_name
) )
else: else:
self.metadata_file = FWUPD_DOM0_METADATA_FILE self.metadata_file = FWUPD_DOM0_METADATA_FILE
@ -1028,10 +921,7 @@ class QubesFwupdmgr(FwupdHeads, FwupdUpdate, FwupdReceiveUpdates):
return EXIT_CODES["NOTHING_TO_DO"] return EXIT_CODES["NOTHING_TO_DO"]
if self._parse_heads_updates(device) == EXIT_CODES["NOTHING_TO_DO"]: if self._parse_heads_updates(device) == EXIT_CODES["NOTHING_TO_DO"]:
return EXIT_CODES["NOTHING_TO_DO"] return EXIT_CODES["NOTHING_TO_DO"]
self._download_firmware_updates( self._download_firmware_updates(self.heads_update_url, self.heads_update_sha)
self.heads_update_url,
self.heads_update_sha
)
return_code = self._copy_heads_firmware(self.arch_path) return_code = self._copy_heads_firmware(self.arch_path)
if return_code == EXIT_CODES["NOTHING_TO_DO"]: if return_code == EXIT_CODES["NOTHING_TO_DO"]:
exit(EXIT_CODES["NOTHING_TO_DO"]) exit(EXIT_CODES["NOTHING_TO_DO"])
@ -1041,9 +931,9 @@ class QubesFwupdmgr(FwupdHeads, FwupdUpdate, FwupdReceiveUpdates):
try: try:
print("An update requires a reboot to complete.") print("An update requires a reboot to complete.")
choice = input("Do you want to restart now? (Y|N)\n") choice = input("Do you want to restart now? (Y|N)\n")
if choice == 'N' or choice == 'n': if choice == "N" or choice == "n":
return EXIT_CODES["SUCCESS"] return EXIT_CODES["SUCCESS"]
elif choice == 'Y' or choice == 'y': elif choice == "Y" or choice == "y":
print("Rebooting...") print("Rebooting...")
os.system("reboot") os.system("reboot")
else: else:
@ -1117,11 +1007,7 @@ def main():
elif sys.argv[1] == "refresh" and "--whonix" not in sys.argv: elif sys.argv[1] == "refresh" and "--whonix" not in sys.argv:
q.refresh_metadata(usbvm=sys_usb, metadata_url=metadata_url) q.refresh_metadata(usbvm=sys_usb, metadata_url=metadata_url)
elif sys.argv[1] == "refresh" and "--whonix" in sys.argv: elif sys.argv[1] == "refresh" and "--whonix" in sys.argv:
q.refresh_metadata( q.refresh_metadata(usbvm=sys_usb, whonix=True, metadata_url=metadata_url)
usbvm=sys_usb,
whonix=True,
metadata_url=metadata_url
)
elif sys.argv[1] == "update-heads" and "--whonix" not in sys.argv: elif sys.argv[1] == "update-heads" and "--whonix" not in sys.argv:
q.heads_update(device=device, metadata_url=metadata_url) q.heads_update(device=device, metadata_url=metadata_url)
elif sys.argv[1] == "update-heads" and "--whonix" in sys.argv: elif sys.argv[1] == "update-heads" and "--whonix" in sys.argv:
@ -1131,5 +1017,5 @@ def main():
exit(1) exit(1)
if __name__ == '__main__': if __name__ == "__main__":
main() main()

View File

@ -16,7 +16,7 @@ import subprocess
FWUPD_VM_DIR = "/home/user/.cache/fwupd" FWUPD_VM_DIR = "/home/user/.cache/fwupd"
FWUPD_VM_UPDATES_DIR = os.path.join(FWUPD_VM_DIR, "updates") FWUPD_VM_UPDATES_DIR = os.path.join(FWUPD_VM_DIR, "updates")
FWUPD_VM_METADATA_DIR = os.path.join(FWUPD_VM_DIR, "metadata") FWUPD_VM_METADATA_DIR = os.path.join(FWUPD_VM_DIR, "metadata")
WARNING_COLOR = '\033[93m' WARNING_COLOR = "\033[93m"
FWUPD_PKI = "/etc/pki/fwupd" FWUPD_PKI = "/etc/pki/fwupd"
@ -27,7 +27,7 @@ class FwupdVmCommon:
Keyword arguments: Keyword arguments:
*args -- paths to be created *args -- paths to be created
""" """
qubes_gid = grp.getgrnam('qubes').gr_gid qubes_gid = grp.getgrnam("qubes").gr_gid
self.old_umask = os.umask(0o002) self.old_umask = os.umask(0o002)
if args is None: if args is None:
raise Exception("Creating directories failed, no paths given.") raise Exception("Creating directories failed, no paths given.")
@ -49,14 +49,11 @@ class FwupdVmCommon:
file_path -- absolute path to the file file_path -- absolute path to the file
sha -- SHA256 checksum of the file sha -- SHA256 checksum of the file
""" """
with open(file_path, 'rb') as f: with open(file_path, "rb") as f:
c_sha = hashlib.sha256(f.read()).hexdigest() c_sha = hashlib.sha256(f.read()).hexdigest()
if c_sha != sha: if c_sha != sha:
self.clean_vm_cache() self.clean_vm_cache()
raise ValueError( raise ValueError("Computed checksum %s did NOT match %s. " % (c_sha, sha))
"Computed checksum %s did NOT match %s. " %
(c_sha, sha)
)
def validate_vm_dirs(self): def validate_vm_dirs(self):
"""Validates and creates directories""" """Validates and creates directories"""
@ -80,25 +77,16 @@ class FwupdVmCommon:
file_path -- absolute path to jcat file file_path -- absolute path to jcat file
file_directory -- absolute path to the directory to jcat file location file_directory -- absolute path to the directory to jcat file location
""" """
cmd_jcat = [ cmd_jcat = ["jcat-tool", "verify", f"{file_path}", "--public-keys", FWUPD_PKI]
"jcat-tool",
"verify",
f"{file_path}",
"--public-keys",
FWUPD_PKI
]
p = subprocess.Popen( p = subprocess.Popen(
cmd_jcat, cmd_jcat, cwd=file_directory, stdout=subprocess.PIPE, stderr=subprocess.PIPE
cwd=file_directory,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
) )
stdout, __ = p.communicate() stdout, __ = p.communicate()
verification = stdout.decode('utf-8') verification = stdout.decode("utf-8")
print(verification) print(verification)
if p.returncode != 0: if p.returncode != 0:
self.clean_vm_cache() self.clean_vm_cache()
raise Exception('jcat-tool: Verification failed') raise Exception("jcat-tool: Verification failed")
def clean_vm_cache(self): def clean_vm_cache(self):
"""Removes updates data""" """Removes updates data"""

View File

@ -41,12 +41,7 @@ class DownloadData(FwupdVmCommon):
metadata_url = METADATA_URL metadata_url = METADATA_URL
else: else:
metadata_url = self.custom_url metadata_url = self.custom_url
cmd_metadata = [ cmd_metadata = ["wget", "-P", FWUPD_VM_METADATA_DIR, metadata_url]
"wget",
"-P",
FWUPD_VM_METADATA_DIR,
metadata_url
]
p = subprocess.Popen(cmd_metadata) p = subprocess.Popen(cmd_metadata)
p.wait() p.wait()
if p.returncode != 0: if p.returncode != 0:
@ -62,12 +57,7 @@ class DownloadData(FwupdVmCommon):
metadata_url = METADATA_URL metadata_url = METADATA_URL
else: else:
metadata_url = self.custom_url metadata_url = self.custom_url
cmd_metadata = [ cmd_metadata = ["wget", "-P", FWUPD_VM_METADATA_DIR, f"{metadata_url}.jcat"]
"wget",
"-P",
FWUPD_VM_METADATA_DIR,
f"{metadata_url}.jcat"
]
p = subprocess.Popen(cmd_metadata) p = subprocess.Popen(cmd_metadata)
p.wait() p.wait()
if p.returncode != 0: if p.returncode != 0:
@ -81,20 +71,13 @@ class DownloadData(FwupdVmCommon):
"""Downloads default metadata and its signatures""" """Downloads default metadata and its signatures"""
if url is not None: if url is not None:
self.custom_url = url self.custom_url = url
custom_metadata_name = url.replace( custom_metadata_name = url.replace(FWUPD_DOWNLOAD_PREFIX, "")
FWUPD_DOWNLOAD_PREFIX,
""
)
self.metadata_file = os.path.join( self.metadata_file = os.path.join(
FWUPD_VM_METADATA_DIR, FWUPD_VM_METADATA_DIR, custom_metadata_name
custom_metadata_name
) )
else: else:
self.custom_url = None self.custom_url = None
self.metadata_file = os.path.join( self.metadata_file = os.path.join(FWUPD_VM_METADATA_DIR, "firmware.xml.gz")
FWUPD_VM_METADATA_DIR,
"firmware.xml.gz"
)
self.validate_vm_dirs() self.validate_vm_dirs()
self._download_metadata_file() self._download_metadata_file()
self._download_metadata_jcat() self._download_metadata_jcat()
@ -110,12 +93,7 @@ class DownloadData(FwupdVmCommon):
self.arch_name = url.replace("https://fwupd.org/downloads/", "") self.arch_name = url.replace("https://fwupd.org/downloads/", "")
self._decrypt_update_url(url) self._decrypt_update_url(url)
update_path = os.path.join(FWUPD_VM_UPDATES_DIR, self.arch_name) update_path = os.path.join(FWUPD_VM_UPDATES_DIR, self.arch_name)
cmd_update = [ cmd_update = ["wget", "-O", update_path, self.dec_url]
"wget",
"-O",
update_path,
self.dec_url
]
p = subprocess.Popen(cmd_update) p = subprocess.Popen(cmd_update)
p.wait() p.wait()
if p.returncode != 0: if p.returncode != 0:
@ -145,5 +123,5 @@ def main():
raise Exception("Invalid command!!!") raise Exception("Invalid command!!!")
if __name__ == '__main__': if __name__ == "__main__":
main() main()

View File

@ -18,14 +18,8 @@ from fwupd_common_vm import FwupdVmCommon
FWUPD_VM_DIR = "/home/user/.cache/fwupd" FWUPD_VM_DIR = "/home/user/.cache/fwupd"
FWUPD_VM_UPDATES_DIR = os.path.join(FWUPD_VM_DIR, "updates") FWUPD_VM_UPDATES_DIR = os.path.join(FWUPD_VM_DIR, "updates")
FWUPD_VM_METADATA_DIR = os.path.join(FWUPD_VM_DIR, "metadata") FWUPD_VM_METADATA_DIR = os.path.join(FWUPD_VM_DIR, "metadata")
FWUPD_VM_METADATA_JCAT = os.path.join( FWUPD_VM_METADATA_JCAT = os.path.join(FWUPD_VM_METADATA_DIR, "firmware.xml.gz.jcat")
FWUPD_VM_METADATA_DIR, FWUPD_VM_METADATA_FILE = os.path.join(FWUPD_VM_METADATA_DIR, "firmware.xml.gz")
"firmware.xml.gz.jcat"
)
FWUPD_VM_METADATA_FILE = os.path.join(
FWUPD_VM_METADATA_DIR,
"firmware.xml.gz"
)
FWUPDMGR = "/bin/fwupdmgr" FWUPDMGR = "/bin/fwupdmgr"
FWUPD_DOWNLOAD_PREFIX = "https://fwupd.org/downloads/" FWUPD_DOWNLOAD_PREFIX = "https://fwupd.org/downloads/"
@ -41,18 +35,14 @@ class FwupdUsbvmUpdates(FwupdVmCommon):
""" """
for untrusted_f in os.listdir(files_path): for untrusted_f in os.listdir(files_path):
if not regex_pattern.match(untrusted_f): if not regex_pattern.match(untrusted_f):
raise Exception( raise Exception("Dom0 sent unexpected file")
'Dom0 sent unexpected file'
)
f = untrusted_f f = untrusted_f
assert '/' not in f assert "/" not in f
assert '\0' not in f assert "\0" not in f
assert '\x1b' not in f assert "\x1b" not in f
path_f = os.path.join(files_path, f) path_f = os.path.join(files_path, f)
if os.path.islink(path_f) or not os.path.isfile(path_f): if os.path.islink(path_f) or not os.path.isfile(path_f):
raise Exception( raise Exception("Dom0 sent not regular file")
'Dom0 sent not regular file'
)
def _extract_archive(self, archive_path, output_path): def _extract_archive(self, archive_path, output_path):
"""Extracts archive file to the specified directory. """Extracts archive file to the specified directory.
@ -61,39 +51,22 @@ class FwupdUsbvmUpdates(FwupdVmCommon):
archive_path -- absolute path to archive file archive_path -- absolute path to archive file
output_path -- absolute path to the output directory output_path -- absolute path to the output directory
""" """
cmd_extract = [ cmd_extract = ["gcab", "-x", f"--directory={output_path}", f"{archive_path}"]
"gcab",
"-x",
f"--directory={output_path}",
f"{archive_path}"
]
p = subprocess.Popen(cmd_extract, stdout=subprocess.PIPE) p = subprocess.Popen(cmd_extract, stdout=subprocess.PIPE)
p.communicate()[0].decode('ascii') p.communicate()[0].decode("ascii")
if p.returncode != 0: if p.returncode != 0:
raise Exception( raise Exception("gcab: Error while extracting %s." % archive_path)
'gcab: Error while extracting %s.' %
archive_path
)
def validate_metadata(self, metadata_url=None): def validate_metadata(self, metadata_url=None):
"""Validates received the metadata files.""" """Validates received the metadata files."""
print("Running validation of the metadata files") print("Running validation of the metadata files")
if metadata_url: if metadata_url:
metadata_name = metadata_url.replace( metadata_name = metadata_url.replace(FWUPD_DOWNLOAD_PREFIX, "")
FWUPD_DOWNLOAD_PREFIX, metadata_file = os.path.join(FWUPD_VM_METADATA_DIR, metadata_name)
""
)
metadata_file = os.path.join(
FWUPD_VM_METADATA_DIR,
metadata_name
)
else: else:
metadata_file = FWUPD_VM_METADATA_FILE metadata_file = FWUPD_VM_METADATA_FILE
try: try:
self._jcat_verification( self._jcat_verification(f"{metadata_file}.jcat", FWUPD_VM_METADATA_DIR)
f"{metadata_file}.jcat",
FWUPD_VM_METADATA_DIR
)
except Exception as e: except Exception as e:
print(str(e), file=sys.stderr) print(str(e), file=sys.stderr)
self.clean_vm_cache() self.clean_vm_cache()
@ -113,10 +86,7 @@ class FwupdUsbvmUpdates(FwupdVmCommon):
arch_temp = os.path.join(output_path, archive_name) arch_temp = os.path.join(output_path, archive_name)
os.mkdir(output_path) os.mkdir(output_path)
shutil.copyfile(archive_path, arch_temp) shutil.copyfile(archive_path, arch_temp)
self._extract_archive( self._extract_archive(arch_temp, output_path)
arch_temp,
output_path
)
signature_name = os.path.join(output_path, "firmware*.jcat") signature_name = os.path.join(output_path, "firmware*.jcat")
file_path = glob.glob(signature_name) file_path = glob.glob(signature_name)
try: try:
@ -145,8 +115,7 @@ def main():
f.clean_vm_cache() f.clean_vm_cache()
elif sys.argv[1] == "updates" and len(sys.argv) < 4: elif sys.argv[1] == "updates" and len(sys.argv) < 4:
raise Exception( raise Exception(
"Invalid number of arguments.\n" "Invalid number of arguments.\n" "Expected archive path and checksum."
"Expected archive path and checksum."
) )
elif sys.argv[1] == "updates" and not len(sys.argv) < 4: elif sys.argv[1] == "updates" and not len(sys.argv) < 4:
f.validate_updates(sys.argv[2], sys.argv[3]) f.validate_updates(sys.argv[2], sys.argv[3])
@ -154,5 +123,5 @@ def main():
raise Exception("Invalid command") raise Exception("Invalid command")
if __name__ == '__main__': if __name__ == "__main__":
main() main()

View File

@ -26,21 +26,15 @@ QUBES_FWUPDMGR_BINDIR = "/usr/sbin/qubes-fwupdmgr"
class TestQubesFwupdHeads(unittest.TestCase): class TestQubesFwupdHeads(unittest.TestCase):
def setUp(self): def setUp(self):
if os.path.exists(QUBES_FWUPDMGR_REPO): if os.path.exists(QUBES_FWUPDMGR_REPO):
self.qfwupd = imp.load_source( self.qfwupd = imp.load_source("qubes_fwupdmgr", QUBES_FWUPDMGR_REPO)
"qubes_fwupdmgr",
QUBES_FWUPDMGR_REPO
)
elif os.path.exists(QUBES_FWUPDMGR_BINDIR): elif os.path.exists(QUBES_FWUPDMGR_BINDIR):
self.qfwupd = imp.load_source( self.qfwupd = imp.load_source("qubes_fwupdmgr", QUBES_FWUPDMGR_BINDIR)
"qubes_fwupdmgr",
QUBES_FWUPDMGR_BINDIR
)
self.q = qf_heads.FwupdHeads() self.q = qf_heads.FwupdHeads()
self.maxDiff = 2000 self.maxDiff = 2000
self.captured_output = io.StringIO() self.captured_output = io.StringIO()
sys.stdout = self.captured_output sys.stdout = self.captured_output
@unittest.skipUnless('qubes' in platform.release(), "Requires Qubes OS") @unittest.skipUnless("qubes" in platform.release(), "Requires Qubes OS")
def test_get_hwids(self): def test_get_hwids(self):
self.q._check_fwupdtool_version() self.q._check_fwupdtool_version()
self.q._get_hwids() self.q._get_hwids()
@ -56,12 +50,11 @@ class TestQubesFwupdHeads(unittest.TestCase):
self.q._gather_firmware_version() self.q._gather_firmware_version()
self.assertEqual(self.q.heads_version, "0.2.2") self.assertEqual(self.q.heads_version, "0.2.2")
@unittest.skipUnless('qubes' in platform.release(), "Requires Qubes OS") @unittest.skipUnless("qubes" in platform.release(), "Requires Qubes OS")
def test_parse_metadata(self): def test_parse_metadata(self):
qmgr = self.qfwupd.QubesFwupdmgr() qmgr = self.qfwupd.QubesFwupdmgr()
qmgr.metadata_file = CUSTOM_METADATA.replace( qmgr.metadata_file = CUSTOM_METADATA.replace(
"https://fwupd.org/downloads", "https://fwupd.org/downloads", self.qfwupd.FWUPD_DOM0_METADATA_DIR
self.qfwupd.FWUPD_DOM0_METADATA_DIR
) )
qmgr._download_metadata(metadata_url=CUSTOM_METADATA) qmgr._download_metadata(metadata_url=CUSTOM_METADATA)
self.q._parse_metadata(qmgr.metadata_file) self.q._parse_metadata(qmgr.metadata_file)
@ -74,16 +67,12 @@ class TestQubesFwupdHeads(unittest.TestCase):
self.assertEqual(return_code, 0) self.assertEqual(return_code, 0)
self.assertEqual( self.assertEqual(
self.q.heads_update_url, self.q.heads_update_url,
"https://fwupd.org/downloads/e747a435bf24fd6081b77b6704b39cec5fa2dcf62e0ca6b86d8a6460121a1d07-heads_coreboot_x230-v0_2_3.cab" "https://fwupd.org/downloads/e747a435bf24fd6081b77b6704b39cec5fa2dcf62e0ca6b86d8a6460121a1d07-heads_coreboot_x230-v0_2_3.cab",
) )
self.assertEqual( self.assertEqual(
self.q.heads_update_sha, self.q.heads_update_sha, "1a54e69ca2b58d1218035115d481480eaf4c66e4"
"1a54e69ca2b58d1218035115d481480eaf4c66e4"
)
self.assertEqual(
self.q.heads_update_version,
"0.2.3"
) )
self.assertEqual(self.q.heads_update_version, "0.2.3")
def test_check_heads_updates_no_updates(self): def test_check_heads_updates_no_updates(self):
self.q.metadata_info = HEADS_XML self.q.metadata_info = HEADS_XML
@ -98,30 +87,24 @@ class TestQubesFwupdHeads(unittest.TestCase):
self.assertEqual(return_code, 0) self.assertEqual(return_code, 0)
self.assertEqual( self.assertEqual(
self.q.heads_update_url, self.q.heads_update_url,
"https://fwupd.org/downloads/e747a435bf24fd6081b77b6704b39cec5fa2dcf62e0ca6b86d8a6460121a1d07-heads_coreboot_x230-v0_2_3.cab" "https://fwupd.org/downloads/e747a435bf24fd6081b77b6704b39cec5fa2dcf62e0ca6b86d8a6460121a1d07-heads_coreboot_x230-v0_2_3.cab",
) )
self.assertEqual( self.assertEqual(
self.q.heads_update_sha, self.q.heads_update_sha, "1a54e69ca2b58d1218035115d481480eaf4c66e4"
"1a54e69ca2b58d1218035115d481480eaf4c66e4"
)
self.assertEqual(
self.q.heads_update_version,
"0.2.3"
) )
self.assertEqual(self.q.heads_update_version, "0.2.3")
@unittest.skipUnless('qubes' in platform.release(), "Requires Qubes OS") @unittest.skipUnless("qubes" in platform.release(), "Requires Qubes OS")
def test_copy_heads_firmware(self): def test_copy_heads_firmware(self):
qmgr = self.qfwupd.QubesFwupdmgr() qmgr = self.qfwupd.QubesFwupdmgr()
self.q.heads_update_url = "https://fwupd.org/downloads/e747a435bf24fd6081b77b6704b39cec5fa2dcf62e0ca6b86d8a6460121a1d07-heads_coreboot_x230-v0_2_3.cab" self.q.heads_update_url = "https://fwupd.org/downloads/e747a435bf24fd6081b77b6704b39cec5fa2dcf62e0ca6b86d8a6460121a1d07-heads_coreboot_x230-v0_2_3.cab"
self.q.heads_update_sha = "1a54e69ca2b58d1218035115d481480eaf4c66e4" self.q.heads_update_sha = "1a54e69ca2b58d1218035115d481480eaf4c66e4"
self.q.heads_update_version = "0.2.3" self.q.heads_update_version = "0.2.3"
qmgr._download_firmware_updates( qmgr._download_firmware_updates(
self.q.heads_update_url, self.q.heads_update_url, self.q.heads_update_sha
self.q.heads_update_sha
) )
heads_boot_path = os.path.join( heads_boot_path = os.path.join(
qf_heads.HEADS_UPDATES_DIR, qf_heads.HEADS_UPDATES_DIR, self.q.heads_update_version
self.q.heads_update_version
) )
if os.path.exists(heads_boot_path): if os.path.exists(heads_boot_path):
shutil.rmtree(heads_boot_path) shutil.rmtree(heads_boot_path)
@ -131,5 +114,5 @@ class TestQubesFwupdHeads(unittest.TestCase):
self.assertTrue(os.path.exists(firmware_path)) self.assertTrue(os.path.exists(firmware_path))
if __name__ == '__main__': if __name__ == "__main__":
unittest.main() unittest.main()

View File

@ -26,39 +26,23 @@ QUBES_FWUPDMGR_REPO = "./src/qubes_fwupdmgr.py"
QUBES_FWUPDMGR_BINDIR = "/usr/sbin/qubes-fwupdmgr" QUBES_FWUPDMGR_BINDIR = "/usr/sbin/qubes-fwupdmgr"
if os.path.exists(QUBES_FWUPDMGR_REPO): if os.path.exists(QUBES_FWUPDMGR_REPO):
qfwupd = imp.load_source( qfwupd = imp.load_source("qubes_fwupdmgr", QUBES_FWUPDMGR_REPO)
"qubes_fwupdmgr",
QUBES_FWUPDMGR_REPO
)
elif os.path.exists(QUBES_FWUPDMGR_BINDIR): elif os.path.exists(QUBES_FWUPDMGR_BINDIR):
qfwupd = imp.load_source( qfwupd = imp.load_source("qubes_fwupdmgr", QUBES_FWUPDMGR_BINDIR)
"qubes_fwupdmgr",
QUBES_FWUPDMGR_BINDIR
)
FWUPD_DOM0_DIR = "/root/.cache/fwupd" FWUPD_DOM0_DIR = "/root/.cache/fwupd"
FWUPD_DOM0_UPDATES_DIR = os.path.join(FWUPD_DOM0_DIR, "updates") FWUPD_DOM0_UPDATES_DIR = os.path.join(FWUPD_DOM0_DIR, "updates")
FWUPD_DOM0_UNTRUSTED_DIR = os.path.join(FWUPD_DOM0_UPDATES_DIR, "untrusted") FWUPD_DOM0_UNTRUSTED_DIR = os.path.join(FWUPD_DOM0_UPDATES_DIR, "untrusted")
FWUPD_VM_LOG = os.path.join(FWUPD_DOM0_DIR, "usbvm-devices.log") FWUPD_VM_LOG = os.path.join(FWUPD_DOM0_DIR, "usbvm-devices.log")
FWUPD_DOM0_METADATA_DIR = os.path.join(FWUPD_DOM0_DIR, "metadata") FWUPD_DOM0_METADATA_DIR = os.path.join(FWUPD_DOM0_DIR, "metadata")
FWUPD_DOM0_METADATA_FILE = os.path.join( FWUPD_DOM0_METADATA_FILE = os.path.join(FWUPD_DOM0_METADATA_DIR, "firmware.xml.gz")
FWUPD_DOM0_METADATA_DIR, FWUPD_DOM0_METADATA_FILE_JCAT = os.path.join(FWUPD_DOM0_METADATA_DIR, "firmware.xml.gz")
"firmware.xml.gz"
)
FWUPD_DOM0_METADATA_FILE_JCAT = os.path.join(
FWUPD_DOM0_METADATA_DIR,
"firmware.xml.gz"
)
FWUPD_VM_DIR = "/home/user/.cache/fwupd" FWUPD_VM_DIR = "/home/user/.cache/fwupd"
FWUPD_VM_UPDATES_DIR = os.path.join(FWUPD_VM_DIR, "updates") FWUPD_VM_UPDATES_DIR = os.path.join(FWUPD_VM_DIR, "updates")
FWUPD_VM_METADATA_DIR = os.path.join(FWUPD_VM_DIR, "metadata") FWUPD_VM_METADATA_DIR = os.path.join(FWUPD_VM_DIR, "metadata")
FWUPD_VM_METADATA_FILE = os.path.join( FWUPD_VM_METADATA_FILE = os.path.join(FWUPD_VM_METADATA_DIR, "firmware.xml.gz")
FWUPD_VM_METADATA_DIR,
"firmware.xml.gz"
)
FWUPD_VM_METADATA_FILE_JCAT = os.path.join( FWUPD_VM_METADATA_FILE_JCAT = os.path.join(
FWUPD_VM_METADATA_DIR, FWUPD_VM_METADATA_DIR, "firmware.xml.gz.jcat"
"firmware.xml.gz.jcat"
) )
REQUIRED_DEV = "Requires device not connected" REQUIRED_DEV = "Requires device not connected"
REQUIRED_USBVM = "Requires sys-usb" REQUIRED_USBVM = "Requires sys-usb"
@ -73,7 +57,7 @@ CUSTOM_METADATA = "https://fwupd.org/downloads/firmware-3c81bfdc9db5c8a42c09d380
def check_usbvm(): def check_usbvm():
"""Checks if sys-usb is running""" """Checks if sys-usb is running"""
if 'qubes' not in platform.release(): if "qubes" not in platform.release():
return False return False
q = qfwupd.QubesFwupdmgr() q = qfwupd.QubesFwupdmgr()
q.check_usbvm() q.check_usbvm()
@ -82,7 +66,7 @@ def check_usbvm():
def device_connected_dom0(): def device_connected_dom0():
"""Checks if the testing device is connected in dom0""" """Checks if the testing device is connected in dom0"""
if 'qubes' not in platform.release(): if "qubes" not in platform.release():
return False return False
q = qfwupd.QubesFwupdmgr() q = qfwupd.QubesFwupdmgr()
q._get_dom0_devices() q._get_dom0_devices()
@ -104,7 +88,7 @@ def device_connected_usbvm():
def check_whonix_updatevm(): def check_whonix_updatevm():
"""Checks if the sys-whonix is running""" """Checks if the sys-whonix is running"""
if 'qubes' not in platform.release(): if "qubes" not in platform.release():
return False return False
q = qfwupd.QubesFwupdmgr() q = qfwupd.QubesFwupdmgr()
q.check_usbvm() q.check_usbvm()
@ -118,7 +102,7 @@ class TestQubesFwupdmgr(unittest.TestCase):
self.captured_output = io.StringIO() self.captured_output = io.StringIO()
sys.stdout = self.captured_output sys.stdout = self.captured_output
@unittest.skipUnless('qubes' in platform.release(), "Requires Qubes OS") @unittest.skipUnless("qubes" in platform.release(), "Requires Qubes OS")
def test_download_metadata(self): def test_download_metadata(self):
self.q.metadata_file = FWUPD_DOM0_METADATA_FILE self.q.metadata_file = FWUPD_DOM0_METADATA_FILE
self.q._download_metadata() self.q._download_metadata()
@ -144,13 +128,12 @@ class TestQubesFwupdmgr(unittest.TestCase):
msg="Metadata signature does not exist", msg="Metadata signature does not exist",
) )
@unittest.skipUnless('qubes' in platform.release(), "Requires Qubes OS") @unittest.skipUnless("qubes" in platform.release(), "Requires Qubes OS")
def test_download_custom_metadata(self): def test_download_custom_metadata(self):
self.q.metadata_file = CUSTOM_METADATA.replace( self.q.metadata_file = CUSTOM_METADATA.replace(
"https://fwupd.org/downloads", "https://fwupd.org/downloads", FWUPD_DOM0_METADATA_DIR
FWUPD_DOM0_METADATA_DIR
) )
self.q.metadata_file_jcat = self.q.metadata_file + '.jcat' self.q.metadata_file_jcat = self.q.metadata_file + ".jcat"
self.q._download_metadata(metadata_url=CUSTOM_METADATA) self.q._download_metadata(metadata_url=CUSTOM_METADATA)
self.assertTrue( self.assertTrue(
os.path.exists(self.q.metadata_file), os.path.exists(self.q.metadata_file),
@ -161,22 +144,22 @@ class TestQubesFwupdmgr(unittest.TestCase):
msg="Metadata signature does not exist", msg="Metadata signature does not exist",
) )
@unittest.skipUnless('qubes' in platform.release(), "Requires Qubes OS") @unittest.skipUnless("qubes" in platform.release(), "Requires Qubes OS")
def test_refresh_metadata_dom0(self): def test_refresh_metadata_dom0(self):
self.q.refresh_metadata() self.q.refresh_metadata()
self.assertEqual( self.assertEqual(
self.q.output, self.q.output,
'Successfully refreshed metadata manually\n', "Successfully refreshed metadata manually\n",
msg="Metadata refresh failed." msg="Metadata refresh failed.",
) )
@unittest.skipUnless('qubes' in platform.release(), "Requires Qubes OS") @unittest.skipUnless("qubes" in platform.release(), "Requires Qubes OS")
def test_refresh_metadata_dom0_custom(self): def test_refresh_metadata_dom0_custom(self):
self.q.refresh_metadata(metadata_url=CUSTOM_METADATA) self.q.refresh_metadata(metadata_url=CUSTOM_METADATA)
self.assertEqual( self.assertEqual(
self.q.output, self.q.output,
'Successfully refreshed metadata manually\n', "Successfully refreshed metadata manually\n",
msg="Metadata refresh failed." msg="Metadata refresh failed.",
) )
@unittest.skipUnless(check_usbvm(), REQUIRED_USBVM) @unittest.skipUnless(check_usbvm(), REQUIRED_USBVM)
@ -184,8 +167,8 @@ class TestQubesFwupdmgr(unittest.TestCase):
self.q.refresh_metadata(usbvm=True) self.q.refresh_metadata(usbvm=True)
self.assertEqual( self.assertEqual(
self.q.output, self.q.output,
'Successfully refreshed metadata manually\n', "Successfully refreshed metadata manually\n",
msg="Metadata refresh failed." msg="Metadata refresh failed.",
) )
@unittest.skipUnless(check_usbvm(), REQUIRED_USBVM) @unittest.skipUnless(check_usbvm(), REQUIRED_USBVM)
@ -193,8 +176,8 @@ class TestQubesFwupdmgr(unittest.TestCase):
self.q.refresh_metadata(usbvm=True, metadata_url=CUSTOM_METADATA) self.q.refresh_metadata(usbvm=True, metadata_url=CUSTOM_METADATA)
self.assertEqual( self.assertEqual(
self.q.output, self.q.output,
'Successfully refreshed metadata manually\n', "Successfully refreshed metadata manually\n",
msg="Metadata refresh failed." msg="Metadata refresh failed.",
) )
@unittest.skipUnless(check_whonix_updatevm(), "Requires sys-whonix") @unittest.skipUnless(check_whonix_updatevm(), "Requires sys-whonix")
@ -202,64 +185,55 @@ class TestQubesFwupdmgr(unittest.TestCase):
self.q.refresh_metadata(whonix=True) self.q.refresh_metadata(whonix=True)
self.assertEqual( self.assertEqual(
self.q.output, self.q.output,
'Successfully refreshed metadata manually\n', "Successfully refreshed metadata manually\n",
msg="Metadata refresh failed." msg="Metadata refresh failed.",
) )
@unittest.skipUnless('qubes' in platform.release(), "Requires Qubes OS") @unittest.skipUnless("qubes" in platform.release(), "Requires Qubes OS")
def test_get_dom0_updates(self): def test_get_dom0_updates(self):
self.q._get_dom0_updates() self.q._get_dom0_updates()
self.assertIn( self.assertIn(
"Devices", "Devices", self.q.dom0_updates_info, msg="Getting available updates failed"
self.q.dom0_updates_info,
msg="Getting available updates failed"
) )
def test_parse_updates_info(self): def test_parse_updates_info(self):
self.q._parse_dom0_updates_info(UPDATE_INFO) self.q._parse_dom0_updates_info(UPDATE_INFO)
self.assertEqual( self.assertEqual(
self.q.dom0_updates_list[0]["Name"], self.q.dom0_updates_list[0]["Name"], "ColorHug2", msg="Wrong device name"
"ColorHug2",
msg="Wrong device name"
) )
self.assertEqual( self.assertEqual(
self.q.dom0_updates_list[0]["Version"], self.q.dom0_updates_list[0]["Version"], "2.0.6", msg="Wrong update version"
"2.0.6",
msg="Wrong update version"
) )
self.assertEqual( self.assertEqual(
self.q.dom0_updates_list[0]["Releases"][0]["Url"], self.q.dom0_updates_list[0]["Releases"][0]["Url"],
"https://fwupd.org/downloads/0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7.cab", "https://fwupd.org/downloads/0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7.cab",
msg="Wrong update URL" msg="Wrong update URL",
) )
self.assertEqual( self.assertEqual(
self.q.dom0_updates_list[0]["Releases"][0]["Checksum"], self.q.dom0_updates_list[0]["Releases"][0]["Checksum"],
"32c4a2c9be787cdf1d757c489d6455bd7bb14053425180b6d331c37e1ccc1cda", "32c4a2c9be787cdf1d757c489d6455bd7bb14053425180b6d331c37e1ccc1cda",
msg="Wrong checksum" msg="Wrong checksum",
) )
@unittest.skipUnless('qubes' in platform.release(), "Requires Qubes OS") @unittest.skipUnless("qubes" in platform.release(), "Requires Qubes OS")
def test_download_firmware_updates(self): def test_download_firmware_updates(self):
self.q._download_firmware_updates( self.q._download_firmware_updates(
"https://fwupd.org/downloads/0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7.cab", "https://fwupd.org/downloads/0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7.cab",
"32c4a2c9be787cdf1d757c489d6455bd7bb14053425180b6d331c37e1ccc1cda" "32c4a2c9be787cdf1d757c489d6455bd7bb14053425180b6d331c37e1ccc1cda",
) )
update_path = os.path.join( update_path = os.path.join(
FWUPD_DOM0_UPDATES_DIR, FWUPD_DOM0_UPDATES_DIR,
"0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7" "0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7",
) )
self.assertTrue(os.path.exists(update_path)) self.assertTrue(os.path.exists(update_path))
@unittest.skipUnless('qubes' in platform.release(), "Requires Qubes OS") @unittest.skipUnless("qubes" in platform.release(), "Requires Qubes OS")
def test_download_firmware_special_char(self): def test_download_firmware_special_char(self):
self.q._download_firmware_updates( self.q._download_firmware_updates(
"https://fwupd.org/downloads/bc334d8b098f2e91603c5f7dfdc837fb01797bbe-Dell%20XPS%2015%209560&Precision%205520%20System%20BIOS_Ver.1.18.0.cab", "https://fwupd.org/downloads/bc334d8b098f2e91603c5f7dfdc837fb01797bbe-Dell%20XPS%2015%209560&Precision%205520%20System%20BIOS_Ver.1.18.0.cab",
"86d9e5e35b0b264be1bb1e49ec16ccd1330390423bfe962267a58c27be7712b8" "86d9e5e35b0b264be1bb1e49ec16ccd1330390423bfe962267a58c27be7712b8",
)
update_path = os.path.join(
FWUPD_DOM0_UPDATES_DIR,
"trusted"
) )
update_path = os.path.join(FWUPD_DOM0_UPDATES_DIR, "trusted")
self.assertTrue(os.path.exists(update_path)) self.assertTrue(os.path.exists(update_path))
@unittest.skipUnless(check_whonix_updatevm(), "Requires sys-whonix") @unittest.skipUnless(check_whonix_updatevm(), "Requires sys-whonix")
@ -271,62 +245,53 @@ class TestQubesFwupdmgr(unittest.TestCase):
) )
update_path = os.path.join( update_path = os.path.join(
FWUPD_DOM0_UPDATES_DIR, FWUPD_DOM0_UPDATES_DIR,
"0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7" "0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7",
) )
self.assertTrue(os.path.exists(update_path)) self.assertTrue(os.path.exists(update_path))
def test_user_input_empty_dict(self): def test_user_input_empty_dict(self):
downgrade_dict = { downgrade_dict = {"usbvm": [], "dom0": []}
"usbvm": [],
"dom0": []
}
self.assertEqual(self.q._user_input(downgrade_dict), 2) self.assertEqual(self.q._user_input(downgrade_dict), 2)
def test_user_input_n(self): def test_user_input_n(self):
user_input = ['sth', 'n'] user_input = ["sth", "n"]
with patch('builtins.input', side_effect=user_input): with patch("builtins.input", side_effect=user_input):
self.q._parse_dom0_updates_info(UPDATE_INFO) self.q._parse_dom0_updates_info(UPDATE_INFO)
downgrade_dict = { downgrade_dict = {
"usbvm": self.q.dom0_updates_list, "usbvm": self.q.dom0_updates_list,
"dom0": self.q.dom0_updates_list "dom0": self.q.dom0_updates_list,
} }
choice = self.q._user_input( choice = self.q._user_input(downgrade_dict, usbvm=True)
downgrade_dict,
usbvm=True
)
self.assertEqual(choice, 2) self.assertEqual(choice, 2)
user_input = ['sth', 'N'] user_input = ["sth", "N"]
with patch('builtins.input', side_effect=user_input): with patch("builtins.input", side_effect=user_input):
self.q._parse_dom0_updates_info(UPDATE_INFO) self.q._parse_dom0_updates_info(UPDATE_INFO)
downgrade_dict = { downgrade_dict = {
"usbvm": self.q.dom0_updates_list, "usbvm": self.q.dom0_updates_list,
"dom0": self.q.dom0_updates_list "dom0": self.q.dom0_updates_list,
} }
choice = self.q._user_input( choice = self.q._user_input(downgrade_dict, usbvm=True)
downgrade_dict,
usbvm=True
)
self.assertEqual(choice, 2) self.assertEqual(choice, 2)
def test_user_input_choice(self): def test_user_input_choice(self):
user_input = ['6', '1'] user_input = ["6", "1"]
with patch('builtins.input', side_effect=user_input): with patch("builtins.input", side_effect=user_input):
self.q._parse_dom0_updates_info(UPDATE_INFO) self.q._parse_dom0_updates_info(UPDATE_INFO)
updates_dict = { updates_dict = {
"usbvm": self.q.dom0_updates_list, "usbvm": self.q.dom0_updates_list,
"dom0": self.q.dom0_updates_list "dom0": self.q.dom0_updates_list,
} }
key, choice = self.q._user_input(updates_dict) key, choice = self.q._user_input(updates_dict)
self.assertEqual(key, "dom0") self.assertEqual(key, "dom0")
self.assertEqual(choice, 0) self.assertEqual(choice, 0)
def test_user_input_choice_usbvm(self): def test_user_input_choice_usbvm(self):
user_input = ['6', '2'] user_input = ["6", "2"]
with patch('builtins.input', side_effect=user_input): with patch("builtins.input", side_effect=user_input):
self.q._parse_dom0_updates_info(UPDATE_INFO) self.q._parse_dom0_updates_info(UPDATE_INFO)
updates_dict = { updates_dict = {
"usbvm": self.q.dom0_updates_list, "usbvm": self.q.dom0_updates_list,
"dom0": self.q.dom0_updates_list "dom0": self.q.dom0_updates_list,
} }
key, choice = self.q._user_input(updates_dict, usbvm=True) key, choice = self.q._user_input(updates_dict, usbvm=True)
self.assertEqual(key, "usbvm") self.assertEqual(key, "usbvm")
@ -338,18 +303,15 @@ class TestQubesFwupdmgr(unittest.TestCase):
self.q._parse_parameters(update_dict, "dom0", 0) self.q._parse_parameters(update_dict, "dom0", 0)
self.assertEqual( self.assertEqual(
self.q.url, self.q.url,
"https://fwupd.org/downloads/0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7.cab" "https://fwupd.org/downloads/0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7.cab",
) )
self.assertEqual( self.assertEqual(
self.q.sha, self.q.sha,
"32c4a2c9be787cdf1d757c489d6455bd7bb14053425180b6d331c37e1ccc1cda" "32c4a2c9be787cdf1d757c489d6455bd7bb14053425180b6d331c37e1ccc1cda",
)
self.assertEqual(
self.q.version,
"2.0.7"
) )
self.assertEqual(self.q.version, "2.0.7")
@unittest.skipUnless('qubes' in platform.release(), "Requires Qubes OS") @unittest.skipUnless("qubes" in platform.release(), "Requires Qubes OS")
def test_clean_cache_dom0(self): def test_clean_cache_dom0(self):
self.q.clean_cache() self.q.clean_cache()
self.assertFalse(os.path.exists(FWUPD_DOM0_METADATA_DIR)) self.assertFalse(os.path.exists(FWUPD_DOM0_METADATA_DIR))
@ -365,28 +327,20 @@ class TestQubesFwupdmgr(unittest.TestCase):
"qvm-run", "qvm-run",
"--pass-io", "--pass-io",
"sys-usb", "sys-usb",
f"! [ -d {FWUPD_VM_METADATA_DIR} ]" f"! [ -d {FWUPD_VM_METADATA_DIR} ]",
] ]
p = subprocess.Popen(cmd_validate_metadata) p = subprocess.Popen(cmd_validate_metadata)
p.wait() p.wait()
self.assertEqual( self.assertEqual(p.returncode, 0, msg="Creating metadata directory failed")
p.returncode,
0,
msg="Creating metadata directory failed"
)
cmd_validate_udpdate = [ cmd_validate_udpdate = [
"qvm-run", "qvm-run",
"--pass-io", "--pass-io",
"sys-usb", "sys-usb",
f"! [ -d {FWUPD_VM_UPDATES_DIR} ]" f"! [ -d {FWUPD_VM_UPDATES_DIR} ]",
] ]
p = subprocess.Popen(cmd_validate_udpdate) p = subprocess.Popen(cmd_validate_udpdate)
p.wait() p.wait()
self.assertEqual( self.assertEqual(p.returncode, 0, msg="Cleaning update directory failed")
p.returncode,
0,
msg="Cleaning update directory failed"
)
def test_output_crawler(self): def test_output_crawler(self):
crawler_output = io.StringIO() crawler_output = io.StringIO()
@ -394,17 +348,16 @@ class TestQubesFwupdmgr(unittest.TestCase):
self.q._output_crawler(json.loads(UPDATE_INFO), 0) self.q._output_crawler(json.loads(UPDATE_INFO), 0)
with open("test/logs/get_devices.log", "r") as get_devices: with open("test/logs/get_devices.log", "r") as get_devices:
self.assertEqual( self.assertEqual(
get_devices.read(), get_devices.read(), crawler_output.getvalue().strip() + "\n"
crawler_output.getvalue().strip() + "\n"
) )
sys.stdout = self.captured_output sys.stdout = self.captured_output
@unittest.skipUnless('qubes' in platform.release(), "Requires Qubes OS") @unittest.skipUnless("qubes" in platform.release(), "Requires Qubes OS")
def test_get_dom0_devices(self): def test_get_dom0_devices(self):
self.q._get_dom0_devices() self.q._get_dom0_devices()
self.assertIsNotNone(self.q.dom0_devices_info) self.assertIsNotNone(self.q.dom0_devices_info)
@unittest.skipUnless('qubes' in platform.release(), "Requires Qubes OS") @unittest.skipUnless("qubes" in platform.release(), "Requires Qubes OS")
def test_get_devices_qubes_dom0(self): def test_get_devices_qubes_dom0(self):
get_devices_output = io.StringIO() get_devices_output = io.StringIO()
sys.stdout = get_devices_output sys.stdout = get_devices_output
@ -441,45 +394,36 @@ class TestQubesFwupdmgr(unittest.TestCase):
sys.stdout = help_output sys.stdout = help_output
self.q.help() self.q.help()
with open("test/logs/help.log", "r") as help_log: with open("test/logs/help.log", "r") as help_log:
self.assertEqual( self.assertEqual(help_log.read(), help_output.getvalue().strip() + "\n")
help_log.read(),
help_output.getvalue().strip() + "\n"
)
sys.stdout = self.captured_output sys.stdout = self.captured_output
@patch( @patch(
'test.test_qubes_fwupdmgr.qfwupd.QubesFwupdmgr._read_dmi', "test.test_qubes_fwupdmgr.qfwupd.QubesFwupdmgr._read_dmi",
return_value=DMI_DECODE return_value=DMI_DECODE,
) )
def test_verify_dmi(self, output): def test_verify_dmi(self, output):
self.q.dmi_version = "P.1.0" self.q.dmi_version = "P.1.0"
self.q._verify_dmi("test/logs/", "P1.1") self.q._verify_dmi("test/logs/", "P1.1")
@patch( @patch(
'test.test_qubes_fwupdmgr.qfwupd.QubesFwupdmgr._read_dmi', "test.test_qubes_fwupdmgr.qfwupd.QubesFwupdmgr._read_dmi",
return_value=DMI_DECODE return_value=DMI_DECODE,
) )
def test_verify_dmi_wrong_vendor(self, output): def test_verify_dmi_wrong_vendor(self, output):
with self.assertRaises(ValueError) as wrong_vendor: with self.assertRaises(ValueError) as wrong_vendor:
self.q.dmi_version = "P.1.0" self.q.dmi_version = "P.1.0"
self.q._verify_dmi("test/logs/metainfo_name/", "P1.1") self.q._verify_dmi("test/logs/metainfo_name/", "P1.1")
self.assertIn( self.assertIn("Wrong firmware provider.", str(wrong_vendor.exception))
"Wrong firmware provider.",
str(wrong_vendor.exception)
)
@patch( @patch(
'test.test_qubes_fwupdmgr.qfwupd.QubesFwupdmgr._read_dmi', "test.test_qubes_fwupdmgr.qfwupd.QubesFwupdmgr._read_dmi",
return_value=DMI_DECODE return_value=DMI_DECODE,
) )
def test_verify_dmi_version(self, output): def test_verify_dmi_version(self, output):
self.q.dmi_version = "P1.0" self.q.dmi_version = "P1.0"
with self.assertRaises(ValueError) as downgrade: with self.assertRaises(ValueError) as downgrade:
self.q._verify_dmi("test/logs/metainfo_version/", "P0.1") self.q._verify_dmi("test/logs/metainfo_version/", "P0.1")
self.assertIn( self.assertIn("P0.1 < P1.0 Downgrade not allowed", str(downgrade.exception))
"P0.1 < P1.0 Downgrade not allowed",
str(downgrade.exception)
)
@unittest.skipUnless(device_connected_dom0(), REQUIRED_DEV) @unittest.skipUnless(device_connected_dom0(), REQUIRED_DEV)
def test_downgrade_firmware_dom0(self): def test_downgrade_firmware_dom0(self):
@ -494,8 +438,8 @@ class TestQubesFwupdmgr(unittest.TestCase):
break break
if old_version is None: if old_version is None:
self.fail("Test device not found") self.fail("Test device not found")
user_input = [str(number+1), '1'] user_input = [str(number + 1), "1"]
with patch('builtins.input', side_effect=user_input): with patch("builtins.input", side_effect=user_input):
self.q.downgrade_firmware() self.q.downgrade_firmware()
self.q._get_dom0_devices() self.q._get_dom0_devices()
downgrades = self.q._parse_downgrades(self.q.dom0_devices_info) downgrades = self.q._parse_downgrades(self.q.dom0_devices_info)
@ -503,16 +447,13 @@ class TestQubesFwupdmgr(unittest.TestCase):
self.assertGreater(l_ver(old_version), l_ver(new_version)) self.assertGreater(l_ver(old_version), l_ver(new_version))
@unittest.skipUnless( @unittest.skipUnless(
check_whonix_updatevm() and device_connected_usbvm(), check_whonix_updatevm() and device_connected_usbvm(), REQUIRED_DEV
REQUIRED_DEV
) )
def test_update_n_downgrade_firmware_whonix(self): def test_update_n_downgrade_firmware_whonix(self):
old_version = None old_version = None
self.q.clean_cache(usbvm=True) self.q.clean_cache(usbvm=True)
self.q._get_dom0_devices() self.q._get_dom0_devices()
dom0_downgrades = self.q._parse_downgrades( dom0_downgrades = self.q._parse_downgrades(self.q.dom0_devices_info)
self.q.dom0_devices_info
)
self.q._get_usbvm_devices() self.q._get_usbvm_devices()
with open(FWUPD_VM_LOG) as usbvm_device_info: with open(FWUPD_VM_LOG) as usbvm_device_info:
raw = usbvm_device_info.read() raw = usbvm_device_info.read()
@ -525,8 +466,8 @@ class TestQubesFwupdmgr(unittest.TestCase):
break break
if old_version is None: if old_version is None:
self.fail("Test device not found") self.fail("Test device not found")
user_input = [str(number+1+len(dom0_downgrades)), '1'] user_input = [str(number + 1 + len(dom0_downgrades)), "1"]
with patch('builtins.input', side_effect=user_input): with patch("builtins.input", side_effect=user_input):
self.q.downgrade_firmware(usbvm=True, whonix=True) self.q.downgrade_firmware(usbvm=True, whonix=True)
self.q._get_usbvm_devices() self.q._get_usbvm_devices()
with open(FWUPD_VM_LOG) as usbvm_device_info: with open(FWUPD_VM_LOG) as usbvm_device_info:
@ -550,8 +491,8 @@ class TestQubesFwupdmgr(unittest.TestCase):
break break
if old_version is None: if old_version is None:
self.fail("Test device not found") self.fail("Test device not found")
user_input = [str(number+1+len(self.q.dom0_updates_list)), '1'] user_input = [str(number + 1 + len(self.q.dom0_updates_list)), "1"]
with patch('builtins.input', side_effect=user_input): with patch("builtins.input", side_effect=user_input):
self.q.update_firmware(usbvm=True, whonix=True) self.q.update_firmware(usbvm=True, whonix=True)
self.q._get_usbvm_devices() self.q._get_usbvm_devices()
with open(FWUPD_VM_LOG) as usbvm_device_info: with open(FWUPD_VM_LOG) as usbvm_device_info:
@ -571,9 +512,7 @@ class TestQubesFwupdmgr(unittest.TestCase):
def test_downgrade_firmware_usbvm(self): def test_downgrade_firmware_usbvm(self):
old_version = None old_version = None
self.q._get_dom0_devices() self.q._get_dom0_devices()
dom0_downgrades = self.q._parse_downgrades( dom0_downgrades = self.q._parse_downgrades(self.q.dom0_devices_info)
self.q.dom0_devices_info
)
self.q._get_usbvm_devices() self.q._get_usbvm_devices()
with open(FWUPD_VM_LOG) as usbvm_device_info: with open(FWUPD_VM_LOG) as usbvm_device_info:
raw = usbvm_device_info.read() raw = usbvm_device_info.read()
@ -586,8 +525,8 @@ class TestQubesFwupdmgr(unittest.TestCase):
break break
if old_version is None: if old_version is None:
self.fail("Test device not found") self.fail("Test device not found")
user_input = [str(number+1+len(dom0_downgrades)), '1'] user_input = [str(number + 1 + len(dom0_downgrades)), "1"]
with patch('builtins.input', side_effect=user_input): with patch("builtins.input", side_effect=user_input):
self.q.downgrade_firmware(usbvm=True) self.q.downgrade_firmware(usbvm=True)
self.q._get_usbvm_devices() self.q._get_usbvm_devices()
with open(FWUPD_VM_LOG) as usbvm_device_info: with open(FWUPD_VM_LOG) as usbvm_device_info:
@ -598,95 +537,62 @@ class TestQubesFwupdmgr(unittest.TestCase):
def test_parse_downgrades(self): def test_parse_downgrades(self):
downgrades = self.q._parse_downgrades(GET_DEVICES) downgrades = self.q._parse_downgrades(GET_DEVICES)
self.assertEqual( self.assertEqual(downgrades[0]["Name"], "ColorHug2")
downgrades[0]["Name"], self.assertEqual(downgrades[0]["Version"], "2.0.6")
"ColorHug2" self.assertEqual(downgrades[0]["Releases"][0]["Version"], "2.0.5")
)
self.assertEqual(
downgrades[0]["Version"],
"2.0.6"
)
self.assertEqual(
downgrades[0]["Releases"][0]["Version"],
"2.0.5"
)
self.assertEqual( self.assertEqual(
downgrades[0]["Releases"][0]["Url"], downgrades[0]["Releases"][0]["Url"],
"https://fwupd.org/downloads/f7dd4ab29fa610438571b8b62b26b0b0e57bb35b-hughski-colorhug2-2.0.5.cab" "https://fwupd.org/downloads/f7dd4ab29fa610438571b8b62b26b0b0e57bb35b-hughski-colorhug2-2.0.5.cab",
) )
self.assertEqual( self.assertEqual(
downgrades[0]["Releases"][0]["Checksum"], downgrades[0]["Releases"][0]["Checksum"],
"8cd379eb2e1467e4fda92c20650306dc7e598b1d421841bbe19d9ed6ea01e3ee" "8cd379eb2e1467e4fda92c20650306dc7e598b1d421841bbe19d9ed6ea01e3ee",
) )
def test_parse_downgrades_no_version(self): def test_parse_downgrades_no_version(self):
downgrades = self.q._parse_downgrades(GET_DEVICES_NO_VERSION) downgrades = self.q._parse_downgrades(GET_DEVICES_NO_VERSION)
self.assertEqual( self.assertEqual(downgrades[0]["Name"], "ColorHug2")
downgrades[0]["Name"], self.assertEqual(downgrades[0]["Version"], "2.0.6")
"ColorHug2" self.assertEqual(downgrades[0]["Releases"][0]["Version"], "2.0.5")
)
self.assertEqual(
downgrades[0]["Version"],
"2.0.6"
)
self.assertEqual(
downgrades[0]["Releases"][0]["Version"],
"2.0.5"
)
self.assertEqual( self.assertEqual(
downgrades[0]["Releases"][0]["Url"], downgrades[0]["Releases"][0]["Url"],
"https://fwupd.org/downloads/f7dd4ab29fa610438571b8b62b26b0b0e57bb35b-hughski-colorhug2-2.0.5.cab" "https://fwupd.org/downloads/f7dd4ab29fa610438571b8b62b26b0b0e57bb35b-hughski-colorhug2-2.0.5.cab",
) )
self.assertEqual( self.assertEqual(
downgrades[0]["Releases"][0]["Checksum"], downgrades[0]["Releases"][0]["Checksum"],
"4ee9dfa38df3b810f739d8a19d13da1b3175fb87" "4ee9dfa38df3b810f739d8a19d13da1b3175fb87",
) )
def test_user_input_downgrade_usbvm(self): def test_user_input_downgrade_usbvm(self):
user_input = ['2', '6', 'sth', '2.2.1', '', ' ', '\0', '2'] user_input = ["2", "6", "sth", "2.2.1", "", " ", "\0", "2"]
with patch('builtins.input', side_effect=user_input): with patch("builtins.input", side_effect=user_input):
downgrade_list = self.q._parse_downgrades(GET_DEVICES) downgrade_list = self.q._parse_downgrades(GET_DEVICES)
downgrade_dict = { downgrade_dict = {"usbvm": downgrade_list, "dom0": downgrade_list}
"usbvm": downgrade_list,
"dom0": downgrade_list
}
key, device_choice, downgrade_choice = self.q._user_input( key, device_choice, downgrade_choice = self.q._user_input(
downgrade_dict, downgrade_dict, downgrade=True, usbvm=True
downgrade=True,
usbvm=True
) )
self.assertEqual(key, "usbvm") self.assertEqual(key, "usbvm")
self.assertEqual(device_choice, 0) self.assertEqual(device_choice, 0)
self.assertEqual(downgrade_choice, 1) self.assertEqual(downgrade_choice, 1)
def test_user_input_downgrade_dom0(self): def test_user_input_downgrade_dom0(self):
user_input = ['1', '6', 'sth', '2.2.1', '', ' ', '\0', '2'] user_input = ["1", "6", "sth", "2.2.1", "", " ", "\0", "2"]
with patch('builtins.input', side_effect=user_input): with patch("builtins.input", side_effect=user_input):
downgrade_list = self.q._parse_downgrades(GET_DEVICES) downgrade_list = self.q._parse_downgrades(GET_DEVICES)
downgrade_dict = { downgrade_dict = {"dom0": downgrade_list}
"dom0": downgrade_list
}
key, device_choice, downgrade_choice = self.q._user_input( key, device_choice, downgrade_choice = self.q._user_input(
downgrade_dict, downgrade_dict, downgrade=True
downgrade=True,
) )
self.assertEqual(key, "dom0") self.assertEqual(key, "dom0")
self.assertEqual(device_choice, 0) self.assertEqual(device_choice, 0)
self.assertEqual(downgrade_choice, 1) self.assertEqual(downgrade_choice, 1)
def test_user_input_downgrade_N(self): def test_user_input_downgrade_N(self):
user_input = ['N'] user_input = ["N"]
with patch('builtins.input', side_effect=user_input): with patch("builtins.input", side_effect=user_input):
downgrade_list = self.q._parse_downgrades(GET_DEVICES) downgrade_list = self.q._parse_downgrades(GET_DEVICES)
downgrade_dict = { downgrade_dict = {"usbvm": downgrade_list, "dom0": downgrade_list}
"usbvm": downgrade_list, N_choice = self.q._user_input(downgrade_dict, downgrade=True, usbvm=True)
"dom0": downgrade_list
}
N_choice = self.q._user_input(
downgrade_dict,
downgrade=True,
usbvm=True
)
self.assertEqual(N_choice, 2) self.assertEqual(N_choice, 2)
@unittest.skipUnless(device_connected_dom0(), REQUIRED_DEV) @unittest.skipUnless(device_connected_dom0(), REQUIRED_DEV)
@ -704,7 +610,7 @@ class TestQubesFwupdmgr(unittest.TestCase):
if old_version is None: if old_version is None:
self.fail("Test device not found") self.fail("Test device not found")
user_input = [str(number + 1)] user_input = [str(number + 1)]
with patch('builtins.input', side_effect=user_input): with patch("builtins.input", side_effect=user_input):
self.q.update_firmware() self.q.update_firmware()
self.q._get_dom0_devices() self.q._get_dom0_devices()
dom0_devices_info_dict = json.loads(self.q.dom0_devices_info) dom0_devices_info_dict = json.loads(self.q.dom0_devices_info)
@ -736,8 +642,8 @@ class TestQubesFwupdmgr(unittest.TestCase):
break break
if old_version is None: if old_version is None:
self.fail("Test device not found") self.fail("Test device not found")
user_input = [str(number+1+len(self.q.dom0_updates_list)), '1'] user_input = [str(number + 1 + len(self.q.dom0_updates_list)), "1"]
with patch('builtins.input', side_effect=user_input): with patch("builtins.input", side_effect=user_input):
self.q.update_firmware(usbvm=True) self.q.update_firmware(usbvm=True)
self.q._get_usbvm_devices() self.q._get_usbvm_devices()
with open(FWUPD_VM_LOG) as usbvm_device_info: with open(FWUPD_VM_LOG) as usbvm_device_info:
@ -766,13 +672,13 @@ class TestQubesFwupdmgr(unittest.TestCase):
self.q.usbvm_updates_list[0]["Releases"], self.q.usbvm_updates_list[0]["Releases"],
[ [
{ {
'Checksum': '32c4a2c9be787cdf1d757c489d6455bd7bb14053425180b6d331c37e1ccc1cda', "Checksum": "32c4a2c9be787cdf1d757c489d6455bd7bb14053425180b6d331c37e1ccc1cda",
'Description': '<p>This release fixes prevents the firmware returning an ' "Description": "<p>This release fixes prevents the firmware returning an "
'error when the remote SHA1 hash was never sent.</p>', "error when the remote SHA1 hash was never sent.</p>",
'Url': 'https://fwupd.org/downloads/0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7.cab', "Url": "https://fwupd.org/downloads/0a29848de74d26348bc5a6e24fc9f03778eddf0e-hughski-colorhug2-2.0.7.cab",
'Version': '2.0.7' "Version": "2.0.7",
} }
] ],
) )
def test_parse_usbvm_updates_no_updates_available(self): def test_parse_usbvm_updates_no_updates_available(self):
@ -786,8 +692,7 @@ class TestQubesFwupdmgr(unittest.TestCase):
self.q._updates_crawler(self.q.usbvm_updates_list, usbvm=True) self.q._updates_crawler(self.q.usbvm_updates_list, usbvm=True)
with open("test/logs/get_updates.log", "r") as getupdates: with open("test/logs/get_updates.log", "r") as getupdates:
self.assertEqual( self.assertEqual(
getupdates.read(), getupdates.read(), crawler_output.getvalue().strip() + "\n"
crawler_output.getvalue().strip() + "\n"
) )
sys.stdout = self.captured_output sys.stdout = self.captured_output
@ -798,33 +703,25 @@ class TestQubesFwupdmgr(unittest.TestCase):
"qvm-run", "qvm-run",
"--pass-io", "--pass-io",
"sys-usb", "sys-usb",
f"[ -d {FWUPD_VM_METADATA_DIR} ]" f"[ -d {FWUPD_VM_METADATA_DIR} ]",
] ]
p = subprocess.Popen(cmd_validate_metadata) p = subprocess.Popen(cmd_validate_metadata)
p.wait() p.wait()
self.assertEqual( self.assertEqual(p.returncode, 0, msg="Creating metadata directory failed")
p.returncode,
0,
msg="Creating metadata directory failed"
)
cmd_validate_udpdate = [ cmd_validate_udpdate = [
"qvm-run", "qvm-run",
"--pass-io", "--pass-io",
"sys-usb", "sys-usb",
f"[ -d {FWUPD_VM_UPDATES_DIR} ]" f"[ -d {FWUPD_VM_UPDATES_DIR} ]",
] ]
p = subprocess.Popen(cmd_validate_udpdate) p = subprocess.Popen(cmd_validate_udpdate)
p.wait() p.wait()
self.assertEqual( self.assertEqual(p.returncode, 0, msg="Creating update directory failed")
p.returncode,
0,
msg="Creating update directory failed"
)
@unittest.skipUnless(check_usbvm(), REQUIRED_USBVM) @unittest.skipUnless(check_usbvm(), REQUIRED_USBVM)
def test_copy_usbvm_metadata(self): def test_copy_usbvm_metadata(self):
self.q.metadata_file = FWUPD_DOM0_METADATA_FILE self.q.metadata_file = FWUPD_DOM0_METADATA_FILE
self.q.metadata_file_jcat = self.q.metadata_file + '.jcat' self.q.metadata_file_jcat = self.q.metadata_file + ".jcat"
self.q._download_metadata() self.q._download_metadata()
self.q._validate_usbvm_dirs() self.q._validate_usbvm_dirs()
self.q._copy_usbvm_metadata() self.q._copy_usbvm_metadata()
@ -832,30 +729,22 @@ class TestQubesFwupdmgr(unittest.TestCase):
"qvm-run", "qvm-run",
"--pass-io", "--pass-io",
"sys-usb", "sys-usb",
f"[ -f {FWUPD_VM_METADATA_FILE} ]" f"[ -f {FWUPD_VM_METADATA_FILE} ]",
] ]
p = subprocess.Popen(cmd_validate_metadata_file) p = subprocess.Popen(cmd_validate_metadata_file)
p.wait() p.wait()
self.assertEqual( self.assertEqual(p.returncode, 0, msg="Metadata file does not exist")
p.returncode,
0,
msg="Metadata file does not exist"
)
cmd_validate_metadata_jcat = [ cmd_validate_metadata_jcat = [
"qvm-run", "qvm-run",
"--pass-io", "--pass-io",
"sys-usb", "sys-usb",
f"[ -f {FWUPD_VM_METADATA_FILE_JCAT} ]" f"[ -f {FWUPD_VM_METADATA_FILE_JCAT} ]",
] ]
p = subprocess.Popen(cmd_validate_metadata_jcat) p = subprocess.Popen(cmd_validate_metadata_jcat)
p.wait() p.wait()
self.assertEqual( self.assertEqual(p.returncode, 0, msg="Metadata jcat signature does not exist")
p.returncode,
0,
msg="Metadata jcat signature does not exist"
)
@unittest.skipUnless('qubes' in platform.release(), "Requires Qubes OS") @unittest.skipUnless("qubes" in platform.release(), "Requires Qubes OS")
def test_enable_lvfs_testing_dom0(self): def test_enable_lvfs_testing_dom0(self):
if os.path.exists(LVFS_TESTING_DOM0_FLAG): if os.path.exists(LVFS_TESTING_DOM0_FLAG):
os.remove(LVFS_TESTING_DOM0_FLAG) os.remove(LVFS_TESTING_DOM0_FLAG)
@ -869,18 +758,15 @@ class TestQubesFwupdmgr(unittest.TestCase):
"--pass-io", "--pass-io",
USBVM_N, USBVM_N,
( (
'script --quiet --return --command ' "script --quiet --return --command "
f'"ls {LVFS_TESTING_USBVM_FLAG} &>/dev/null"' f'"ls {LVFS_TESTING_USBVM_FLAG} &>/dev/null"'
) ),
] ]
cmd_rm_flag = [ cmd_rm_flag = [
"qvm-run", "qvm-run",
"--pass-io", "--pass-io",
USBVM_N, USBVM_N,
( ("script --quiet --return --command " f'"rm {LVFS_TESTING_USBVM_FLAG}"'),
'script --quiet --return --command '
f'"rm {LVFS_TESTING_USBVM_FLAG}"'
)
] ]
flag = subprocess.Popen(cmd_validate_flag) flag = subprocess.Popen(cmd_validate_flag)
flag.wait() flag.wait()
@ -897,7 +783,7 @@ class TestQubesFwupdmgr(unittest.TestCase):
@unittest.skipUnless(check_usbvm(), REQUIRED_USBVM) @unittest.skipUnless(check_usbvm(), REQUIRED_USBVM)
def test_validate_usbvm_metadata(self): def test_validate_usbvm_metadata(self):
self.q.metadata_file = FWUPD_DOM0_METADATA_FILE self.q.metadata_file = FWUPD_DOM0_METADATA_FILE
self.q.metadata_file_jcat = self.q.metadata_file + '.jcat' self.q.metadata_file_jcat = self.q.metadata_file + ".jcat"
self.q._download_metadata() self.q._download_metadata()
self.q._validate_usbvm_dirs() self.q._validate_usbvm_dirs()
self.q._copy_usbvm_metadata() self.q._copy_usbvm_metadata()
@ -906,7 +792,7 @@ class TestQubesFwupdmgr(unittest.TestCase):
@unittest.skipUnless(check_usbvm(), REQUIRED_USBVM) @unittest.skipUnless(check_usbvm(), REQUIRED_USBVM)
def test_refresh_usbvm_metadata(self): def test_refresh_usbvm_metadata(self):
self.q.metadata_file = FWUPD_DOM0_METADATA_FILE self.q.metadata_file = FWUPD_DOM0_METADATA_FILE
self.q.metadata_file_jcat = self.q.metadata_file + '.jcat' self.q.metadata_file_jcat = self.q.metadata_file + ".jcat"
self.q.lvfs = "lvfs" self.q.lvfs = "lvfs"
self.q._download_metadata() self.q._download_metadata()
self.q._validate_usbvm_dirs() self.q._validate_usbvm_dirs()
@ -922,28 +808,20 @@ class TestQubesFwupdmgr(unittest.TestCase):
"qvm-run", "qvm-run",
"--pass-io", "--pass-io",
"sys-usb", "sys-usb",
f"! [ -d {FWUPD_VM_METADATA_DIR} ]" f"! [ -d {FWUPD_VM_METADATA_DIR} ]",
] ]
p = subprocess.Popen(cmd_validate_metadata) p = subprocess.Popen(cmd_validate_metadata)
p.wait() p.wait()
self.assertEqual( self.assertEqual(p.returncode, 0, msg="Cleaning metadata directory failed")
p.returncode,
0,
msg="Cleaning metadata directory failed"
)
cmd_validate_udpdate = [ cmd_validate_udpdate = [
"qvm-run", "qvm-run",
"--pass-io", "--pass-io",
"sys-usb", "sys-usb",
f"! [ -d {FWUPD_VM_METADATA_DIR} ]" f"! [ -d {FWUPD_VM_METADATA_DIR} ]",
] ]
p = subprocess.Popen(cmd_validate_udpdate) p = subprocess.Popen(cmd_validate_udpdate)
p.wait() p.wait()
self.assertEqual( self.assertEqual(p.returncode, 0, msg="Cleaning update directory failed")
p.returncode,
0,
msg="Cleaning update directory failed"
)
@unittest.skipUnless(check_usbvm(), REQUIRED_USBVM) @unittest.skipUnless(check_usbvm(), REQUIRED_USBVM)
def test_validate_usbvm_archive(self): def test_validate_usbvm_archive(self):
@ -952,46 +830,33 @@ class TestQubesFwupdmgr(unittest.TestCase):
name = url.replace("https://fwupd.org/downloads/", "") name = url.replace("https://fwupd.org/downloads/", "")
self.q._clean_usbvm() self.q._clean_usbvm()
self.q._validate_usbvm_dirs() self.q._validate_usbvm_dirs()
self.q._download_firmware_updates( self.q._download_firmware_updates(url, sha)
url, self.q._copy_firmware_updates(name)
sha self.q._validate_usbvm_archive(name, sha)
)
self.q._copy_firmware_updates(
name
)
self.q._validate_usbvm_archive(
name,
sha
)
cmd_validate_udpdate = [ cmd_validate_udpdate = [
"qvm-run", "qvm-run",
"--pass-io", "--pass-io",
"sys-usb", "sys-usb",
"[ -f %s ]" % "[ -f %s ]" % os.path.join(FWUPD_VM_UPDATES_DIR, name),
os.path.join(FWUPD_VM_UPDATES_DIR, name)
] ]
p = subprocess.Popen(cmd_validate_udpdate) p = subprocess.Popen(cmd_validate_udpdate)
p.wait() p.wait()
self.assertEqual( self.assertEqual(p.returncode, 0, msg="Archive validation failed")
p.returncode,
0,
msg="Archive validation failed"
)
@unittest.skipUnless('qubes' in platform.release(), "Requires Qubes OS") @unittest.skipUnless("qubes" in platform.release(), "Requires Qubes OS")
def test_check_usbvm(self): def test_check_usbvm(self):
self.q.check_usbvm() self.q.check_usbvm()
self.assertIn(XL_LIST_LOG, self.q.output) self.assertIn(XL_LIST_LOG, self.q.output)
@unittest.skipUnless('qubes' in platform.release(), "Requires Qubes OS") @unittest.skipUnless("qubes" in platform.release(), "Requires Qubes OS")
def test_bios_refresh_metadata(self): def test_bios_refresh_metadata(self):
sys_usb = self.q.check_usbvm() sys_usb = self.q.check_usbvm()
Path(BIOS_UPDATE_FLAG).touch(mode=0o644, exist_ok=True) Path(BIOS_UPDATE_FLAG).touch(mode=0o644, exist_ok=True)
self.q.refresh_metadata_after_bios_update(usbvm=sys_usb) self.q.refresh_metadata_after_bios_update(usbvm=sys_usb)
self.assertEqual( self.assertEqual(
self.q.output, self.q.output,
'Successfully refreshed metadata manually\n', "Successfully refreshed metadata manually\n",
msg="Metadata refresh failed." msg="Metadata refresh failed.",
) )
@unittest.skipUnless(check_usbvm(), REQUIRED_USBVM) @unittest.skipUnless(check_usbvm(), REQUIRED_USBVM)
@ -1006,5 +871,5 @@ class TestQubesFwupdmgr(unittest.TestCase):
self.assertFalse(os.path.exists(trusted_path.replace(".cab", ""))) self.assertFalse(os.path.exists(trusted_path.replace(".cab", "")))
if __name__ == '__main__': if __name__ == "__main__":
unittest.main() unittest.main()

View File

@ -13,7 +13,7 @@ import shutil
import tempfile import tempfile
import zipfile import zipfile
TAG = b'#\x00' TAG = b"#\x00"
def parse_args(): def parse_args():
@ -23,19 +23,19 @@ def parse_args():
parser.add_argument("--directory", help="Directory to extract to") parser.add_argument("--directory", help="Directory to extract to")
parser.add_argument( parser.add_argument(
"--cleanup", "--cleanup",
action='store_true', action="store_true",
help="Remove tools when done with installation", help="Remove tools when done with installation",
) )
parser.add_argument( parser.add_argument(
"--verbose", action='store_true', help="Run the tool in verbose mode" "--verbose", action="store_true", help="Run the tool in verbose mode"
) )
parser.add_argument( parser.add_argument(
"--allow-reinstall", "--allow-reinstall",
action='store_true', action="store_true",
help="Allow re-installing existing firmware versions", help="Allow re-installing existing firmware versions",
) )
parser.add_argument( parser.add_argument(
"--allow-older", action='store_true', help="Allow downgrading firmware versions" "--allow-older", action="store_true", help="Allow downgrading firmware versions"
) )
parser.add_argument( parser.add_argument(
"command", choices=["install", "extract"], help="Command to run" "command", choices=["install", "extract"], help="Command to run"
@ -61,7 +61,7 @@ def bytes_slicer(length, source):
def get_zip(): def get_zip():
script = os.path.realpath(__file__) script = os.path.realpath(__file__)
bytes_out = io.BytesIO() bytes_out = io.BytesIO()
with open(script, 'rb') as source: with open(script, "rb") as source:
for line in source: for line in source:
if not line.startswith(TAG): if not line.startswith(TAG):
continue continue
@ -71,7 +71,7 @@ def get_zip():
def unzip(destination): def unzip(destination):
zipf = get_zip() zipf = get_zip()
source = zipfile.ZipFile(zipf, 'r') source = zipfile.ZipFile(zipf, "r")
for item in source.namelist(): for item in source.namelist():
# extract handles the sanitization # extract handles the sanitization
source.extract(item, destination) source.extract(item, destination)
@ -83,7 +83,7 @@ def copy_cabs(source, target):
cabs = [] cabs = []
for root, dirs, files in os.walk(source): for root, dirs, files in os.walk(source):
for f in files: for f in files:
if f.endswith('.cab'): if f.endswith(".cab"):
origf = os.path.join(root, f) origf = os.path.join(root, f)
shutil.copy(origf, target) shutil.copy(origf, target)
cabs.append(os.path.join(target, f)) cabs.append(os.path.join(target, f))
@ -91,31 +91,31 @@ def copy_cabs(source, target):
def install_snap(directory, verbose, allow_reinstall, allow_older, uninstall): def install_snap(directory, verbose, allow_reinstall, allow_older, uninstall):
app = 'fwupd' app = "fwupd"
common = '/root/snap/%s/common' % app common = "/root/snap/%s/common" % app
# check if snap is installed # check if snap is installed
with open(os.devnull, 'w') as devnull: with open(os.devnull, "w") as devnull:
subprocess.run(['snap'], check=True, stdout=devnull, stderr=devnull) subprocess.run(["snap"], check=True, stdout=devnull, stderr=devnull)
# check existing installed # check existing installed
cmd = ['snap', 'list', app] cmd = ["snap", "list", app]
with open(os.devnull, 'w') as devnull: with open(os.devnull, "w") as devnull:
if verbose: if verbose:
print(cmd) print(cmd)
ret = subprocess.run(cmd, stdout=devnull, stderr=devnull) ret = subprocess.run(cmd, stdout=devnull, stderr=devnull)
if ret.returncode == 0: if ret.returncode == 0:
cmd = ['snap', 'remove', app] cmd = ["snap", "remove", app]
if verbose: if verbose:
print(cmd) print(cmd)
subprocess.run(cmd, check=True) subprocess.run(cmd, check=True)
# install the snap # install the snap
cmd = ['snap', 'ack', os.path.join(directory, 'fwupd.assert')] cmd = ["snap", "ack", os.path.join(directory, "fwupd.assert")]
if verbose: if verbose:
print(cmd) print(cmd)
subprocess.run(cmd, check=True) subprocess.run(cmd, check=True)
cmd = ['snap', 'install', '--classic', os.path.join(directory, 'fwupd.snap')] cmd = ["snap", "install", "--classic", os.path.join(directory, "fwupd.snap")]
if verbose: if verbose:
print(cmd) print(cmd)
subprocess.run(cmd, check=True) subprocess.run(cmd, check=True)
@ -125,7 +125,7 @@ def install_snap(directory, verbose, allow_reinstall, allow_older, uninstall):
# run the snap # run the snap
for cab in cabs: for cab in cabs:
cmd = ["%s.fwupdmgr" % app, 'install', cab] cmd = ["%s.fwupdmgr" % app, "install", cab]
if allow_reinstall: if allow_reinstall:
cmd += ["--allow-reinstall"] cmd += ["--allow-reinstall"]
if allow_older: if allow_older:
@ -141,61 +141,61 @@ def install_snap(directory, verbose, allow_reinstall, allow_older, uninstall):
# cleanup # cleanup
if uninstall: if uninstall:
cmd = ['snap', 'remove', app] cmd = ["snap", "remove", app]
if verbose: if verbose:
print(cmd) print(cmd)
subprocess.run(cmd) subprocess.run(cmd)
def install_flatpak(directory, verbose, allow_reinstall, allow_older, uninstall): def install_flatpak(directory, verbose, allow_reinstall, allow_older, uninstall):
app = 'org.freedesktop.fwupd' app = "org.freedesktop.fwupd"
common = '%s/.var/app/%s' % (os.getenv('HOME'), app) common = "%s/.var/app/%s" % (os.getenv("HOME"), app)
with open(os.devnull, 'w') as devnull: with open(os.devnull, "w") as devnull:
if not verbose: if not verbose:
output = devnull output = devnull
else: else:
output = None output = None
# look for dependencies # look for dependencies
dep = 'org.gnome.Platform/x86_64/3.30' dep = "org.gnome.Platform/x86_64/3.30"
repo = 'flathub' repo = "flathub"
repo_url = 'https://flathub.org/repo/flathub.flatpakrepo' repo_url = "https://flathub.org/repo/flathub.flatpakrepo"
cmd = ['flatpak', 'info', dep] cmd = ["flatpak", "info", dep]
if verbose: if verbose:
print(cmd) print(cmd)
ret = subprocess.run(cmd, stdout=output, stderr=output) ret = subprocess.run(cmd, stdout=output, stderr=output)
# not installed # not installed
if ret.returncode != 0: if ret.returncode != 0:
# look for remotes # look for remotes
cmd = ['flatpak', 'remote-info', repo, dep] cmd = ["flatpak", "remote-info", repo, dep]
if verbose: if verbose:
print(cmd) print(cmd)
ret = subprocess.run(cmd, stdout=output, stderr=output) ret = subprocess.run(cmd, stdout=output, stderr=output)
# not enabled, enable it # not enabled, enable it
if ret.returncode != 0: if ret.returncode != 0:
cmd = ['flatpak', 'remote-add', repo, repo_url] cmd = ["flatpak", "remote-add", repo, repo_url]
if verbose: if verbose:
print(cmd) print(cmd)
ret = subprocess.run(cmd, stderr=output) ret = subprocess.run(cmd, stderr=output)
# install dep # install dep
cmd = ['flatpak', 'install', repo, dep] cmd = ["flatpak", "install", repo, dep]
if verbose: if verbose:
print(cmd) print(cmd)
ret = subprocess.run(cmd) ret = subprocess.run(cmd)
# check existing installed # check existing installed
cmd = ['flatpak', 'info', app] cmd = ["flatpak", "info", app]
if verbose: if verbose:
print(cmd) print(cmd)
ret = subprocess.run(cmd, stdout=output, stderr=output) ret = subprocess.run(cmd, stdout=output, stderr=output)
if ret.returncode == 0: if ret.returncode == 0:
cmd = ['flatpak', 'remove', app] cmd = ["flatpak", "remove", app]
if verbose: if verbose:
print(cmd) print(cmd)
subprocess.run(cmd, check=True) subprocess.run(cmd, check=True)
# install the flatpak # install the flatpak
cmd = ['flatpak', 'install', os.path.join(directory, 'fwupd.flatpak')] cmd = ["flatpak", "install", os.path.join(directory, "fwupd.flatpak")]
if verbose: if verbose:
print(cmd) print(cmd)
subprocess.run(cmd, check=True) subprocess.run(cmd, check=True)
@ -205,7 +205,7 @@ def install_flatpak(directory, verbose, allow_reinstall, allow_older, uninstall)
# run command # run command
for cab in cabs: for cab in cabs:
cmd = ['flatpak', 'run', app, 'install', cab] cmd = ["flatpak", "run", app, "install", cab]
if allow_reinstall: if allow_reinstall:
cmd += ["--allow-reinstall"] cmd += ["--allow-reinstall"]
if allow_older: if allow_older:
@ -221,7 +221,7 @@ def install_flatpak(directory, verbose, allow_reinstall, allow_older, uninstall)
# cleanup # cleanup
if uninstall: if uninstall:
cmd = ['flatpak', 'remove', app] cmd = ["flatpak", "remove", app]
if verbose: if verbose:
print(cmd) print(cmd)
subprocess.run(cmd) subprocess.run(cmd)
@ -261,10 +261,10 @@ def remove_packaged_version(pkg, cache):
res = False res = False
while True: while True:
res = input("Remove now (Y/N)? ") res = input("Remove now (Y/N)? ")
if res.lower() == 'n': if res.lower() == "n":
res = False res = False
break break
if res.lower() == 'y': if res.lower() == "y":
res = True res = True
break break
if res: if res:
@ -279,11 +279,11 @@ def install_builtin(directory, verbose, allow_reinstall, allow_older):
cabs = [] cabs = []
for root, dirs, files in os.walk(directory): for root, dirs, files in os.walk(directory):
for f in files: for f in files:
if f.endswith('.cab'): if f.endswith(".cab"):
cabs.append(os.path.join(root, f)) cabs.append(os.path.join(root, f))
# run command # run command
for cab in cabs: for cab in cabs:
cmd = ['fwupdmgr', 'install', cab] cmd = ["fwupdmgr", "install", cab]
if allow_reinstall: if allow_reinstall:
cmd += ["--allow-reinstall"] cmd += ["--allow-reinstall"]
if allow_older: if allow_older:
@ -310,11 +310,11 @@ def run_installation(directory, verbose, allow_reinstall, allow_older, uninstall
return return
# determine what self extracting binary has # determine what self extracting binary has
if os.path.exists(os.path.join(directory, 'fwupd.snap')) and os.path.exists( if os.path.exists(os.path.join(directory, "fwupd.snap")) and os.path.exists(
os.path.join(directory, 'fwupd.assert') os.path.join(directory, "fwupd.assert")
): ):
try_snap = True try_snap = True
if os.path.exists(os.path.join(directory, 'fwupd.flatpak')): if os.path.exists(os.path.join(directory, "fwupd.flatpak")):
try_flatpak = True try_flatpak = True
if try_snap: if try_snap:
@ -330,9 +330,9 @@ def run_installation(directory, verbose, allow_reinstall, allow_older, uninstall
install_flatpak(directory, verbose, allow_reinstall, allow_older, uninstall) install_flatpak(directory, verbose, allow_reinstall, allow_older, uninstall)
if __name__ == '__main__': if __name__ == "__main__":
args = parse_args() args = parse_args()
if 'extract' in args.command: if "extract" in args.command:
if args.allow_reinstall: if args.allow_reinstall:
error( error(
"allow-reinstall argument doesn't make sense with command %s" "allow-reinstall argument doesn't make sense with command %s"
@ -358,7 +358,7 @@ if __name__ == '__main__':
) )
if os.getuid() != 0: if os.getuid() != 0:
error("This tool must be run as root") error("This tool must be run as root")
with tempfile.TemporaryDirectory(prefix='fwupd') as target: with tempfile.TemporaryDirectory(prefix="fwupd") as target:
unzip(target) unzip(target)
run_installation( run_installation(
target, target,

View File

@ -28,12 +28,12 @@ def parse_args():
) )
parser.add_argument( parser.add_argument(
"--disable-snap-download", "--disable-snap-download",
action='store_true', action="store_true",
help="Don't download support for snap", help="Don't download support for snap",
) )
parser.add_argument( parser.add_argument(
"--disable-flatpak-download", "--disable-flatpak-download",
action='store_true', action="store_true",
help="Don't download support for flatpak", help="Don't download support for flatpak",
) )
parser.add_argument( parser.add_argument(
@ -46,7 +46,7 @@ def parse_args():
"cab", "cab",
help="CAB file or directory containing CAB files to automatically install", help="CAB file or directory containing CAB files to automatically install",
) )
parser.add_argument('target', help='target file to create') parser.add_argument("target", help="target file to create")
args = parser.parse_args() args = parser.parse_args()
return args return args
@ -74,80 +74,80 @@ def generate_installer(directory, target):
source = os.path.join(root, f) source = os.path.join(root, f)
archive_fname = source.split(directory)[1] archive_fname = source.split(directory)[1]
archive.write(source, archive_fname) archive.write(source, archive_fname)
if 'DEBUG' in os.environ: if "DEBUG" in os.environ:
print(archive.namelist()) print(archive.namelist())
archive.close() archive.close()
with open(target, 'ab') as bytes_out: with open(target, "ab") as bytes_out:
encoded = b64encode(buffer.getvalue()) encoded = b64encode(buffer.getvalue())
for section in bytes_slicer(64, encoded): for section in bytes_slicer(64, encoded):
bytes_out.write(TAG) bytes_out.write(TAG)
bytes_out.write(section) bytes_out.write(section)
bytes_out.write(b'\n') bytes_out.write(b"\n")
def download_snap(directory, channel): def download_snap(directory, channel):
cmd = ['snap', 'download', 'fwupd'] cmd = ["snap", "download", "fwupd"]
if channel is not None: if channel is not None:
cmd += ['--channel', channel] cmd += ["--channel", channel]
if 'DEBUG' in os.environ: if "DEBUG" in os.environ:
print(cmd) print(cmd)
subprocess.run(cmd, cwd=directory, check=True) subprocess.run(cmd, cwd=directory, check=True)
for f in os.listdir(directory): for f in os.listdir(directory):
# the signatures associated with the snap # the signatures associated with the snap
if f.endswith(".assert"): if f.endswith(".assert"):
shutil.move( shutil.move(
os.path.join(directory, f), os.path.join(directory, 'fwupd.assert') os.path.join(directory, f), os.path.join(directory, "fwupd.assert")
) )
# the snap binary itself # the snap binary itself
elif f.endswith(".snap"): elif f.endswith(".snap"):
shutil.move( shutil.move(
os.path.join(directory, f), os.path.join(directory, 'fwupd.snap') os.path.join(directory, f), os.path.join(directory, "fwupd.snap")
) )
def download_cab_file(directory, uri): def download_cab_file(directory, uri):
cmd = ['wget', uri] cmd = ["wget", uri]
if 'DEBUG' in os.environ: if "DEBUG" in os.environ:
print(cmd) print(cmd)
subprocess.run(cmd, cwd=directory, check=True) subprocess.run(cmd, cwd=directory, check=True)
def download_flatpak(directory): def download_flatpak(directory):
dep = 'org.freedesktop.fwupd' dep = "org.freedesktop.fwupd"
flatpak_dir = os.path.join(os.getenv('HOME'), '.local', 'share', 'flatpak') flatpak_dir = os.path.join(os.getenv("HOME"), ".local", "share", "flatpak")
verbose = 'DEBUG' in os.environ verbose = "DEBUG" in os.environ
# check if we have installed locally already or not # check if we have installed locally already or not
if not os.path.exists(os.path.join(flatpak_dir, 'app', dep)): if not os.path.exists(os.path.join(flatpak_dir, "app", dep)):
# install into local user's repo # install into local user's repo
cmd = [ cmd = [
'flatpak', "flatpak",
'install', "install",
'--user', "--user",
'https://www.flathub.org/repo/appstream/org.freedesktop.fwupd.flatpakref', "https://www.flathub.org/repo/appstream/org.freedesktop.fwupd.flatpakref",
'--no-deps', "--no-deps",
'-y', "-y",
] ]
if verbose: if verbose:
print(cmd) print(cmd)
subprocess.run(cmd, cwd=directory, check=True) subprocess.run(cmd, cwd=directory, check=True)
# generate a bundle # generate a bundle
repo = os.path.join(flatpak_dir, 'repo') repo = os.path.join(flatpak_dir, "repo")
cmd = ['flatpak', 'build-bundle', repo, 'fwupd.flatpak', dep, 'stable'] cmd = ["flatpak", "build-bundle", repo, "fwupd.flatpak", dep, "stable"]
if verbose: if verbose:
print(cmd) print(cmd)
subprocess.run(cmd, cwd=directory, check=True) subprocess.run(cmd, cwd=directory, check=True)
if __name__ == '__main__': if __name__ == "__main__":
args = parse_args() args = parse_args()
if not args.cab.startswith("http"): if not args.cab.startswith("http"):
local = args.cab local = args.cab
with tempfile.TemporaryDirectory(prefix='fwupd') as directory: with tempfile.TemporaryDirectory(prefix="fwupd") as directory:
if local: if local:
if not os.path.exists(local): if not os.path.exists(local):
error("%s doesn't exist" % local) error("%s doesn't exist" % local)

View File

@ -14,7 +14,7 @@ import glob
import json import json
from termcolor import colored from termcolor import colored
gi.require_version('Fwupd', '2.0') gi.require_version("Fwupd", "2.0")
from gi.repository import Fwupd from gi.repository import Fwupd
from gi.repository import Gio from gi.repository import Gio
@ -22,16 +22,16 @@ from gi.repository import GLib
def _get_cache_file(fn): def _get_cache_file(fn):
cachedir = os.path.expanduser('~/.cache/fwupdmgr') cachedir = os.path.expanduser("~/.cache/fwupdmgr")
if not os.path.exists(cachedir): if not os.path.exists(cachedir):
os.makedirs(cachedir) os.makedirs(cachedir)
cachefn = os.path.join(cachedir, fn) cachefn = os.path.join(cachedir, fn)
if not os.path.exists(cachefn): if not os.path.exists(cachefn):
url = 'https://fwupd.org/downloads/' + fn url = "https://fwupd.org/downloads/" + fn
print("Downloading", url) print("Downloading", url)
r = requests.get(url) r = requests.get(url)
r.raise_for_status() r.raise_for_status()
f = open(cachefn, 'wb') f = open(cachefn, "wb")
f.write(r.content) f.write(r.content)
f.close() f.close()
return cachefn return cachefn
@ -40,25 +40,25 @@ def _get_cache_file(fn):
class DeviceTest: class DeviceTest:
def __init__(self, obj): def __init__(self, obj):
self.client = Fwupd.Client.new() self.client = Fwupd.Client.new()
self.name = obj.get('name', 'Unknown') self.name = obj.get("name", "Unknown")
self.guids = obj.get('guids', []) self.guids = obj.get("guids", [])
self.releases = obj.get('releases', []) self.releases = obj.get("releases", [])
self.has_runtime = obj.get('runtime', True) self.has_runtime = obj.get("runtime", True)
self.interactive = obj.get('interactive', False) self.interactive = obj.get("interactive", False)
self.disabled = obj.get('disabled', False) self.disabled = obj.get("disabled", False)
self.protocol = obj.get('protocol', None) self.protocol = obj.get("protocol", None)
def _info(self, msg): def _info(self, msg):
print(colored('[INFO]'.ljust(10), 'blue'), msg) print(colored("[INFO]".ljust(10), "blue"), msg)
def _warn(self, msg): def _warn(self, msg):
print(colored('[WARN]'.ljust(10), 'yellow'), msg) print(colored("[WARN]".ljust(10), "yellow"), msg)
def _failed(self, msg): def _failed(self, msg):
print(colored('[FAILED]'.ljust(10), 'red'), msg) print(colored("[FAILED]".ljust(10), "red"), msg)
def _success(self, msg): def _success(self, msg):
print(colored('[SUCCESS]'.ljust(10), 'green'), msg) print(colored("[SUCCESS]".ljust(10), "green"), msg)
def _get_by_device_guids(self): def _get_by_device_guids(self):
cancellable = Gio.Cancellable.new() cancellable = Gio.Cancellable.new()
@ -72,82 +72,82 @@ class DeviceTest:
def run(self): def run(self):
print('Running test on {}'.format(self.name)) print("Running test on {}".format(self.name))
dev = self._get_by_device_guids() dev = self._get_by_device_guids()
if not dev: if not dev:
self._warn('no {} attached'.format(self.name)) self._warn("no {} attached".format(self.name))
return return
self._info('Current version {}'.format(dev.get_version())) self._info("Current version {}".format(dev.get_version()))
# apply each file # apply each file
for obj in self.releases: for obj in self.releases:
ver = obj.get('version') ver = obj.get("version")
fn = obj.get('file') fn = obj.get("file")
repeat = obj.get('repeat', 1) repeat = obj.get("repeat", 1)
try: try:
fn_cache = _get_cache_file(fn) fn_cache = _get_cache_file(fn)
except requests.exceptions.HTTPError as e: except requests.exceptions.HTTPError as e:
self._failed('Failed to download: {}'.format(str(e))) self._failed("Failed to download: {}".format(str(e)))
return return
# some hardware updates more than one partition with the same firmware # some hardware updates more than one partition with the same firmware
for cnt in range(0, repeat): for cnt in range(0, repeat):
if dev.get_version() == ver: if dev.get_version() == ver:
flags = Fwupd.InstallFlags.ALLOW_REINSTALL flags = Fwupd.InstallFlags.ALLOW_REINSTALL
self._info('Reinstalling version {}'.format(ver)) self._info("Reinstalling version {}".format(ver))
else: else:
flags = Fwupd.InstallFlags.ALLOW_OLDER flags = Fwupd.InstallFlags.ALLOW_OLDER
self._info('Installing version {}'.format(ver)) self._info("Installing version {}".format(ver))
cancellable = Gio.Cancellable.new() cancellable = Gio.Cancellable.new()
try: try:
self.client.install(dev.get_id(), fn_cache, flags, cancellable) self.client.install(dev.get_id(), fn_cache, flags, cancellable)
except GLib.Error as e: except GLib.Error as e:
if str(e).find('no HWIDs matched') != -1: if str(e).find("no HWIDs matched") != -1:
self._info('Skipping as {}'.format(e)) self._info("Skipping as {}".format(e))
continue continue
self._failed('Could not install: {}'.format(e)) self._failed("Could not install: {}".format(e))
return return
# verify version # verify version
if self.has_runtime: if self.has_runtime:
dev = self._get_by_device_guids() dev = self._get_by_device_guids()
if not dev: if not dev:
self._failed('Device did not come back: ' + self.name) self._failed("Device did not come back: " + self.name)
return return
if not dev.get_version(): if not dev.get_version():
self._failed('No version set after flash for: ' + self.name) self._failed("No version set after flash for: " + self.name)
return return
if cnt == repeat - 1 and dev.get_version() != ver: if cnt == repeat - 1 and dev.get_version() != ver:
self._failed('Got: ' + dev.get_version() + ', expected: ' + ver) self._failed("Got: " + dev.get_version() + ", expected: " + ver)
return return
self._success('Installed {}'.format(dev.get_version())) self._success("Installed {}".format(dev.get_version()))
else: else:
self._success('Assumed success (no runtime)') self._success("Assumed success (no runtime)")
# wait for device to settle? # wait for device to settle?
time.sleep(2) time.sleep(2)
if __name__ == '__main__': if __name__ == "__main__":
# get manifests to parse # get manifests to parse
device_fns = [] device_fns = []
if len(sys.argv) == 1: if len(sys.argv) == 1:
device_fns.extend(glob.glob('devices/*.json')) device_fns.extend(glob.glob("devices/*.json"))
else: else:
for fn in sys.argv[1:]: for fn in sys.argv[1:]:
device_fns.append(fn) device_fns.append(fn)
# run each test # run each test
for fn in sorted(device_fns): for fn in sorted(device_fns):
print('{}:'.format(fn)) print("{}:".format(fn))
with open(fn, 'r') as f: with open(fn, "r") as f:
try: try:
obj = json.load(f) obj = json.load(f)
except json.decoder.JSONDecodeError as e: except json.decoder.JSONDecodeError as e:
print('Failed to parse {}: {}'.format(fn, e)) print("Failed to parse {}: {}".format(fn, e))
continue continue
t = DeviceTest(obj) t = DeviceTest(obj)
if t.disabled: if t.disabled:

View File

@ -21,15 +21,15 @@ def usage(return_code):
sys.exit(return_code) sys.exit(return_code)
if __name__ == '__main__': if __name__ == "__main__":
if {'-?', '--help', '--usage'}.intersection(set(sys.argv)): if {"-?", "--help", "--usage"}.intersection(set(sys.argv)):
usage(0) usage(0)
if len(sys.argv) < 3: if len(sys.argv) < 3:
usage(1) usage(1)
m = hashlib.sha256() m = hashlib.sha256()
for argv in sys.argv[2:]: for argv in sys.argv[2:]:
with open(argv, 'rb') as f: with open(argv, "rb") as f:
m.update(f.read()) m.update(f.read())
with open(sys.argv[1], 'w') as f2: with open(sys.argv[1], "w") as f2:
f2.write('#pragma once\n') f2.write("#pragma once\n")
f2.write('#define FU_BUILD_HASH "%s"\n' % m.hexdigest()) f2.write('#define FU_BUILD_HASH "%s"\n' % m.hexdigest())

View File

@ -13,26 +13,26 @@ from difflib import SequenceMatcher
# finds a part using the ID # finds a part using the ID
def _find_part_by_id(parts, part_id): def _find_part_by_id(parts, part_id):
for part in parts: for part in parts:
if 'id' not in part: if "id" not in part:
continue continue
if part['id'] == part_id: if part["id"] == part_id:
return part return part
return None return None
# finds a memory layout for a part, climbing up the tree to the parent if reqd. # finds a memory layout for a part, climbing up the tree to the parent if reqd.
def _find_mem_layout(parts, part): def _find_mem_layout(parts, part):
if 'memory-application' in part: if "memory-application" in part:
memory_flash = part['memory-application'] memory_flash = part["memory-application"]
if memory_flash: if memory_flash:
return memory_flash return memory_flash
# look at the parent # look at the parent
if 'parent' in part: if "parent" in part:
parent = _find_part_by_id(parts, part['parent']) parent = _find_part_by_id(parts, part["parent"])
if parent: if parent:
return _find_mem_layout(parts, parent) return _find_mem_layout(parts, parent)
print('no parent ', part['parent'], 'found for', part['id']) print("no parent ", part["parent"], "found for", part["id"])
return None return None
@ -47,8 +47,8 @@ def _parse_parts(fn_source):
for line in open(fn_source).readlines(): for line in open(fn_source).readlines():
# try to clean up crazy syntax # try to clean up crazy syntax
line = line.replace('\n', '') line = line.replace("\n", "")
if line.endswith(';'): if line.endswith(";"):
line = line[:-1] line = line[:-1]
# ignore blank lines # ignore blank lines
@ -59,42 +59,42 @@ def _parse_parts(fn_source):
# count how many spaces deep this is # count how many spaces deep this is
lvl = 0 lvl = 0
for char in line: for char in line:
if char != ' ': if char != " ":
break break
lvl = lvl + 1 lvl = lvl + 1
# ignore comments # ignore comments
line = line.strip() line = line.strip()
if line[0] == '#': if line[0] == "#":
continue continue
# level 0 of hell # level 0 of hell
if lvl == 0: if lvl == 0:
if line.startswith('part'): if line.startswith("part"):
memory_id = None memory_id = None
part = {} part = {}
parts.append(part) parts.append(part)
if line.startswith('part parent '): if line.startswith("part parent "):
part['parent'] = line[13:].replace('"', '') part["parent"] = line[13:].replace('"', "")
continue continue
# level 4 of hell # level 4 of hell
if lvl == 4: if lvl == 4:
if line.startswith('memory'): if line.startswith("memory"):
memory_id = 'memory-' + line[7:].replace('"', '') memory_id = "memory-" + line[7:].replace('"', "")
part[memory_id] = {} part[memory_id] = {}
continue continue
split = line.split('=') split = line.split("=")
if len(split) != 2: if len(split) != 2:
print('ignoring', line) print("ignoring", line)
continue continue
part[split[0].strip()] = split[1].strip().replace('"', '') part[split[0].strip()] = split[1].strip().replace('"', "")
continue continue
# level 8 of hell # level 8 of hell
if lvl == 8: if lvl == 8:
if memory_id: if memory_id:
split = line.split('=') split = line.split("=")
if len(split) != 2: if len(split) != 2:
continue continue
memory = part[memory_id] memory = part[memory_id]
@ -117,52 +117,52 @@ def _write_quirks(parts, fn_destination):
for part in parts: for part in parts:
# ignore meta parts with deprecated names # ignore meta parts with deprecated names
if 'desc' not in part: if "desc" not in part:
continue continue
if 'signature' not in part: if "signature" not in part:
continue continue
# find the layout # find the layout
mem_part = _find_mem_layout(parts, part) mem_part = _find_mem_layout(parts, part)
if not mem_part: if not mem_part:
print("no memory layout for", part['desc']) print("no memory layout for", part["desc"])
continue continue
if not 'size' in mem_part: if not "size" in mem_part:
print("no memory size for", part['desc']) print("no memory size for", part["desc"])
continue continue
if mem_part['size'].startswith('0x'): if mem_part["size"].startswith("0x"):
size = int(mem_part['size'], 16) size = int(mem_part["size"], 16)
else: else:
size = int(mem_part['size'], 10) size = int(mem_part["size"], 10)
# output the line for the quirk # output the line for the quirk
chip_id = '0x' + part['signature'].replace('0x', '').replace(' ', '') chip_id = "0x" + part["signature"].replace("0x", "").replace(" ", "")
mem_layout = '@Flash/0x0/1*%.0iKg' % int(size / 1024) mem_layout = "@Flash/0x0/1*%.0iKg" % int(size / 1024)
# merge duplicate quirks # merge duplicate quirks
if chip_id in results: if chip_id in results:
result = results[chip_id] result = results[chip_id]
result['desc'] = _get_longest_substring(result['desc'], part['desc']) result["desc"] = _get_longest_substring(result["desc"], part["desc"])
else: else:
result = {} result = {}
result['desc'] = part['desc'] result["desc"] = part["desc"]
result['size'] = size result["size"] = size
result['mem_layout'] = mem_layout result["mem_layout"] = mem_layout
results[chip_id] = result results[chip_id] = result
for chip_id in results: for chip_id in results:
result = results[chip_id] result = results[chip_id]
outp.append( outp.append(
'# ' + result['desc'] + ' [USER] USER=0x%x' % result['size'] + '\n' "# " + result["desc"] + " [USER] USER=0x%x" % result["size"] + "\n"
) )
outp.append(chip_id + '=' + result['mem_layout'] + '\n\n') outp.append(chip_id + "=" + result["mem_layout"] + "\n\n")
# write file # write file
print("writing", fn_destination) print("writing", fn_destination)
open(fn_destination, 'w').writelines(outp) open(fn_destination, "w").writelines(outp)
if __name__ == '__main__': if __name__ == "__main__":
if len(sys.argv) != 3: if len(sys.argv) != 3:
print("USAGE: %s avrdude.conf tmp.quirk" % sys.argv[0]) print("USAGE: %s avrdude.conf tmp.quirk" % sys.argv[0])
sys.exit(1) sys.exit(1)

View File

@ -50,15 +50,7 @@ def _run_objcopy(args):
def _run_genpeimg(args): def _run_genpeimg(args):
# this is okay if it does not exist # this is okay if it does not exist
argv = [ argv = ["genpeimg", "-d", "+d", "+n", "-d", "+s", args.outfile]
"genpeimg",
"-d",
"+d",
"+n",
"-d",
"+s",
args.outfile,
]
try: try:
subprocess.run(argv, check=True) subprocess.run(argv, check=True)
except FileNotFoundError as _: except FileNotFoundError as _:
@ -69,23 +61,11 @@ if __name__ == "__main__":
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument( parser.add_argument(
"--objcopy", "--objcopy", default="objcopy", help="Binary file to use for objcopy"
default="objcopy",
help="Binary file to use for objcopy",
)
parser.add_argument(
"--arch",
default="x86_64",
help="EFI architecture",
)
parser.add_argument(
"infile",
help="Input file",
)
parser.add_argument(
"outfile",
help="Output file",
) )
parser.add_argument("--arch", default="x86_64", help="EFI architecture")
parser.add_argument("infile", help="Input file")
parser.add_argument("outfile", help="Output file")
_args = parser.parse_args() _args = parser.parse_args()
_run_objcopy(_args) _run_objcopy(_args)
_run_genpeimg(_args) _run_genpeimg(_args)

View File

@ -81,40 +81,18 @@ if __name__ == "__main__":
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument( parser.add_argument(
"--cc", "--cc", default="gcc", help="Compiler to use for generating sbat object"
default="gcc",
help="Compiler to use for generating sbat object",
) )
parser.add_argument( parser.add_argument(
"--objcopy", "--objcopy", default="objcopy", help="Binary file to use for objcopy"
default="objcopy",
help="Binary file to use for objcopy",
) )
parser.add_argument("--project-name", help="SBAT project name")
parser.add_argument("--project-version", help="SBAT project version")
parser.add_argument("--sbat-version", default=1, type=int, help="SBAT version")
parser.add_argument( parser.add_argument(
"--project-name", "--sbat-generation", default=1, type=int, help="SBAT generation"
help="SBAT project name",
)
parser.add_argument(
"--project-version",
help="SBAT project version",
)
parser.add_argument(
"--sbat-version",
default=1,
type=int,
help="SBAT version",
)
parser.add_argument(
"--sbat-generation",
default=1,
type=int,
help="SBAT generation",
)
parser.add_argument(
"--sbat-distro-id",
default=None,
help="SBAT distribution ID"
) )
parser.add_argument("--sbat-distro-id", default=None, help="SBAT distribution ID")
parser.add_argument( parser.add_argument(
"--sbat-distro-generation", "--sbat-distro-generation",
default=None, default=None,
@ -122,29 +100,16 @@ if __name__ == "__main__":
help="SBAT distribution generation", help="SBAT distribution generation",
) )
parser.add_argument( parser.add_argument(
"--sbat-distro-summary", "--sbat-distro-summary", default=None, help="SBAT distribution summary"
default=None,
help="SBAT distribution summary",
) )
parser.add_argument( parser.add_argument(
"--sbat-distro-pkgname", "--sbat-distro-pkgname", default=None, help="SBAT distribution package name"
default=None,
help="SBAT distribution package name",
) )
parser.add_argument( parser.add_argument(
"--sbat-distro-version", "--sbat-distro-version", default=None, help="SBAT distribution version"
default=None,
help="SBAT distribution version",
)
parser.add_argument(
"--sbat-distro-url",
default=None,
help="SBAT distribution URL",
)
parser.add_argument(
"outfile",
help="Output file",
) )
parser.add_argument("--sbat-distro-url", default=None, help="SBAT distribution URL")
parser.add_argument("outfile", help="Output file")
_args = parser.parse_args() _args = parser.parse_args()
_generate_sbat(_args) _generate_sbat(_args)