alias Towerops.Accounts alias Towerops.Accounts.User # Simulate enrollment flow secret = Accounts.generate_totp_secret() user = %User{email: "test@example.com"} IO.puts("=== TOTP Enrollment Flow Test ===") IO.puts("") IO.puts("1. Generated secret:") IO.puts(" Bytes: #{byte_size(secret)}") IO.puts(" Type: #{inspect(:io_lib.printable_list(secret))}") # Generate URI (what goes in QR code) uri = Accounts.generate_totp_uri(user, secret) IO.puts("") IO.puts("2. Generated URI:") IO.puts(" #{uri}") # Extract the Base32 secret from the URI case Regex.run(~r/secret=([A-Z2-7]+)/, uri) do [_, base32] -> IO.puts("") IO.puts("3. Extracted Base32 from URI:") IO.puts(" Base32: #{base32}") IO.puts(" Length: #{String.length(base32)} characters") # Verify the Base32 can be decoded back try do decoded = Base.decode32!(base32, padding: false) IO.puts("") IO.puts("4. Decode verification:") IO.puts(" Decoded bytes: #{byte_size(decoded)}") IO.puts(" Matches original: #{decoded == secret}") if decoded != secret do IO.puts(" ERROR: Decoded secret doesn't match!") IO.puts(" Original bytes: #{byte_size(secret)}") IO.puts(" Decoded bytes: #{byte_size(decoded)}") end rescue e -> IO.puts("") IO.puts("4. Decode ERROR: #{inspect(e)}") end _ -> IO.puts("") IO.puts("ERROR: Failed to extract Base32 from URI") end # Test verification current_time = System.system_time(:second) code = NimbleTOTP.verification_code(secret, time: current_time) valid = Accounts.verify_totp(secret, code) IO.puts("") IO.puts("5. Verification test:") IO.puts(" Generated code: #{code}") IO.puts(" Validates: #{valid}")