[root tip] [Utility Script] Using python to download and verify a Manjaro ISO

,

Download and verify a Manjaro ISO.

The tool is a command line tool and is limited to x86 ISO but it provides a convenient way of downloading and verifying an ISO as they are listed on Manjaro Downloads.

Neither Sway nor ARM is supported, sway because the files is located elsewhere and ARM because there is no signature.

The source is free to use, and you are encouraged to clone my repo at scm.nix.dk.

Get started

Besides the basic Python modules - the script relies on the Python requests module.

Manjaro

On Manjaro you don’t need to install it - it is present as a dependency of pacman-mirrors.

Other Linux

If you are using another Linux you can use requirements.txt to install the necessary dependency.

Setup

Create the folder ~/.local/bin

mkdir -p ~/.local/bin

Then create a new file in this bin folder - name the file get-iso - then use your favorite text editor to copy paste the code into the new file.

Make the file executable

chmod +x ~/.local/bin/get-iso

Usage

 $ get-iso -h
usage: get-iso [-h] [-f] {plasma,xfce,gnome,budgie,cinnamon,i3,mate}

This tool will download a named Manjaro ISO and verify the signature

positional arguments:
  {plasma,xfce,gnome,budgie,cinnamon,i3,mate}
                        edition e.g. plasma or xfce

options:
  -h, --help            show this help message and exit
  -f, --full            Download full ISO

get-iso version 0.1 - License GPL v3 or later

The script defaults to pull the minimal ISO and downloaded files is placed your home folder.

Example downloading full mate edition

get-iso mate -f
Downloading: manjaro-mate-22.0-230104-linux61.iso
Downloading: manjaro-mate-22.0-230104-linux61.iso.sig
Wait for verification ...
gpg: assuming signed data in 'manjaro-mate-22.0-230104-linux61.iso'
gpg: Signature made ons 04 jan 2023 12:48:04 CET
gpg:                using RSA key 3B794DE6D4320FCE594F4171279E7CF5D8D56EC8
gpg: Good signature from "Manjaro Build Server <build@manjaro.org>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: 3B79 4DE6 D432 0FCE 594F  4171 279E 7CF5 D8D5 6EC8

Another example downloading minimal plasma

get-iso plasma
 $ get-iso plasma
Downloading: manjaro-kde-22.1.3-minimal-230529-linux61.iso
Downloading: manjaro-kde-22.1.3-minimal-230529-linux61.iso.sig
Wait for verification ...
gpg: assuming signed data in 'manjaro-kde-22.1.3-minimal-230529-linux61.iso'
gpg: Signature made man 29 maj 2023 11:46:55 CEST
gpg:                using RSA key 3B794DE6D4320FCE594F4171279E7CF5D8D56EC8
gpg: Good signature from "Manjaro Build Server <build@manjaro.org>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: 3B79 4DE6 D432 0FCE 594F  4171 279E 7CF5 D8D5 6EC8

Similar tool

When I wrote the [root tip] [How To] Forum mini guide to verify ISO signature I vaguely recalled a similar tool in the repo manjaro-iso-downloader with a small GUI created using yad but at the time it didn’t work for me.

I have since made @Ste74 aware and it has been fixed.

So if you are the point and click user, you can install it from the repo

sudo pacman -Syu manjaro-iso-downloader

The complete script

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# @linux-aarhus - root.nix.dk
# License: GNU GPL, version 3 or later; https://www.gnu.org/licenses/gpl.html
import argparse
import subprocess
import sys
import os
import requests
import time
from typing import List
from pathlib import Path

DEF_URL = "https://gitlab.manjaro.org/webpage/iso-info/-/raw/master/file-info.json"
FOLDER = Path.home()
PROG_NAME = os.path.basename(__file__)
PROG_VERSION = "0.2"
GNU_URL = "https://www.gnu.org/licenses/gpl.html"


def download_file(url: str, folder_name: str) -> bool:
    filename: str = url.split("/")[-1]
    path = os.path.join("/{}/{}".format(folder_name, filename))
    try:
        response = requests.get(url, stream=True)
        total_size_in_bytes = int(response.headers.get("content-length", 0))
        block_size = 1024
        if total_size_in_bytes < block_size:
            block_size = total_size_in_bytes

        with open(path, "wb") as f:
            progress = 0
            for data in response.iter_content(block_size):
                f.write(data)
                if len(data) < block_size:
                    progress += len(data)
                else:
                    progress += block_size
                print(f"Receiving <- {progress}/{total_size_in_bytes}", end="\r")

    except Exception as e:
        print(e)
        return False
    return True


def get_definitions(url: str) -> dict:
    iso_def = {}
    try:
        resp = requests.get(url=url, timeout=10)
        resp.raise_for_status()
        iso_def = resp.json()
    except Exception as e:
        print(f"{e}")
    return iso_def


def init_iso_list(url: str) -> List:
    data = get_definitions(url)
    data_official = data.get("official")
    data_community = data.get("community")
    init_iso_result = []
    for ok, ov in data_official.items():
        try:
            init_iso_result.append({"name": ok,
                                    "full": {"img": ov["image"], "sig": ov["signature"]},
                                    "minimal": {"img": ov["minimal"]["image"], "sig": ov["minimal"]["signature"]}
                                    })
        except:
            continue

    for ck, cv in data_community.items():
        try:
            init_iso_result.append({"name": ck,
                                    "full": {"img": cv["image"], "sig": cv["signature"]},
                                    "minimal": {"img": cv["minimal"]["image"], "sig": cv["minimal"]["signature"]}
                                    })
        except:
            continue

    return init_iso_result


def download(url: str) -> bool:
    print(f'Downloading: {url.split("/")[-1]}')
    success = download_file(url, f"{FOLDER}")
    return success


def main():
    iso_files = init_iso_list(DEF_URL)
    choices = []
    for c in iso_files:
        choices.append(c["name"])
    parser = argparse.ArgumentParser(
        prog=f"{PROG_NAME}",
        description="This tool will download a named Manjaro ISO and verify the signature",
        epilog=f"{PROG_NAME} v. {PROG_VERSION} - GPL v3 or later <{GNU_URL}>")
    parser.add_argument("edition",
                        type=str,
                        help="edition e.g. plasma or xfce",
                        choices=choices)
    parser.add_argument("-f", "--full",
                        required=False,
                        action="store_true",
                        help="Download full ISO")
    args = parser.parse_args()
    if args.edition is None:
        parser.print_usage()
    edition = [x for x in iso_files if args.edition == x["name"]]
    for x in edition:
        if args.full:
            iso = x["full"]
        else:
            iso = x["minimal"]
        iso_result = download(iso["img"])
        sig_result = download(iso["sig"])
        if sig_result and iso_result:
            print("Wait for verification ...")
            time.sleep(5)
            result = subprocess.run(
                ["gpg", "--verify", f'{iso["sig"].split("/")[-1]}'],
                cwd=f"{FOLDER}")
        else:
            print("Download ISO failed")
            sys.exit(0)
    sys.exit(0)


if __name__ == '__main__':
    try:
        main()
    except KeyboardInterrupt:
        print("\n" + "Exit: interrupted by the user.")
        sys.exit(1)

Crossposted at Use Python to download and verify Manjaro ISO | root.nix.dk

11 Likes