From 772c0dfc64f149f94a1a90352b3286af75333a36 Mon Sep 17 00:00:00 2001 From: Houkime <> Date: Mon, 12 Dec 2022 14:22:36 +0000 Subject: [PATCH] refactor(tokens-repository): move use_mnemonic_recovery_key() to abstract class --- .../tokens/abstract_tokens_repository.py | 35 +++++++++++++++++-- .../tokens/json_tokens_repository.py | 27 +------------- 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/selfprivacy_api/repositories/tokens/abstract_tokens_repository.py b/selfprivacy_api/repositories/tokens/abstract_tokens_repository.py index 29c96a4..82a0189 100644 --- a/selfprivacy_api/repositories/tokens/abstract_tokens_repository.py +++ b/selfprivacy_api/repositories/tokens/abstract_tokens_repository.py @@ -1,9 +1,14 @@ from abc import ABC, abstractmethod from datetime import datetime from typing import Optional +from mnemonic import Mnemonic from selfprivacy_api.models.tokens.token import Token -from selfprivacy_api.repositories.tokens.exceptions import TokenNotFound +from selfprivacy_api.repositories.tokens.exceptions import ( + TokenNotFound, + InvalidMnemonic, + RecoveryKeyNotFound, +) from selfprivacy_api.models.tokens.recovery_key import RecoveryKey from selfprivacy_api.models.tokens.new_device_key import NewDeviceKey @@ -87,11 +92,22 @@ class AbstractTokensRepository(ABC): ) -> RecoveryKey: """Create the recovery key""" - @abstractmethod def use_mnemonic_recovery_key( self, mnemonic_phrase: str, device_name: str ) -> Token: """Use the mnemonic recovery key and create a new token with the given name""" + if not self.is_recovery_key_valid(): + raise RecoveryKeyNotFound("Recovery key not found") + + recovery_hex_key = self.get_recovery_key().key + if not self._assert_mnemonic(recovery_hex_key, mnemonic_phrase): + raise RecoveryKeyNotFound("Recovery key not found") + + new_token = self.create_token(device_name=device_name) + + self._decrement_recovery_token() + + return new_token def is_recovery_key_valid(self) -> bool: """Check if the recovery key is valid""" @@ -117,3 +133,18 @@ class AbstractTokensRepository(ABC): @abstractmethod def _store_token(self, new_token: Token): """Store a token directly""" + + @abstractmethod + def _decrement_recovery_token(self): + """Decrement recovery key use count by one""" + + # TODO: find a proper place for it + def _assert_mnemonic(self, hex_key: str, mnemonic_phrase: str): + """Return true if hex string matches the phrase, false otherwise + Raise an InvalidMnemonic error if not mnemonic""" + recovery_token = bytes.fromhex(hex_key) + if not Mnemonic(language="english").check(mnemonic_phrase): + raise InvalidMnemonic("Phrase is not mnemonic!") + + phrase_bytes = Mnemonic(language="english").to_entropy(mnemonic_phrase) + return phrase_bytes == recovery_token diff --git a/selfprivacy_api/repositories/tokens/json_tokens_repository.py b/selfprivacy_api/repositories/tokens/json_tokens_repository.py index 1ebdca8..50d8869 100644 --- a/selfprivacy_api/repositories/tokens/json_tokens_repository.py +++ b/selfprivacy_api/repositories/tokens/json_tokens_repository.py @@ -11,7 +11,6 @@ from selfprivacy_api.models.tokens.recovery_key import RecoveryKey from selfprivacy_api.models.tokens.new_device_key import NewDeviceKey from selfprivacy_api.repositories.tokens.exceptions import ( TokenNotFound, - RecoveryKeyNotFound, InvalidMnemonic, NewDeviceKeyNotFound, ) @@ -98,36 +97,12 @@ class JsonTokensRepository(AbstractTokensRepository): return recovery_key - def use_mnemonic_recovery_key( - self, mnemonic_phrase: str, device_name: str - ) -> Token: - """Use the mnemonic recovery key and create a new token with the given name""" - if not self.is_recovery_key_valid(): - raise RecoveryKeyNotFound("Recovery key not found") - - recovery_hex_key = self.get_recovery_key().key - if not self._assert_mnemonic(recovery_hex_key, mnemonic_phrase): - raise RecoveryKeyNotFound("Recovery key not found") - - new_token = self.create_token(device_name=device_name) - - self._decrement_recovery_token() - - return new_token - def _decrement_recovery_token(self): + """Decrement recovery key use count by one""" if self.is_recovery_key_valid(): with WriteUserData(UserDataFiles.TOKENS) as tokens: tokens["recovery_token"]["uses_left"] -= 1 - def _assert_mnemonic(self, hex_key: str, mnemonic_phrase: str): - recovery_token = bytes.fromhex(hex_key) - if not Mnemonic(language="english").check(mnemonic_phrase): - raise InvalidMnemonic("Phrase is not mnemonic!") - - phrase_bytes = Mnemonic(language="english").to_entropy(mnemonic_phrase) - return phrase_bytes == recovery_token - def get_new_device_key(self) -> NewDeviceKey: """Creates and returns the new device key""" new_device_key = NewDeviceKey.generate()