Files
Stalwart/crates/common/src/config/inner.rs

247 lines
8.0 KiB
Rust

/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
use super::server::tls::{build_self_signed_cert, parse_certificates};
use crate::{
CacheSwap, Caches, Data, DavResource, DavResources, MailboxCache, MessageStoreCache,
MessageUidCache, TlsConnectors,
auth::{AccessToken, roles::RolePermissions},
config::{
smtp::resolver::{Policy, Tlsa},
spamfilter::SpamClassifier,
},
listener::blocked::BlockedIps,
manager::webadmin::WebAdminManager,
};
use ahash::{AHashMap, AHashSet};
use arc_swap::ArcSwap;
use mail_auth::{MX, Parameters, Txt};
use mail_send::smtp::tls::build_tls_connector;
use parking_lot::RwLock;
use std::{
net::{IpAddr, Ipv4Addr, Ipv6Addr},
sync::Arc,
};
use utils::{
cache::{Cache, CacheWithTtl},
config::Config,
snowflake::SnowflakeIdGenerator,
};
impl Data {
pub fn parse(config: &mut Config) -> Self {
// Parse certificates
let mut certificates = AHashMap::new();
let mut subject_names = AHashSet::new();
parse_certificates(config, &mut certificates, &mut subject_names);
if subject_names.is_empty() {
subject_names.insert("localhost".to_string());
}
// Build and test snowflake id generator
let node_id = config
.property::<u64>("cluster.node-id")
.unwrap_or_else(store::rand::random);
let id_generator = SnowflakeIdGenerator::with_node_id(node_id);
if !id_generator.is_valid() {
panic!("Invalid system time, panicking to avoid data corruption");
}
Data {
spam_classifier: ArcSwap::from_pointee(SpamClassifier::default()),
tls_certificates: ArcSwap::from_pointee(certificates),
tls_self_signed_cert: build_self_signed_cert(
subject_names.into_iter().collect::<Vec<_>>(),
)
.or_else(|err| {
config.new_build_error("certificate.self-signed", err);
build_self_signed_cert(vec!["localhost".to_string()])
})
.ok()
.map(Arc::new),
blocked_ips: RwLock::new(BlockedIps::parse(config).blocked_ip_addresses),
jmap_id_gen: id_generator.clone(),
queue_id_gen: id_generator.clone(),
span_id_gen: id_generator,
queue_status: true.into(),
webadmin: config
.value("webadmin.path")
.map(|path| WebAdminManager::new(path.into()))
.unwrap_or_default(),
logos: Default::default(),
smtp_connectors: TlsConnectors::default(),
asn_geo_data: Default::default(),
}
}
}
impl Caches {
pub fn parse(config: &mut Config) -> Self {
const MB_50: u64 = 50 * 1024 * 1024;
const MB_10: u64 = 10 * 1024 * 1024;
const MB_5: u64 = 5 * 1024 * 1024;
const MB_1: u64 = 1024 * 1024;
Caches {
access_tokens: Cache::from_config(
config,
"access-token",
MB_10,
(std::mem::size_of::<AccessToken>() + 255) as u64,
),
http_auth: Cache::from_config(
config,
"http-auth",
MB_1,
(50 + std::mem::size_of::<u32>()) as u64,
),
permissions: Cache::from_config(
config,
"permission",
MB_5,
std::mem::size_of::<RolePermissions>() as u64,
),
messages: Cache::from_config(
config,
"message",
MB_50,
(std::mem::size_of::<u32>()
+ std::mem::size_of::<CacheSwap<MessageStoreCache>>()
+ (1024 * std::mem::size_of::<MessageUidCache>())
+ (15 * (std::mem::size_of::<MailboxCache>() + 60))) as u64,
),
files: Cache::from_config(
config,
"files",
MB_10,
(std::mem::size_of::<DavResources>() + (500 * std::mem::size_of::<DavResource>()))
as u64,
),
events: Cache::from_config(
config,
"events",
MB_10,
(std::mem::size_of::<DavResources>() + (500 * std::mem::size_of::<DavResource>()))
as u64,
),
contacts: Cache::from_config(
config,
"contacts",
MB_10,
(std::mem::size_of::<DavResources>() + (500 * std::mem::size_of::<DavResource>()))
as u64,
),
scheduling: Cache::from_config(
config,
"scheduling",
MB_1,
(std::mem::size_of::<DavResources>() + (500 * std::mem::size_of::<DavResource>()))
as u64,
),
dns_txt: CacheWithTtl::from_config(
config,
"dns.txt",
MB_5,
(std::mem::size_of::<Txt>() + 255) as u64,
),
dns_mx: CacheWithTtl::from_config(
config,
"dns.mx",
MB_5,
((std::mem::size_of::<MX>() + 255) * 2) as u64,
),
dns_ptr: CacheWithTtl::from_config(
config,
"dns.ptr",
MB_1,
(std::mem::size_of::<IpAddr>() + 255) as u64,
),
dns_ipv4: CacheWithTtl::from_config(
config,
"dns.ipv4",
MB_5,
((std::mem::size_of::<Ipv4Addr>() + 255) * 2) as u64,
),
dns_ipv6: CacheWithTtl::from_config(
config,
"dns.ipv6",
MB_5,
((std::mem::size_of::<Ipv6Addr>() + 255) * 2) as u64,
),
dns_tlsa: CacheWithTtl::from_config(
config,
"dns.tlsa",
MB_1,
(std::mem::size_of::<Tlsa>() + 255) as u64,
),
dbs_mta_sts: CacheWithTtl::from_config(
config,
"dns.mta-sts",
MB_1,
(std::mem::size_of::<Policy>() + 255) as u64,
),
dns_rbl: CacheWithTtl::from_config(
config,
"dns.rbl",
MB_5,
((std::mem::size_of::<Ipv4Addr>() + 255) * 2) as u64,
),
}
}
#[allow(clippy::type_complexity)]
#[inline(always)]
pub fn build_auth_parameters<T>(
&self,
params: T,
) -> Parameters<
'_,
T,
CacheWithTtl<String, Txt>,
CacheWithTtl<String, Arc<Vec<MX>>>,
CacheWithTtl<String, Arc<Vec<Ipv4Addr>>>,
CacheWithTtl<String, Arc<Vec<Ipv6Addr>>>,
CacheWithTtl<IpAddr, Arc<Vec<String>>>,
> {
Parameters {
params,
cache_txt: Some(&self.dns_txt),
cache_mx: Some(&self.dns_mx),
cache_ptr: Some(&self.dns_ptr),
cache_ipv4: Some(&self.dns_ipv4),
cache_ipv6: Some(&self.dns_ipv6),
}
}
}
impl Default for Data {
fn default() -> Self {
Self {
spam_classifier: Default::default(),
tls_certificates: Default::default(),
tls_self_signed_cert: Default::default(),
blocked_ips: Default::default(),
jmap_id_gen: Default::default(),
queue_id_gen: Default::default(),
span_id_gen: Default::default(),
queue_status: true.into(),
webadmin: Default::default(),
logos: Default::default(),
smtp_connectors: Default::default(),
asn_geo_data: Default::default(),
}
}
}
impl Default for TlsConnectors {
fn default() -> Self {
TlsConnectors {
pki_verify: build_tls_connector(false),
dummy_verify: build_tls_connector(true),
}
}
}