Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/test smtp #2806

Merged
merged 13 commits into from
Jan 9, 2025
499 changes: 447 additions & 52 deletions core/Cargo.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions core/models/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ rand = "0.8.5"
regex = "1.10.2"
reqwest = "0.12"
rpc-toolkit = { git = "https://github.com/Start9Labs/rpc-toolkit.git", branch = "refactor/no-dyn-ctx" }
rustls = "0.23"
serde = { version = "1.0", features = ["derive", "rc"] }
serde_json = "1.0"
sqlx = { version = "0.7.2", features = [
Expand Down
5 changes: 5 additions & 0 deletions core/models/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,11 @@ impl From<torut::onion::OnionAddressParseError> for Error {
Error::new(e, ErrorKind::Tor)
}
}
impl From<rustls::Error> for Error {
fn from(e: rustls::Error) -> Self {
Error::new(e, ErrorKind::OpenSsl)
}
}
impl From<patch_db::value::Error> for Error {
fn from(value: patch_db::value::Error) -> Self {
match value.kind {
Expand Down
3 changes: 3 additions & 0 deletions core/startos/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,9 @@ url = { version = "2.4.1", features = ["serde"] }
urlencoding = "2.1.3"
uuid = { version = "1.4.1", features = ["v4"] }
zeroize = "1.6.0"
mail-send = { git = "https://github.com/dr-bonez/mail-send.git", branch = "main" }
rustls = "0.23.20"
rustls-pki-types = { version = "1.10.1", features = ["alloc"]}

[profile.test]
opt-level = 3
Expand Down
7 changes: 7 additions & 0 deletions core/startos/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,13 @@ pub fn server<C: Context>() -> ParentHandler<C> {
.with_about("Set system smtp server and credentials")
.with_call_remote::<CliContext>()
)
.subcommand(
"test-smtp",
from_fn_async(system::test_system_smtp)
.no_display()
.with_about("Send test email using system smtp server and credentials")
.with_call_remote::<CliContext>()
)
.subcommand(
"clear-smtp",
from_fn_async(system::clear_system_smtp)
Expand Down
6 changes: 2 additions & 4 deletions core/startos/src/lxc/dev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,11 @@ use rpc_toolkit::{
use serde::{Deserialize, Serialize};
use ts_rs::TS;

use crate::context::{CliContext, RpcContext};
use crate::lxc::{ContainerId, LxcConfig};
use crate::prelude::*;
use crate::rpc_continuations::Guid;
use crate::{
context::{CliContext, RpcContext},
service::ServiceStats,
};
use crate::service::ServiceStats;

pub fn lxc<C: Context>() -> ParentHandler<C> {
ParentHandler::new()
Expand Down
3 changes: 2 additions & 1 deletion core/startos/src/lxc/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use std::collections::BTreeSet;
use std::ffi::OsString;
use std::net::Ipv4Addr;
use std::path::Path;
use std::sync::{Arc, Weak};
use std::time::Duration;
use std::{collections::BTreeSet, ffi::OsString};

use clap::builder::ValueParserFactory;
use futures::{AsyncWriteExt, StreamExt};
Expand Down
10 changes: 7 additions & 3 deletions core/startos/src/net/vhost.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ use crate::net::acme::AcmeCertCache;
use crate::net::static_server::server_error;
use crate::prelude::*;
use crate::util::io::BackTrackingIO;
use crate::util::sync::SyncMutex;
use crate::util::serde::MaybeUtf8String;
use crate::util::sync::SyncMutex;

#[derive(Debug)]
struct SingleCertResolver(Arc<CertifiedKey>);
Expand Down Expand Up @@ -126,7 +126,11 @@ struct VHostServer {
}
impl VHostServer {
#[instrument(skip_all)]
async fn new(port: u16, db: TypedPatchDb<Database>, crypto_provider: Arc<CryptoProvider>) -> Result<Self, Error> {
async fn new(
port: u16,
db: TypedPatchDb<Database>,
crypto_provider: Arc<CryptoProvider>,
) -> Result<Self, Error> {
let acme_tls_alpn_cache = Arc::new(SyncMutex::new(BTreeMap::<
InternedString,
watch::Receiver<Option<Arc<CertifiedKey>>>,
Expand Down Expand Up @@ -273,7 +277,7 @@ impl VHostServer {
let domains = [domain.to_string()];
let (send, recv) = watch::channel(None);
acme_tls_alpn_cache.mutate(|c| c.insert(domain.clone(), recv));
let cert =
let cert =
async_acme::rustls_helper::order(
|_, cert| {
send.send_replace(Some(Arc::new(cert)));
Expand Down
4 changes: 2 additions & 2 deletions core/startos/src/notifications.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ use serde::{Deserialize, Serialize};
use tracing::instrument;
use ts_rs::TS;

use crate::backup::BackupReport;
use crate::context::{CliContext, RpcContext};
use crate::db::model::DatabaseModel;
use crate::db::model::{Database, DatabaseModel};
use crate::prelude::*;
use crate::util::serde::HandlerExtSerde;
use crate::{backup::BackupReport, db::model::Database};

// #[command(subcommands(list, delete, delete_before, create))]
pub fn notification<C: Context>() -> ParentHandler<C> {
Expand Down
5 changes: 2 additions & 3 deletions core/startos/src/service/effects/subcontainer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@ use imbl_value::InternedString;
use models::ImageId;
use tokio::process::Command;

use crate::disk::mount::filesystem::overlayfs::OverlayGuard;
use crate::rpc_continuations::Guid;
use crate::service::effects::prelude::*;
use crate::service::persistent_container::Subcontainer;
use crate::util::Invoke;
use crate::{
disk::mount::filesystem::overlayfs::OverlayGuard, service::persistent_container::Subcontainer,
};

#[cfg(feature = "container-runtime")]
mod sync;
Expand Down
57 changes: 57 additions & 0 deletions core/startos/src/system.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
use std::collections::BTreeSet;
use std::fmt;
use std::sync::Arc;

use chrono::Utc;
use clap::Parser;
use color_eyre::eyre::eyre;
use futures::FutureExt;
use imbl::vector;
use mail_send::mail_builder::MessageBuilder;
use mail_send::SmtpClientBuilder;
use rpc_toolkit::{from_fn_async, Context, Empty, HandlerExt, ParentHandler};
use rustls::crypto::CryptoProvider;
use rustls::RootCertStore;
use rustls_pki_types::CertificateDer;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use tokio::process::Command;
use tokio::sync::broadcast::Receiver;
Expand Down Expand Up @@ -871,6 +877,57 @@ pub async fn clear_system_smtp(ctx: RpcContext) -> Result<(), Error> {
}
Ok(())
}
pub async fn test_system_smtp(
_: RpcContext,
SmtpValue {
server,
port,
from,
login,
password,
}: SmtpValue,
) -> Result<(), Error> {
use rustls_pki_types::pem::PemObject;

let Some(pass_val) = password else {
return Err(Error::new(
eyre!("mail-send requires a password"),
ErrorKind::InvalidRequest,
));
};

let mut root_cert_store = RootCertStore::empty();
let pem = tokio::fs::read("/etc/ssl/certs/ca-certificates.crt").await?;
for cert in CertificateDer::pem_slice_iter(&pem) {
root_cert_store.add_parsable_certificates([cert.with_kind(ErrorKind::OpenSsl)?]);
}

let cfg = Arc::new(
rustls::ClientConfig::builder_with_provider(Arc::new(
rustls::crypto::ring::default_provider(),
))
.with_safe_default_protocol_versions()?
.with_root_certificates(root_cert_store)
.with_no_client_auth(),
);
let client = SmtpClientBuilder::new_with_tls_config(server, port, cfg)
.implicit_tls(false)
.credentials((login.clone().split_once("@").unwrap().0.to_owned(), pass_val));

let message = MessageBuilder::new()
.from((from.clone(), login.clone()))
.to(vec![(from, login)])
.subject("StartOS Test Email")
.text_body("This is a test email sent from your StartOS Server");
client
.connect()
.await
.map_err(|e| Error::new(eyre!("mail-send connection error: {:?}", e), ErrorKind::Unknown))?
.send(message)
.await
.map_err(|e| Error::new(eyre!("mail-send send error: {:?}", e), ErrorKind::Unknown))?;
Ok(())
}

#[tokio::test]
#[ignore]
Expand Down