From 1e4275518757ce2f5945c0907be8be62ea9a09b0 Mon Sep 17 00:00:00 2001 From: Mathijs van Veluw Date: Tue, 19 Mar 2024 19:47:30 +0100 Subject: [PATCH] Update chrono and sqlite (#4436) - Updated sqlite crate - Updated chrono crate The latter needed a lot of changes done, mostly `Duration` to `TimeDelta`. And some changes on how to use Naive. --- Cargo.lock | 8 ++--- Cargo.toml | 4 +-- src/api/core/accounts.rs | 2 +- src/api/core/emergency_access.rs | 8 ++--- src/api/core/public.rs | 2 +- src/api/core/sends.rs | 6 ++-- src/api/core/two_factor/email.rs | 10 +++--- src/api/core/two_factor/mod.rs | 4 +-- src/api/core/two_factor/protected_actions.rs | 8 ++--- src/api/notifications.rs | 2 +- src/auth.rs | 38 ++++++++++---------- src/db/models/auth_request.rs | 2 +- src/db/models/cipher.rs | 4 +-- src/db/models/device.rs | 4 +-- src/db/models/event.rs | 4 +-- src/db/models/user.rs | 4 +-- src/util.rs | 2 +- 17 files changed, 56 insertions(+), 56 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b83eb071..bf8c7675 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -533,9 +533,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.34" +version = "0.4.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b" +checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a" dependencies = [ "android-tzdata", "iana-time-zone", @@ -1714,9 +1714,9 @@ dependencies = [ [[package]] name = "libsqlite3-sys" -version = "0.27.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716" +checksum = "0c10584274047cb335c23d3e61bcef8e323adae7c5c8c760540f73610177fc3f" dependencies = [ "cc", "pkg-config", diff --git a/Cargo.toml b/Cargo.toml index 26916626..4fe555b6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -79,7 +79,7 @@ diesel_migrations = "2.1.0" diesel_logger = { version = "0.3.0", optional = true } # Bundled/Static SQLite -libsqlite3-sys = { version = "0.27.0", features = ["bundled"], optional = true } +libsqlite3-sys = { version = "0.28.0", features = ["bundled"], optional = true } # Crypto-related libraries rand = { version = "0.8.5", features = ["small_rng"] } @@ -89,7 +89,7 @@ ring = "0.17.8" uuid = { version = "1.7.0", features = ["v4"] } # Date and time libraries -chrono = { version = "0.4.34", features = ["clock", "serde"], default-features = false } +chrono = { version = "0.4.35", features = ["clock", "serde"], default-features = false } chrono-tz = "0.8.6" time = "0.3.34" diff --git a/src/api/core/accounts.rs b/src/api/core/accounts.rs index a97c4c31..da25d488 100644 --- a/src/api/core/accounts.rs +++ b/src/api/core/accounts.rs @@ -773,7 +773,7 @@ async fn delete_account(data: JsonUpcase, headers: Headers, m #[get("/accounts/revision-date")] fn revision_date(headers: Headers) -> JsonResult { - let revision_date = headers.user.updated_at.timestamp_millis(); + let revision_date = headers.user.updated_at.and_utc().timestamp_millis(); Ok(Json(json!(revision_date))) } diff --git a/src/api/core/emergency_access.rs b/src/api/core/emergency_access.rs index fb163849..5f64cde0 100644 --- a/src/api/core/emergency_access.rs +++ b/src/api/core/emergency_access.rs @@ -1,4 +1,4 @@ -use chrono::{Duration, Utc}; +use chrono::{TimeDelta, Utc}; use rocket::{serde::json::Json, Route}; use serde_json::Value; @@ -766,7 +766,7 @@ pub async fn emergency_request_timeout_job(pool: DbPool) { for mut emer in emergency_access_list { // The find_all_recoveries_initiated already checks if the recovery_initiated_at is not null (None) let recovery_allowed_at = - emer.recovery_initiated_at.unwrap() + Duration::days(i64::from(emer.wait_time_days)); + emer.recovery_initiated_at.unwrap() + TimeDelta::try_days(i64::from(emer.wait_time_days)).unwrap(); if recovery_allowed_at.le(&now) { // Only update the access status // Updating the whole record could cause issues when the emergency_notification_reminder_job is also active @@ -822,10 +822,10 @@ pub async fn emergency_notification_reminder_job(pool: DbPool) { // The find_all_recoveries_initiated already checks if the recovery_initiated_at is not null (None) // Calculate the day before the recovery will become active let final_recovery_reminder_at = - emer.recovery_initiated_at.unwrap() + Duration::days(i64::from(emer.wait_time_days - 1)); + emer.recovery_initiated_at.unwrap() + TimeDelta::try_days(i64::from(emer.wait_time_days - 1)).unwrap(); // Calculate if a day has passed since the previous notification, else no notification has been sent before let next_recovery_reminder_at = if let Some(last_notification_at) = emer.last_notification_at { - last_notification_at + Duration::days(1) + last_notification_at + TimeDelta::try_days(1).unwrap() } else { now }; diff --git a/src/api/core/public.rs b/src/api/core/public.rs index 74f79a3e..085ac552 100644 --- a/src/api/core/public.rs +++ b/src/api/core/public.rs @@ -209,7 +209,7 @@ impl<'r> FromRequest<'r> for PublicToken { Err(_) => err_handler!("Invalid claim"), }; // Check if time is between claims.nbf and claims.exp - let time_now = Utc::now().naive_utc().timestamp(); + let time_now = Utc::now().timestamp(); if time_now < claims.nbf { err_handler!("Token issued in the future"); } diff --git a/src/api/core/sends.rs b/src/api/core/sends.rs index 1bc6d00f..6842d398 100644 --- a/src/api/core/sends.rs +++ b/src/api/core/sends.rs @@ -1,6 +1,6 @@ use std::path::Path; -use chrono::{DateTime, Duration, Utc}; +use chrono::{DateTime, TimeDelta, Utc}; use num_traits::ToPrimitive; use rocket::form::Form; use rocket::fs::NamedFile; @@ -119,7 +119,7 @@ fn create_send(data: SendData, user_uuid: String) -> ApiResult { err!("Send data not provided"); }; - if data.DeletionDate > Utc::now() + Duration::days(31) { + if data.DeletionDate > Utc::now() + TimeDelta::try_days(31).unwrap() { err!( "You cannot have a Send with a deletion date that far into the future. Adjust the Deletion Date to a value less than 31 days from now and try again." ); @@ -569,7 +569,7 @@ async fn put_send( send.data = data_str; } - if data.DeletionDate > Utc::now() + Duration::days(31) { + if data.DeletionDate > Utc::now() + TimeDelta::try_days(31).unwrap() { err!( "You cannot have a Send with a deletion date that far into the future. Adjust the Deletion Date to a value less than 31 days from now and try again." ); diff --git a/src/api/core/two_factor/email.rs b/src/api/core/two_factor/email.rs index 582265b1..62344cf8 100644 --- a/src/api/core/two_factor/email.rs +++ b/src/api/core/two_factor/email.rs @@ -1,4 +1,4 @@ -use chrono::{Duration, NaiveDateTime, Utc}; +use chrono::{DateTime, TimeDelta, Utc}; use rocket::serde::json::Json; use rocket::Route; @@ -232,9 +232,9 @@ pub async fn validate_email_code_str(user_uuid: &str, token: &str, data: &str, c twofactor.data = email_data.to_json(); twofactor.save(conn).await?; - let date = NaiveDateTime::from_timestamp_opt(email_data.token_sent, 0).expect("Email token timestamp invalid."); + let date = DateTime::from_timestamp(email_data.token_sent, 0).expect("Email token timestamp invalid.").naive_utc(); let max_time = CONFIG.email_expiration_time() as i64; - if date + Duration::seconds(max_time) < Utc::now().naive_utc() { + if date + TimeDelta::try_seconds(max_time).unwrap() < Utc::now().naive_utc() { err!( "Token has expired", ErrorEvent { @@ -265,14 +265,14 @@ impl EmailTokenData { EmailTokenData { email, last_token: Some(token), - token_sent: Utc::now().naive_utc().timestamp(), + token_sent: Utc::now().timestamp(), attempts: 0, } } pub fn set_token(&mut self, token: String) { self.last_token = Some(token); - self.token_sent = Utc::now().naive_utc().timestamp(); + self.token_sent = Utc::now().timestamp(); } pub fn reset_token(&mut self) { diff --git a/src/api/core/two_factor/mod.rs b/src/api/core/two_factor/mod.rs index a40c23e6..8c0d6764 100644 --- a/src/api/core/two_factor/mod.rs +++ b/src/api/core/two_factor/mod.rs @@ -1,4 +1,4 @@ -use chrono::{Duration, Utc}; +use chrono::{TimeDelta, Utc}; use data_encoding::BASE32; use rocket::serde::json::Json; use rocket::Route; @@ -259,7 +259,7 @@ pub async fn send_incomplete_2fa_notifications(pool: DbPool) { }; let now = Utc::now().naive_utc(); - let time_limit = Duration::minutes(CONFIG.incomplete_2fa_time_limit()); + let time_limit = TimeDelta::try_minutes(CONFIG.incomplete_2fa_time_limit()).unwrap(); let time_before = now - time_limit; let incomplete_logins = TwoFactorIncomplete::find_logins_before(&time_before, &mut conn).await; for login in incomplete_logins { diff --git a/src/api/core/two_factor/protected_actions.rs b/src/api/core/two_factor/protected_actions.rs index 09c7ede0..537ed0c6 100644 --- a/src/api/core/two_factor/protected_actions.rs +++ b/src/api/core/two_factor/protected_actions.rs @@ -1,4 +1,4 @@ -use chrono::{Duration, NaiveDateTime, Utc}; +use chrono::{DateTime, TimeDelta, Utc}; use rocket::Route; use crate::{ @@ -32,7 +32,7 @@ impl ProtectedActionData { pub fn new(token: String) -> Self { Self { token, - token_sent: Utc::now().naive_utc().timestamp(), + token_sent: Utc::now().timestamp(), attempts: 0, } } @@ -122,9 +122,9 @@ pub async fn validate_protected_action_otp( // Check if the token has expired (Using the email 2fa expiration time) let date = - NaiveDateTime::from_timestamp_opt(pa_data.token_sent, 0).expect("Protected Action token timestamp invalid."); + DateTime::from_timestamp(pa_data.token_sent, 0).expect("Protected Action token timestamp invalid.").naive_utc(); let max_time = CONFIG.email_expiration_time() as i64; - if date + Duration::seconds(max_time) < Utc::now().naive_utc() { + if date + TimeDelta::try_seconds(max_time).unwrap() < Utc::now().naive_utc() { pa.delete(conn).await?; err!("Token has expired") } diff --git a/src/api/notifications.rs b/src/api/notifications.rs index 1f64b86e..7a1aa2ac 100644 --- a/src/api/notifications.rs +++ b/src/api/notifications.rs @@ -288,7 +288,7 @@ fn serialize(val: Value) -> Vec { } fn serialize_date(date: NaiveDateTime) -> Value { - let seconds: i64 = date.timestamp(); + let seconds: i64 = date.and_utc().timestamp(); let nanos: i64 = date.timestamp_subsec_nanos().into(); let timestamp = nanos << 34 | seconds; diff --git a/src/auth.rs b/src/auth.rs index 7eabbc1e..36e84613 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -1,6 +1,6 @@ // JWT Handling // -use chrono::{Duration, Utc}; +use chrono::{TimeDelta, Utc}; use num_traits::FromPrimitive; use once_cell::sync::{Lazy, OnceCell}; @@ -13,7 +13,7 @@ use crate::{error::Error, CONFIG}; const JWT_ALGORITHM: Algorithm = Algorithm::RS256; -pub static DEFAULT_VALIDITY: Lazy = Lazy::new(|| Duration::hours(2)); +pub static DEFAULT_VALIDITY: Lazy = Lazy::new(|| TimeDelta::try_hours(2).unwrap()); static JWT_HEADER: Lazy
= Lazy::new(|| Header::new(JWT_ALGORITHM)); pub static JWT_LOGIN_ISSUER: Lazy = Lazy::new(|| format!("{}|login", CONFIG.domain_origin())); @@ -187,11 +187,11 @@ pub fn generate_invite_claims( user_org_id: Option, invited_by_email: Option, ) -> InviteJwtClaims { - let time_now = Utc::now().naive_utc(); + let time_now = Utc::now(); let expire_hours = i64::from(CONFIG.invitation_expiration_hours()); InviteJwtClaims { nbf: time_now.timestamp(), - exp: (time_now + Duration::hours(expire_hours)).timestamp(), + exp: (time_now + TimeDelta::try_hours(expire_hours).unwrap()).timestamp(), iss: JWT_INVITE_ISSUER.to_string(), sub: uuid, email, @@ -225,11 +225,11 @@ pub fn generate_emergency_access_invite_claims( grantor_name: String, grantor_email: String, ) -> EmergencyAccessInviteJwtClaims { - let time_now = Utc::now().naive_utc(); + let time_now = Utc::now(); let expire_hours = i64::from(CONFIG.invitation_expiration_hours()); EmergencyAccessInviteJwtClaims { nbf: time_now.timestamp(), - exp: (time_now + Duration::hours(expire_hours)).timestamp(), + exp: (time_now + TimeDelta::try_hours(expire_hours).unwrap()).timestamp(), iss: JWT_EMERGENCY_ACCESS_INVITE_ISSUER.to_string(), sub: uuid, email, @@ -256,10 +256,10 @@ pub struct OrgApiKeyLoginJwtClaims { } pub fn generate_organization_api_key_login_claims(uuid: String, org_id: String) -> OrgApiKeyLoginJwtClaims { - let time_now = Utc::now().naive_utc(); + let time_now = Utc::now(); OrgApiKeyLoginJwtClaims { nbf: time_now.timestamp(), - exp: (time_now + Duration::hours(1)).timestamp(), + exp: (time_now + TimeDelta::try_hours(1).unwrap()).timestamp(), iss: JWT_ORG_API_KEY_ISSUER.to_string(), sub: uuid, client_id: format!("organization.{org_id}"), @@ -283,10 +283,10 @@ pub struct FileDownloadClaims { } pub fn generate_file_download_claims(uuid: String, file_id: String) -> FileDownloadClaims { - let time_now = Utc::now().naive_utc(); + let time_now = Utc::now(); FileDownloadClaims { nbf: time_now.timestamp(), - exp: (time_now + Duration::minutes(5)).timestamp(), + exp: (time_now + TimeDelta::try_minutes(5).unwrap()).timestamp(), iss: JWT_FILE_DOWNLOAD_ISSUER.to_string(), sub: uuid, file_id, @@ -306,42 +306,42 @@ pub struct BasicJwtClaims { } pub fn generate_delete_claims(uuid: String) -> BasicJwtClaims { - let time_now = Utc::now().naive_utc(); + let time_now = Utc::now(); let expire_hours = i64::from(CONFIG.invitation_expiration_hours()); BasicJwtClaims { nbf: time_now.timestamp(), - exp: (time_now + Duration::hours(expire_hours)).timestamp(), + exp: (time_now + TimeDelta::try_hours(expire_hours).unwrap()).timestamp(), iss: JWT_DELETE_ISSUER.to_string(), sub: uuid, } } pub fn generate_verify_email_claims(uuid: String) -> BasicJwtClaims { - let time_now = Utc::now().naive_utc(); + let time_now = Utc::now(); let expire_hours = i64::from(CONFIG.invitation_expiration_hours()); BasicJwtClaims { nbf: time_now.timestamp(), - exp: (time_now + Duration::hours(expire_hours)).timestamp(), + exp: (time_now + TimeDelta::try_hours(expire_hours).unwrap()).timestamp(), iss: JWT_VERIFYEMAIL_ISSUER.to_string(), sub: uuid, } } pub fn generate_admin_claims() -> BasicJwtClaims { - let time_now = Utc::now().naive_utc(); + let time_now = Utc::now(); BasicJwtClaims { nbf: time_now.timestamp(), - exp: (time_now + Duration::minutes(CONFIG.admin_session_lifetime())).timestamp(), + exp: (time_now + TimeDelta::try_minutes(CONFIG.admin_session_lifetime()).unwrap()).timestamp(), iss: JWT_ADMIN_ISSUER.to_string(), sub: "admin_panel".to_string(), } } pub fn generate_send_claims(send_id: &str, file_id: &str) -> BasicJwtClaims { - let time_now = Utc::now().naive_utc(); + let time_now = Utc::now(); BasicJwtClaims { nbf: time_now.timestamp(), - exp: (time_now + Duration::minutes(2)).timestamp(), + exp: (time_now + TimeDelta::try_minutes(2).unwrap()).timestamp(), iss: JWT_SEND_ISSUER.to_string(), sub: format!("{send_id}/{file_id}"), } @@ -498,7 +498,7 @@ impl<'r> FromRequest<'r> for Headers { // Check if the stamp exception has expired first. // Then, check if the current route matches any of the allowed routes. // After that check the stamp in exception matches the one in the claims. - if Utc::now().naive_utc().timestamp() > stamp_exception.expire { + if Utc::now().timestamp() > stamp_exception.expire { // If the stamp exception has been expired remove it from the database. // This prevents checking this stamp exception for new requests. let mut user = user; diff --git a/src/db/models/auth_request.rs b/src/db/models/auth_request.rs index 2a004fb1..9388c71a 100644 --- a/src/db/models/auth_request.rs +++ b/src/db/models/auth_request.rs @@ -140,7 +140,7 @@ impl AuthRequest { } pub async fn purge_expired_auth_requests(conn: &mut DbConn) { - let expiry_time = Utc::now().naive_utc() - chrono::Duration::minutes(5); //after 5 minutes, clients reject the request + let expiry_time = Utc::now().naive_utc() - chrono::TimeDelta::try_minutes(5).unwrap(); //after 5 minutes, clients reject the request for auth_request in Self::find_created_before(&expiry_time, conn).await { auth_request.delete(conn).await.ok(); } diff --git a/src/db/models/cipher.rs b/src/db/models/cipher.rs index 61683d85..0574a833 100644 --- a/src/db/models/cipher.rs +++ b/src/db/models/cipher.rs @@ -1,5 +1,5 @@ use crate::CONFIG; -use chrono::{Duration, NaiveDateTime, Utc}; +use chrono::{NaiveDateTime, TimeDelta, Utc}; use serde_json::Value; use super::{ @@ -361,7 +361,7 @@ impl Cipher { pub async fn purge_trash(conn: &mut DbConn) { if let Some(auto_delete_days) = CONFIG.trash_auto_delete_days() { let now = Utc::now().naive_utc(); - let dt = now - Duration::days(auto_delete_days); + let dt = now - TimeDelta::try_days(auto_delete_days).unwrap(); for cipher in Self::find_deleted_before(&dt, conn).await { cipher.delete(conn).await.ok(); } diff --git a/src/db/models/device.rs b/src/db/models/device.rs index de612e69..60c63589 100644 --- a/src/db/models/device.rs +++ b/src/db/models/device.rs @@ -67,8 +67,8 @@ impl Device { } // Update the expiration of the device and the last update date - let time_now = Utc::now().naive_utc(); - self.updated_at = time_now; + let time_now = Utc::now(); + self.updated_at = time_now.naive_utc(); // --- // Disabled these keys to be added to the JWT since they could cause the JWT to get too large diff --git a/src/db/models/event.rs b/src/db/models/event.rs index af2f6c66..22d8fb00 100644 --- a/src/db/models/event.rs +++ b/src/db/models/event.rs @@ -3,7 +3,7 @@ use serde_json::Value; use crate::{api::EmptyResult, error::MapResult, CONFIG}; -use chrono::{Duration, NaiveDateTime, Utc}; +use chrono::{NaiveDateTime, TimeDelta, Utc}; // https://bitwarden.com/help/event-logs/ @@ -316,7 +316,7 @@ impl Event { pub async fn clean_events(conn: &mut DbConn) -> EmptyResult { if let Some(days_to_retain) = CONFIG.events_days_retain() { - let dt = Utc::now().naive_utc() - Duration::days(days_to_retain); + let dt = Utc::now().naive_utc() - TimeDelta::try_days(days_to_retain).unwrap(); db_run! { conn: { diesel::delete(event::table.filter(event::event_date.lt(dt))) .execute(conn) diff --git a/src/db/models/user.rs b/src/db/models/user.rs index 1475d637..feb09438 100644 --- a/src/db/models/user.rs +++ b/src/db/models/user.rs @@ -1,4 +1,4 @@ -use chrono::{Duration, NaiveDateTime, Utc}; +use chrono::{NaiveDateTime, TimeDelta, Utc}; use serde_json::Value; use crate::crypto; @@ -202,7 +202,7 @@ impl User { let stamp_exception = UserStampException { routes: route_exception, security_stamp: self.security_stamp.clone(), - expire: (Utc::now().naive_utc() + Duration::minutes(2)).timestamp(), + expire: (Utc::now() + TimeDelta::try_minutes(2).unwrap()).timestamp(), }; self.stamp_exception = Some(serde_json::to_string(&stamp_exception).unwrap_or_default()); } diff --git a/src/util.rs b/src/util.rs index 2f04fe34..ed730cb7 100644 --- a/src/util.rs +++ b/src/util.rs @@ -214,7 +214,7 @@ impl<'r, R: 'r + Responder<'r, 'static> + Send> Responder<'r, 'static> for Cache res.set_raw_header("Cache-Control", cache_control_header); let time_now = chrono::Local::now(); - let expiry_time = time_now + chrono::Duration::seconds(self.ttl.try_into().unwrap()); + let expiry_time = time_now + chrono::TimeDelta::try_seconds(self.ttl.try_into().unwrap()).unwrap(); res.set_raw_header("Expires", format_datetime_http(&expiry_time)); Ok(res) }