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 @@
-
+
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