1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#![deny(missing_docs, missing_debug_implementations)]
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(feature = "unsize", feature(fixed_size_array))]
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(all(feature = "base32", any(feature = "std", feature = "alloc")))]
pub(crate) const B32A: base32::Alphabet =
base32::Alphabet::RFC4648 { padding: false };
#[cfg(not(feature = "only-gauth"))]
pub(crate) mod alg;
#[cfg(not(feature = "only-gauth"))]
pub use alg::*;
mod array;
pub use array::Array;
mod hotp;
pub use hotp::HOTP;
mod totp;
pub use totp::TOTP;
#[cfg(all(feature = "base32", any(feature = "alloc", feature = "std")))]
mod err {
#[cfg(feature = "cstr")]
use std::str::Utf8Error;
#[derive(Debug)]
pub enum Error {
#[cfg(feature = "cstr")]
Utf8(Utf8Error),
BadEnc,
}
impl core::fmt::Display for Error {
fn fmt(
&self,
f: &mut core::fmt::Formatter,
) -> core::fmt::Result {
match self {
#[cfg(feature = "cstr")]
Self::Utf8(ref e) => core::fmt::Display::fmt(e, f),
Self::BadEnc => f.write_str("Bad base32 encoding"),
}
}
}
#[cfg(feature = "cstr")]
impl From<Utf8Error> for Error {
fn from(e: Utf8Error) -> Self {
Self::Utf8(e)
}
}
#[cfg(feature = "std")]
impl std::error::Error for Error {}
}
#[cfg(all(feature = "base32", any(feature = "alloc", feature = "std")))]
pub use err::Error;
#[cfg(all(feature = "base32", any(feature = "alloc", feature = "std")))]
mod segs {
use core::cmp::min;
#[derive(Debug)]
pub struct Segs {
pub(crate) sec: String,
pub(crate) chunk_size: usize,
pub(crate) curr: usize,
}
impl Iterator for Segs {
type Item = String;
fn next(&mut self) -> Option<Self::Item> {
if self.curr >= self.sec.len() {
None
} else {
let (off, ()) = (self.curr, self.curr += self.chunk_size);
let end = min(self.curr, self.sec.len());
let next = self.sec.get(off..end)?;
Some(next.into())
}
}
}
impl Segs {
pub fn join<S: AsRef<str>>(
self,
sep: S,
) -> String {
let s = sep.as_ref();
let cap =
self.sec.len() + s.len() * (self.sec.len() / self.chunk_size) + 1;
let mut first = true;
self.fold(String::with_capacity(cap), |mut acc, seg| {
if first {
first = false;
} else {
acc.push_str(s);
}
acc.push_str(&seg);
acc
})
}
}
}
#[cfg(all(feature = "base32", any(feature = "alloc", feature = "std")))]
pub use segs::Segs;