Skip to content

Commit 3a1b2f2

Browse files
authored
Various fixes in OTP digits handling and code formatting (#565)
2 parents 4151871 + 40e1b84 commit 3a1b2f2

File tree

3 files changed

+36
-6
lines changed

3 files changed

+36
-6
lines changed

src/arguments/add.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ pub struct AddArgs {
4040
long,
4141
default_value_t = 6,
4242
default_value_if("type", "STEAM", "5"),
43-
value_parser=value_parser!(u64).range(0..=9)
43+
value_parser=value_parser!(u64).range(1..=10)
4444
)]
4545
pub digits: u64,
4646

src/arguments/edit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ pub struct EditArgs {
2424
pub algorithm: Option<OTPAlgorithm>,
2525

2626
/// Code digits
27-
#[arg(short, long, value_parser=value_parser!(u64).range(0..=9))]
27+
#[arg(short, long, value_parser=value_parser!(u64).range(1..=10))]
2828
pub digits: Option<u64>,
2929

3030
/// Code period

src/otp/otp_element.rs

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ pub struct OTPElement {
154154
pub pin: Option<String>,
155155
}
156156

157+
static ALLOWED_DIGITS_RANGE: std::ops::RangeInclusive<u64> = 1..=10;
158+
157159
impl OTPElement {
158160
pub fn get_otpauth_uri(&self) -> String {
159161
let otp_type = self.type_.to_string().to_lowercase();
@@ -183,6 +185,10 @@ impl OTPElement {
183185
}
184186

185187
pub fn get_otp_code(&self) -> Result<String, OtpError> {
188+
if !ALLOWED_DIGITS_RANGE.contains(&self.digits) {
189+
return Err(OtpError::InvalidDigits);
190+
}
191+
186192
match self.type_ {
187193
OTPType::Totp => {
188194
let code = totp(&self.secret, self.algorithm)?;
@@ -222,11 +228,11 @@ impl OTPElement {
222228

223229
fn format_code(&self, value: u32) -> Result<String, OtpError> {
224230
// Get the formatted code
225-
let exponential = 10_u32
231+
let exponential = 10_u64
226232
.checked_pow(self.digits as u32)
227233
.ok_or(OtpError::InvalidDigits)?;
228-
let s = (value % exponential).to_string();
229-
Ok("0".repeat(self.digits as usize - s.chars().count()) + s.as_str())
234+
let s = (value as u64 % exponential).to_string();
235+
Ok("0".repeat((self.digits as usize).saturating_sub(s.chars().count())) + s.as_str())
230236
}
231237
}
232238

@@ -357,7 +363,7 @@ mod test {
357363
#[test]
358364
fn test_invalid_digits_should_not_overflow() {
359365
// Arrange
360-
let invalid_digits_value = 10;
366+
let invalid_digits_value = 11;
361367

362368
let element = OTPElement {
363369
secret: "xr5gh44x7bprcqgrdtulafeevt5rxqlbh5wvked22re43dh2d4mapv5g".to_uppercase(),
@@ -378,6 +384,30 @@ mod test {
378384
assert_eq!(Err(OtpError::InvalidDigits), result);
379385
}
380386

387+
#[test]
388+
fn test_10_digits_should_be_allowed() {
389+
// Arrange
390+
let invalid_digits_value = 10;
391+
392+
let element = OTPElement {
393+
secret: "xr5gh44x7bprcqgrdtulafeevt5rxqlbh5wvked22re43dh2d4mapv5g".to_uppercase(),
394+
issuer: String::from("IssuerText"),
395+
label: String::from("LabelText"),
396+
digits: invalid_digits_value,
397+
type_: Totp,
398+
algorithm: Sha1,
399+
period: 30,
400+
counter: None,
401+
pin: None,
402+
};
403+
404+
// Act
405+
let result = element.get_otp_code();
406+
407+
// Assert
408+
assert!(result.is_ok());
409+
}
410+
381411
#[test]
382412
fn test_lowercase_secret() {
383413
// Arrange / Act

0 commit comments

Comments
 (0)