diff --git a/Cargo.lock b/Cargo.lock
index 2c8c3236..17729b7e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -5731,9 +5731,9 @@ dependencies = [
[[package]]
name = "socket2"
-version = "0.5.6"
+version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871"
+checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
dependencies = [
"libc",
"windows-sys 0.52.0",
diff --git a/crates/common/src/addresses.rs b/crates/common/src/addresses.rs
index 3e17d5b3..75fa1d01 100644
--- a/crates/common/src/addresses.rs
+++ b/crates/common/src/addresses.rs
@@ -1,3 +1,26 @@
+/*
+ * Copyright (c) 2023 Stalwart Labs Ltd.
+ *
+ * This file is part of Stalwart Mail Server.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ * in the LICENSE file at the top-level directory of this distribution.
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ *
+ * You can be released from the requirements of the AGPLv3 license by
+ * purchasing a commercial license. Please contact licensing@stalw.art
+ * for more details.
+*/
+
use std::borrow::Cow;
use directory::Directory;
diff --git a/crates/common/src/expr/eval.rs b/crates/common/src/expr/eval.rs
index ccc1bcca..19bb3bff 100644
--- a/crates/common/src/expr/eval.rs
+++ b/crates/common/src/expr/eval.rs
@@ -576,24 +576,6 @@ impl Display for Variable<'_> {
}
}
-trait IntoBool {
- fn into_bool(self) -> bool;
-}
-
-impl IntoBool for f64 {
- #[inline(always)]
- fn into_bool(self) -> bool {
- self != 0.0
- }
-}
-
-impl IntoBool for i64 {
- #[inline(always)]
- fn into_bool(self) -> bool {
- self != 0
- }
-}
-
impl<'x> From<&'x Constant> for Variable<'x> {
fn from(value: &'x Constant) -> Self {
match value {
diff --git a/crates/common/src/lib.rs b/crates/common/src/lib.rs
index 9973b396..24adadba 100644
--- a/crates/common/src/lib.rs
+++ b/crates/common/src/lib.rs
@@ -1,3 +1,26 @@
+/*
+ * Copyright (c) 2023 Stalwart Labs Ltd.
+ *
+ * This file is part of Stalwart Mail Server.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ * in the LICENSE file at the top-level directory of this distribution.
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ *
+ * You can be released from the requirements of the AGPLv3 license by
+ * purchasing a commercial license. Please contact licensing@stalw.art
+ * for more details.
+*/
+
use std::{borrow::Cow, net::IpAddr, sync::Arc};
use arc_swap::ArcSwap;
diff --git a/crates/common/src/listener/blocked.rs b/crates/common/src/listener/blocked.rs
index 9da78d79..761b3e54 100644
--- a/crates/common/src/listener/blocked.rs
+++ b/crates/common/src/listener/blocked.rs
@@ -21,7 +21,7 @@
* for more details.
*/
-use std::{fmt::Debug, net::IpAddr};
+use std::{fmt::Debug, net::IpAddr, sync::atomic::AtomicU8};
use ahash::AHashSet;
use parking_lot::RwLock;
@@ -35,6 +35,7 @@ use crate::Core;
pub struct BlockedIps {
pub ip_addresses: RwLock>,
+ pub version: AtomicU8,
ip_networks: Vec,
has_networks: bool,
limiter_rate: Option,
@@ -71,6 +72,7 @@ impl BlockedIps {
has_networks: !ip_networks.is_empty(),
ip_networks,
limiter_rate: config.property_or_default::("authentication.fail2ban", "100/1d"),
+ version: 0.into(),
}
}
}
@@ -103,6 +105,9 @@ impl Core {
}])
.await?;
+ // Increment version
+ self.network.blocked_ips.increment_version();
+
return Ok(true);
}
}
@@ -126,6 +131,13 @@ impl Core {
}
}
+impl BlockedIps {
+ pub fn increment_version(&self) {
+ self.version
+ .fetch_add(1, std::sync::atomic::Ordering::Relaxed);
+ }
+}
+
impl Default for BlockedIps {
fn default() -> Self {
Self {
@@ -133,6 +145,7 @@ impl Default for BlockedIps {
ip_networks: Default::default(),
has_networks: Default::default(),
limiter_rate: Default::default(),
+ version: Default::default(),
}
}
}
@@ -144,6 +157,10 @@ impl Clone for BlockedIps {
ip_networks: self.ip_networks.clone(),
has_networks: self.has_networks,
limiter_rate: self.limiter_rate.clone(),
+ version: self
+ .version
+ .load(std::sync::atomic::Ordering::Relaxed)
+ .into(),
}
}
}
diff --git a/crates/common/src/listener/listen.rs b/crates/common/src/listener/listen.rs
index df4fac2a..f9a8273b 100644
--- a/crates/common/src/listener/listen.rs
+++ b/crates/common/src/listener/listen.rs
@@ -325,7 +325,7 @@ impl Servers {
pub fn spawn(
mut self,
spawn: impl Fn(Server, TcpAcceptor, watch::Receiver),
- ) -> watch::Sender {
+ ) -> (watch::Sender, watch::Receiver) {
// Spawn listeners
let (shutdown_tx, shutdown_rx) = watch::channel(false);
for server in self.servers {
@@ -336,7 +336,7 @@ impl Servers {
spawn(server, acceptor, shutdown_rx.clone());
}
- shutdown_tx
+ (shutdown_tx, shutdown_rx)
}
}
diff --git a/crates/common/src/manager/boot.rs b/crates/common/src/manager/boot.rs
index fb115283..1692c14f 100644
--- a/crates/common/src/manager/boot.rs
+++ b/crates/common/src/manager/boot.rs
@@ -221,6 +221,22 @@ impl BootManager {
)));
}
+ // Generate a Cluster encryption key if missing
+ if config
+ .value("cluster.key")
+ .filter(|v| !v.is_empty())
+ .is_none()
+ {
+ insert_keys.push(ConfigKey::from((
+ "cluster.key",
+ thread_rng()
+ .sample_iter(Alphanumeric)
+ .take(64)
+ .map(char::from)
+ .collect::(),
+ )));
+ }
+
// Download SPAM filters if missing
if config
.value("version.spam-filter")
diff --git a/crates/jmap/src/api/http.rs b/crates/jmap/src/api/http.rs
index fb10f455..ff39072a 100644
--- a/crates/jmap/src/api/http.rs
+++ b/crates/jmap/src/api/http.rs
@@ -49,7 +49,7 @@ use crate::{
auth::oauth::OAuthMetadata,
blob::{DownloadResponse, UploadResponse},
services::state,
- JMAP,
+ JmapInstance, JMAP,
};
use super::{HtmlResponse, HttpRequest, HttpResponse, JmapSessionManager, JsonResponse};
@@ -356,7 +356,9 @@ impl JMAP {
}
RequestError::not_found().into_http_response()
}
+}
+impl JmapInstance {
async fn handle_session(self, session: SessionData) {
let span = session.span;
let _in_flight = session.in_flight;
@@ -367,7 +369,7 @@ impl JMAP {
.serve_connection(
TokioIo::new(session.stream),
service_fn(|req: hyper::Request| {
- let jmap = self.clone();
+ let jmap_instance = self.clone();
let span = span.clone();
let instance = session.instance.clone();
@@ -377,6 +379,7 @@ impl JMAP {
event = "request",
uri = req.uri().to_string(),
);
+ let jmap = JMAP::from(jmap_instance);
// Obtain remote IP
let remote_ip = if !jmap.core.jmap.http_use_forwarded {
@@ -442,7 +445,7 @@ impl SessionManager for JmapSessionManager {
self,
session: SessionData,
) -> impl std::future::Future