You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-07-29 22:01:14 +03:00
Remove dependency on mas-email and lettre in mas-config
This commit is contained in:
3
Cargo.lock
generated
3
Cargo.lock
generated
@ -2552,7 +2552,6 @@ dependencies = [
|
||||
"quoted_printable",
|
||||
"rustls",
|
||||
"rustls-pemfile",
|
||||
"serde",
|
||||
"socket2",
|
||||
"tokio",
|
||||
"tokio-rustls",
|
||||
@ -2741,8 +2740,6 @@ dependencies = [
|
||||
"chrono",
|
||||
"figment",
|
||||
"indoc",
|
||||
"lettre",
|
||||
"mas-email",
|
||||
"mas-iana",
|
||||
"mas-jose",
|
||||
"mas-keystore",
|
||||
|
@ -12,17 +12,17 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use anyhow::Context;
|
||||
use clap::Parser;
|
||||
use hyper::{Response, Uri};
|
||||
use mas_config::PolicyConfig;
|
||||
use mas_handlers::HttpClientFactory;
|
||||
use mas_http::HttpServiceExt;
|
||||
use mas_policy::PolicyFactory;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
use tower::{Service, ServiceExt};
|
||||
use tracing::info;
|
||||
|
||||
use crate::util::policy_factory_from_config;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
pub(super) struct Options {
|
||||
#[command(subcommand)]
|
||||
@ -124,19 +124,7 @@ impl Options {
|
||||
SC::Policy => {
|
||||
let config: PolicyConfig = root.load_config()?;
|
||||
info!("Loading and compiling the policy module");
|
||||
let policy_file = tokio::fs::File::open(&config.wasm_module)
|
||||
.await
|
||||
.context("failed to open OPA WASM policy file")?;
|
||||
|
||||
let policy_factory = PolicyFactory::load(
|
||||
policy_file,
|
||||
config.data.clone().unwrap_or_default(),
|
||||
config.register_entrypoint.clone(),
|
||||
config.client_registration_entrypoint.clone(),
|
||||
config.authorization_grant_entrypoint.clone(),
|
||||
)
|
||||
.await
|
||||
.context("failed to load the policy")?;
|
||||
let policy_factory = policy_factory_from_config(&config).await?;
|
||||
|
||||
let _instance = policy_factory.instantiate().await?;
|
||||
Ok(())
|
||||
|
@ -19,10 +19,8 @@ use clap::Parser;
|
||||
use futures_util::stream::{StreamExt, TryStreamExt};
|
||||
use itertools::Itertools;
|
||||
use mas_config::RootConfig;
|
||||
use mas_email::Mailer;
|
||||
use mas_handlers::{AppState, HttpClientFactory, MatrixHomeserver};
|
||||
use mas_listener::{server::Server, shutdown::ShutdownStream};
|
||||
use mas_policy::PolicyFactory;
|
||||
use mas_router::UrlBuilder;
|
||||
use mas_storage::MIGRATOR;
|
||||
use mas_tasks::TaskQueue;
|
||||
@ -30,7 +28,7 @@ use mas_templates::Templates;
|
||||
use tokio::signal::unix::SignalKind;
|
||||
use tracing::{error, info, log::warn};
|
||||
|
||||
use crate::util::password_manager_from_config;
|
||||
use crate::util::{mailer_from_config, password_manager_from_config, policy_factory_from_config};
|
||||
|
||||
#[derive(Parser, Debug, Default)]
|
||||
pub(super) struct Options {
|
||||
@ -106,10 +104,6 @@ impl Options {
|
||||
pub async fn run(&self, root: &super::Options) -> anyhow::Result<()> {
|
||||
let config: RootConfig = root.load_config()?;
|
||||
|
||||
// Connect to the mail server
|
||||
let mail_transport = config.email.transport.to_transport().await?;
|
||||
mail_transport.test_connection().await?;
|
||||
|
||||
// Connect to the database
|
||||
let pool = config.database.connect().await?;
|
||||
|
||||
@ -126,6 +120,7 @@ impl Options {
|
||||
queue.recuring(Duration::from_secs(15), mas_tasks::cleanup_expired(&pool));
|
||||
queue.start();
|
||||
|
||||
// TODO: task queue, key store, encrypter, url builder, http client
|
||||
// Initialize the key store
|
||||
let key_store = config
|
||||
.secrets
|
||||
@ -137,19 +132,7 @@ impl Options {
|
||||
|
||||
// Load and compile the WASM policies (and fallback to the default embedded one)
|
||||
info!("Loading and compiling the policy module");
|
||||
let policy_file = tokio::fs::File::open(&config.policy.wasm_module)
|
||||
.await
|
||||
.context("failed to open OPA WASM policy file")?;
|
||||
|
||||
let policy_factory = PolicyFactory::load(
|
||||
policy_file,
|
||||
config.policy.data.clone().unwrap_or_default(),
|
||||
config.policy.register_entrypoint.clone(),
|
||||
config.policy.client_registration_entrypoint.clone(),
|
||||
config.policy.authorization_grant_entrypoint.clone(),
|
||||
)
|
||||
.await
|
||||
.context("failed to load the policy")?;
|
||||
let policy_factory = policy_factory_from_config(&config.policy).await?;
|
||||
let policy_factory = Arc::new(policy_factory);
|
||||
|
||||
let url_builder = UrlBuilder::new(config.http.public_base.clone());
|
||||
@ -159,12 +142,8 @@ impl Options {
|
||||
.await
|
||||
.context("could not load templates")?;
|
||||
|
||||
let mailer = Mailer::new(
|
||||
&templates,
|
||||
&mail_transport,
|
||||
&config.email.from,
|
||||
&config.email.reply_to,
|
||||
);
|
||||
let mailer = mailer_from_config(&config.email, &templates).await?;
|
||||
mailer.test_connection().await?;
|
||||
|
||||
let homeserver = MatrixHomeserver::new(config.matrix.homeserver.clone());
|
||||
|
||||
|
@ -12,8 +12,12 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use mas_config::PasswordsConfig;
|
||||
use anyhow::Context;
|
||||
use mas_config::{EmailConfig, EmailSmtpMode, EmailTransportConfig, PasswordsConfig, PolicyConfig};
|
||||
use mas_email::{MailTransport, Mailer};
|
||||
use mas_handlers::passwords::PasswordManager;
|
||||
use mas_policy::PolicyFactory;
|
||||
use mas_templates::Templates;
|
||||
|
||||
pub async fn password_manager_from_config(
|
||||
config: &PasswordsConfig,
|
||||
@ -35,3 +39,55 @@ pub async fn password_manager_from_config(
|
||||
|
||||
PasswordManager::new(schemes)
|
||||
}
|
||||
|
||||
pub async fn mailer_from_config(
|
||||
config: &EmailConfig,
|
||||
templates: &Templates,
|
||||
) -> Result<Mailer, anyhow::Error> {
|
||||
let from = config.from.parse()?;
|
||||
let reply_to = config.reply_to.parse()?;
|
||||
let transport = match &config.transport {
|
||||
EmailTransportConfig::Blackhole => MailTransport::blackhole(),
|
||||
EmailTransportConfig::Smtp {
|
||||
mode,
|
||||
hostname,
|
||||
credentials,
|
||||
port,
|
||||
} => {
|
||||
let credentials = credentials
|
||||
.clone()
|
||||
.map(|c| mas_email::SmtpCredentials::new(c.username, c.password));
|
||||
|
||||
let mode = match mode {
|
||||
EmailSmtpMode::Plain => mas_email::SmtpMode::Plain,
|
||||
EmailSmtpMode::StartTls => mas_email::SmtpMode::StartTls,
|
||||
EmailSmtpMode::Tls => mas_email::SmtpMode::Tls,
|
||||
};
|
||||
|
||||
MailTransport::smtp(mode, hostname, port.as_ref().copied(), credentials)
|
||||
.context("failed to build SMTP transport")?
|
||||
}
|
||||
EmailTransportConfig::Sendmail { command } => MailTransport::sendmail(command),
|
||||
EmailTransportConfig::AwsSes => MailTransport::aws_ses().await?,
|
||||
};
|
||||
|
||||
Ok(Mailer::new(templates.clone(), transport, from, reply_to))
|
||||
}
|
||||
|
||||
pub async fn policy_factory_from_config(
|
||||
config: &PolicyConfig,
|
||||
) -> Result<PolicyFactory, anyhow::Error> {
|
||||
let policy_file = tokio::fs::File::open(&config.wasm_module)
|
||||
.await
|
||||
.context("failed to open OPA WASM policy file")?;
|
||||
|
||||
PolicyFactory::load(
|
||||
policy_file,
|
||||
config.data.clone().unwrap_or_default(),
|
||||
config.register_entrypoint.clone(),
|
||||
config.client_registration_entrypoint.clone(),
|
||||
config.authorization_grant_entrypoint.clone(),
|
||||
)
|
||||
.await
|
||||
.context("failed to load the policy")
|
||||
}
|
||||
|
@ -24,7 +24,6 @@ serde = { version = "1.0.150", features = ["derive"] }
|
||||
serde_with = { version = "2.1.0", features = ["hex", "chrono"] }
|
||||
serde_json = "1.0.89"
|
||||
sqlx = { version = "0.6.2", features = ["runtime-tokio-rustls", "postgres"] }
|
||||
lettre = { version = "0.10.1", default-features = false, features = ["serde", "builder"] }
|
||||
|
||||
pem-rfc7468 = "0.6.0"
|
||||
rustls-pemfile = "1.0.1"
|
||||
@ -36,11 +35,8 @@ indoc = "1.0.7"
|
||||
mas-jose = { path = "../jose" }
|
||||
mas-keystore = { path = "../keystore" }
|
||||
mas-iana = { path = "../iana" }
|
||||
mas-email = { path = "../email" }
|
||||
|
||||
[features]
|
||||
native-roots = ["mas-email/native-roots"]
|
||||
webpki-roots = ["mas-email/webpki-roots"]
|
||||
docker = []
|
||||
|
||||
[[bin]]
|
||||
|
@ -14,10 +14,7 @@
|
||||
|
||||
use std::num::NonZeroU16;
|
||||
|
||||
use anyhow::Context;
|
||||
use async_trait::async_trait;
|
||||
use lettre::{message::Mailbox, Address};
|
||||
use mas_email::MailTransport;
|
||||
use rand::Rng;
|
||||
use schemars::{
|
||||
gen::SchemaGenerator,
|
||||
@ -59,22 +56,14 @@ pub struct Credentials {
|
||||
pub enum EmailSmtpMode {
|
||||
/// Plain text
|
||||
Plain,
|
||||
|
||||
/// StartTLS (starts as plain text then upgrade to TLS)
|
||||
StartTls,
|
||||
|
||||
/// TLS
|
||||
Tls,
|
||||
}
|
||||
|
||||
impl From<&EmailSmtpMode> for mas_email::SmtpMode {
|
||||
fn from(value: &EmailSmtpMode) -> Self {
|
||||
match value {
|
||||
EmailSmtpMode::Plain => Self::Plain,
|
||||
EmailSmtpMode::StartTls => Self::StartTls,
|
||||
EmailSmtpMode::Tls => Self::Tls,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// What backend should be used when sending emails
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(tag = "transport", rename_all = "snake_case")]
|
||||
@ -118,9 +107,8 @@ impl Default for EmailTransportConfig {
|
||||
}
|
||||
}
|
||||
|
||||
fn default_email() -> Mailbox {
|
||||
let address = Address::new("root", "localhost").unwrap();
|
||||
Mailbox::new(Some("Authentication Service".to_owned()), address)
|
||||
fn default_email() -> String {
|
||||
r#""Authentication Service" <root@localhost>"#.to_owned()
|
||||
}
|
||||
|
||||
fn default_sendmail_command() -> String {
|
||||
@ -133,12 +121,12 @@ pub struct EmailConfig {
|
||||
/// Email address to use as From when sending emails
|
||||
#[serde(default = "default_email")]
|
||||
#[schemars(schema_with = "mailbox_schema")]
|
||||
pub from: Mailbox,
|
||||
pub from: String,
|
||||
|
||||
/// Email address to use as Reply-To when sending emails
|
||||
#[serde(default = "default_email")]
|
||||
#[schemars(schema_with = "mailbox_schema")]
|
||||
pub reply_to: Mailbox,
|
||||
pub reply_to: String,
|
||||
|
||||
/// What backend should be used when sending emails
|
||||
#[serde(flatten, default)]
|
||||
@ -172,30 +160,3 @@ impl ConfigurationSection<'_> for EmailConfig {
|
||||
Self::default()
|
||||
}
|
||||
}
|
||||
|
||||
impl EmailTransportConfig {
|
||||
/// Create a [`lettre::Transport`] out of this config
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the transport could not be created
|
||||
pub async fn to_transport(&self) -> Result<MailTransport, anyhow::Error> {
|
||||
match self {
|
||||
Self::Blackhole => Ok(MailTransport::blackhole()),
|
||||
Self::Smtp {
|
||||
mode,
|
||||
hostname,
|
||||
credentials,
|
||||
port,
|
||||
} => {
|
||||
let credentials = credentials
|
||||
.clone()
|
||||
.map(|c| mas_email::SmtpCredentials::new(c.username, c.password));
|
||||
MailTransport::smtp(mode.into(), hostname, port.as_ref().copied(), credentials)
|
||||
.context("failed to build SMTP transport")
|
||||
}
|
||||
EmailTransportConfig::Sendmail { command } => Ok(MailTransport::sendmail(command)),
|
||||
EmailTransportConfig::AwsSes => Ok(MailTransport::aws_ses().await?),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,16 +35,16 @@ impl Mailer {
|
||||
/// Constructs a new [`Mailer`]
|
||||
#[must_use]
|
||||
pub fn new(
|
||||
templates: &Templates,
|
||||
transport: &MailTransport,
|
||||
from: &Mailbox,
|
||||
reply_to: &Mailbox,
|
||||
templates: Templates,
|
||||
transport: MailTransport,
|
||||
from: Mailbox,
|
||||
reply_to: Mailbox,
|
||||
) -> Self {
|
||||
Self {
|
||||
templates: templates.clone(),
|
||||
transport: transport.clone(),
|
||||
from: from.clone(),
|
||||
reply_to: reply_to.clone(),
|
||||
templates,
|
||||
transport,
|
||||
from,
|
||||
reply_to,
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,4 +110,13 @@ impl Mailer {
|
||||
self.transport.send(message).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Test the connetion to the mail server
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the connection failed
|
||||
pub async fn test_connection(&self) -> Result<(), anyhow::Error> {
|
||||
self.transport.test_connection().await
|
||||
}
|
||||
}
|
||||
|
@ -372,8 +372,8 @@ async fn test_state(pool: PgPool) -> Result<AppState, anyhow::Error> {
|
||||
let password_manager = PasswordManager::new([(1, Hasher::argon2id(None))])?;
|
||||
|
||||
let transport = MailTransport::blackhole();
|
||||
let mailbox = "server@example.com".parse()?;
|
||||
let mailer = Mailer::new(&templates, &transport, &mailbox, &mailbox);
|
||||
let mailbox: lettre::message::Mailbox = "server@example.com".parse()?;
|
||||
let mailer = Mailer::new(templates.clone(), transport, mailbox.clone(), mailbox);
|
||||
|
||||
let homeserver = MatrixHomeserver::new("example.com".to_owned());
|
||||
|
||||
|
Reference in New Issue
Block a user