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(
|
||||
&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>>> {
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
@@ -45,7 +45,8 @@ impl Server {
|
||||
&self,
|
||||
permissions: &structs::Permissions,
|
||||
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> {
|
||||
// Calculate effective permissions
|
||||
let (mut permissions, roles) = match permissions {
|
||||
|
||||
-1
@@ -17,7 +17,6 @@ use registry::{
|
||||
},
|
||||
types::id::ObjectId,
|
||||
};
|
||||
use store::{registry::RegistryQuery, roaring::RoaringBitmap};
|
||||
use types::id::Id;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
|
||||
+2
-2
@@ -28,7 +28,7 @@ use registry::{
|
||||
enums::{DkimRotationStage, Locale, StorageQuota, TenantStorageQuota},
|
||||
prelude::{ObjectType, Property},
|
||||
structs::{
|
||||
Account, DkimSignature, Domain, EncryptionAtRest, MailingList, MaskedEmail,
|
||||
Account, DkimSignature, Domain, EncryptionAtRest, MailingList,
|
||||
Permissions, PublicKey, Role, SubAddressing, Tenant,
|
||||
},
|
||||
},
|
||||
@@ -38,7 +38,7 @@ use std::{borrow::Cow, sync::Arc};
|
||||
use store::{
|
||||
U64_LEN,
|
||||
registry::{RegistryQuery, bootstrap::Bootstrap},
|
||||
write::{key::KeySerializer, now},
|
||||
write::key::KeySerializer,
|
||||
};
|
||||
use trc::{AddContext, StoreEvent};
|
||||
use types::id::Id;
|
||||
|
||||
@@ -38,7 +38,7 @@ pub mod storage;
|
||||
pub mod telemetry;
|
||||
|
||||
impl Core {
|
||||
pub async fn parse(bp: &mut Bootstrap, mut storage: Storage) -> Self {
|
||||
pub async fn parse(bp: &mut Bootstrap, storage: Storage) -> Self {
|
||||
|
||||
Self {
|
||||
sieve: Scripting::parse(bp).await,
|
||||
|
||||
@@ -141,7 +141,8 @@ impl Telemetry {
|
||||
}
|
||||
|
||||
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 tracers: Vec<TelemetrySubscriber> = Vec::new();
|
||||
let mut global_interests = Interests::default();
|
||||
|
||||
@@ -161,6 +161,9 @@ pub struct Data {
|
||||
pub struct LogoCache {
|
||||
domain_id: 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>>>,
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ use crate::{
|
||||
};
|
||||
use directory::Recipient;
|
||||
use mail_auth::IpLookupStrategy;
|
||||
use registry::schema::{enums::ExpressionVariable, structs::MaskedEmail};
|
||||
use registry::schema::enums::ExpressionVariable;
|
||||
use sieve::Sieve;
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
@@ -32,10 +32,9 @@ use std::{
|
||||
};
|
||||
use store::{
|
||||
Deserialize, IterateParams, ValueKey,
|
||||
write::{AlignedBytes, Archive, QueueClass, ValueClass, now},
|
||||
write::{AlignedBytes, Archive, QueueClass, ValueClass},
|
||||
};
|
||||
use trc::{AddContext, SpamEvent};
|
||||
use types::id::Id;
|
||||
|
||||
impl Server {
|
||||
pub async fn rcpt_resolve(
|
||||
|
||||
@@ -4,9 +4,7 @@
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use sieve::{FunctionMap, compiler::Number, runtime::Variable};
|
||||
use std::time::Instant;
|
||||
use trc::{AiEvent, SecurityEvent};
|
||||
use sieve::{FunctionMap, runtime::Variable};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
||||
|
||||
@@ -96,7 +96,8 @@ impl Telemetry {
|
||||
}
|
||||
|
||||
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 {
|
||||
TelemetrySubscriberType::ConsoleTracer(settings) => {
|
||||
spawn_console_tracer(builder, settings)
|
||||
|
||||
@@ -20,10 +20,7 @@ use registry::{
|
||||
},
|
||||
types::EnumImpl,
|
||||
};
|
||||
use store::{
|
||||
registry::{RegistryObjectCounter, RegistryQuery},
|
||||
write::{BatchBuilder, RegistryClass, ValueClass, now},
|
||||
};
|
||||
use store::write::{BatchBuilder, RegistryClass, ValueClass, now};
|
||||
use trc::AddContext;
|
||||
use types::id::Id;
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ use registry::{
|
||||
jmap::{IntoValue, JsonPointerPatch, RegistryJsonPatch},
|
||||
schema::{
|
||||
enums::{DeliveryErrorType, MessageFlag, RecipientFlag},
|
||||
prelude::{ObjectType, Property},
|
||||
prelude::Property,
|
||||
structs::{
|
||||
DeliveryError, QueueExpiry, QueueExpiryAttempts, QueueExpiryTtl, QueuedMessage,
|
||||
QueuedRecipient, RecipientStatus, ServerResponse,
|
||||
@@ -40,7 +40,7 @@ use std::str::FromStr;
|
||||
use store::{
|
||||
Deserialize, IterateParams, U64_LEN, ValueKey,
|
||||
ahash::AHashSet,
|
||||
registry::{RegistryFilterOp, RegistryQuery},
|
||||
registry::RegistryFilterOp,
|
||||
write::{AlignedBytes, Archive, QueueClass, ValueClass, key::DeserializeBigEndian, now},
|
||||
};
|
||||
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!(
|
||||
"This feature is only available in the Enterprise edition. ",
|
||||
"Obtain your trial license at https://license.stalw.art/trial."
|
||||
"This feature isn't available in ",
|
||||
types::brand!(),
|
||||
" yet."
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ use groupware::{cache::GroupwareCache, calendar::CalendarEvent, contact::Contact
|
||||
use registry::{
|
||||
schema::{
|
||||
enums::IndexDocumentType,
|
||||
prelude::{ObjectType, Property},
|
||||
structs::{TaskIndexDocument, TaskIndexTrace, TaskStatus},
|
||||
},
|
||||
types::EnumImpl,
|
||||
@@ -29,7 +28,6 @@ use store::{
|
||||
};
|
||||
use trc::{AddContext, TaskManagerEvent};
|
||||
use types::{
|
||||
blob_hash::BlobHash,
|
||||
collection::{Collection, SyncCollection},
|
||||
field::EmailField,
|
||||
};
|
||||
|
||||
@@ -18,7 +18,21 @@ impl RegistryStore {
|
||||
|
||||
// Build store
|
||||
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::Bootstrap => {
|
||||
inner.env_recovery_mode = true;
|
||||
|
||||
Reference in New Issue
Block a user