def validate_backup_code(self, plaintext: str) -> bool: """ Verify if a password is correct. Parameters ---------- plaintext: str Input to check Returns ------- bool Raises ------ Unauthorized If the backup code is not valid """ for code in self.two_factor_backups: try: if code.verify(plaintext): db.session.delete(code) db.session.commit() return True except Unauthorized: pass # Need to check them all raise Unauthorized("Code not valid.")
def validate(self, code: str) -> bool: """ Validate a code against the otp generator, and if that fails, the backup codes, and mark as just used. A valid code is only valid once. Parameters ---------- code : str Code to check Returns ------- bool True if the code is a valid OTP Raises ------ Unauthorized Raised if the code is invalid, or has just been used. """ current_app.logger.debug( "Verifying 2factor code", code=code, secret_key=self.decrypted_secret_key ) is_valid = pyotp.totp.TOTP(self.decrypted_secret_key).verify(code) if is_valid: if ( current_app.config["CACHE_BACKEND"].get(f"{self.user_id}".encode()) == code ): # Reject if the code is being reused raise Unauthorized("Code not valid.") else: current_app.config["CACHE_BACKEND"].set( f"{self.user_id}".encode(), code ) return True else: raise Unauthorized("Code not valid.")
def verify(self, plaintext: str) -> bool: """ Parameters ---------- plaintext : str Code to verify Returns ------- bool True if a valid code. Raises ------ Unauthorized Raised if the code is not valid """ if argon2.verify(plaintext, self._backup_code): return True else: raise Unauthorized("Code not valid.")