1use crate::hash::HashFunction;
36
37#[cfg(feature = "oath-uri")]
38const DEFAULT_KEY_URI_PARAM_POLICY: ParametersVisibility = ParametersVisibility::ShowNonDefault;
39const DEFAULT_OTP_HASH: HashFunction = HashFunction::Sha1;
40const DEFAULT_OTP_OUT_BASE: &str = "0123456789";
41const DEFAULT_OTP_OUT_LEN: usize = 6;
42const DEFAULT_TOTP_PERIOD: u32 = 30;
43const DEFAULT_TOTP_T0: u64 = 0;
44const DEFAULT_LOOK_AHEAD: u64 = 0;
45
46#[repr(C)]
102#[derive(Clone, Copy, Debug)]
103pub enum ErrorCode {
104 Success = 0,
105
106 NullPtr = 1,
107 NotEnoughSpace = 2,
108
109 InvalidBaseLen = 10,
110 InvalidKeyLen = 11,
111 CodeTooSmall = 12,
112 CodeTooBig = 13,
113
114 InvalidKey = 20,
115 InvalidPeriod = 21,
116
117 InvalidUTF8 = 30,
118}
119
120#[derive(Clone, Copy, Debug)]
124#[cfg_attr(feature = "thiserror", derive(thiserror::Error))]
125pub enum Error {
126 #[cfg_attr(feature = "thiserror", error("Code too small"))]
127 CodeTooSmall,
128 #[cfg_attr(feature = "thiserror", error("Code too big"))]
129 CodeTooBig,
130
131 #[cfg_attr(feature = "thiserror", error("Invalid key"))]
132 InvalidKey,
133
134 #[cfg_attr(feature = "thiserror", error("Invalid period"))]
135 InvalidPeriod,
136}
137
138impl From<Error> for ErrorCode {
139 fn from(error: Error) -> Self {
140 match error {
141 Error::CodeTooSmall => ErrorCode::CodeTooSmall,
142 Error::CodeTooBig => ErrorCode::CodeTooBig,
143 Error::InvalidKey => ErrorCode::InvalidKey,
144 Error::InvalidPeriod => ErrorCode::InvalidPeriod,
145 }
146 }
147}
148
149macro_rules! builder_common {
150 () => {
151 pub fn key(&mut self, key: &[u8]) -> &mut Self {
153 self.key = Some(key.to_owned());
154 self
155 }
156
157 pub fn ascii_key(&mut self, key: &str) -> &mut Self {
159 self.key = Some(key.as_bytes().to_vec());
160 self
161 }
162
163 pub fn hex_key(&mut self, key: &str) -> &mut Self {
165 match hex::decode(key) {
166 Ok(k) => {
167 self.key = Some(k);
168 }
169 Err(_) => {
170 self.runtime_error = Some(Error::InvalidKey);
171 }
172 }
173 self
174 }
175
176 pub fn base32_key(&mut self, key: &str) -> &mut Self {
178 match base32::decode(base32::Alphabet::Rfc4648 { padding: false }, &key) {
179 Some(k) => {
180 self.key = Some(k);
181 }
182 None => {
183 self.runtime_error = Some(Error::InvalidKey);
184 }
185 }
186 self
187 }
188
189 pub fn base64_key(&mut self, key: &str) -> &mut Self {
191 use base64::Engine;
192 match base64::engine::general_purpose::STANDARD.decode(key) {
193 Ok(k) => {
194 self.key = Some(k);
195 }
196 Err(_) => {
197 self.runtime_error = Some(Error::InvalidKey);
198 }
199 }
200 self
201 }
202
203 fn code_length(&self) -> usize {
204 let base_len = self.output_base.len();
205 let mut nb_bits = base_len;
206 for _ in 1..self.output_len {
207 nb_bits = match nb_bits.checked_mul(base_len) {
208 Some(nb_bits) => nb_bits,
209 None => return usize::MAX,
210 };
211 }
212 nb_bits
213 }
214
215 pub fn output_len(&mut self, output_len: usize) -> &mut Self {
217 self.output_len = output_len;
218 self
219 }
220
221 pub fn output_base(&mut self, base: &str) -> &mut Self {
223 self.output_base = base.to_string();
224 self
225 }
226
227 pub fn hash_function(&mut self, hash_function: HashFunction) -> &mut Self {
229 self.hash_function = hash_function;
230 self
231 }
232 };
233}
234
235#[cfg(feature = "oath-uri")]
236mod key_uri;
237#[cfg(feature = "oath-uri")]
238pub use self::key_uri::{KeyUriBuilder, ParametersVisibility};
239
240mod hotp;
241pub use self::hotp::HOTP;
242pub use self::hotp::HOTPBuilder;
243
244mod totp;
245pub use self::totp::TOTP;
246pub use self::totp::TOTPBuilder;
247
248#[cfg(feature = "cbindings")]
249mod cbindings;
250#[cfg(feature = "cbindings")]
251pub use self::cbindings::HOTPcfg;
252#[cfg(feature = "cbindings")]
253pub use self::cbindings::libreauth_hotp_generate;
254#[cfg(all(feature = "cbindings", feature = "oath-uri"))]
255pub use self::cbindings::libreauth_hotp_get_uri;
256#[cfg(feature = "cbindings")]
257pub use self::cbindings::libreauth_hotp_init;
258#[cfg(feature = "cbindings")]
259pub use self::cbindings::libreauth_hotp_is_valid;
260
261#[cfg(feature = "cbindings")]
262pub use self::cbindings::TOTPcfg;
263#[cfg(feature = "cbindings")]
264pub use self::cbindings::libreauth_totp_generate;
265#[cfg(all(feature = "cbindings", feature = "oath-uri"))]
266pub use self::cbindings::libreauth_totp_get_uri;
267#[cfg(feature = "cbindings")]
268pub use self::cbindings::libreauth_totp_init;
269#[cfg(feature = "cbindings")]
270pub use self::cbindings::libreauth_totp_is_valid;