@@ -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+
157159impl 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