mtotp_lib/
lib.rs

1pub use error::*;
2pub use database::join_paths;
3use std::collections::HashMap;
4
5mod database;
6pub mod error;
7pub mod otp;
8
9pub type Register = database::registered::Model;
10
11pub async fn init(folder: String) {
12    database::init(folder).await;
13}
14
15pub async fn print_codes() -> Vec<PrintCode> {
16    let mut codes: Vec<PrintCode> = Vec::new();
17    let registered_codes = database::registered::find_all().await;
18    for x in registered_codes {
19        let label = x.label;
20        let uuid = x.uuid;
21        match otp::totp(x.secret.as_str(), 30, 6) {
22            Ok(code) => {
23                codes.push(PrintCode { uuid, label, code });
24            }
25            Err(err) => {
26                codes.push(PrintCode {
27                    uuid,
28                    label,
29                    code: match err {
30                        Error::Hmac(_) => "HMac key error".to_owned(),
31                        Error::Message(msg) => msg.content,
32                        Error::Other(_) => "Exception".to_owned(),
33                    },
34                });
35            }
36        };
37    }
38    codes
39}
40
41pub async fn registered_codes() -> Vec<Register> {
42    database::registered::find_all().await
43}
44
45pub async fn save_url(url: String) -> Result<PrintCode> {
46    let url = match url::Url::parse(url.as_str()) {
47        Ok(url) => url,
48        Err(err) => {
49            return Err(Error::message(format!("Invalid url : {}", err)));
50        }
51    };
52    let path_split = url.path().split("/");
53    let label = path_split.last().expect("").to_owned();
54    let mut query_map: HashMap<String, String> = HashMap::new();
55    for (key, value) in url.query_pairs() {
56        query_map.insert(key.to_string(), value.to_string());
57    }
58    let secret = query_map
59        .get::<String>(&("secret".to_string()))
60        .expect("secret not found")
61        .to_string();
62    let issuer = match query_map.get::<String>(&("issuer".to_string())) {
63        None => "".to_string(),
64        Some(so) => so.to_string(),
65    };
66    Ok(save_register(label, secret, issuer).await?)
67}
68
69pub async fn save_register(label: String, secret: String, issuer: String) -> Result<PrintCode> {
70    let code = match otp::totp(secret.as_str(), 30, 6) {
71        Ok(code) => code,
72        Err(err) => {
73            return Err(err);
74        }
75    };
76    let registered = database::registered::Model {
77        uuid: uuid::Uuid::new_v4().to_string(),
78        label: label.clone(),
79        secret,
80        issuer,
81    };
82    database::registered::insert(registered.clone()).await;
83    Ok(PrintCode {
84        uuid: registered.uuid,
85        label: registered.label,
86        code,
87    })
88}
89
90pub fn register_to_url(label: &str, secret: &str, issuer: &str) -> Result<String> {
91    let url = format!("otpauth://totp/{}?secret={}&issuer={}", label, secret, issuer);
92    Ok(url)
93}
94
95pub async fn remove(uuid: &str) {
96    database::registered::delete_by_uuid(uuid).await;
97}
98
99pub async fn rename(uuid: &str, label: &str) {
100    database::registered::update_label_by_uuid(uuid, label).await;
101}
102
103pub struct PrintCode {
104    pub uuid: String,
105    pub label: String,
106    pub code: String,
107}