diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ede0eb8..e91551d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.13.0] - 2023-11-8 + +### Added +- interface: Adding RAISE_CUSTOM raise policy to allow custom definition of white-listed status. + ## [1.12.0] - 2023-10-20 ### Added: diff --git a/doc/faq.rst b/doc/faq.rst index 7bd33fa7..6cc283fb 100644 --- a/doc/faq.rst +++ b/doc/faq.rst @@ -52,12 +52,15 @@ By default, this policy is ``RaisePolicy.RAISE_ALL_BUT_0x9000``, which means the backend will raise an :py:class:`ExceptionRAPDU ` if the :term:`APDU` returned by the :term:`application` does not end with ``b'0x9000'``, else returns a :py:class:`RAPDU ` -instance. This behavior can be change with the two other options: +instance. This behavior can be change with the three other options: - ``RaisePolicy.RAISE_NOTHING``, where the backend will never raise, and always returns a proper :py:class:`RAPDU `. - ``RaisePolicy.RAISE_ALL``, where the backend will always raise a :py:class:`ExceptionAPDU `, whatever the status. +- ``RaisePolicy.RAISE_CUSTOM``, where the backend will raise a + :py:class:`ExceptionAPDU `, for :term:`APDU` ending with + status defined in ``whitelisted_status``. From that, every higher-level error management can be performed on top of ``Ragger``. diff --git a/src/ragger/backend/interface.py b/src/ragger/backend/interface.py index dd4544da..0e182def 100644 --- a/src/ragger/backend/interface.py +++ b/src/ragger/backend/interface.py @@ -19,7 +19,7 @@ from pathlib import Path from time import time from types import TracebackType -from typing import Optional, Type, Generator, Any +from typing import Optional, Type, Generator, Any, Iterable from ragger.firmware import Firmware from ragger.utils import pack_APDU, RAPDU, Crop @@ -30,11 +30,15 @@ class RaisePolicy(Enum): RAISE_NOTHING = auto() RAISE_ALL_BUT_0x9000 = auto() RAISE_ALL = auto() + RAISE_CUSTOM = auto() class BackendInterface(ABC): - def __init__(self, firmware: Firmware, log_apdu_file: Optional[Path] = None): + def __init__(self, + firmware: Firmware, + log_apdu_file: Optional[Path] = None, + whitelisted_status: Iterable = ()): """Initializes the Backend :param firmware: Which Firmware will be managed @@ -50,6 +54,8 @@ def __init__(self, firmware: Firmware, log_apdu_file: Optional[Path] = None): self.logger = get_default_logger() self.apdu_logger = get_apdu_logger() + self.whitelisted_status = whitelisted_status + @property def firmware(self) -> Firmware: """ @@ -94,7 +100,9 @@ def is_raise_required(self, rapdu: RAPDU) -> bool: """ return ((self.raise_policy == RaisePolicy.RAISE_ALL) or ((self.raise_policy == RaisePolicy.RAISE_ALL_BUT_0x9000) and - (rapdu.status != 0x9000))) + (rapdu.status != 0x9000)) + or ((self.raise_policy == RaisePolicy.RAISE_CUSTOM) and + (rapdu.status not in self.whitelisted_status))) def send(self, cla: int, ins: int, p1: int = 0, p2: int = 0, data: bytes = b"") -> None: """