from src.application.abstractions import IUnitOfWork from src.application.contracts import IHashService, ILogger, ICache from src.application.domain.entities import UserEntity from src.application.domain.exceptions import BadRequestException, ConflictException from src.infrastructure.database.decorators import transactional class SetEncryptedMnemonicCompleteCommand: def __init__( self, unit_of_work: IUnitOfWork, hash_service: IHashService, cache: ICache, logger: ILogger, ): self._unit_of_work = unit_of_work self._hash_service = hash_service self._cache = cache self._logger = logger @transactional async def __call__(self, *, user_id: str, code: str, encrypted_mnemonic: str) -> UserEntity: code = (code or '').strip() USER_PREFIX = 'encrypted_mnemonic:user:' CODE_PREFIX = 'encrypted_mnemonic:code:' user_key = f'{USER_PREFIX}{user_id}' code_key = f'{CODE_PREFIX}{code}' user = await self._unit_of_work.user_repository.get_user_by_id(user_id=user_id) if user.encrypted_mnemonic is not None: self._logger.info(f'Encrypted mnemonic already set for user_id={user_id}') raise ConflictException(message='Encrypted mnemonic already set and cannot be changed') cached_user_id = await self._cache.get(code_key) if not cached_user_id: self._logger.info(f'Encrypted mnemonic set failed: code not found (user_id={user_id})') raise BadRequestException(message='Invalid or expired code') if cached_user_id != user_id: self._logger.info(f'Encrypted mnemonic set failed: code-user mismatch (user_id={user_id})') raise BadRequestException(message='Invalid or expired code') code_hash = await self._cache.get(user_key) if not code_hash: self._logger.info(f'Encrypted mnemonic set failed: user key missing (user_id={user_id})') raise BadRequestException(message='Invalid or expired code') ok = await self._hash_service.verify(hashed_value=code_hash, plain_value=code) if not ok: self._logger.info(f'Encrypted mnemonic set failed: code hash mismatch (user_id={user_id})') raise BadRequestException(message='Invalid or expired code') user = await self._unit_of_work.user_repository.set_encrypted_mnemonic( user_id=user_id, encrypted_mnemonic=encrypted_mnemonic, ) await self._cache.set_user(user_id, user) try: await self._cache.delete(code_key) await self._cache.delete(user_key) except Exception as e: self._logger.warning(f'Encrypted mnemonic set cleanup failed (user_id={user_id}): {e}') self._logger.info(f'Encrypted mnemonic set for user_id={user_id}') return user