Skip to content

Commit 2aa6384

Browse files
authored
Merge pull request #73 from constantoine/bump_msrv
Update dependencies and add msrv check
2 parents da78569 + d79bac7 commit 2aa6384

File tree

6 files changed

+55
-22
lines changed

6 files changed

+55
-22
lines changed

.github/workflows/rust.yml

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,23 @@ jobs:
1313
build:
1414
runs-on: ubuntu-latest
1515
steps:
16-
- uses: actions/checkout@v2
16+
- uses: actions/checkout@v4
1717
- name: Build
1818
run: cargo build --all-features
1919

20+
msrv:
21+
runs-on: ubuntu-latest
22+
steps:
23+
- uses: actions/checkout@v4
24+
- name: Install cargo-msrv
25+
run: cargo install cargo-msrv
26+
- name: Verify Minimum Supported Rust Version
27+
run: cargo msrv verify
28+
2029
test:
2130
runs-on: ubuntu-latest
2231
steps:
23-
- uses: actions/checkout@v2
32+
- uses: actions/checkout@v4
2433
- name: Install llvm-tools-preview
2534
run: rustup component add llvm-tools-preview
2635
- name: Download grcov
@@ -42,12 +51,12 @@ jobs:
4251
- name: Create coverage file
4352
run: ./grcov . --binary-path ./target/debug/deps/ -s . -t cobertura --branch --ignore-not-existing --ignore '../*' --ignore "/*" -o target/coverage/cobertura.xml
4453
- name: Upload to codecov.io
45-
uses: codecov/codecov-action@v2
54+
uses: codecov/codecov-action@v5
4655
with:
4756
token: ${{secrets.CODECOV_TOKEN}}
4857

4958
- name: Archive code coverage results
50-
uses: actions/upload-artifact@v1
59+
uses: actions/upload-artifact@v4
5160
with:
5261
name: code-coverage-report
5362
path: target/coverage/cobertura.xml

CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
# [5.7.0](https://github.com/constantoine/totp-rs/releases/tag/v5.7.0) (12/04/2025)
2+
### Breaking changes.
3+
- MSRV has been set to Rust `1.66`.
4+
5+
### Changes
6+
- Updated `base32` crate to `0.5`.
7+
- Updated `constant_time_eq` crate to `0.3`.
8+
- Updated `rand` crate to `0.9`.
9+
- Added a bit of documentation.
10+
11+
### Note
12+
This is probably the last version update before the big `6.0`, which will be a big rewrite, and the `2024` edition.
13+
The goal will be to expose the same feature as before, but in a more harmonized and idiomatic way.
14+
115
# [5.6.0](https://github.com/constantoine/totp-rs/releases/tag/v5.6.0) (24/07/2024)
216
### Changes
317
- [qrcodegen-image](https://crates.io/crates/qrcodegen-image) has now been moved to its own [repo](https://github.com/constantoine/qrcodegen-image).

Cargo.toml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
[package]
22
name = "totp-rs"
3-
version = "5.6.0"
3+
version = "5.7.0"
44
authors = ["Cleo Rebert <cleo.rebert@gmail.com>"]
5-
rust-version = "1.61"
5+
rust-version = "1.66"
66
edition = "2021"
77
readme = "README.md"
88
license = "MIT"
@@ -29,10 +29,10 @@ serde = { version = "1.0", features = ["derive"], optional = true }
2929
sha2 = "0.10"
3030
sha1 = "0.10"
3131
hmac = "0.12"
32-
base32 = "0.4"
32+
base32 = "0.5"
3333
urlencoding = { version = "2.1", optional = true}
3434
url = { version = "2.4", optional = true }
35-
constant_time_eq = "0.2"
36-
rand = { version = "0.8", features = ["std_rng", "std"], optional = true, default-features = false }
35+
constant_time_eq = "0.3"
36+
rand = { version = "0.9", features = ["thread_rng"], optional = true, default-features = false }
3737
zeroize = { version = "1.6", features = ["alloc", "derive"], optional = true }
3838
qrcodegen-image = { version = "1.4", features = ["base64"], optional = true }

src/lib.rs

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -87,16 +87,22 @@ const STEAM_CHARS: &str = "23456789BCDFGHJKMNPQRTVWXY";
8787
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
8888
#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))]
8989
pub enum Algorithm {
90+
/// HMAC-SHA1 is the default algorithm of most TOTP implementations.
91+
/// Some will outright ignore the algorithm parameter to force using SHA1, leading to confusion.
9092
SHA1,
93+
/// HMAC-SHA256. Supported in theory according to [yubico](https://docs.yubico.com/yesdk/users-manual/application-oath/uri-string-format.html).
94+
/// Ignored in practice by most.
9195
SHA256,
96+
/// HMAC-SHA512. Supported in theory according to [yubico](https://docs.yubico.com/yesdk/users-manual/application-oath/uri-string-format.html).
97+
/// Ignored in practice by most.
9298
SHA512,
9399
#[cfg(feature = "steam")]
94100
#[cfg_attr(docsrs, doc(cfg(feature = "steam")))]
95-
/// Steam TOTP token algorithm
101+
/// Steam TOTP token algorithm.
96102
Steam,
97103
}
98104

99-
impl std::default::Default for Algorithm {
105+
impl Default for Algorithm {
100106
fn default() -> Self {
101107
Algorithm::SHA1
102108
}
@@ -486,7 +492,7 @@ impl TOTP {
486492
/// Will return the base32 representation of the secret, which might be useful when users want to manually add the secret to their authenticator
487493
pub fn get_secret_base32(&self) -> String {
488494
base32::encode(
489-
base32::Alphabet::RFC4648 { padding: false },
495+
base32::Alphabet::Rfc4648 { padding: false },
490496
self.secret.as_ref(),
491497
)
492498
}
@@ -586,7 +592,7 @@ impl TOTP {
586592
}
587593
"secret" => {
588594
secret = base32::decode(
589-
base32::Alphabet::RFC4648 { padding: false },
595+
base32::Alphabet::Rfc4648 { padding: false },
590596
value.as_ref(),
591597
)
592598
.ok_or_else(|| TotpUrlError::Secret(value.to_string()))?;
@@ -1056,7 +1062,7 @@ mod tests {
10561062
assert_eq!(
10571063
totp.secret,
10581064
base32::decode(
1059-
base32::Alphabet::RFC4648 { padding: false },
1065+
base32::Alphabet::Rfc4648 { padding: false },
10601066
"KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ"
10611067
)
10621068
.unwrap()
@@ -1074,7 +1080,7 @@ mod tests {
10741080
assert_eq!(
10751081
totp.secret,
10761082
base32::decode(
1077-
base32::Alphabet::RFC4648 { padding: false },
1083+
base32::Alphabet::Rfc4648 { padding: false },
10781084
"KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ"
10791085
)
10801086
.unwrap()
@@ -1092,7 +1098,7 @@ mod tests {
10921098
assert_eq!(
10931099
totp.secret,
10941100
base32::decode(
1095-
base32::Alphabet::RFC4648 { padding: false },
1101+
base32::Alphabet::Rfc4648 { padding: false },
10961102
"KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ"
10971103
)
10981104
.unwrap()
@@ -1127,7 +1133,7 @@ mod tests {
11271133
assert_eq!(
11281134
totp.secret,
11291135
base32::decode(
1130-
base32::Alphabet::RFC4648 { padding: false },
1136+
base32::Alphabet::Rfc4648 { padding: false },
11311137
"KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ"
11321138
)
11331139
.unwrap()
@@ -1201,7 +1207,7 @@ mod tests {
12011207
assert_eq!(
12021208
totp.secret,
12031209
base32::decode(
1204-
base32::Alphabet::RFC4648 { padding: false },
1210+
base32::Alphabet::Rfc4648 { padding: false },
12051211
"KRSXG5CTMVRXEZLUKN2XAZLSKNSWG4TFOQ"
12061212
)
12071213
.unwrap()

src/rfc.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ impl std::fmt::Display for Rfc6238Error {
3333
}
3434
}
3535

36+
// Check that the number of digits is RFC-compliant.
37+
// (between 6 and 8 inclusive).
3638
pub fn assert_digits(digits: &usize) -> Result<(), Rfc6238Error> {
3739
if !(&6..=&8).contains(&digits) {
3840
Err(Rfc6238Error::InvalidDigits(*digits))
@@ -41,6 +43,8 @@ pub fn assert_digits(digits: &usize) -> Result<(), Rfc6238Error> {
4143
}
4244
}
4345

46+
// Check that the secret is AT LEAST 128 bits long, as per the RFC's requirements.
47+
// It is still RECOMMENDED to have an at least 160 bits long secret.
4448
pub fn assert_secret_length(secret: &[u8]) -> Result<(), Rfc6238Error> {
4549
if secret.as_ref().len() < 16 {
4650
Err(Rfc6238Error::SecretTooSmall(secret.as_ref().len() * 8))

src/secret.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ impl Secret {
131131
pub fn to_bytes(&self) -> Result<Vec<u8>, SecretParseError> {
132132
match self {
133133
Secret::Raw(s) => Ok(s.to_vec()),
134-
Secret::Encoded(s) => match base32::decode(Alphabet::RFC4648 { padding: false }, s) {
134+
Secret::Encoded(s) => match base32::decode(Alphabet::Rfc4648 { padding: false }, s) {
135135
Some(bytes) => Ok(bytes),
136136
None => Err(SecretParseError::ParseBase32),
137137
},
@@ -142,7 +142,7 @@ impl Secret {
142142
pub fn to_raw(&self) -> Result<Self, SecretParseError> {
143143
match self {
144144
Secret::Raw(_) => Ok(self.clone()),
145-
Secret::Encoded(s) => match base32::decode(Alphabet::RFC4648 { padding: false }, s) {
145+
Secret::Encoded(s) => match base32::decode(Alphabet::Rfc4648 { padding: false }, s) {
146146
Some(buf) => Ok(Secret::Raw(buf)),
147147
None => Err(SecretParseError::ParseBase32),
148148
},
@@ -153,7 +153,7 @@ impl Secret {
153153
pub fn to_encoded(&self) -> Self {
154154
match self {
155155
Secret::Raw(s) => {
156-
Secret::Encoded(base32::encode(Alphabet::RFC4648 { padding: false }, s))
156+
Secret::Encoded(base32::encode(Alphabet::Rfc4648 { padding: false }, s))
157157
}
158158
Secret::Encoded(_) => self.clone(),
159159
}
@@ -171,7 +171,7 @@ impl Secret {
171171
pub fn generate_secret() -> Secret {
172172
use rand::Rng;
173173

174-
let mut rng = rand::thread_rng();
174+
let mut rng = rand::rng();
175175
let mut secret: [u8; 20] = Default::default();
176176
rng.fill(&mut secret[..]);
177177
Secret::Raw(secret.to_vec())

0 commit comments

Comments
 (0)