/* * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC * * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL */ #![warn(clippy::large_futures)] use crate::auth::{AccessTokenInner, EmailAddress}; use crate::manager::application::WebApplications; use crate::network::asn::AsnGeoLookupData; use crate::{ auth::{AccountCache, DomainCache, EmailCache, MailingListCache, RoleCache, TenantCache}, config::{ mailstore::{ email::EmailConfig, imap::ImapConfig, scripts::Scripting, spamfilter::{IpResolver, SpamClassifier, SpamFilterConfig}, }, smtp::auth::DkimSigners, }, ipc::TrainTaskController, network::security::BlockedIps, }; use ahash::{AHashMap, AHashSet}; use arc_swap::ArcSwap; use auth::oauth::config::OAuthConfig; use calcard::common::timezone::Tz; use config::{ groupware::GroupwareConfig, mailstore::jmap::JmapConfig, network::Network, smtp::{ SmtpConfig, resolver::{Policy, Tlsa}, }, storage::Storage, telemetry::Metrics, }; use ipc::{BroadcastEvent, PushEvent, QueueEvent, ReportingEvent}; use mail_auth::{MX, RecordSet, Txt}; use manager::application::Resource; use parking_lot::{Mutex, RwLock}; use rustls::sign::CertifiedKey; use std::sync::atomic::AtomicU64; use std::{ net::{IpAddr, Ipv4Addr, Ipv6Addr}, sync::{Arc, atomic::AtomicBool}, time::{Duration, Instant}, }; use store::InMemoryStore; use tinyvec::TinyVec; use tokio::sync::{Notify, Semaphore, mpsc}; use tokio_rustls::TlsConnector; use types::{acl::AclGrant, special_use::SpecialUse}; use utils::{ cache::{Cache, CacheWithTtl}, snowflake::SnowflakeIdGenerator, }; pub mod auth; pub mod cache; pub mod config; pub mod expr; pub mod i18n; pub mod ipc; pub mod manager; pub mod network; pub mod scripts; pub mod sharing; pub mod storage; pub mod telemetry; // SPDX-SnippetBegin // SPDX-FileCopyrightText: 2020 Stalwart Labs LLC // SPDX-License-Identifier: LicenseRef-SEL #[cfg(feature = "enterprise")] pub mod enterprise; // SPDX-SnippetEnd pub use psl; pub static VERSION_PRIVATE: &str = env!("CARGO_PKG_VERSION"); pub static VERSION_PUBLIC: &str = "1.0.0"; pub static USER_AGENT: &str = "Stalwart/1.0.0"; pub static DAEMON_NAME: &str = concat!("Stalwart v", env!("CARGO_PKG_VERSION"),); pub static PROD_ID: &str = "-//Stalwart Labs LLC//Stalwart Server//EN"; /* Schema history: 1 - v0.12.0 2 - v0.12.4 3 - v0.13.0 4 - v0.14.0 5 - v0.15.0 6 - v0.16.0 */ pub const DATABASE_SCHEMA_VERSION: u32 = 6; pub const LONG_1D_SLUMBER: Duration = Duration::from_secs(60 * 60 * 24); pub const LONG_1Y_SLUMBER: Duration = Duration::from_secs(60 * 60 * 24 * 365); pub const IPC_CHANNEL_BUFFER: usize = 1024; pub const KV_ACME: u8 = 0; pub const KV_OAUTH: u8 = 1; pub const KV_RATE_LIMIT_RCPT: u8 = 2; pub const KV_RATE_LIMIT_SCAN: u8 = 3; pub const KV_RATE_LIMIT_LOITER: u8 = 4; pub const KV_RATE_LIMIT_AUTH: u8 = 5; pub const KV_RATE_LIMIT_SMTP: u8 = 6; pub const KV_RATE_LIMIT_CONTACT: u8 = 7; pub const KV_RATE_LIMIT_HTTP_AUTHENTICATED: u8 = 8; pub const KV_RATE_LIMIT_HTTP_ANONYMOUS: u8 = 9; pub const KV_RATE_LIMIT_IMAP: u8 = 10; pub const KV_QUOTA_BLOB: u8 = 11; pub const KV_GREYLIST: u8 = 16; pub const KV_LOCK_QUEUE_MESSAGE: u8 = 21; pub const KV_LOCK_TASK: u8 = 23; pub const KV_LOCK_DAV: u8 = 25; pub const KV_SIEVE_ID: u8 = 26; #[derive(Clone)] pub struct Server { pub inner: Arc, pub core: Arc, } pub struct Inner { pub shared_core: ArcSwap, pub data: Data, pub cache: Caches, pub ipc: Ipc, } #[allow(clippy::type_complexity)] pub struct Data { pub spam_classifier: ArcSwap, pub tls_certificates: ArcSwap, Arc>>, pub tls_self_signed_cert: Option>, pub blocked_ips: RwLock, pub lookup_stores: ArcSwap, InMemoryStore>>, pub asn_geo_data: AsnGeoLookupData, pub jmap_id_gen: SnowflakeIdGenerator, pub queue_id_gen: SnowflakeIdGenerator, pub span_id_gen: SnowflakeIdGenerator, pub registry_id_gen: SnowflakeIdGenerator, pub queue_status: AtomicBool, pub applications: WebApplications, pub logos: Mutex, LogoCache>>, pub smtp_connectors: TlsConnectors, } #[derive(Clone)] pub struct LogoCache { domain_id: u32, tenant_id: Option, data: Option>>, } pub struct Caches { pub access_tokens: Cache>, pub http_auth: Cache, HttpAuthCache>, pub messages: Cache>, pub files: Cache>, pub contacts: Cache>, pub events: Cache>, pub scheduling: Cache>, pub emails: Cache, pub emails_negative: CacheWithTtl, pub domain_names: Cache, u32>, pub domain_names_negative: CacheWithTtl, ()>, pub domains: Cache>, pub accounts: Cache>, pub roles: Cache>, pub tenants: Cache>, pub lists: Cache>, pub dkim_signers: Cache>, pub dns_txt: CacheWithTtl, Txt>, pub dns_mx: CacheWithTtl, RecordSet>, pub dns_ptr: CacheWithTtl>>, pub dns_ipv4: CacheWithTtl, RecordSet>, pub dns_ipv6: CacheWithTtl, RecordSet>, pub dns_tlsa: CacheWithTtl, Arc>, pub dns_mta_sts: CacheWithTtl, Arc>, pub dns_rbl: CacheWithTtl, Option>>, pub negative_cache_ttl: Duration, } #[derive(Debug, Clone)] pub struct MessageStoreCache { pub emails: Arc, pub mailboxes: Arc, pub update_lock: Arc, pub last_change_id: u64, pub size: u64, } #[derive(Debug, Clone)] pub struct MailboxesCache { pub change_id: u64, pub index: AHashMap, pub items: Box<[MailboxCache]>, pub size: u64, } #[derive(Debug, Clone)] pub struct MessagesCache { pub change_id: u64, pub items: Box<[MessageCache]>, pub index: AHashMap, pub keywords: Box<[Box]>, pub size: u64, } #[derive(Debug, Clone)] pub struct MessageCache { pub document_id: u32, pub mailboxes: TinyVec<[MessageUidCache; 2]>, pub keywords: u128, pub thread_id: u32, pub change_id: u64, pub size: u32, } #[derive(Debug, Default, Clone, Copy)] pub struct MessageUidCache { pub mailbox_id: u32, pub uid: u32, } #[derive(Debug, Clone)] pub struct MailboxCache { pub document_id: u32, pub name: String, pub path: String, pub role: SpecialUse, pub parent_id: u32, pub sort_order: u32, pub subscribers: TinyVec<[u32; 4]>, pub uid_validity: u32, pub acls: TinyVec<[AclGrant; 2]>, } #[derive(Debug, Clone)] pub struct HttpAuthCache { pub account_id: u32, pub revision: u64, pub credential_id: Option, pub expires: Instant, } pub struct Ipc { pub push_tx: mpsc::Sender, pub task_tx: Arc, pub queue_tx: mpsc::Sender, pub report_tx: mpsc::Sender, pub broadcast_tx: Option>, pub train_task_controller: Arc, } pub struct TlsConnectors { pub pki_verify: TlsConnector, pub dummy_verify: TlsConnector, } pub struct NameWrapper(pub String); #[derive(Debug, Clone)] pub struct DavResources { pub base_path: String, pub paths: AHashSet, pub resources: Vec, pub item_change_id: u64, pub container_change_id: u64, pub highest_change_id: u64, pub size: u64, pub update_lock: Arc, } #[derive(Debug)] pub struct UpdateLock { pub semaphore: Semaphore, pub revision: AtomicU64, } #[derive(Debug, Clone)] pub struct DavPath { pub path: String, pub parent_id: Option, pub hierarchy_seq: u32, pub resource_idx: usize, } #[derive(Debug, Clone)] pub struct DavResource { pub document_id: u32, pub data: DavResourceMetadata, } #[derive(Debug, Clone, Copy)] pub struct DavResourcePath<'x> { pub path: &'x DavPath, pub resource: &'x DavResource, } #[derive(Debug, Clone)] pub enum DavResourceMetadata { File { name: String, size: Option, parent_id: Option, acls: TinyVec<[AclGrant; 2]>, }, Calendar { name: String, acls: TinyVec<[AclGrant; 2]>, preferences: TinyVec<[TinyCalendarPreferences; 2]>, }, CalendarEvent { names: TinyVec<[DavName; 2]>, start: i64, duration: u32, }, CalendarEventNotification { names: TinyVec<[DavName; 2]>, }, AddressBook { name: String, acls: TinyVec<[AclGrant; 2]>, }, ContactCard { names: TinyVec<[DavName; 2]>, }, } #[derive(Debug, Clone, Default)] pub struct TinyCalendarPreferences { pub account_id: u32, pub tz: Tz, pub flags: u16, } #[derive( rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, Debug, Default, Clone, PartialEq, Eq, )] #[rkyv(derive(Debug))] pub struct DavName { pub name: String, pub parent_id: u32, } #[derive(Clone)] pub struct Core { pub storage: Storage, pub sieve: Scripting, pub network: Network, pub oauth: OAuthConfig, pub email: EmailConfig, pub jmap: JmapConfig, pub imap: ImapConfig, pub smtp: SmtpConfig, pub spam: SpamFilterConfig, pub groupware: GroupwareConfig, pub metrics: Metrics, // SPDX-SnippetBegin // SPDX-FileCopyrightText: 2020 Stalwart Labs LLC // SPDX-License-Identifier: LicenseRef-SEL #[cfg(feature = "enterprise")] pub enterprise: Option, // SPDX-SnippetEnd } pub trait BuildServer { fn build_server(&self) -> Server; } impl BuildServer for Arc { fn build_server(&self) -> Server { Server { inner: self.clone(), core: self.shared_core.load_full(), } } } pub trait IntoString: Sized { fn into_string(self) -> String; } impl IntoString for Vec { fn into_string(self) -> String { String::from_utf8(self) .unwrap_or_else(|err| String::from_utf8_lossy(err.as_bytes()).into_owned()) } } #[derive(Debug, Clone, Eq)] pub struct ThrottleKey { pub hash: [u8; 32], } #[derive(Default)] pub struct ThrottleKeyHasher { hash: u64, } #[derive(Clone, Default)] pub struct ThrottleKeyHasherBuilder {} pub const DEFAULT_LOGO_BASE64: &str = "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\r\n\ AElFTkSuQmCC";