Skip to main content

wae_authentication/totp/
config.rs

1//! TOTP 配置模块
2
3use std::time::Duration;
4
5/// TOTP 哈希算法
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
7pub enum TotpAlgorithm {
8    /// SHA-1 (默认,兼容性最好)
9    #[default]
10    SHA1,
11    /// SHA-256
12    SHA256,
13    /// SHA-512
14    SHA512,
15}
16
17impl TotpAlgorithm {
18    /// 获取算法名称
19    pub fn as_str(&self) -> &'static str {
20        match self {
21            TotpAlgorithm::SHA1 => "SHA1",
22            TotpAlgorithm::SHA256 => "SHA256",
23            TotpAlgorithm::SHA512 => "SHA512",
24        }
25    }
26
27    /// 获取算法 OID (用于 URI)
28    pub fn oid(&self) -> &'static str {
29        match self {
30            TotpAlgorithm::SHA1 => "SHA1",
31            TotpAlgorithm::SHA256 => "SHA256",
32            TotpAlgorithm::SHA512 => "SHA512",
33        }
34    }
35}
36
37/// TOTP 配置
38#[derive(Debug, Clone)]
39pub struct TotpConfig {
40    /// 发行者 (应用名称)
41    pub issuer: String,
42
43    /// 用户账号
44    pub account_name: String,
45
46    /// 密钥 (Base32 编码)
47    pub secret: String,
48
49    /// 哈希算法
50    pub algorithm: TotpAlgorithm,
51
52    /// 数字位数 (通常为 6 或 8)
53    pub digits: u32,
54
55    /// 时间步长 (秒)
56    pub time_step: u64,
57
58    /// 有效窗口 (前后允许的步数)
59    pub valid_window: u32,
60}
61
62impl TotpConfig {
63    /// 创建新的 TOTP 配置
64    ///
65    /// # Arguments
66    /// * `issuer` - 发行者名称
67    /// * `account_name` - 用户账号
68    /// * `secret` - Base32 编码的密钥
69    pub fn new(issuer: impl Into<String>, account_name: impl Into<String>, secret: impl Into<String>) -> Self {
70        Self {
71            issuer: issuer.into(),
72            account_name: account_name.into(),
73            secret: secret.into(),
74            algorithm: TotpAlgorithm::default(),
75            digits: 6,
76            time_step: 30,
77            valid_window: 1,
78        }
79    }
80
81    /// 设置哈希算法
82    pub fn with_algorithm(mut self, algorithm: TotpAlgorithm) -> Self {
83        self.algorithm = algorithm;
84        self
85    }
86
87    /// 设置数字位数
88    pub fn with_digits(mut self, digits: u32) -> Self {
89        self.digits = digits;
90        self
91    }
92
93    /// 设置时间步长
94    pub fn with_time_step(mut self, time_step: Duration) -> Self {
95        self.time_step = time_step.as_secs();
96        self
97    }
98
99    /// 设置有效窗口
100    pub fn with_valid_window(mut self, window: u32) -> Self {
101        self.valid_window = window;
102        self
103    }
104
105    /// 生成 otpauth:// URI
106    pub fn to_uri(&self) -> String {
107        let label = wae_types::url_encode(&format!("{}:{}", self.issuer, self.account_name));
108        let params = [
109            ("secret", self.secret.as_str()),
110            ("issuer", &self.issuer),
111            ("algorithm", self.algorithm.oid()),
112            ("digits", &self.digits.to_string()),
113            ("period", &self.time_step.to_string()),
114        ];
115
116        let query = params.iter().map(|(k, v)| format!("{}={}", k, wae_types::url_encode(v))).collect::<Vec<_>>().join("&");
117
118        format!("otpauth://totp/{}?{}", label, query)
119    }
120}
121
122/// HOTP (HMAC-based One-Time Password) 配置
123#[derive(Debug, Clone)]
124pub struct HotpConfig {
125    /// 发行者
126    pub issuer: String,
127
128    /// 用户账号
129    pub account_name: String,
130
131    /// 密钥 (Base32 编码)
132    pub secret: String,
133
134    /// 哈希算法
135    pub algorithm: TotpAlgorithm,
136
137    /// 数字位数
138    pub digits: u32,
139
140    /// 计数器
141    pub counter: u64,
142}
143
144impl HotpConfig {
145    /// 创建新的 HOTP 配置
146    pub fn new(issuer: impl Into<String>, account_name: impl Into<String>, secret: impl Into<String>) -> Self {
147        Self {
148            issuer: issuer.into(),
149            account_name: account_name.into(),
150            secret: secret.into(),
151            algorithm: TotpAlgorithm::default(),
152            digits: 6,
153            counter: 0,
154        }
155    }
156
157    /// 设置计数器
158    pub fn with_counter(mut self, counter: u64) -> Self {
159        self.counter = counter;
160        self
161    }
162
163    /// 设置数字位数
164    pub fn with_digits(mut self, digits: u32) -> Self {
165        self.digits = digits;
166        self
167    }
168
169    /// 设置哈希算法
170    pub fn with_algorithm(mut self, algorithm: TotpAlgorithm) -> Self {
171        self.algorithm = algorithm;
172        self
173    }
174
175    /// 生成 otpauth:// URI
176    pub fn to_uri(&self) -> String {
177        let label = wae_types::url_encode(&format!("{}:{}", self.issuer, self.account_name));
178        let params = [
179            ("secret", self.secret.as_str()),
180            ("issuer", &self.issuer),
181            ("algorithm", self.algorithm.oid()),
182            ("digits", &self.digits.to_string()),
183            ("counter", &self.counter.to_string()),
184        ];
185
186        let query = params.iter().map(|(k, v)| format!("{}={}", k, wae_types::url_encode(v))).collect::<Vec<_>>().join("&");
187
188        format!("otpauth://hotp/{}?{}", label, query)
189    }
190}