mirror of
https://github.com/pimalaya/himalaya.git
synced 2026-06-15 11:27:53 +08:00
Generated
+9
-9
@@ -1078,7 +1078,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "io-email"
|
||||
version = "0.0.1"
|
||||
source = "git+https://github.com/pimalaya/io-email#5d01da7acb98d8394077d40780f1cded639f4574"
|
||||
source = "git+https://github.com/pimalaya/io-email#050738cbaf9e177683c7e4eeeb8b2ef145c4abe2"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"chumsky",
|
||||
@@ -1103,7 +1103,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "io-http"
|
||||
version = "0.0.3"
|
||||
source = "git+https://github.com/pimalaya/io-http#73b264b85209d86de48afed25957ab582b54c272"
|
||||
source = "git+https://github.com/pimalaya/io-http#23f3668558059c2db3603b1afdda5ce0f840e46a"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64",
|
||||
@@ -1119,7 +1119,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "io-imap"
|
||||
version = "0.0.1"
|
||||
source = "git+https://github.com/pimalaya/io-imap#518da423e551684fa8202a9cc4fede99f1be3f23"
|
||||
source = "git+https://github.com/pimalaya/io-imap#5c915ae5536e5e5ac48f3284c1827111a71939f7"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64",
|
||||
@@ -1134,7 +1134,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "io-jmap"
|
||||
version = "0.0.1"
|
||||
source = "git+https://github.com/pimalaya/io-jmap#2463ecb104d0ff24b8c3ba2f4eaa09562ce5a1cd"
|
||||
source = "git+https://github.com/pimalaya/io-jmap#18103bdbf883798b48566f6d45e4dfed8458d0e6"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"io-http",
|
||||
@@ -1170,7 +1170,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "io-smtp"
|
||||
version = "0.0.1"
|
||||
source = "git+https://github.com/pimalaya/io-smtp#3b8cf0d806c23339a46a540e159de3d4cd9898f3"
|
||||
source = "git+https://github.com/pimalaya/io-smtp#8ade022516b83358d66772b74bd42216763b5ec3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64",
|
||||
@@ -1664,7 +1664,7 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
|
||||
[[package]]
|
||||
name = "pimalaya-cli"
|
||||
version = "0.0.1"
|
||||
source = "git+https://github.com/pimalaya/cli#313c2e999ea9157fa42c84a6ae867451d8308114"
|
||||
source = "git+https://github.com/pimalaya/cli#64cd78d702ed9251021f4ed8f549ac262b0e6985"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
@@ -1704,7 +1704,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "pimalaya-stream"
|
||||
version = "0.0.1"
|
||||
source = "git+https://github.com/pimalaya/stream#6449136364c9ef81248e3b4ab6491dd154293481"
|
||||
source = "git+https://github.com/pimalaya/stream#152911be92647ae47c2052c1bf1270f02eefbdd1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"log",
|
||||
@@ -2484,9 +2484,9 @@ checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.13.2"
|
||||
version = "1.13.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c"
|
||||
checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
|
||||
@@ -165,6 +165,11 @@ imap.server = "example.com"
|
||||
# Enable STARTTLS (only valid when the server resolves to `imap://`).
|
||||
#imap.starttls = false
|
||||
|
||||
# ALPN protocol identifiers offered during the TLS handshake (rustls only;
|
||||
# native-tls ignores it). Defaults to ["imap"]; set to [] to skip ALPN.
|
||||
#imap.alpn = ["imap"]
|
||||
#imap.alpn = []
|
||||
|
||||
# Pick exactly one SASL mechanism among `anonymous`, `login`, `plain`,
|
||||
# `oauthbearer`, `xoauth2`, `scram-sha-256`. Omit the whole `imap.sasl` table
|
||||
# to skip authentication entirely (no `AUTHENTICATE` command sent).
|
||||
@@ -231,6 +236,11 @@ imap.sasl.plain.passwd.raw = "***"
|
||||
#jmap.tls.rustls.crypto = "ring"
|
||||
#jmap.tls.cert = "/path/to/custom/cert.pem"
|
||||
|
||||
# ALPN protocol identifiers offered during the TLS handshake. Defaults to
|
||||
# ["http/1.1"] (JMAP rides on HTTP/1.1); set to [] to skip ALPN.
|
||||
#jmap.alpn = ["http/1.1"]
|
||||
#jmap.alpn = []
|
||||
|
||||
# Pick exactly one of `header`, `bearer`, `basic`.
|
||||
|
||||
# Raw `Authorization` header value, used verbatim.
|
||||
@@ -289,6 +299,11 @@ smtp.server = "example.com"
|
||||
# Enable STARTTLS (only valid when the server resolves to `smtp://`).
|
||||
#smtp.starttls = false
|
||||
|
||||
# ALPN protocol identifiers offered during the TLS handshake. Defaults to
|
||||
# ["smtp"]; set to [] to skip ALPN.
|
||||
#smtp.alpn = ["smtp"]
|
||||
#smtp.alpn = []
|
||||
|
||||
# Pick exactly one SASL mechanism among `anonymous`, `login`, `plain`,
|
||||
# `oauthbearer`, `xoauth2`, `scram-sha-256`. Omit the whole `smtp.sasl` table
|
||||
# to skip authentication entirely.
|
||||
|
||||
@@ -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