diff --git a/pynitrokey/cli/pro.py b/pynitrokey/cli/pro.py index c7cc5819..0de0ea7e 100644 --- a/pynitrokey/cli/pro.py +++ b/pynitrokey/cli/pro.py @@ -5,7 +5,12 @@ import intelhex as ih import nkdfu -from pynitrokey.helpers import local_critical, local_print, prompt +from pynitrokey.helpers import ( + check_pynitrokey_version, + local_critical, + local_print, + prompt, +) from pynitrokey.libnk import DeviceNotFound, NitrokeyPro, RetCode print = local_print @@ -119,6 +124,8 @@ def update(firmware_path: str): import nkdfu.dfu as dfu import usb1 + check_pynitrokey_version() + print = local_print # TODO(szszsz): extract logic to nkdfu, leaving only end-user error handling assert firmware_path.endswith("bin") diff --git a/pynitrokey/cli/start.py b/pynitrokey/cli/start.py index 81183379..6d7b78d1 100644 --- a/pynitrokey/cli/start.py +++ b/pynitrokey/cli/start.py @@ -16,7 +16,7 @@ from tqdm import tqdm from usb.core import USBError -from pynitrokey.helpers import local_critical, local_print +from pynitrokey.helpers import check_pynitrokey_version, local_critical, local_print from pynitrokey.start.gnuk_token import OnlyBusyICCError, get_gnuk_device from pynitrokey.start.threaded_log import ThreadLog from pynitrokey.start.upgrade_by_passwd import ( @@ -211,6 +211,8 @@ def update( green_led, ) + check_pynitrokey_version() + if green_led and (regnual is None or gnuk is None): local_critical( "You selected the --green-led option, please provide '--regnual' and " diff --git a/pynitrokey/cli/storage.py b/pynitrokey/cli/storage.py index bab5d928..d14397f4 100644 --- a/pynitrokey/cli/storage.py +++ b/pynitrokey/cli/storage.py @@ -20,7 +20,14 @@ from tqdm import tqdm from pynitrokey.cli.exceptions import CliException -from pynitrokey.helpers import AskUser, confirm, local_critical, local_print, prompt +from pynitrokey.helpers import ( + AskUser, + check_pynitrokey_version, + confirm, + local_critical, + local_print, + prompt, +) from pynitrokey.libnk import DeviceNotFound, NitrokeyStorage, RetCode @@ -144,6 +151,8 @@ def is_connected() -> ConnectedDevices: ) def update(firmware: str, experimental): """experimental: run assisted update through dfu-programmer tool""" + check_pynitrokey_version() + if platform.system() != "Linux" or not experimental: local_print( "This feature is Linux only and experimental, which means it was not tested thoroughly.\n" diff --git a/pynitrokey/cli/update.py b/pynitrokey/cli/update.py index 65760d29..7347b95d 100644 --- a/pynitrokey/cli/update.py +++ b/pynitrokey/cli/update.py @@ -19,7 +19,12 @@ import pynitrokey from pynitrokey.confconsts import LOG_FN -from pynitrokey.helpers import AskUser, local_critical, local_print +from pynitrokey.helpers import ( + AskUser, + check_pynitrokey_version, + local_critical, + local_print, +) logger = logging.getLogger() @@ -41,6 +46,8 @@ def update(serial, yes, force): # print('Please use {} to run the firmware update'.format(update_url)) # return + check_pynitrokey_version() + IS_LINUX = platform.system() == "Linux" logger.debug(f"Start session {datetime.now()}") diff --git a/pynitrokey/helpers.py b/pynitrokey/helpers.py index 8235954a..e8302289 100644 --- a/pynitrokey/helpers.py +++ b/pynitrokey/helpers.py @@ -15,12 +15,14 @@ import sys import time from getpass import getpass +from importlib.metadata import version from itertools import chain from numbers import Number from threading import Event, Timer from typing import Any, Callable, Dict, List, NoReturn, Optional, Tuple, TypeVar, Union import click +import semver from tqdm import tqdm from pynitrokey.confconsts import ( @@ -32,6 +34,7 @@ VERBOSE, Verbosity, ) +from pynitrokey.updates import Repository STDOUT_PRINT = True @@ -404,3 +407,22 @@ def require_windows_admin() -> None: "Warning: It is recommended to execute nitropy with admin privileges " "to be able to access Nitrokey 3 and Nitrokey FIDO 2 devices." ) + + +def check_pynitrokey_version() -> None: + """Checks wether the used pynitrokey version is the latest available version and warns the user if the used version is outdated""" + + latest_release = Repository("Nitrokey", "pynitrokey").get_latest_release() + latest_version = semver.Version.parse(latest_release.tag[1:]) + + current_version = semver.Version.parse(version("pynitrokey")) + + if current_version < latest_version: + local_print( + f"You are using an outdated version ({current_version}) of pynitrokey." + ) + local_print(f"Latest pynitrokey version is {latest_version}") + local_print("Updating with an outdated version is discouraged.") + + if not confirm("Do you still want to continue?", default=False): + raise click.Abort()