From 44f8ef29e108729d7bb57573beb08eed83132490 Mon Sep 17 00:00:00 2001 From: mdecimus Date: Fri, 21 Feb 2025 09:59:23 +0100 Subject: [PATCH] Bump to Rust 2024 --- Cargo.lock | 100 ++++++++++++++++-- README.md | 2 +- crates/cli/Cargo.toml | 4 +- crates/cli/src/modules/import.rs | 2 +- crates/common/Cargo.toml | 2 +- crates/common/src/auth/oauth/config.rs | 12 +-- crates/common/src/auth/oauth/token.rs | 8 +- crates/common/src/listener/acme/directory.rs | 22 ++-- crates/common/src/manager/boot.rs | 17 +-- crates/common/src/manager/config.rs | 8 +- .../common/src/scripts/plugins/llm_prompt.rs | 4 +- crates/directory/Cargo.toml | 2 +- .../directory/src/backend/internal/manage.rs | 49 +++++---- crates/directory/src/backend/internal/mod.rs | 17 +-- crates/email/Cargo.toml | 3 +- crates/email/src/crypto.rs | 18 ++-- crates/email/src/ingest.rs | 2 +- crates/imap-proto/Cargo.toml | 2 +- crates/imap-proto/src/parser/create.rs | 12 +-- crates/imap-proto/src/parser/fetch.rs | 28 ++--- crates/imap-proto/src/parser/list.rs | 25 +++-- crates/imap-proto/src/parser/mod.rs | 4 +- crates/imap-proto/src/parser/search.rs | 10 +- crates/imap-proto/src/parser/select.rs | 20 ++-- crates/imap-proto/src/parser/sort.rs | 8 +- crates/imap-proto/src/parser/status.rs | 14 +-- crates/imap/Cargo.toml | 4 +- crates/imap/src/core/mailbox.rs | 2 +- crates/imap/src/op/list.rs | 6 +- crates/jmap-proto/Cargo.toml | 2 +- crates/jmap-proto/src/parser/impls.rs | 6 +- crates/jmap-proto/src/types/id.rs | 4 +- crates/jmap/Cargo.toml | 4 +- crates/jmap/src/api/http.rs | 2 +- crates/jmap/src/api/management/principal.rs | 2 +- crates/jmap/src/api/management/queue.rs | 32 +++--- crates/jmap/src/api/management/report.rs | 24 ++--- crates/jmap/src/api/management/settings.rs | 2 +- crates/jmap/src/auth/oauth/auth.rs | 31 +++--- crates/jmap/src/auth/oauth/registration.rs | 10 +- crates/jmap/src/email/delete.rs | 40 +++---- crates/jmap/src/push/ece.rs | 6 +- crates/jmap/src/push/set.rs | 11 +- crates/jmap/src/services/index.rs | 2 +- crates/jmap/src/sieve/set.rs | 28 ++--- crates/jmap/src/thread/get.rs | 2 +- crates/main/Cargo.toml | 2 +- crates/managesieve/Cargo.toml | 2 +- crates/nlp/Cargo.toml | 2 +- crates/nlp/src/bayes/mod.rs | 2 +- crates/pop3/Cargo.toml | 2 +- crates/smtp/Cargo.toml | 4 +- crates/smtp/src/core/mod.rs | 2 +- crates/smtp/src/inbound/data.rs | 2 +- crates/smtp/src/outbound/delivery.rs | 2 +- crates/smtp/src/outbound/lookup.rs | 10 +- crates/smtp/src/queue/manager.rs | 26 ++--- crates/smtp/src/reporting/dmarc.rs | 2 +- crates/smtp/src/reporting/mod.rs | 2 +- crates/smtp/src/reporting/tls.rs | 2 +- crates/spam-filter/Cargo.toml | 2 +- crates/spam-filter/src/analysis/mime.rs | 12 +-- crates/spam-filter/src/analysis/recipient.rs | 4 +- crates/spam-filter/src/modules/bayes.rs | 35 +++--- crates/spam-filter/src/modules/html.rs | 66 ++++++------ crates/store/Cargo.toml | 4 +- .../store/src/backend/foundationdb/write.rs | 21 ++-- crates/store/src/backend/fs/mod.rs | 2 +- crates/store/src/backend/http/lookup.rs | 22 ++-- crates/store/src/backend/mysql/write.rs | 14 +-- crates/store/src/backend/postgres/write.rs | 2 +- crates/store/src/backend/rocksdb/mod.rs | 3 +- crates/store/src/backend/rocksdb/write.rs | 15 +-- crates/store/src/backend/sqlite/pool.rs | 3 +- crates/store/src/dispatch/store.rs | 17 +-- crates/store/src/write/hash.rs | 4 +- crates/store/src/write/mod.rs | 6 +- crates/trc/Cargo.toml | 2 +- crates/trc/event-macro/Cargo.toml | 2 +- crates/utils/Cargo.toml | 4 +- crates/utils/proc-macros/Cargo.toml | 2 +- crates/utils/src/snowflake.rs | 4 +- tests/Cargo.toml | 6 +- tests/src/imap/append.rs | 2 +- tests/src/imap/body_structure.rs | 2 +- tests/src/jmap/email_get.rs | 4 +- tests/src/jmap/email_set.rs | 6 +- tests/src/jmap/enterprise.rs | 10 +- tests/src/jmap/mod.rs | 28 ++--- tests/src/jmap/stress_test.rs | 22 ++-- tests/src/jmap/thread_merge.rs | 2 +- tests/src/store/lookup.rs | 42 ++++---- 92 files changed, 570 insertions(+), 477 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index be36759b..3f468546 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -102,7 +102,7 @@ dependencies = [ "once_cell", "serde", "version_check", - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -2059,6 +2059,7 @@ dependencies = [ "mail-builder", "mail-parser", "nlp", + "rand 0.8.5", "rasn", "rasn-cms", "rasn-pkix", @@ -2596,6 +2597,18 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "getrandom" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.13.3+wasi-0.2.2", + "windows-targets 0.52.6", +] + [[package]] name = "ghash" version = "0.5.1" @@ -3282,7 +3295,7 @@ dependencies = [ "md5", "nlp", "parking_lot", - "rand 0.8.5", + "rand 0.9.0", "rustls 0.23.21", "rustls-pemfile 2.2.0", "store", @@ -3549,7 +3562,7 @@ dependencies = [ "p256", "pkcs8", "quick-xml 0.37.2", - "rand 0.8.5", + "rand 0.9.0", "reqwest 0.12.12", "rev_lines", "rsa", @@ -4883,7 +4896,7 @@ version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" dependencies = [ - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -5240,6 +5253,17 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "rand" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.1", + "zerocopy 0.8.20", +] + [[package]] name = "rand_chacha" version = "0.2.2" @@ -5260,6 +5284,16 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.1", +] + [[package]] name = "rand_core" version = "0.5.1" @@ -5278,6 +5312,16 @@ dependencies = [ "getrandom 0.2.15", ] +[[package]] +name = "rand_core" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a88e0da7a2c97baa202165137c158d0a2e824ac465d13d81046727b34cb247d3" +dependencies = [ + "getrandom 0.3.1", + "zerocopy 0.8.20", +] + [[package]] name = "rand_hc" version = "0.2.0" @@ -6498,7 +6542,7 @@ dependencies = [ "nlp", "num_cpus", "parking_lot", - "rand 0.8.5", + "rand 0.9.0", "rayon", "regex", "reqwest 0.12.12", @@ -6634,7 +6678,7 @@ dependencies = [ "num_cpus", "prettytable-rs", "pwhash", - "rand 0.8.5", + "rand 0.9.0", "reqwest 0.12.12", "rpassword", "serde", @@ -6676,7 +6720,7 @@ dependencies = [ "num_cpus", "parking_lot", "r2d2", - "rand 0.8.5", + "rand 0.9.0", "rayon", "redis", "regex", @@ -7561,7 +7605,7 @@ dependencies = [ "privdrop", "psl", "quick_cache", - "rand 0.8.5", + "rand 0.9.0", "rcgen 0.13.2", "regex", "reqwest 0.12.12", @@ -7644,6 +7688,15 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi" +version = "0.13.3+wasi-0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +dependencies = [ + "wit-bindgen-rt", +] + [[package]] name = "wasite" version = "0.1.0" @@ -8053,6 +8106,15 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "wit-bindgen-rt" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +dependencies = [ + "bitflags 2.8.0", +] + [[package]] name = "write16" version = "1.0.0" @@ -8171,7 +8233,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "byteorder", - "zerocopy-derive", + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "zerocopy" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dde3bb8c68a8f3f1ed4ac9221aad6b10cece3e60a8e2ea54a6a2dec806d0084c" +dependencies = [ + "zerocopy-derive 0.8.20", ] [[package]] @@ -8185,6 +8256,17 @@ dependencies = [ "syn 2.0.96", ] +[[package]] +name = "zerocopy-derive" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eea57037071898bf96a6da35fd626f4f27e9cee3ead2a6c703cf09d472b2e700" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + [[package]] name = "zerofrom" version = "0.1.5" diff --git a/README.md b/README.md index aa3d3d29..22179663 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@

- continuous integration + continuous integration   License: AGPL v3   diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index a2d19a06..f4f58351 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -6,7 +6,7 @@ license = "AGPL-3.0-only OR LicenseRef-SEL" repository = "https://github.com/stalwartlabs/cli" homepage = "https://github.com/stalwartlabs/cli" version = "0.11.5" -edition = "2021" +edition = "2024" readme = "README.md" resolver = "2" @@ -28,5 +28,5 @@ form_urlencoded = "1.1.0" human-size = "0.4.2" futures = "0.3.28" pwhash = "1.0.0" -rand = "0.8.5" +rand = "0.9.0" mail-auth = { version = "0.6" } diff --git a/crates/cli/src/modules/import.rs b/crates/cli/src/modules/import.rs index eea73f9e..4bd1d7d0 100644 --- a/crates/cli/src/modules/import.rs +++ b/crates/cli/src/modules/import.rs @@ -364,7 +364,7 @@ impl ImportCommands { } Err(_) if retry_count < RETRY_ATTEMPTS => { let backoff = - rand::thread_rng().gen_range(50..=300); + rand::rng().random_range(50..=300); tokio::time::sleep(Duration::from_millis(backoff)) .await; retry_count += 1; diff --git a/crates/common/Cargo.toml b/crates/common/Cargo.toml index 3da0183f..d3ea574e 100644 --- a/crates/common/Cargo.toml +++ b/crates/common/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "common" version = "0.11.5" -edition = "2021" +edition = "2024" resolver = "2" [dependencies] diff --git a/crates/common/src/auth/oauth/config.rs b/crates/common/src/auth/oauth/config.rs index ab875b8a..fd9cad2d 100644 --- a/crates/common/src/auth/oauth/config.rs +++ b/crates/common/src/auth/oauth/config.rs @@ -10,14 +10,14 @@ use biscuit::{ jwa::{Algorithm, SignatureAlgorithm}, jwk::{ AlgorithmParameters, CommonParameters, EllipticCurve, EllipticCurveKeyParameters, - EllipticCurveKeyType, JWKSet, OctetKeyParameters, OctetKeyType, PublicKeyUse, - RSAKeyParameters, RSAKeyType, JWK, + EllipticCurveKeyType, JWK, JWKSet, OctetKeyParameters, OctetKeyType, PublicKeyUse, + RSAKeyParameters, RSAKeyType, }, jws::Secret, }; use ring::signature::{self, KeyPair}; -use rsa::{pkcs1::DecodeRsaPublicKey, traits::PublicKeyParts, RsaPublicKey}; -use store::rand::{distributions::Alphanumeric, thread_rng, Rng}; +use rsa::{RsaPublicKey, pkcs1::DecodeRsaPublicKey, traits::PublicKeyParts}; +use store::rand::{Rng, distr::Alphanumeric, rng}; use utils::config::Config; use x509_parser::num_bigint::BigUint; @@ -74,7 +74,7 @@ impl OAuthConfig { None => SignatureAlgorithm::HS256, }; - let rand_key = thread_rng() + let rand_key = rng() .sample_iter(Alphanumeric) .take(64) .map(char::from) @@ -149,7 +149,7 @@ impl OAuthConfig { .value("oauth.key") .map(|s| s.to_string()) .unwrap_or_else(|| { - thread_rng() + rng() .sample_iter(Alphanumeric) .take(64) .map(char::from) diff --git a/crates/common/src/auth/oauth/token.rs b/crates/common/src/auth/oauth/token.rs index f6abd5d6..32316e65 100644 --- a/crates/common/src/auth/oauth/token.rs +++ b/crates/common/src/auth/oauth/token.rs @@ -6,19 +6,19 @@ use std::time::SystemTime; -use directory::{backend::internal::PrincipalField, QueryBy}; +use directory::{QueryBy, backend::internal::PrincipalField}; use mail_builder::encoders::base64::base64_encode; use mail_parser::decoders::base64::base64_decode; use store::{ blake3, - rand::{thread_rng, Rng}, + rand::{Rng, rng}, }; use trc::AddContext; use utils::codec::leb128::{Leb128Iterator, Leb128Vec}; use crate::Server; -use super::{crypto::SymmetricEncrypt, GrantType, CLIENT_ID_MAX_LEN, RANDOM_CODE_LEN}; +use super::{CLIENT_ID_MAX_LEN, GrantType, RANDOM_CODE_LEN, crypto::SymmetricEncrypt}; pub struct TokenInfo { pub grant_type: GrantType, @@ -89,7 +89,7 @@ impl Server { // Encrypt random bytes let mut token = SymmetricEncrypt::new(key.as_bytes(), &context) - .encrypt(&thread_rng().gen::<[u8; RANDOM_CODE_LEN]>(), &nonce) + .encrypt(&rng().random::<[u8; RANDOM_CODE_LEN]>(), &nonce) .map_err(|_| { trc::AuthEvent::Error .into_err() diff --git a/crates/common/src/listener/acme/directory.rs b/crates/common/src/listener/acme/directory.rs index 95212c80..6eedc5a9 100644 --- a/crates/common/src/listener/acme/directory.rs +++ b/crates/common/src/listener/acme/directory.rs @@ -2,25 +2,25 @@ use std::time::Duration; -use base64::engine::general_purpose::URL_SAFE_NO_PAD; use base64::Engine; +use base64::engine::general_purpose::URL_SAFE_NO_PAD; use hyper::header::USER_AGENT; use rcgen::{Certificate, CustomExtension, PKCS_ECDSA_P256_SHA256}; use reqwest::header::CONTENT_TYPE; use reqwest::{Method, Response}; use ring::rand::SystemRandom; -use ring::signature::{EcdsaKeyPair, EcdsaSigningAlgorithm, ECDSA_P256_SHA256_FIXED_SIGNING}; +use ring::signature::{ECDSA_P256_SHA256_FIXED_SIGNING, EcdsaKeyPair, EcdsaSigningAlgorithm}; use serde::Deserialize; -use store::write::Bincode; use store::Serialize; -use trc::event::conv::AssertSuccess; +use store::write::Bincode; use trc::AddContext; +use trc::event::conv::AssertSuccess; -use super::jose::{ - eab_sign, key_authorization, key_authorization_sha256, key_authorization_sha256_base64, sign, - Body, -}; use super::AcmeProvider; +use super::jose::{ + Body, eab_sign, key_authorization, key_authorization_sha256, key_authorization_sha256_base64, + sign, +}; pub const LETS_ENCRYPT_STAGING_DIRECTORY: &str = "https://acme-staging-v02.api.letsencrypt.org/directory"; @@ -172,13 +172,11 @@ impl Account { } pub fn http_proof(&self, challenge: &Challenge) -> trc::Result> { - key_authorization(&self.key_pair, &challenge.token) - .map(|key| key.into_bytes()) - .map_err(Into::into) + key_authorization(&self.key_pair, &challenge.token).map(|key| key.into_bytes()) } pub fn dns_proof(&self, challenge: &Challenge) -> trc::Result { - key_authorization_sha256_base64(&self.key_pair, &challenge.token).map_err(Into::into) + key_authorization_sha256_base64(&self.key_pair, &challenge.token) } pub fn tls_alpn_key(&self, challenge: &Challenge, domain: String) -> trc::Result> { diff --git a/crates/common/src/manager/boot.rs b/crates/common/src/manager/boot.rs index f31b3100..4150fe8d 100644 --- a/crates/common/src/manager/boot.rs +++ b/crates/common/src/manager/boot.rs @@ -13,27 +13,28 @@ use std::{ use arc_swap::ArcSwap; use pwhash::sha512_crypt; use store::{ - rand::{distributions::Alphanumeric, thread_rng, Rng}, Stores, + rand::{Rng, distr::Alphanumeric, rng}, }; -use tokio::sync::{mpsc, Notify, Semaphore}; +use tokio::sync::{Notify, Semaphore, mpsc}; use utils::{ + Semver, UnwrapFailure, config::{Config, ConfigKey}, - failed, Semver, UnwrapFailure, + failed, }; use crate::{ + Caches, Core, Data, IPC_CHANNEL_BUFFER, Inner, Ipc, config::{network::AsnGeoLookupConfig, server::Listeners, telemetry::Telemetry}, core::BuildServer, ipc::{HousekeeperEvent, QueueEvent, ReportingEvent, StateEvent}, - Caches, Core, Data, Inner, Ipc, IPC_CHANNEL_BUFFER, }; use super::{ + WEBADMIN_KEY, backup::BackupParams, config::{ConfigManager, Patterns}, console::store_console, - WEBADMIN_KEY, }; pub struct BootManager { @@ -203,7 +204,7 @@ impl BootManager { { insert_keys.push(ConfigKey::from(( "oauth.key", - thread_rng() + rng() .sample_iter(Alphanumeric) .take(64) .map(char::from) @@ -219,7 +220,7 @@ impl BootManager { { insert_keys.push(ConfigKey::from(( "cluster.key", - thread_rng() + rng() .sample_iter(Alphanumeric) .take(64) .map(char::from) @@ -524,7 +525,7 @@ fn quickstart(path: impl Into) { } let admin_pass = std::env::var("STALWART_ADMIN_PASSWORD").unwrap_or_else(|_| { - thread_rng() + rng() .sample_iter(Alphanumeric) .take(10) .map(char::from) diff --git a/crates/common/src/manager/config.rs b/crates/common/src/manager/config.rs index 97945965..c5e2c9a9 100644 --- a/crates/common/src/manager/config.rs +++ b/crates/common/src/manager/config.rs @@ -5,7 +5,7 @@ */ use std::{ - collections::{btree_map::Entry, BTreeMap}, + collections::{BTreeMap, btree_map::Entry}, path::PathBuf, sync::Arc, }; @@ -13,14 +13,14 @@ use std::{ use ahash::AHashMap; use arc_swap::ArcSwap; use store::{ - write::{BatchBuilder, ValueClass}, Deserialize, IterateParams, Store, ValueKey, + write::{BatchBuilder, ValueClass}, }; use trc::AddContext; use utils::{ + Semver, config::{Config, ConfigKey}, glob::GlobPattern, - Semver, }; #[derive(Default)] @@ -347,7 +347,7 @@ impl ConfigManager { .ctx(trc::Key::Reason, reason) })?; - if current_version.map_or(true, |v| external.version > v || force_update) { + if current_version.is_none_or(|v| external.version > v || force_update) { if is_update { // Delete previous STWT_* rules let mut rule_settings = AHashMap::new(); diff --git a/crates/common/src/scripts/plugins/llm_prompt.rs b/crates/common/src/scripts/plugins/llm_prompt.rs index 5ca7ac38..677b404e 100644 --- a/crates/common/src/scripts/plugins/llm_prompt.rs +++ b/crates/common/src/scripts/plugins/llm_prompt.rs @@ -7,7 +7,7 @@ use std::time::Instant; use directory::Permission; -use sieve::{compiler::Number, runtime::Variable, FunctionMap}; +use sieve::{FunctionMap, compiler::Number, runtime::Variable}; use trc::{AiEvent, SecurityEvent}; use super::PluginContext; @@ -35,7 +35,7 @@ pub async fn exec(ctx: PluginContext<'_>) -> trc::Result { }); if let Some(ai_api) = ctx.server.core.enterprise.as_ref().and_then(|e| { - if ctx.access_token.map_or(true, |token| { + if ctx.access_token.is_none_or(|token| { if token.has_permission(Permission::AiModelInteract) { true } else { diff --git a/crates/directory/Cargo.toml b/crates/directory/Cargo.toml index dc022e7a..c7d2c4ee 100644 --- a/crates/directory/Cargo.toml +++ b/crates/directory/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "directory" version = "0.11.5" -edition = "2021" +edition = "2024" resolver = "2" [dependencies] diff --git a/crates/directory/src/backend/internal/manage.rs b/crates/directory/src/backend/internal/manage.rs index cc56d8d5..f6c40a94 100644 --- a/crates/directory/src/backend/internal/manage.rs +++ b/crates/directory/src/backend/internal/manage.rs @@ -7,23 +7,23 @@ use ahash::{AHashMap, AHashSet}; use jmap_proto::types::collection::Collection; use store::{ + Deserialize, IterateParams, Serialize, Store, U32_LEN, ValueKey, write::{ - assert::HashedValue, key::DeserializeBigEndian, AssignedIds, BatchBuilder, DirectoryClass, - MaybeDynamicId, MaybeDynamicValue, SerializeWithId, ValueClass, + AssignedIds, BatchBuilder, DirectoryClass, MaybeDynamicId, MaybeDynamicValue, + SerializeWithId, ValueClass, assert::HashedValue, key::DeserializeBigEndian, }, - Deserialize, IterateParams, Serialize, Store, ValueKey, U32_LEN, }; use trc::AddContext; use utils::sanitize_email; use crate::{ - backend::RcptType, Permission, Permissions, Principal, QueryBy, Type, MAX_TYPE_ID, ROLE_ADMIN, - ROLE_TENANT_ADMIN, ROLE_USER, + MAX_TYPE_ID, Permission, Permissions, Principal, QueryBy, ROLE_ADMIN, ROLE_TENANT_ADMIN, + ROLE_USER, Type, backend::RcptType, }; use super::{ - lookup::DirectoryStore, PrincipalAction, PrincipalField, PrincipalInfo, PrincipalUpdate, - PrincipalValue, SpecialSecrets, + PrincipalAction, PrincipalField, PrincipalInfo, PrincipalUpdate, PrincipalValue, + SpecialSecrets, lookup::DirectoryStore, }; pub struct MemberOf { @@ -76,7 +76,7 @@ pub trait ManageDirectory: Sized { allowed_permissions: Option<&Permissions>, ) -> trc::Result; async fn update_principal(&self, params: UpdatePrincipal<'_>) - -> trc::Result; + -> trc::Result; async fn delete_principal(&self, by: QueryBy<'_>) -> trc::Result; async fn list_principals( &self, @@ -254,12 +254,14 @@ impl ManageDirectory for Store { .caused_by(trc::location!())?; if total >= limit { - trc::bail!(trc::LimitEvent::TenantQuota - .into_err() - .details("Tenant principal quota exceeded") - .ctx(trc::Key::Details, principal.typ().as_str()) - .ctx(trc::Key::Limit, limit) - .ctx(trc::Key::Total, total)); + trc::bail!( + trc::LimitEvent::TenantQuota + .into_err() + .details("Tenant principal quota exceeded") + .ctx(trc::Key::Details, principal.typ().as_str()) + .ctx(trc::Key::Limit, limit) + .ctx(trc::Key::Total, total) + ); } } } @@ -353,7 +355,7 @@ impl ManageDirectory for Store { .await .caused_by(trc::location!())? .filter(|v| { - expected_type.map_or(true, |t| v.typ == t) + expected_type.is_none_or(|t| v.typ == t) && v.has_tenant_access(tenant_id) }), field.map_internal_roles(&name), @@ -400,7 +402,7 @@ impl ManageDirectory for Store { if !permissions.contains(&permission) { if allowed_permissions .as_ref() - .map_or(true, |p| p.get(permission as usize)) + .is_none_or(|p| p.get(permission as usize)) || field == PrincipalField::DisabledPermissions { permissions.push(permission); @@ -1572,7 +1574,7 @@ impl ManageDirectory for Store { if params .allowed_permissions .as_ref() - .map_or(true, |p| p.get(permission as usize)) + .is_none_or(|p| p.get(permission as usize)) || change.field == PrincipalField::DisabledPermissions { permissions.push(permission); @@ -1612,7 +1614,7 @@ impl ManageDirectory for Store { if params .allowed_permissions .as_ref() - .map_or(true, |p| p.get(permission as usize)) + .is_none_or(|p| p.get(permission as usize)) || change.field == PrincipalField::DisabledPermissions { principal.inner.append_int(change.field, permission); @@ -1819,9 +1821,10 @@ impl ManageDirectory for Store { .ok_or_else(|| not_found(principal.name().to_string()))?; } - if filters.as_ref().map_or(true, |filters| { - filters.iter().all(|f| principal.find_str(f)) - }) { + if filters + .as_ref() + .is_none_or(|filters| filters.iter().all(|f| principal.find_str(f))) + { result.total += 1; if offset == 0 { @@ -1867,9 +1870,9 @@ impl ManageDirectory for Store { let name = std::str::from_utf8(key.get(1..).unwrap_or_default()).unwrap_or_default(); - if typ.map_or(true, |t| pt.typ == t) + if typ.is_none_or(|t| pt.typ == t) && pt.has_tenant_access(tenant_id) - && filter.map_or(true, |f| name.contains(f)) + && filter.is_none_or(|f| name.contains(f)) { count += 1; } diff --git a/crates/directory/src/backend/internal/mod.rs b/crates/directory/src/backend/internal/mod.rs index b1bcd8f5..474e439d 100644 --- a/crates/directory/src/backend/internal/mod.rs +++ b/crates/directory/src/backend/internal/mod.rs @@ -13,15 +13,15 @@ use ahash::AHashMap; use jmap_proto::types::collection::Collection; use manage::DynamicPrincipalInfo; use store::{ + Deserialize, IterateParams, SUBSPACE_DIRECTORY, Serialize, Store, U32_LEN, ValueKey, write::{ - key::KeySerializer, AnyClass, BatchBuilder, DirectoryClass, MaybeDynamicId, ValueClass, + AnyClass, BatchBuilder, DirectoryClass, MaybeDynamicId, ValueClass, key::KeySerializer, }, - Deserialize, IterateParams, Serialize, Store, ValueKey, SUBSPACE_DIRECTORY, U32_LEN, }; use trc::AddContext; use utils::codec::leb128::{Leb128Iterator, Leb128Reader}; -use crate::{Principal, Type, ROLE_ADMIN, ROLE_USER}; +use crate::{Principal, ROLE_ADMIN, ROLE_USER, Type}; const INT_MARKER: u8 = 1 << 7; @@ -105,7 +105,7 @@ impl PrincipalInfo { // SPDX-License-Identifier: LicenseRef-SEL pub fn has_tenant_access(&self, tenant_id: Option) -> bool { - tenant_id.map_or(true, |tenant_id| { + tenant_id.is_none_or(|tenant_id| { self.tenant.is_some_and(|t| tenant_id == t) || (self.typ == Type::Tenant && self.id == tenant_id) }) @@ -371,10 +371,11 @@ impl MigrateDirectory for Store { })); if let Err(err) = self.write(batch.build()).await { - trc::error!(err - .caused_by(trc::location!()) - .details("Failed to migrate domain, probably a principal already exists") - .ctx(trc::Key::Domain, domain)); + trc::error!( + err.caused_by(trc::location!()) + .details("Failed to migrate domain, probably a principal already exists") + .ctx(trc::Key::Domain, domain) + ); } } diff --git a/crates/email/Cargo.toml b/crates/email/Cargo.toml index f1595817..a8b95a98 100644 --- a/crates/email/Cargo.toml +++ b/crates/email/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "email" version = "0.11.5" -edition = "2021" +edition = "2024" resolver = "2" [dependencies] @@ -29,6 +29,7 @@ rasn = "0.10" rasn-cms = "0.10" rasn-pkix = "0.10" rsa = "0.9.2" +rand = "0.8" sequoia-openpgp = { version = "1.16", default-features = false, features = ["crypto-rust", "allow-experimental-crypto", "allow-variable-time-crypto"] } [features] diff --git a/crates/email/src/crypto.rs b/crates/email/src/crypto.rs index 5a6e3c46..5c77c83c 100644 --- a/crates/email/src/crypto.rs +++ b/crates/email/src/crypto.rs @@ -6,29 +6,29 @@ use std::{borrow::Cow, collections::BTreeSet, fmt::Display, io::Cursor}; -use aes::cipher::{block_padding::Pkcs7, BlockEncryptMut, KeyIvInit}; +use aes::cipher::{BlockEncryptMut, KeyIvInit, block_padding::Pkcs7}; use mail_builder::{encoders::base64::base64_encode_mime, mime::make_boundary}; -use mail_parser::{decoders::base64::base64_decode, Message, MimeHeaders, PartType}; +use mail_parser::{Message, MimeHeaders, PartType, decoders::base64::base64_decode}; use openpgp::{ parse::Parse, serialize::stream, types::{KeyFlags, SymmetricAlgorithm}, }; +use rand::{RngCore, SeedableRng, rngs::StdRng}; use rasn::types::{ObjectIdentifier, OctetString}; use rasn_cms::{ + AlgorithmIdentifier, CONTENT_DATA, CONTENT_ENVELOPED_DATA, EncryptedContent, + EncryptedContentInfo, EncryptedKey, EnvelopedData, IssuerAndSerialNumber, + KeyTransRecipientInfo, RecipientIdentifier, RecipientInfo, algorithms::{AES128_CBC, AES256_CBC, RSA}, pkcs7_compat::EncapsulatedContentInfo, - AlgorithmIdentifier, EncryptedContent, EncryptedContentInfo, EncryptedKey, EnvelopedData, - IssuerAndSerialNumber, KeyTransRecipientInfo, RecipientIdentifier, RecipientInfo, CONTENT_DATA, - CONTENT_ENVELOPED_DATA, }; -use rsa::{pkcs1::DecodeRsaPublicKey, Pkcs1v15Encrypt, RsaPublicKey}; +use rsa::{Pkcs1v15Encrypt, RsaPublicKey, pkcs1::DecodeRsaPublicKey}; use sequoia_openpgp as openpgp; -use store::rand::{rngs::StdRng, RngCore, SeedableRng}; use store::{ - write::{Bincode, ToBitmaps}, Deserialize, Serialize, + write::{Bincode, ToBitmaps}, }; const P: openpgp::policy::StandardPolicy<'static> = openpgp::policy::StandardPolicy::new(); @@ -599,7 +599,7 @@ fn try_parse_pem( ); } Err(err) => { - return Err(format!("Failed to decode OpenPGP public key: {err}").into()) + return Err(format!("Failed to decode OpenPGP public key: {err}").into()); } }, EncryptionMethod::SMIME => { diff --git a/crates/email/src/ingest.rs b/crates/email/src/ingest.rs index 494b2ba8..37e8ff98 100644 --- a/crates/email/src/ingest.rs +++ b/crates/email/src/ingest.rs @@ -701,7 +701,7 @@ impl EmailIngest for Server { match self.core.storage.data.write(batch.build()).await { Ok(_) => return Ok(Some(thread_id)), Err(err) if err.is_assertion_failure() && try_count < MAX_RETRIES => { - let backoff = store::rand::thread_rng().gen_range(50..=300); + let backoff = store::rand::rng().random_range(50..=300); tokio::time::sleep(Duration::from_millis(backoff)).await; try_count += 1; } diff --git a/crates/imap-proto/Cargo.toml b/crates/imap-proto/Cargo.toml index 77030f16..6bfd91b8 100644 --- a/crates/imap-proto/Cargo.toml +++ b/crates/imap-proto/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "imap_proto" version = "0.11.5" -edition = "2021" +edition = "2024" resolver = "2" [dependencies] diff --git a/crates/imap-proto/src/parser/create.rs b/crates/imap-proto/src/parser/create.rs index afa71a48..120b31c7 100644 --- a/crates/imap-proto/src/parser/create.rs +++ b/crates/imap-proto/src/parser/create.rs @@ -5,10 +5,10 @@ */ use crate::{ - protocol::{create, ProtocolVersion}, - receiver::{bad, Request, Token}, - utf7::utf7_maybe_decode, Command, + protocol::{ProtocolVersion, create}, + receiver::{Request, Token, bad}, + utf7::utf7_maybe_decode, }; impl Request { @@ -32,7 +32,7 @@ impl Request { } if tokens .next() - .map_or(true, |token| !token.is_parenthesis_open()) + .is_none_or(|token| !token.is_parenthesis_open()) { return Err(bad(self.tag, "Expected '(' after 'USE'.")); } @@ -54,7 +54,7 @@ impl Request { return Err(bad( self.tag, "A mailbox with the \"\\All\" attribute already exists.", - )) + )); } None => { return Err(bad( @@ -90,7 +90,7 @@ impl Request { mod tests { use crate::{ - protocol::{create, ProtocolVersion}, + protocol::{ProtocolVersion, create}, receiver::Receiver, }; diff --git a/crates/imap-proto/src/parser/fetch.rs b/crates/imap-proto/src/parser/fetch.rs index edb26fd7..c0d3f77e 100644 --- a/crates/imap-proto/src/parser/fetch.rs +++ b/crates/imap-proto/src/parser/fetch.rs @@ -9,12 +9,12 @@ use std::iter::Peekable; use std::vec::IntoIter; use crate::{ - protocol::fetch::{self, Attribute, Section}, - receiver::{bad, Request, Token}, Command, + protocol::fetch::{self, Attribute, Section}, + receiver::{Request, Token, bad}, }; -use super::{parse_number, parse_sequence_set, PushUnique}; +use super::{PushUnique, parse_number, parse_sequence_set}; impl Request { #[allow(clippy::while_let_on_iterator)] @@ -121,14 +121,14 @@ impl Request { tokens.next(); if tokens .next() - .map_or(true, |token| !token.eq_ignore_ascii_case(b"PEEK")) + .is_none_or( |token| !token.eq_ignore_ascii_case(b"PEEK")) { return Err(bad( self.tag.clone(), "Expected 'PEEK' after '.'.", )); } - if tokens.next().map_or(true, |token| !token.is_bracket_open()) { + if tokens.next().is_none_or( |token| !token.is_bracket_open()) { return Err(bad( self.tag.clone(), "Expected '[' after 'BODY.PEEK'", @@ -156,7 +156,7 @@ impl Request { let section = if value.eq_ignore_ascii_case(b"HEADER") { if let Some(Token::Dot) = tokens.peek() { tokens.next(); - if tokens.next().map_or(true, |token| { + if tokens.next().is_none_or( |token| { !token.eq_ignore_ascii_case(b"FIELDS") }) { return Err(bad( @@ -166,7 +166,7 @@ impl Request { } let is_not = if let Some(Token::Dot) = tokens.peek() { tokens.next(); - if tokens.next().map_or(true, |token| { + if tokens.next().is_none_or( |token| { !token.eq_ignore_ascii_case(b"NOT") }) { return Err(bad( @@ -180,7 +180,7 @@ impl Request { }; if tokens .next() - .map_or(true, |token| !token.is_parenthesis_open()) + .is_none_or( |token| !token.is_parenthesis_open()) { return Err(bad( self.tag, @@ -267,7 +267,7 @@ impl Request { }; // Parse section-part - if tokens.next().map_or(true, |token| !token.is_bracket_open()) { + if tokens.next().is_none_or( |token| !token.is_bracket_open()) { return Err(bad(self.tag.to_string(), "Expected '[' after 'BINARY'.")); } let mut sections = Vec::new(); @@ -364,7 +364,7 @@ impl Request { return Err(bad( self.tag, format!("Invalid fetch argument {:?}.", token.to_string()), - )) + )); } } } @@ -419,7 +419,7 @@ impl Request { } pub fn parse_partial(tokens: &mut Peekable>) -> super::Result> { - if tokens.peek().map_or(true, |token| !token.is_lt()) { + if tokens.peek().is_none_or(|token| !token.is_lt()) { return Ok(None); } tokens.next(); @@ -431,7 +431,7 @@ pub fn parse_partial(tokens: &mut Peekable>) -> super::Result>) -> super::Result' after range.".into()); } @@ -499,8 +499,8 @@ pub fn parse_partial(tokens: &mut Peekable>) -> super::Result { @@ -60,7 +60,7 @@ impl Request { return Err(bad( self.tag.to_string(), "Invalid selection option argument.", - )) + )); } } } @@ -109,7 +109,7 @@ impl Request { { if tokens .next() - .map_or(true, |token| !token.is_parenthesis_open()) + .is_none_or(|token| !token.is_parenthesis_open()) { return Err(bad( self.tag.to_string(), @@ -126,13 +126,12 @@ impl Request { if let ReturnOption::Status(status) = &mut return_option { if tokens .next() - .map_or(true, |token| !token.is_parenthesis_open()) + .is_none_or(|token| !token.is_parenthesis_open()) { return Err(bad( - self.tag, - "Invalid return option, expected parenthesis after STATUS.", - ) - ); + self.tag, + "Invalid return option, expected parenthesis after STATUS.", + )); } while let Some(token) = tokens.next() { match token { @@ -148,7 +147,7 @@ impl Request { return Err(bad( self.tag, "Invalid status return option argument.", - )) + )); } } } @@ -159,7 +158,7 @@ impl Request { return Err(bad( self.tag.to_string(), "Invalid return option argument.", - )) + )); } } } @@ -211,9 +210,9 @@ impl ReturnOption { mod tests { use crate::{ protocol::{ + ProtocolVersion, list::{self, ReturnOption, SelectionOption}, status::Status, - ProtocolVersion, }, receiver::Receiver, }; diff --git a/crates/imap-proto/src/parser/mod.rs b/crates/imap-proto/src/parser/mod.rs index 917946e3..0c6be3a6 100644 --- a/crates/imap-proto/src/parser/mod.rs +++ b/crates/imap-proto/src/parser/mod.rs @@ -30,9 +30,9 @@ use std::{borrow::Cow, str::FromStr}; use chrono::{DateTime, NaiveDate}; use crate::{ + Command, protocol::{Flag, Sequence}, receiver::CommandParser, - Command, }; pub type Result = std::result::Result>; @@ -253,7 +253,7 @@ pub fn parse_sequence_set(value: &[u8]) -> Result { } } b'$' => { - if value.get(pos + 1).map_or(true, |&ch| ch == b',') { + if value.get(pos + 1).is_none_or(|&ch| ch == b',') { is_saved_search = true; } else { return Err(Cow::from(format!( diff --git a/crates/imap-proto/src/parser/search.rs b/crates/imap-proto/src/parser/search.rs index 44c90388..532b5b52 100644 --- a/crates/imap-proto/src/parser/search.rs +++ b/crates/imap-proto/src/parser/search.rs @@ -8,14 +8,14 @@ use std::borrow::Cow; use std::iter::Peekable; use std::vec::IntoIter; -use mail_parser::decoders::charsets::map::charset_decoder; use mail_parser::decoders::charsets::DecoderFnc; +use mail_parser::decoders::charsets::map::charset_decoder; +use crate::Command; use crate::protocol::search::{self, Filter}; use crate::protocol::search::{ModSeqEntry, ResultOption}; use crate::protocol::{Flag, ProtocolVersion}; -use crate::receiver::{bad, Request, Token}; -use crate::Command; +use crate::receiver::{Request, Token, bad}; use super::{parse_date, parse_number, parse_sequence_set}; @@ -74,7 +74,7 @@ pub fn parse_result_options( let mut result_options = Vec::new(); if tokens .next() - .map_or(true, |token| !token.is_parenthesis_open()) + .is_none_or(|token| !token.is_parenthesis_open()) { return Err(Cow::from("Invalid result option, expected parenthesis.")); } @@ -538,8 +538,8 @@ impl ResultOption { mod tests { use crate::{ protocol::{ - search::{self, Filter, ModSeqEntry, ResultOption}, Flag, ProtocolVersion, Sequence, + search::{self, Filter, ModSeqEntry, ResultOption}, }, receiver::Receiver, }; diff --git a/crates/imap-proto/src/parser/select.rs b/crates/imap-proto/src/parser/select.rs index 2a9717ce..186040c1 100644 --- a/crates/imap-proto/src/parser/select.rs +++ b/crates/imap-proto/src/parser/select.rs @@ -5,13 +5,13 @@ */ use crate::{ - protocol::{ - select::{self, QResync}, - ProtocolVersion, - }, - receiver::{bad, Request, Token}, - utf7::utf7_maybe_decode, Command, + protocol::{ + ProtocolVersion, + select::{self, QResync}, + }, + receiver::{Request, Token, bad}, + utf7::utf7_maybe_decode, }; use super::{parse_number, parse_sequence_set}; @@ -44,7 +44,7 @@ impl Request { Token::Argument(param) if param.eq_ignore_ascii_case(b"QRESYNC") => { if tokens .next() - .map_or(true, |token| !token.is_parenthesis_open()) + .is_none_or(|token| !token.is_parenthesis_open()) { return Err(bad(self.tag, "Expected '(' after 'QRESYNC'.")); } @@ -125,7 +125,7 @@ impl Request { )); if tokens .next() - .map_or(true, |token| !token.is_parenthesis_close()) + .is_none_or(|token| !token.is_parenthesis_close()) { return Err(bad(self.tag, "Missing ')' for 'QRESYNC'.")); } @@ -133,7 +133,7 @@ impl Request { if tokens .next() - .map_or(true, |token| !token.is_parenthesis_close()) + .is_none_or(|token| !token.is_parenthesis_close()) { return Err(bad(self.tag, "Missing ')' for 'QRESYNC'.")); } @@ -180,8 +180,8 @@ impl Request { mod tests { use crate::{ protocol::{ - select::{self, QResync}, ProtocolVersion, Sequence, + select::{self, QResync}, }, receiver::Receiver, }; diff --git a/crates/imap-proto/src/parser/sort.rs b/crates/imap-proto/src/parser/sort.rs index ec99e83e..a8696de2 100644 --- a/crates/imap-proto/src/parser/sort.rs +++ b/crates/imap-proto/src/parser/sort.rs @@ -7,9 +7,9 @@ use mail_parser::decoders::charsets::map::charset_decoder; use crate::{ - protocol::search::{Arguments, Comparator, Sort}, - receiver::{bad, Request, Token}, Command, + protocol::search::{Arguments, Comparator, Sort}, + receiver::{Request, Token, bad}, }; use super::search::{parse_filters, parse_result_options}; @@ -37,7 +37,7 @@ impl Request { if tokens .next() - .map_or(true, |token| !token.is_parenthesis_open()) + .is_none_or(|token| !token.is_parenthesis_open()) { return Err(bad( self.tag.to_string(), @@ -112,8 +112,8 @@ mod tests { use crate::{ protocol::{ - search::{Arguments, Comparator, Filter, ResultOption, Sort}, Flag, + search::{Arguments, Comparator, Filter, ResultOption, Sort}, }, receiver::Receiver, }; diff --git a/crates/imap-proto/src/parser/status.rs b/crates/imap-proto/src/parser/status.rs index 62402bf1..98e874ac 100644 --- a/crates/imap-proto/src/parser/status.rs +++ b/crates/imap-proto/src/parser/status.rs @@ -4,11 +4,11 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ -use crate::protocol::status::Status; -use crate::protocol::{status, ProtocolVersion}; -use crate::receiver::{bad, Request, Token}; -use crate::utf7::utf7_maybe_decode; use crate::Command; +use crate::protocol::status::Status; +use crate::protocol::{ProtocolVersion, status}; +use crate::receiver::{Request, Token, bad}; +use crate::utf7::utf7_maybe_decode; impl Request { pub fn parse_status(self, version: ProtocolVersion) -> trc::Result { @@ -28,7 +28,7 @@ impl Request { if tokens .next() - .map_or(true, |token| !token.is_parenthesis_open()) + .is_none_or(|token| !token.is_parenthesis_open()) { return Err(bad( self.tag.to_string(), @@ -49,7 +49,7 @@ impl Request { return Err(bad( self.tag.to_string(), "Invalid status return option argument.", - )) + )); } } } @@ -95,7 +95,7 @@ impl Status { #[cfg(test)] mod tests { use crate::{ - protocol::{status, ProtocolVersion}, + protocol::{ProtocolVersion, status}, receiver::Receiver, }; diff --git a/crates/imap/Cargo.toml b/crates/imap/Cargo.toml index 640ca4fd..d2f2c871 100644 --- a/crates/imap/Cargo.toml +++ b/crates/imap/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "imap" version = "0.11.5" -edition = "2021" +edition = "2024" resolver = "2" [dependencies] @@ -24,7 +24,7 @@ tokio-rustls = { version = "0.26", default-features = false, features = ["ring", parking_lot = "0.12" ahash = { version = "0.8" } md5 = "0.7.0" -rand = "0.8.5" +rand = "0.9.0" [features] diff --git a/crates/imap/src/core/mailbox.rs b/crates/imap/src/core/mailbox.rs index 956f3e0c..ac54f58d 100644 --- a/crates/imap/src/core/mailbox.rs +++ b/crates/imap/src/core/mailbox.rs @@ -606,7 +606,7 @@ impl SessionData { if account .prefix .as_ref() - .map_or(true, |p| mailbox_name.starts_with(p)) + .is_none_or( |p| mailbox_name.starts_with(p)) { for (mailbox_name_, mailbox_id_) in account.mailbox_names.iter() { if (!is_inbox && mailbox_name_ == mailbox_name) diff --git a/crates/imap/src/op/list.rs b/crates/imap/src/op/list.rs index 9b2cc3f3..250db4be 100644 --- a/crates/imap/src/op/list.rs +++ b/crates/imap/src/op/list.rs @@ -13,14 +13,14 @@ use crate::{ use common::listener::SessionStream; use directory::Permission; use imap_proto::{ + Command, StatusResponse, protocol::{ + ImapResponse, ProtocolVersion, list::{ self, Arguments, Attribute, ChildInfo, ListItem, ReturnOption, SelectionOption, Tag, }, - ImapResponse, ProtocolVersion, }, receiver::Request, - Command, StatusResponse, }; use super::ImapContext; @@ -316,7 +316,7 @@ pub fn matches_pattern(patterns: &[String], mailbox_name: &str) -> bool { 'inner: while let Some((pos, &ch)) = pattern_bytes.next() { if ch == b'%' || ch == b'*' { let mut end_pos = pos; - while let Some((_, &next_ch)) = pattern_bytes.peek() { + while let Some(&(_, &next_ch)) = pattern_bytes.peek() { if next_ch == b'%' || next_ch == b'*' { break; } else { diff --git a/crates/jmap-proto/Cargo.toml b/crates/jmap-proto/Cargo.toml index bff567cc..60f9432d 100644 --- a/crates/jmap-proto/Cargo.toml +++ b/crates/jmap-proto/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "jmap_proto" version = "0.11.5" -edition = "2021" +edition = "2024" resolver = "2" [dependencies] diff --git a/crates/jmap-proto/src/parser/impls.rs b/crates/jmap-proto/src/parser/impls.rs index 6f984d09..edf2d3aa 100644 --- a/crates/jmap-proto/src/parser/impls.rs +++ b/crates/jmap-proto/src/parser/impls.rs @@ -11,7 +11,7 @@ use utils::map::{ vec_map::VecMap, }; -use super::{json::Parser, Ignore, JsonObjectParser, Token}; +use super::{Ignore, JsonObjectParser, Token, json::Parser}; impl JsonObjectParser for u64 { fn parse(parser: &mut Parser<'_>) -> trc::Result @@ -78,9 +78,7 @@ impl JsonObjectParser for String { } b'"' if !is_escaped => { parser.is_eof = true; - return String::from_utf8(buf) - .map(Into::into) - .map_err(|_| parser.error_utf8()); + return String::from_utf8(buf).map_err(|_| parser.error_utf8()); } _ => { if !is_escaped { diff --git a/crates/jmap-proto/src/types/id.rs b/crates/jmap-proto/src/types/id.rs index da3498d1..d38a209c 100644 --- a/crates/jmap-proto/src/types/id.rs +++ b/crates/jmap-proto/src/types/id.rs @@ -8,7 +8,7 @@ use std::ops::Deref; use utils::codec::base32_custom::{BASE32_ALPHABET, BASE32_INVERSE}; -use crate::parser::{json::Parser, JsonObjectParser}; +use crate::parser::{JsonObjectParser, json::Parser}; use super::DocumentId; @@ -122,7 +122,7 @@ impl Id { pub fn from_parts(prefix_id: DocumentId, doc_id: DocumentId) -> Id { Id { - id: (prefix_id as u64) << 32 | doc_id as u64, + id: ((prefix_id as u64) << 32) | doc_id as u64, } } diff --git a/crates/jmap/Cargo.toml b/crates/jmap/Cargo.toml index 7be56e44..b9edbcee 100644 --- a/crates/jmap/Cargo.toml +++ b/crates/jmap/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "jmap" version = "0.11.5" -edition = "2021" +edition = "2024" resolver = "2" [dependencies] @@ -42,7 +42,7 @@ reqwest = { version = "0.12", default-features = false, features = ["rustls-tls- tokio-tungstenite = "0.26" tungstenite = "0.26" chrono = "0.4" -rand = "0.8.5" +rand = "0.9.0" pkcs8 = { version = "0.10.2", features = ["alloc", "std"] } lz4_flex = { version = "0.11", default-features = false } rev_lines = "0.3.0" diff --git a/crates/jmap/src/api/http.rs b/crates/jmap/src/api/http.rs index 3ac8ff9f..dc7be473 100644 --- a/crates/jmap/src/api/http.rs +++ b/crates/jmap/src/api/http.rs @@ -485,7 +485,7 @@ impl ParseHttp for Server { if let Some(auth) = &prometheus.auth { if req .authorization_basic() - .map_or(true, |secret| secret != auth) + .is_none_or( |secret| secret != auth) { return Err(trc::AuthEvent::Failed .into_err() diff --git a/crates/jmap/src/api/management/principal.rs b/crates/jmap/src/api/management/principal.rs index 39e51f2b..44281879 100644 --- a/crates/jmap/src/api/management/principal.rs +++ b/crates/jmap/src/api/management/principal.rs @@ -732,7 +732,7 @@ impl PrincipalManager for Server { .headers() .get(header::AUTHORIZATION) .and_then(|h| h.to_str().ok()) - .map_or(true, |header| !header.to_lowercase().starts_with("basic ")) + .is_none_or( |header| !header.to_lowercase().starts_with("basic ")) { return Err(manage::error( "Password changes only allowed using Basic auth", diff --git a/crates/jmap/src/api/management/queue.rs b/crates/jmap/src/api/management/queue.rs index 5460c304..acbced01 100644 --- a/crates/jmap/src/api/management/queue.rs +++ b/crates/jmap/src/api/management/queue.rs @@ -205,7 +205,7 @@ impl QueueManagement for Server { .filter(|message| { tenant_domains .as_ref() - .map_or(true, |domains| message.has_domain(domains)) + .is_none_or( |domains| message.has_domain(domains)) }) { Ok(JsonResponse::new(json!({ @@ -282,7 +282,7 @@ impl QueueManagement for Server { .filter(|message| { tenant_domains .as_ref() - .map_or(true, |domains| message.has_domain(domains)) + .is_none_or( |domains| message.has_domain(domains)) }) { let prev_event = message.next_event().unwrap_or_default(); @@ -294,7 +294,7 @@ impl QueueManagement for Server { Status::Scheduled | Status::TemporaryFailure(_) ) && item .as_ref() - .map_or(true, |item| domain.domain.contains(item)) + .is_none_or( |item| domain.domain.contains(item)) { domain.retry.due = time; if domain.expires > time { @@ -374,7 +374,7 @@ impl QueueManagement for Server { .filter(|message| { tenant_domains .as_ref() - .map_or(true, |domains| message.has_domain(domains)) + .is_none_or( |domains| message.has_domain(domains)) }) { let mut found = false; @@ -475,7 +475,7 @@ impl QueueManagement for Server { QueueClass::DmarcReportHeader(event) if tenant_domains .as_ref() - .map_or(true, |domains| domains.contains(&event.domain)) => + .is_none_or( |domains| domains.contains(&event.domain)) => { let mut rua = Vec::new(); if let Some(report) = self @@ -488,7 +488,7 @@ impl QueueManagement for Server { QueueClass::TlsReportHeader(event) if tenant_domains .as_ref() - .map_or(true, |domains| domains.contains(&event.domain)) => + .is_none_or( |domains| domains.contains(&event.domain)) => { let mut rua = Vec::new(); if let Some(report) = self @@ -548,7 +548,7 @@ impl QueueManagement for Server { QueueClass::DmarcReportHeader(event) if tenant_domains .as_ref() - .map_or(true, |domains| domains.contains(&event.domain)) => + .is_none_or( |domains| domains.contains(&event.domain)) => { self.delete_dmarc_report(event).await; true @@ -556,7 +556,7 @@ impl QueueManagement for Server { QueueClass::TlsReportHeader(event) if tenant_domains .as_ref() - .map_or(true, |domains| domains.contains(&event.domain)) => + .is_none_or( |domains| domains.contains(&event.domain)) => { self.delete_tls_report(vec![event]).await; true @@ -719,7 +719,7 @@ async fn fetch_queued_messages( .inner; let matches = tenant_domains .as_ref() - .map_or(true, |domains| message.has_domain(domains)) + .is_none_or( |domains| message.has_domain(domains)) && (!has_filters || (text .as_ref() @@ -732,8 +732,8 @@ async fn fetch_queued_messages( }) .unwrap_or_else(|| { from.as_ref() - .map_or(true, |from| message.return_path.contains(from)) - && to.as_ref().map_or(true, |to| { + .is_none_or( |from| message.return_path.contains(from)) + && to.as_ref().is_none_or( |to| { message .recipients .iter() @@ -742,10 +742,10 @@ async fn fetch_queued_messages( }) && before .as_ref() - .map_or(true, |before| message.next_delivery_event() < *before) + .is_none_or( |before| message.next_delivery_event() < *before) && after .as_ref() - .map_or(true, |after| message.next_delivery_event() > *after))); + .is_none_or( |after| message.next_delivery_event() > *after))); if matches { if offset == 0 { @@ -825,13 +825,13 @@ async fn fetch_queued_reports( .iterate( IterateParams::new(from_key, to_key).ascending().no_values(), |key, _| { - if type_.map_or(true, |t| t == *key.last().unwrap()) { + if type_.is_none_or( |t| t == *key.last().unwrap()) { let event = ReportEvent::deserialize(key)?; if tenant_domains .as_ref() - .map_or(true, |domains| domains.contains(&event.domain)) + .is_none_or( |domains| domains.contains(&event.domain)) && event.seq_id != 0 - && domain.as_ref().map_or(true, |d| event.domain.contains(d)) + && domain.as_ref().is_none_or( |d| event.domain.contains(d)) { if offset == 0 { if limit == 0 || total_returned < limit { diff --git a/crates/jmap/src/api/management/report.rs b/crates/jmap/src/api/management/report.rs index 7185059d..a6e7ac64 100644 --- a/crates/jmap/src/api/management/report.rs +++ b/crates/jmap/src/api/management/report.rs @@ -129,7 +129,7 @@ impl ManageReports for Server { Some(report) if tenant_domains .as_ref() - .map_or(true, |domains| report.inner.has_domain(domains)) => + .is_none_or( |domains| report.inner.has_domain(domains)) => { Ok(JsonResponse::new(json!({ "data": report.inner, @@ -150,7 +150,7 @@ impl ManageReports for Server { Some(report) if tenant_domains .as_ref() - .map_or(true, |domains| report.inner.has_domain(domains)) => + .is_none_or( |domains| report.inner.has_domain(domains)) => { Ok(JsonResponse::new(json!({ "data": report.inner, @@ -171,7 +171,7 @@ impl ManageReports for Server { Some(report) if tenant_domains .as_ref() - .map_or(true, |domains| report.inner.has_domain(domains)) => + .is_none_or( |domains| report.inner.has_domain(domains)) => { Ok(JsonResponse::new(json!({ "data": report.inner, @@ -253,7 +253,7 @@ impl ManageReports for Server { ValueClass::Report(report_id.clone()), )) .await? - .map_or(true, |report| report.inner.has_domain(domains)), + .is_none_or( |report| report.inner.has_domain(domains)), ReportClass::Dmarc { .. } => self .core .storage @@ -262,7 +262,7 @@ impl ManageReports for Server { ValueKey::from(ValueClass::Report(report_id.clone())), ) .await? - .map_or(true, |report| report.inner.has_domain(domains)), + .is_none_or( |report| report.inner.has_domain(domains)), ReportClass::Arf { .. } => self .core @@ -272,7 +272,7 @@ impl ManageReports for Server { ValueClass::Report(report_id.clone()), )) .await? - .map_or(true, |report| report.inner.has_domain(domains)), + .is_none_or( |report| report.inner.has_domain(domains)), }; if !is_tenant_report { @@ -388,30 +388,30 @@ async fn fetch_incoming_reports( .caused_by(trc::location!())? .inner; - filter.map_or(true, |f| report.contains(f)) + filter.is_none_or( |f| report.contains(f)) && tenant_domains .as_ref() - .map_or(true, |domains| report.has_domain(domains)) + .is_none_or( |domains| report.has_domain(domains)) } ReportType::Tls => { let report = Bincode::>::deserialize(value) .caused_by(trc::location!())? .inner; - filter.map_or(true, |f| report.contains(f)) + filter.is_none_or( |f| report.contains(f)) && tenant_domains .as_ref() - .map_or(true, |domains| report.has_domain(domains)) + .is_none_or( |domains| report.has_domain(domains)) } ReportType::Arf => { let report = Bincode::>::deserialize(value) .caused_by(trc::location!())? .inner; - filter.map_or(true, |f| report.contains(f)) + filter.is_none_or( |f| report.contains(f)) && tenant_domains .as_ref() - .map_or(true, |domains| report.has_domain(domains)) + .is_none_or( |domains| report.has_domain(domains)) } } } else { diff --git a/crates/jmap/src/api/management/settings.rs b/crates/jmap/src/api/management/settings.rs index ff41763d..fe69140a 100644 --- a/crates/jmap/src/api/management/settings.rs +++ b/crates/jmap/src/api/management/settings.rs @@ -119,7 +119,7 @@ impl ManageSettings for Server { record.insert("_id".to_string(), id.to_string()); for (k, v) in &settings { if let Some(k) = k.strip_prefix(&prefix) { - if field.map_or(true, |field| field == k) { + if field.is_none_or( |field| field == k) { record.insert(k.to_string(), v.to_string()); } } else if record.len() > 1 { diff --git a/crates/jmap/src/auth/oauth/auth.rs b/crates/jmap/src/auth/oauth/auth.rs index 3fa4518c..d28ec80e 100644 --- a/crates/jmap/src/auth/oauth/auth.rs +++ b/crates/jmap/src/auth/oauth/auth.rs @@ -7,32 +7,31 @@ use std::sync::Arc; use common::{ + KV_OAUTH, Server, auth::{ - oauth::{CLIENT_ID_MAX_LEN, DEVICE_CODE_LEN, USER_CODE_ALPHABET, USER_CODE_LEN}, AccessToken, + oauth::{CLIENT_ID_MAX_LEN, DEVICE_CODE_LEN, USER_CODE_ALPHABET, USER_CODE_LEN}, }, - Server, KV_OAUTH, }; -use rand::distributions::Standard; +use rand::{ + Rng, + distr::{Alphanumeric, StandardUniform}, + rng, +}; use serde::Deserialize; use serde_json::json; use std::future::Future; -use store::{ - dispatch::lookup::KeyValue, - rand::{distributions::Alphanumeric, thread_rng, Rng}, - write::Bincode, - Serialize, -}; +use store::{Serialize, dispatch::lookup::KeyValue, write::Bincode}; use crate::{ api::{ - http::{HttpContext, HttpSessionData, ToHttpResponse}, HttpRequest, HttpResponse, JsonResponse, + http::{HttpContext, HttpSessionData, ToHttpResponse}, }, auth::oauth::OAuthStatus, }; -use super::{DeviceAuthResponse, FormData, OAuthCode, OAuthCodeRequest, MAX_POST_LEN}; +use super::{DeviceAuthResponse, FormData, MAX_POST_LEN, OAuthCode, OAuthCodeRequest}; #[derive(Debug, serde::Serialize, Deserialize)] pub struct OAuthMetadata { @@ -100,7 +99,7 @@ impl OAuthApiHandler for Server { } // Generate client code - let client_code = thread_rng() + let client_code = rng() .sample_iter(Alphanumeric) .take(DEVICE_CODE_LEN) .map(char::from) @@ -210,7 +209,7 @@ impl OAuthApiHandler for Server { let nonce = form_data.remove("nonce"); // Generate device code - let device_code = thread_rng() + let device_code = rng() .sample_iter(Alphanumeric) .take(DEVICE_CODE_LEN) .map(char::from) @@ -218,10 +217,10 @@ impl OAuthApiHandler for Server { // Generate user code let mut user_code = String::with_capacity(USER_CODE_LEN + 1); - for (pos, ch) in thread_rng() - .sample_iter::(Standard) + for (pos, ch) in rng() + .sample_iter(StandardUniform) .take(USER_CODE_LEN) - .map(|v| char::from(USER_CODE_ALPHABET[v % USER_CODE_ALPHABET.len()])) + .map(|v: u64| char::from(USER_CODE_ALPHABET[v as usize % USER_CODE_ALPHABET.len()])) .enumerate() { if pos == USER_CODE_LEN / 2 { diff --git a/crates/jmap/src/auth/oauth/registration.rs b/crates/jmap/src/auth/oauth/registration.rs index 428acf82..f84bd291 100644 --- a/crates/jmap/src/auth/oauth/registration.rs +++ b/crates/jmap/src/auth/oauth/registration.rs @@ -7,20 +7,20 @@ use std::future::Future; use common::{ - auth::oauth::registration::{ClientRegistrationRequest, ClientRegistrationResponse}, Server, + auth::oauth::registration::{ClientRegistrationRequest, ClientRegistrationResponse}, }; use directory::{ - backend::internal::{lookup::DirectoryStore, manage::ManageDirectory, PrincipalField}, Permission, Principal, QueryBy, Type, + backend::internal::{PrincipalField, lookup::DirectoryStore, manage::ManageDirectory}, }; -use rand::{distributions::Alphanumeric, thread_rng, Rng}; +use rand::{Rng, distr::Alphanumeric, rng}; use trc::{AddContext, AuthEvent}; use crate::{ api::{ - http::{fetch_body, HttpSessionData, ToHttpResponse}, HttpRequest, HttpResponse, JsonResponse, + http::{HttpSessionData, ToHttpResponse, fetch_body}, }, auth::{authenticate::Authenticator, rate_limit::RateLimiter}, }; @@ -68,7 +68,7 @@ impl ClientRegistrationHandler for Server { })?; // Generate client ID - let client_id = thread_rng() + let client_id = rng() .sample_iter(Alphanumeric) .take(20) .map(|ch| char::from(ch.to_ascii_lowercase())) diff --git a/crates/jmap/src/email/delete.rs b/crates/jmap/src/email/delete.rs index 54f43dc5..d421be88 100644 --- a/crates/jmap/src/email/delete.rs +++ b/crates/jmap/src/email/delete.rs @@ -6,10 +6,10 @@ use std::time::Duration; -use common::{Server, KV_LOCK_PURGE_ACCOUNT}; +use common::{KV_LOCK_PURGE_ACCOUNT, Server}; use email::{ index::EmailIndexBuilder, - mailbox::{UidMailbox, JUNK_ID, TOMBSTONE_ID, TRASH_ID}, + mailbox::{JUNK_ID, TOMBSTONE_ID, TRASH_ID, UidMailbox}, metadata::MessageMetadata, }; use jmap_proto::types::{ @@ -17,13 +17,13 @@ use jmap_proto::types::{ type_state::DataType, }; use store::{ + BitmapKey, IterateParams, U32_LEN, ValueKey, ahash::AHashMap, roaring::RoaringBitmap, write::{ - log::ChangeLogBuilder, BatchBuilder, Bincode, BitmapClass, MaybeDynamicId, TagValue, - ValueClass, F_BITMAP, F_CLEAR, F_VALUE, + BatchBuilder, Bincode, BitmapClass, F_BITMAP, F_CLEAR, F_VALUE, MaybeDynamicId, TagValue, + ValueClass, log::ChangeLogBuilder, }, - BitmapKey, IterateParams, ValueKey, U32_LEN, }; use trc::{AddContext, StoreEvent}; use utils::codec::leb128::Leb128Reader; @@ -238,7 +238,7 @@ impl EmailDeletion for Server { let mut account_ids: Vec = account_ids.into_iter().collect(); // Shuffle account ids - account_ids.shuffle(&mut rand::thread_rng()); + account_ids.shuffle(&mut rand::rng()); for account_id in account_ids { self.purge_account(account_id).await; @@ -261,9 +261,10 @@ impl EmailDeletion for Server { return; } Err(err) => { - trc::error!(err - .details("Failed to lock account.") - .account_id(account_id)); + trc::error!( + err.details("Failed to lock account.") + .account_id(account_id) + ); return; } } @@ -271,25 +272,28 @@ impl EmailDeletion for Server { // Auto-expunge deleted and junk messages if let Some(period) = self.core.jmap.mail_autoexpunge_after { if let Err(err) = self.emails_auto_expunge(account_id, period).await { - trc::error!(err - .details("Failed to auto-expunge messages.") - .account_id(account_id)); + trc::error!( + err.details("Failed to auto-expunge messages.") + .account_id(account_id) + ); } } // Purge tombstoned messages if let Err(err) = self.emails_purge_tombstoned(account_id).await { - trc::error!(err - .details("Failed to purge tombstoned messages.") - .account_id(account_id)); + trc::error!( + err.details("Failed to purge tombstoned messages.") + .account_id(account_id) + ); } // Purge changelogs if let Some(history) = self.core.jmap.changes_max_history { if let Err(err) = self.delete_changes(account_id, history).await { - trc::error!(err - .details("Failed to purge changes.") - .account_id(account_id)); + trc::error!( + err.details("Failed to purge changes.") + .account_id(account_id) + ); } } diff --git a/crates/jmap/src/push/ece.rs b/crates/jmap/src/push/ece.rs index 03bc4158..33bb467f 100644 --- a/crates/jmap/src/push/ece.rs +++ b/crates/jmap/src/push/ece.rs @@ -5,14 +5,14 @@ */ use aes_gcm::{ - aead::{generic_array::GenericArray, Aead}, Aes128Gcm, Nonce, + aead::{Aead, generic_array::GenericArray}, }; use hkdf::Hkdf; use p256::{ + PublicKey, ecdh::EphemeralSecret, elliptic_curve::{rand_core::OsRng, sec1::ToEncodedPoint}, - PublicKey, }; use sha2::Sha256; use store::rand::Rng; @@ -45,7 +45,7 @@ pub fn ece_encrypt( client_auth_secret: &[u8], mut data: &[u8], ) -> Result, String> { - let salt = store::rand::thread_rng().gen::<[u8; 16]>(); + let salt = store::rand::rng().random::<[u8; 16]>(); let server_secret = EphemeralSecret::random(&mut OsRng); let server_public_key = server_secret.public_key(); let server_public_key_bytes = server_public_key.to_encoded_point(false); diff --git a/crates/jmap/src/push/set.rs b/crates/jmap/src/push/set.rs index 78ca5540..29427de3 100644 --- a/crates/jmap/src/push/set.rs +++ b/crates/jmap/src/push/set.rs @@ -4,8 +4,8 @@ * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ -use base64::{engine::general_purpose, Engine}; -use common::{auth::AccessToken, Server}; +use base64::{Engine, engine::general_purpose}; +use common::{Server, auth::AccessToken}; use jmap_proto::{ error::set::SetError, method::set::{RequestArguments, SetRequest, SetResponse}, @@ -19,10 +19,11 @@ use jmap_proto::{ value::{MaybePatchValue, Value}, }, }; +use rand::distr::Alphanumeric; use std::future::Future; use store::{ - rand::{distributions::Alphanumeric, thread_rng, Rng}, - write::{now, BatchBuilder, F_CLEAR, F_VALUE}, + rand::{Rng, rng}, + write::{BatchBuilder, F_CLEAR, F_VALUE, now}, }; use trc::AddContext; @@ -105,7 +106,7 @@ impl PushSubscriptionSet for Server { push.append( Property::Value, Value::Text( - thread_rng() + rng() .sample_iter(Alphanumeric) .take(VERIFICATION_CODE_LEN) .map(char::from) diff --git a/crates/jmap/src/services/index.rs b/crates/jmap/src/services/index.rs index 803d5655..07f7889d 100644 --- a/crates/jmap/src/services/index.rs +++ b/crates/jmap/src/services/index.rs @@ -113,7 +113,7 @@ impl Indexer for Server { let entry = EmailTask::deserialize(key)?; if locked_seq_ids .get(&entry.seq) - .map_or(true, |expires| now >= *expires) + .is_none_or( |expires| now >= *expires) { entries.push(entry); } diff --git a/crates/jmap/src/sieve/set.rs b/crates/jmap/src/sieve/set.rs index 01254395..3e0e9a55 100644 --- a/crates/jmap/src/sieve/set.rs +++ b/crates/jmap/src/sieve/set.rs @@ -5,16 +5,16 @@ */ use common::{ - auth::{AccessToken, ResourceToken}, Server, + auth::{AccessToken, ResourceToken}, }; use jmap_proto::{ error::set::{SetError, SetErrorType}, method::set::{SetRequest, SetResponse}, object::{ + Object, index::{IndexAs, IndexProperty, ObjectIndexBuilder}, sieve::SetArguments, - Object, }, request::reference::MaybeReference, response::references::EvalObjectReferences, @@ -26,19 +26,20 @@ use jmap_proto::{ value::{MaybePatchValue, SetValue, Value}, }, }; +use rand::distr::Alphanumeric; use sieve::compiler::ErrorType; use store::{ - query::Filter, - rand::{distributions::Alphanumeric, thread_rng, Rng}, - write::{ - assert::HashedValue, log::ChangeLogBuilder, BatchBuilder, BlobOp, DirectoryClass, F_CLEAR, - F_VALUE, - }, BlobClass, + query::Filter, + rand::{Rng, rng}, + write::{ + BatchBuilder, BlobOp, DirectoryClass, F_CLEAR, F_VALUE, assert::HashedValue, + log::ChangeLogBuilder, + }, }; use trc::AddContext; -use crate::{api::http::HttpSessionData, blob::download::BlobDownload, JmapMethods}; +use crate::{JmapMethods, api::http::HttpSessionData, blob::download::BlobDownload}; use std::future::Future; pub struct SetContext<'x> { @@ -493,8 +494,7 @@ impl SieveScriptSet for Server { } else if update .as_ref() .and_then(|(_, obj)| obj.inner.properties.get(&Property::Name)) - .map_or( - true, + .is_none_or( |p| matches!(p, Value::Text (prev_value ) if prev_value != &value), ) { @@ -529,7 +529,7 @@ impl SieveScriptSet for Server { _ => { return Ok(Err(SetError::invalid_properties() .with_property(property) - .with_description("Invalid property or value.".to_string()))) + .with_description("Invalid property or value.".to_string()))); } }; changes.append(property, value); @@ -542,7 +542,7 @@ impl SieveScriptSet for Server { changes.set( Property::Name, Value::Text( - thread_rng() + rng() .sample_iter(Alphanumeric) .take(15) .map(char::from) @@ -556,7 +556,7 @@ impl SieveScriptSet for Server { } let blob_update = if let Some(blob_id) = blob_id { - if update.as_ref().map_or(true, |(document_id, _)| { + if update.as_ref().is_none_or( |(document_id, _)| { !matches!(blob_id.class, BlobClass::Linked { account_id, collection, document_id: d } if account_id == ctx.resource_token.account_id && collection == u8::from(Collection::SieveScript) && *document_id == d) }) { // Check access diff --git a/crates/jmap/src/thread/get.rs b/crates/jmap/src/thread/get.rs index 4d6d090e..ebc1036f 100644 --- a/crates/jmap/src/thread/get.rs +++ b/crates/jmap/src/thread/get.rs @@ -42,7 +42,7 @@ impl ThreadGet for Server { }; let add_email_ids = request .properties - .map_or(true, |p| p.unwrap().contains(&Property::EmailIds)); + .is_none_or( |p| p.unwrap().contains(&Property::EmailIds)); let mut response = GetResponse { account_id: request.account_id.into(), state: self.get_state(account_id, Collection::Thread).await?.into(), diff --git a/crates/main/Cargo.toml b/crates/main/Cargo.toml index 036d2dcf..657115be 100644 --- a/crates/main/Cargo.toml +++ b/crates/main/Cargo.toml @@ -8,7 +8,7 @@ keywords = ["imap", "jmap", "smtp", "email", "mail", "server"] categories = ["email"] license = "AGPL-3.0-only OR LicenseRef-SEL" version = "0.11.5" -edition = "2021" +edition = "2024" resolver = "2" [[bin]] diff --git a/crates/managesieve/Cargo.toml b/crates/managesieve/Cargo.toml index 650ab23b..955f7f09 100644 --- a/crates/managesieve/Cargo.toml +++ b/crates/managesieve/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "managesieve" version = "0.11.5" -edition = "2021" +edition = "2024" resolver = "2" [dependencies] diff --git a/crates/nlp/Cargo.toml b/crates/nlp/Cargo.toml index b2259b3f..a9ea2bf6 100644 --- a/crates/nlp/Cargo.toml +++ b/crates/nlp/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "nlp" version = "0.11.5" -edition = "2021" +edition = "2024" resolver = "2" [dependencies] diff --git a/crates/nlp/src/bayes/mod.rs b/crates/nlp/src/bayes/mod.rs index 10578b68..d5dfce94 100644 --- a/crates/nlp/src/bayes/mod.rs +++ b/crates/nlp/src/bayes/mod.rs @@ -139,7 +139,7 @@ impl From for Weights { impl From for i64 { fn from(value: Weights) -> Self { - (value.ham as i64) << 32 | value.spam as i64 + ((value.ham as i64) << 32) | value.spam as i64 } } diff --git a/crates/pop3/Cargo.toml b/crates/pop3/Cargo.toml index 5f86ed00..ff9c1ec2 100644 --- a/crates/pop3/Cargo.toml +++ b/crates/pop3/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "pop3" version = "0.11.5" -edition = "2021" +edition = "2024" resolver = "2" [dependencies] diff --git a/crates/smtp/Cargo.toml b/crates/smtp/Cargo.toml index 5997c1c3..c013eb68 100644 --- a/crates/smtp/Cargo.toml +++ b/crates/smtp/Cargo.toml @@ -8,7 +8,7 @@ keywords = ["smtp", "email", "mail", "server"] categories = ["email"] license = "AGPL-3.0-only OR LicenseRef-SEL" version = "0.11.5" -edition = "2021" +edition = "2024" resolver = "2" [dependencies] @@ -45,7 +45,7 @@ parking_lot = "0.12" regex = "1.7.0" blake3 = "1.3" lru-cache = "0.1.2" -rand = "0.8.5" +rand = "0.9.0" x509-parser = "0.16.0" reqwest = { version = "0.12", default-features = false, features = ["rustls-tls-webpki-roots", "http2"] } serde = { version = "1.0", features = ["derive", "rc"] } diff --git a/crates/smtp/src/core/mod.rs b/crates/smtp/src/core/mod.rs index 138b6965..7e5ac27f 100644 --- a/crates/smtp/src/core/mod.rs +++ b/crates/smtp/src/core/mod.rs @@ -250,7 +250,7 @@ impl Session { } pub fn has_failed(&mut self) -> Option { - if self.stream.tx_buf.first().map_or(true, |&c| c == b'2') { + if self.stream.tx_buf.first().is_none_or( |&c| c == b'2') { self.stream.tx_buf.clear(); None } else { diff --git a/crates/smtp/src/inbound/data.rs b/crates/smtp/src/inbound/data.rs index 93678ef1..eb9465d3 100644 --- a/crates/smtp/src/inbound/data.rs +++ b/crates/smtp/src/inbound/data.rs @@ -727,7 +727,7 @@ impl Session { if message .domains .last() - .map_or(true, |d| d.domain != rcpt.domain) + .is_none_or( |d| d.domain != rcpt.domain) { let rcpt_idx = message.domains.len(); message.domains.push(queue::Domain { diff --git a/crates/smtp/src/outbound/delivery.rs b/crates/smtp/src/outbound/delivery.rs index 225473fa..68c341d5 100644 --- a/crates/smtp/src/outbound/delivery.rs +++ b/crates/smtp/src/outbound/delivery.rs @@ -116,7 +116,7 @@ impl QueuedMessage { } } else { QueueEventStatus::Locked { - until: now() + LOCK_EXPIRY + rand::thread_rng().gen_range(5..10), + until: now() + LOCK_EXPIRY + rand::rng().random_range(5..10), } }; diff --git a/crates/smtp/src/outbound/lookup.rs b/crates/smtp/src/outbound/lookup.rs index 791ede86..c18800c7 100644 --- a/crates/smtp/src/outbound/lookup.rs +++ b/crates/smtp/src/outbound/lookup.rs @@ -11,11 +11,11 @@ use std::{ }; use common::{ - expr::{functions::ResolveVariable, V_MX}, Server, + expr::{V_MX, functions::ResolveVariable}, }; use mail_auth::{IpLookupStrategy, MX}; -use rand::{seq::SliceRandom, Rng}; +use rand::{Rng, seq::SliceRandom}; use crate::queue::{Error, ErrorDetails, Status}; @@ -166,7 +166,7 @@ impl DnsLookup for Server { } std::cmp::Ordering::Greater => { result.source_ipv4 = - IpAddr::from(source_ips[rand::thread_rng().gen_range(0..source_ips.len())]) + IpAddr::from(source_ips[rand::rng().random_range(0..source_ips.len())]) .into(); } std::cmp::Ordering::Less => (), @@ -187,7 +187,7 @@ impl DnsLookup for Server { } std::cmp::Ordering::Greater => { result.source_ipv6 = - IpAddr::from(source_ips[rand::thread_rng().gen_range(0..source_ips.len())]) + IpAddr::from(source_ips[rand::rng().random_range(0..source_ips.len())]) .into(); } std::cmp::Ordering::Less => (), @@ -224,7 +224,7 @@ impl ToNextHop for Vec { 'outer: for mx in self.iter() { if mx.exchanges.len() > 1 { let mut slice = mx.exchanges.iter().collect::>(); - slice.shuffle(&mut rand::thread_rng()); + slice.shuffle(&mut rand::rng()); for remote_host in slice { remote_hosts.push(NextHop::MX(remote_host.as_str())); if remote_hosts.len() == max_mx { diff --git a/crates/smtp/src/queue/manager.rs b/crates/smtp/src/queue/manager.rs index 02f9b7aa..c56760da 100644 --- a/crates/smtp/src/queue/manager.rs +++ b/crates/smtp/src/queue/manager.rs @@ -5,24 +5,24 @@ */ use std::{ - sync::{atomic::Ordering, Arc}, + sync::{Arc, atomic::Ordering}, time::{Duration, Instant}, }; use ahash::{AHashMap, AHashSet}; use common::{ + Inner, core::BuildServer, ipc::{QueueEvent, QueueEventStatus}, listener::limiter::ConcurrencyLimiter, - Inner, }; use rand::seq::SliceRandom; use store::write::now; use tokio::sync::mpsc; use super::{ - spool::{SmtpSpool, QUEUE_REFRESH}, Message, QueueId, Status, + spool::{QUEUE_REFRESH, SmtpSpool}, }; pub struct Queue { @@ -161,7 +161,7 @@ impl Queue { let mut queue_events = server.next_event().await; if queue_events.len() > 5 { - queue_events.shuffle(&mut rand::thread_rng()); + queue_events.shuffle(&mut rand::rng()); } for queue_event in &queue_events { @@ -183,7 +183,9 @@ impl Queue { .fold([0, 0, 0], |mut acc, v| { match v { OnHold::InFlight => acc[0] += 1, - OnHold::ConcurrencyLimited { .. } => acc[1] += 1, + OnHold::ConcurrencyLimited { .. } => { + acc[1] += 1 + } OnHold::Locked { .. } => acc[2] += 1, } acc @@ -289,11 +291,7 @@ impl Message { } } - if has_events { - next_event.into() - } else { - None - } + if has_events { next_event.into() } else { None } } pub fn next_delivery_event(&self) -> u64 { @@ -356,21 +354,19 @@ impl Message { Status::Scheduled | Status::TemporaryFailure(_) ) { if domain.retry.due > instant - && next_event - .as_ref() - .map_or(true, |ne| domain.retry.due.lt(ne)) + && next_event.as_ref().is_none_or(|ne| domain.retry.due.lt(ne)) { next_event = domain.retry.due.into(); } if domain.notify.due > instant && next_event .as_ref() - .map_or(true, |ne| domain.notify.due.lt(ne)) + .is_none_or(|ne| domain.notify.due.lt(ne)) { next_event = domain.notify.due.into(); } if domain.expires > instant - && next_event.as_ref().map_or(true, |ne| domain.expires.lt(ne)) + && next_event.as_ref().is_none_or(|ne| domain.expires.lt(ne)) { next_event = domain.expires.into(); } diff --git a/crates/smtp/src/reporting/dmarc.rs b/crates/smtp/src/reporting/dmarc.rs index 9b4cf48d..b55a0757 100644 --- a/crates/smtp/src/reporting/dmarc.rs +++ b/crates/smtp/src/reporting/dmarc.rs @@ -551,7 +551,7 @@ impl DmarcReporting for Server { Entry::Vacant(e) => { if serialized_size .as_deref_mut() - .map_or(true, |serialized_size| { + .is_none_or( |serialized_size| { serde::Serialize::serialize(e.key(), serialized_size).is_ok() }) { diff --git a/crates/smtp/src/reporting/mod.rs b/crates/smtp/src/reporting/mod.rs index 674e13af..4160286d 100644 --- a/crates/smtp/src/reporting/mod.rs +++ b/crates/smtp/src/reporting/mod.rs @@ -138,7 +138,7 @@ impl SmtpReporting for Server { { use rand::Rng; - let delivery_time = rand::thread_rng().gen_range(0u64..10800u64); + let delivery_time = rand::rng().random_range(0u64..10800u64); for domain in &mut message.domains { domain.retry.due += delivery_time; domain.expires += delivery_time; diff --git a/crates/smtp/src/reporting/tls.rs b/crates/smtp/src/reporting/tls.rs index a389c5e3..1da29ea9 100644 --- a/crates/smtp/src/reporting/tls.rs +++ b/crates/smtp/src/reporting/tls.rs @@ -348,7 +348,7 @@ impl TlsReporting for Server { Entry::Vacant(e) => { if serialized_size .as_deref_mut() - .map_or(true, |serialized_size| { + .is_none_or( |serialized_size| { serde::Serialize::serialize(e.key(), serialized_size) .is_ok() }) diff --git a/crates/spam-filter/Cargo.toml b/crates/spam-filter/Cargo.toml index f5b63353..e9c15754 100644 --- a/crates/spam-filter/Cargo.toml +++ b/crates/spam-filter/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "spam-filter" version = "0.11.5" -edition = "2021" +edition = "2024" resolver = "2" [dependencies] diff --git a/crates/spam-filter/src/analysis/mime.rs b/crates/spam-filter/src/analysis/mime.rs index 67a58db7..d9a81fcc 100644 --- a/crates/spam-filter/src/analysis/mime.rs +++ b/crates/spam-filter/src/analysis/mime.rs @@ -7,11 +7,11 @@ use std::{collections::HashSet, future::Future, vec}; use common::{ - scripts::{ - functions::{array::cosine_similarity, unicode::CharUtils}, - IsMixedCharset, - }, Server, + scripts::{ + IsMixedCharset, + functions::{array::cosine_similarity, unicode::CharUtils}, + }, }; use mail_parser::{HeaderName, MimeHeaders, PartType}; use nlp::tokenizers::types::TokenType; @@ -291,7 +291,7 @@ impl SpamFilterAnalyzeMime for Server { && ct_subtype == "plain" && ct .and_then(|ct| ct.attribute("charset")) - .map_or(true, |c| c.is_empty()) + .is_none_or(|c| c.is_empty()) { // Charset header is missing ctx.result.add_tag("MISSING_CHARSET"); @@ -339,7 +339,7 @@ impl SpamFilterAnalyzeMime for Server { "octet-stream" => { if !is_encrypted && !has_content_id - && cd.map_or(true, |cd| { + && cd.is_none_or(|cd| { !cd.c_type.eq_ignore_ascii_case("attachment") && !cd.has_attribute("filename") }) diff --git a/crates/spam-filter/src/analysis/recipient.rs b/crates/spam-filter/src/analysis/recipient.rs index 2cb66b66..a1d87e15 100644 --- a/crates/spam-filter/src/analysis/recipient.rs +++ b/crates/spam-filter/src/analysis/recipient.rs @@ -6,7 +6,7 @@ use std::future::Future; -use common::{scripts::functions::text::levenshtein_distance, Server}; +use common::{Server, scripts::functions::text::levenshtein_distance}; use mail_parser::HeaderName; use smtp_proto::{MAIL_BODY_8BITMIME, MAIL_BODY_BINARYMIME, MAIL_SMTPUTF8}; use store::ahash::HashSet; @@ -85,7 +85,7 @@ impl SpamFilterAnalyzeRecipient for Server { // Validate unnecessary encoding in recipient headers let raw_utf8 = raw_utf8.unwrap_or_default(); if recipients.iter().all(|rcpt| { - rcpt.name.as_ref().map_or(true, |name| name.is_ascii()) + rcpt.name.as_ref().is_none_or(|name| name.is_ascii()) && rcpt.email.address.is_ascii() }) && raw_utf8.contains("=?") && raw_utf8.contains("?=") diff --git a/crates/spam-filter/src/modules/bayes.rs b/crates/spam-filter/src/modules/bayes.rs index d9168058..65fedbf1 100644 --- a/crates/spam-filter/src/modules/bayes.rs +++ b/crates/spam-filter/src/modules/bayes.rs @@ -6,12 +6,12 @@ use std::{borrow::Cow, collections::HashSet, future::Future, time::Duration}; -use common::{ip_to_bytes, Server, KV_BAYES_MODEL_GLOBAL, KV_BAYES_MODEL_USER}; +use common::{KV_BAYES_MODEL_GLOBAL, KV_BAYES_MODEL_USER, Server, ip_to_bytes}; use mail_auth::DmarcResult; use nlp::{ bayes::{ - tokenize::{symbols, BayesInputToken, BayesTokenizer}, BayesModel, TokenHash, Weights, + tokenize::{BayesInputToken, BayesTokenizer, symbols}, }, tokenizers::{ osb::{Gram, OsbToken, OsbTokenizer}, @@ -22,7 +22,7 @@ use store::dispatch::lookup::KeyValue; use trc::AddContext; use utils::cache::TtlEntry; -use crate::{analysis::url::UrlParts, Email, IpParts, SpamFilterContext, TextPart}; +use crate::{Email, IpParts, SpamFilterContext, TextPart, analysis::url::UrlParts}; pub trait BayesClassifier { fn bayes_train( @@ -116,9 +116,11 @@ impl BayesClassifier for Server { } if model.weights.is_empty() { - trc::bail!(trc::SpamEvent::TrainError - .into_err() - .reason("No weights found")); + trc::bail!( + trc::SpamEvent::TrainError + .into_err() + .reason("No weights found") + ); } trc::event!( @@ -216,8 +218,7 @@ impl BayesClassifier for Server { ctx.input.account_id, TokenHash::from(Gram::Uni { t1: &token }), ) - .await - .map(Weights::from)?; + .await?; osb_tokens.push(OsbToken { inner: weights, idx: 1, @@ -234,8 +235,7 @@ impl BayesClassifier for Server { ) { let weights = self .bayes_weights_for_token(ctx.input.account_id, token.inner) - .await - .map(Weights::from)?; + .await?; osb_tokens.push(OsbToken { inner: weights, idx: token.idx, @@ -260,8 +260,7 @@ impl BayesClassifier for Server { ) { let weights = self .bayes_weights_for_token(ctx.input.account_id, token.inner) - .await - .map(Weights::from)?; + .await?; osb_tokens.push(OsbToken { inner: weights, idx: token.idx, @@ -275,8 +274,7 @@ impl BayesClassifier for Server { ) { let weights = self .bayes_weights_for_token(ctx.input.account_id, token.inner) - .await - .map(Weights::from)?; + .await?; osb_tokens.push(OsbToken { inner: weights, idx: token.idx, @@ -365,10 +363,11 @@ impl BayesClassifier for Server { }; if let Some(account_id) = ctx.input.account_id { - trc::error!(err - .span_id(ctx.input.span_id) - .account_id(account_id) - .caused_by(trc::location!())); + trc::error!( + err.span_id(ctx.input.span_id) + .account_id(account_id) + .caused_by(trc::location!()) + ); } else { trc::error!(err.span_id(ctx.input.span_id).caused_by(trc::location!())); } diff --git a/crates/spam-filter/src/modules/html.rs b/crates/spam-filter/src/modules/html.rs index ffe89378..63ab6d11 100644 --- a/crates/spam-filter/src/modules/html.rs +++ b/crates/spam-filter/src/modules/html.rs @@ -25,46 +25,46 @@ pub enum HtmlToken { } pub(crate) const A: u64 = b'a' as u64; -pub(crate) const IMG: u64 = (b'i' as u64) | (b'm' as u64) << 8 | (b'g' as u64) << 16; +pub(crate) const IMG: u64 = (b'i' as u64) | ((b'm' as u64) << 8) | ((b'g' as u64) << 16); pub(crate) const HEAD: u64 = - (b'h' as u64) | (b'e' as u64) << 8 | (b'a' as u64) << 16 | (b'd' as u64) << 24; + (b'h' as u64) | ((b'e' as u64) << 8) | ((b'a' as u64) << 16) | ((b'd' as u64) << 24); pub(crate) const BODY: u64 = - (b'b' as u64) | (b'o' as u64) << 8 | (b'd' as u64) << 16 | (b'y' as u64) << 24; + (b'b' as u64) | ((b'o' as u64) << 8) | ((b'd' as u64) << 16) | ((b'y' as u64) << 24); pub(crate) const META: u64 = - (b'm' as u64) | (b'e' as u64) << 8 | (b't' as u64) << 16 | (b'a' as u64) << 24; + (b'm' as u64) | ((b'e' as u64) << 8) | ((b't' as u64) << 16) | ((b'a' as u64) << 24); pub(crate) const LINK: u64 = - (b'l' as u64) | (b'i' as u64) << 8 | (b'n' as u64) << 16 | (b'k' as u64) << 24; + (b'l' as u64) | ((b'i' as u64) << 8) | ((b'n' as u64) << 16) | ((b'k' as u64) << 24); pub(crate) const HREF: u64 = - (b'h' as u64) | (b'r' as u64) << 8 | (b'e' as u64) << 16 | (b'f' as u64) << 24; -pub(crate) const SRC: u64 = (b's' as u64) | (b'r' as u64) << 8 | (b'c' as u64) << 16; + (b'h' as u64) | ((b'r' as u64) << 8) | ((b'e' as u64) << 16) | ((b'f' as u64) << 24); +pub(crate) const SRC: u64 = (b's' as u64) | ((b'r' as u64) << 8) | ((b'c' as u64) << 16); pub(crate) const WIDTH: u64 = (b'w' as u64) - | (b'i' as u64) << 8 - | (b'd' as u64) << 16 - | (b't' as u64) << 24 - | (b'h' as u64) << 32; + | ((b'i' as u64) << 8) + | ((b'd' as u64) << 16) + | ((b't' as u64) << 24) + | ((b'h' as u64) << 32); pub(crate) const HEIGHT: u64 = (b'h' as u64) - | (b'e' as u64) << 8 - | (b'i' as u64) << 16 - | (b'g' as u64) << 24 - | (b'h' as u64) << 32 - | (b't' as u64) << 40; -pub(crate) const REL: u64 = (b'r' as u64) | (b'e' as u64) << 8 | (b'l' as u64) << 16; + | ((b'e' as u64) << 8) + | ((b'i' as u64) << 16) + | ((b'g' as u64) << 24) + | ((b'h' as u64) << 32) + | ((b't' as u64) << 40); +pub(crate) const REL: u64 = (b'r' as u64) | ((b'e' as u64) << 8) | ((b'l' as u64) << 16); pub(crate) const CONTENT: u64 = (b'c' as u64) - | (b'o' as u64) << 8 - | (b'n' as u64) << 16 - | (b't' as u64) << 24 - | (b'e' as u64) << 32 - | (b'n' as u64) << 40 - | (b't' as u64) << 48; + | ((b'o' as u64) << 8) + | ((b'n' as u64) << 16) + | ((b't' as u64) << 24) + | ((b'e' as u64) << 32) + | ((b'n' as u64) << 40) + | ((b't' as u64) << 48); pub(crate) const HTTP_EQUIV: u64 = (b'h' as u64) - | (b't' as u64) << 8 - | (b't' as u64) << 16 - | (b'p' as u64) << 24 - | (b'-' as u64) << 32 - | (b'e' as u64) << 40 - | (b'q' as u64) << 48 - | (b'u' as u64) << 56; + | ((b't' as u64) << 8) + | ((b't' as u64) << 16) + | ((b'p' as u64) << 24) + | ((b'-' as u64) << 32) + | ((b'e' as u64) << 40) + | ((b'q' as u64) << 48) + | ((b'u' as u64) << 56); pub fn html_to_tokens(input: &str) -> Vec { let input = input.as_bytes(); @@ -98,7 +98,7 @@ pub fn html_to_tokens(input: &str) -> Vec { }); } - while matches!(iter.peek(), Some((_, &ch)) if ch.is_ascii_whitespace()) { + while matches!(iter.peek(), Some(&(_, &ch)) if ch.is_ascii_whitespace()) { pos += 1; iter.next(); } @@ -135,7 +135,7 @@ pub fn html_to_tokens(input: &str) -> Vec { let mut is_end_tag = false; loop { match iter.peek() { - Some((_, &b'/')) => { + Some(&(_, &b'/')) => { is_end_tag = true; pos += 1; iter.next(); @@ -184,7 +184,7 @@ pub fn html_to_tokens(input: &str) -> Vec { in_quote = !in_quote; } b'=' if !in_quote => { - while matches!(iter.peek(), Some((_, &ch)) if ch.is_ascii_whitespace()) + while matches!(iter.peek(), Some(&(_, &ch)) if ch.is_ascii_whitespace()) { iter.next(); } diff --git a/crates/store/Cargo.toml b/crates/store/Cargo.toml index b0cf7d77..2df7e8e5 100644 --- a/crates/store/Cargo.toml +++ b/crates/store/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "store" version = "0.11.5" -edition = "2021" +edition = "2024" resolver = "2" [dependencies] @@ -19,7 +19,7 @@ reqwest = { version = "0.12", default-features = false, features = ["rustls-tls- tokio = { version = "1.23", features = ["sync", "fs", "io-util"] } r2d2 = { version = "0.8.10", optional = true } futures = { version = "0.3", optional = true } -rand = "0.8.5" +rand = "0.9.0" roaring = "0.10.1" rayon = { version = "1.5.1", optional = true } serde = { version = "1.0", features = ["derive"]} diff --git a/crates/store/src/backend/foundationdb/write.rs b/crates/store/src/backend/foundationdb/write.rs index beac4c37..38d66fe1 100644 --- a/crates/store/src/backend/foundationdb/write.rs +++ b/crates/store/src/backend/foundationdb/write.rs @@ -10,28 +10,27 @@ use std::{ }; use foundationdb::{ - options::{self, MutationType, StreamingMode}, FdbError, KeySelector, RangeOption, Transaction, + options::{self, MutationType, StreamingMode}, }; use futures::TryStreamExt; use rand::Rng; use roaring::RoaringBitmap; use crate::{ - backend::deserialize_i64_le, - write::{ - key::{DeserializeBigEndian, KeySerializer}, - AssignedIds, Batch, BitmapClass, Operation, RandomAvailableId, ValueOp, - MAX_COMMIT_ATTEMPTS, MAX_COMMIT_TIME, - }, BitmapKey, IndexKey, Key, LogKey, SUBSPACE_COUNTER, SUBSPACE_IN_MEMORY_COUNTER, SUBSPACE_QUOTA, U32_LEN, WITH_SUBSPACE, + backend::deserialize_i64_le, + write::{ + AssignedIds, Batch, BitmapClass, MAX_COMMIT_ATTEMPTS, MAX_COMMIT_TIME, Operation, + RandomAvailableId, ValueOp, + key::{DeserializeBigEndian, KeySerializer}, + }, }; use super::{ - into_error, - read::{read_chunked_value, ChunkedValue}, - FdbStore, ReadVersion, MAX_VALUE_SIZE, + FdbStore, MAX_VALUE_SIZE, ReadVersion, into_error, + read::{ChunkedValue, read_chunked_value}, }; impl FdbStore { @@ -274,7 +273,7 @@ impl FdbStore { { return Ok(result); } else { - let backoff = rand::thread_rng().gen_range(50..=300); + let backoff = rand::rng().random_range(50..=300); tokio::time::sleep(Duration::from_millis(backoff)).await; retry_count += 1; } diff --git a/crates/store/src/backend/fs/mod.rs b/crates/store/src/backend/fs/mod.rs index fe106cbd..54a82747 100644 --- a/crates/store/src/backend/fs/mod.rs +++ b/crates/store/src/backend/fs/mod.rs @@ -12,7 +12,7 @@ use tokio::{ }; use utils::{ codec::base32_custom::Base32Writer, - config::{utils::AsKey, Config}, + config::{Config, utils::AsKey}, }; pub struct FsStore { diff --git a/crates/store/src/backend/http/lookup.rs b/crates/store/src/backend/http/lookup.rs index b817eab3..bb5c6104 100644 --- a/crates/store/src/backend/http/lookup.rs +++ b/crates/store/src/backend/http/lookup.rs @@ -6,15 +6,15 @@ use std::{ io::{BufRead, BufReader}, - sync::{atomic::Ordering, Arc}, + sync::{Arc, atomic::Ordering}, time::Instant, }; use ahash::AHashMap; -use rand::seq::SliceRandom; +use rand::seq::IndexedRandom; use utils::HttpLimitResponse; -use crate::{backend::http::HttpStoreFormat, write::now, Value}; +use crate::{Value, backend::http::HttpStoreFormat, write::now}; use super::HttpStore; @@ -89,7 +89,7 @@ impl HttpStoreGet for Arc { impl HttpStore { async fn try_refresh(&self) -> trc::Result>> { let time = Instant::now(); - let agent = BROWSER_USER_AGENTS.choose(&mut rand::thread_rng()).unwrap(); + let agent = BROWSER_USER_AGENTS.choose(&mut rand::rng()).unwrap(); let response = reqwest::Client::builder() .timeout(self.config.timeout) .user_agent(*agent) @@ -107,12 +107,14 @@ impl HttpStore { })?; if !response.status().is_success() { - trc::bail!(trc::StoreEvent::HttpStoreError - .into_err() - .ctx(trc::Key::Code, response.status().as_u16()) - .ctx(trc::Key::Url, self.config.url.to_string()) - .ctx(trc::Key::Elapsed, time.elapsed()) - .details("Failed to fetch HTTP list")); + trc::bail!( + trc::StoreEvent::HttpStoreError + .into_err() + .ctx(trc::Key::Code, response.status().as_u16()) + .ctx(trc::Key::Url, self.config.url.to_string()) + .ctx(trc::Key::Elapsed, time.elapsed()) + .details("Failed to fetch HTTP list") + ); } let bytes = response diff --git a/crates/store/src/backend/mysql/write.rs b/crates/store/src/backend/mysql/write.rs index a4db08aa..1c3c2d37 100644 --- a/crates/store/src/backend/mysql/write.rs +++ b/crates/store/src/backend/mysql/write.rs @@ -8,20 +8,20 @@ use std::time::{Duration, Instant}; use ahash::AHashMap; use futures::TryStreamExt; -use mysql_async::{params, prelude::Queryable, Conn, Error, IsolationLevel, TxOpts}; +use mysql_async::{Conn, Error, IsolationLevel, TxOpts, params, prelude::Queryable}; use rand::Rng; use roaring::RoaringBitmap; use crate::{ - write::{ - key::DeserializeBigEndian, AssignedIds, Batch, BitmapClass, Operation, RandomAvailableId, - ValueOp, MAX_COMMIT_ATTEMPTS, MAX_COMMIT_TIME, - }, BitmapKey, IndexKey, Key, LogKey, SUBSPACE_COUNTER, SUBSPACE_IN_MEMORY_COUNTER, SUBSPACE_QUOTA, U32_LEN, + write::{ + AssignedIds, Batch, BitmapClass, MAX_COMMIT_ATTEMPTS, MAX_COMMIT_TIME, Operation, + RandomAvailableId, ValueOp, key::DeserializeBigEndian, + }, }; -use super::{into_error, MysqlStore}; +use super::{MysqlStore, into_error}; #[derive(Debug)] enum CommitError { @@ -58,7 +58,7 @@ impl MysqlStore { } } - let backoff = rand::thread_rng().gen_range(50..=300); + let backoff = rand::rng().random_range(50..=300); tokio::time::sleep(Duration::from_millis(backoff)).await; retry_count += 1; } diff --git a/crates/store/src/backend/postgres/write.rs b/crates/store/src/backend/postgres/write.rs index 6a1728a0..b840eaf3 100644 --- a/crates/store/src/backend/postgres/write.rs +++ b/crates/store/src/backend/postgres/write.rs @@ -63,7 +63,7 @@ impl PostgresStore { } } - let backoff = rand::thread_rng().gen_range(50..=300); + let backoff = rand::rng().random_range(50..=300); tokio::time::sleep(Duration::from_millis(backoff)).await; retry_count += 1; } diff --git a/crates/store/src/backend/rocksdb/mod.rs b/crates/store/src/backend/rocksdb/mod.rs index 6e14130d..9d176492 100644 --- a/crates/store/src/backend/rocksdb/mod.rs +++ b/crates/store/src/backend/rocksdb/mod.rs @@ -26,7 +26,8 @@ pub(crate) trait CfHandle { impl CfHandle for OptimisticTransactionDB { #[inline(always)] fn subspace_handle(&self, subspace: u8) -> Arc> { - self.cf_handle(unsafe { std::str::from_utf8_unchecked(&[subspace]) }) + let subspace = &[subspace]; + self.cf_handle(unsafe { std::str::from_utf8_unchecked(subspace) }) .unwrap() } } diff --git a/crates/store/src/backend/rocksdb/write.rs b/crates/store/src/backend/rocksdb/write.rs index 2eb50807..97624d98 100644 --- a/crates/store/src/backend/rocksdb/write.rs +++ b/crates/store/src/backend/rocksdb/write.rs @@ -17,12 +17,15 @@ use rocksdb::{ OptimisticTransactionOptions, WriteOptions, }; -use super::{into_error, CfHandle, RocksDbStore, CF_INDEXES, CF_LOGS}; +use super::{CF_INDEXES, CF_LOGS, CfHandle, RocksDbStore, into_error}; use crate::{ - backend::deserialize_i64_le, write::{ - key::DeserializeBigEndian, AssignedIds, Batch, BitmapClass, Operation, RandomAvailableId, - ValueOp, MAX_COMMIT_ATTEMPTS, MAX_COMMIT_TIME, - }, BitmapKey, Deserialize, IndexKey, Key, LogKey, SUBSPACE_COUNTER, SUBSPACE_IN_MEMORY_COUNTER, SUBSPACE_QUOTA, U32_LEN + BitmapKey, Deserialize, IndexKey, Key, LogKey, SUBSPACE_COUNTER, SUBSPACE_IN_MEMORY_COUNTER, + SUBSPACE_QUOTA, U32_LEN, + backend::deserialize_i64_le, + write::{ + AssignedIds, Batch, BitmapClass, MAX_COMMIT_ATTEMPTS, MAX_COMMIT_TIME, Operation, + RandomAvailableId, ValueOp, key::DeserializeBigEndian, + }, }; impl RocksDbStore { @@ -53,7 +56,7 @@ impl RocksDbStore { if retry_count < MAX_COMMIT_ATTEMPTS && start.elapsed() < MAX_COMMIT_TIME => { - let backoff = rand::thread_rng().gen_range(50..=300); + let backoff = rand::rng().random_range(50..=300); sleep(Duration::from_millis(backoff)); retry_count += 1; } diff --git a/crates/store/src/backend/sqlite/pool.rs b/crates/store/src/backend/sqlite/pool.rs index 6471f7d8..4b40cb01 100644 --- a/crates/store/src/backend/sqlite/pool.rs +++ b/crates/store/src/backend/sqlite/pool.rs @@ -99,7 +99,6 @@ impl r2d2::ManageConnection for SqliteConnectionManager { Source::File(ref path) => Connection::open_with_flags(path, self.flags), Source::Memory => Connection::open_in_memory_with_flags(self.flags), } - .map_err(Into::into) .and_then(|mut c| { c.busy_handler(Some(sleeper))?; match self.init { @@ -110,7 +109,7 @@ impl r2d2::ManageConnection for SqliteConnectionManager { } fn is_valid(&self, conn: &mut Connection) -> Result<(), Error> { - conn.execute_batch("").map_err(Into::into) + conn.execute_batch("") } fn has_broken(&self, _: &mut Connection) -> bool { diff --git a/crates/store/src/dispatch/store.rs b/crates/store/src/dispatch/store.rs index de9024cb..f4c7d202 100644 --- a/crates/store/src/dispatch/store.rs +++ b/crates/store/src/dispatch/store.rs @@ -13,14 +13,15 @@ use roaring::RoaringBitmap; use trc::{AddContext, StoreEvent}; use crate::{ + BitmapKey, Deserialize, IterateParams, Key, QueryResult, SUBSPACE_BITMAP_ID, + SUBSPACE_BITMAP_TAG, SUBSPACE_BITMAP_TEXT, SUBSPACE_INDEXES, SUBSPACE_LOGS, Store, U32_LEN, + Value, ValueKey, write::{ + AnyClass, AnyKey, AssignedIds, Batch, BatchBuilder, BitmapClass, BitmapHash, Operation, + ReportClass, ValueClass, ValueOp, key::{DeserializeBigEndian, KeySerializer}, - now, AnyClass, AnyKey, AssignedIds, Batch, BatchBuilder, BitmapClass, BitmapHash, - Operation, ReportClass, ValueClass, ValueOp, + now, }, - BitmapKey, Deserialize, IterateParams, Key, QueryResult, Store, Value, ValueKey, - SUBSPACE_BITMAP_ID, SUBSPACE_BITMAP_TAG, SUBSPACE_BITMAP_TEXT, SUBSPACE_INDEXES, SUBSPACE_LOGS, - U32_LEN, }; use super::DocumentSet; @@ -417,7 +418,7 @@ impl Store { ) .no_values(), |key, _| { - if collection_offset.map_or(true, |offset| { + if collection_offset.is_none_or(|offset| { key.get(key.len() - U32_LEN - offset).copied() == Some(collection) }) { let document_id = key.deserialize_be_u32(key.len() - U32_LEN)?; @@ -645,9 +646,9 @@ impl Store { #[cfg(feature = "test_mode")] pub async fn blob_expire_all(&self) { - use utils::{BlobHash, BLOB_HASH_LEN}; + use utils::{BLOB_HASH_LEN, BlobHash}; - use crate::{write::BlobOp, U64_LEN}; + use crate::{U64_LEN, write::BlobOp}; // Delete all temporary hashes let from_key = ValueKey { diff --git a/crates/store/src/write/hash.rs b/crates/store/src/write/hash.rs index 6164948d..a15003b6 100644 --- a/crates/store/src/write/hash.rs +++ b/crates/store/src/write/hash.rs @@ -18,7 +18,7 @@ impl BitmapClass { pub fn stemmed(token: impl AsRef<[u8]>, field: impl Into) -> Self { BitmapClass::Text { - field: field.into() | 1 << 7, + field: field.into() | (1 << 7), token: BitmapHash::new(token), } } @@ -60,6 +60,6 @@ impl TokenType { } pub fn stemmed(field: u8) -> u8 { - 1 << 7 | field + (1 << 7) | field } } diff --git a/crates/store/src/write/mod.rs b/crates/store/src/write/mod.rs index 24b55fdd..6e6987ff 100644 --- a/crates/store/src/write/mod.rs +++ b/crates/store/src/write/mod.rs @@ -17,11 +17,11 @@ use nlp::tokenizers::word::WordTokenizer; use rand::Rng; use roaring::RoaringBitmap; use utils::{ - codec::leb128::{Leb128Iterator, Leb128Vec}, BlobHash, + codec::leb128::{Leb128Iterator, Leb128Vec}, }; -use crate::{backend::MAX_TOKEN_LENGTH, BlobClass, Deserialize, Serialize, Value}; +use crate::{BlobClass, Deserialize, Serialize, Value, backend::MAX_TOKEN_LENGTH}; use self::assert::AssertValue; @@ -896,7 +896,7 @@ impl RandomAvailableId for RoaringBitmap { last_id += 1; } - available_ids[rand::thread_rng().gen_range(0..available_ids.len())] + available_ids[rand::rng().random_range(0..available_ids.len())] } } diff --git a/crates/trc/Cargo.toml b/crates/trc/Cargo.toml index e4f2ca7c..35352c40 100644 --- a/crates/trc/Cargo.toml +++ b/crates/trc/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "trc" version = "0.11.5" -edition = "2021" +edition = "2024" resolver = "2" [dependencies] diff --git a/crates/trc/event-macro/Cargo.toml b/crates/trc/event-macro/Cargo.toml index 3b42e748..9eb9a2ac 100644 --- a/crates/trc/event-macro/Cargo.toml +++ b/crates/trc/event-macro/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "event_macro" version = "0.11.5" -edition = "2021" +edition = "2024" [lib] proc-macro = true diff --git a/crates/utils/Cargo.toml b/crates/utils/Cargo.toml index e0a7ef9d..23699967 100644 --- a/crates/utils/Cargo.toml +++ b/crates/utils/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "utils" version = "0.11.5" -edition = "2021" +edition = "2024" resolver = "2" [dependencies] @@ -17,7 +17,7 @@ smtp-proto = { version = "0.1" } mail-send = { version = "0.5", default-features = false, features = ["cram-md5", "ring", "tls12"] } ahash = { version = "0.8" } chrono = "0.4" -rand = "0.8.5" +rand = "0.9.0" webpki-roots = { version = "0.26"} ring = { version = "0.17" } base64 = "0.22" diff --git a/crates/utils/proc-macros/Cargo.toml b/crates/utils/proc-macros/Cargo.toml index 6768cdb5..cf32bacc 100644 --- a/crates/utils/proc-macros/Cargo.toml +++ b/crates/utils/proc-macros/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "proc_macros" version = "0.11.5" -edition = "2021" +edition = "2024" [lib] proc-macro = true diff --git a/crates/utils/src/snowflake.rs b/crates/utils/src/snowflake.rs index 99e8ecc7..79edc586 100644 --- a/crates/utils/src/snowflake.rs +++ b/crates/utils/src/snowflake.rs @@ -75,8 +75,8 @@ impl SnowflakeIdGenerator { let elapsed = self.epoch.elapsed().ok()?.as_millis() as u64; let sequence = self.sequence.fetch_add(1, Ordering::Relaxed); - (elapsed << (SEQUENCE_LEN + NODE_ID_LEN) - | (self.node_id & NODE_ID_MASK) << SEQUENCE_LEN + ((elapsed << (SEQUENCE_LEN + NODE_ID_LEN)) + | ((self.node_id & NODE_ID_MASK) << SEQUENCE_LEN) | (sequence & SEQUENCE_MASK)) .into() } diff --git a/tests/Cargo.toml b/tests/Cargo.toml index 6aa6d35b..da5483e9 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -1,13 +1,13 @@ [package] name = "tests" version = "0.11.5" -edition = "2021" +edition = "2024" resolver = "2" [features] #default = ["sqlite", "postgres", "mysql", "rocks", "elastic", "s3", "redis", "azure", "foundationdb"] -#default = ["sqlite", "postgres", "mysql", "rocks", "s3", "redis", "foundationdb"] -default = ["rocks", "redis", "s3"] +default = ["sqlite", "postgres", "mysql", "rocks", "s3", "redis"] +#default = ["rocks", "redis", "s3"] sqlite = ["store/sqlite"] foundationdb = ["store/foundation", "common/foundation"] postgres = ["store/postgres"] diff --git a/tests/src/imap/append.rs b/tests/src/imap/append.rs index 4b45511d..bebf8eb6 100644 --- a/tests/src/imap/append.rs +++ b/tests/src/imap/append.rs @@ -32,7 +32,7 @@ pub async fn test(imap: &mut ImapConnection, _imap_check: &mut ImapConnection, h let mut expected_uid = 1; for file_name in entries.into_iter().take(20) { - if file_name.extension().map_or(true, |e| e != "txt") { + if file_name.extension().is_none_or( |e| e != "txt") { continue; } let raw_message = fs::read(&file_name).unwrap(); diff --git a/tests/src/imap/body_structure.rs b/tests/src/imap/body_structure.rs index b9363b81..3e97f087 100644 --- a/tests/src/imap/body_structure.rs +++ b/tests/src/imap/body_structure.rs @@ -21,7 +21,7 @@ fn body_structure() { for file_name in fs::read_dir(resources_dir()).unwrap() { let mut file_name = file_name.as_ref().unwrap().path(); - if file_name.extension().map_or(true, |e| e != "txt") { + if file_name.extension().is_none_or( |e| e != "txt") { continue; } diff --git a/tests/src/jmap/email_get.rs b/tests/src/jmap/email_get.rs index 8b3c1408..8c659fe9 100644 --- a/tests/src/jmap/email_get.rs +++ b/tests/src/jmap/email_get.rs @@ -7,7 +7,7 @@ use std::{fs, path::PathBuf}; use ::email::mailbox::INBOX_ID; -use jmap_client::email::{self, import::EmailImportResponse, Header, HeaderForm}; +use jmap_client::email::{self, Header, HeaderForm, import::EmailImportResponse}; use jmap_proto::types::id::Id; use mail_parser::HeaderName; @@ -29,7 +29,7 @@ pub async fn test(params: &mut JMAPTest) { for file_name in fs::read_dir(&test_dir).unwrap() { let mut file_name = file_name.as_ref().unwrap().path(); - if file_name.extension().map_or(true, |e| e != "eml") { + if file_name.extension().is_none_or(|e| e != "eml") { continue; } let is_headers_test = file_name.file_name().unwrap() == "headers.eml"; diff --git a/tests/src/jmap/email_set.rs b/tests/src/jmap/email_set.rs index 24cc6324..341d0668 100644 --- a/tests/src/jmap/email_set.rs +++ b/tests/src/jmap/email_set.rs @@ -11,15 +11,15 @@ use ahash::AHashSet; use ::email::mailbox::INBOX_ID; use jmap_client::{ + Error, Set, client::Client, core::set::{SetError, SetErrorType}, email::{self, Email}, mailbox::Role, - Error, Set, }; use jmap_proto::types::id::Id; -use super::{find_values, replace_blob_ids, replace_boundaries, replace_values, JMAPTest}; +use super::{JMAPTest, find_values, replace_blob_ids, replace_boundaries, replace_values}; pub async fn test(params: &mut JMAPTest) { println!("Running Email Set tests..."); @@ -43,7 +43,7 @@ async fn create(client: &mut Client, mailbox_id: &str) { for file_name in fs::read_dir(&test_dir).unwrap() { let mut file_name = file_name.as_ref().unwrap().path(); - if file_name.extension().map_or(true, |e| e != "json") { + if file_name.extension().is_none_or(|e| e != "json") { continue; } println!("Creating email from {:?}", file_name); diff --git a/tests/src/jmap/enterprise.rs b/tests/src/jmap/enterprise.rs index 78cf4cfc..d9ff6fb7 100644 --- a/tests/src/jmap/enterprise.rs +++ b/tests/src/jmap/enterprise.rs @@ -472,16 +472,16 @@ pub async fn insert_test_metrics(core: Arc) { EventType::IncomingReport(IncomingReportEvent::TlsReportWithWarnings), ] { // Generate a random value between 0 and 100 - Collector::update_event_counter(event_type, rand::thread_rng().gen_range(0..=100)) + Collector::update_event_counter(event_type, rand::rng().random_range(0..=100)) } Collector::update_gauge( MetricType::QueueCount, - rand::thread_rng().gen_range(0..=1000), + rand::rng().random_range(0..=1000), ); Collector::update_gauge( MetricType::ServerMemory, - rand::thread_rng().gen_range(100 * 1024 * 1024..=300 * 1024 * 1024), + rand::rng().random_range(100 * 1024 * 1024..=300 * 1024 * 1024), ); for metric_type in [ @@ -490,11 +490,11 @@ pub async fn insert_test_metrics(core: Arc) { MetricType::DeliveryTime, MetricType::DnsLookupTime, ] { - Collector::update_histogram(metric_type, rand::thread_rng().gen_range(2..=1000)) + Collector::update_histogram(metric_type, rand::rng().random_range(2..=1000)) } Collector::update_histogram( MetricType::DeliveryTotalTime, - rand::thread_rng().gen_range(1000..=5000), + rand::rng().random_range(1000..=5000), ); store diff --git a/tests/src/jmap/mod.rs b/tests/src/jmap/mod.rs index 092d806d..f44f0781 100644 --- a/tests/src/jmap/mod.rs +++ b/tests/src/jmap/mod.rs @@ -7,10 +7,11 @@ use std::{fmt::Debug, path::PathBuf, sync::Arc, time::Duration}; use base64::{ - engine::general_purpose::{self, STANDARD}, Engine, + engine::general_purpose::{self, STANDARD}, }; use common::{ + Caches, Core, Data, Inner, KV_BAYES_MODEL_GLOBAL, Server, auth::AccessToken, config::{ server::{Listeners, ServerProtocol}, @@ -21,31 +22,30 @@ use common::{ boot::build_ipc, config::{ConfigManager, Patterns}, }, - Caches, Core, Data, Inner, Server, KV_BAYES_MODEL_GLOBAL, }; -use enterprise::{insert_test_metrics, EnterpriseCore}; -use hyper::{header::AUTHORIZATION, Method}; +use enterprise::{EnterpriseCore, insert_test_metrics}; +use hyper::{Method, header::AUTHORIZATION}; use imap::core::ImapSessionManager; -use jmap::{api::JmapSessionManager, email::delete::EmailDeletion, SpawnServices}; +use jmap::{SpawnServices, api::JmapSessionManager, email::delete::EmailDeletion}; use jmap_client::client::{Client, Credentials}; use jmap_proto::{error::request::RequestError, types::id::Id}; use managesieve::core::ManageSieveSessionManager; use pop3::Pop3SessionManager; use reqwest::header; -use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use smtp::{core::SmtpSessionManager, SpawnQueueManager}; +use serde::{Deserialize, Serialize, de::DeserializeOwned}; +use smtp::{SpawnQueueManager, core::SmtpSessionManager}; use store::{ + IterateParams, SUBSPACE_PROPERTY, Stores, ValueKey, roaring::RoaringBitmap, - write::{key::DeserializeBigEndian, AnyKey, TaskQueueClass, ValueClass}, - IterateParams, Stores, ValueKey, SUBSPACE_PROPERTY, + write::{AnyKey, TaskQueueClass, ValueClass, key::DeserializeBigEndian}, }; use tokio::sync::watch; -use utils::{config::Config, BlobHash}; -use webhooks::{spawn_mock_webhook_endpoint, MockWebhookEndpoint}; +use utils::{BlobHash, config::Config}; +use webhooks::{MockWebhookEndpoint, spawn_mock_webhook_endpoint}; use crate::{ - add_test_certs, directory::internal::TestInternalDirectory, store::TempDir, AssertConfig, + AssertConfig, add_test_certs, directory::internal::TestInternalDirectory, store::TempDir, }; pub mod auth_acl; @@ -384,13 +384,13 @@ pub async fn jmap_tests() { thread_merge::test(&mut params).await; mailbox::test(&mut params).await; delivery::test(&mut params).await; - auth_acl::test(&mut params).await; + auth_acl::test(&mut params).await;*/ auth_limits::test(&mut params).await; auth_oauth::test(&mut params).await; event_source::test(&mut params).await; push_subscription::test(&mut params).await; sieve_script::test(&mut params).await; - vacation_response::test(&mut params).await;*/ + vacation_response::test(&mut params).await; email_submission::test(&mut params).await; websocket::test(&mut params).await; quota::test(&mut params).await; diff --git a/tests/src/jmap/stress_test.rs b/tests/src/jmap/stress_test.rs index 3db76711..eae82a28 100644 --- a/tests/src/jmap/stress_test.rs +++ b/tests/src/jmap/stress_test.rs @@ -65,13 +65,13 @@ async fn email_tests(server: Server, client: Arc) { let mut futures = Vec::new(); for num in 0..1000 { - match rand::thread_rng().gen_range(0..3) { + match rand::rng().random_range(0..3) { 0 => { let client = client.clone(); let mailboxes = mailboxes.clone(); futures.push(tokio::spawn(async move { let mailbox_num = - rand::thread_rng().gen_range::(0..mailboxes.len()); + rand::rng().random_range::(0..mailboxes.len()); let _message_id = client .email_import( format!( @@ -107,7 +107,7 @@ async fn email_tests(server: Server, client: Arc) { req.query_email(); let ids = req.send_query_email().await.unwrap().take_ids(); if !ids.is_empty() { - let message_id = &ids[rand::thread_rng().gen_range(0..ids.len())]; + let message_id = &ids[rand::rng().random_range(0..ids.len())]; /*println!( "Deleting message {}.", Id::from_bytes(message_id.as_bytes()).unwrap().document_id() @@ -159,14 +159,14 @@ async fn email_tests(server: Server, client: Arc) { .take_list(); if !emails.is_empty() { - let message = &emails[rand::thread_rng().gen_range(0..emails.len())]; + let message = &emails[rand::rng().random_range(0..emails.len())]; let message_id = message.id().unwrap(); let mailbox_ids = message.mailbox_ids(); assert_eq!(mailbox_ids.len(), 1, "{:#?}", message); let mailbox_id = mailbox_ids.last().unwrap(); loop { let new_mailbox_id = - &mailboxes[rand::thread_rng().gen_range(0..mailboxes.len())]; + &mailboxes[rand::rng().random_range(0..mailboxes.len())]; if new_mailbox_id != mailbox_id { /*println!( "Moving message {} from {} to {}.", @@ -193,7 +193,7 @@ async fn email_tests(server: Server, client: Arc) { })); } } - tokio::time::sleep(Duration::from_millis(rand::thread_rng().gen_range(5..10))).await; + tokio::time::sleep(Duration::from_millis(rand::rng().random_range(5..10))).await; } join_all(futures).await; @@ -285,7 +285,7 @@ async fn mailbox_tests(server: Server, client: Arc) { println!("----------------- MAILBOX STRESS TEST -----------------"); for _ in 0..1000 { - match rand::thread_rng().gen_range(0..=3) { + match rand::rng().random_range(0..=3) { 0 => { for pos in 0..mailboxes.len() { let client = client.clone(); @@ -332,15 +332,15 @@ async fn mailbox_tests(server: Server, client: Arc) { .unwrap() .take_ids(); if !ids.is_empty() { - let id = ids.swap_remove(rand::thread_rng().gen_range(0..ids.len())); - let sort_order = rand::thread_rng().gen_range(0..100); + let id = ids.swap_remove(rand::rng().random_range(0..ids.len())); + let sort_order = rand::rng().random_range(0..100); //println!("Updating mailbox {}.", id); client.mailbox_update_sort_order(&id, sort_order).await.ok(); } })); } } - tokio::time::sleep(Duration::from_millis(rand::thread_rng().gen_range(5..10))).await; + tokio::time::sleep(Duration::from_millis(rand::rng().random_range(5..10))).await; } join_all(futures).await; @@ -421,7 +421,7 @@ async fn delete_mailbox(client: &Client, mailbox_id: &str) { Err(err) => match err { jmap_client::Error::Set(_) => break, jmap_client::Error::Transport(_) => { - let backoff = rand::thread_rng().gen_range(50..=300); + let backoff = rand::rng().random_range(50..=300); tokio::time::sleep(Duration::from_millis(backoff)).await; } _ => panic!("Failed: {:?}", err), diff --git a/tests/src/jmap/thread_merge.rs b/tests/src/jmap/thread_merge.rs index 7e53d949..d7c50383 100644 --- a/tests/src/jmap/thread_merge.rs +++ b/tests/src/jmap/thread_merge.rs @@ -261,7 +261,7 @@ async fn test_multi_thread(params: &mut JMAPTest) { Err(err) => { if err.is_assertion_failure() && retry_count < 10 { //println!("Retrying ingest for {}...", message.from()); - let backoff = rand::thread_rng().gen_range(50..=300); + let backoff = rand::rng().random_range(50..=300); tokio::time::sleep(Duration::from_millis(backoff)).await; retry_count += 1; continue; diff --git a/tests/src/store/lookup.rs b/tests/src/store/lookup.rs index 7edf434d..960a606e 100644 --- a/tests/src/store/lookup.rs +++ b/tests/src/store/lookup.rs @@ -6,12 +6,12 @@ use std::time::Duration; -use store::{dispatch::lookup::KeyValue, InMemoryStore, Stores}; +use store::{InMemoryStore, Stores, dispatch::lookup::KeyValue}; use utils::config::{Config, Rate}; use crate::{ - store::{TempDir, CONFIG}, AssertConfig, + store::{CONFIG, TempDir}, }; #[tokio::test] @@ -98,22 +98,28 @@ pub async fn lookup_tests() { assert_eq!(0, store.counter_get(key.clone()).await.unwrap()); // Test rate limiter - assert!(store - .is_rate_allowed(0, "rate".as_bytes(), &rate, false) - .await - .unwrap() - .is_none()); - assert!(store - .is_rate_allowed(0, "rate".as_bytes(), &rate, false) - .await - .unwrap() - .is_some()); + assert!( + store + .is_rate_allowed(0, "rate".as_bytes(), &rate, false) + .await + .unwrap() + .is_none() + ); + assert!( + store + .is_rate_allowed(0, "rate".as_bytes(), &rate, false) + .await + .unwrap() + .is_some() + ); tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; - assert!(store - .is_rate_allowed(0, "rate".as_bytes(), &rate, false) - .await - .unwrap() - .is_none()); + assert!( + store + .is_rate_allowed(0, "rate".as_bytes(), &rate, false) + .await + .unwrap() + .is_none() + ); tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; store.purge_in_memory_store().await.unwrap(); if let InMemoryStore::Store(store) = &store { @@ -281,5 +287,5 @@ pub async fn lookup_tests() { } fn pack_u32(a: u32, b: u32) -> Vec { - ((a as u64) << 32 | b as u64).to_be_bytes().to_vec() + (((a as u64) << 32) | b as u64).to_be_bytes().to_vec() }