@@ -171,13 +171,13 @@ impl OTPElement {
171171 OTPType :: Totp => {
172172 let code = totp ( & self . secret , self . algorithm ) ?;
173173
174- Ok ( self . format_code ( code) )
174+ Ok ( self . format_code ( code) ? )
175175 }
176176 OTPType :: Hotp => match self . counter {
177177 Some ( counter) => {
178178 let code = hotp ( & self . secret , self . algorithm , counter) ?;
179179
180- Ok ( self . format_code ( code) )
180+ Ok ( self . format_code ( code) ? )
181181 }
182182 None => Err ( OtpError :: MissingCounter ) ,
183183 } ,
@@ -204,10 +204,13 @@ impl OTPElement {
204204 }
205205 }
206206
207- pub fn format_code ( & self , value : u32 ) -> String {
207+ fn format_code ( & self , value : u32 ) -> Result < String , OtpError > {
208208 // Get the formatted code
209- let s = ( value % 10_u32 . pow ( self . digits as u32 ) ) . to_string ( ) ;
210- "0" . repeat ( self . digits as usize - s. chars ( ) . count ( ) ) + s. as_str ( )
209+ let exponential = 10_u32
210+ . checked_pow ( self . digits as u32 )
211+ . ok_or ( OtpError :: InvalidDigits ) ?;
212+ let s = ( value % exponential) . to_string ( ) ;
213+ Ok ( "0" . repeat ( self . digits as usize - s. chars ( ) . count ( ) ) + s. as_str ( ) )
211214 }
212215
213216 pub fn valid_secret ( & self ) -> bool {
@@ -231,6 +234,7 @@ mod test {
231234 use crate :: otp:: otp_element:: OTPType :: Totp ;
232235
233236 use crate :: otp:: from_otp_uri:: FromOtpUri ;
237+ use crate :: otp:: otp_error:: OtpError ;
234238
235239 #[ test]
236240 fn test_serialization_otp_uri_full_element ( ) {
@@ -287,4 +291,28 @@ mod test {
287291 let otp_uri = "otpauth://totp/2Ponies%40Github%20No.1?secret=JBSWY3DPEHPK3PXP&algorithm=SHA1&digits=6&period=30&lock=false&issuer=test" ;
288292 assert_eq ! ( true , OTPElement :: from_otp_uri( otp_uri) . is_ok( ) )
289293 }
294+
295+ #[ test]
296+ fn test_invalid_digits_should_not_overflow ( ) {
297+ // Arrange
298+ let invalid_digits_value = 10 ;
299+
300+ let element = OTPElement {
301+ secret : "xr5gh44x7bprcqgrdtulafeevt5rxqlbh5wvked22re43dh2d4mapv5g" . to_uppercase ( ) ,
302+ issuer : String :: from ( "IssuerText" ) ,
303+ label : String :: from ( "LabelText" ) ,
304+ digits : invalid_digits_value,
305+ type_ : Totp ,
306+ algorithm : Sha1 ,
307+ period : 30 ,
308+ counter : None ,
309+ pin : None ,
310+ } ;
311+
312+ // Act
313+ let result = element. get_otp_code ( ) ;
314+
315+ // Assert
316+ assert_eq ! ( Err ( OtpError :: InvalidDigits ) , result)
317+ }
290318}
0 commit comments