| 1 | from __future__ import annotations |
| 2 | |
| 3 | import pyotp |
| 4 | |
| 5 | |
| 6 | def new_totp_secret() -> str: |
| 7 | return pyotp.random_base32() |
| 8 | |
| 9 | |
| 10 | def otpauth_uri(secret: str, account_name: str, issuer: str = "OpenAgentRegistry") -> str: |
| 11 | return pyotp.TOTP(secret).provisioning_uri(name=account_name, issuer_name=issuer) |
| 12 | |
| 13 | |
| 14 | def verify_totp(secret: str, code: str, *, valid_window: int = 1) -> bool: |
| 15 | cleaned = code.strip().replace(" ", "") |
| 16 | if not cleaned.isdigit(): |
| 17 | return False |
| 18 | return pyotp.TOTP(secret).verify(cleaned, valid_window=valid_window) |
| 19 | |
View only · write via MCP/CIDE