Skip to content

Commit

Permalink
Add enterprise cargo feature + Allow copying SEL licensed code for te…
Browse files Browse the repository at this point in the history
…sting/development purposes (closes #602 closes #601)
  • Loading branch information
mdecimus committed Jul 8, 2024
1 parent e2fc705 commit 38ff4b9
Show file tree
Hide file tree
Showing 19 changed files with 82 additions and 46 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ jobs:
mkdir -p "${root}/target/${target}/release" && cd "$_"
if [ "${USE_FOUNDATIONDB:-0}" = 1 ]; then
build -p mail-server --no-default-features --features "foundationdb elastic s3 redis"
build -p mail-server --no-default-features --features "foundationdb elastic s3 redis enterprise"
artifact stalwart-mail stalwart-mail-foundationdb
fi
Expand Down
28 changes: 16 additions & 12 deletions LICENSES/LicenseRef-SEL.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Stalwart Enterprise License 1.0 (SELv1) Agreement
=================================================

Last Update: June 26, 2024
Last Update: July 8, 2024

PLEASE CAREFULLY READ THIS STALWART ENTERPRISE LICENSE AGREEMENT ("AGREEMENT"). THIS AGREEMENT CONSTITUTES A LEGALLY BINDING AGREEMENT BETWEEN YOU AND STALWART LABS LTD AND GOVERNS YOUR USE OF THE SOFTWARE (DEFINED BELOW). IF YOU DO NOT AGREE WITH THIS AGREEMENT, YOU MAY NOT USE THE SOFTWARE. IF YOU ARE USING THE SOFTWARE ON BEHALF OF A LEGAL ENTITY, YOU REPRESENT AND WARRANT THAT YOU HAVE AUTHORITY TO AGREE TO THIS AGREEMENT ON BEHALF OF SUCH ENTITY. IF YOU DO NOT HAVE SUCH AUTHORITY, DO NOT USE THE SOFTWARE IN ANY MANNER.

Expand All @@ -10,31 +10,35 @@ This Agreement is entered into by and between Stalwart Labs Ltd and you, or the
1. DEFINITIONS

1.1. "Software" refers to the Stalwart Mail Server Enterprise Edition software, including all its versions, updates, modifications, accompanying documentation, and related materials.
1.2. "Licensor" refers to Stalwart Labs Ltd, the entity providing the Software.
1.3. "Licensee" refers to the individual or entity installing, accessing, or using the Software.
1.4. "License Key" refers to the unique code provided by Licensor upon purchasing a subscription which activates the full features of the Software.
1.2. "Subscription" refers to the paid access to the Software provided by Licensor to Licensee.
1.3. "Licensor" refers to Stalwart Labs Ltd, the entity providing the Software.
1.4. "Licensee" refers to the individual or entity installing, accessing, or using the Software with a valid Subscription.
1.5. "License Key" refers to the unique code provided by Licensor upon purchasing a Subscription which activates the full features of the Software.
1.6. "Source Code" refers to the human-readable version of the Software's code, as opposed to the compiled machine-readable version.

2. GRANT OF LICENSE

2.1. Licensor grants Licensee a revocable, non-exclusive, non-transferable, non-sublicensable, limited license to download, install, and use the Software.
2.2. The use of the Software is conditioned upon Licensee maintaining an active and valid paid subscription with Licensor. The paid subscription covers all versions of the Software and all updates and modifications.
2.3. This license grants Licensee the right to use the Software for both personal and commercial purposes. However, Licensee is expressly prohibited from reselling, leasing, sublicensing, or otherwise redistributing the Software itself.
2.4. This license is further governed by the terms and conditions set forth in any licensing agreements separately executed between Licensor and Licensee. In the event of any conflict between the terms of this Agreement and the terms of a signed licensing agreement, the terms of the signed licensing agreement shall control.
2.5. You are not granted any other rights beyond what is expressly stated herein.

3. LICENSE KEYS

3.1. The Software shall not be used without a valid License Key issued by Licensor.
3.1. Distribution or sharing of License Keys to third parties, not associated with Licensee, is strictly prohibited.
3.2. License Keys are bound to the subscription period. Should your subscription expire, all License Keys will become invalid after 15 days from the subscription expiration date.
3.3. Any instance of the Software using such an expired key will revert to the Community Edition functionality after the aforementioned 15-day period.
3.2. Licensee is required to use valid License Keys issued by Licensor to run the Software, including any modified versions. Any attempts to bypass the License Key requirement is a violation of this Agreement.
3.3. Distribution or sharing of License Keys to third parties, not associated with Licensee, is strictly prohibited.
3.4. License Keys are bound to the subscription period. Should your subscription expire, all License Keys will become invalid after 15 days from the subscription expiration date.
3.5. Any instance of the Software using such an expired key will revert to the Community Edition functionality after the aforementioned 15-day period.

4. SOURCE CODE USAGE

4.1. Licensee is permitted to view, copy, and modify the Software's source code, as made available by Licensor, solely for Licensee's internal business use and in compliance with this Agreement's terms.
4.2. Any modifications to the source code do not grant Licensee any ownership rights to the original Software or any modifications. All rights, title, and interest to the Software and its source code remain exclusively with Licensor.
4.3. Licensee is strictly prohibited from altering, removing, or in any way tampering with the license key validation system within the Software. Any such unauthorized modifications will be considered a material breach of this Agreement and may result in legal action.
4.4. Licensee is required to use valid License Keys issued by Licensor to run the Software, including any modified versions. Any attempts to bypass the License Key requirement is a violation of this Agreement.
4.5. Notwithstanding the availability of the Software's source code for review and limited modification, the Software and its source code are not open source and remain proprietary to Licensor. The provision of access to the source code does not confer any rights typically associated with open source software, including but not limited to the right to freely distribute, sublicense, or create derivative works for public distribution. All rights not expressly granted herein are reserved by Licensor.
4.1. Licensee is permitted to view, copy, and modify the Software's Source Code, as made available by Licensor, solely for Licensee's internal business use and in compliance with this Agreement's terms.
4.2. Any modifications to the Source Code do not grant Licensee any ownership rights to the original Software or any modifications. All rights, title, and interest to the Software and its Source Code remain exclusively with Licensor.
4.3. Licensee is strictly prohibited from altering, removing, or in any way tampering with the License Key validation system within the Software. Any such unauthorized modifications will be considered a material breach of this Agreement and may result in legal action.
4.3. Notwithstanding the availability of the Software's Source Code for review and limited modification, the Software and its Source Code are not open source and remain proprietary to Licensor. The provision of access to the Source Code does not confer any rights typically associated with open source software, including but not limited to the right to freely sublicense, or create derivative works for public distribution. All rights not expressly granted herein are reserved by Licensor.
4.4. Notwithstanding the foregoing, you may copy the Source Code for development and testing purposes, without requiring a Subscription.

5. INTELLECTUAL PROPERTY RIGHTS

Expand Down
3 changes: 2 additions & 1 deletion crates/common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ nlp = { path = "../nlp" }
store = { path = "../store" }
directory = { path = "../directory" }
jmap_proto = { path = "../jmap-proto" }
se_licensing = { path = "../se-licensing" }
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" }
Expand Down Expand Up @@ -67,3 +67,4 @@ tracing-journald = "0.3"

[features]
test_mode = []
enterprise = ["se_licensing"]
24 changes: 17 additions & 7 deletions crates/common/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,25 @@
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/

use std::{sync::Arc, time::Duration};
use std::sync::Arc;

use arc_swap::ArcSwap;
use directory::{Directories, Directory};
use jmap_proto::types::collection::Collection;
use se_licensing::license::LicenseValidator;
use store::{BitmapKey, BlobBackend, BlobStore, FtsStore, LookupStore, Store, Stores};
use store::{BlobBackend, BlobStore, FtsStore, LookupStore, Store, Stores};
use utils::config::Config;

use crate::{
expr::*, listener::tls::TlsManager, manager::config::ConfigManager, webhooks::Webhooks, Core,
Enterprise, Network,
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,
Expand Down Expand Up @@ -122,14 +127,18 @@ impl Core {
// SPDX-FileCopyrightText: 2020 Stalwart Labs Ltd <[email protected]>
// 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(BitmapKey::document_ids(u32::MAX, Collection::Principal))
.get_bitmap(store::BitmapKey::document_ids(
u32::MAX,
Collection::Principal,
))
.await
{
Ok(Some(bitmap)) if bitmap.len() > license.accounts as u64 => {
Expand All @@ -152,7 +161,7 @@ impl Core {
_ => Some(Enterprise {
license,
undelete_period: config
.property_or_default::<Option<Duration>>(
.property_or_default::<Option<std::time::Duration>>(
"enterprise.undelete-period",
"false",
)
Expand Down Expand Up @@ -206,6 +215,7 @@ impl Core {
blobs: stores.blob_stores,
ftss: stores.fts_stores,
},
#[cfg(feature = "enterprise")]
enterprise,
}
}
Expand Down
7 changes: 5 additions & 2 deletions crates/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/

use std::{borrow::Cow, net::IpAddr, sync::Arc, time::Duration};
use std::{borrow::Cow, net::IpAddr, sync::Arc};

use arc_swap::ArcSwap;
use config::{
Expand Down Expand Up @@ -35,6 +35,7 @@ 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;
Expand Down Expand Up @@ -71,6 +72,7 @@ pub struct Core {
pub jmap: JmapConfig,
pub imap: ImapConfig,
pub web_hooks: Webhooks,
#[cfg(feature = "enterprise")]
pub enterprise: Option<Enterprise>,
}

Expand All @@ -85,10 +87,11 @@ pub struct Network {
// SPDX-FileCopyrightText: 2020 Stalwart Labs Ltd <[email protected]>
// SPDX-License-Identifier: LicenseRef-SEL

#[cfg(feature = "enterprise")]
#[derive(Clone)]
pub struct Enterprise {
pub license: LicenseKey,
pub undelete_period: Option<Duration>,
pub undelete_period: Option<std::time::Duration>,
}

// SPDX-SnippetEnd
Expand Down
3 changes: 2 additions & 1 deletion crates/jmap/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jmap_proto = { path = "../jmap-proto" }
smtp = { path = "../smtp" }
utils = { path = "../utils" }
common = { path = "../common" }
se_common = { path = "../se-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"] }
Expand Down Expand Up @@ -61,3 +61,4 @@ quick-xml = "0.35"

[features]
test_mode = []
enterprise = ["se_common"]
5 changes: 2 additions & 3 deletions crates/jmap/src/api/management/enterprise.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@
* SPDX-License-Identifier: LicenseRef-SEL
*
* This file is subject to the Stalwart Enterprise License Agreement (SEL) and
* is not open source software. It must not be modified or distributed without
* explicit permission from Stalwart Labs Ltd.
* Unauthorized use, modification, or distribution is strictly prohibited.
* is NOT open source software.
*
*/

use std::str::FromStr;
Expand Down
4 changes: 4 additions & 0 deletions crates/jmap/src/api/management/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

pub mod dkim;
pub mod domain;
#[cfg(feature = "enterprise")]
pub mod enterprise;
pub mod log;
pub mod principal;
Expand All @@ -24,6 +25,8 @@ use serde::Serialize;

use super::{http::ToHttpResponse, HttpRequest, HttpResponse, JsonResponse};
use crate::{auth::AccessToken, JMAP};

#[cfg(feature = "enterprise")]
use se_common::EnterpriseCore;

#[derive(Serialize)]
Expand Down Expand Up @@ -95,6 +98,7 @@ impl JMAP {
// SPDX-SnippetBegin
// SPDX-FileCopyrightText: 2020 Stalwart Labs Ltd <[email protected]>
// SPDX-License-Identifier: LicenseRef-SEL
#[cfg(feature = "enterprise")]
"pro" if is_superuser => {
// WARNING: TAMPERING WITH THIS FUNCTION IS STRICTLY PROHIBITED
// Any attempt to modify, bypass, or disable this license validation mechanism
Expand Down
9 changes: 8 additions & 1 deletion crates/jmap/src/auth/oauth/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ use crate::{
auth::{oauth::OAuthStatus, AccessToken},
JMAP,
};

#[cfg(feature = "enterprise")]
use se_common::EnterpriseCore;

use super::{
Expand Down Expand Up @@ -90,11 +92,16 @@ impl JMAP {
return err.into_http_response();
}

#[cfg(not(feature = "enterprise"))]
let is_enterprise = false;
#[cfg(feature = "enterprise")]
let is_enterprise = self.core.is_enterprise_edition();

json!({
"data": {
"code": client_code,
"is_admin": access_token.is_super_user(),
"is_enterprise": self.core.is_enterprise_edition(),
"is_enterprise": is_enterprise,
},
})
}
Expand Down
2 changes: 2 additions & 0 deletions crates/jmap/src/email/delete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use jmap_proto::{
type_state::DataType,
},
};
#[cfg(feature = "enterprise")]
use se_common::undelete::Undelete;
use store::{
ahash::AHashMap,
Expand Down Expand Up @@ -516,6 +517,7 @@ impl JMAP {
// SPDX-License-Identifier: LicenseRef-SEL

// Hold blob for undeletion
#[cfg(feature = "enterprise")]
self.core.hold_undelete(
&mut batch,
Collection::Email.into(),
Expand Down
3 changes: 3 additions & 0 deletions crates/jmap/src/services/housekeeper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ enum ActionClass {
Account,
Store(usize),
Acme(String),
#[cfg(feature = "enterprise")]
ReloadLicense,
}

Expand Down Expand Up @@ -113,6 +114,7 @@ pub fn spawn_housekeeper(core: JmapInstance, mut rx: mpsc::Receiver<Event>) {
// SPDX-License-Identifier: LicenseRef-SEL

// Enterprise Edition license management
#[cfg(feature = "enterprise")]
if let Some(enterprise) = &core_.enterprise {
queue.schedule(
Instant::now() + enterprise.license.expires_in(),
Expand Down Expand Up @@ -347,6 +349,7 @@ pub fn spawn_housekeeper(core: JmapInstance, mut rx: mpsc::Receiver<Event>) {
// SPDX-SnippetBegin
// SPDX-FileCopyrightText: 2020 Stalwart Labs Ltd <[email protected]>
// SPDX-License-Identifier: LicenseRef-SEL
#[cfg(feature = "enterprise")]
ActionClass::ReloadLicense => {
match core_.reload().await {
Ok(result) => {
Expand Down
7 changes: 4 additions & 3 deletions crates/main/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,16 @@ managesieve = { path = "../managesieve" }
common = { path = "../common" }
directory = { path = "../directory" }
utils = { path = "../utils" }
se_common = { path = "../se-common" }
se_common = { path = "../se-common", optional = true }
tokio = { version = "1.23", features = ["full"] }
tracing = "0.1"

[target.'cfg(not(target_env = "msvc"))'.dependencies]
jemallocator = "0.5.0"

[features]
default = ["sqlite", "postgres", "mysql", "rocks", "elastic", "s3", "redis"]
#default = ["sqlite", "postgres", "mysql", "rocks", "elastic", "s3", "redis", "foundationdb"]
default = ["sqlite", "postgres", "mysql", "rocks", "elastic", "s3", "redis", "enterprise"]
#default = ["sqlite", "postgres", "mysql", "rocks", "elastic", "s3", "redis", "foundationdb", "enterprise"]
sqlite = ["store/sqlite"]
foundationdb = ["store/foundation"]
postgres = ["store/postgres"]
Expand All @@ -44,3 +44,4 @@ rocks = ["store/rocks"]
elastic = ["store/elastic"]
s3 = ["store/s3"]
redis = ["store/redis"]
enterprise = ["se_common", "se_common/enterprise", "jmap/enterprise", "common/enterprise"]
2 changes: 2 additions & 0 deletions crates/main/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ 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;
Expand Down Expand Up @@ -56,6 +57,7 @@ async fn main() -> std::io::Result<()> {
config.log_warnings(init.guards.is_none());

// Log licensing information
#[cfg(feature = "enterprise")]
core.load().as_ref().log_license_details();

// Spawn servers
Expand Down
1 change: 1 addition & 0 deletions crates/se-common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ serde = { version = "1.0", features = ["derive"]}

[features]
test_mode = []
enterprise = ["common/enterprise"]
11 changes: 6 additions & 5 deletions crates/se-common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,22 @@
* SPDX-License-Identifier: LicenseRef-SEL
*
* This file is subject to the Stalwart Enterprise License Agreement (SEL) and
* is not open source software. It must not be modified or distributed without
* explicit permission from Stalwart Labs Ltd.
* Unauthorized use, modification, or distribution is strictly prohibited.
* is NOT open source software.
*
*/

#[cfg(feature = "enterprise")]
pub mod undelete;
use common::Core;

#[cfg(feature = "enterprise")]
pub trait EnterpriseCore {
fn is_enterprise_edition(&self) -> bool;
fn log_license_details(&self);
fn licensed_accounts(&self) -> u32;
}

impl EnterpriseCore for Core {
#[cfg(feature = "enterprise")]
impl EnterpriseCore for common::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.
Expand Down
5 changes: 2 additions & 3 deletions crates/se-common/src/undelete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@
* SPDX-License-Identifier: LicenseRef-SEL
*
* This file is subject to the Stalwart Enterprise License Agreement (SEL) and
* is not open source software. It must not be modified or distributed without
* explicit permission from Stalwart Labs Ltd.
* Unauthorized use, modification, or distribution is strictly prohibited.
* is NOT open source software.
*
*/

use std::future::Future;
Expand Down
Loading

0 comments on commit 38ff4b9

Please sign in to comment.