Quick fixes from the first boot: recovery admin, upsell, warnings
- The recovery administrator (INBUXA_RECOVERY_ADMIN, or STALWART_RECOVERY_ADMIN) is honored only in bootstrap and recovery mode. On a configured server it's ignored with a startup warning. Before, it was a standing full-admin login for as long as the variable stayed set. - The Enterprise upsell error is replaced by "This feature isn't available in INBUXA yet" for the features still to be rebuilt. - Workspace warnings: 25 to 0. cargo fix removed the unused imports. The seven places where Enterprise code used to plug in keep their parameters, each with an inbuxa: comment naming the rebuild that uses it again. The antispam test's mock-server imports are back behind pending-rebuild.
This commit is contained in:
@@ -514,13 +514,15 @@ impl Server {
|
|||||||
|
|
||||||
pub async fn get_directory_for_domain(
|
pub async fn get_directory_for_domain(
|
||||||
&self,
|
&self,
|
||||||
domain_name: &str,
|
// inbuxa: unused until per-domain directories (Domain.directoryId) are rebuilt; see docs/spec/SPEC.md §4
|
||||||
|
_domain_name: &str,
|
||||||
) -> trc::Result<Option<&Arc<Directory>>> {
|
) -> trc::Result<Option<&Arc<Directory>>> {
|
||||||
|
|
||||||
Ok(self.get_default_directory())
|
Ok(self.get_default_directory())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_directory_for_cached_domain(&self, domain: &DomainCache) -> Option<&Arc<Directory>> {
|
// inbuxa: `_domain` is unused until per-domain directories (Domain.directoryId) are rebuilt
|
||||||
|
pub fn get_directory_for_cached_domain(&self, _domain: &DomainCache) -> Option<&Arc<Directory>> {
|
||||||
|
|
||||||
self.get_default_directory()
|
self.get_default_directory()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,8 @@ impl Server {
|
|||||||
&self,
|
&self,
|
||||||
permissions: &structs::Permissions,
|
permissions: &structs::Permissions,
|
||||||
role_ids: &[Id],
|
role_ids: &[Id],
|
||||||
tenant_id: Option<u32>,
|
// inbuxa: unused until multi-tenancy is rebuilt: the tenant permission ceiling (docs/spec/features/multi-tenancy.md MT-13)
|
||||||
|
_tenant_id: Option<u32>,
|
||||||
) -> trc::Result<PermissionsGroup> {
|
) -> trc::Result<PermissionsGroup> {
|
||||||
// Calculate effective permissions
|
// Calculate effective permissions
|
||||||
let (mut permissions, roles) = match permissions {
|
let (mut permissions, roles) = match permissions {
|
||||||
|
|||||||
-1
@@ -17,7 +17,6 @@ use registry::{
|
|||||||
},
|
},
|
||||||
types::id::ObjectId,
|
types::id::ObjectId,
|
||||||
};
|
};
|
||||||
use store::{registry::RegistryQuery, roaring::RoaringBitmap};
|
|
||||||
use types::id::Id;
|
use types::id::Id;
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
|
|||||||
+2
-2
@@ -28,7 +28,7 @@ use registry::{
|
|||||||
enums::{DkimRotationStage, Locale, StorageQuota, TenantStorageQuota},
|
enums::{DkimRotationStage, Locale, StorageQuota, TenantStorageQuota},
|
||||||
prelude::{ObjectType, Property},
|
prelude::{ObjectType, Property},
|
||||||
structs::{
|
structs::{
|
||||||
Account, DkimSignature, Domain, EncryptionAtRest, MailingList, MaskedEmail,
|
Account, DkimSignature, Domain, EncryptionAtRest, MailingList,
|
||||||
Permissions, PublicKey, Role, SubAddressing, Tenant,
|
Permissions, PublicKey, Role, SubAddressing, Tenant,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -38,7 +38,7 @@ use std::{borrow::Cow, sync::Arc};
|
|||||||
use store::{
|
use store::{
|
||||||
U64_LEN,
|
U64_LEN,
|
||||||
registry::{RegistryQuery, bootstrap::Bootstrap},
|
registry::{RegistryQuery, bootstrap::Bootstrap},
|
||||||
write::{key::KeySerializer, now},
|
write::key::KeySerializer,
|
||||||
};
|
};
|
||||||
use trc::{AddContext, StoreEvent};
|
use trc::{AddContext, StoreEvent};
|
||||||
use types::id::Id;
|
use types::id::Id;
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ pub mod storage;
|
|||||||
pub mod telemetry;
|
pub mod telemetry;
|
||||||
|
|
||||||
impl Core {
|
impl Core {
|
||||||
pub async fn parse(bp: &mut Bootstrap, mut storage: Storage) -> Self {
|
pub async fn parse(bp: &mut Bootstrap, storage: Storage) -> Self {
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
sieve: Scripting::parse(bp).await,
|
sieve: Scripting::parse(bp).await,
|
||||||
|
|||||||
@@ -141,7 +141,8 @@ impl Telemetry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Tracers {
|
impl Tracers {
|
||||||
pub async fn parse(bp: &mut Bootstrap, storage: &Storage) -> Self {
|
// inbuxa: `_storage` is unused until monitoring history (stored traces and metrics) is rebuilt
|
||||||
|
pub async fn parse(bp: &mut Bootstrap, _storage: &Storage) -> Self {
|
||||||
let mut custom_levels = AHashMap::new();
|
let mut custom_levels = AHashMap::new();
|
||||||
let mut tracers: Vec<TelemetrySubscriber> = Vec::new();
|
let mut tracers: Vec<TelemetrySubscriber> = Vec::new();
|
||||||
let mut global_interests = Interests::default();
|
let mut global_interests = Interests::default();
|
||||||
|
|||||||
@@ -161,6 +161,9 @@ pub struct Data {
|
|||||||
pub struct LogoCache {
|
pub struct LogoCache {
|
||||||
domain_id: u32,
|
domain_id: u32,
|
||||||
tenant_id: Option<u32>,
|
tenant_id: Option<u32>,
|
||||||
|
// inbuxa: read again when the /logo endpoint (per-tenant and per-domain
|
||||||
|
// branding) is rebuilt; docs/spec/features/multi-tenancy.md MT-22.
|
||||||
|
#[allow(dead_code)]
|
||||||
data: Option<Resource<Vec<u8>>>,
|
data: Option<Resource<Vec<u8>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use directory::Recipient;
|
use directory::Recipient;
|
||||||
use mail_auth::IpLookupStrategy;
|
use mail_auth::IpLookupStrategy;
|
||||||
use registry::schema::{enums::ExpressionVariable, structs::MaskedEmail};
|
use registry::schema::enums::ExpressionVariable;
|
||||||
use sieve::Sieve;
|
use sieve::Sieve;
|
||||||
use std::{
|
use std::{
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
@@ -32,10 +32,9 @@ use std::{
|
|||||||
};
|
};
|
||||||
use store::{
|
use store::{
|
||||||
Deserialize, IterateParams, ValueKey,
|
Deserialize, IterateParams, ValueKey,
|
||||||
write::{AlignedBytes, Archive, QueueClass, ValueClass, now},
|
write::{AlignedBytes, Archive, QueueClass, ValueClass},
|
||||||
};
|
};
|
||||||
use trc::{AddContext, SpamEvent};
|
use trc::{AddContext, SpamEvent};
|
||||||
use types::id::Id;
|
|
||||||
|
|
||||||
impl Server {
|
impl Server {
|
||||||
pub async fn rcpt_resolve(
|
pub async fn rcpt_resolve(
|
||||||
|
|||||||
@@ -4,9 +4,7 @@
|
|||||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use sieve::{FunctionMap, compiler::Number, runtime::Variable};
|
use sieve::{FunctionMap, runtime::Variable};
|
||||||
use std::time::Instant;
|
|
||||||
use trc::{AiEvent, SecurityEvent};
|
|
||||||
|
|
||||||
use super::PluginContext;
|
use super::PluginContext;
|
||||||
|
|
||||||
@@ -14,7 +12,8 @@ pub fn register(plugin_id: u32, fnc_map: &mut FunctionMap) {
|
|||||||
fnc_map.set_external_function("llm_prompt", plugin_id, 3);
|
fnc_map.set_external_function("llm_prompt", plugin_id, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn exec(ctx: PluginContext<'_>) -> trc::Result<Variable> {
|
// inbuxa: the LLM Sieve function is a no-op until AI classification is rebuilt
|
||||||
|
pub async fn exec(_ctx: PluginContext<'_>) -> trc::Result<Variable> {
|
||||||
|
|
||||||
Ok(false.into())
|
Ok(false.into())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,7 +96,8 @@ impl Telemetry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TelemetrySubscriberType {
|
impl TelemetrySubscriberType {
|
||||||
pub fn spawn(self, builder: SubscriberBuilder, is_enterprise: bool) {
|
// inbuxa: `_is_enterprise` is unused until monitoring history is rebuilt, and goes when it is: there is one edition
|
||||||
|
pub fn spawn(self, builder: SubscriberBuilder, _is_enterprise: bool) {
|
||||||
match self {
|
match self {
|
||||||
TelemetrySubscriberType::ConsoleTracer(settings) => {
|
TelemetrySubscriberType::ConsoleTracer(settings) => {
|
||||||
spawn_console_tracer(builder, settings)
|
spawn_console_tracer(builder, settings)
|
||||||
|
|||||||
@@ -20,10 +20,7 @@ use registry::{
|
|||||||
},
|
},
|
||||||
types::EnumImpl,
|
types::EnumImpl,
|
||||||
};
|
};
|
||||||
use store::{
|
use store::write::{BatchBuilder, RegistryClass, ValueClass, now};
|
||||||
registry::{RegistryObjectCounter, RegistryQuery},
|
|
||||||
write::{BatchBuilder, RegistryClass, ValueClass, now},
|
|
||||||
};
|
|
||||||
use trc::AddContext;
|
use trc::AddContext;
|
||||||
use types::id::Id;
|
use types::id::Id;
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ use registry::{
|
|||||||
jmap::{IntoValue, JsonPointerPatch, RegistryJsonPatch},
|
jmap::{IntoValue, JsonPointerPatch, RegistryJsonPatch},
|
||||||
schema::{
|
schema::{
|
||||||
enums::{DeliveryErrorType, MessageFlag, RecipientFlag},
|
enums::{DeliveryErrorType, MessageFlag, RecipientFlag},
|
||||||
prelude::{ObjectType, Property},
|
prelude::Property,
|
||||||
structs::{
|
structs::{
|
||||||
DeliveryError, QueueExpiry, QueueExpiryAttempts, QueueExpiryTtl, QueuedMessage,
|
DeliveryError, QueueExpiry, QueueExpiryAttempts, QueueExpiryTtl, QueuedMessage,
|
||||||
QueuedRecipient, RecipientStatus, ServerResponse,
|
QueuedRecipient, RecipientStatus, ServerResponse,
|
||||||
@@ -40,7 +40,7 @@ use std::str::FromStr;
|
|||||||
use store::{
|
use store::{
|
||||||
Deserialize, IterateParams, U64_LEN, ValueKey,
|
Deserialize, IterateParams, U64_LEN, ValueKey,
|
||||||
ahash::AHashSet,
|
ahash::AHashSet,
|
||||||
registry::{RegistryFilterOp, RegistryQuery},
|
registry::RegistryFilterOp,
|
||||||
write::{AlignedBytes, Archive, QueueClass, ValueClass, key::DeserializeBigEndian, now},
|
write::{AlignedBytes, Archive, QueueClass, ValueClass, key::DeserializeBigEndian, now},
|
||||||
};
|
};
|
||||||
use trc::AddContext;
|
use trc::AddContext;
|
||||||
|
|||||||
@@ -29,9 +29,13 @@ impl EnterpriseRegistry for Server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// These are the Enterprise features INBUXA hasn't rebuilt yet
|
||||||
|
// (docs/spec/SPEC.md §4). Each type leaves this list when its rebuild
|
||||||
|
// lands. There's no edition to upgrade to, so the message says so.
|
||||||
Err(trc::JmapEvent::Forbidden.into_err().details(concat!(
|
Err(trc::JmapEvent::Forbidden.into_err().details(concat!(
|
||||||
"This feature is only available in the Enterprise edition. ",
|
"This feature isn't available in ",
|
||||||
"Obtain your trial license at https://license.stalw.art/trial."
|
types::brand!(),
|
||||||
|
" yet."
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ use groupware::{cache::GroupwareCache, calendar::CalendarEvent, contact::Contact
|
|||||||
use registry::{
|
use registry::{
|
||||||
schema::{
|
schema::{
|
||||||
enums::IndexDocumentType,
|
enums::IndexDocumentType,
|
||||||
prelude::{ObjectType, Property},
|
|
||||||
structs::{TaskIndexDocument, TaskIndexTrace, TaskStatus},
|
structs::{TaskIndexDocument, TaskIndexTrace, TaskStatus},
|
||||||
},
|
},
|
||||||
types::EnumImpl,
|
types::EnumImpl,
|
||||||
@@ -29,7 +28,6 @@ use store::{
|
|||||||
};
|
};
|
||||||
use trc::{AddContext, TaskManagerEvent};
|
use trc::{AddContext, TaskManagerEvent};
|
||||||
use types::{
|
use types::{
|
||||||
blob_hash::BlobHash,
|
|
||||||
collection::{Collection, SyncCollection},
|
collection::{Collection, SyncCollection},
|
||||||
field::EmailField,
|
field::EmailField,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,7 +18,21 @@ impl RegistryStore {
|
|||||||
|
|
||||||
// Build store
|
// Build store
|
||||||
inner.store = match inner.read_data_store().await {
|
inner.store = match inner.read_data_store().await {
|
||||||
RegistryInit::Ok(data_store) => Store::build(data_store).await?,
|
RegistryInit::Ok(data_store) => {
|
||||||
|
// The recovery administrator exists for first-boot setup and
|
||||||
|
// for recovery mode. On a configured server running normally
|
||||||
|
// it would be a standing full-admin login for whoever knows the
|
||||||
|
// variable, so it's ignored there, and loudly.
|
||||||
|
if !inner.env_recovery_mode && inner.env_recovery_admin.take().is_some() {
|
||||||
|
eprintln!();
|
||||||
|
eprintln!("⚠️ INBUXA_RECOVERY_ADMIN (or STALWART_RECOVERY_ADMIN) is set, but the");
|
||||||
|
eprintln!(" server is configured and not in recovery mode, so it is ignored.");
|
||||||
|
eprintln!(" Remove it from the environment. To use it for recovery, also set");
|
||||||
|
eprintln!(" INBUXA_RECOVERY_MODE=1.");
|
||||||
|
eprintln!();
|
||||||
|
}
|
||||||
|
Store::build(data_store).await?
|
||||||
|
}
|
||||||
RegistryInit::Err(err) => return Err(err),
|
RegistryInit::Err(err) => return Err(err),
|
||||||
RegistryInit::Bootstrap => {
|
RegistryInit::Bootstrap => {
|
||||||
inner.env_recovery_mode = true;
|
inner.env_recovery_mode = true;
|
||||||
|
|||||||
@@ -10,9 +10,14 @@ use common::enterprise::llm::{
|
|||||||
};
|
};
|
||||||
#[cfg(feature = "pending-rebuild")]
|
#[cfg(feature = "pending-rebuild")]
|
||||||
use spam_filter::analysis::llm::SpamFilterAnalyzeLlm;
|
use spam_filter::analysis::llm::SpamFilterAnalyzeLlm;
|
||||||
|
#[cfg(feature = "pending-rebuild")]
|
||||||
|
use crate::utils::http_server::{HttpMessage, spawn_mock_http_server};
|
||||||
|
#[cfg(feature = "pending-rebuild")]
|
||||||
|
use http_proto::{JsonResponse, ToHttpResponse};
|
||||||
|
#[cfg(feature = "pending-rebuild")]
|
||||||
|
use hyper::Method;
|
||||||
use crate::utils::{
|
use crate::utils::{
|
||||||
dns::DnsCache,
|
dns::DnsCache,
|
||||||
http_server::{HttpMessage, spawn_mock_http_server},
|
|
||||||
server::TestServerBuilder,
|
server::TestServerBuilder,
|
||||||
};
|
};
|
||||||
use ahash::AHashSet;
|
use ahash::AHashSet;
|
||||||
@@ -21,8 +26,6 @@ use common::{
|
|||||||
auth::{AccountCache, AccountInfo},
|
auth::{AccountCache, AccountInfo},
|
||||||
config::mailstore::spamfilter::SpamFilterAction,
|
config::mailstore::spamfilter::SpamFilterAction,
|
||||||
};
|
};
|
||||||
use http_proto::{JsonResponse, ToHttpResponse};
|
|
||||||
use hyper::Method;
|
|
||||||
use mail_auth::{
|
use mail_auth::{
|
||||||
ArcOutput, DkimOutput, DkimResult, DmarcResult, DnssecStatus, IprevOutput, IprevResult, MX,
|
ArcOutput, DkimOutput, DkimResult, DmarcResult, DnssecStatus, IprevOutput, IprevResult, MX,
|
||||||
SpfOutput, SpfResult, dkim::Signature, dmarc::Policy,
|
SpfOutput, SpfResult, dkim::Signature, dmarc::Policy,
|
||||||
|
|||||||
Reference in New Issue
Block a user