@@ -154,6 +154,8 @@ pub struct OTPElement {
154
154
pub pin : Option < String > ,
155
155
}
156
156
157
+ static ALLOWED_DIGITS_RANGE : std:: ops:: RangeInclusive < u64 > = 1 ..=10 ;
158
+
157
159
impl OTPElement {
158
160
pub fn get_otpauth_uri ( & self ) -> String {
159
161
let otp_type = self . type_ . to_string ( ) . to_lowercase ( ) ;
@@ -183,6 +185,10 @@ impl OTPElement {
183
185
}
184
186
185
187
pub fn get_otp_code ( & self ) -> Result < String , OtpError > {
188
+ if !ALLOWED_DIGITS_RANGE . contains ( & self . digits ) {
189
+ return Err ( OtpError :: InvalidDigits ) ;
190
+ }
191
+
186
192
match self . type_ {
187
193
OTPType :: Totp => {
188
194
let code = totp ( & self . secret , self . algorithm ) ?;
@@ -222,11 +228,11 @@ impl OTPElement {
222
228
223
229
fn format_code ( & self , value : u32 ) -> Result < String , OtpError > {
224
230
// Get the formatted code
225
- let exponential = 10_u32
231
+ let exponential = 10_u64
226
232
. checked_pow ( self . digits as u32 )
227
233
. 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 ( ) )
230
236
}
231
237
}
232
238
@@ -357,7 +363,7 @@ mod test {
357
363
#[ test]
358
364
fn test_invalid_digits_should_not_overflow ( ) {
359
365
// Arrange
360
- let invalid_digits_value = 10 ;
366
+ let invalid_digits_value = 11 ;
361
367
362
368
let element = OTPElement {
363
369
secret : "xr5gh44x7bprcqgrdtulafeevt5rxqlbh5wvked22re43dh2d4mapv5g" . to_uppercase ( ) ,
@@ -378,6 +384,30 @@ mod test {
378
384
assert_eq ! ( Err ( OtpError :: InvalidDigits ) , result) ;
379
385
}
380
386
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
+
381
411
#[ test]
382
412
fn test_lowercase_secret ( ) {
383
413
// Arrange / Act
0 commit comments