From c94b4d07bfe2f7ddd10c7231fc1d85e4e44cf607 Mon Sep 17 00:00:00 2001 From: Houkime <> Date: Wed, 21 Jun 2023 12:15:33 +0000 Subject: [PATCH] fix(tokens-repo): persistent hashing --- .../tokens/redis_tokens_repository.py | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/selfprivacy_api/repositories/tokens/redis_tokens_repository.py b/selfprivacy_api/repositories/tokens/redis_tokens_repository.py index c72e231..8baa16d 100644 --- a/selfprivacy_api/repositories/tokens/redis_tokens_repository.py +++ b/selfprivacy_api/repositories/tokens/redis_tokens_repository.py @@ -3,6 +3,7 @@ Token repository using Redis as backend. """ from typing import Optional from datetime import datetime +from hashlib import md5 from selfprivacy_api.repositories.tokens.abstract_tokens_repository import ( AbstractTokensRepository, @@ -28,7 +29,10 @@ class RedisTokensRepository(AbstractTokensRepository): @staticmethod def token_key_for_device(device_name: str): - return TOKENS_PREFIX + str(hash(device_name)) + hash = md5() + hash.update(bytes(device_name, "utf-8")) + digest = hash.hexdigest() + return TOKENS_PREFIX + digest def get_tokens(self) -> list[Token]: """Get the tokens""" @@ -41,11 +45,20 @@ class RedisTokensRepository(AbstractTokensRepository): tokens.append(token) return tokens + def _discover_token_key(self, input_token: Token) -> str: + """brute-force searching for tokens, for robust deletion""" + redis = self.connection + token_keys = redis.keys(TOKENS_PREFIX + "*") + for key in token_keys: + token = self._token_from_hash(key) + if token == input_token: + return key + def delete_token(self, input_token: Token) -> None: """Delete the token""" redis = self.connection - key = RedisTokensRepository._token_redis_key(input_token) - if input_token not in self.get_tokens(): + key = self._discover_token_key(input_token) + if key is None: raise TokenNotFound redis.delete(key) @@ -138,7 +151,10 @@ class RedisTokensRepository(AbstractTokensRepository): return None def _token_from_hash(self, redis_key: str) -> Optional[Token]: - return self._hash_as_model(redis_key, Token) + token = self._hash_as_model(redis_key, Token) + if token is not None: + token.created_at = token.created_at.replace(tzinfo=None) + return token def _recovery_key_from_hash(self, redis_key: str) -> Optional[RecoveryKey]: return self._hash_as_model(redis_key, RecoveryKey)