summaryrefslogtreecommitdiff
path: root/crates/jmap/src/api/management
diff options
context:
space:
mode:
Diffstat (limited to 'crates/jmap/src/api/management')
-rw-r--r--crates/jmap/src/api/management/dkim.rs40
-rw-r--r--crates/jmap/src/api/management/dns.rs38
-rw-r--r--crates/jmap/src/api/management/enterprise/telemetry.rs23
-rw-r--r--crates/jmap/src/api/management/enterprise/undelete.rs22
-rw-r--r--crates/jmap/src/api/management/log.rs20
-rw-r--r--crates/jmap/src/api/management/mod.rs31
-rw-r--r--crates/jmap/src/api/management/principal.rs74
-rw-r--r--crates/jmap/src/api/management/queue.rs46
-rw-r--r--crates/jmap/src/api/management/reload.rs56
-rw-r--r--crates/jmap/src/api/management/report.rs22
-rw-r--r--crates/jmap/src/api/management/settings.rs22
-rw-r--r--crates/jmap/src/api/management/sieve.rs26
-rw-r--r--crates/jmap/src/api/management/stores.rs58
13 files changed, 339 insertions, 139 deletions
diff --git a/crates/jmap/src/api/management/dkim.rs b/crates/jmap/src/api/management/dkim.rs
index 09e0c383..5fcbe4eb 100644
--- a/crates/jmap/src/api/management/dkim.rs
+++ b/crates/jmap/src/api/management/dkim.rs
@@ -6,7 +6,7 @@
use std::str::FromStr;
-use common::{auth::AccessToken, config::smtp::auth::simple_pem_parse};
+use common::{auth::AccessToken, config::smtp::auth::simple_pem_parse, Server};
use directory::{backend::internal::manage, Permission};
use hyper::Method;
use mail_auth::{
@@ -21,12 +21,10 @@ use serde::{Deserialize, Serialize};
use serde_json::json;
use store::write::now;
-use crate::{
- api::{http::ToHttpResponse, HttpRequest, HttpResponse, JsonResponse},
- JMAP,
-};
+use crate::api::{http::ToHttpResponse, HttpRequest, HttpResponse, JsonResponse};
use super::decode_path_element;
+use std::future::Future;
#[derive(Debug, Serialize, Deserialize, Copy, Clone, PartialEq, Eq)]
pub enum Algorithm {
@@ -42,8 +40,36 @@ struct DkimSignature {
selector: Option<String>,
}
-impl JMAP {
- pub async fn handle_manage_dkim(
+pub trait DkimManagement: Sync + Send {
+ fn handle_manage_dkim(
+ &self,
+ req: &HttpRequest,
+ path: Vec<&str>,
+ body: Option<Vec<u8>>,
+ access_token: &AccessToken,
+ ) -> impl Future<Output = trc::Result<HttpResponse>> + Send;
+
+ fn handle_get_public_key(
+ &self,
+ path: Vec<&str>,
+ ) -> impl Future<Output = trc::Result<HttpResponse>> + Send;
+
+ fn handle_create_signature(
+ &self,
+ body: Option<Vec<u8>>,
+ ) -> impl Future<Output = trc::Result<HttpResponse>> + Send;
+
+ fn create_dkim_key(
+ &self,
+ algo: Algorithm,
+ id: impl AsRef<str> + Send,
+ domain: impl Into<String> + Send,
+ selector: impl Into<String> + Send,
+ ) -> impl Future<Output = trc::Result<()>> + Send;
+}
+
+impl DkimManagement for Server {
+ async fn handle_manage_dkim(
&self,
req: &HttpRequest,
path: Vec<&str>,
diff --git a/crates/jmap/src/api/management/dns.rs b/crates/jmap/src/api/management/dns.rs
index 65e56bb1..72a7a54e 100644
--- a/crates/jmap/src/api/management/dns.rs
+++ b/crates/jmap/src/api/management/dns.rs
@@ -4,7 +4,7 @@
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
-use common::auth::AccessToken;
+use common::{auth::AccessToken, Server};
use directory::{
backend::internal::manage::{self},
Permission,
@@ -17,27 +17,39 @@ use sha1::Digest;
use utils::config::Config;
use x509_parser::parse_x509_certificate;
-use crate::{
- api::{
- http::ToHttpResponse,
- management::dkim::{obtain_dkim_public_key, Algorithm},
- HttpRequest, HttpResponse, JsonResponse,
- },
- JMAP,
+use crate::api::{
+ http::ToHttpResponse,
+ management::dkim::{obtain_dkim_public_key, Algorithm},
+ HttpRequest, HttpResponse, JsonResponse,
};
use super::decode_path_element;
+use std::future::Future;
#[derive(Debug, Serialize, Deserialize)]
-struct DnsRecord {
+pub struct DnsRecord {
#[serde(rename = "type")]
typ: String,
name: String,
content: String,
}
-impl JMAP {
- pub async fn handle_manage_dns(
+pub trait DnsManagement: Sync + Send {
+ fn handle_manage_dns(
+ &self,
+ req: &HttpRequest,
+ path: Vec<&str>,
+ access_token: &AccessToken,
+ ) -> impl Future<Output = trc::Result<HttpResponse>> + Send;
+
+ fn build_dns_records(
+ &self,
+ domain_name: &str,
+ ) -> impl Future<Output = trc::Result<Vec<DnsRecord>>> + Send;
+}
+
+impl DnsManagement for Server {
+ async fn handle_manage_dns(
&self,
req: &HttpRequest,
path: Vec<&str>,
@@ -210,7 +222,7 @@ impl JMAP {
});
// Add MTA-STS records
- if let Some(policy) = self.core.build_mta_sts_policy() {
+ if let Some(policy) = self.build_mta_sts_policy() {
records.push(DnsRecord {
typ: "CNAME".to_string(),
name: format!("mta-sts.{domain_name}."),
@@ -239,7 +251,7 @@ impl JMAP {
});
// Add TLSA records
- for (name, key) in self.core.tls.certificates.load().iter() {
+ for (name, key) in self.inner.data.tls_certificates.load().iter() {
if !name.ends_with(domain_name)
|| name.starts_with("mta-sts.")
|| name.starts_with("autoconfig.")
diff --git a/crates/jmap/src/api/management/enterprise/telemetry.rs b/crates/jmap/src/api/management/enterprise/telemetry.rs
index b5b06e8f..6a1ff7b2 100644
--- a/crates/jmap/src/api/management/enterprise/telemetry.rs
+++ b/crates/jmap/src/api/management/enterprise/telemetry.rs
@@ -19,6 +19,7 @@ use common::{
metrics::store::{Metric, MetricsStore},
tracers::store::{TracingQuery, TracingStore},
},
+ Server,
};
use directory::{backend::internal::manage, Permission};
use http_body_util::{combinators::BoxBody, StreamBody};
@@ -28,6 +29,7 @@ use hyper::{
};
use mail_parser::DateTime;
use serde_json::json;
+use std::future::Future;
use store::ahash::{AHashMap, AHashSet};
use trc::{
ipc::{bitset::Bitset, subscriber::SubscriberBuilder},
@@ -41,11 +43,20 @@ use crate::{
http::ToHttpResponse, management::Timestamp, HttpRequest, HttpResponse, HttpResponseBody,
JsonResponse,
},
- JMAP,
+ auth::oauth::token::TokenHandler,
};
-impl JMAP {
- pub async fn handle_telemetry_api_request(
+pub trait TelemetryApi: Sync + Send {
+ fn handle_telemetry_api_request(
+ &self,
+ req: &HttpRequest,
+ path: Vec<&str>,
+ access_token: &AccessToken,
+ ) -> impl Future<Output = trc::Result<HttpResponse>> + Send;
+}
+
+impl TelemetryApi for Server {
+ async fn handle_telemetry_api_request(
&self,
req: &HttpRequest,
path: Vec<&str>,
@@ -455,9 +466,9 @@ impl JMAP {
] {
if metric_types.contains(&metric_type) {
let value = match metric_type {
- MetricType::QueueCount => self.core.total_queued_messages().await?,
- MetricType::UserCount => self.core.total_accounts().await?,
- MetricType::DomainCount => self.core.total_domains().await?,
+ MetricType::QueueCount => self.total_queued_messages().await?,
+ MetricType::UserCount => self.total_accounts().await?,
+ MetricType::DomainCount => self.total_domains().await?,
_ => unreachable!(),
};
Collector::update_gauge(metric_type, value);
diff --git a/crates/jmap/src/api/management/enterprise/undelete.rs b/crates/jmap/src/api/management/enterprise/undelete.rs
index e14de9ed..e3a40cef 100644
--- a/crates/jmap/src/api/management/enterprise/undelete.rs
+++ b/crates/jmap/src/api/management/enterprise/undelete.rs
@@ -11,12 +11,13 @@
use std::str::FromStr;
use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine};
-use common::{auth::AccessToken, enterprise::undelete::DeletedBlob};
+use common::{auth::AccessToken, enterprise::undelete::DeletedBlob, Server};
use directory::backend::internal::manage::ManageDirectory;
use hyper::Method;
use jmap_proto::types::collection::Collection;
use mail_parser::{DateTime, MessageParser};
use serde_json::json;
+use std::future::Future;
use store::write::{BatchBuilder, BlobOp, ValueClass};
use trc::AddContext;
use utils::{url_params::UrlParams, BlobHash};
@@ -27,9 +28,10 @@ use crate::{
management::decode_path_element,
HttpRequest, HttpResponse, JsonResponse,
},
- email::ingest::{IngestEmail, IngestSource},
+ blob::download::BlobDownload,
+ email::ingest::{EmailIngest, IngestEmail, IngestSource},
mailbox::INBOX_ID,
- JMAP,
+ JmapMethods,
};
#[derive(serde::Deserialize, serde::Serialize)]
@@ -52,8 +54,18 @@ pub enum UndeleteResponse {
Error { reason: String },
}
-impl JMAP {
- pub async fn handle_undelete_api_request(
+pub trait UndeleteApi: Sync + Send {
+ fn handle_undelete_api_request(
+ &self,
+ req: &HttpRequest,
+ path: Vec<&str>,
+ body: Option<Vec<u8>>,
+ session: &HttpSessionData,
+ ) -> impl Future<Output = trc::Result<HttpResponse>> + Send;
+}
+
+impl UndeleteApi for Server {
+ async fn handle_undelete_api_request(
&self,
req: &HttpRequest,
path: Vec<&str>,
diff --git a/crates/jmap/src/api/management/log.rs b/crates/jmap/src/api/management/log.rs
index 94a87af2..ef4191e9 100644
--- a/crates/jmap/src/api/management/log.rs
+++ b/crates/jmap/src/api/management/log.rs
@@ -5,18 +5,16 @@ use std::{
};
use chrono::DateTime;
-use common::auth::AccessToken;
+use common::{auth::AccessToken, Server};
use directory::{backend::internal::manage, Permission};
use rev_lines::RevLines;
use serde::Serialize;
use serde_json::json;
+use std::future::Future;
use tokio::sync::oneshot;
use utils::url_params::UrlParams;
-use crate::{
- api::{http::ToHttpResponse, HttpRequest, HttpResponse, JsonResponse},
- JMAP,
-};
+use crate::api::{http::ToHttpResponse, HttpRequest, HttpResponse, JsonResponse};
#[derive(Serialize)]
struct LogEntry {
@@ -27,8 +25,16 @@ struct LogEntry {
details: String,
}
-impl JMAP {
- pub async fn handle_view_logs(
+pub trait LogManagement: Sync + Send {
+ fn handle_view_logs(
+ &self,
+ req: &HttpRequest,
+ access_token: &AccessToken,
+ ) -> impl Future<Output = trc::Result<HttpResponse>> + Send;
+}
+
+impl LogManagement for Server {
+ async fn handle_view_logs(
&self,
req: &HttpRequest,
access_token: &AccessToken,
diff --git a/crates/jmap/src/api/management/mod.rs b/crates/jmap/src/api/management/mod.rs
index 0a3dc0c2..d7a0b704 100644
--- a/crates/jmap/src/api/management/mod.rs
+++ b/crates/jmap/src/api/management/mod.rs
@@ -19,15 +19,28 @@ pub mod stores;
use std::{borrow::Cow, str::FromStr, sync::Arc};
-use common::auth::AccessToken;
+use common::{auth::AccessToken, Server};
use directory::{backend::internal::manage, Permission};
+use dkim::DkimManagement;
+use dns::DnsManagement;
+use enterprise::telemetry::TelemetryApi;
use hyper::Method;
+use log::LogManagement;
use mail_parser::DateTime;
+use principal::PrincipalManager;
+use queue::QueueManagement;
+use reload::ManageReload;
+use report::ManageReports;
use serde::Serialize;
+use settings::ManageSettings;
+use sieve::SieveHandler;
use store::write::now;
+use stores::ManageStore;
+
+use crate::{auth::oauth::auth::OAuthApiHandler, email::crypto::CryptoHandler};
use super::{http::HttpSessionData, HttpRequest, HttpResponse};
-use crate::JMAP;
+use std::future::Future;
#[derive(Serialize)]
#[serde(tag = "error")]
@@ -53,9 +66,19 @@ pub enum ManagementApiError<'x> {
},
}
-impl JMAP {
+pub trait ManagementApi: Sync + Send {
+ fn handle_api_manage_request(
+ &self,
+ req: &HttpRequest,
+ body: Option<Vec<u8>>,
+ access_token: Arc<AccessToken>,
+ session: &HttpSessionData,
+ ) -> impl Future<Output = trc::Result<HttpResponse>> + Send;
+}
+
+impl ManagementApi for Server {
#[allow(unused_variables)]
- pub async fn handle_api_manage_request(
+ async fn handle_api_manage_request(
&self,
req: &HttpRequest,
body: Option<Vec<u8>>,
diff --git a/crates/jmap/src/api/management/principal.rs b/crates/jmap/src/api/management/principal.rs
index 51994756..764414de 100644
--- a/crates/jmap/src/api/management/principal.rs
+++ b/crates/jmap/src/api/management/principal.rs
@@ -6,7 +6,7 @@
use std::sync::{atomic::Ordering, Arc};
-use common::auth::AccessToken;
+use common::{auth::AccessToken, Server};
use directory::{
backend::internal::{
lookup::DirectoryStore,
@@ -21,12 +21,10 @@ use serde_json::json;
use trc::AddContext;
use utils::url_params::UrlParams;
-use crate::{
- api::{http::ToHttpResponse, HttpRequest, HttpResponse, JsonResponse},
- JMAP,
-};
+use crate::api::{http::ToHttpResponse, HttpRequest, HttpResponse, JsonResponse};
use super::decode_path_element;
+use std::future::Future;
#[derive(Debug, serde::Serialize, serde::Deserialize)]
#[serde(tag = "type")]
@@ -47,8 +45,32 @@ pub struct AccountAuthResponse {
pub app_passwords: Vec<String>,
}
-impl JMAP {
- pub async fn handle_manage_principal(
+pub trait PrincipalManager: Sync + Send {
+ fn handle_manage_principal(
+ &self,
+ req: &HttpRequest,
+ path: Vec<&str>,
+ body: Option<Vec<u8>>,
+ access_token: &AccessToken,
+ ) -> impl Future<Output = trc::Result<HttpResponse>> + Send;
+
+ fn handle_account_auth_get(
+ &self,
+ access_token: Arc<AccessToken>,
+ ) -> impl Future<Output = trc::Result<HttpResponse>> + Send;
+
+ fn handle_account_auth_post(
+ &self,
+ req: &HttpRequest,
+ access_token: Arc<AccessToken>,
+ body: Option<Vec<u8>>,
+ ) -> impl Future<Output = trc::Result<HttpResponse>> + Send;
+
+ fn assert_supported_directory(&self) -> trc::Result<()>;
+}
+
+impl PrincipalManager for Server {
+ async fn handle_manage_principal(
&self,
req: &HttpRequest,
path: Vec<&str>,
@@ -297,13 +319,16 @@ impl JMAP {
}
// Remove entries from cache
- self.inner.sessions.retain(|_, id| id.item != account_id);
+ self.inner
+ .data
+ .http_auth_cache
+ .retain(|_, id| id.item != account_id);
if matches!(typ, Type::Role | Type::Tenant) {
// Update permissions cache
- self.core.security.permissions.clear();
- self.core
- .security
+ self.inner.data.permissions.clear();
+ self.inner
+ .data
.permissions_version
.fetch_add(1, Ordering::Relaxed);
}
@@ -399,20 +424,23 @@ impl JMAP {
if expire_session {
// Remove entries from cache
- self.inner.sessions.retain(|_, id| id.item != account_id);
+ self.inner
+ .data
+ .http_auth_cache
+ .retain(|_, id| id.item != account_id);
}
if is_role_change {
// Update permissions cache
- self.core.security.permissions.clear();
- self.core
- .security
+ self.inner.data.permissions.clear();
+ self.inner
+ .data
.permissions_version
.fetch_add(1, Ordering::Relaxed);
}
if expire_token {
- self.core.security.access_tokens.remove(&account_id);
+ self.inner.data.access_tokens.remove(&account_id);
}
Ok(JsonResponse::new(json!({
@@ -428,7 +456,7 @@ impl JMAP {
}
}
- pub async fn handle_account_auth_get(
+ async fn handle_account_auth_get(
&self,
access_token: Arc<AccessToken>,
) -> trc::Result<HttpResponse> {
@@ -463,7 +491,7 @@ impl JMAP {
.into_http_response())
}
- pub async fn handle_account_auth_post(
+ async fn handle_account_auth_post(
&self,
req: &HttpRequest,
access_token: Arc<AccessToken>,
@@ -513,7 +541,10 @@ impl JMAP {
.await?;
// Remove entries from cache
- self.inner.sessions.retain(|_, id| id.item != u32::MAX);
+ self.inner
+ .data
+ .http_auth_cache
+ .retain(|_, id| id.item != u32::MAX);
return Ok(JsonResponse::new(json!({
"data": (),
@@ -578,7 +609,8 @@ impl JMAP {
// Remove entries from cache
self.inner
- .sessions
+ .data
+ .http_auth_cache
.retain(|_, id| id.item != access_token.primary_id());
Ok(JsonResponse::new(json!({
@@ -587,7 +619,7 @@ impl JMAP {
.into_http_response())
}
- pub fn assert_supported_directory(&self) -> trc::Result<()> {
+ fn assert_supported_directory(&self) -> trc::Result<()> {
let class = match &self.core.storage.directory.store {
DirectoryInner::Internal(_) => return Ok(()),
DirectoryInner::Ldap(_) => "LDAP",
diff --git a/crates/jmap/src/api/management/queue.rs b/crates/jmap/src/api/management/queue.rs
index 596abf65..c19bc707 100644
--- a/crates/jmap/src/api/management/queue.rs
+++ b/crates/jmap/src/api/management/queue.rs
@@ -4,8 +4,10 @@
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
+use std::future::Future;
+
use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine};
-use common::auth::AccessToken;
+use common::{auth::AccessToken, ipc::QueueEvent, Server};
use directory::{
backend::internal::{manage::ManageDirectory, PrincipalField},
Permission, Type,
@@ -19,7 +21,10 @@ use mail_auth::{
use mail_parser::DateTime;
use serde::{Deserializer, Serializer};
use serde_json::json;
-use smtp::queue::{self, ErrorDetails, HostResponse, QueueId, Status};
+use smtp::{
+ queue::{self, spool::SmtpSpool, ErrorDetails, HostResponse, QueueId, Status},
+ reporting::{dmarc::DmarcReporting, tls::TlsReporting},
+};
use store::{
write::{key::DeserializeBigEndian, now, Bincode, QueueClass, ReportEvent, ValueClass},
Deserialize, IterateParams, ValueKey,
@@ -27,10 +32,7 @@ use store::{
use trc::AddContext;
use utils::url_params::UrlParams;
-use crate::{
- api::{http::ToHttpResponse, HttpRequest, HttpResponse, JsonResponse},
- JMAP,
-};
+use crate::api::{http::ToHttpResponse, HttpRequest, HttpResponse, JsonResponse};
use super::{decode_path_element, FutureTimestamp};
@@ -106,8 +108,17 @@ pub enum Report {
},
}
-impl JMAP {
- pub async fn handle_manage_queue(
+pub trait QueueManagement: Sync + Send {
+ fn handle_manage_queue(
+ &self,
+ req: &HttpRequest,
+ path: Vec<&str>,
+ access_token: &AccessToken,
+ ) -> impl Future<Output = trc::Result<HttpResponse>> + Send;
+}
+
+impl QueueManagement for Server {
+ async fn handle_manage_queue(
&self,
req: &HttpRequest,
path: Vec<&str>,
@@ -270,7 +281,6 @@ impl JMAP {
access_token.assert_has_permission(Permission::MessageQueueGet)?;
if let Some(message) = self
- .smtp
.read_message(queue_id.parse().unwrap_or_default())
.await
.filter(|message| {
@@ -298,7 +308,6 @@ impl JMAP {
let item = params.get("filter");
if let Some(mut message) = self
- .smtp
.read_message(queue_id.parse().unwrap_or_default())
.await
.filter(|message| {
@@ -329,9 +338,9 @@ impl JMAP {
if found {
let next_event = message.next_event().unwrap_or_default();
message
- .save_changes(&self.smtp, prev_event.into(), next_event.into())
+ .save_changes(self, prev_event.into(), next_event.into())
.await;
- let _ = self.smtp.inner.queue_tx.send(queue::Event::Reload).await;
+ let _ = self.inner.ipc.queue_tx.send(QueueEvent::Reload).await;
}
Ok(JsonResponse::new(json!({
@@ -347,7 +356,6 @@ impl JMAP {
access_token.assert_has_permission(Permission::MessageQueueDelete)?;
if let Some(mut message) = self
- .smtp
.read_message(queue_id.parse().unwrap_or_default())
.await
.filter(|message| {
@@ -411,14 +419,14 @@ impl JMAP {
}) {
let next_event = message.next_event().unwrap_or_default();
message
- .save_changes(&self.smtp, next_event.into(), prev_event.into())
+ .save_changes(self, next_event.into(), prev_event.into())
.await;
} else {
- message.remove(&self.smtp, prev_event).await;
+ message.remove(self, prev_event).await;
}
}
} else {
- message.remove(&self.smtp, prev_event).await;
+ message.remove(self, prev_event).await;
found = true;
}
@@ -528,7 +536,6 @@ impl JMAP {
{
let mut rua = Vec::new();
if let Some(report) = self
- .smtp
.generate_dmarc_aggregate_report(&event, &mut rua, None, 0)
.await?
{
@@ -542,7 +549,6 @@ impl JMAP {
{
let mut rua = Vec::new();
if let Some(report) = self
- .smtp
.generate_tls_aggregate_report(&[event.clone()], &mut rua, None, 0)
.await?
{
@@ -573,7 +579,7 @@ impl JMAP {
.as_ref()
.map_or(true, |domains| domains.contains(&event.domain)) =>
{
- self.smtp.delete_dmarc_report(event).await;
+ self.delete_dmarc_report(event).await;
true
}
QueueClass::TlsReportHeader(event)
@@ -581,7 +587,7 @@ impl JMAP {
.as_ref()
.map_or(true, |domains| domains.contains(&event.domain)) =>
{
- self.smtp.delete_tls_report(vec![event]).await;
+ self.delete_tls_report(vec![event]).await;
true
}
_ => false,
diff --git a/crates/jmap/src/api/management/reload.rs b/crates/jmap/src/api/management/reload.rs
index f396e1b6..4c4fe110 100644
--- a/crates/jmap/src/api/management/reload.rs
+++ b/crates/jmap/src/api/management/reload.rs
@@ -4,20 +4,36 @@
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
-use common::auth::AccessToken;
+use common::{auth::AccessToken, ipc::HousekeeperEvent, Server};
use directory::Permission;
use hyper::Method;
use serde_json::json;
+use std::future::Future;
use utils::url_params::UrlParams;
use crate::{
api::{http::ToHttpResponse, HttpRequest, HttpResponse, JsonResponse},
- services::housekeeper::Event,
- JMAP,
+ JmapMethods,
};
-impl JMAP {
- pub async fn handle_manage_reload(
+pub trait ManageReload: Sync + Send {
+ fn handle_manage_reload(
+ &self,
+ req: &HttpRequest,
+ path: Vec<&str>,
+ access_token: &AccessToken,
+ ) -> impl Future<Output = trc::Result<HttpResponse>> + Send;
+
+ fn handle_manage_update(
+ &self,
+ req: &HttpRequest,
+ path: Vec<&str>,
+ access_token: &AccessToken,
+ ) -> impl Future<Output = trc::Result<HttpResponse>> + Send;
+}
+
+impl ManageReload for Server {
+ async fn handle_manage_reload(
&self,
req: &HttpRequest,
path: Vec<&str>,
@@ -28,10 +44,10 @@ impl JMAP {
match (path.get(1).copied(), req.method()) {
(Some("lookup"), &Method::GET) => {
- let result = self.core.reload_lookups().await?;
+ let result = self.reload_lookups().await?;
// Update core
if let Some(core) = result.new_core {
- self.shared_core.store(core.into());
+ self.inner.shared_core.store(core.into());
}
Ok(JsonResponse::new(json!({
@@ -40,13 +56,14 @@ impl JMAP {
.into_http_response())
}
(Some("certificate"), &Method::GET) => Ok(JsonResponse::new(json!({
- "data": self.core.reload_certificates().await?.config,
+ "data": self.reload_certificates().await?.config,
}))
.into_http_response()),
(Some("server.blocked-ip"), &Method::GET) => {
- let result = self.core.reload_blocked_ips().await?;
+ let result = self.reload_blocked_ips().await?;
+
// Increment version counter
- self.core.network.blocked_ips.increment_version();
+ self.increment_blocked_version();
Ok(JsonResponse::new(json!({
"data": result.config,
@@ -54,28 +71,29 @@ impl JMAP {
.into_http_response())
}
(_, &Method::GET) => {
- let result = self.core.reload().await?;
+ let result = self.reload().await?;
if !UrlParams::new(req.uri().query()).has_key("dry-run") {
if let Some(core) = result.new_core {
// Update core
- self.shared_core.store(core.into());
+ self.inner.shared_core.store(core.into());
// Increment version counter
- self.inner.increment_config_version();
+ self.increment_config_version();
}
if let Some(tracers) = result.tracers {
// Update tracers
#[cfg(feature = "enterprise")]
- tracers.update(self.shared_core.load().is_enterprise_edition());
+ tracers.update(self.inner.shared_core.load().is_enterprise_edition());
#[cfg(not(feature = "enterprise"))]
tracers.update(false);
}
// Reload settings
self.inner
+ .ipc
.housekeeper_tx
- .send(Event::ReloadSettings)
+ .send(HousekeeperEvent::ReloadSettings)
.await
.map_err(|err| {
trc::EventType::Server(trc::ServerEvent::ThreadError)
@@ -94,7 +112,7 @@ impl JMAP {
}
}
- pub async fn handle_manage_update(
+ async fn handle_manage_update(
&self,
req: &HttpRequest,
path: Vec<&str>,
@@ -119,7 +137,11 @@ impl JMAP {
// Validate the access token
access_token.assert_has_permission(Permission::UpdateWebadmin)?;
- self.inner.webadmin.update_and_unpack(&self.core).await?;
+ self.inner
+ .data
+ .webadmin
+ .update_and_unpack(&self.core)
+ .await?;
Ok(JsonResponse::new(json!({
"data": (),
diff --git a/crates/jmap/src/api/management/report.rs b/crates/jmap/src/api/management/report.rs
index daa91451..5540d41b 100644
--- a/crates/jmap/src/api/management/report.rs
+++ b/crates/jmap/src/api/management/report.rs
@@ -4,7 +4,9 @@
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
-use common::auth::AccessToken;
+use std::future::Future;
+
+use common::{auth::AccessToken, Server};
use directory::{
backend::internal::{manage::ManageDirectory, PrincipalField},
Permission, Type,
@@ -23,10 +25,7 @@ use store::{
use trc::AddContext;
use utils::url_params::UrlParams;
-use crate::{
- api::{http::ToHttpResponse, HttpRequest, HttpResponse, JsonResponse},
- JMAP,
-};
+use crate::api::{http::ToHttpResponse, HttpRequest, HttpResponse, JsonResponse};
use super::decode_path_element;
@@ -36,8 +35,17 @@ enum ReportType {
Arf,
}
-impl JMAP {
- pub async fn handle_manage_reports(
+pub trait ManageReports: Sync + Send {
+ fn handle_manage_reports(
+ &self,
+ req: &HttpRequest,
+ path: Vec<&str>,
+ access_token: &AccessToken,
+ ) -> impl Future<Output = trc::Result<HttpResponse>> + Send;
+}
+
+impl ManageReports for Server {
+ async fn handle_manage_reports(
&self,
req: &HttpRequest,
path: Vec<&str>,
diff --git a/crates/jmap/src/api/management/settings.rs b/crates/jmap/src/api/management/settings.rs
index 6844c503..ccabef51 100644
--- a/crates/jmap/src/api/management/settings.rs
+++ b/crates/jmap/src/api/management/settings.rs
@@ -4,19 +4,17 @@
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
-use common::auth::AccessToken;
+use common::{auth::AccessToken, Server};
use directory::Permission;
use hyper::Method;
use serde_json::json;
use store::ahash::AHashMap;
use utils::{config::ConfigKey, map::vec_map::VecMap, url_params::UrlParams};
-use crate::{
- api::{http::ToHttpResponse, HttpRequest, HttpResponse, JsonResponse},
- JMAP,
-};
+use crate::api::{http::ToHttpResponse, HttpRequest, HttpResponse, JsonResponse};
use super::decode_path_element;
+use std::future::Future;
#[derive(Debug, serde::Serialize, serde::Deserialize)]
#[serde(tag = "type")]
@@ -34,8 +32,18 @@ pub enum UpdateSettings {
},
}
-impl JMAP {
- pub async fn handle_manage_settings(
+pub trait ManageSettings: Sync + Send {
+ fn handle_manage_settings(
+ &self,
+ req: &HttpRequest,
+ path: Vec<&str>,
+ body: Option<Vec<u8>>,
+ access_token: &AccessToken,
+ ) -> impl Future<Output = trc::Result<HttpResponse>> + Send;
+}
+
+impl ManageSettings for Server {
+ async fn handle_manage_settings(
&self,
req: &HttpRequest,
path: Vec<&str>,
diff --git a/crates/jmap/src/api/management/sieve.rs b/crates/jmap/src/api/management/sieve.rs
index eb918185..85159378 100644
--- a/crates/jmap/src/api/management/sieve.rs
+++ b/crates/jmap/src/api/management/sieve.rs
@@ -6,18 +6,16 @@
use std::time::SystemTime;
-use common::{auth::AccessToken, scripts::ScriptModification, IntoString};
+use common::{auth::AccessToken, scripts::ScriptModification, IntoString, Server};
use directory::Permission;
use hyper::Method;
use serde_json::json;
use sieve::{runtime::Variable, Envelope};
-use smtp::scripts::{ScriptParameters, ScriptResult};
+use smtp::scripts::{event_loop::RunScript, ScriptParameters, ScriptResult};
+use std::future::Future;
use utils::url_params::UrlParams;
-use crate::{
- api::{http::ToHttpResponse, HttpRequest, HttpResponse, JsonResponse},
- JMAP,
-};
+use crate::api::{http::ToHttpResponse, HttpRequest, HttpResponse, JsonResponse};
#[derive(Debug, serde::Serialize)]
#[serde(tag = "action")]
@@ -36,8 +34,18 @@ pub enum Response {
Discard,
}
-impl JMAP {
- pub async fn handle_run_sieve(
+pub trait SieveHandler: Sync + Send {
+ fn handle_run_sieve(
+ &self,
+ req: &HttpRequest,
+ path: Vec<&str>,
+ body: Option<Vec<u8>>,
+ access_token: &AccessToken,
+ ) -> impl Future<Output = trc::Result<HttpResponse>> + Send;
+}
+
+impl SieveHandler for Server {
+ async fn handle_run_sieve(
&self,
req: &HttpRequest,
path: Vec<&str>,
@@ -103,7 +111,7 @@ impl JMAP {
}
// Run script
- let result = match self.smtp.run_script(script_id, script, params, 0).await {
+ let result = match self.run_script(script_id, script, params, 0).await {
ScriptResult::Accept { modifications } => Response::Accept { modifications },
ScriptResult::Replace {
message,
diff --git a/crates/jmap/src/api/management/stores.rs b/crates/jmap/src/api/management/stores.rs
index b86c88be..0b9dea48 100644
--- a/crates/jmap/src/api/management/stores.rs
+++ b/crates/jmap/src/api/management/stores.rs
@@ -5,7 +5,12 @@
*/
use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine};
-use common::{auth::AccessToken, manager::webadmin::Resource};
+use common::{
+ auth::AccessToken,
+ ipc::{HousekeeperEvent, PurgeType},
+ manager::webadmin::Resource,
+ Server,
+};
use directory::{
backend::internal::manage::{self, ManageDirectory},
Permission,
@@ -19,14 +24,30 @@ use crate::{
http::{HttpSessionData, ToHttpResponse},
HttpRequest, HttpResponse, JsonResponse,
},
- services::housekeeper::{Event, PurgeType},
- JMAP,
+ services::index::Indexer,
};
-use super::decode_path_element;
+use super::{decode_path_element, enterprise::undelete::UndeleteApi};
+use std::future::Future;
+
+pub trait ManageStore: Sync + Send {
+ fn handle_manage_store(
+ &self,
+ req: &HttpRequest,
+ path: Vec<&str>,
+ body: Option<Vec<u8>>,
+ session: &HttpSessionData,
+ access_token: &AccessToken,
+ ) -> impl Future<Output = trc::Result<HttpResponse>> + Send;
+
+ fn housekeeper_request(
+ &self,
+ event: HousekeeperEvent,
+ ) -> impl Future<Output = trc::Result<HttpResponse>> + Send;
+}
-impl JMAP {
- pub async fn handle_manage_store(
+impl ManageStore for Server {
+ async fn handle_manage_store(
&self,
req: &HttpRequest,
path: Vec<&str>,
@@ -75,7 +96,7 @@ impl JMAP {
// Validate the access token
access_token.assert_has_permission(Permission::PurgeBlobStore)?;
- self.housekeeper_request(Event::Purge(PurgeType::Blobs {
+ self.housekeeper_request(HousekeeperEvent::Purge(PurgeType::Blobs {
store: self.core.storage.data.clone(),
blob_store: self.core.storage.blob.clone(),
}))
@@ -95,7 +116,7 @@ impl JMAP {
self.core.storage.data.clone()
};
- self.housekeeper_request(Event::Purge(PurgeType::Data(store)))
+ self.housekeeper_request(HousekeeperEvent::Purge(PurgeType::Data(store)))
.await
}
(Some("purge"), Some("lookup"), id, &Method::GET) => {
@@ -112,7 +133,7 @@ impl JMAP {
self.core.storage.lookup.clone()
};
- self.housekeeper_request(Event::Purge(PurgeType::Lookup(store)))
+ self.housekeeper_request(HousekeeperEvent::Purge(PurgeType::Lookup(store)))
.await
}
(Some("purge"), Some("account"), id, &Method::GET) => {
@@ -131,7 +152,7 @@ impl JMAP {
None
};
- self.housekeeper_request(Event::Purge(PurgeType::Account(account_id)))
+ self.housekeeper_request(HousekeeperEvent::Purge(PurgeType::Account(account_id)))
.await
}
(Some("reindex"), id, None, &Method::GET) => {
@@ -192,12 +213,17 @@ impl JMAP {
}
}
- async fn housekeeper_request(&self, event: Event) -> trc::Result<HttpResponse> {
- self.inner.housekeeper_tx.send(event).await.map_err(|err| {
- trc::EventType::Server(trc::ServerEvent::ThreadError)
- .reason(err)
- .details("Failed to send housekeeper event")
- })?;
+ async fn housekeeper_request(&self, event: HousekeeperEvent) -> trc::Result<HttpResponse> {
+ self.inner
+ .ipc
+ .housekeeper_tx
+ .send(event)
+ .await
+ .map_err(|err| {
+ trc::EventType::Server(trc::ServerEvent::ThreadError)
+ .reason(err)
+ .details("Failed to send housekeeper event")
+ })?;
Ok(JsonResponse::new(json!({
"data": (),