JMAP Registry API implementation - part 11
This commit is contained in:
@@ -67,8 +67,7 @@ impl Server {
|
||||
let username = UsernameParts::new(username);
|
||||
|
||||
// Try to authenticate as fallback admin if configured
|
||||
if let Some((fallback_user, fallback_hash)) =
|
||||
&self.core.network.security.fallback_admin
|
||||
if let Some((fallback_user, fallback_hash)) = &self.registry().recovery_admin()
|
||||
&& username.auth_as().address() == fallback_user
|
||||
{
|
||||
return if verify_secret_hash(fallback_hash, secret.as_bytes()).await? {
|
||||
|
||||
@@ -231,7 +231,7 @@ impl Server {
|
||||
.into_err()
|
||||
.details("Account no longer exists")
|
||||
})
|
||||
} else if let Some((_, secret)) = &self.core.network.security.fallback_admin {
|
||||
} else if let Some((_, secret)) = self.registry().recovery_admin() {
|
||||
Ok(secret.into())
|
||||
} else {
|
||||
Err(trc::AuthEvent::Error
|
||||
|
||||
@@ -197,186 +197,11 @@ impl PermissionsGroup {
|
||||
}
|
||||
|
||||
pub fn user() -> Self {
|
||||
let todo = "fix";
|
||||
let mut permissions = PermissionsGroup::default();
|
||||
for permission in [
|
||||
Permission::Authenticate,
|
||||
Permission::AuthenticateOauth,
|
||||
Permission::EmailSend,
|
||||
Permission::EmailReceive,
|
||||
Permission::ManageEncryption,
|
||||
Permission::ManagePasswords,
|
||||
Permission::JmapEmailGet,
|
||||
Permission::JmapMailboxGet,
|
||||
Permission::JmapThreadGet,
|
||||
Permission::JmapIdentityGet,
|
||||
Permission::JmapEmailSubmissionGet,
|
||||
Permission::JmapPushSubscriptionGet,
|
||||
Permission::JmapSieveScriptGet,
|
||||
Permission::JmapVacationResponseGet,
|
||||
Permission::JmapQuotaGet,
|
||||
Permission::JmapBlobGet,
|
||||
Permission::JmapEmailSet,
|
||||
Permission::JmapMailboxSet,
|
||||
Permission::JmapIdentitySet,
|
||||
Permission::JmapEmailSubmissionSet,
|
||||
Permission::JmapPushSubscriptionSet,
|
||||
Permission::JmapSieveScriptSet,
|
||||
Permission::JmapVacationResponseSet,
|
||||
Permission::JmapEmailChanges,
|
||||
Permission::JmapMailboxChanges,
|
||||
Permission::JmapThreadChanges,
|
||||
Permission::JmapIdentityChanges,
|
||||
Permission::JmapEmailSubmissionChanges,
|
||||
Permission::JmapQuotaChanges,
|
||||
Permission::JmapEmailCopy,
|
||||
Permission::JmapBlobCopy,
|
||||
Permission::JmapEmailImport,
|
||||
Permission::JmapEmailParse,
|
||||
Permission::JmapEmailQueryChanges,
|
||||
Permission::JmapMailboxQueryChanges,
|
||||
Permission::JmapEmailSubmissionQueryChanges,
|
||||
Permission::JmapSieveScriptQueryChanges,
|
||||
Permission::JmapQuotaQueryChanges,
|
||||
Permission::JmapEmailQuery,
|
||||
Permission::JmapMailboxQuery,
|
||||
Permission::JmapEmailSubmissionQuery,
|
||||
Permission::JmapSieveScriptQuery,
|
||||
Permission::JmapQuotaQuery,
|
||||
Permission::JmapSearchSnippet,
|
||||
Permission::JmapSieveScriptValidate,
|
||||
Permission::JmapBlobLookup,
|
||||
Permission::JmapBlobUpload,
|
||||
Permission::JmapEcho,
|
||||
Permission::ImapAuthenticate,
|
||||
Permission::ImapAclGet,
|
||||
Permission::ImapAclSet,
|
||||
Permission::ImapMyRights,
|
||||
Permission::ImapListRights,
|
||||
Permission::ImapAppend,
|
||||
Permission::ImapCapability,
|
||||
Permission::ImapId,
|
||||
Permission::ImapCopy,
|
||||
Permission::ImapMove,
|
||||
Permission::ImapCreate,
|
||||
Permission::ImapDelete,
|
||||
Permission::ImapEnable,
|
||||
Permission::ImapExpunge,
|
||||
Permission::ImapFetch,
|
||||
Permission::ImapIdle,
|
||||
Permission::ImapList,
|
||||
Permission::ImapLsub,
|
||||
Permission::ImapNamespace,
|
||||
Permission::ImapRename,
|
||||
Permission::ImapSearch,
|
||||
Permission::ImapSort,
|
||||
Permission::ImapSelect,
|
||||
Permission::ImapExamine,
|
||||
Permission::ImapStatus,
|
||||
Permission::ImapStore,
|
||||
Permission::ImapSubscribe,
|
||||
Permission::ImapThread,
|
||||
Permission::Pop3Authenticate,
|
||||
Permission::Pop3List,
|
||||
Permission::Pop3Uidl,
|
||||
Permission::Pop3Stat,
|
||||
Permission::Pop3Retr,
|
||||
Permission::Pop3Dele,
|
||||
Permission::SieveAuthenticate,
|
||||
Permission::SieveListScripts,
|
||||
Permission::SieveSetActive,
|
||||
Permission::SieveGetScript,
|
||||
Permission::SievePutScript,
|
||||
Permission::SieveDeleteScript,
|
||||
Permission::SieveRenameScript,
|
||||
Permission::SieveCheckScript,
|
||||
Permission::SieveHaveSpace,
|
||||
Permission::DavSyncCollection,
|
||||
Permission::DavExpandProperty,
|
||||
Permission::DavPrincipalAcl,
|
||||
Permission::DavPrincipalList,
|
||||
Permission::DavPrincipalSearch,
|
||||
Permission::DavPrincipalMatch,
|
||||
Permission::DavPrincipalSearchPropSet,
|
||||
Permission::DavFilePropFind,
|
||||
Permission::DavFilePropPatch,
|
||||
Permission::DavFileGet,
|
||||
Permission::DavFileMkCol,
|
||||
Permission::DavFileDelete,
|
||||
Permission::DavFilePut,
|
||||
Permission::DavFileCopy,
|
||||
Permission::DavFileMove,
|
||||
Permission::DavFileLock,
|
||||
Permission::DavFileAcl,
|
||||
Permission::DavCardPropFind,
|
||||
Permission::DavCardPropPatch,
|
||||
Permission::DavCardGet,
|
||||
Permission::DavCardMkCol,
|
||||
Permission::DavCardDelete,
|
||||
Permission::DavCardPut,
|
||||
Permission::DavCardCopy,
|
||||
Permission::DavCardMove,
|
||||
Permission::DavCardLock,
|
||||
Permission::DavCardAcl,
|
||||
Permission::DavCardQuery,
|
||||
Permission::DavCardMultiGet,
|
||||
Permission::DavCalPropFind,
|
||||
Permission::DavCalPropPatch,
|
||||
Permission::DavCalGet,
|
||||
Permission::DavCalMkCol,
|
||||
Permission::DavCalDelete,
|
||||
Permission::DavCalPut,
|
||||
Permission::DavCalCopy,
|
||||
Permission::DavCalMove,
|
||||
Permission::DavCalLock,
|
||||
Permission::DavCalAcl,
|
||||
Permission::DavCalQuery,
|
||||
Permission::DavCalMultiGet,
|
||||
Permission::DavCalFreeBusyQuery,
|
||||
Permission::CalendarAlarms,
|
||||
Permission::CalendarSchedulingSend,
|
||||
Permission::CalendarSchedulingReceive,
|
||||
Permission::JmapAddressBookGet,
|
||||
Permission::JmapAddressBookSet,
|
||||
Permission::JmapAddressBookChanges,
|
||||
Permission::JmapContactCardGet,
|
||||
Permission::JmapContactCardChanges,
|
||||
Permission::JmapContactCardQuery,
|
||||
Permission::JmapContactCardQueryChanges,
|
||||
Permission::JmapContactCardSet,
|
||||
Permission::JmapContactCardCopy,
|
||||
Permission::JmapContactCardParse,
|
||||
Permission::JmapFileNodeGet,
|
||||
Permission::JmapFileNodeSet,
|
||||
Permission::JmapFileNodeChanges,
|
||||
Permission::JmapFileNodeQuery,
|
||||
Permission::JmapFileNodeQueryChanges,
|
||||
Permission::JmapPrincipalGetAvailability,
|
||||
Permission::JmapPrincipalChanges,
|
||||
Permission::JmapPrincipalQuery,
|
||||
Permission::JmapPrincipalGet,
|
||||
Permission::JmapPrincipalQueryChanges,
|
||||
Permission::JmapShareNotificationGet,
|
||||
Permission::JmapShareNotificationSet,
|
||||
Permission::JmapShareNotificationChanges,
|
||||
Permission::JmapShareNotificationQuery,
|
||||
Permission::JmapShareNotificationQueryChanges,
|
||||
Permission::JmapCalendarGet,
|
||||
Permission::JmapCalendarSet,
|
||||
Permission::JmapCalendarChanges,
|
||||
Permission::JmapCalendarEventGet,
|
||||
Permission::JmapCalendarEventSet,
|
||||
Permission::JmapCalendarEventChanges,
|
||||
Permission::JmapCalendarEventQuery,
|
||||
Permission::JmapCalendarEventQueryChanges,
|
||||
Permission::JmapCalendarEventCopy,
|
||||
Permission::JmapCalendarEventParse,
|
||||
Permission::JmapCalendarEventNotificationGet,
|
||||
Permission::JmapCalendarEventNotificationSet,
|
||||
Permission::JmapCalendarEventNotificationChanges,
|
||||
Permission::JmapCalendarEventNotificationQuery,
|
||||
Permission::JmapCalendarEventNotificationQueryChanges,
|
||||
Permission::JmapParticipantIdentityGet,
|
||||
Permission::JmapParticipantIdentitySet,
|
||||
Permission::JmapParticipantIdentityChanges,
|
||||
] {
|
||||
permissions.enabled.set(permission as usize);
|
||||
|
||||
2
crates/common/src/cache/principals.rs
vendored
2
crates/common/src/cache/principals.rs
vendored
@@ -116,7 +116,7 @@ impl Server {
|
||||
}
|
||||
SubAddressing::Custom(custom) => {
|
||||
flags |= DOMAIN_FLAG_SUB_ADDRESSING;
|
||||
let mut bp = Bootstrap::new(self.registry().clone());
|
||||
let mut bp = Bootstrap::new_uninitialized(self.registry().clone());
|
||||
let custom = bp.compile_expr(
|
||||
ObjectId::new(ObjectType::Domain, domain_id.into()),
|
||||
&custom.ctx_custom_rule(),
|
||||
|
||||
2
crates/common/src/cache/reload.rs
vendored
2
crates/common/src/cache/reload.rs
vendored
@@ -31,7 +31,7 @@ pub struct ReloadResult {
|
||||
|
||||
impl Server {
|
||||
pub async fn reload_registry(&self, change: RegistryChange) -> trc::Result<ReloadResult> {
|
||||
let mut bootstrap = Bootstrap::new(self.registry().clone());
|
||||
let mut bootstrap = Bootstrap::new(self.registry().clone()).await;
|
||||
let object = match change {
|
||||
RegistryChange::Insert(id) => {
|
||||
if matches!(id.object(), ObjectType::BlockedIp) {
|
||||
|
||||
@@ -47,7 +47,7 @@ impl Data {
|
||||
|
||||
// Build and test snowflake id generator
|
||||
let node_id = bp.node_id();
|
||||
SnowflakeIdGenerator::set_node_id(node_id);
|
||||
SnowflakeIdGenerator::set_node_id(node_id as u64);
|
||||
let id_generator = SnowflakeIdGenerator::new();
|
||||
if !id_generator.is_valid() {
|
||||
panic!("Invalid system time, panicking to avoid data corruption");
|
||||
|
||||
@@ -9,13 +9,10 @@ use crate::{
|
||||
expr::if_block::{BootstrapExprExt, IfBlock},
|
||||
network::security::Security,
|
||||
};
|
||||
use ahash::AHashMap;
|
||||
use registry::{
|
||||
schema::{
|
||||
prelude::ObjectType,
|
||||
structs::{self, Asn, HttpForm, Rate, SystemSettings, TaskManager},
|
||||
},
|
||||
types::EnumImpl,
|
||||
use registry::schema::{
|
||||
enums::{ClusterShardedTaskType, ClusterTaskType},
|
||||
prelude::ObjectType,
|
||||
structs::{self, Asn, ClusterTaskGroup, HttpForm, Rate, SystemSettings, TaskManager},
|
||||
};
|
||||
use std::{hash::Hasher, str::FromStr, time::Duration};
|
||||
use xxhash_rust::xxh3::Xxh3Builder;
|
||||
@@ -152,7 +149,7 @@ impl Network {
|
||||
let system = bp.setting_infallible::<SystemSettings>().await;
|
||||
|
||||
let mut network = Network {
|
||||
node_id: bp.node_id(),
|
||||
node_id: bp.node_id() as u64,
|
||||
server_name: system.default_hostname,
|
||||
security: Security::parse(bp).await,
|
||||
contact_form: ContactForm::parse(bp).await,
|
||||
@@ -162,161 +159,146 @@ impl Network {
|
||||
task_manager: bp.setting_infallible::<TaskManager>().await,
|
||||
};
|
||||
|
||||
// Process ranges
|
||||
let node_id = bp.node_id();
|
||||
let ranges = bp.list_infallible::<NodeRole>().await;
|
||||
if !ranges.is_empty() {
|
||||
for network_role in network.roles.all_mut() {
|
||||
network_role.set_uninit();
|
||||
}
|
||||
|
||||
for range in ranges {
|
||||
let is_success = match &range.object {
|
||||
NodeRole::CalculateMetrics(_)
|
||||
| NodeRole::PushMetrics(_)
|
||||
| NodeRole::SpamClassifierTraining(_)
|
||||
| NodeRole::TaskScheduler(_) => {
|
||||
let (roles, role_obj) = match &range.object {
|
||||
NodeRole::CalculateMetrics(role) => {
|
||||
(&mut network.roles.calculate_metrics, role)
|
||||
}
|
||||
NodeRole::PushMetrics(role) => (&mut network.roles.push_metrics, role),
|
||||
NodeRole::SpamClassifierTraining(role) => {
|
||||
(&mut network.roles.spam_training, role)
|
||||
}
|
||||
NodeRole::TaskScheduler(role) => {
|
||||
(&mut network.roles.task_scheduler, role)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
roles.set_role(role_obj.node_id == node_id)
|
||||
if let Some(role) = &bp.role {
|
||||
match &role.tasks {
|
||||
ClusterTaskGroup::EnableAll => {}
|
||||
ClusterTaskGroup::DisableAll => {
|
||||
for network_role in network.roles.all_mut() {
|
||||
network_role.set_role(false);
|
||||
}
|
||||
NodeRole::StoreMaintenance(_)
|
||||
| NodeRole::AccountMaintenance(_)
|
||||
| NodeRole::PushNotifications(_)
|
||||
| NodeRole::SearchIndexing(_)
|
||||
| NodeRole::ImipProcessing(_)
|
||||
| NodeRole::CalendarAlerts(_)
|
||||
| NodeRole::MergeThreads(_)
|
||||
| NodeRole::DnsAndAcme(_)
|
||||
| NodeRole::OutboundMta(_)
|
||||
| NodeRole::TaskQueueProcessing(_) => {
|
||||
let (roles, role_obj) = match &range.object {
|
||||
NodeRole::StoreMaintenance(role) => {
|
||||
(&mut network.roles.store_maintenance, role)
|
||||
}
|
||||
NodeRole::AccountMaintenance(role) => {
|
||||
(&mut network.roles.account_maintenance, role)
|
||||
}
|
||||
NodeRole::PushNotifications(role) => {
|
||||
(&mut network.roles.push_notifications, role)
|
||||
}
|
||||
NodeRole::SearchIndexing(role) => {
|
||||
(&mut network.roles.search_indexing, role)
|
||||
}
|
||||
NodeRole::ImipProcessing(role) => {
|
||||
(&mut network.roles.imip_processing, role)
|
||||
}
|
||||
NodeRole::CalendarAlerts(role) => {
|
||||
(&mut network.roles.calendar_alerts, role)
|
||||
}
|
||||
NodeRole::MergeThreads(role) => {
|
||||
(&mut network.roles.merge_threads, role)
|
||||
}
|
||||
NodeRole::OutboundMta(role) => (&mut network.roles.outbound_mta, role),
|
||||
NodeRole::DnsAndAcme(role) => (&mut network.roles.dns_acme, role),
|
||||
NodeRole::TaskQueueProcessing(role) => {
|
||||
(&mut network.roles.task_manager, role)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
roles.set_role(
|
||||
role_obj
|
||||
.node_ranges
|
||||
.values()
|
||||
.any(|range| range.contains(node_id)),
|
||||
)
|
||||
}
|
||||
ClusterTaskGroup::EnableSome(group) => {
|
||||
for network_role in network.roles.all_mut() {
|
||||
network_role.set_role(false);
|
||||
}
|
||||
};
|
||||
|
||||
if !is_success {
|
||||
bp.build_warning(
|
||||
range.id,
|
||||
format!("Multiple role definitions found for node id {node_id}",),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for network_role in network.roles.all_mut() {
|
||||
network_role.finalize();
|
||||
}
|
||||
|
||||
// Node shards
|
||||
let mut shards = AHashMap::new();
|
||||
for shard in bp.list_infallible::<NodeShard>().await {
|
||||
shards
|
||||
.entry(shard.object.shard_type)
|
||||
.or_insert_with(Vec::new)
|
||||
.push(shard);
|
||||
}
|
||||
for (shard_type, shards) in shards {
|
||||
if shards.len() == 1 {
|
||||
bp.build_warning(shards[0].id, format!(
|
||||
"Only one shard defined for shard type {:?}, ignoring shard configuration",
|
||||
shard_type.as_str()
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
let roles = match shard_type {
|
||||
NodeShardType::StoreMaintenance => &mut network.roles.store_maintenance,
|
||||
NodeShardType::AccountMaintenance => &mut network.roles.account_maintenance,
|
||||
NodeShardType::DnsAndAcme => &mut network.roles.dns_acme,
|
||||
NodeShardType::PushNotifications => &mut network.roles.push_notifications,
|
||||
NodeShardType::SearchIndexing => &mut network.roles.search_indexing,
|
||||
NodeShardType::ImipProcessing => &mut network.roles.imip_processing,
|
||||
NodeShardType::CalendarAlerts => &mut network.roles.calendar_alerts,
|
||||
NodeShardType::MergeThreads => &mut network.roles.merge_threads,
|
||||
};
|
||||
|
||||
if matches!(roles, ClusterRole::Disabled) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (shard_num, shard) in shards.iter().enumerate() {
|
||||
if shard
|
||||
.object
|
||||
.node_ranges
|
||||
.values()
|
||||
.any(|range| range.contains(node_id))
|
||||
{
|
||||
if matches!(roles, ClusterRole::Enabled) {
|
||||
*roles = ClusterRole::Sharded {
|
||||
shard_id: shard_num as u32,
|
||||
total_shards: shards.len() as u32,
|
||||
};
|
||||
} else {
|
||||
bp.build_warning(
|
||||
shard.id,
|
||||
format!(
|
||||
"Node id {node_id} matches multiple shards for shard type {:?}",
|
||||
shard_type.as_str()
|
||||
),
|
||||
);
|
||||
for task_type in group.task_types.iter() {
|
||||
match task_type {
|
||||
ClusterTaskType::StoreMaintenance => {
|
||||
network.roles.store_maintenance.set_role(true);
|
||||
}
|
||||
ClusterTaskType::AccountMaintenance => {
|
||||
network.roles.account_maintenance.set_role(true);
|
||||
}
|
||||
ClusterTaskType::DnsAndAcme => {
|
||||
network.roles.dns_acme.set_role(true);
|
||||
}
|
||||
ClusterTaskType::CalculateMetrics => {
|
||||
network.roles.calculate_metrics.set_role(true);
|
||||
}
|
||||
ClusterTaskType::PushMetrics => {
|
||||
network.roles.push_metrics.set_role(true);
|
||||
}
|
||||
ClusterTaskType::PushNotifications => {
|
||||
network.roles.push_notifications.set_role(true);
|
||||
}
|
||||
ClusterTaskType::SearchIndexing => {
|
||||
network.roles.search_indexing.set_role(true);
|
||||
}
|
||||
ClusterTaskType::SpamClassifierTraining => {
|
||||
network.roles.spam_training.set_role(true);
|
||||
}
|
||||
ClusterTaskType::ImipProcessing => {
|
||||
network.roles.imip_processing.set_role(true);
|
||||
}
|
||||
ClusterTaskType::CalendarAlerts => {
|
||||
network.roles.calendar_alerts.set_role(true);
|
||||
}
|
||||
ClusterTaskType::MergeThreads => {
|
||||
network.roles.merge_threads.set_role(true);
|
||||
}
|
||||
ClusterTaskType::OutboundMta => {
|
||||
network.roles.outbound_mta.set_role(true);
|
||||
}
|
||||
ClusterTaskType::TaskQueueProcessing => {
|
||||
network.roles.task_manager.set_role(true);
|
||||
}
|
||||
ClusterTaskType::TaskScheduler => {
|
||||
network.roles.task_scheduler.set_role(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ClusterTaskGroup::DisableSome(group) => {
|
||||
for task_type in group.task_types.iter() {
|
||||
match task_type {
|
||||
ClusterTaskType::StoreMaintenance => {
|
||||
network.roles.store_maintenance.set_role(true);
|
||||
}
|
||||
ClusterTaskType::AccountMaintenance => {
|
||||
network.roles.account_maintenance.set_role(false);
|
||||
}
|
||||
ClusterTaskType::DnsAndAcme => {
|
||||
network.roles.dns_acme.set_role(false);
|
||||
}
|
||||
ClusterTaskType::CalculateMetrics => {
|
||||
network.roles.calculate_metrics.set_role(false);
|
||||
}
|
||||
ClusterTaskType::PushMetrics => {
|
||||
network.roles.push_metrics.set_role(false);
|
||||
}
|
||||
ClusterTaskType::PushNotifications => {
|
||||
network.roles.push_notifications.set_role(false);
|
||||
}
|
||||
ClusterTaskType::SearchIndexing => {
|
||||
network.roles.search_indexing.set_role(false);
|
||||
}
|
||||
ClusterTaskType::SpamClassifierTraining => {
|
||||
network.roles.spam_training.set_role(false);
|
||||
}
|
||||
ClusterTaskType::ImipProcessing => {
|
||||
network.roles.imip_processing.set_role(false);
|
||||
}
|
||||
ClusterTaskType::CalendarAlerts => {
|
||||
network.roles.calendar_alerts.set_role(false);
|
||||
}
|
||||
ClusterTaskType::MergeThreads => {
|
||||
network.roles.merge_threads.set_role(false);
|
||||
}
|
||||
ClusterTaskType::OutboundMta => {
|
||||
network.roles.outbound_mta.set_role(false);
|
||||
}
|
||||
ClusterTaskType::TaskQueueProcessing => {
|
||||
network.roles.task_manager.set_role(false);
|
||||
}
|
||||
ClusterTaskType::TaskScheduler => {
|
||||
network.roles.task_scheduler.set_role(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if matches!(roles, ClusterRole::Enabled) {
|
||||
bp.build_warning(
|
||||
shards[0].id,
|
||||
format!(
|
||||
"Node id {node_id} does not match any shards for shard type {:?}, defaulting to all shards",
|
||||
shard_type.as_str()
|
||||
),
|
||||
);
|
||||
if role.shard_size > 1 {
|
||||
for task_type in role.shard_task_types.iter() {
|
||||
let network_role = match task_type {
|
||||
ClusterShardedTaskType::StoreMaintenance => {
|
||||
&mut network.roles.store_maintenance
|
||||
}
|
||||
ClusterShardedTaskType::AccountMaintenance => {
|
||||
&mut network.roles.account_maintenance
|
||||
}
|
||||
ClusterShardedTaskType::DnsAndAcme => &mut network.roles.dns_acme,
|
||||
ClusterShardedTaskType::PushNotifications => {
|
||||
&mut network.roles.push_notifications
|
||||
}
|
||||
ClusterShardedTaskType::SearchIndexing => {
|
||||
&mut network.roles.search_indexing
|
||||
}
|
||||
ClusterShardedTaskType::ImipProcessing => {
|
||||
&mut network.roles.imip_processing
|
||||
}
|
||||
ClusterShardedTaskType::CalendarAlerts => {
|
||||
&mut network.roles.calendar_alerts
|
||||
}
|
||||
ClusterShardedTaskType::MergeThreads => &mut network.roles.merge_threads,
|
||||
};
|
||||
|
||||
if network_role.is_enabled_or_sharded() {
|
||||
*network_role = ClusterRole::Sharded {
|
||||
shard_id: bp.registry.cluster_role_shard() as u32,
|
||||
total_shards: role.shard_size as u32,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ use crate::{
|
||||
};
|
||||
use registry::schema::{
|
||||
enums::{NetworkListenerProtocol, TlsCipherSuite, TlsVersion},
|
||||
structs::{NetworkListener, SystemSettings},
|
||||
structs::{ClusterListenerGroup, NetworkListener, SystemSettings},
|
||||
};
|
||||
use rustls::{
|
||||
ALL_VERSIONS, ServerConfig, SupportedCipherSuite,
|
||||
@@ -35,17 +35,19 @@ impl Listeners {
|
||||
};
|
||||
|
||||
// Parse servers
|
||||
let node_id = bp.node_id();
|
||||
let system = bp.setting_infallible::<SystemSettings>().await;
|
||||
|
||||
for listener in bp.list_infallible::<NetworkListener>().await {
|
||||
if listener.object.enable_for_nodes.is_empty()
|
||||
|| listener
|
||||
.object
|
||||
.enable_for_nodes
|
||||
.values()
|
||||
.any(|n| n.contains(node_id))
|
||||
{
|
||||
if bp.role.as_ref().is_none_or(|r| match &r.listeners {
|
||||
ClusterListenerGroup::EnableAll => true,
|
||||
ClusterListenerGroup::DisableAll => false,
|
||||
ClusterListenerGroup::EnableSome(group) => {
|
||||
group.listener_ids.iter().any(|id| *id == listener.id.id())
|
||||
}
|
||||
ClusterListenerGroup::DisableSome(group) => {
|
||||
!group.listener_ids.iter().any(|id| *id == listener.id.id())
|
||||
}
|
||||
}) {
|
||||
servers.parse_server(bp, listener, &system);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,7 +235,8 @@ impl BootManager {
|
||||
let registry = RegistryStore::init(PathBuf::from(config_path.unwrap()))
|
||||
.await
|
||||
.failed("⚠️ Startup failed");
|
||||
let mut bootstrap = Bootstrap::new(registry);
|
||||
let mut bootstrap = Bootstrap::new(registry).await;
|
||||
let todo = "implement recovery mode";
|
||||
|
||||
// Start listeners
|
||||
let mut servers = Listeners::parse(&mut bootstrap).await;
|
||||
@@ -270,9 +271,23 @@ impl BootManager {
|
||||
|
||||
trc::event!(
|
||||
Server(trc::ServerEvent::Startup),
|
||||
Hostname = bootstrap.registry.local_hostname().to_string(),
|
||||
Version = env!("CARGO_PKG_VERSION"),
|
||||
);
|
||||
|
||||
if core.storage.coordinator.is_enabled() {
|
||||
trc::event!(
|
||||
Cluster(trc::ClusterEvent::Startup),
|
||||
Id = bootstrap.registry.node_id(),
|
||||
Type = bootstrap
|
||||
.registry
|
||||
.cluster_role()
|
||||
.unwrap_or("[default]")
|
||||
.to_string(),
|
||||
Details = bootstrap.registry.cluster_role_shard()
|
||||
);
|
||||
}
|
||||
|
||||
// Build shared inner
|
||||
let has_remote_asn = matches!(
|
||||
core.network.asn_geo_lookup,
|
||||
|
||||
@@ -14,7 +14,7 @@ use registry::{
|
||||
schema::{
|
||||
enums::{BlockReason, PasswordHashAlgorithm},
|
||||
prelude::{Object, ObjectType},
|
||||
structs::{self, AllowedIp, BlockedIp, Rate},
|
||||
structs::{self, AllowedIp, BlockedIp, Rate, SystemSettings},
|
||||
},
|
||||
types::{datetime::UTCDateTime, ipmask::IpAddrOrMask},
|
||||
};
|
||||
@@ -32,8 +32,6 @@ use utils::glob::{GlobPattern, MatchType};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Security {
|
||||
pub fallback_admin: Option<(String, String)>,
|
||||
|
||||
pub allowed_ip_addresses: AHashSet<IpAddr>,
|
||||
pub allowed_ip_networks: Vec<IpAddrOrMask>,
|
||||
pub has_allowed_networks: bool,
|
||||
@@ -75,7 +73,7 @@ impl Security {
|
||||
if ip.expires_at.as_ref().is_none_or(|ip| ip.timestamp() > now) {
|
||||
if let Some(ip) = ip.address.try_to_ip() {
|
||||
allowed_ip_addresses.insert(ip);
|
||||
} else {
|
||||
} else if !allowed_ip_networks.contains(&ip.address) {
|
||||
allowed_ip_networks.push(ip.address);
|
||||
}
|
||||
} else {
|
||||
@@ -90,6 +88,16 @@ impl Security {
|
||||
}
|
||||
}
|
||||
|
||||
// Add proxy protocol IPs as allowed
|
||||
let system = bp.setting_infallible::<SystemSettings>().await;
|
||||
for ip in system.proxy_trusted_networks {
|
||||
if let Some(ip) = ip.try_to_ip() {
|
||||
allowed_ip_addresses.insert(ip);
|
||||
} else if !allowed_ip_networks.contains(&ip) {
|
||||
allowed_ip_networks.push(ip);
|
||||
}
|
||||
}
|
||||
|
||||
if !expired_allows.is_empty() {
|
||||
for (id, _, object) in &expired_allows {
|
||||
if let Err(err) = bp
|
||||
@@ -123,12 +131,6 @@ impl Security {
|
||||
let security = bp.setting_infallible::<structs::Security>().await;
|
||||
let auth = bp.setting_infallible::<structs::Authentication>().await;
|
||||
Security {
|
||||
fallback_admin: local.fallback_admin_user.as_ref().and_then(|user| {
|
||||
local
|
||||
.fallback_admin_secret
|
||||
.as_ref()
|
||||
.map(|secret| (user.to_string(), secret.to_string()))
|
||||
}),
|
||||
has_allowed_networks: !allowed_ip_networks.is_empty(),
|
||||
allowed_ip_addresses,
|
||||
allowed_ip_networks,
|
||||
|
||||
Reference in New Issue
Block a user