| 
						
						
							
								
							
						
						
					 | 
					@ -103,7 +103,6 @@ pub fn validate_totp_code_str(user_uuid: &str, totp_code: &str, secret: &str, co | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					pub fn validate_totp_code(user_uuid: &str, totp_code: u64, secret: &str, conn: &DbConn) -> EmptyResult { | 
					 | 
					 | 
					pub fn validate_totp_code(user_uuid: &str, totp_code: u64, secret: &str, conn: &DbConn) -> EmptyResult { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    use oath::{totp_raw_custom_time, HashType}; | 
					 | 
					 | 
					    use oath::{totp_raw_custom_time, HashType}; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    use std::time::{UNIX_EPOCH, SystemTime}; | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    let decoded_secret = match BASE32.decode(secret.as_bytes()) { | 
					 | 
					 | 
					    let decoded_secret = match BASE32.decode(secret.as_bytes()) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        Ok(s) => s, | 
					 | 
					 | 
					        Ok(s) => s, | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -116,24 +115,23 @@ pub fn validate_totp_code(user_uuid: &str, totp_code: u64, secret: &str, conn: & | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    }; | 
					 | 
					 | 
					    }; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    // Get the current system time in UNIX Epoch (UTC)
 | 
					 | 
					 | 
					    // Get the current system time in UNIX Epoch (UTC)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    let current_time: u64 = SystemTime::now().duration_since(UNIX_EPOCH) | 
					 | 
					 | 
					    let current_time = chrono::Utc::now(); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					        .expect("Earlier than 1970-01-01 00:00:00 UTC").as_secs(); | 
					 | 
					 | 
					    let current_timestamp = current_time.timestamp(); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    // The amount of steps back and forward in time
 | 
					 | 
					 | 
					    // The amount of steps back and forward in time
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    // Also check if we need to disable time drifted TOTP codes.
 | 
					 | 
					 | 
					    // Also check if we need to disable time drifted TOTP codes.
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    // If that is the case, we set the steps to 0 so only the current TOTP is valid.
 | 
					 | 
					 | 
					    // If that is the case, we set the steps to 0 so only the current TOTP is valid.
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    let steps = if CONFIG.authenticator_disable_time_drift() { 0 } else { 1 }; | 
					 | 
					 | 
					    let steps: i64 = if CONFIG.authenticator_disable_time_drift() { 0 } else { 1 }; | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    for step in -steps..=steps { | 
					 | 
					 | 
					    for step in -steps..=steps { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        let time_step = (current_time / 30) as i32 + step; | 
					 | 
					 | 
					        let time_step = current_timestamp / 30i64 + step; | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					        // We need to calculate the time offsite and cast it as an i128.
 | 
					 | 
					 | 
					        // We need to calculate the time offsite and cast it as an i128.
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        // Else we can't do math with it on a default u64 variable.
 | 
					 | 
					 | 
					        // Else we can't do math with it on a default u64 variable.
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        let time_offset: i128 = (step * 30).into(); | 
					 | 
					 | 
					        let time = (current_timestamp + step * 30i64) as u64; | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					        let generated = totp_raw_custom_time(&decoded_secret, 6, 0, 30, (current_time as i128 + time_offset) as u64, &HashType::SHA1); | 
					 | 
					 | 
					        let generated = totp_raw_custom_time(&decoded_secret, 6, 0, 30, time, &HashType::SHA1); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        // Check the the given code equals the generated and if the time_step is larger then the one last used.
 | 
					 | 
					 | 
					        // Check the the given code equals the generated and if the time_step is larger then the one last used.
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        if generated == totp_code && time_step > twofactor.last_used { | 
					 | 
					 | 
					        if generated == totp_code && time_step > twofactor.last_used as i64 { | 
				
			
			
				
				
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					            // If the step does not equals 0 the time is drifted either server or client side.
 | 
					 | 
					 | 
					            // If the step does not equals 0 the time is drifted either server or client side.
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            if step != 0 { | 
					 | 
					 | 
					            if step != 0 { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                info!("TOTP Time drift detected. The step offset is {}", step); | 
					 | 
					 | 
					                info!("TOTP Time drift detected. The step offset is {}", step); | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -141,15 +139,15 @@ pub fn validate_totp_code(user_uuid: &str, totp_code: u64, secret: &str, conn: & | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            // Save the last used time step so only totp time steps higher then this one are allowed.
 | 
					 | 
					 | 
					            // Save the last used time step so only totp time steps higher then this one are allowed.
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            // This will also save a newly created twofactor if the code is correct.
 | 
					 | 
					 | 
					            // This will also save a newly created twofactor if the code is correct.
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					            twofactor.last_used = time_step; | 
					 | 
					 | 
					            twofactor.last_used = time_step as i32; | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					            twofactor.save(&conn)?; | 
					 | 
					 | 
					            twofactor.save(&conn)?; | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            return Ok(()); | 
					 | 
					 | 
					            return Ok(()); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        } else if generated == totp_code && time_step <= twofactor.last_used { | 
					 | 
					 | 
					        } else if generated == totp_code && time_step <= twofactor.last_used as i64 { | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					            warn!("This or a TOTP code within {} steps back and forward has already been used!", steps); | 
					 | 
					 | 
					            warn!("This or a TOTP code within {} steps back and forward has already been used!", steps); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					            err!("Invalid TOTP Code!"); | 
					 | 
					 | 
					            err!(format!("Invalid TOTP code! Server time: {}", current_time.format("%F %T UTC"))); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					        } | 
					 | 
					 | 
					        } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    } | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    // Else no valide code received, deny access
 | 
					 | 
					 | 
					    // Else no valide code received, deny access
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					    err!("Invalid TOTP code!"); | 
					 | 
					 | 
					    err!(format!("Invalid TOTP code! Server time: {}", current_time.format("%F %T UTC"))); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					} | 
					 | 
					 | 
					} | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
					 | 
					
  |