diff --git a/Cargo.lock b/Cargo.lock index bb00aaeb..0321403f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2884,6 +2884,7 @@ dependencies = [ "mime", "nlp", "p256", + "pkcs8", "rand", "rasn", "rasn-cms", diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index e17e4f9b..51e86a06 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -185,8 +185,8 @@ async fn oauth(url: &str) -> Credentials { #[derive(Deserialize)] #[serde(untagged)] pub enum Response { - Data { data: T }, Error(ManagementApiError), + Data { data: T }, } #[derive(Deserialize)] @@ -283,11 +283,11 @@ impl Client { } } - match serde_json::from_slice::>( - &response.bytes().await.unwrap_result("fetch bytes"), - ) - .unwrap_result("deserialize response") - { + let bytes = response.bytes().await.unwrap_result("fetch bytes"); + match serde_json::from_slice::>(&bytes).unwrap_result(&format!( + "deserialize response {}", + String::from_utf8_lossy(bytes.as_ref()) + )) { Response::Data { data } => Some(data), Response::Error(error) => { eprintln!("Request failed: {error})"); diff --git a/crates/cli/src/modules/domain.rs b/crates/cli/src/modules/domain.rs index 7152f27d..4e4119eb 100644 --- a/crates/cli/src/modules/domain.rs +++ b/crates/cli/src/modules/domain.rs @@ -27,6 +27,8 @@ use prettytable::{Attr, Cell, Row, Table}; use reqwest::Method; use serde_json::Value; +use crate::modules::List; + use super::cli::{Client, DomainCommands}; impl DomainCommands { @@ -70,15 +72,15 @@ impl DomainCommands { }; let domains = client - .http_request::, String>(Method::GET, query.as_ref(), None) + .http_request::, String>(Method::GET, query.as_ref(), None) .await; - if !domains.is_empty() { + if !domains.items.is_empty() { let mut table = Table::new(); table.add_row(Row::new(vec![ Cell::new("Domain Name").with_style(Attr::Bold) ])); - for domain in &domains { + for domain in &domains.items { table.add_row(Row::new(vec![Cell::new(domain)])); } @@ -89,8 +91,8 @@ impl DomainCommands { eprintln!( "\n\n{} domain{} found.\n", - domains.len(), - if domains.len() == 1 { "" } else { "s" } + domains.total, + if domains.total == 1 { "" } else { "s" } ); } } diff --git a/crates/common/src/config/tracers.rs b/crates/common/src/config/tracers.rs index 05787bbe..fa390dcf 100644 --- a/crates/common/src/config/tracers.rs +++ b/crates/common/src/config/tracers.rs @@ -93,8 +93,8 @@ impl Tracers { level, appender, ansi: config - .property_or_default(("tracer", id, "ansi"), "true") - .unwrap_or(true), + .property_or_default(("tracer", id, "ansi"), "false") + .unwrap_or(false), }); } } diff --git a/crates/common/src/manager/webadmin.rs b/crates/common/src/manager/webadmin.rs index 1ccbab31..ac813761 100644 --- a/crates/common/src/manager/webadmin.rs +++ b/crates/common/src/manager/webadmin.rs @@ -103,6 +103,7 @@ impl WebAdminManager { { "html" => "text/html", "css" => "text/css", + "wasm" => "application/wasm", "js" => "application/javascript", "json" => "application/json", "png" => "image/png", diff --git a/crates/imap/src/op/idle.rs b/crates/imap/src/op/idle.rs index a0da4b71..80c46a58 100644 --- a/crates/imap/src/op/idle.rs +++ b/crates/imap/src/op/idle.rs @@ -80,7 +80,7 @@ impl Session { // Send continuation response self.write_bytes(b"+ Idling, send 'DONE' to stop.\r\n".to_vec()) .await?; - tracing::debug!(parent: &self.span, event = "stat", context = "idle", "Starting IDLE."); + tracing::debug!(parent: &self.span, event = "start", context = "idle", "Starting IDLE."); let mut buf = vec![0; 1024]; loop { tokio::select! { diff --git a/crates/jmap/Cargo.toml b/crates/jmap/Cargo.toml index 3f36e0f7..4276f9ea 100644 --- a/crates/jmap/Cargo.toml +++ b/crates/jmap/Cargo.toml @@ -47,6 +47,7 @@ aes = "0.8.3" cbc = { version = "0.1.2", features = ["alloc"] } sequoia-openpgp = { version = "1.16", default-features = false, features = ["crypto-rust", "allow-experimental-crypto", "allow-variable-time-crypto"] } rand = "0.8.5" +pkcs8 = { version = "0.10.2", features = ["alloc", "std"] } rasn = "0.10" rasn-cms = "0.10" rasn-pkix = "0.10" diff --git a/crates/jmap/src/api/management/dkim.rs b/crates/jmap/src/api/management/dkim.rs index 1b1680d3..9f55fe9c 100644 --- a/crates/jmap/src/api/management/dkim.rs +++ b/crates/jmap/src/api/management/dkim.rs @@ -32,6 +32,12 @@ use mail_auth::{ }; use mail_builder::encoders::base64::base64_encode; use mail_parser::DateTime; +use pkcs8::{ + der::{asn1::BitString, Encode}, + spki::{AlgorithmIdentifier, SubjectPublicKeyInfoOwned}, + Document, +}; +use rsa::pkcs1::DecodeRsaPublicKey; use serde::{Deserialize, Serialize}; use serde_json::json; use store::write::now; @@ -238,20 +244,44 @@ impl JMAP { pub fn obtain_dkim_public_key(algo: Algorithm, pk: &str) -> Result { match simple_pem_parse(pk) { Some(der) => match algo { - Algorithm::Rsa => match RsaKey::::from_der(&der) { - Ok(pk) => Ok(String::from_utf8( - base64_encode(&pk.public_key()).unwrap_or_default(), - ) - .unwrap_or_default()), - Err(_) => Err("Failed to read RSA DER"), - }, - Algorithm::Ed25519 => match Ed25519Key::from_pkcs8_der(&der) { - Ok(pk) => Ok(String::from_utf8( - base64_encode(&pk.public_key()).unwrap_or_default(), - ) - .unwrap_or_default()), - Err(_) => Err("Failed to read ED25519 PKCS#8 DER"), + Algorithm::Rsa => match RsaKey::::from_der(&der).and_then(|key| { + Document::from_pkcs1_der(&key.public_key()) + .map_err(|err| mail_auth::Error::CryptoError(err.to_string())) + }) { + Ok(pk) => Ok( + String::from_utf8(base64_encode(pk.as_bytes()).unwrap_or_default()) + .unwrap_or_default(), + ), + Err(err) => { + tracing::debug!("Failed to read RSA DER: {err}"); + + Err("Failed to read RSA DER") + } }, + Algorithm::Ed25519 => { + match Ed25519Key::from_pkcs8_maybe_unchecked_der(&der).and_then(|key| { + BitString::from_bytes(&key.public_key()) + .and_then(|subject_public_key| { + SubjectPublicKeyInfoOwned { + algorithm: AlgorithmIdentifier { + oid: "1.3.101.112".parse().unwrap(), + parameters: None, + }, + subject_public_key, + } + .to_der() + }) + .map_err(|err| mail_auth::Error::CryptoError(err.to_string())) + }) { + Ok(pk) => Ok(String::from_utf8(base64_encode(&pk).unwrap_or_default()) + .unwrap_or_default()), + Err(err) => { + tracing::debug!("Failed to read ED25519 DER: {err}"); + + Err("Failed to read ED25519 DER") + } + } + } }, None => Err("Failed to decode private key"), }