Import upstream v0.16.22, stripped
Upstream commit: 474dd0229cb20cf513036619781ed97bd8073c3f Enterprise-only files removed or emptied: 63 Enterprise-only snippets removed: 117 in 50 files Dangling module declarations removed: 5 Cargo edits turning enterprise off: 14 Verification: clean Enterprise feature gates left for rebuilt features: 19 in 18 files Produced by tools/fork/strip.py. The full report is in docs/fork/strip-reports/ on main.
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use types::id::Id;
|
||||
|
||||
use crate::schema::prelude::{
|
||||
Account, Credential, GroupAccount, PasswordCredential, SecondaryCredential, UserAccount,
|
||||
};
|
||||
|
||||
impl Account {
|
||||
pub fn into_user(self) -> Option<UserAccount> {
|
||||
if let Account::User(user) = self {
|
||||
Some(user)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_group(self) -> Option<GroupAccount> {
|
||||
if let Account::Group(group) = self {
|
||||
Some(group)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl UserAccount {
|
||||
pub fn set_password(&mut self, password: String) {
|
||||
if let Some(credential) = self.credentials.0.values_mut().find_map(|credential| {
|
||||
if let Credential::Password(credential) = credential {
|
||||
Some(credential)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}) {
|
||||
credential.secret = password;
|
||||
} else {
|
||||
let credential_id = self.next_credential_id().into();
|
||||
self.credentials
|
||||
.push(Credential::Password(PasswordCredential {
|
||||
credential_id,
|
||||
secret: password,
|
||||
..Default::default()
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn password_credential(&self) -> Option<&PasswordCredential> {
|
||||
self.credentials.iter().find_map(|credential| {
|
||||
if let Credential::Password(credential) = credential {
|
||||
Some(credential)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn password_credential_mut(&mut self) -> Option<&mut PasswordCredential> {
|
||||
self.credentials.values_mut().find_map(|credential| {
|
||||
if let Credential::Password(credential) = credential {
|
||||
Some(credential)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn password(&self) -> Option<&str> {
|
||||
self.password_credential()
|
||||
.map(|credential| credential.secret.as_str())
|
||||
}
|
||||
|
||||
pub fn into_password_credential(self) -> Option<PasswordCredential> {
|
||||
self.credentials.into_iter().find_map(|credential| {
|
||||
if let Credential::Password(credential) = credential {
|
||||
Some(credential)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn into_password(self) -> Option<String> {
|
||||
self.into_password_credential()
|
||||
.map(|credential| credential.secret)
|
||||
}
|
||||
|
||||
pub fn next_credential_id(&self) -> u64 {
|
||||
self.credentials
|
||||
.0
|
||||
.values()
|
||||
.map(|credential| match credential {
|
||||
Credential::Password(credential) => credential.credential_id.id() + 1,
|
||||
Credential::AppPassword(credential_properties)
|
||||
| Credential::ApiKey(credential_properties) => {
|
||||
credential_properties.credential_id.id() + 1
|
||||
}
|
||||
})
|
||||
.max()
|
||||
.unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
impl Credential {
|
||||
pub fn credential_id(&self) -> Id {
|
||||
match self {
|
||||
Credential::Password(credential) => credential.credential_id,
|
||||
Credential::AppPassword(credential_properties) => credential_properties.credential_id,
|
||||
Credential::ApiKey(credential_properties) => credential_properties.credential_id,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_credential_id(&mut self, credential_id: Id) {
|
||||
match self {
|
||||
Credential::Password(credential) => credential.credential_id = credential_id,
|
||||
Credential::AppPassword(credential_properties) => {
|
||||
credential_properties.credential_id = credential_id
|
||||
}
|
||||
Credential::ApiKey(credential_properties) => {
|
||||
credential_properties.credential_id = credential_id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_secondary_credential(self) -> Option<SecondaryCredential> {
|
||||
match self {
|
||||
Credential::AppPassword(credential_properties) => Some(credential_properties),
|
||||
Credential::ApiKey(credential_properties) => Some(credential_properties),
|
||||
Credential::Password(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_secondary_credential(&self) -> Option<&SecondaryCredential> {
|
||||
match self {
|
||||
Credential::AppPassword(credential_properties) => Some(credential_properties),
|
||||
Credential::ApiKey(credential_properties) => Some(credential_properties),
|
||||
Credential::Password(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_main_credential(&self) -> Option<&PasswordCredential> {
|
||||
match self {
|
||||
Credential::Password(credential) => Some(credential),
|
||||
Credential::AppPassword(_) | Credential::ApiKey(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use crate::schema::prelude::{ArchivedItem, UTCDateTime};
|
||||
use types::{blob::BlobId, id::Id};
|
||||
|
||||
impl ArchivedItem {
|
||||
pub fn account_id(&self) -> Id {
|
||||
match self {
|
||||
ArchivedItem::Email(i) => i.account_id,
|
||||
ArchivedItem::FileNode(i) => i.account_id,
|
||||
ArchivedItem::CalendarEvent(i) => i.account_id,
|
||||
ArchivedItem::ContactCard(i) => i.account_id,
|
||||
ArchivedItem::SieveScript(i) => i.account_id,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn blob_id(&self) -> &BlobId {
|
||||
match self {
|
||||
ArchivedItem::Email(i) => &i.blob_id,
|
||||
ArchivedItem::FileNode(i) => &i.blob_id,
|
||||
ArchivedItem::CalendarEvent(i) => &i.blob_id,
|
||||
ArchivedItem::ContactCard(i) => &i.blob_id,
|
||||
ArchivedItem::SieveScript(i) => &i.blob_id,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn archived_until(&self) -> UTCDateTime {
|
||||
match self {
|
||||
ArchivedItem::Email(i) => i.archived_until,
|
||||
ArchivedItem::FileNode(i) => i.archived_until,
|
||||
ArchivedItem::CalendarEvent(i) => i.archived_until,
|
||||
ArchivedItem::ContactCard(i) => i.archived_until,
|
||||
ArchivedItem::SieveScript(i) => i.archived_until,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn created_at(&self) -> UTCDateTime {
|
||||
match self {
|
||||
ArchivedItem::Email(i) => i.received_at,
|
||||
ArchivedItem::FileNode(i) => i.created_at,
|
||||
ArchivedItem::CalendarEvent(i) => i.created_at,
|
||||
ArchivedItem::ContactCard(i) => i.created_at,
|
||||
ArchivedItem::SieveScript(i) => i.created_at,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_account_id(&mut self, value: Id) {
|
||||
match self {
|
||||
ArchivedItem::Email(i) => i.account_id = value,
|
||||
ArchivedItem::FileNode(i) => i.account_id = value,
|
||||
ArchivedItem::CalendarEvent(i) => i.account_id = value,
|
||||
ArchivedItem::ContactCard(i) => i.account_id = value,
|
||||
ArchivedItem::SieveScript(i) => i.account_id = value,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_blob_id(&mut self, value: BlobId) {
|
||||
match self {
|
||||
ArchivedItem::Email(i) => i.blob_id = value,
|
||||
ArchivedItem::FileNode(i) => i.blob_id = value,
|
||||
ArchivedItem::CalendarEvent(i) => i.blob_id = value,
|
||||
ArchivedItem::ContactCard(i) => i.blob_id = value,
|
||||
ArchivedItem::SieveScript(i) => i.blob_id = value,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_archived_until(&mut self, value: UTCDateTime) {
|
||||
match self {
|
||||
ArchivedItem::Email(i) => i.archived_until = value,
|
||||
ArchivedItem::FileNode(i) => i.archived_until = value,
|
||||
ArchivedItem::CalendarEvent(i) => i.archived_until = value,
|
||||
ArchivedItem::ContactCard(i) => i.archived_until = value,
|
||||
ArchivedItem::SieveScript(i) => i.archived_until = value,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn account_id_mut(&mut self) -> &mut Id {
|
||||
match self {
|
||||
ArchivedItem::Email(i) => &mut i.account_id,
|
||||
ArchivedItem::FileNode(i) => &mut i.account_id,
|
||||
ArchivedItem::CalendarEvent(i) => &mut i.account_id,
|
||||
ArchivedItem::ContactCard(i) => &mut i.account_id,
|
||||
ArchivedItem::SieveScript(i) => &mut i.account_id,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn blob_id_mut(&mut self) -> &mut BlobId {
|
||||
match self {
|
||||
ArchivedItem::Email(i) => &mut i.blob_id,
|
||||
ArchivedItem::FileNode(i) => &mut i.blob_id,
|
||||
ArchivedItem::CalendarEvent(i) => &mut i.blob_id,
|
||||
ArchivedItem::ContactCard(i) => &mut i.blob_id,
|
||||
ArchivedItem::SieveScript(i) => &mut i.blob_id,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn archived_until_mut(&mut self) -> &mut UTCDateTime {
|
||||
match self {
|
||||
ArchivedItem::Email(i) => &mut i.archived_until,
|
||||
ArchivedItem::FileNode(i) => &mut i.archived_until,
|
||||
ArchivedItem::CalendarEvent(i) => &mut i.archived_until,
|
||||
ArchivedItem::ContactCard(i) => &mut i.archived_until,
|
||||
ArchivedItem::SieveScript(i) => &mut i.archived_until,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_blob_id(self) -> BlobId {
|
||||
match self {
|
||||
ArchivedItem::Email(i) => i.blob_id,
|
||||
ArchivedItem::FileNode(i) => i.blob_id,
|
||||
ArchivedItem::CalendarEvent(i) => i.blob_id,
|
||||
ArchivedItem::ContactCard(i) => i.blob_id,
|
||||
ArchivedItem::SieveScript(i) => i.blob_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use crate::schema::prelude::Cron;
|
||||
use utils::cron::SimpleCron;
|
||||
|
||||
impl From<Cron> for SimpleCron {
|
||||
fn from(value: Cron) -> Self {
|
||||
match value {
|
||||
Cron::Daily(cron) => SimpleCron::Day {
|
||||
hour: cron.hour as u32,
|
||||
minute: cron.minute as u32,
|
||||
},
|
||||
Cron::Weekly(cron) => SimpleCron::Week {
|
||||
day: cron.day as u32,
|
||||
hour: cron.hour as u32,
|
||||
minute: cron.minute as u32,
|
||||
},
|
||||
Cron::Hourly(cron) => SimpleCron::Hour {
|
||||
minute: cron.minute as u32,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use crate::schema::{
|
||||
enums::{DkimRotationStage, DkimSignatureType},
|
||||
prelude::{DkimSignature, UTCDateTime},
|
||||
};
|
||||
use types::id::Id;
|
||||
|
||||
impl DkimSignature {
|
||||
pub fn rotation_due(&self) -> Option<DkimRotationStage> {
|
||||
let (stage, next_transition) = match self {
|
||||
DkimSignature::Dkim1Ed25519Sha256(sign) => (sign.stage, sign.next_transition_at),
|
||||
DkimSignature::Dkim1RsaSha256(sign) => (sign.stage, sign.next_transition_at),
|
||||
DkimSignature::Dkim2Ed25519Sha256(sign) => (sign.stage, sign.next_transition_at),
|
||||
DkimSignature::Dkim2RsaSha256(sign) => (sign.stage, sign.next_transition_at),
|
||||
};
|
||||
next_transition.and_then(|next_transition| {
|
||||
if next_transition <= UTCDateTime::now() {
|
||||
Some(stage)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn next_transition(&self) -> Option<UTCDateTime> {
|
||||
match self {
|
||||
DkimSignature::Dkim1Ed25519Sha256(sign) => sign.next_transition_at,
|
||||
DkimSignature::Dkim1RsaSha256(sign) => sign.next_transition_at,
|
||||
DkimSignature::Dkim2Ed25519Sha256(sign) => sign.next_transition_at,
|
||||
DkimSignature::Dkim2RsaSha256(sign) => sign.next_transition_at,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_next_transition(&mut self, next_transition: UTCDateTime) {
|
||||
match self {
|
||||
DkimSignature::Dkim1Ed25519Sha256(sign) => {
|
||||
sign.next_transition_at = Some(next_transition)
|
||||
}
|
||||
DkimSignature::Dkim1RsaSha256(sign) => sign.next_transition_at = Some(next_transition),
|
||||
DkimSignature::Dkim2Ed25519Sha256(sign) => {
|
||||
sign.next_transition_at = Some(next_transition)
|
||||
}
|
||||
DkimSignature::Dkim2RsaSha256(sign) => sign.next_transition_at = Some(next_transition),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stage(&self) -> DkimRotationStage {
|
||||
match self {
|
||||
DkimSignature::Dkim1Ed25519Sha256(sign) => sign.stage,
|
||||
DkimSignature::Dkim1RsaSha256(sign) => sign.stage,
|
||||
DkimSignature::Dkim2Ed25519Sha256(sign) => sign.stage,
|
||||
DkimSignature::Dkim2RsaSha256(sign) => sign.stage,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_stage(&mut self, stage: DkimRotationStage) {
|
||||
match self {
|
||||
DkimSignature::Dkim1Ed25519Sha256(sign) => sign.stage = stage,
|
||||
DkimSignature::Dkim1RsaSha256(sign) => sign.stage = stage,
|
||||
DkimSignature::Dkim2Ed25519Sha256(sign) => sign.stage = stage,
|
||||
DkimSignature::Dkim2RsaSha256(sign) => sign.stage = stage,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_active(&self) -> bool {
|
||||
match self {
|
||||
DkimSignature::Dkim1Ed25519Sha256(sign) => sign.stage == DkimRotationStage::Active,
|
||||
DkimSignature::Dkim1RsaSha256(sign) => sign.stage == DkimRotationStage::Active,
|
||||
DkimSignature::Dkim2Ed25519Sha256(sign) => sign.stage == DkimRotationStage::Active,
|
||||
DkimSignature::Dkim2RsaSha256(sign) => sign.stage == DkimRotationStage::Active,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_published(&self) -> bool {
|
||||
!matches!(self.stage(), DkimRotationStage::Retired)
|
||||
}
|
||||
|
||||
pub fn selector(&self) -> &str {
|
||||
match self {
|
||||
DkimSignature::Dkim1Ed25519Sha256(sign) => &sign.selector,
|
||||
DkimSignature::Dkim1RsaSha256(sign) => &sign.selector,
|
||||
DkimSignature::Dkim2Ed25519Sha256(sign) => &sign.selector,
|
||||
DkimSignature::Dkim2RsaSha256(sign) => &sign.selector,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn domain_id(&self) -> Id {
|
||||
match self {
|
||||
DkimSignature::Dkim1Ed25519Sha256(sign) => sign.domain_id,
|
||||
DkimSignature::Dkim1RsaSha256(sign) => sign.domain_id,
|
||||
DkimSignature::Dkim2Ed25519Sha256(sign) => sign.domain_id,
|
||||
DkimSignature::Dkim2RsaSha256(sign) => sign.domain_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DkimSignatureType {
|
||||
pub const fn algorithm(self) -> &'static str {
|
||||
match self {
|
||||
Self::Dkim1Ed25519Sha256 | Self::Dkim2Ed25519Sha256 => "ed25519",
|
||||
Self::Dkim1RsaSha256 | Self::Dkim2RsaSha256 => "rsa",
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn hash(self) -> &'static str {
|
||||
"sha256"
|
||||
}
|
||||
|
||||
pub const fn version(self) -> &'static str {
|
||||
match self {
|
||||
Self::Dkim1Ed25519Sha256 | Self::Dkim1RsaSha256 => "1",
|
||||
Self::Dkim2Ed25519Sha256 | Self::Dkim2RsaSha256 => "2",
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use crate::schema::prelude::{Duration, HttpAuth};
|
||||
use utils::{
|
||||
Client, HeaderMap,
|
||||
http::{build_http_client, build_http_headers},
|
||||
map::vec_map::VecMap,
|
||||
};
|
||||
|
||||
impl HttpAuth {
|
||||
pub async fn build_headers(
|
||||
&self,
|
||||
extra_headers: VecMap<String, String>,
|
||||
content_type: Option<&str>,
|
||||
) -> Result<HeaderMap, String> {
|
||||
match self {
|
||||
HttpAuth::Unauthenticated => {
|
||||
build_http_headers(extra_headers, None, None, None, content_type)
|
||||
}
|
||||
HttpAuth::Basic(auth) => build_http_headers(
|
||||
extra_headers,
|
||||
auth.username.as_str().into(),
|
||||
auth.secret.secret().await?.as_ref().into(),
|
||||
None,
|
||||
content_type,
|
||||
),
|
||||
HttpAuth::Bearer(auth) => build_http_headers(
|
||||
extra_headers,
|
||||
None,
|
||||
None,
|
||||
auth.bearer_token.secret().await?.as_ref().into(),
|
||||
content_type,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn build_http_client(
|
||||
&self,
|
||||
extra_headers: VecMap<String, String>,
|
||||
content_type: Option<&str>,
|
||||
timeout: Duration,
|
||||
allow_invalid_certs: bool,
|
||||
) -> Result<Client, String> {
|
||||
match self {
|
||||
HttpAuth::Unauthenticated => build_http_client(
|
||||
extra_headers,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
content_type,
|
||||
timeout.into_inner(),
|
||||
allow_invalid_certs,
|
||||
),
|
||||
HttpAuth::Basic(auth) => build_http_client(
|
||||
extra_headers,
|
||||
auth.username.as_str().into(),
|
||||
auth.secret.secret().await?.as_ref().into(),
|
||||
None,
|
||||
content_type,
|
||||
timeout.into_inner(),
|
||||
allow_invalid_certs,
|
||||
),
|
||||
HttpAuth::Bearer(auth) => build_http_client(
|
||||
extra_headers,
|
||||
None,
|
||||
None,
|
||||
auth.bearer_token.secret().await?.as_ref().into(),
|
||||
content_type,
|
||||
timeout.into_inner(),
|
||||
allow_invalid_certs,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use crate::schema::prelude::{DkimSignature, Roles, SecretText};
|
||||
use types::id::Id;
|
||||
|
||||
pub mod account;
|
||||
pub mod archived_item;
|
||||
pub mod cron;
|
||||
pub mod dkim;
|
||||
pub mod http;
|
||||
pub mod report;
|
||||
pub mod secret;
|
||||
pub mod task;
|
||||
|
||||
impl Roles {
|
||||
pub fn role_ids(&self) -> Option<&[Id]> {
|
||||
match self {
|
||||
Roles::Default => None,
|
||||
Roles::Custom(custom_roles) => Some(custom_roles.role_ids.as_slice()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DkimSignature {
|
||||
pub fn private_key(&self) -> &SecretText {
|
||||
match self {
|
||||
DkimSignature::Dkim1Ed25519Sha256(signature) => &signature.private_key,
|
||||
DkimSignature::Dkim1RsaSha256(signature) => &signature.private_key,
|
||||
DkimSignature::Dkim2Ed25519Sha256(signature) => &signature.private_key,
|
||||
DkimSignature::Dkim2RsaSha256(signature) => &signature.private_key,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn private_key_mut(&mut self) -> &mut SecretText {
|
||||
match self {
|
||||
DkimSignature::Dkim1Ed25519Sha256(signature) => &mut signature.private_key,
|
||||
DkimSignature::Dkim1RsaSha256(signature) => &mut signature.private_key,
|
||||
DkimSignature::Dkim2Ed25519Sha256(signature) => &mut signature.private_key,
|
||||
DkimSignature::Dkim2RsaSha256(signature) => &mut signature.private_key,
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use crate::schema::prelude::{
|
||||
PublicStringOptional, PublicStringValue, PublicText, SecretKey, SecretKeyEnvironmentVariable,
|
||||
SecretKeyFile, SecretKeyOptional, SecretKeyValue, SecretText, SecretTextOptional,
|
||||
SecretTextValue,
|
||||
};
|
||||
use std::borrow::Cow;
|
||||
|
||||
impl SecretKey {
|
||||
pub async fn secret(&self) -> Result<Cow<'_, str>, String> {
|
||||
match self {
|
||||
SecretKey::Value(value) => Ok(Cow::Borrowed(value.secret())),
|
||||
SecretKey::File(file) => file.secret().await.map(Cow::Owned),
|
||||
SecretKey::EnvironmentVariable(env_var) => env_var.secret().map(Cow::Owned),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SecretText {
|
||||
pub async fn secret(&self) -> Result<Cow<'_, str>, String> {
|
||||
match self {
|
||||
SecretText::Text(value) => Ok(Cow::Borrowed(value.secret())),
|
||||
SecretText::File(file) => file.secret().await.map(Cow::Owned),
|
||||
SecretText::EnvironmentVariable(env_var) => env_var.secret().map(Cow::Owned),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PublicText {
|
||||
pub async fn value(&self) -> Result<Cow<'_, str>, String> {
|
||||
match self {
|
||||
PublicText::Text(value) => Ok(Cow::Borrowed(value.value.as_str())),
|
||||
PublicText::File(file) => file.secret().await.map(Cow::Owned),
|
||||
PublicText::EnvironmentVariable(env_var) => env_var.secret().map(Cow::Owned),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SecretKeyOptional {
|
||||
pub async fn secret(&self) -> Result<Option<Cow<'_, str>>, String> {
|
||||
match self {
|
||||
SecretKeyOptional::None => Ok(None),
|
||||
SecretKeyOptional::Value(secret_key_value) => {
|
||||
Ok(Some(Cow::Borrowed(secret_key_value.secret())))
|
||||
}
|
||||
SecretKeyOptional::EnvironmentVariable(secret_key_environment_variable) => {
|
||||
secret_key_environment_variable
|
||||
.secret()
|
||||
.map(|s| Some(Cow::Owned(s)))
|
||||
}
|
||||
SecretKeyOptional::File(secret_key_file) => {
|
||||
secret_key_file.secret().await.map(|s| Some(Cow::Owned(s)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PublicStringOptional {
|
||||
pub async fn value(&self) -> Result<Option<Cow<'_, str>>, String> {
|
||||
match self {
|
||||
PublicStringOptional::None => Ok(None),
|
||||
PublicStringOptional::Value(public_string_value) => {
|
||||
Ok(Some(Cow::Borrowed(public_string_value.value())))
|
||||
}
|
||||
PublicStringOptional::EnvironmentVariable(secret_key_environment_variable) => {
|
||||
secret_key_environment_variable
|
||||
.secret()
|
||||
.map(|s| Some(Cow::Owned(s)))
|
||||
}
|
||||
PublicStringOptional::File(secret_key_file) => {
|
||||
secret_key_file.secret().await.map(|s| Some(Cow::Owned(s)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PublicStringValue {
|
||||
pub fn value(&self) -> &str {
|
||||
self.value.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl SecretTextOptional {
|
||||
pub async fn secret(&self) -> Result<Option<Cow<'_, str>>, String> {
|
||||
match self {
|
||||
SecretTextOptional::None => Ok(None),
|
||||
SecretTextOptional::Text(secret_text_value) => {
|
||||
Ok(Some(Cow::Borrowed(secret_text_value.secret())))
|
||||
}
|
||||
SecretTextOptional::EnvironmentVariable(secret_text_environment_variable) => {
|
||||
secret_text_environment_variable
|
||||
.secret()
|
||||
.map(|s| Some(Cow::Owned(s)))
|
||||
}
|
||||
SecretTextOptional::File(secret_text_file) => {
|
||||
secret_text_file.secret().await.map(|s| Some(Cow::Owned(s)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SecretKeyValue {
|
||||
pub fn secret(&self) -> &str {
|
||||
self.secret.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl SecretTextValue {
|
||||
pub fn secret(&self) -> &str {
|
||||
self.secret.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl SecretKeyFile {
|
||||
pub async fn secret(&self) -> Result<String, String> {
|
||||
let path = self.file_path.trim();
|
||||
if !path.is_empty() {
|
||||
tokio::fs::read_to_string(path)
|
||||
.await
|
||||
.map_err(|err| format!("Failed to read secret from file '{}': {}", path, err))
|
||||
.and_then(|content| {
|
||||
let secret = content.trim_end();
|
||||
if !secret.is_empty() {
|
||||
Ok(secret.to_string())
|
||||
} else {
|
||||
Err(format!("Secret in file '{}' is empty", path))
|
||||
}
|
||||
})
|
||||
} else {
|
||||
Err("File path cannot be empty".to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SecretKeyEnvironmentVariable {
|
||||
pub fn secret(&self) -> Result<String, String> {
|
||||
let var = self.variable_name.trim();
|
||||
if !var.is_empty() {
|
||||
std::env::var(var)
|
||||
.ok()
|
||||
.filter(|v| !v.is_empty())
|
||||
.ok_or_else(|| format!("Environment variable '{}' not found", var))
|
||||
} else {
|
||||
Err("Variable name cannot be empty".to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use crate::schema::{
|
||||
enums::Permission,
|
||||
prelude::{Action, Task, TaskStatus, TaskStatusPending, UTCDateTime},
|
||||
};
|
||||
|
||||
impl Task {
|
||||
pub fn set_status(&mut self, status: TaskStatus) {
|
||||
match self {
|
||||
Task::IndexDocument(task) => task.status = status,
|
||||
Task::UnindexDocument(task) => task.status = status,
|
||||
Task::IndexTrace(task) => task.status = status,
|
||||
Task::CalendarAlarmEmail(task) => task.status = status,
|
||||
Task::CalendarAlarmNotification(task) => task.status = status,
|
||||
Task::CalendarItipMessage(task) => task.status = status,
|
||||
Task::MergeThreads(task) => task.status = status,
|
||||
Task::DmarcReport(task) => task.status = status,
|
||||
Task::TlsReport(task) => task.status = status,
|
||||
Task::RestoreArchivedItem(task) => task.status = status,
|
||||
Task::DestroyAccount(task) => task.status = status,
|
||||
Task::AccountMaintenance(task) => task.status = status,
|
||||
Task::StoreMaintenance(task) => task.status = status,
|
||||
Task::SpamFilterMaintenance(task) => task.status = status,
|
||||
Task::AcmeRenewal(task) => task.status = status,
|
||||
Task::DkimManagement(task) => task.status = status,
|
||||
Task::DnsManagement(task) => task.status = status,
|
||||
Task::TenantMaintenance(task) => task.status = status,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn status(&self) -> &TaskStatus {
|
||||
match self {
|
||||
Task::IndexDocument(task) => &task.status,
|
||||
Task::UnindexDocument(task) => &task.status,
|
||||
Task::IndexTrace(task) => &task.status,
|
||||
Task::CalendarAlarmEmail(task) => &task.status,
|
||||
Task::CalendarAlarmNotification(task) => &task.status,
|
||||
Task::CalendarItipMessage(task) => &task.status,
|
||||
Task::MergeThreads(task) => &task.status,
|
||||
Task::DmarcReport(task) => &task.status,
|
||||
Task::TlsReport(task) => &task.status,
|
||||
Task::RestoreArchivedItem(task) => &task.status,
|
||||
Task::DestroyAccount(task) => &task.status,
|
||||
Task::AccountMaintenance(task) => &task.status,
|
||||
Task::StoreMaintenance(task) => &task.status,
|
||||
Task::SpamFilterMaintenance(task) => &task.status,
|
||||
Task::AcmeRenewal(task) => &task.status,
|
||||
Task::DkimManagement(task) => &task.status,
|
||||
Task::DnsManagement(task) => &task.status,
|
||||
Task::TenantMaintenance(task) => &task.status,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn attempt_number(&self) -> u64 {
|
||||
match self.status() {
|
||||
TaskStatus::Pending(_) => 0,
|
||||
TaskStatus::Retry(status) => status.attempt_number,
|
||||
TaskStatus::Failed(status) => status.failed_attempt_number,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn due_timestamp(&self) -> u64 {
|
||||
match self.status() {
|
||||
TaskStatus::Pending(status) => status.due.timestamp() as u64,
|
||||
TaskStatus::Retry(status) => status.due.timestamp() as u64,
|
||||
TaskStatus::Failed(_) => u64::MAX,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn permission(&self) -> Permission {
|
||||
match self {
|
||||
Task::IndexDocument(_) => Permission::TaskIndexDocument,
|
||||
Task::UnindexDocument(_) => Permission::TaskUnindexDocument,
|
||||
Task::IndexTrace(_) => Permission::TaskIndexTrace,
|
||||
Task::CalendarAlarmEmail(_) => Permission::TaskCalendarAlarmEmail,
|
||||
Task::CalendarAlarmNotification(_) => Permission::TaskCalendarAlarmNotification,
|
||||
Task::CalendarItipMessage(_) => Permission::TaskCalendarItipMessage,
|
||||
Task::MergeThreads(_) => Permission::TaskMergeThreads,
|
||||
Task::DmarcReport(_) => Permission::TaskDmarcReport,
|
||||
Task::TlsReport(_) => Permission::TaskTlsReport,
|
||||
Task::RestoreArchivedItem(_) => Permission::TaskRestoreArchivedItem,
|
||||
Task::DestroyAccount(_) => Permission::TaskDestroyAccount,
|
||||
Task::AccountMaintenance(_) => Permission::TaskAccountMaintenance,
|
||||
Task::StoreMaintenance(_) => Permission::TaskStoreMaintenance,
|
||||
Task::SpamFilterMaintenance(_) => Permission::TaskSpamFilterMaintenance,
|
||||
Task::AcmeRenewal(_) => Permission::TaskAcmeRenewal,
|
||||
Task::DkimManagement(_) => Permission::TaskDkimManagement,
|
||||
Task::DnsManagement(_) => Permission::TaskDnsManagement,
|
||||
Task::TenantMaintenance(_) => Permission::TaskTenantMaintenance,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Action {
|
||||
pub fn permission(&self) -> Permission {
|
||||
match self {
|
||||
Action::ReloadSettings => Permission::ActionReloadSettings,
|
||||
Action::ReloadTlsCertificates => Permission::ActionReloadTlsCertificates,
|
||||
Action::ReloadLookupStores => Permission::ActionReloadLookupStores,
|
||||
Action::ReloadBlockedIps => Permission::ActionReloadBlockedIps,
|
||||
Action::TroubleshootDmarc(_) => Permission::ActionTroubleshootDmarc,
|
||||
Action::ClassifySpam(_) => Permission::ActionClassifySpam,
|
||||
Action::InvalidateCaches => Permission::ActionInvalidateCaches,
|
||||
Action::InvalidateNegativeCaches => Permission::ActionInvalidateNegativeCaches,
|
||||
Action::PauseMtaQueue => Permission::ActionPauseMtaQueue,
|
||||
Action::ResumeMtaQueue => Permission::ActionResumeMtaQueue,
|
||||
Action::UpdateApps => Permission::ActionUpdateApps,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TaskStatus {
|
||||
pub fn now() -> Self {
|
||||
let now = UTCDateTime::now();
|
||||
TaskStatus::Pending(TaskStatusPending {
|
||||
created_at: now,
|
||||
due: now,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn at(timestamp: i64) -> Self {
|
||||
TaskStatus::Pending(TaskStatusPending {
|
||||
due: UTCDateTime::from_timestamp(timestamp),
|
||||
created_at: UTCDateTime::now(),
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user