EE code reorganisation

This commit is contained in:
mdecimus 2024-07-09 09:47:51 +02:00
parent 38ff4b9ea0
commit e683deb74e
19 changed files with 94 additions and 192 deletions

22
Cargo.lock generated
View file

@ -1054,7 +1054,6 @@ dependencies = [
"rustls 0.23.10",
"rustls-pemfile 2.1.2",
"rustls-pki-types",
"se_licensing",
"serde",
"serde_json",
"sha1",
@ -3180,7 +3179,6 @@ dependencies = [
"reqwest 0.12.5",
"rev_lines",
"rsa",
"se_common",
"sequoia-openpgp",
"serde",
"serde_json",
@ -3589,7 +3587,6 @@ dependencies = [
"jmap_proto",
"managesieve",
"pop3",
"se_common",
"smtp",
"store",
"tokio",
@ -5627,25 +5624,6 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b84345e4c9bd703274a082fb80caaa99b7612be48dfaa1dd9266577ec412309d"
[[package]]
name = "se_common"
version = "0.8.5"
dependencies = [
"common",
"serde",
"store",
"tracing",
"utils",
]
[[package]]
name = "se_licensing"
version = "0.8.5"
dependencies = [
"base64 0.22.1",
"ring 0.17.8",
]
[[package]]
name = "seahash"
version = "4.1.0"

View file

@ -12,8 +12,6 @@ members = [
"crates/nlp",
"crates/store",
"crates/directory",
"crates/se-licensing",
"crates/se-common",
"crates/utils",
"crates/common",
"crates/cli",

View file

@ -10,7 +10,6 @@ nlp = { path = "../nlp" }
store = { path = "../store" }
directory = { path = "../directory" }
jmap_proto = { path = "../jmap-proto" }
se_licensing = { path = "../se-licensing", optional = true }
sieve-rs = { version = "0.5" }
mail-parser = { version = "0.9", features = ["full_encoding", "ludicrous_mode"] }
mail-auth = { version = "0.4" }
@ -67,4 +66,4 @@ tracing-journald = "0.3"
[features]
test_mode = []
enterprise = ["se_licensing"]
enterprise = []

View file

@ -16,13 +16,6 @@ use crate::{
Network,
};
#[cfg(feature = "enterprise")]
use crate::Enterprise;
#[cfg(feature = "enterprise")]
use jmap_proto::types::collection::Collection;
#[cfg(feature = "enterprise")]
use se_licensing::license::LicenseValidator;
use self::{
imap::ImapConfig, jmap::settings::JmapConfig, scripts::Scripting, smtp::SmtpConfig,
storage::Storage,
@ -123,60 +116,6 @@ impl Core {
.directories
.insert("*".to_string(), directory.clone());
// SPDX-SnippetBegin
// SPDX-FileCopyrightText: 2020 Stalwart Labs Ltd <hello@stalw.art>
// SPDX-License-Identifier: LicenseRef-SEL
#[cfg(feature = "enterprise")]
let enterprise = match config.value("enterprise.license-key").map(|key| {
LicenseValidator::new().try_parse(key).and_then(|key| {
key.into_validated_key(config.value("lookup.default.hostname").unwrap_or_default())
})
}) {
Some(Ok(license)) => {
match data
.get_bitmap(store::BitmapKey::document_ids(
u32::MAX,
Collection::Principal,
))
.await
{
Ok(Some(bitmap)) if bitmap.len() > license.accounts as u64 => {
config.new_build_warning(
"enterprise.license-key",
format!(
"License key is valid but only allows {} accounts, found {}.",
license.accounts,
bitmap.len()
),
);
None
}
Err(e) => {
if !matches!(data, Store::None) {
config.new_build_error("enterprise.license-key", e.to_string());
}
None
}
_ => Some(Enterprise {
license,
undelete_period: config
.property_or_default::<Option<std::time::Duration>>(
"enterprise.undelete-period",
"false",
)
.unwrap_or_default(),
}),
}
}
Some(Err(e)) => {
config.new_build_warning("enterprise.license-key", e.to_string());
None
}
None => None,
};
// SPDX-SnippetEnd
// If any of the stores are missing, disable all stores to avoid data loss
if matches!(data, Store::None)
|| matches!(&blob.backend, BlobBackend::Store(Store::None))
@ -194,6 +133,8 @@ impl Core {
}
Self {
#[cfg(feature = "enterprise")]
enterprise: crate::enterprise::Enterprise::parse(config, &data).await,
sieve: Scripting::parse(config, &stores).await,
network: Network::parse(config),
smtp: SmtpConfig::parse(config).await,
@ -215,8 +156,6 @@ impl Core {
blobs: stores.blob_stores,
ftss: stores.fts_stores,
},
#[cfg(feature = "enterprise")]
enterprise,
}
}

View file

@ -0,0 +1,64 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs Ltd <hello@stalw.art>
*
* SPDX-License-Identifier: LicenseRef-SEL
*
* This file is subject to the Stalwart Enterprise License Agreement (SEL) and
* is NOT open source software.
*
*/
use std::time::Duration;
use jmap_proto::types::collection::Collection;
use store::{BitmapKey, Store};
use utils::config::Config;
use super::{license::LicenseValidator, Enterprise};
impl Enterprise {
pub async fn parse(config: &mut Config, data: &Store) -> Option<Self> {
let license = match LicenseValidator::new()
.try_parse(config.value("enterprise.license-key")?)
.and_then(|key| {
key.into_validated_key(config.value("lookup.default.hostname").unwrap_or_default())
}) {
Ok(key) => key,
Err(err) => {
config.new_build_warning("enterprise.license-key", err.to_string());
return None;
}
};
match data
.get_bitmap(BitmapKey::document_ids(u32::MAX, Collection::Principal))
.await
{
Ok(Some(bitmap)) if bitmap.len() > license.accounts as u64 => {
config.new_build_warning(
"enterprise.license-key",
format!(
"License key is valid but only allows {} accounts, found {}.",
license.accounts,
bitmap.len()
),
);
return None;
}
Err(e) => {
if !matches!(data, Store::None) {
config.new_build_error("enterprise.license-key", e.to_string());
}
return None;
}
_ => (),
}
Some(Enterprise {
license,
undelete_period: config
.property_or_default::<Option<Duration>>("enterprise.undelete-period", "false")
.unwrap_or_default(),
})
}
}

View file

@ -8,18 +8,23 @@
*
*/
#[cfg(feature = "enterprise")]
pub mod config;
pub mod license;
pub mod undelete;
#[cfg(feature = "enterprise")]
pub trait EnterpriseCore {
fn is_enterprise_edition(&self) -> bool;
fn log_license_details(&self);
fn licensed_accounts(&self) -> u32;
use std::time::Duration;
use license::LicenseKey;
use crate::Core;
#[derive(Clone)]
pub struct Enterprise {
pub license: LicenseKey,
pub undelete_period: Option<Duration>,
}
#[cfg(feature = "enterprise")]
impl EnterpriseCore for common::Core {
impl Core {
// 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.
@ -29,17 +34,17 @@ impl EnterpriseCore for common::Core {
// violators to the fullest extent of the law, including but not limited to claims
// for copyright infringement, breach of contract, and fraud.
fn is_enterprise_edition(&self) -> bool {
pub fn is_enterprise_edition(&self) -> bool {
self.enterprise
.as_ref()
.map_or(false, |e| !e.license.is_expired())
}
fn licensed_accounts(&self) -> u32 {
pub fn licensed_accounts(&self) -> u32 {
self.enterprise.as_ref().map_or(0, |e| e.license.accounts)
}
fn log_license_details(&self) {
pub fn log_license_details(&self) {
if let Some(enterprise) = &self.enterprise {
tracing::info!(
licensed_to = enterprise.license.hostname,

View file

@ -8,9 +8,6 @@
*
*/
use std::future::Future;
use common::Core;
use serde::{Deserialize, Serialize};
use store::{
write::{
@ -21,6 +18,8 @@ use store::{
};
use utils::{BlobHash, BLOB_HASH_LEN};
use crate::Core;
#[derive(Debug, Serialize, Deserialize)]
pub struct DeletedBlob<H, T, C> {
pub hash: H,
@ -32,22 +31,8 @@ pub struct DeletedBlob<H, T, C> {
pub collection: C,
}
pub trait Undelete: Sync + Send {
fn hold_undelete(
&self,
batch: &mut BatchBuilder,
collection: u8,
blob_hash: &BlobHash,
blob_size: usize,
);
fn list_deleted(
&self,
account_id: u32,
) -> impl Future<Output = store::Result<Vec<DeletedBlob<BlobHash, u64, u8>>>> + Send;
}
impl Undelete for Core {
fn hold_undelete(
impl Core {
pub fn hold_undelete(
&self,
batch: &mut BatchBuilder,
collection: u8,
@ -71,7 +56,7 @@ impl Undelete for Core {
}
}
async fn list_deleted(
pub async fn list_deleted(
&self,
account_id: u32,
) -> store::Result<Vec<DeletedBlob<BlobHash, u64, u8>>> {

View file

@ -35,8 +35,6 @@ use opentelemetry_sdk::{
Resource,
};
use opentelemetry_semantic_conventions::resource::{SERVICE_NAME, SERVICE_VERSION};
#[cfg(feature = "enterprise")]
use se_licensing::license::LicenseKey;
use sieve::Sieve;
use store::LookupStore;
use tokio::sync::{mpsc, oneshot};
@ -49,6 +47,8 @@ use webhooks::{manager::WebhookEvent, WebhookPayload, WebhookType, Webhooks};
pub mod addresses;
pub mod config;
#[cfg(feature = "enterprise")]
pub mod enterprise;
pub mod expr;
pub mod listener;
pub mod manager;
@ -73,7 +73,7 @@ pub struct Core {
pub imap: ImapConfig,
pub web_hooks: Webhooks,
#[cfg(feature = "enterprise")]
pub enterprise: Option<Enterprise>,
pub enterprise: Option<enterprise::Enterprise>,
}
#[derive(Clone)]
@ -83,19 +83,6 @@ pub struct Network {
pub url: IfBlock,
}
// SPDX-SnippetBegin
// SPDX-FileCopyrightText: 2020 Stalwart Labs Ltd <hello@stalw.art>
// SPDX-License-Identifier: LicenseRef-SEL
#[cfg(feature = "enterprise")]
#[derive(Clone)]
pub struct Enterprise {
pub license: LicenseKey,
pub undelete_period: Option<std::time::Duration>,
}
// SPDX-SnippetEnd
pub enum AuthResult<T> {
Success(T),
Failure(AuthFailureReason),

View file

@ -11,7 +11,6 @@ jmap_proto = { path = "../jmap-proto" }
smtp = { path = "../smtp" }
utils = { path = "../utils" }
common = { path = "../common" }
se_common = { path = "../se-common", optional = true }
directory = { path = "../directory" }
smtp-proto = { version = "0.1" }
mail-parser = { version = "0.9", features = ["full_encoding", "serde_support", "ludicrous_mode"] }
@ -61,4 +60,4 @@ quick-xml = "0.35"
[features]
test_mode = []
enterprise = ["se_common"]
enterprise = []

View file

@ -11,11 +11,11 @@
use std::str::FromStr;
use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine};
use common::enterprise::undelete::DeletedBlob;
use directory::backend::internal::manage::ManageDirectory;
use hyper::Method;
use jmap_proto::{error::request::RequestError, types::collection::Collection};
use mail_parser::{DateTime, MessageParser};
use se_common::undelete::{DeletedBlob, Undelete};
use serde_json::json;
use store::write::{BatchBuilder, BlobOp, ValueClass};
use utils::{url_params::UrlParams, BlobHash};

View file

@ -26,9 +26,6 @@ use serde::Serialize;
use super::{http::ToHttpResponse, HttpRequest, HttpResponse, JsonResponse};
use crate::{auth::AccessToken, JMAP};
#[cfg(feature = "enterprise")]
use se_common::EnterpriseCore;
#[derive(Serialize)]
#[serde(tag = "error")]
pub enum ManagementApiError {

View file

@ -24,9 +24,6 @@ use crate::{
JMAP,
};
#[cfg(feature = "enterprise")]
use se_common::EnterpriseCore;
use super::{
DeviceAuthResponse, FormData, OAuthCode, OAuthCodeRequest, CLIENT_ID_MAX_LEN, DEVICE_CODE_LEN,
MAX_POST_LEN, USER_CODE_ALPHABET, USER_CODE_LEN,

View file

@ -13,8 +13,6 @@ use jmap_proto::{
type_state::DataType,
},
};
#[cfg(feature = "enterprise")]
use se_common::undelete::Undelete;
use store::{
ahash::AHashMap,
roaring::RoaringBitmap,

View file

@ -26,7 +26,6 @@ managesieve = { path = "../managesieve" }
common = { path = "../common" }
directory = { path = "../directory" }
utils = { path = "../utils" }
se_common = { path = "../se-common", optional = true }
tokio = { version = "1.23", features = ["full"] }
tracing = "0.1"
@ -44,4 +43,4 @@ rocks = ["store/rocks"]
elastic = ["store/elastic"]
s3 = ["store/s3"]
redis = ["store/redis"]
enterprise = ["se_common", "se_common/enterprise", "jmap/enterprise", "common/enterprise"]
enterprise = ["jmap/enterprise", "common/enterprise"]

View file

@ -14,8 +14,6 @@ use imap::core::{ImapSessionManager, IMAP};
use jmap::{api::JmapSessionManager, services::gossip::spawn::GossiperBuilder, JMAP};
use managesieve::core::ManageSieveSessionManager;
use pop3::Pop3SessionManager;
#[cfg(feature = "enterprise")]
use se_common::EnterpriseCore;
use smtp::core::{SmtpSessionManager, SMTP};
use tokio::sync::mpsc;
use utils::wait_for_shutdown;

View file

@ -1,17 +0,0 @@
[package]
name = "se_common"
version = "0.8.5"
edition = "2021"
license = "LicenseRef-SEL"
resolver = "2"
[dependencies]
common = { path = "../common" }
store = { path = "../store" }
utils = { path = "../utils" }
tracing = "0.1"
serde = { version = "1.0", features = ["derive"]}
[features]
test_mode = []
enterprise = ["common/enterprise"]

View file

@ -1,13 +0,0 @@
[package]
name = "se_licensing"
version = "0.8.5"
edition = "2021"
license = "LicenseRef-SEL"
resolver = "2"
[dependencies]
base64 = "0.22.1"
ring = "0.17.8"
[features]
test_mode = []

View file

@ -1,11 +0,0 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs Ltd <hello@stalw.art>
*
* SPDX-License-Identifier: LicenseRef-SEL
*
* This file is subject to the Stalwart Enterprise License Agreement (SEL) and
* is NOT open source software.
*
*/
pub mod license;