Generate QrCode to enroll Authenticator App

This commit is contained in:
2022-04-19 09:56:51 +02:00
parent 3023771334
commit 38eddc1cf0
7 changed files with 489 additions and 8 deletions

View File

@ -2,7 +2,7 @@ use std::path::{Path, PathBuf};
use clap::Parser;
use crate::constants::{CLIENTS_LIST_FILE, USERS_LIST_FILE};
use crate::constants::{APP_NAME, CLIENTS_LIST_FILE, USERS_LIST_FILE};
/// Basic OIDC provider
#[derive(Parser, Debug, Clone)]
@ -53,4 +53,8 @@ impl AppConfig {
format!("{}/{}", self.website_origin, uri)
}
}
pub fn domain_name(&self) -> &str {
self.website_origin.split('/').skip(2).next().unwrap_or(APP_NAME)
}
}

View File

@ -10,4 +10,5 @@ pub mod jwt_signer;
pub mod id_token;
pub mod code_challenge;
pub mod open_id_user_info;
pub mod access_token;
pub mod access_token;
pub mod totp_key;

53
src/data/totp_key.rs Normal file
View File

@ -0,0 +1,53 @@
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()
}
}