diff options
Diffstat (limited to 'crates/jmap/src/api/management')
-rw-r--r-- | crates/jmap/src/api/management/dkim.rs | 40 | ||||
-rw-r--r-- | crates/jmap/src/api/management/dns.rs | 38 | ||||
-rw-r--r-- | crates/jmap/src/api/management/enterprise/telemetry.rs | 23 | ||||
-rw-r--r-- | crates/jmap/src/api/management/enterprise/undelete.rs | 22 | ||||
-rw-r--r-- | crates/jmap/src/api/management/log.rs | 20 | ||||
-rw-r--r-- | crates/jmap/src/api/management/mod.rs | 31 | ||||
-rw-r--r-- | crates/jmap/src/api/management/principal.rs | 74 | ||||
-rw-r--r-- | crates/jmap/src/api/management/queue.rs | 46 | ||||
-rw-r--r-- | crates/jmap/src/api/management/reload.rs | 56 | ||||
-rw-r--r-- | crates/jmap/src/api/management/report.rs | 22 | ||||
-rw-r--r-- | crates/jmap/src/api/management/settings.rs | 22 | ||||
-rw-r--r-- | crates/jmap/src/api/management/sieve.rs | 26 | ||||
-rw-r--r-- | crates/jmap/src/api/management/stores.rs | 58 |
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": (), |