From af5b795bb03ac076d68d3f5df2250e34c773d3e5 Mon Sep 17 00:00:00 2001 From: BlackDex Date: Fri, 8 May 2026 17:16:47 +0200 Subject: [PATCH] Reorder and merge imports Signed-off-by: BlackDex --- rustfmt.toml | 2 +- src/api/core/accounts.rs | 20 +++++------ src/api/core/ciphers.rs | 8 ++--- src/api/core/mod.rs | 40 +++++++++++----------- src/api/core/organizations.rs | 10 +++--- src/api/core/public.rs | 4 +-- src/api/core/two_factor/authenticator.rs | 3 +- src/api/core/two_factor/duo.rs | 3 +- src/api/core/two_factor/duo_oidc.rs | 5 +-- src/api/core/two_factor/email.rs | 3 +- src/api/core/two_factor/mod.rs | 3 +- src/api/core/two_factor/webauthn.rs | 31 ++++++++--------- src/api/core/two_factor/yubikey.rs | 3 +- src/api/mod.rs | 10 +++--- src/api/notifications.rs | 10 +++--- src/api/web.rs | 6 ++-- src/auth.rs | 36 ++++++++++---------- src/db/mod.rs | 2 -- src/db/models/archive.rs | 10 +++--- src/db/models/attachment.rs | 25 ++++++++------ src/db/models/auth_request.rs | 20 ++++++----- src/db/models/cipher.rs | 35 +++++++++++--------- src/db/models/collection.rs | 26 ++++++++------- src/db/models/device.rs | 14 ++++---- src/db/models/emergency_access.rs | 12 ++++--- src/db/models/event.rs | 15 ++++++--- src/db/models/favorite.rs | 15 +++++---- src/db/models/folder.rs | 19 ++++++----- src/db/models/group.rs | 18 ++++++---- src/db/models/org_policy.rs | 17 ++++++---- src/db/models/organization.rs | 42 +++++++++++++----------- src/db/models/send.rs | 29 +++++++--------- src/db/models/sso_auth.rs | 25 +++++++------- src/db/models/two_factor.rs | 12 ++++--- src/db/models/two_factor_duo_context.rs | 9 +++-- src/db/models/two_factor_incomplete.rs | 4 +-- src/db/models/user.rs | 14 +++++--- src/db/query_logger.rs | 3 +- src/error.rs | 11 ++++--- src/mail.rs | 9 ++--- src/main.rs | 11 ++++--- src/util.rs | 30 ++++++----------- 42 files changed, 329 insertions(+), 295 deletions(-) diff --git a/rustfmt.toml b/rustfmt.toml index 1d5e440f..a00d27e0 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,4 +1,4 @@ -edition = "2021" +edition = "2024" max_width = 120 newline_style = "Unix" use_small_heuristics = "Off" diff --git a/src/api/core/accounts.rs b/src/api/core/accounts.rs index f2852e5c..954b35bd 100644 --- a/src/api/core/accounts.rs +++ b/src/api/core/accounts.rs @@ -1,7 +1,11 @@ use std::collections::HashSet; -use crate::db::DbPool; use chrono::Utc; +use rocket::{ + http::Status, + request::{FromRequest, Outcome, Request}, + serde::json::Json, +}; use serde_json::Value; use crate::{ @@ -14,7 +18,7 @@ use crate::{ auth::{ClientHeaders, Headers, decode_delete, decode_invite, decode_verify_email}, crypto, db::{ - DbConn, + DbConn, DbPool, models::{ AuthRequest, AuthRequestId, Cipher, CipherId, Device, DeviceId, DeviceType, DeviceWithAuthRequest, EmergencyAccess, EmergencyAccessId, EventType, Folder, FolderId, Invitation, Membership, MembershipId, @@ -25,13 +29,9 @@ use crate::{ util::{NumberOrString, deser_opt_nonempty_str, format_date}, }; -use super::ciphers::{CipherData, update_cipher_from_data}; -use super::sends::{SendData, update_send_from_data}; - -use rocket::{ - http::Status, - request::{FromRequest, Outcome, Request}, - serde::json::Json, +use super::{ + ciphers::{CipherData, update_cipher_from_data}, + sends::{SendData, update_send_from_data}, }; pub fn routes() -> Vec { @@ -1282,8 +1282,6 @@ async fn verify_password(data: Json, headers: Headers } async fn update_api_key(data: Json, rotate: bool, headers: Headers, conn: DbConn) -> JsonResult { - use crate::util::format_date; - let data: PasswordOrOtpData = data.into_inner(); let mut user = headers.user; diff --git a/src/api/core/ciphers.rs b/src/api/core/ciphers.rs index 7e6a34fa..6b9994cf 100644 --- a/src/api/core/ciphers.rs +++ b/src/api/core/ciphers.rs @@ -2,19 +2,18 @@ use std::collections::{HashMap, HashSet}; use chrono::{NaiveDateTime, Utc}; use num_traits::ToPrimitive; -use rocket::fs::TempFile; -use rocket::serde::json::Json; use rocket::{ Route, form::{Form, FromForm}, + fs::TempFile, + serde::json::Json, }; use serde_json::Value; -use crate::auth::ClientVersion; -use crate::util::{NumberOrString, deser_opt_nonempty_str, save_temp_file}; use crate::{ CONFIG, api::{self, EmptyResult, JsonResult, Notify, PasswordOrOtpData, UpdateType, core::log_event}, + auth::ClientVersion, auth::{Headers, OrgIdGuard, OwnerHeaders}, config::PathType, crypto, @@ -26,6 +25,7 @@ use crate::{ MembershipType, OrgPolicy, OrgPolicyType, OrganizationId, RepromptType, Send, UserId, }, }, + util::{NumberOrString, deser_opt_nonempty_str, save_temp_file}, }; use super::folders::FolderData; diff --git a/src/api/core/mod.rs b/src/api/core/mod.rs index 178d7c45..2ea8ab21 100644 --- a/src/api/core/mod.rs +++ b/src/api/core/mod.rs @@ -1,4 +1,6 @@ pub mod accounts; +pub mod two_factor; + mod ciphers; mod emergency_access; mod events; @@ -6,15 +8,30 @@ mod folders; mod organizations; mod public; mod sends; -pub mod two_factor; pub use accounts::purge_auth_requests; pub use ciphers::{CipherData, CipherSyncData, CipherSyncType, purge_trashed_ciphers}; pub use emergency_access::{emergency_notification_reminder_job, emergency_request_timeout_job}; pub use events::{event_cleanup_job, log_event, log_user_event}; -use reqwest::Method; pub use sends::purge_sends; +use reqwest::Method; +use rocket::{Catcher, Route, serde::json::Json, serde::json::Value}; + +use crate::{ + CONFIG, + api::{EmptyResult, JsonResult, Notify, UpdateType}, + auth::Headers, + db::{ + DbConn, + models::{Membership, MembershipStatus, OrgPolicy, Organization, User}, + }, + error::Error, + http_client::make_http_request, + mail, + util::{FeatureFlagFilter, parse_experimental_client_feature_flags}, +}; + pub fn routes() -> Vec { let mut eq_domains_routes = routes![get_settings_domains, post_settings_domains, put_settings_domains]; let mut hibp_routes = routes![hibp_breach]; @@ -44,25 +61,6 @@ pub fn events_routes() -> Vec { routes } -// -// Move this somewhere else -// -use rocket::{Catcher, Route, serde::json::Json, serde::json::Value}; - -use crate::{ - CONFIG, - api::{EmptyResult, JsonResult, Notify, UpdateType}, - auth::Headers, - db::{ - DbConn, - models::{Membership, MembershipStatus, OrgPolicy, Organization, User}, - }, - error::Error, - http_client::make_http_request, - mail, - util::{FeatureFlagFilter, parse_experimental_client_feature_flags}, -}; - #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] struct GlobalDomain { diff --git a/src/api/core/organizations.rs b/src/api/core/organizations.rs index 50de218b..13688531 100644 --- a/src/api/core/organizations.rs +++ b/src/api/core/organizations.rs @@ -1,12 +1,12 @@ -use num_traits::FromPrimitive; -use rocket::Route; -use rocket::serde::json::Json; -use serde_json::Value; use std::collections::{HashMap, HashSet}; -use crate::api::admin::FAKE_ADMIN_UUID; +use num_traits::FromPrimitive; +use rocket::{Route, serde::json::Json}; +use serde_json::Value; + use crate::{ CONFIG, + api::admin::FAKE_ADMIN_UUID, api::{ EmptyResult, JsonResult, Notify, PasswordOrOtpData, UpdateType, core::{CipherSyncData, CipherSyncType, accept_org_invite, log_event, two_factor}, diff --git a/src/api/core/public.rs b/src/api/core/public.rs index f50b2543..33189e78 100644 --- a/src/api/core/public.rs +++ b/src/api/core/public.rs @@ -1,3 +1,5 @@ +use std::collections::HashSet; + use chrono::Utc; use rocket::{ Request, Route, @@ -5,8 +7,6 @@ use rocket::{ serde::json::Json, }; -use std::collections::HashSet; - use crate::{ CONFIG, api::EmptyResult, diff --git a/src/api/core/two_factor/authenticator.rs b/src/api/core/two_factor/authenticator.rs index 44cd7427..692e8248 100644 --- a/src/api/core/two_factor/authenticator.rs +++ b/src/api/core/two_factor/authenticator.rs @@ -1,6 +1,5 @@ use data_encoding::BASE32; -use rocket::Route; -use rocket::serde::json::Json; +use rocket::{Route, serde::json::Json}; use crate::{ api::{EmptyResult, JsonResult, PasswordOrOtpData, core::log_user_event, core::two_factor::generate_recover_code}, diff --git a/src/api/core/two_factor/duo.rs b/src/api/core/two_factor/duo.rs index 512de9c1..ed112eb9 100644 --- a/src/api/core/two_factor/duo.rs +++ b/src/api/core/two_factor/duo.rs @@ -1,7 +1,6 @@ use chrono::Utc; use data_encoding::BASE64; -use rocket::Route; -use rocket::serde::json::Json; +use rocket::{Route, serde::json::Json}; use crate::{ CONFIG, diff --git a/src/api/core/two_factor/duo_oidc.rs b/src/api/core/two_factor/duo_oidc.rs index 560e6f65..adb030af 100644 --- a/src/api/core/two_factor/duo_oidc.rs +++ b/src/api/core/two_factor/duo_oidc.rs @@ -1,10 +1,12 @@ +use std::collections::HashMap; + use chrono::Utc; use data_encoding::HEXLOWER; use jsonwebtoken::{Algorithm, DecodingKey, EncodingKey, Header, Validation}; use reqwest::{StatusCode, header}; use ring::digest::{Digest, SHA512_256, digest}; use serde::Serialize; -use std::collections::HashMap; +use url::Url; use crate::{ CONFIG, @@ -17,7 +19,6 @@ use crate::{ error::Error, http_client::make_http_request, }; -use url::Url; // The location on this service that Duo should redirect users to. For us, this is a bridge // built in to the Bitwarden clients. diff --git a/src/api/core/two_factor/email.rs b/src/api/core/two_factor/email.rs index a48a2bcd..464383d4 100644 --- a/src/api/core/two_factor/email.rs +++ b/src/api/core/two_factor/email.rs @@ -1,6 +1,5 @@ use chrono::{DateTime, TimeDelta, Utc}; -use rocket::Route; -use rocket::serde::json::Json; +use rocket::{Route, serde::json::Json}; use crate::{ CONFIG, diff --git a/src/api/core/two_factor/mod.rs b/src/api/core/two_factor/mod.rs index bf4e2282..8869d23d 100644 --- a/src/api/core/two_factor/mod.rs +++ b/src/api/core/two_factor/mod.rs @@ -1,8 +1,7 @@ use chrono::{TimeDelta, Utc}; use data_encoding::BASE32; use num_traits::FromPrimitive; -use rocket::Route; -use rocket::serde::json::Json; +use rocket::{Route, serde::json::Json}; use serde::Deserialize; use serde_json::Value; diff --git a/src/api/core/two_factor/webauthn.rs b/src/api/core/two_factor/webauthn.rs index ddcdc75a..07b964e5 100644 --- a/src/api/core/two_factor/webauthn.rs +++ b/src/api/core/two_factor/webauthn.rs @@ -1,3 +1,19 @@ +use std::{str::FromStr, sync::LazyLock, time::Duration}; + +use rocket::{Route, serde::json::Json}; +use serde_json::Value; +use url::Url; +use uuid::Uuid; +use webauthn_rs::{ + Webauthn, WebauthnBuilder, + prelude::{Base64UrlSafeData, Credential, Passkey, PasskeyAuthentication, PasskeyRegistration}, +}; +use webauthn_rs_proto::{ + AuthenticationExtensionsClientOutputs, AuthenticatorAssertionResponseRaw, AuthenticatorAttestationResponseRaw, + PublicKeyCredential, RegisterPublicKeyCredential, RegistrationExtensionsClientOutputs, + RequestAuthenticationExtensions, UserVerificationPolicy, +}; + use crate::{ CONFIG, api::{ @@ -13,21 +29,6 @@ use crate::{ error::Error, util::NumberOrString, }; -use rocket::Route; -use rocket::serde::json::Json; -use serde_json::Value; -use std::str::FromStr; -use std::sync::LazyLock; -use std::time::Duration; -use url::Url; -use uuid::Uuid; -use webauthn_rs::prelude::{Base64UrlSafeData, Credential, Passkey, PasskeyAuthentication, PasskeyRegistration}; -use webauthn_rs::{Webauthn, WebauthnBuilder}; -use webauthn_rs_proto::{ - AuthenticationExtensionsClientOutputs, AuthenticatorAssertionResponseRaw, AuthenticatorAttestationResponseRaw, - PublicKeyCredential, RegisterPublicKeyCredential, RegistrationExtensionsClientOutputs, - RequestAuthenticationExtensions, UserVerificationPolicy, -}; static WEBAUTHN: LazyLock = LazyLock::new(|| { let domain = CONFIG.domain(); diff --git a/src/api/core/two_factor/yubikey.rs b/src/api/core/two_factor/yubikey.rs index 7412371d..08e8d269 100644 --- a/src/api/core/two_factor/yubikey.rs +++ b/src/api/core/two_factor/yubikey.rs @@ -1,5 +1,4 @@ -use rocket::Route; -use rocket::serde::json::Json; +use rocket::{Route, serde::json::Json}; use serde_json::Value; use yubico::{config::Config, verify_async}; diff --git a/src/api/mod.rs b/src/api/mod.rs index 3c85d17e..05c4215d 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -9,7 +9,6 @@ mod web; use rocket::serde::json::Json; use serde_json::Value; -use crate::CONFIG; pub use crate::api::{ admin::catchers as admin_catchers, admin::routes as admin_routes, @@ -33,9 +32,12 @@ pub use crate::api::{ web::routes as web_routes, web::static_files, }; -use crate::db::{ - DbConn, - models::{OrgPolicy, OrgPolicyType, User}, +use crate::{ + CONFIG, + db::{ + DbConn, + models::{OrgPolicy, OrgPolicyType, User}, + }, }; // Type aliases for API methods results diff --git a/src/api/notifications.rs b/src/api/notifications.rs index 27fa1fd6..80067433 100644 --- a/src/api/notifications.rs +++ b/src/api/notifications.rs @@ -19,6 +19,11 @@ use crate::{ }, }; +use super::{ + push::push_auth_request, push::push_auth_response, push_cipher_update, push_folder_update, push_logout, + push_send_update, push_user_update, +}; + pub static WS_USERS: LazyLock> = LazyLock::new(|| { Arc::new(WebSocketUsers { map: Arc::new(dashmap::DashMap::new()), @@ -31,11 +36,6 @@ pub static WS_ANONYMOUS_SUBSCRIPTIONS: LazyLock = LazyLock::new(|| !CONFIG.enable_websocket() && !CONFIG.push_enabled()); pub fn routes() -> Vec { diff --git a/src/api/web.rs b/src/api/web.rs index 771a08b0..8c628f96 100644 --- a/src/api/web.rs +++ b/src/api/web.rs @@ -13,7 +13,10 @@ use crate::{ CONFIG, api::{ApiResult, EmptyResult, core::now}, auth::decode_file_download, - db::models::{AttachmentId, CipherId}, + db::{ + DbConn, + models::{AttachmentId, CipherId}, + }, error::Error, util::Cached, }; @@ -178,7 +181,6 @@ async fn attachments(cipher_id: CipherId, file_id: AttachmentId, token: String) } // We use DbConn here to let the alive healthcheck also verify the database connection. -use crate::db::DbConn; #[get("/alive")] fn alive(_conn: DbConn) -> Json { now() diff --git a/src/auth.rs b/src/auth.rs index ae190981..b96fc46c 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -8,16 +8,24 @@ use chrono::{DateTime, TimeDelta, Utc}; use jsonwebtoken::{Algorithm, DecodingKey, EncodingKey, Header, errors::ErrorKind}; use num_traits::FromPrimitive; use openssl::rsa::Rsa; -use serde::de::DeserializeOwned; -use serde::ser::Serialize; +use serde::{de::DeserializeOwned, ser::Serialize}; + +use rocket::{ + outcome::try_outcome, + request::{FromRequest, Outcome, Request}, +}; use crate::{ CONFIG, api::ApiResult, config::PathType, - db::models::{ - AttachmentId, CipherId, CollectionId, DeviceId, DeviceType, EmergencyAccessId, MembershipId, OrgApiKeyId, - OrganizationId, SendFileId, SendId, UserId, + db::{ + DbConn, + models::{ + AttachmentId, CipherId, Collection, CollectionId, Device, DeviceId, DeviceType, EmergencyAccessId, + Membership, MembershipId, MembershipStatus, MembershipType, OrgApiKeyId, OrganizationId, SendFileId, + SendId, User, UserId, UserStampException, + }, }, error::Error, sso, @@ -53,16 +61,16 @@ static PRIVATE_RSA_KEY: OnceLock = OnceLock::new(); static PUBLIC_RSA_KEY: OnceLock = OnceLock::new(); pub async fn initialize_keys() -> Result<(), Error> { - use std::io::Error; + use std::io::Error as IoError; let rsa_key_filename = std::path::PathBuf::from(CONFIG.private_rsa_key()) .file_name() - .ok_or_else(|| Error::other("Private RSA key path missing filename"))? + .ok_or_else(|| IoError::other("Private RSA key path missing filename"))? .to_str() - .ok_or_else(|| Error::other("Private RSA key path filename is not valid UTF-8"))? + .ok_or_else(|| IoError::other("Private RSA key path filename is not valid UTF-8"))? .to_owned(); - let operator = CONFIG.opendal_operator_for_path_type(&PathType::RsaKey).map_err(Error::other)?; + let operator = CONFIG.opendal_operator_for_path_type(&PathType::RsaKey).map_err(IoError::other)?; let priv_key_buffer = match operator.read(&rsa_key_filename).await { Ok(buffer) => Some(buffer), @@ -528,16 +536,6 @@ pub fn generate_send_claims(send_id: &SendId, file_id: &SendFileId) -> BasicJwtC // // Bearer token authentication // -use rocket::{ - outcome::try_outcome, - request::{FromRequest, Outcome, Request}, -}; - -use crate::db::{ - DbConn, - models::{Collection, Device, Membership, MembershipStatus, MembershipType, User, UserStampException}, -}; - pub struct Host { pub host: String, } diff --git a/src/db/mod.rs b/src/db/mod.rs index 95f3896b..4f90da45 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -10,13 +10,11 @@ use diesel::{ connection::SimpleConnection, r2d2::{CustomizeConnection, Pool, PooledConnection}, }; - use rocket::{ Request, http::Status, request::{FromRequest, Outcome}, }; - use tokio::{ sync::{Mutex, OwnedSemaphorePermit, Semaphore}, time::timeout, diff --git a/src/db/models/archive.rs b/src/db/models/archive.rs index ac15fa93..74772abb 100644 --- a/src/db/models/archive.rs +++ b/src/db/models/archive.rs @@ -1,11 +1,13 @@ use chrono::NaiveDateTime; use diesel::prelude::*; +use crate::{ + api::EmptyResult, + db::{DbConn, schema::archives}, + error::MapResult, +}; + use super::{CipherId, User, UserId}; -use crate::api::EmptyResult; -use crate::db::DbConn; -use crate::db::schema::archives; -use crate::error::MapResult; #[derive(Identifiable, Queryable, Insertable)] #[diesel(table_name = archives)] diff --git a/src/db/models/attachment.rs b/src/db/models/attachment.rs index 0b2adc15..c2773f74 100644 --- a/src/db/models/attachment.rs +++ b/src/db/models/attachment.rs @@ -1,13 +1,24 @@ +use std::time::Duration; + use bigdecimal::{BigDecimal, ToPrimitive}; use derive_more::{AsRef, Deref, Display}; use diesel::prelude::*; use serde_json::Value; -use std::time::Duration; + +use crate::{ + CONFIG, + api::EmptyResult, + auth::{encode_jwt, generate_file_download_claims}, + config::PathType, + db::{ + DbConn, + schema::{attachments, ciphers}, + }, + error::MapResult, +}; +use macros::IdFromParam; use super::{CipherId, OrganizationId, UserId}; -use crate::db::schema::{attachments, ciphers}; -use crate::{CONFIG, config::PathType}; -use macros::IdFromParam; #[derive(Identifiable, Queryable, Insertable, AsChangeset)] #[diesel(table_name = attachments)] @@ -67,12 +78,6 @@ impl Attachment { } } -use crate::auth::{encode_jwt, generate_file_download_claims}; -use crate::db::DbConn; - -use crate::api::EmptyResult; -use crate::error::MapResult; - /// Database methods impl Attachment { pub async fn save(&self, conn: &DbConn) -> EmptyResult { diff --git a/src/db/models/auth_request.rs b/src/db/models/auth_request.rs index 93c6e445..2924518c 100644 --- a/src/db/models/auth_request.rs +++ b/src/db/models/auth_request.rs @@ -1,12 +1,19 @@ -use super::{DeviceId, OrganizationId, UserId}; -use crate::db::schema::auth_requests; -use crate::{crypto::ct_eq, util::format_date}; use chrono::{NaiveDateTime, Utc}; use derive_more::{AsRef, Deref, Display, From}; use diesel::prelude::*; -use macros::UuidFromParam; use serde_json::Value; +use crate::{ + api::EmptyResult, + crypto::ct_eq, + db::{DbConn, schema::auth_requests}, + error::MapResult, + util::format_date, +}; +use macros::UuidFromParam; + +use super::{DeviceId, OrganizationId, UserId}; + #[derive(Identifiable, Queryable, Insertable, AsChangeset, Deserialize, Serialize)] #[diesel(table_name = auth_requests)] #[diesel(treat_none_as_null = true)] @@ -74,11 +81,6 @@ impl AuthRequest { } } -use crate::db::DbConn; - -use crate::api::EmptyResult; -use crate::error::MapResult; - impl AuthRequest { pub async fn save(&mut self, conn: &DbConn) -> EmptyResult { db_run! { conn: diff --git a/src/db/models/cipher.rs b/src/db/models/cipher.rs index f23bb6f8..1070a337 100644 --- a/src/db/models/cipher.rs +++ b/src/db/models/cipher.rs @@ -1,22 +1,32 @@ -use crate::CONFIG; -use crate::db::schema::{ - ciphers, ciphers_collections, collections, collections_groups, folders, folders_ciphers, groups, groups_users, - users_collections, users_organizations, -}; -use crate::util::LowerCase; +use std::borrow::Cow; + use chrono::{NaiveDateTime, TimeDelta, Utc}; use derive_more::{AsRef, Deref, Display, From}; use diesel::prelude::*; use serde_json::Value; +use crate::{ + CONFIG, + api::{ + EmptyResult, + core::{CipherData, CipherSyncData, CipherSyncType}, + }, + db::{ + DbConn, + schema::{ + ciphers, ciphers_collections, collections, collections_groups, folders, folders_ciphers, groups, + groups_users, users_collections, users_organizations, + }, + }, + error::MapResult, + util::LowerCase, +}; +use macros::UuidFromParam; + use super::{ Archive, Attachment, CollectionCipher, CollectionId, Favorite, FolderCipher, FolderId, Group, Membership, MembershipStatus, MembershipType, OrganizationId, User, UserId, }; -use crate::api::core::{CipherData, CipherSyncData, CipherSyncType}; -use macros::UuidFromParam; - -use std::borrow::Cow; #[derive(Identifiable, Queryable, Insertable, AsChangeset)] #[diesel(table_name = ciphers)] @@ -130,11 +140,6 @@ impl Cipher { } } -use crate::db::DbConn; - -use crate::api::EmptyResult; -use crate::error::MapResult; - /// Database methods impl Cipher { pub async fn to_json( diff --git a/src/db/models/collection.rs b/src/db/models/collection.rs index 679550d6..13d93cef 100644 --- a/src/db/models/collection.rs +++ b/src/db/models/collection.rs @@ -1,16 +1,25 @@ use derive_more::{AsRef, Deref, Display, From}; +use diesel::prelude::*; use serde_json::Value; +use crate::{ + CONFIG, + api::EmptyResult, + db::{ + DbConn, + schema::{ + ciphers_collections, collections, collections_groups, groups, groups_users, users_collections, + users_organizations, + }, + }, + error::MapResult, +}; +use macros::UuidFromParam; + use super::{ CipherId, CollectionGroup, GroupUser, Membership, MembershipId, MembershipStatus, MembershipType, OrganizationId, User, UserId, }; -use crate::CONFIG; -use crate::db::schema::{ - ciphers_collections, collections, collections_groups, groups, groups_users, users_collections, users_organizations, -}; -use diesel::prelude::*; -use macros::UuidFromParam; #[derive(Identifiable, Queryable, Insertable, AsChangeset)] #[diesel(table_name = collections)] @@ -147,11 +156,6 @@ impl Collection { } } -use crate::db::DbConn; - -use crate::api::EmptyResult; -use crate::error::MapResult; - /// Database methods impl Collection { pub async fn save(&self, conn: &DbConn) -> EmptyResult { diff --git a/src/db/models/device.rs b/src/db/models/device.rs index 3eb817c5..78c1ce9d 100644 --- a/src/db/models/device.rs +++ b/src/db/models/device.rs @@ -1,18 +1,20 @@ use chrono::{NaiveDateTime, Utc}; - use data_encoding::BASE64URL; use derive_more::{Display, From}; +use diesel::prelude::*; use serde_json::Value; -use super::{AuthRequest, UserId}; -use crate::db::schema::devices; use crate::{ + api::EmptyResult, crypto, + db::{DbConn, schema::devices}, + error::MapResult, util::{format_date, get_uuid}, }; -use diesel::prelude::*; use macros::{IdFromParam, UuidFromParam}; +use super::{AuthRequest, UserId}; + #[derive(Identifiable, Queryable, Insertable, AsChangeset)] #[diesel(table_name = devices)] #[diesel(treat_none_as_null = true)] @@ -135,10 +137,6 @@ impl DeviceWithAuthRequest { } } } -use crate::db::DbConn; - -use crate::api::EmptyResult; -use crate::error::MapResult; /// Database methods impl Device { diff --git a/src/db/models/emergency_access.rs b/src/db/models/emergency_access.rs index fea034a3..c7588050 100644 --- a/src/db/models/emergency_access.rs +++ b/src/db/models/emergency_access.rs @@ -1,13 +1,17 @@ use chrono::{NaiveDateTime, Utc}; use derive_more::{AsRef, Deref, Display, From}; +use diesel::prelude::*; use serde_json::Value; -use super::{User, UserId}; -use crate::db::schema::emergency_access; -use crate::{api::EmptyResult, db::DbConn, error::MapResult}; -use diesel::prelude::*; +use crate::{ + api::EmptyResult, + db::{DbConn, schema::emergency_access}, + error::MapResult, +}; use macros::UuidFromParam; +use super::{User, UserId}; + #[derive(Identifiable, Queryable, Insertable, AsChangeset)] #[diesel(table_name = emergency_access)] #[diesel(treat_none_as_null = true)] diff --git a/src/db/models/event.rs b/src/db/models/event.rs index bea01ce1..dad57f44 100644 --- a/src/db/models/event.rs +++ b/src/db/models/event.rs @@ -1,11 +1,18 @@ use chrono::{NaiveDateTime, TimeDelta, Utc}; -//use derive_more::{AsRef, Deref, Display, From}; +use diesel::prelude::*; use serde_json::Value; +use crate::{ + CONFIG, + api::EmptyResult, + db::{ + DbConn, + schema::{event, users_organizations}, + }, + error::MapResult, +}; + use super::{CipherId, CollectionId, GroupId, MembershipId, OrgPolicyId, OrganizationId, UserId}; -use crate::db::schema::{event, users_organizations}; -use crate::{CONFIG, api::EmptyResult, db::DbConn, error::MapResult}; -use diesel::prelude::*; // https://bitwarden.com/help/event-logs/ diff --git a/src/db/models/favorite.rs b/src/db/models/favorite.rs index d7aa74bb..c6e780ad 100644 --- a/src/db/models/favorite.rs +++ b/src/db/models/favorite.rs @@ -1,7 +1,13 @@ -use super::{CipherId, User, UserId}; -use crate::db::schema::favorites; use diesel::prelude::*; +use crate::{ + api::EmptyResult, + db::{DbConn, schema::favorites}, + error::MapResult, +}; + +use super::{CipherId, User, UserId}; + #[derive(Identifiable, Queryable, Insertable)] #[diesel(table_name = favorites)] #[diesel(primary_key(user_uuid, cipher_uuid))] @@ -10,11 +16,6 @@ pub struct Favorite { pub cipher_uuid: CipherId, } -use crate::db::DbConn; - -use crate::api::EmptyResult; -use crate::error::MapResult; - impl Favorite { // Returns whether the specified cipher is a favorite of the specified user. pub async fn is_favorite(cipher_uuid: &CipherId, user_uuid: &UserId, conn: &DbConn) -> bool { diff --git a/src/db/models/folder.rs b/src/db/models/folder.rs index f63e3378..dac52ec4 100644 --- a/src/db/models/folder.rs +++ b/src/db/models/folder.rs @@ -1,12 +1,20 @@ use chrono::{NaiveDateTime, Utc}; use derive_more::{AsRef, Deref, Display, From}; +use diesel::prelude::*; use serde_json::Value; -use super::{CipherId, User, UserId}; -use crate::db::schema::{folders, folders_ciphers}; -use diesel::prelude::*; +use crate::{ + api::EmptyResult, + db::{ + DbConn, + schema::{folders, folders_ciphers}, + }, + error::MapResult, +}; use macros::UuidFromParam; +use super::{CipherId, User, UserId}; + #[derive(Identifiable, Queryable, Insertable, AsChangeset)] #[diesel(table_name = folders)] #[diesel(primary_key(uuid))] @@ -62,11 +70,6 @@ impl FolderCipher { } } -use crate::db::DbConn; - -use crate::api::EmptyResult; -use crate::error::MapResult; - /// Database methods impl Folder { pub async fn save(&mut self, conn: &DbConn) -> EmptyResult { diff --git a/src/db/models/group.rs b/src/db/models/group.rs index ea1e7d48..53cc9be5 100644 --- a/src/db/models/group.rs +++ b/src/db/models/group.rs @@ -1,14 +1,20 @@ -use super::{CollectionId, Membership, MembershipId, OrganizationId, User, UserId}; -use crate::api::EmptyResult; -use crate::db::DbConn; -use crate::db::schema::{collections, collections_groups, groups, groups_users, users_organizations}; -use crate::error::MapResult; use chrono::{NaiveDateTime, Utc}; use derive_more::{AsRef, Deref, Display, From}; use diesel::prelude::*; -use macros::UuidFromParam; use serde_json::Value; +use crate::{ + api::EmptyResult, + db::{ + DbConn, + schema::{collections, collections_groups, groups, groups_users, users_organizations}, + }, + error::MapResult, +}; +use macros::UuidFromParam; + +use super::{CollectionId, Membership, MembershipId, OrganizationId, User, UserId}; + #[derive(Identifiable, Queryable, Insertable, AsChangeset)] #[diesel(table_name = groups)] #[diesel(treat_none_as_null = true)] diff --git a/src/db/models/org_policy.rs b/src/db/models/org_policy.rs index 701b6ff9..b4d69009 100644 --- a/src/db/models/org_policy.rs +++ b/src/db/models/org_policy.rs @@ -1,14 +1,17 @@ use derive_more::{AsRef, From}; +use diesel::prelude::*; use serde::Deserialize; use serde_json::Value; -use crate::CONFIG; -use crate::api::EmptyResult; -use crate::api::core::two_factor; -use crate::db::DbConn; -use crate::db::schema::{org_policies, users_organizations}; -use crate::error::MapResult; -use diesel::prelude::*; +use crate::{ + CONFIG, + api::{EmptyResult, core::two_factor}, + db::{ + DbConn, + schema::{org_policies, users_organizations}, + }, + error::MapResult, +}; use super::{Membership, MembershipId, MembershipStatus, MembershipType, OrganizationId, TwoFactor, UserId}; diff --git a/src/db/models/organization.rs b/src/db/models/organization.rs index c2c64acb..d1d37283 100644 --- a/src/db/models/organization.rs +++ b/src/db/models/organization.rs @@ -1,24 +1,33 @@ -use chrono::{NaiveDateTime, Utc}; -use derive_more::{AsRef, Deref, Display, From}; -use diesel::prelude::*; -use num_traits::FromPrimitive; -use serde_json::Value; use std::{ cmp::Ordering, collections::{HashMap, HashSet}, }; -use super::{ - CipherId, Collection, CollectionGroup, CollectionId, CollectionUser, Group, GroupId, GroupUser, OrgPolicy, - OrgPolicyType, TwoFactor, User, UserId, -}; -use crate::CONFIG; -use crate::db::schema::{ - ciphers, ciphers_collections, collections_groups, groups, groups_users, org_policies, organization_api_key, - organizations, users, users_collections, users_organizations, +use chrono::{NaiveDateTime, Utc}; +use derive_more::{AsRef, Deref, Display, From}; +use diesel::prelude::*; +use num_traits::FromPrimitive; +use serde_json::Value; + +use crate::{ + CONFIG, + api::EmptyResult, + db::{ + DbConn, + schema::{ + ciphers, ciphers_collections, collections_groups, groups, groups_users, org_policies, organization_api_key, + organizations, users, users_collections, users_organizations, + }, + }, + error::MapResult, }; use macros::UuidFromParam; +use super::{ + Cipher, CipherId, Collection, CollectionGroup, CollectionId, CollectionUser, Group, GroupId, GroupUser, OrgPolicy, + OrgPolicyType, TwoFactor, User, UserId, +}; + #[derive(Identifiable, Queryable, Insertable, AsChangeset)] #[diesel(table_name = organizations)] #[diesel(treat_none_as_null = true)] @@ -325,11 +334,6 @@ impl OrganizationApiKey { } } -use crate::db::DbConn; - -use crate::api::EmptyResult; -use crate::error::MapResult; - /// Database methods impl Organization { pub async fn save(&self, conn: &DbConn) -> EmptyResult { @@ -373,8 +377,6 @@ impl Organization { } pub async fn delete(self, conn: &DbConn) -> EmptyResult { - use super::{Cipher, Collection}; - Cipher::delete_all_by_organization(&self.uuid, conn).await?; Collection::delete_all_by_organization(&self.uuid, conn).await?; Membership::delete_all_by_organization(&self.uuid, conn).await?; diff --git a/src/db/models/send.rs b/src/db/models/send.rs index 8af302fa..1f209eaa 100644 --- a/src/db/models/send.rs +++ b/src/db/models/send.rs @@ -1,11 +1,19 @@ use chrono::{NaiveDateTime, Utc}; +use data_encoding::BASE64URL_NOPAD; +use diesel::prelude::*; use serde_json::Value; +use uuid::Uuid; -use crate::{CONFIG, config::PathType, util::LowerCase}; +use crate::{ + CONFIG, + api::EmptyResult, + config::PathType, + db::{DbConn, schema::sends}, + error::MapResult, + util::{LowerCase, NumberOrString, format_date}, +}; use super::{OrganizationId, User, UserId}; -use crate::db::schema::sends; -use diesel::prelude::*; use id::SendId; #[derive(Identifiable, Queryable, Insertable, AsChangeset)] @@ -130,10 +138,6 @@ impl Send { } pub fn to_json(&self) -> Value { - use crate::util::format_date; - use data_encoding::BASE64URL_NOPAD; - use uuid::Uuid; - let mut data = serde_json::from_str::>(&self.data).map(|d| d.data).unwrap_or_default(); // Mobile clients expect size to be a string instead of a number @@ -167,8 +171,6 @@ impl Send { } pub async fn to_json_access(&self, conn: &DbConn) -> Value { - use crate::util::format_date; - let mut data = serde_json::from_str::>(&self.data).map(|d| d.data).unwrap_or_default(); // Mobile clients expect size to be a string instead of a number @@ -191,12 +193,6 @@ impl Send { } } -use crate::db::DbConn; - -use crate::api::EmptyResult; -use crate::error::MapResult; -use crate::util::NumberOrString; - impl Send { pub async fn save(&mut self, conn: &DbConn) -> EmptyResult { self.update_users_revision(conn).await; @@ -273,9 +269,6 @@ impl Send { } pub async fn find_by_access_id(access_id: &str, conn: &DbConn) -> Option { - use data_encoding::BASE64URL_NOPAD; - use uuid::Uuid; - let Ok(uuid_vec) = BASE64URL_NOPAD.decode(access_id.as_bytes()) else { return None; }; diff --git a/src/db/models/sso_auth.rs b/src/db/models/sso_auth.rs index 2c6eec6d..cb7b0012 100644 --- a/src/db/models/sso_auth.rs +++ b/src/db/models/sso_auth.rs @@ -1,17 +1,20 @@ -use chrono::{NaiveDateTime, Utc}; use std::time::Duration; -use crate::api::EmptyResult; -use crate::db::schema::sso_auth; -use crate::db::{DbConn, DbPool}; -use crate::error::MapResult; -use crate::sso::{OIDCCode, OIDCCodeChallenge, OIDCIdentifier, OIDCState, SSO_AUTH_EXPIRATION}; +use chrono::{NaiveDateTime, Utc}; +use diesel::{ + deserialize::FromSql, + expression::AsExpression, + prelude::*, + serialize::{Output, ToSql}, + sql_types::Text, +}; -use diesel::deserialize::FromSql; -use diesel::expression::AsExpression; -use diesel::prelude::*; -use diesel::serialize::{Output, ToSql}; -use diesel::sql_types::Text; +use crate::{ + api::EmptyResult, + db::{DbConn, DbPool, schema::sso_auth}, + error::MapResult, + sso::{OIDCCode, OIDCCodeChallenge, OIDCIdentifier, OIDCState, SSO_AUTH_EXPIRATION}, +}; #[derive(AsExpression, Clone, Debug, Serialize, Deserialize, FromSqlRow)] #[diesel(sql_type = Text)] diff --git a/src/db/models/two_factor.rs b/src/db/models/two_factor.rs index cf64d950..de3fba95 100644 --- a/src/db/models/two_factor.rs +++ b/src/db/models/two_factor.rs @@ -1,13 +1,17 @@ -use super::UserId; -use crate::api::core::two_factor::webauthn::WebauthnRegistration; -use crate::db::schema::twofactor; -use crate::{api::EmptyResult, db::DbConn, error::MapResult}; use diesel::prelude::*; use serde_json::Value; use webauthn_rs::prelude::{Credential, ParsedAttestation}; use webauthn_rs_core::proto::CredentialV3; use webauthn_rs_proto::{AttestationFormat, RegisteredExtensions}; +use crate::{ + api::{EmptyResult, core::two_factor::webauthn::WebauthnRegistration}, + db::{DbConn, schema::twofactor}, + error::MapResult, +}; + +use super::UserId; + #[derive(Identifiable, Queryable, Insertable, AsChangeset)] #[diesel(table_name = twofactor)] #[diesel(primary_key(uuid))] diff --git a/src/db/models/two_factor_duo_context.rs b/src/db/models/two_factor_duo_context.rs index 4f7d2388..053e8525 100644 --- a/src/db/models/two_factor_duo_context.rs +++ b/src/db/models/two_factor_duo_context.rs @@ -1,9 +1,12 @@ use chrono::Utc; - -use crate::db::schema::twofactor_duo_ctx; -use crate::{api::EmptyResult, db::DbConn, error::MapResult}; use diesel::prelude::*; +use crate::{ + api::EmptyResult, + db::{DbConn, schema::twofactor_duo_ctx}, + error::MapResult, +}; + #[derive(Identifiable, Queryable, Insertable, AsChangeset)] #[diesel(table_name = twofactor_duo_ctx)] #[diesel(primary_key(state))] diff --git a/src/db/models/two_factor_incomplete.rs b/src/db/models/two_factor_incomplete.rs index ca008821..1b1a1bf9 100644 --- a/src/db/models/two_factor_incomplete.rs +++ b/src/db/models/two_factor_incomplete.rs @@ -1,6 +1,6 @@ use chrono::{NaiveDateTime, Utc}; +use diesel::prelude::*; -use crate::db::schema::twofactor_incomplete; use crate::{ CONFIG, api::EmptyResult, @@ -8,10 +8,10 @@ use crate::{ db::{ DbConn, models::{DeviceId, UserId}, + schema::twofactor_incomplete, }, error::MapResult, }; -use diesel::prelude::*; #[derive(Identifiable, Queryable, Insertable, AsChangeset)] #[diesel(table_name = twofactor_incomplete)] diff --git a/src/db/models/user.rs b/src/db/models/user.rs index 9e43bc11..d366dfd3 100644 --- a/src/db/models/user.rs +++ b/src/db/models/user.rs @@ -1,23 +1,27 @@ -use crate::db::schema::{invitations, sso_users, twofactor_incomplete, users}; use chrono::{NaiveDateTime, TimeDelta, Utc}; use derive_more::{AsRef, Deref, Display, From}; use diesel::prelude::*; use serde_json::Value; -use super::{ - Cipher, Device, EmergencyAccess, Favorite, Folder, Membership, MembershipType, TwoFactor, TwoFactorIncomplete, -}; use crate::{ CONFIG, api::EmptyResult, crypto, - db::{DbConn, models::DeviceId}, + db::{ + DbConn, + models::DeviceId, + schema::{invitations, sso_users, twofactor_incomplete, users}, + }, error::MapResult, sso::OIDCIdentifier, util::{format_date, get_uuid, retry}, }; use macros::UuidFromParam; +use super::{ + Cipher, Device, EmergencyAccess, Favorite, Folder, Membership, MembershipType, TwoFactor, TwoFactorIncomplete, +}; + #[derive(Identifiable, Queryable, Insertable, AsChangeset, Selectable)] #[diesel(table_name = users)] #[diesel(treat_none_as_null = true)] diff --git a/src/db/query_logger.rs b/src/db/query_logger.rs index e8312aac..89a1f3b5 100644 --- a/src/db/query_logger.rs +++ b/src/db/query_logger.rs @@ -1,6 +1,7 @@ -use diesel::connection::{Instrumentation, InstrumentationEvent}; use std::{cell::RefCell, collections::HashMap, time::Instant}; +use diesel::connection::{Instrumentation, InstrumentationEvent}; + thread_local! { static QUERY_PERF_TRACKER: RefCell> = RefCell::new(HashMap::new()); } diff --git a/src/error.rs b/src/error.rs index ccc23e15..d075dfe5 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,10 +1,11 @@ // // Error generator macro // +use std::error::Error as StdError; + use crate::db::models::EventType; use crate::http_client::CustomHttpClientError; use serde::ser::{Serialize, SerializeStruct, Serializer}; -use std::error::Error as StdError; macro_rules! make_error { ( $( $name:ident ( $ty:ty ): $src_fn:expr, $usr_msg_fun:expr ),+ $(,)? ) => { @@ -300,9 +301,11 @@ fn compact_api_error(_: &impl std::any::Any, msg: &str) -> String { // use std::io::Cursor; -use rocket::http::{ContentType, Status}; -use rocket::request::Request; -use rocket::response::{self, Responder, Response}; +use rocket::{ + http::{ContentType, Status}, + request::Request, + response::{self, Responder, Response}, +}; impl Responder<'_, 'static> for Error { fn respond_to(self, _: &Request<'_>) -> response::Result<'static> { diff --git a/src/mail.rs b/src/mail.rs index 5da753bf..f31234d7 100644 --- a/src/mail.rs +++ b/src/mail.rs @@ -1,7 +1,6 @@ -use chrono::NaiveDateTime; -use percent_encoding::{NON_ALPHANUMERIC, percent_encode}; use std::{env::consts::EXE_SUFFIX, str::FromStr}; +use chrono::NaiveDateTime; use lettre::{ Address, AsyncSendmailTransport, AsyncSmtpTransport, AsyncTransport, Tokio1Executor, message::{Attachment, Body, Mailbox, Message, MultiPart, SinglePart}, @@ -9,6 +8,7 @@ use lettre::{ transport::smtp::client::{Tls, TlsParameters}, transport::smtp::extension::ClientId, }; +use percent_encoding::{NON_ALPHANUMERIC, percent_encode}; use crate::{ CONFIG, @@ -19,6 +19,7 @@ use crate::{ }, db::models::{Device, DeviceType, EmergencyAccessId, MembershipId, OrganizationId, User, UserId}, error::Error, + util::upcase_first, }; fn sendmail_transport() -> AsyncSendmailTransport { @@ -505,8 +506,6 @@ pub async fn send_invite_confirmed(address: &str, org_name: &str) -> EmptyResult } pub async fn send_new_device_logged_in(address: &str, ip: &str, dt: &NaiveDateTime, device: &Device) -> EmptyResult { - use crate::util::upcase_first; - let fmt = "%A, %B %_d, %Y at %r %Z"; let (subject, body_html, body_text) = get_text( "email/new_device_logged_in", @@ -530,8 +529,6 @@ pub async fn send_incomplete_2fa_login( device_name: &str, device_type: &str, ) -> EmptyResult { - use crate::util::upcase_first; - let fmt = "%A, %B %_d, %Y at %r %Z"; let (subject, body_html, body_text) = get_text( "email/incomplete_2fa_login", diff --git a/src/main.rs b/src/main.rs index b494861f..06ba0c2c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -33,6 +33,7 @@ use std::{ path::Path, process::exit, str::FromStr, + sync::{Arc, atomic::Ordering}, thread, }; @@ -44,6 +45,8 @@ use tokio::{ #[cfg(unix)] use tokio::signal::unix::SignalKind; +use rocket::data::{Limits, ToByteUnit}; + #[macro_use] mod error; mod api; @@ -59,13 +62,11 @@ mod sso; mod sso_client; mod util; -use crate::api::core::two_factor::duo_oidc::purge_duo_contexts; -use crate::api::purge_auth_requests; -use crate::api::{WS_ANONYMOUS_SUBSCRIPTIONS, WS_USERS}; +use crate::api::{ + WS_ANONYMOUS_SUBSCRIPTIONS, WS_USERS, core::two_factor::duo_oidc::purge_duo_contexts, purge_auth_requests, +}; pub use config::{CONFIG, PathType}; pub use error::{Error, MapResult}; -use rocket::data::{Limits, ToByteUnit}; -use std::sync::{Arc, atomic::Ordering}; pub use util::is_running_in_container; #[rocket::main] diff --git a/src/util.rs b/src/util.rs index 2e505dee..91f075d1 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,9 +1,18 @@ // // Web Headers and caching // -use std::{collections::HashMap, io::Cursor, path::Path}; +use std::{collections::HashMap, env, fmt, io::Cursor, path::Path, str::FromStr}; +use chrono::{DateTime, Local, NaiveDateTime, TimeZone}; use num_traits::ToPrimitive; +use tokio::{ + runtime::Handle, + time::{Duration, sleep}, +}; + +use serde::de::{self, DeserializeOwned, Deserializer, MapAccess, SeqAccess, Visitor}; +use serde_json::Value; + use rocket::{ Data, Orbit, Request, Response, Rocket, fairing::{Fairing, Info, Kind}, @@ -11,11 +20,6 @@ use rocket::{ response::{self, Responder}, }; -use tokio::{ - runtime::Handle, - time::{Duration, sleep}, -}; - use crate::{ CONFIG, config::{PathType, SUPPORTED_FEATURE_FLAGS}, @@ -356,9 +360,6 @@ pub fn get_uuid() -> String { // // String util methods // - -use std::str::FromStr; - #[inline] pub fn upcase_first(s: &str) -> String { let mut c = s.chars(); @@ -392,9 +393,6 @@ where // // Env methods // - -use std::env; - pub fn get_env_str_value(key: &str) -> Option { let key_file = format!("{key}_FILE"); let value_from_env = env::var(key); @@ -433,8 +431,6 @@ pub fn get_env_bool(key: &str) -> Option { // Date util methods // -use chrono::{DateTime, Local, NaiveDateTime, TimeZone}; - /// Formats a UTC-offset `NaiveDateTime` in the format used by Bitwarden API /// responses with "date" fields (`CreationDate`, `RevisionDate`, etc.). pub fn format_date(dt: &NaiveDateTime) -> String { @@ -559,12 +555,6 @@ pub fn get_active_web_release() -> String { // // Deserialization methods // - -use std::fmt; - -use serde::de::{self, DeserializeOwned, Deserializer, MapAccess, SeqAccess, Visitor}; -use serde_json::Value; - pub type JsonMap = serde_json::Map; #[derive(Serialize, Deserialize)]