use base32::Alphabet; use rand::Rng; use crate::data::app_config::AppConfig; use crate::data::user::User; const BASE32_ALPHABET: Alphabet = Alphabet::RFC4648 { padding: true }; const NUM_DIGITS: i32 = 6; const PERIOD: i32 = 30; #[derive(serde::Serialize, serde::Deserialize, Debug)] pub struct TotpKey { encoded: String, } impl TotpKey { /// Generate a new TOTP key pub fn new_random() -> Self { let random_bytes = rand::thread_rng().gen::<[u8; 10]>(); TotpKey { encoded: base32::encode(BASE32_ALPHABET, &random_bytes) } } /// Get QrCode URL for user /// /// Based on https://github.com/google/google-authenticator/wiki/Key-Uri-Format pub fn url_for_user(&self, u: &User, conf: &AppConfig) -> String { format!( "otpauth://totp/{}:{}?secret={}&issuer={}&algorithm=SHA1&digits={}&period={}", urlencoding::encode(&conf.domain_name()), urlencoding::encode(&u.username), self.encoded, urlencoding::encode(&conf.domain_name()), NUM_DIGITS, PERIOD, ) } /// Get account name pub fn account_name(&self, u: &User, conf: &AppConfig) -> String { format!( "{}:{}", urlencoding::encode(conf.domain_name()), urlencoding::encode(&u.username) ) } /// Get current secret in base32 format pub fn get_secret(&self) -> String { self.encoded.to_string() } }