1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-08-07 17:03:01 +03:00

Upgrade chrono and replace deprecated methods usage

This commit is contained in:
Quentin Gliech
2024-03-18 14:00:38 +01:00
parent f543a8bd40
commit 61a69f5af4
32 changed files with 103 additions and 85 deletions

4
Cargo.lock generated
View File

@@ -896,9 +896,9 @@ dependencies = [
[[package]]
name = "chrono"
version = "0.4.33"
version = "0.4.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f13690e35a5e4ace198e7beea2895d29f3a9cc55015fcebe6336bd2010af9eb"
checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a"
dependencies = [
"android-tzdata",
"iana-time-zone",

View File

@@ -65,7 +65,7 @@ version = "1.1.6"
# Time utilities
[workspace.dependencies.chrono]
version = "0.4.33"
version = "0.4.35"
default-features = false
features = ["serde", "clock"]

View File

@@ -153,8 +153,8 @@ impl CsrfExt for CookieJar {
};
let token = maybe_token.map_or_else(
|| CsrfToken::generate(now, rng, Duration::hours(1)),
|token| token.refresh(now, Duration::hours(1)),
|| CsrfToken::generate(now, rng, Duration::try_hours(1).unwrap()),
|token| token.refresh(now, Duration::try_hours(1).unwrap()),
);
let jar = self.save("csrf", &token, false);

View File

@@ -22,7 +22,7 @@ use serde_with::serde_as;
use crate::ConfigurationSection;
fn default_token_ttl() -> Duration {
Duration::minutes(5)
Duration::microseconds(5 * 60 * 1000 * 1000)
}
/// Configuration sections for experimental options

View File

@@ -175,11 +175,16 @@ impl std::ops::Deref for AuthorizationGrant {
}
}
const DEFAULT_MAX_AGE: Duration = Duration::microseconds(3600 * 24 * 365 * 1000 * 1000);
impl AuthorizationGrant {
#[must_use]
pub fn max_auth_time(&self) -> DateTime<Utc> {
let max_age: Option<i64> = self.max_age.map(|x| x.get().into());
self.created_at - Duration::seconds(max_age.unwrap_or(3600 * 24 * 365))
let max_age = self
.max_age
.and_then(|x| Duration::try_seconds(x.get().into()))
.unwrap_or(DEFAULT_MAX_AGE);
self.created_at - max_age
}
/// Mark the authorization grant as exchanged.

View File

@@ -185,10 +185,10 @@ impl UserEmailVerification {
pub fn samples(now: chrono::DateTime<Utc>, rng: &mut impl Rng) -> Vec<Self> {
let states = [
UserEmailVerificationState::AlreadyUsed {
when: now - Duration::minutes(5),
when: now - Duration::microseconds(5 * 60 * 1000 * 1000),
},
UserEmailVerificationState::Expired {
when: now - Duration::hours(5),
when: now - Duration::microseconds(5 * 60 * 1000 * 1000),
},
UserEmailVerificationState::Valid,
];
@@ -204,7 +204,7 @@ impl UserEmailVerification {
id: Ulid::from_datetime_with_source(now.into(), &mut rng),
user_email_id: email.id,
code: "123456".to_owned(),
created_at: now - Duration::minutes(10),
created_at: now - Duration::microseconds(10 * 60 * 1000 * 1000),
state: state.clone(),
})
})

View File

@@ -179,7 +179,7 @@ impl OAuth2SessionMutations {
let ttl = if permanent {
None
} else {
Some(Duration::minutes(5))
Some(Duration::microseconds(5 * 60 * 1000 * 1000))
};
let access_token = repo
.oauth2_access_token()

View File

@@ -321,7 +321,7 @@ async fn token_login(
session_id,
..
} => {
if now > fulfilled_at + Duration::seconds(30) {
if now > fulfilled_at + Duration::microseconds(30 * 1000 * 1000) {
return Err(RouteError::LoginTookTooLong);
}
@@ -332,7 +332,7 @@ async fn token_login(
session_id,
..
} => {
if now > exchanged_at + Duration::seconds(30) {
if now > exchanged_at + Duration::microseconds(30 * 1000 * 1000) {
// TODO: log that session out
tracing::error!(
compat_sso_login.id = %login.id,
@@ -706,7 +706,9 @@ mod tests {
let (_device, token) = get_login_token(&state, &user).await;
// Advance the clock to make the token expire.
state.clock.advance(Duration::minutes(1));
state
.clock
.advance(Duration::microseconds(60 * 1000 * 1000));
let request = Request::post("/_matrix/client/v3/login").json(serde_json::json!({
"type": "m.login.token",

View File

@@ -103,7 +103,7 @@ pub async fn get(
.context("Could not find compat SSO login")?;
// Bail out if that login session is more than 30min old
if clock.now() > login.created_at + Duration::minutes(30) {
if clock.now() > login.created_at + Duration::microseconds(30 * 60 * 1000 * 1000) {
let ctx = ErrorContext::new()
.with_code("compat_sso_login_expired")
.with_description("This login session expired.".to_owned())
@@ -174,7 +174,7 @@ pub async fn post(
.context("Could not find compat SSO login")?;
// Bail out if that login session is more than 30min old
if clock.now() > login.created_at + Duration::minutes(30) {
if clock.now() > login.created_at + Duration::microseconds(30 * 60 * 1000 * 1000) {
let ctx = ErrorContext::new()
.with_code("compat_sso_login_expired")
.with_description("This login session expired.".to_owned())

View File

@@ -124,7 +124,7 @@ pub(crate) async fn post(
// XXX: Is this really how we do empty scopes?
.unwrap_or(std::iter::empty::<ScopeToken>().collect());
let expires_in = Duration::minutes(20);
let expires_in = Duration::microseconds(20 * 60 * 1000 * 1000);
let user_agent = user_agent.map(|ua| UserAgent::parse(ua.as_str().to_owned()));
let ip_address = activity_tracker.ip();
@@ -157,7 +157,7 @@ pub(crate) async fn post(
verification_uri: url_builder.device_code_link(),
verification_uri_complete: Some(url_builder.device_code_link_full(device_code.user_code)),
expires_in,
interval: Some(Duration::seconds(5)),
interval: Some(Duration::microseconds(5 * 1000 * 1000)),
};
Ok((

View File

@@ -550,7 +550,7 @@ mod tests {
&state.clock,
&mut repo,
&session,
Duration::minutes(5),
Duration::microseconds(5 * 60 * 1000 * 1000),
)
.await
.unwrap();
@@ -633,7 +633,7 @@ mod tests {
// Advance the clock to invalidate the access token
let old_now = state.clock.now();
state.clock.advance(Duration::hours(1));
state.clock.advance(Duration::try_hours(1).unwrap());
let request = Request::post(OAuth2Introspection::PATH)
.basic_auth(&introspecting_client_id, &introspecting_client_secret)
@@ -808,7 +808,7 @@ mod tests {
assert!(!response.active); // It shouldn't be active
// Advance the clock to invalidate the access token
state.clock.advance(Duration::hours(1));
state.clock.advance(Duration::try_hours(1).unwrap());
let request = Request::post(OAuth2Introspection::PATH)
.basic_auth(&introspecting_client_id, &introspecting_client_secret)

View File

@@ -70,7 +70,7 @@ pub(crate) fn generate_id_token(
claims::SUB.insert(&mut claims, &browser_session.user.sub)?;
claims::AUD.insert(&mut claims, client.client_id.clone())?;
claims::IAT.insert(&mut claims, now)?;
claims::EXP.insert(&mut claims, now + Duration::hours(1))?;
claims::EXP.insert(&mut claims, now + Duration::try_hours(1).unwrap())?;
if let Some(nonce) = grant.and_then(|grant| grant.nonce.as_ref()) {
claims::NONCE.insert(&mut claims, nonce)?;

View File

@@ -326,7 +326,7 @@ mod tests {
&state.clock,
&mut repo,
&session,
Duration::minutes(5),
Duration::microseconds(5 * 60 * 1000 * 1000),
)
.await
.unwrap();
@@ -393,7 +393,7 @@ mod tests {
&state.clock,
&mut repo,
&session,
Duration::minutes(5),
Duration::microseconds(5 * 60 * 1000 * 1000),
)
.await
.unwrap();

View File

@@ -365,7 +365,7 @@ async fn authorization_code_grant(
debug!(%exchanged_at, %fulfilled_at, "Authorization code was already exchanged");
// Ending the session if the token was already exchanged more than 20s ago
if now - exchanged_at > Duration::seconds(20) {
if now - exchanged_at > Duration::microseconds(20 * 1000 * 1000) {
debug!("Ending potentially compromised session");
let session = repo
.oauth2_session()
@@ -386,7 +386,7 @@ async fn authorization_code_grant(
session_id,
fulfilled_at,
} => {
if now - fulfilled_at > Duration::minutes(10) {
if now - fulfilled_at > Duration::microseconds(10 * 60 * 1000 * 1000) {
debug!("Code exchange took more than 10 minutes");
return Err(RouteError::InvalidGrant);
}
@@ -928,7 +928,7 @@ mod tests {
assert!(state.is_access_token_valid(&access_token).await);
// Now wait a bit
state.clock.advance(Duration::minutes(1));
state.clock.advance(Duration::try_minutes(1).unwrap());
// Exchange it again, this it should fail
let request =
@@ -994,7 +994,9 @@ mod tests {
repo.save().await.unwrap();
// Now wait a bit
state.clock.advance(Duration::minutes(15));
state
.clock
.advance(Duration::microseconds(15 * 60 * 1000 * 1000));
// Exchange it, it should fail
let request =
@@ -1075,7 +1077,7 @@ mod tests {
&state.clock,
&mut repo,
&session,
Duration::minutes(5),
Duration::microseconds(5 * 60 * 1000 * 1000),
)
.await
.unwrap();
@@ -1386,7 +1388,7 @@ mod tests {
let ClientError { error, .. } = response.json();
assert_eq!(error, ClientErrorCode::AuthorizationPending);
state.clock.advance(Duration::hours(1));
state.clock.advance(Duration::try_hours(1).unwrap());
// Poll again, it should be expired
let request =

View File

@@ -26,8 +26,8 @@ pub struct SiteConfig {
impl Default for SiteConfig {
fn default() -> Self {
Self {
access_token_ttl: Duration::minutes(5),
compat_token_ttl: Duration::minutes(5),
access_token_ttl: Duration::microseconds(5 * 60 * 1000 * 1000),
compat_token_ttl: Duration::microseconds(5 * 60 * 1000 * 1000),
tos_uri: None,
}
}

View File

@@ -14,7 +14,7 @@
// TODO: move that to a standalone cookie manager
use chrono::{DateTime, Duration, NaiveDateTime, TimeZone, Utc};
use chrono::{DateTime, Duration, Utc};
use mas_axum_utils::cookies::CookieJar;
use mas_router::PostAuthAction;
use mas_storage::Clock;
@@ -26,7 +26,7 @@ use ulid::Ulid;
static COOKIE_NAME: &str = "upstream-oauth2-sessions";
/// Sessions expire after 10 minutes
static SESSION_MAX_TIME_SECS: i64 = 60 * 10;
static SESSION_MAX_TIME: Duration = Duration::microseconds(10 * 60 * 1000 * 1000);
#[derive(Serialize, Deserialize, Debug)]
pub struct Payload {
@@ -42,12 +42,10 @@ impl Payload {
let Ok(ts) = self.session.timestamp_ms().try_into() else {
return true;
};
let Some(when) = NaiveDateTime::from_timestamp_millis(ts) else {
let Some(when) = DateTime::from_timestamp_millis(ts) else {
return true;
};
let when = Utc.from_utc_datetime(&when);
let max_age = Duration::seconds(SESSION_MAX_TIME_SECS);
now - when > max_age
now - when > SESSION_MAX_TIME
}
}
@@ -184,7 +182,7 @@ mod tests {
let first_state = "first-state";
let sessions = sessions.add(first_session, provider_a, first_state.into(), None);
let now = now + Duration::minutes(5);
let now = now + Duration::microseconds(5 * 60 * 1000 * 1000);
let second_session = Ulid::from_datetime_with_source(now.into(), &mut rng);
let second_state = "second-state";
@@ -203,7 +201,7 @@ mod tests {
assert!(sessions.find_session(provider_a, second_state).is_err());
// Make the first session expire
let now = now + Duration::minutes(6);
let now = now + Duration::microseconds(6 * 60 * 1000 * 1000);
let sessions = sessions.expire(now);
assert!(sessions.find_session(provider_a, first_state).is_err());
assert_eq!(

View File

@@ -203,7 +203,7 @@ impl TimeOptions {
pub fn new(when: chrono::DateTime<chrono::Utc>) -> Self {
Self {
when,
leeway: chrono::Duration::minutes(5),
leeway: chrono::Duration::microseconds(5 * 60 * 1000 * 1000),
}
}
@@ -586,7 +586,7 @@ mod tests {
let now = chrono::Utc
.with_ymd_and_hms(2018, 1, 18, 1, 30, 22)
.unwrap();
let expiration = now + chrono::Duration::minutes(5);
let expiration = now + chrono::Duration::microseconds(5 * 60 * 1000 * 1000);
let time_options = TimeOptions::new(now).leeway(chrono::Duration::zero());
let claims = serde_json::json!({
@@ -660,7 +660,7 @@ mod tests {
}
// Let's go back in time a bit
let now = now - chrono::Duration::minutes(1);
let now = now - chrono::Duration::microseconds(60 * 1000 * 1000);
{
// There is now a time variance between the two parties...
@@ -686,7 +686,8 @@ mod tests {
let mut claims = claims.clone();
// but no time variance is allowed. "iat" and "nbf" validation will fail
let time_options = TimeOptions::new(now).leeway(chrono::Duration::minutes(2));
let time_options =
TimeOptions::new(now).leeway(chrono::Duration::microseconds(2 * 60 * 1000 * 1000));
assert!(IAT
.extract_required_with_options(&mut claims, &time_options)
.is_ok());
@@ -699,7 +700,7 @@ mod tests {
}
// Let's wait some time so it expires
let now = now + chrono::Duration::minutes(1 + 6);
let now = now + chrono::Duration::microseconds((1 + 6) * 60 * 1000 * 1000);
{
// At this point, the claims expired one minute ago
@@ -723,7 +724,8 @@ mod tests {
let mut claims = claims;
// Same, but with a 2 minutes leeway should be fine then
let time_options = TimeOptions::new(now).leeway(chrono::Duration::minutes(2));
let time_options =
TimeOptions::new(now).leeway(chrono::Duration::try_minutes(2).unwrap());
assert!(IAT
.extract_required_with_options(&mut claims, &time_options)
.is_ok());

View File

@@ -366,7 +366,7 @@ pub struct DeviceAuthorizationRequest {
/// The default value of the `interval` between polling requests, if it is not
/// set.
pub const DEFAULT_DEVICE_AUTHORIZATION_INTERVAL_SECONDS: i64 = 5;
pub const DEFAULT_DEVICE_AUTHORIZATION_INTERVAL: Duration = Duration::microseconds(5 * 1000 * 1000);
/// A successful response from the [Device Authorization Endpoint].
///
@@ -399,7 +399,7 @@ pub struct DeviceAuthorizationResponse {
/// The minimum amount of time in seconds that the client should wait
/// between polling requests to the token endpoint.
///
/// Defaults to [`DEFAULT_DEVICE_AUTHORIZATION_INTERVAL_SECONDS`].
/// Defaults to [`DEFAULT_DEVICE_AUTHORIZATION_INTERVAL`].
#[serde_as(as = "Option<DurationSeconds<i64>>")]
pub interval: Option<Duration>,
}
@@ -408,11 +408,11 @@ impl DeviceAuthorizationResponse {
/// The minimum amount of time in seconds that the client should wait
/// between polling requests to the token endpoint.
///
/// Defaults to [`DEFAULT_DEVICE_AUTHORIZATION_INTERVAL_SECONDS`].
/// Defaults to [`DEFAULT_DEVICE_AUTHORIZATION_INTERVAL`].
#[must_use]
pub fn interval(&self) -> Duration {
self.interval
.unwrap_or_else(|| Duration::seconds(DEFAULT_DEVICE_AUTHORIZATION_INTERVAL_SECONDS))
.unwrap_or(DEFAULT_DEVICE_AUTHORIZATION_INTERVAL)
}
}

View File

@@ -399,7 +399,10 @@ fn prepare_claims(
claims::SUB.insert(&mut claims, iss)?;
claims::AUD.insert(&mut claims, aud)?;
claims::IAT.insert(&mut claims, now)?;
claims::EXP.insert(&mut claims, now + Duration::minutes(5))?;
claims::EXP.insert(
&mut claims,
now + Duration::microseconds(5 * 60 * 1000 * 1000),
)?;
let mut jti = [0u8; 16];
rng.fill(&mut jti);

View File

@@ -105,7 +105,7 @@ fn id_token(issuer: &str) -> (IdToken, PublicJsonWebKeySet) {
claims::IAT.insert(&mut claims, now).unwrap();
claims::EXP
.insert(&mut claims, now + Duration::hours(1))
.insert(&mut claims, now + Duration::try_hours(1).unwrap())
.unwrap();
claims::AT_HASH

View File

@@ -174,7 +174,7 @@ async fn pass_pushed_authorization_request() {
.respond_with(
ResponseTemplate::new(200).set_body_json(PushedAuthorizationResponse {
request_uri: REQUEST_URI.to_owned(),
expires_in: Duration::seconds(30),
expires_in: Duration::microseconds(30 * 1000 * 1000),
}),
)
.mount(&mock_server)

View File

@@ -68,11 +68,11 @@ fn id_token(
if flag == Some(IdTokenFlag::WrongExpiration) {
claims::EXP
.insert(&mut claims, now - Duration::hours(1))
.insert(&mut claims, now - Duration::try_hours(1).unwrap())
.unwrap();
} else {
claims::EXP
.insert(&mut claims, now + Duration::hours(1))
.insert(&mut claims, now + Duration::try_hours(1).unwrap())
.unwrap();
}
@@ -229,7 +229,7 @@ async fn fail_verify_id_token_wrong_auth_time() {
let issuer = "http://localhost/";
let now = now();
let (auth_id_token, _) = id_token(issuer, None, Some(now));
let (id_token, jwks) = id_token(issuer, None, Some(now + Duration::hours(1)));
let (id_token, jwks) = id_token(issuer, None, Some(now + Duration::try_hours(1).unwrap()));
let verification_data = JwtVerificationData {
issuer,

View File

@@ -608,7 +608,7 @@ mod tests {
// We're moving the clock forward by 1 minute between each session to ensure
// we're getting consistent ordering in lists.
clock.advance(Duration::minutes(1));
clock.advance(Duration::try_minutes(1).unwrap());
let oauth_session = repo
.oauth2_session()

View File

@@ -321,7 +321,7 @@ mod tests {
&clock,
&session,
FIRST_TOKEN.to_owned(),
Some(Duration::minutes(1)),
Some(Duration::try_minutes(1).unwrap()),
)
.await
.unwrap();
@@ -341,7 +341,7 @@ mod tests {
&clock,
&session,
FIRST_TOKEN.to_owned(),
Some(Duration::minutes(1)),
Some(Duration::try_minutes(1).unwrap()),
)
.await
.is_err());
@@ -374,7 +374,7 @@ mod tests {
// Token is currently valid
assert!(token.is_valid(clock.now()));
clock.advance(Duration::minutes(1));
clock.advance(Duration::try_minutes(1).unwrap());
// Token should have expired
assert!(!token.is_valid(clock.now()));

View File

@@ -208,7 +208,7 @@ impl<'c> OAuth2AccessTokenRepository for PgOAuth2AccessTokenRepository<'c> {
async fn cleanup_expired(&mut self, clock: &dyn Clock) -> Result<usize, Self::Error> {
// Cleanup token which expired more than 15 minutes ago
let threshold = clock.now() - Duration::minutes(15);
let threshold = clock.now() - Duration::microseconds(15 * 60 * 1000 * 1000);
let res = sqlx::query!(
r#"
DELETE FROM oauth2_access_tokens

View File

@@ -272,7 +272,7 @@ mod tests {
&clock,
&session,
"aabbcc".to_owned(),
Some(Duration::minutes(5)),
Some(Duration::try_minutes(5).unwrap()),
)
.await
.unwrap();
@@ -343,11 +343,11 @@ mod tests {
assert_eq!(refresh_token, refresh_token_lookup);
assert!(access_token.is_valid(clock.now()));
clock.advance(Duration::minutes(6));
clock.advance(Duration::try_minutes(6).unwrap());
assert!(!access_token.is_valid(clock.now()));
// XXX: we might want to create a new access token
clock.advance(Duration::minutes(-6)); // Go back in time
clock.advance(Duration::try_minutes(-6).unwrap()); // Go back in time
assert!(access_token.is_valid(clock.now()));
// Mark the access token as revoked
@@ -487,28 +487,28 @@ mod tests {
.add_from_browser_session(&mut rng, &clock, &client1, &user1_session, scope.clone())
.await
.unwrap();
clock.advance(Duration::minutes(1));
clock.advance(Duration::try_minutes(1).unwrap());
let session12 = repo
.oauth2_session()
.add_from_browser_session(&mut rng, &clock, &client1, &user2_session, scope.clone())
.await
.unwrap();
clock.advance(Duration::minutes(1));
clock.advance(Duration::try_minutes(1).unwrap());
let session21 = repo
.oauth2_session()
.add_from_browser_session(&mut rng, &clock, &client2, &user1_session, scope2.clone())
.await
.unwrap();
clock.advance(Duration::minutes(1));
clock.advance(Duration::try_minutes(1).unwrap());
let session22 = repo
.oauth2_session()
.add_from_browser_session(&mut rng, &clock, &client2, &user2_session, scope2.clone())
.await
.unwrap();
clock.advance(Duration::minutes(1));
clock.advance(Duration::try_minutes(1).unwrap());
// We're also finishing two of the sessions
let session11 = repo
@@ -775,7 +775,7 @@ mod tests {
scope: scope.clone(),
device_code: device_code.to_owned(),
user_code: user_code.to_owned(),
expires_in: Duration::minutes(5),
expires_in: Duration::try_minutes(5).unwrap(),
ip_address: None,
user_agent: None,
},
@@ -880,7 +880,7 @@ mod tests {
scope: scope.clone(),
device_code: "second_devicecode".to_owned(),
user_code: "second_usercode".to_owned(),
expires_in: Duration::minutes(5),
expires_in: Duration::try_minutes(5).unwrap(),
ip_address: None,
user_agent: None,
},

View File

@@ -266,7 +266,7 @@ mod tests {
.await
.unwrap();
ids.push(provider.id);
clock.advance(Duration::seconds(10));
clock.advance(Duration::microseconds(10 * 1000 * 1000));
}
// Now we have 20 providers

View File

@@ -191,7 +191,7 @@ async fn test_user_email_repo(pool: PgPool) {
&mut rng,
&clock,
&user_email,
Duration::hours(8),
Duration::try_hours(8).unwrap(),
CODE.to_owned(),
)
.await
@@ -208,7 +208,7 @@ async fn test_user_email_repo(pool: PgPool) {
&mut rng,
&clock,
&user_email,
Duration::hours(8),
Duration::try_hours(8).unwrap(),
CODE2.to_owned(),
)
.await
@@ -395,7 +395,7 @@ async fn test_user_password_repo(pool: PgPool) {
// Getting the last inserted password is based on the clock, so we need to
// advance it
clock.advance(Duration::seconds(10));
clock.advance(Duration::microseconds(10 * 1000 * 1000));
let second_password = repo
.user_password()

View File

@@ -66,9 +66,9 @@ impl Clock for SystemClock {
/// let t2 = clock.now();
/// assert_eq!(t1, t2);
///
/// clock.advance(Duration::seconds(10));
/// clock.advance(Duration::microseconds(10 * 1000 * 1000));
/// let t3 = clock.now();
/// assert_eq!(t2 + Duration::seconds(10), t3);
/// assert_eq!(t2 + Duration::microseconds(10 * 1000 * 1000), t3);
/// ```
pub struct MockClock {
timestamp: AtomicI64,
@@ -121,9 +121,9 @@ mod tests {
assert_eq!(first, second);
// Clock can be advanced by a fixed duration
clock.advance(Duration::seconds(10));
clock.advance(Duration::microseconds(10 * 1000 * 1000));
let third = clock.now();
assert_eq!(first + Duration::seconds(10), third);
assert_eq!(first + Duration::microseconds(10 * 1000 * 1000), third);
}
#[test]

View File

@@ -69,7 +69,13 @@ async fn verify_email(
// Save the verification code in the database
let verification = repo
.user_email()
.add_verification_code(&mut rng, &clock, &user_email, Duration::hours(8), code)
.add_verification_code(
&mut rng,
&clock,
&user_email,
Duration::try_hours(8).unwrap(),
code,
)
.await?;
// And send the verification email

View File

@@ -337,7 +337,7 @@ where
.as_secs()
.try_into()
.map_err(|e| StorageError::Database(Box::new(e)))?;
let wait = chrono::Duration::seconds(wait);
let wait = chrono::Duration::microseconds(wait * 1000 * 1000);
// TODO: should we use a clock here?
#[allow(clippy::disallowed_methods)]
let run_at = Utc::now().add(wait);

View File

@@ -626,8 +626,8 @@ impl TemplateContext for PolicyViolationContext {
scope: [OPENID].into_iter().collect(),
user_code: Alphanumeric.sample_string(rng, 6).to_uppercase(),
device_code: Alphanumeric.sample_string(rng, 32),
created_at: now - Duration::minutes(5),
expires_at: now + Duration::minutes(25),
created_at: now - Duration::try_minutes(5).unwrap(),
expires_at: now + Duration::try_minutes(25).unwrap(),
ip_address: None,
user_agent: None,
},
@@ -1161,8 +1161,8 @@ impl TemplateContext for DeviceConsentContext {
scope: [OPENID].into_iter().collect(),
user_code: Alphanumeric.sample_string(rng, 6).to_uppercase(),
device_code: Alphanumeric.sample_string(rng, 32),
created_at: now - Duration::minutes(5),
expires_at: now + Duration::minutes(25),
created_at: now - Duration::try_minutes(5).unwrap(),
expires_at: now + Duration::try_minutes(25).unwrap(),
ip_address: Some(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))),
user_agent: Some(UserAgent::parse("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.0.0 Safari/537.36".to_owned())),
};