1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-08-06 06:02:40 +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]] [[package]]
name = "chrono" name = "chrono"
version = "0.4.33" version = "0.4.35"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f13690e35a5e4ace198e7beea2895d29f3a9cc55015fcebe6336bd2010af9eb" checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a"
dependencies = [ dependencies = [
"android-tzdata", "android-tzdata",
"iana-time-zone", "iana-time-zone",

View File

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

View File

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

View File

@@ -22,7 +22,7 @@ use serde_with::serde_as;
use crate::ConfigurationSection; use crate::ConfigurationSection;
fn default_token_ttl() -> Duration { fn default_token_ttl() -> Duration {
Duration::minutes(5) Duration::microseconds(5 * 60 * 1000 * 1000)
} }
/// Configuration sections for experimental options /// 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 { impl AuthorizationGrant {
#[must_use] #[must_use]
pub fn max_auth_time(&self) -> DateTime<Utc> { pub fn max_auth_time(&self) -> DateTime<Utc> {
let max_age: Option<i64> = self.max_age.map(|x| x.get().into()); let max_age = self
self.created_at - Duration::seconds(max_age.unwrap_or(3600 * 24 * 365)) .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. /// 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> { pub fn samples(now: chrono::DateTime<Utc>, rng: &mut impl Rng) -> Vec<Self> {
let states = [ let states = [
UserEmailVerificationState::AlreadyUsed { UserEmailVerificationState::AlreadyUsed {
when: now - Duration::minutes(5), when: now - Duration::microseconds(5 * 60 * 1000 * 1000),
}, },
UserEmailVerificationState::Expired { UserEmailVerificationState::Expired {
when: now - Duration::hours(5), when: now - Duration::microseconds(5 * 60 * 1000 * 1000),
}, },
UserEmailVerificationState::Valid, UserEmailVerificationState::Valid,
]; ];
@@ -204,7 +204,7 @@ impl UserEmailVerification {
id: Ulid::from_datetime_with_source(now.into(), &mut rng), id: Ulid::from_datetime_with_source(now.into(), &mut rng),
user_email_id: email.id, user_email_id: email.id,
code: "123456".to_owned(), code: "123456".to_owned(),
created_at: now - Duration::minutes(10), created_at: now - Duration::microseconds(10 * 60 * 1000 * 1000),
state: state.clone(), state: state.clone(),
}) })
}) })

View File

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

View File

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

View File

@@ -103,7 +103,7 @@ pub async fn get(
.context("Could not find compat SSO login")?; .context("Could not find compat SSO login")?;
// Bail out if that login session is more than 30min old // 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() let ctx = ErrorContext::new()
.with_code("compat_sso_login_expired") .with_code("compat_sso_login_expired")
.with_description("This login session expired.".to_owned()) .with_description("This login session expired.".to_owned())
@@ -174,7 +174,7 @@ pub async fn post(
.context("Could not find compat SSO login")?; .context("Could not find compat SSO login")?;
// Bail out if that login session is more than 30min old // 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() let ctx = ErrorContext::new()
.with_code("compat_sso_login_expired") .with_code("compat_sso_login_expired")
.with_description("This login session expired.".to_owned()) .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? // XXX: Is this really how we do empty scopes?
.unwrap_or(std::iter::empty::<ScopeToken>().collect()); .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 user_agent = user_agent.map(|ua| UserAgent::parse(ua.as_str().to_owned()));
let ip_address = activity_tracker.ip(); let ip_address = activity_tracker.ip();
@@ -157,7 +157,7 @@ pub(crate) async fn post(
verification_uri: url_builder.device_code_link(), verification_uri: url_builder.device_code_link(),
verification_uri_complete: Some(url_builder.device_code_link_full(device_code.user_code)), verification_uri_complete: Some(url_builder.device_code_link_full(device_code.user_code)),
expires_in, expires_in,
interval: Some(Duration::seconds(5)), interval: Some(Duration::microseconds(5 * 1000 * 1000)),
}; };
Ok(( Ok((

View File

@@ -550,7 +550,7 @@ mod tests {
&state.clock, &state.clock,
&mut repo, &mut repo,
&session, &session,
Duration::minutes(5), Duration::microseconds(5 * 60 * 1000 * 1000),
) )
.await .await
.unwrap(); .unwrap();
@@ -633,7 +633,7 @@ mod tests {
// Advance the clock to invalidate the access token // Advance the clock to invalidate the access token
let old_now = state.clock.now(); 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) let request = Request::post(OAuth2Introspection::PATH)
.basic_auth(&introspecting_client_id, &introspecting_client_secret) .basic_auth(&introspecting_client_id, &introspecting_client_secret)
@@ -808,7 +808,7 @@ mod tests {
assert!(!response.active); // It shouldn't be active assert!(!response.active); // It shouldn't be active
// Advance the clock to invalidate the access token // 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) let request = Request::post(OAuth2Introspection::PATH)
.basic_auth(&introspecting_client_id, &introspecting_client_secret) .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::SUB.insert(&mut claims, &browser_session.user.sub)?;
claims::AUD.insert(&mut claims, client.client_id.clone())?; claims::AUD.insert(&mut claims, client.client_id.clone())?;
claims::IAT.insert(&mut claims, now)?; 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()) { if let Some(nonce) = grant.and_then(|grant| grant.nonce.as_ref()) {
claims::NONCE.insert(&mut claims, nonce)?; claims::NONCE.insert(&mut claims, nonce)?;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -366,7 +366,7 @@ pub struct DeviceAuthorizationRequest {
/// The default value of the `interval` between polling requests, if it is not /// The default value of the `interval` between polling requests, if it is not
/// set. /// 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]. /// 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 /// The minimum amount of time in seconds that the client should wait
/// between polling requests to the token endpoint. /// 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>>")] #[serde_as(as = "Option<DurationSeconds<i64>>")]
pub interval: Option<Duration>, pub interval: Option<Duration>,
} }
@@ -408,11 +408,11 @@ impl DeviceAuthorizationResponse {
/// The minimum amount of time in seconds that the client should wait /// The minimum amount of time in seconds that the client should wait
/// between polling requests to the token endpoint. /// between polling requests to the token endpoint.
/// ///
/// Defaults to [`DEFAULT_DEVICE_AUTHORIZATION_INTERVAL_SECONDS`]. /// Defaults to [`DEFAULT_DEVICE_AUTHORIZATION_INTERVAL`].
#[must_use] #[must_use]
pub fn interval(&self) -> Duration { pub fn interval(&self) -> Duration {
self.interval 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::SUB.insert(&mut claims, iss)?;
claims::AUD.insert(&mut claims, aud)?; claims::AUD.insert(&mut claims, aud)?;
claims::IAT.insert(&mut claims, now)?; 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]; let mut jti = [0u8; 16];
rng.fill(&mut jti); 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::IAT.insert(&mut claims, now).unwrap();
claims::EXP claims::EXP
.insert(&mut claims, now + Duration::hours(1)) .insert(&mut claims, now + Duration::try_hours(1).unwrap())
.unwrap(); .unwrap();
claims::AT_HASH claims::AT_HASH

View File

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

View File

@@ -68,11 +68,11 @@ fn id_token(
if flag == Some(IdTokenFlag::WrongExpiration) { if flag == Some(IdTokenFlag::WrongExpiration) {
claims::EXP claims::EXP
.insert(&mut claims, now - Duration::hours(1)) .insert(&mut claims, now - Duration::try_hours(1).unwrap())
.unwrap(); .unwrap();
} else { } else {
claims::EXP claims::EXP
.insert(&mut claims, now + Duration::hours(1)) .insert(&mut claims, now + Duration::try_hours(1).unwrap())
.unwrap(); .unwrap();
} }
@@ -229,7 +229,7 @@ async fn fail_verify_id_token_wrong_auth_time() {
let issuer = "http://localhost/"; let issuer = "http://localhost/";
let now = now(); let now = now();
let (auth_id_token, _) = id_token(issuer, None, Some(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 { let verification_data = JwtVerificationData {
issuer, 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 moving the clock forward by 1 minute between each session to ensure
// we're getting consistent ordering in lists. // we're getting consistent ordering in lists.
clock.advance(Duration::minutes(1)); clock.advance(Duration::try_minutes(1).unwrap());
let oauth_session = repo let oauth_session = repo
.oauth2_session() .oauth2_session()

View File

@@ -321,7 +321,7 @@ mod tests {
&clock, &clock,
&session, &session,
FIRST_TOKEN.to_owned(), FIRST_TOKEN.to_owned(),
Some(Duration::minutes(1)), Some(Duration::try_minutes(1).unwrap()),
) )
.await .await
.unwrap(); .unwrap();
@@ -341,7 +341,7 @@ mod tests {
&clock, &clock,
&session, &session,
FIRST_TOKEN.to_owned(), FIRST_TOKEN.to_owned(),
Some(Duration::minutes(1)), Some(Duration::try_minutes(1).unwrap()),
) )
.await .await
.is_err()); .is_err());
@@ -374,7 +374,7 @@ mod tests {
// Token is currently valid // Token is currently valid
assert!(token.is_valid(clock.now())); assert!(token.is_valid(clock.now()));
clock.advance(Duration::minutes(1)); clock.advance(Duration::try_minutes(1).unwrap());
// Token should have expired // Token should have expired
assert!(!token.is_valid(clock.now())); 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> { async fn cleanup_expired(&mut self, clock: &dyn Clock) -> Result<usize, Self::Error> {
// Cleanup token which expired more than 15 minutes ago // 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!( let res = sqlx::query!(
r#" r#"
DELETE FROM oauth2_access_tokens DELETE FROM oauth2_access_tokens

View File

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

View File

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

View File

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

View File

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

View File

@@ -69,7 +69,13 @@ async fn verify_email(
// Save the verification code in the database // Save the verification code in the database
let verification = repo let verification = repo
.user_email() .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?; .await?;
// And send the verification email // And send the verification email

View File

@@ -337,7 +337,7 @@ where
.as_secs() .as_secs()
.try_into() .try_into()
.map_err(|e| StorageError::Database(Box::new(e)))?; .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? // TODO: should we use a clock here?
#[allow(clippy::disallowed_methods)] #[allow(clippy::disallowed_methods)]
let run_at = Utc::now().add(wait); let run_at = Utc::now().add(wait);

View File

@@ -626,8 +626,8 @@ impl TemplateContext for PolicyViolationContext {
scope: [OPENID].into_iter().collect(), scope: [OPENID].into_iter().collect(),
user_code: Alphanumeric.sample_string(rng, 6).to_uppercase(), user_code: Alphanumeric.sample_string(rng, 6).to_uppercase(),
device_code: Alphanumeric.sample_string(rng, 32), device_code: Alphanumeric.sample_string(rng, 32),
created_at: now - Duration::minutes(5), created_at: now - Duration::try_minutes(5).unwrap(),
expires_at: now + Duration::minutes(25), expires_at: now + Duration::try_minutes(25).unwrap(),
ip_address: None, ip_address: None,
user_agent: None, user_agent: None,
}, },
@@ -1161,8 +1161,8 @@ impl TemplateContext for DeviceConsentContext {
scope: [OPENID].into_iter().collect(), scope: [OPENID].into_iter().collect(),
user_code: Alphanumeric.sample_string(rng, 6).to_uppercase(), user_code: Alphanumeric.sample_string(rng, 6).to_uppercase(),
device_code: Alphanumeric.sample_string(rng, 32), device_code: Alphanumeric.sample_string(rng, 32),
created_at: now - Duration::minutes(5), created_at: now - Duration::try_minutes(5).unwrap(),
expires_at: now + Duration::minutes(25), expires_at: now + Duration::try_minutes(25).unwrap(),
ip_address: Some(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))), 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())), 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())),
}; };