Security

Two-factor codes

Two-factor sign-in with authenticator apps: secrets, the 6-digit codes, checking them, and the otpauth:// link to scan.

Version 1.0.0 · 4 functions · 1 crate

#auth#2fa#totp#sign-in

Functions

What use totp.qwer gives a program, with the types Quillo sees. To take only some, or under other names: use totp_secret, totp_code from totp (Quillo 0.6).

totp_secret() → str

A new secret, as base32 text: keep it with the user, and show it once (as a link or a QR code).

totp_code(secret: str) → stror an error

The 6-digit code for secret now, as an authenticator app shows it.

totp_verify(secret: str, code: str) → boolor an error

Whether code is right for secret now, or 30 s either side. Count tries yourself: there are a million codes.

totp_url(secret: str, issuer: str, account: str) → stror an error

The otpauth:// link an app adds the account from: put it in a QR code (the qr plugin) for the set-up page.

Get it

$ quillo install totp               # totp.qwer into this folder$ quillo install totp --example     # and its example, totp.qwe

Or with curl:

$ curl -O https://quillolang.org/plugins/files/totp.qwer$ curl -O https://quillolang.org/plugins/files/totp.qwe

Then, in your program, all of it or only what you call:

main.qwe
use totp.qweruse totp_secret, totp_code from totp      // Quillo 0.6: only these

It uses this crate, which cargo fetches the first time the plugin is built:

[dependencies]
totp-rs = { version = "5", features = ["gen_secret", "otpauth"] }

Example

totp.qwe
// Setting up two-factor sign-in, and checking a code.////   quillo run totp.qwe      then open http://localhost:8080/setupuse "totp.qwer"route GET /setup {    let secret = totp_secret()    { secret, link: totp_url(secret, "Quillo Shop", "ada@example.com")? }}route GET /check {    let secret = totp_secret()    let code = totp_code(secret)?    { code, right: totp_verify(secret, code)?, wrong: totp_verify(secret, "000000")? }}
$ quillo run totp.qwe$ curl 'localhost:8080/setup'$ curl 'localhost:8080/check'

Source

totp.qwer
//! Two-factor sign-in with authenticator apps (TOTP, RFC 6238): secrets, codes, checks and the otpauth:// link.//! version: 1.0.0//!//! [dependencies]//! totp-rs = { version = "5", features = ["gen_secret", "otpauth"] }use totp_rs::{Algorithm, Secret, TOTP};fn totp(secret: &str, issuer: &str, account: &str) -> Result<TOTP, String> {    let bytes = Secret::Encoded(secret.trim().replace(' ', "").to_uppercase()).to_bytes().map_err(|e| format!("{:?}", e))?;    let issuer = if issuer.is_empty() { None } else { Some(issuer.to_string()) };    TOTP::new(Algorithm::SHA1, 6, 1, 30, bytes, issuer, account.to_string()).map_err(|e| e.to_string())}/// A new secret, as base32 text: keep it with the user, and show it once (as a link or a QR code).pub fn totp_secret() -> String {    match Secret::generate_secret().to_encoded() {        Secret::Encoded(s) => s,        Secret::Raw(_) => unreachable!(),    }}/// The 6-digit code for `secret` now, as an authenticator app shows it.pub fn totp_code(secret: &str) -> Result<String, String> {    totp(secret, "", "user")?.generate_current().map_err(|e| e.to_string())}/// Whether `code` is right for `secret` now, or 30 s either side. Count tries yourself: there are a million codes.pub fn totp_verify(secret: &str, code: &str) -> Result<bool, String> {    totp(secret, "", "user")?.check_current(code.trim()).map_err(|e| e.to_string())}/// The `otpauth://` link an app adds the account from: put it in a QR code (the qr plugin) for the set-up page.pub fn totp_url(secret: &str, issuer: &str, account: &str) -> Result<String, String> {    Ok(totp(secret, issuer, account)?.get_url())}
Thread
68Useful? Like it, or add to its thread below.

Thread 0 posts

On Two-factor codes: questions, tips, corrections, and code that uses it.

No posts yet. The first one opens the thread.