# Logical storage model used for testing. class StorageModel: _EMPTY_PIN = "" _PIN_MAX_TRIES = 16 def __init__(self) -> None: self.wipe() def init(self, salt: bytes) -> None: self.unlocked = False def wipe(self) -> None: self.unlocked = False self.pin = self._EMPTY_PIN self.pin_rem = self._PIN_MAX_TRIES self.dict = {} def lock(self) -> None: self.unlocked = False def unlock(self, pin: str) -> bool: if pin == self.pin: self.pin_rem = self._PIN_MAX_TRIES self.unlocked = True return True else: self.pin_rem -= 1 if self.pin_rem <= 0: self.wipe() return False def has_pin(self) -> bool: return self.pin != self._EMPTY_PIN def get_pin_rem(self) -> int: return self.pin_rem def change_pin(self, oldpin: str, newpin: str) -> bool: if self.unlocked and self.unlock(oldpin): self.pin = newpin return True else: return False def get(self, key: int) -> bytes: if (key & 0x8000 != 0 or self.unlocked) and self.dict.get(key) is not None: return self.dict[key] raise RuntimeError("Failed to find key in storage.") def set(self, key: int, val: bytes) -> None: if self.unlocked: self.dict[key] = val else: raise RuntimeError("Failed to set value in storage.") def delete(self, key: int) -> bool: if not self.unlocked: return False try: self.dict.pop(key) except KeyError: return False return True def __iter__(self): return iter(self.dict.items())