mirror of
https://github.com/pimalaya/himalaya.git
synced 2026-06-17 21:37:55 +08:00
@@ -114,13 +114,12 @@ fn check_imap(
|
||||
imap_config: crate::config::ImapConfig,
|
||||
) -> BackendCheck {
|
||||
use io_imap::client::ImapClientStd;
|
||||
use pimalaya_stream::{sasl::Sasl, tls::Tls};
|
||||
use pimalaya_stream::sasl::Sasl;
|
||||
|
||||
use crate::imap::id::resolve_auto_id_params;
|
||||
|
||||
let result = (|| -> Result<()> {
|
||||
let mut tls: Tls = imap_config.tls.clone().into();
|
||||
tls.rustls.alpn = vec!["imap".into()];
|
||||
let tls = imap_config.tls.clone().into_tls(imap_config.alpn.clone());
|
||||
let sasl: Option<Sasl> = imap_config.sasl.clone().map(Sasl::try_from).transpose()?;
|
||||
let auto_id = resolve_auto_id_params(&imap_config.id)?;
|
||||
let server = crate::imap::client::parse_imap_server(&imap_config.server)?;
|
||||
@@ -138,13 +137,11 @@ fn check_jmap(
|
||||
jmap_config: crate::config::JmapConfig,
|
||||
) -> BackendCheck {
|
||||
use io_jmap::client::JmapClientStd;
|
||||
use pimalaya_stream::tls::Tls;
|
||||
|
||||
use crate::jmap::client::{jmap_http_auth, parse_server_url};
|
||||
|
||||
let result = (|| -> Result<()> {
|
||||
let mut tls: Tls = jmap_config.tls.clone().into();
|
||||
tls.rustls.alpn = vec!["http/1.1".into()];
|
||||
let tls = jmap_config.tls.clone().into_tls(jmap_config.alpn.clone());
|
||||
let http_auth = jmap_http_auth(jmap_config.auth.clone())?;
|
||||
let url = parse_server_url(&jmap_config.server)?;
|
||||
let mut client = JmapClientStd::connect(&url, &tls, http_auth)?;
|
||||
@@ -183,11 +180,10 @@ fn check_smtp(
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
use io_smtp::{client::SmtpClientStd, rfc5321::types::ehlo_domain::EhloDomain};
|
||||
use pimalaya_stream::{sasl::Sasl, tls::Tls};
|
||||
use pimalaya_stream::sasl::Sasl;
|
||||
|
||||
let result = (|| -> Result<()> {
|
||||
let mut tls: Tls = smtp_config.tls.clone().into();
|
||||
tls.rustls.alpn = vec!["smtp".into()];
|
||||
let tls = smtp_config.tls.clone().into_tls(smtp_config.alpn.clone());
|
||||
let sasl: Option<Sasl> = smtp_config.sasl.clone().map(Sasl::try_from).transpose()?;
|
||||
let domain: EhloDomain<'static> = Ipv4Addr::new(127, 0, 0, 1).into();
|
||||
let server = crate::smtp::client::parse_smtp_server(&smtp_config.server)?;
|
||||
|
||||
+32
-6
@@ -331,6 +331,13 @@ pub struct ImapConfig {
|
||||
#[serde(default)]
|
||||
pub starttls: bool,
|
||||
|
||||
/// ALPN protocol identifiers offered during the TLS handshake.
|
||||
/// Defaults to `["imap"]` (RFC 7595, IANA registry). Set to `[]`
|
||||
/// to skip ALPN negotiation entirely. Only relevant for the
|
||||
/// rustls provider; `native-tls` ignores ALPN.
|
||||
#[serde(default = "io_imap::client::default_alpn")]
|
||||
pub alpn: Vec<String>,
|
||||
|
||||
/// Optional SASL credentials. When omitted, the connection skips
|
||||
/// authentication entirely (no `AUTHENTICATE` command is sent);
|
||||
/// to advertise the ANONYMOUS mechanism explicitly, set
|
||||
@@ -397,6 +404,13 @@ pub struct SmtpConfig {
|
||||
#[serde(default)]
|
||||
pub starttls: bool,
|
||||
|
||||
/// ALPN protocol identifiers offered during the TLS handshake.
|
||||
/// Defaults to `["smtp"]` (RFC 7595, IANA registry). Set to `[]`
|
||||
/// to skip ALPN negotiation entirely. Only relevant for the
|
||||
/// rustls provider; `native-tls` ignores ALPN.
|
||||
#[serde(default = "io_smtp::client::default_alpn")]
|
||||
pub alpn: Vec<String>,
|
||||
|
||||
/// Optional SASL credentials. See [`ImapConfig::sasl`].
|
||||
pub sasl: Option<SaslConfig>,
|
||||
}
|
||||
@@ -434,21 +448,26 @@ pub enum RustlsCryptoConfig {
|
||||
Ring,
|
||||
}
|
||||
|
||||
impl From<TlsConfig> for Tls {
|
||||
fn from(config: TlsConfig) -> Self {
|
||||
impl TlsConfig {
|
||||
/// Builds the runtime [`Tls`] handle the connect helpers expect.
|
||||
/// `alpn` is the protocol-level ALPN list (e.g. `["imap"]`,
|
||||
/// `["smtp"]`, `["http/1.1"]`); pass an empty vec to skip ALPN.
|
||||
/// The TOML schema never exposes `tls.rustls.alpn` directly: the
|
||||
/// per-protocol `*.alpn` field is folded in here.
|
||||
pub fn into_tls(self, alpn: Vec<String>) -> Tls {
|
||||
Tls {
|
||||
provider: config.provider.map(|config| match config {
|
||||
provider: self.provider.map(|p| match p {
|
||||
TlsProviderConfig::Rustls => TlsProvider::Rustls,
|
||||
TlsProviderConfig::NativeTls => TlsProvider::NativeTls,
|
||||
}),
|
||||
rustls: Rustls {
|
||||
crypto: config.rustls.crypto.map(|config| match config {
|
||||
crypto: self.rustls.crypto.map(|c| match c {
|
||||
RustlsCryptoConfig::Aws => RustlsCrypto::Aws,
|
||||
RustlsCryptoConfig::Ring => RustlsCrypto::Ring,
|
||||
}),
|
||||
alpn: Vec::new(),
|
||||
alpn,
|
||||
},
|
||||
cert: config.cert,
|
||||
cert: self.cert,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -590,6 +609,13 @@ pub struct JmapConfig {
|
||||
#[serde(default)]
|
||||
pub tls: TlsConfig,
|
||||
|
||||
/// ALPN protocol identifiers offered during the TLS handshake.
|
||||
/// Defaults to `["http/1.1"]` (JMAP rides on HTTP/1.1). Set to
|
||||
/// `[]` to skip ALPN negotiation entirely. Only relevant for the
|
||||
/// rustls provider; `native-tls` ignores ALPN.
|
||||
#[serde(default = "io_jmap::client::default_alpn")]
|
||||
pub alpn: Vec<String>,
|
||||
|
||||
/// Authentication configuration.
|
||||
pub auth: JmapAuthConfig,
|
||||
|
||||
|
||||
+2
-3
@@ -30,7 +30,7 @@ use std::{
|
||||
use anyhow::{Result, anyhow};
|
||||
use io_imap::client::ImapClientStd as Inner;
|
||||
use pimalaya_config::toml::TomlConfig;
|
||||
use pimalaya_stream::{sasl::Sasl, tls::Tls};
|
||||
use pimalaya_stream::sasl::Sasl;
|
||||
use url::Url;
|
||||
|
||||
use crate::{
|
||||
@@ -48,8 +48,7 @@ impl ImapClient {
|
||||
/// discarded; IMAP-specific subcommands that need it should call
|
||||
/// [`Inner::capability`] explicitly.
|
||||
pub fn new(config: ImapConfig) -> Result<Self> {
|
||||
let mut tls: Tls = config.tls.into();
|
||||
tls.rustls.alpn = vec!["imap".into()];
|
||||
let tls = config.tls.into_tls(config.alpn);
|
||||
let sasl: Option<Sasl> = config.sasl.map(Sasl::try_from).transpose()?;
|
||||
let auto_id = resolve_auto_id_params(&config.id)?;
|
||||
let server = parse_imap_server(&config.server)?;
|
||||
|
||||
+1
-3
@@ -31,7 +31,6 @@ use anyhow::{Result, anyhow};
|
||||
use base64::{Engine, prelude::BASE64_STANDARD};
|
||||
use io_jmap::client::JmapClientStd as Inner;
|
||||
use pimalaya_config::toml::TomlConfig;
|
||||
use pimalaya_stream::tls::Tls;
|
||||
use secrecy::{ExposeSecret, SecretString};
|
||||
use url::Url;
|
||||
|
||||
@@ -54,8 +53,7 @@ impl JmapClient {
|
||||
/// Establishes the JMAP session (TLS, `/.well-known/jmap`
|
||||
/// discovery).
|
||||
pub fn new(config: JmapConfig) -> Result<Self> {
|
||||
let mut tls: Tls = config.tls.clone().into();
|
||||
tls.rustls.alpn = vec!["http/1.1".into()];
|
||||
let tls = config.tls.clone().into_tls(config.alpn.clone());
|
||||
|
||||
let http_auth = jmap_http_auth(config.auth.clone())?;
|
||||
let url = parse_server_url(&config.server)?;
|
||||
|
||||
@@ -22,7 +22,6 @@ use io_jmap::{
|
||||
rfc8621::{capabilities::MAIL, email::EmailProperty},
|
||||
};
|
||||
use pimalaya_cli::printer::{Message, Printer};
|
||||
use pimalaya_stream::tls::Tls;
|
||||
use url::Url;
|
||||
|
||||
use crate::jmap::client::{JmapClient, jmap_http_auth};
|
||||
@@ -68,8 +67,11 @@ impl JmapEmailExportCommand {
|
||||
let data = if same_authority(&api_url, &download_url) {
|
||||
client.blob_download(&download_url)?
|
||||
} else {
|
||||
let mut tls: Tls = client.config.tls.clone().into();
|
||||
tls.rustls.alpn = vec!["http/1.1".into()];
|
||||
let tls = client
|
||||
.config
|
||||
.tls
|
||||
.clone()
|
||||
.into_tls(client.config.alpn.clone());
|
||||
let http_auth = jmap_http_auth(client.config.auth.clone())?;
|
||||
let mut download_client = JmapClientStd::connect(&download_url, &tls, http_auth)?;
|
||||
download_client.blob_download(&download_url)?
|
||||
|
||||
@@ -24,7 +24,6 @@ use io_jmap::{
|
||||
rfc8621::{capabilities::MAIL, email::EmailImport},
|
||||
};
|
||||
use pimalaya_cli::printer::{Message, Printer};
|
||||
use pimalaya_stream::tls::Tls;
|
||||
use url::Url;
|
||||
|
||||
use crate::{
|
||||
@@ -84,8 +83,11 @@ impl JmapEmailImportCommand {
|
||||
.blob_upload(&upload_url, "message/rfc822", data)?
|
||||
.blob_id
|
||||
} else {
|
||||
let mut tls: Tls = client.config.tls.clone().into();
|
||||
tls.rustls.alpn = vec!["http/1.1".into()];
|
||||
let tls = client
|
||||
.config
|
||||
.tls
|
||||
.clone()
|
||||
.into_tls(client.config.alpn.clone());
|
||||
let http_auth = jmap_http_auth(client.config.auth.clone())?;
|
||||
let mut upload_client = JmapClientStd::connect(&upload_url, &tls, http_auth)?;
|
||||
upload_client
|
||||
|
||||
+5
-11
@@ -60,12 +60,9 @@ impl EmailClient {
|
||||
#[cfg(feature = "jmap")]
|
||||
if backend.allows_jmap() {
|
||||
if let Some(jmap_config) = account_config.jmap.take() {
|
||||
use pimalaya_stream::tls::Tls;
|
||||
|
||||
use crate::jmap::client::{jmap_http_auth, parse_server_url};
|
||||
|
||||
let mut tls: Tls = jmap_config.tls.clone().into();
|
||||
tls.rustls.alpn = vec!["http/1.1".into()];
|
||||
let tls = jmap_config.tls.clone().into_tls(jmap_config.alpn.clone());
|
||||
let http_auth = jmap_http_auth(jmap_config.auth.clone())?;
|
||||
let url = parse_server_url(&jmap_config.server)?;
|
||||
inner = inner.connect_jmap(&url, &tls, http_auth)?;
|
||||
@@ -76,12 +73,11 @@ impl EmailClient {
|
||||
if backend.allows_imap() {
|
||||
if let Some(imap_config) = account_config.imap.take() {
|
||||
use io_email::imap::client::ImapClientStd;
|
||||
use pimalaya_stream::{sasl::Sasl, tls::Tls};
|
||||
use pimalaya_stream::sasl::Sasl;
|
||||
|
||||
use crate::imap::id::resolve_auto_id_params;
|
||||
|
||||
let mut tls: Tls = imap_config.tls.into();
|
||||
tls.rustls.alpn = vec!["imap".into()];
|
||||
let tls = imap_config.tls.into_tls(imap_config.alpn);
|
||||
let sasl: Option<Sasl> = imap_config.sasl.map(Sasl::try_from).transpose()?;
|
||||
let auto_id = resolve_auto_id_params(&imap_config.id)?;
|
||||
let server = crate::imap::client::parse_imap_server(&imap_config.server)?;
|
||||
@@ -98,7 +94,6 @@ impl EmailClient {
|
||||
|
||||
let client = MaildirClient::new(maildir_config.root.to_string_lossy().into_owned());
|
||||
inner = inner.with_maildir(client);
|
||||
configured = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,10 +123,9 @@ impl EmailClient {
|
||||
|
||||
use io_email::smtp::client::SmtpClientStd;
|
||||
use io_smtp::rfc5321::types::ehlo_domain::EhloDomain;
|
||||
use pimalaya_stream::{sasl::Sasl, tls::Tls};
|
||||
use pimalaya_stream::sasl::Sasl;
|
||||
|
||||
let mut tls: Tls = smtp_config.tls.into();
|
||||
tls.rustls.alpn = vec!["smtp".into()];
|
||||
let tls = smtp_config.tls.into_tls(smtp_config.alpn);
|
||||
let sasl: Option<Sasl> = smtp_config.sasl.map(Sasl::try_from).transpose()?;
|
||||
let domain: EhloDomain<'static> = Ipv4Addr::new(127, 0, 0, 1).into();
|
||||
let server = crate::smtp::client::parse_smtp_server(&smtp_config.server)?;
|
||||
|
||||
+2
-3
@@ -32,7 +32,7 @@ use std::{
|
||||
use anyhow::{Result, anyhow};
|
||||
use io_smtp::{client::SmtpClientStd as Inner, rfc5321::types::ehlo_domain::EhloDomain};
|
||||
use pimalaya_config::toml::TomlConfig;
|
||||
use pimalaya_stream::{sasl::Sasl, tls::Tls};
|
||||
use pimalaya_stream::sasl::Sasl;
|
||||
use url::Url;
|
||||
|
||||
use crate::{account::context::Account, cli::load_or_wizard, config::SmtpConfig};
|
||||
@@ -45,8 +45,7 @@ impl SmtpClient {
|
||||
/// Opens the SMTP connection (TCP/TLS/STARTTLS, greeting, EHLO,
|
||||
/// SASL).
|
||||
pub fn new(config: SmtpConfig) -> Result<Self> {
|
||||
let mut tls: Tls = config.tls.into();
|
||||
tls.rustls.alpn = vec!["smtp".into()];
|
||||
let tls = config.tls.into_tls(config.alpn);
|
||||
let sasl: Option<Sasl> = config.sasl.map(Sasl::try_from).transpose()?;
|
||||
let domain: EhloDomain<'static> = Ipv4Addr::new(127, 0, 0, 1).into();
|
||||
let server = parse_smtp_server(&config.server)?;
|
||||
|
||||
@@ -48,6 +48,7 @@ pub fn imap_to_config(w: WizardImapConfig) -> Result<ImapConfig> {
|
||||
server,
|
||||
tls: Default::default(),
|
||||
starttls,
|
||||
alpn: io_imap::client::default_alpn(),
|
||||
sasl,
|
||||
id: Default::default(),
|
||||
})
|
||||
@@ -66,6 +67,7 @@ pub fn smtp_to_config(w: WizardSmtpConfig) -> Result<SmtpConfig> {
|
||||
server,
|
||||
tls: Default::default(),
|
||||
starttls,
|
||||
alpn: io_smtp::client::default_alpn(),
|
||||
sasl,
|
||||
})
|
||||
}
|
||||
@@ -84,6 +86,7 @@ pub fn jmap_to_config(w: WizardJmapConfig) -> Result<JmapConfig> {
|
||||
Ok(JmapConfig {
|
||||
server: w.server,
|
||||
tls: Default::default(),
|
||||
alpn: io_jmap::client::default_alpn(),
|
||||
auth,
|
||||
identity_id: None,
|
||||
drafts_mailbox_id: None,
|
||||
|
||||
Reference in New Issue
Block a user