Registry testing - part 2

This commit is contained in:
mdecimus
2026-03-12 18:26:35 +01:00
parent 7c143c85f8
commit d45f1299d3
42 changed files with 1649 additions and 1064 deletions

View File

@@ -95,7 +95,7 @@ impl EmailConfig {
default_domain.name
} else {
bp.build_error(
ObjectType::Authentication.singleton(),
ObjectType::SystemSettings.singleton(),
format!(
"Default domain with ID {} not found",
system.default_domain_id

View File

@@ -6,6 +6,7 @@
use coordinator::Coordinator;
use directory::{Directories, Directory};
use registry::schema::prelude::ObjectType;
use std::{collections::HashMap, sync::Arc};
use store::{
BlobStore, InMemoryStore, RegistryStore, SearchStore, Store, registry::bootstrap::Bootstrap,
@@ -31,12 +32,20 @@ impl Storage {
pub async fn parse(bp: &mut Bootstrap) -> Self {
let memory = InMemoryStore::build(bp).await.unwrap_or_default();
let directory = Directories::build(bp).await;
let search = SearchStore::build(bp).await.unwrap_or_default();
if let Err(err) = search.create_indexes().await {
bp.build_warning(
ObjectType::SearchStore.singleton(),
format!("Failed to create search indexes: {err}"),
);
}
Storage {
registry: bp.registry.clone(),
data: bp.data_store.clone(),
blob: BlobStore::build(bp).await.unwrap_or_default(),
search: SearchStore::build(bp).await.unwrap_or_default(),
search,
coordinator: Coordinator::build(bp, &memory).await.unwrap_or_default(),
memory,
tracing: Store::build_tracing(bp).await.unwrap_or_default(),

View File

@@ -178,6 +178,7 @@ impl Tracers {
let lossy;
let events;
let events_policy;
let enable;
let typ = match tracer {
Tracer::Log(tracer) if tracer.enable => {
@@ -185,6 +186,7 @@ impl Tracers {
lossy = tracer.lossy;
events = tracer.events;
events_policy = tracer.events_policy;
enable = tracer.enable;
TelemetrySubscriberType::LogTracer(LogTracer {
path: tracer.path,
@@ -204,6 +206,7 @@ impl Tracers {
lossy = tracer.lossy;
events = tracer.events;
events_policy = tracer.events_policy;
enable = tracer.enable;
if !tracers
.iter()
@@ -226,6 +229,7 @@ impl Tracers {
lossy = tracer.lossy;
events = tracer.events;
events_policy = tracer.events_policy;
enable = tracer.enable;
if !tracers
.iter()
@@ -260,6 +264,7 @@ impl Tracers {
lossy = tracer.lossy;
events = tracer.events;
events_policy = tracer.events_policy;
enable = tracer.enable;
let headers = match tracer
.http_auth
@@ -328,6 +333,7 @@ impl Tracers {
lossy = tracer.lossy;
events = tracer.events;
events_policy = tracer.events_policy;
enable = tracer.enable;
let mut span_exporter = SpanExporter::builder()
.with_tonic()
@@ -374,6 +380,10 @@ impl Tracers {
_ => continue,
};
if !enable {
continue;
}
// Create tracer
let mut tracer = TelemetrySubscriber {
id: format!("t_{}", id.id()),

View File

@@ -37,8 +37,17 @@ impl Enterprise {
.await
.default_hostname;
let mut update_license = None;
let mut enterprise = bp.setting_infallible::<structs::Enterprise>().await;
// WARNING: TAMPERING WITH THIS FUNCTION IS STRICTLY PROHIBITED
// Any attempt to modify, bypass, or disable this license validation mechanism
// constitutes a severe violation of the Stalwart Enterprise License Agreement.
// Such actions may result in immediate termination of your license, legal action,
// and substantial financial penalties. Stalwart Labs LLC actively monitors for
// unauthorized modifications and will pursue all available legal remedies against
// violators to the fullest extent of the law, including but not limited to claims
// for copyright infringement, breach of contract, and fraud.
let license_result = match (
enterprise.license_key.secret().await,
enterprise.api_key.secret().await,
@@ -75,7 +84,16 @@ impl Enterprise {
result.key
}),
(Ok(None), Ok(None)) => {
#[cfg(not(feature = "test_mode"))]
return None;
#[cfg(feature = "test_mode")]
Ok(LicenseKey {
valid_to: store::write::now() + (86400 * 365),
valid_from: store::write::now() - 3600,
domain: server_hostname.to_string(),
accounts: 100,
})
}
(Err(err), _) => {
bp.build_error(ObjectType::Enterprise.singleton(), err);

View File

@@ -179,7 +179,9 @@ impl Core {
key: vec![u8::MAX; 32],
},
)
.set_values(subspace != SUBSPACE_INDEXES),
.set_values(
![SUBSPACE_INDEXES, SUBSPACE_REGISTRY_IDX].contains(&subspace),
),
|key, value| {
writer
.send((key.to_vec(), value.to_vec()))

View File

@@ -4,30 +4,22 @@
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
use crate::{auth::permissions::DefaultPermissions, network::dkim::generate_dkim_private_key};
use crate::auth::permissions::DefaultPermissions;
use registry::{
schema::{
enums::{DkimSignatureType, MtaInboundThrottleKey, MtaIpStrategy},
prelude::ObjectType,
structs::{
Authentication, Dkim1Signature, DkimPrivateKey, DkimSignature, Domain,
MtaConnectionStrategy, MtaDeliveryExpiration, MtaDeliveryExpirationAttempts,
MtaDeliveryExpirationTtl, MtaDeliverySchedule, MtaDeliveryScheduleInterval,
MtaDeliveryScheduleIntervals, MtaDeliveryScheduleIntervalsOrDefault,
MtaInboundThrottle, MtaQueueQuota, MtaRoute, MtaRouteCommon, MtaRouteMx,
MtaTlsStrategy, MtaVirtualQueue, OidcProvider, Rate, Role, SecretKey, SecretKeyValue,
SecretText, SecretTextValue, SystemSettings,
},
enums::*,
prelude::{ObjectType, SocketAddr},
structs::*,
},
types::{duration::Duration, error::Error, list::List, map::Map},
};
use std::str::FromStr;
use store::{
rand::{Rng, distr::Alphanumeric, rng},
registry::{
bootstrap::Bootstrap,
write::{RegistryWrite, RegistryWriteResult},
},
write::now,
};
use types::id::Id;
@@ -399,21 +391,24 @@ async fn insert_safe_defaults(bp: &mut Bootstrap) -> trc::Result<()> {
}
}
#[cfg(not(feature = "test_mode"))]
if let Some(domain_id) = default_domain_id {
let now = now();
let now = store::write::now();
let signature_rsa = DkimSignature::Dkim1RsaSha256(Dkim1Signature {
domain_id,
enabled: true,
selector: format!("rsa-{now}"),
private_key: DkimPrivateKey::Value(SecretTextValue {
secret: generate_dkim_private_key(DkimSignatureType::Dkim1RsaSha256)
.await?
.map_err(|err| {
trc::EventType::Dkim(trc::DkimEvent::BuildError)
.into_err()
.reason(err)
.caused_by(trc::location!())
})?,
secret: crate::network::dkim::generate_dkim_private_key(
DkimSignatureType::Dkim1RsaSha256,
)
.await?
.map_err(|err| {
trc::EventType::Dkim(trc::DkimEvent::BuildError)
.into_err()
.reason(err)
.caused_by(trc::location!())
})?,
}),
..Default::default()
});
@@ -422,14 +417,16 @@ async fn insert_safe_defaults(bp: &mut Bootstrap) -> trc::Result<()> {
enabled: true,
selector: format!("ed-{now}"),
private_key: DkimPrivateKey::Value(SecretTextValue {
secret: generate_dkim_private_key(DkimSignatureType::Dkim1Ed25519Sha256)
.await?
.map_err(|err| {
trc::EventType::Dkim(trc::DkimEvent::BuildError)
.into_err()
.reason(err)
.caused_by(trc::location!())
})?,
secret: crate::network::dkim::generate_dkim_private_key(
DkimSignatureType::Dkim1Ed25519Sha256,
)
.await?
.map_err(|err| {
trc::EventType::Dkim(trc::DkimEvent::BuildError)
.into_err()
.reason(err)
.caused_by(trc::location!())
})?,
}),
..Default::default()
});
@@ -455,5 +452,56 @@ async fn insert_safe_defaults(bp: &mut Bootstrap) -> trc::Result<()> {
.await?;
}
if bp
.registry
.count_object(ObjectType::NetworkListener)
.await?
== 0
{
for (protocol, name, port, use_tls) in [
(NetworkListenerProtocol::Smtp, "smtp", 25, false),
(NetworkListenerProtocol::Smtp, "submission", 587, false),
(NetworkListenerProtocol::Smtp, "submissions", 465, true),
(NetworkListenerProtocol::Imap, "imap", 143, false),
(NetworkListenerProtocol::Imap, "imaps", 993, true),
(NetworkListenerProtocol::Pop3, "pop3", 110, false),
(NetworkListenerProtocol::Pop3, "pop3s", 995, true),
(NetworkListenerProtocol::ManageSieve, "sieve", 4190, false),
(NetworkListenerProtocol::Http, "https", 443, true),
(NetworkListenerProtocol::Http, "http", 8080, false),
] {
bp.registry
.write(RegistryWrite::insert(
&NetworkListener {
bind: Map::new(vec![
SocketAddr::from_str(&format!("[::]:{port}")).unwrap(),
]),
name: name.to_string(),
protocol,
use_tls,
..Default::default()
}
.into(),
))
.await?;
}
}
if bp.registry.count_object(ObjectType::Tracer).await? == 0 {
bp.registry
.write(RegistryWrite::insert(
&Tracer::Log(TracerLog {
enable: true,
ansi: false,
prefix: "stalwart.log".into(),
rotate: LogRotateFrequency::Daily,
path: "/var/log/stalwart".into(),
..Default::default()
})
.into(),
))
.await?;
}
Ok(())
}