Compare commits

..

1 Commits

Author SHA1 Message Date
link2xt
95b2a8e6a6 fix: separate entered and configured certificate checks 2024-08-16 22:14:00 +00:00
31 changed files with 174 additions and 672 deletions

View File

@@ -1,56 +1,5 @@
# Changelog
## [1.142.12] - 2024-09-02
### Fixes
- Display Config::MdnsEnabled as true by default ([#5948](https://github.com/deltachat/deltachat-core-rust/pull/5948)).
## [1.142.11] - 2024-08-30
### Fixes
- Set backward verification when observing vc-contact-confirm or `vg-member-added` ([#5930](https://github.com/deltachat/deltachat-core-rust/pull/5930)).
## [1.142.10] - 2024-08-26
### Fixes
- Only include one From: header in securejoin messages ([#5917](https://github.com/deltachat/deltachat-core-rust/pull/5917)).
## [1.142.9] - 2024-08-24
### Fixes
- Fix reading of multiline SMTP greetings ([#5911](https://github.com/deltachat/deltachat-core-rust/pull/5911)).
### Features / Changes
- Update preloaded DNS cache.
## [1.142.8] - 2024-08-21
### Fixes
- Do not panic on unknown CertificateChecks values.
## [1.142.7] - 2024-08-17
### Fixes
- Do not save "Automatic" into configured_imap_certificate_checks. **This fixes regression introduced in core 1.142.4. Versions 1.142.4..1.142.6 should not be used in releases.**
- Create a group unblocked for bot even if 1:1 chat is blocked ([#5514](https://github.com/deltachat/deltachat-core-rust/pull/5514)).
- Update rpgp from 0.13.1 to 0.13.2 to fix "unable to decrypt" errors when sending messages to old Delta Chat clients and using Ed25519 keys to encrypt.
- Do not request ALPN on standard ports and when using STARTTLS.
### Features / Changes
- jsonrpc: Add ContactObject::e2ee_avail.
### Tests
- Protected group for bot is auto-accepted.
## [1.142.6] - 2024-08-15
### Fixes
@@ -4800,9 +4749,3 @@ https://github.com/deltachat/deltachat-core-rust/pulls?q=is%3Apr+is%3Aclosed
[1.142.4]: https://github.com/deltachat/deltachat-core-rust/compare/v1.142.3...v1.142.4
[1.142.5]: https://github.com/deltachat/deltachat-core-rust/compare/v1.142.4...v1.142.5
[1.142.6]: https://github.com/deltachat/deltachat-core-rust/compare/v1.142.5...v1.142.6
[1.142.7]: https://github.com/deltachat/deltachat-core-rust/compare/v1.142.6...v1.142.7
[1.142.8]: https://github.com/deltachat/deltachat-core-rust/compare/v1.142.7...v1.142.8
[1.142.9]: https://github.com/deltachat/deltachat-core-rust/compare/v1.142.8...v1.142.9
[1.142.10]: https://github.com/deltachat/deltachat-core-rust/compare/v1.142.9..v1.142.10
[1.142.11]: https://github.com/deltachat/deltachat-core-rust/compare/v1.142.10..v1.142.11
[1.142.12]: https://github.com/deltachat/deltachat-core-rust/compare/v1.142.11..v1.142.12

16
Cargo.lock generated
View File

@@ -1353,7 +1353,7 @@ dependencies = [
[[package]]
name = "deltachat"
version = "1.142.12"
version = "1.142.6"
dependencies = [
"ansi_term",
"anyhow",
@@ -1444,7 +1444,7 @@ dependencies = [
[[package]]
name = "deltachat-jsonrpc"
version = "1.142.12"
version = "1.142.6"
dependencies = [
"anyhow",
"async-channel 2.3.1",
@@ -1469,7 +1469,7 @@ dependencies = [
[[package]]
name = "deltachat-repl"
version = "1.142.12"
version = "1.142.6"
dependencies = [
"ansi_term",
"anyhow",
@@ -1484,7 +1484,7 @@ dependencies = [
[[package]]
name = "deltachat-rpc-server"
version = "1.142.12"
version = "1.142.6"
dependencies = [
"anyhow",
"deltachat",
@@ -1513,7 +1513,7 @@ dependencies = [
[[package]]
name = "deltachat_ffi"
version = "1.142.12"
version = "1.142.6"
dependencies = [
"anyhow",
"deltachat",
@@ -3080,7 +3080,7 @@ dependencies = [
"iana-time-zone-haiku",
"js-sys",
"wasm-bindgen",
"windows-core 0.51.1",
"windows-core 0.52.0",
]
[[package]]
@@ -4428,9 +4428,9 @@ dependencies = [
[[package]]
name = "pgp"
version = "0.13.2"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a6c842436d5fa2b59eac1e9b3d142b50bfff99c1744c816b1f4c2ac55a20754"
checksum = "aeab6e08a63a51a29a65e461d0b6fd0f8d350914712ec43773ca22ed51d5501c"
dependencies = [
"aes",
"aes-gcm",

View File

@@ -1,6 +1,6 @@
[package]
name = "deltachat"
version = "1.142.12"
version = "1.142.6"
edition = "2021"
license = "MPL-2.0"
rust-version = "1.77"
@@ -73,7 +73,7 @@ num-traits = { workspace = true }
once_cell = { workspace = true }
percent-encoding = "2.3"
parking_lot = "0.12"
pgp = { version = "0.13.2", default-features = false }
pgp = { version = "0.13", default-features = false }
qrcodegen = "1.7.0"
quick-xml = "0.36"
quoted_printable = "0.5"

View File

@@ -1,6 +1,6 @@
[package]
name = "deltachat_ffi"
version = "1.142.12"
version = "1.142.6"
description = "Deltachat FFI"
edition = "2018"
readme = "README.md"

View File

@@ -5712,7 +5712,7 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot);
* Accept invalid certificates, including self-signed ones
* or having incorrect hostname.
*/
#define DC_CERTCK_ACCEPT_INVALID_CERTIFICATES 3
#define DC_CERTCK_ACCEPT_INVALID_CERTIFICATES 2
/**
* @}

View File

@@ -1,6 +1,6 @@
[package]
name = "deltachat-jsonrpc"
version = "1.142.12"
version = "1.142.6"
description = "DeltaChat JSON-RPC API"
edition = "2021"
default-run = "deltachat-jsonrpc-server"

View File

@@ -58,5 +58,5 @@
},
"type": "module",
"types": "dist/deltachat.d.ts",
"version": "1.142.12"
"version": "1.142.6"
}

View File

@@ -1,6 +1,6 @@
[package]
name = "deltachat-repl"
version = "1.142.12"
version = "1.142.6"
license = "MPL-2.0"
edition = "2021"
repository = "https://github.com/deltachat/deltachat-core-rust"

View File

@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "deltachat-rpc-client"
version = "1.142.12"
version = "1.142.6"
description = "Python client for Delta Chat core JSON-RPC interface"
classifiers = [
"Development Status :: 5 - Production/Stable",

View File

@@ -165,7 +165,7 @@ class CertificateChecks(IntEnum):
AUTOMATIC = 0
STRICT = 1
ACCEPT_INVALID_CERTIFICATES = 3
ACCEPT_INVALID_CERTIFICATES = 2
class Connectivity(IntEnum):

View File

@@ -61,16 +61,9 @@ def test_qr_setup_contact_svg(acfactory) -> None:
@pytest.mark.parametrize("protect", [True, False])
def test_qr_securejoin(acfactory, protect, tmp_path):
def test_qr_securejoin(acfactory, protect):
alice, bob = acfactory.get_online_accounts(2)
# Setup second device for Alice
# to test observing securejoin protocol.
alice.export_backup(tmp_path)
files = list(tmp_path.glob("*.tar"))
alice2 = acfactory.get_unconfigured_account()
alice2.import_backup(files[0])
logging.info("Alice creates a verified group")
alice_chat = alice.create_group("Verified group", protect=protect)
assert alice_chat.get_basic_snapshot().is_protected == protect
@@ -104,14 +97,6 @@ def test_qr_securejoin(acfactory, protect, tmp_path):
bob_contact_alice_snapshot = bob_contact_alice.get_snapshot()
assert bob_contact_alice_snapshot.is_verified
# Start second Alice device.
# Alice observes securejoin protocol and verifies Bob on second device.
alice2.start_io()
alice2.wait_for_securejoin_inviter_success()
alice2_contact_bob = alice2.get_contact_by_addr(bob.get_config("addr"))
alice2_contact_bob_snapshot = alice2_contact_bob.get_snapshot()
assert alice2_contact_bob_snapshot.is_verified
def test_qr_securejoin_contact_request(acfactory) -> None:
"""Alice invites Bob to a group when Bob's chat with Alice is in a contact request mode."""

View File

@@ -635,24 +635,3 @@ def test_get_http_response(acfactory):
http_response = alice._rpc.get_http_response(alice.id, "https://example.org")
assert http_response["mimetype"] == "text/html"
assert b"<title>Example Domain</title>" in base64.b64decode((http_response["blob"] + "==").encode())
def test_configured_imap_certificate_checks(acfactory):
alice = acfactory.new_configured_account()
configured_certificate_checks = alice.get_config("configured_imap_certificate_checks")
# Certificate checks should be configured (not None)
assert configured_certificate_checks
# 0 is the value old Delta Chat core versions used
# to mean user entered "imap_certificate_checks=0" (Automatic)
# and configuration failed to use strict TLS checks
# so it switched strict TLS checks off.
#
# New versions of Delta Chat are not disabling TLS checks
# unless users explicitly disables them
# or provider database says provider has invalid certificates.
#
# Core 1.142.4, 1.142.5 and 1.142.6 saved this value due to bug.
# This test is a regression test to prevent this happening again.
assert configured_certificate_checks != "0"

View File

@@ -1,6 +1,6 @@
[package]
name = "deltachat-rpc-server"
version = "1.142.12"
version = "1.142.6"
description = "DeltaChat JSON-RPC server"
edition = "2021"
readme = "README.md"

View File

@@ -15,5 +15,5 @@
},
"type": "module",
"types": "index.d.ts",
"version": "1.142.12"
"version": "1.142.6"
}

View File

@@ -1,7 +1,7 @@
// Generated!
module.exports = {
DC_CERTCK_ACCEPT_INVALID_CERTIFICATES: 3,
DC_CERTCK_ACCEPT_INVALID_CERTIFICATES: 2,
DC_CERTCK_AUTO: 0,
DC_CERTCK_STRICT: 1,
DC_CHAT_ID_ALLDONE_HINT: 7,

View File

@@ -1,7 +1,7 @@
// Generated!
export enum C {
DC_CERTCK_ACCEPT_INVALID_CERTIFICATES = 3,
DC_CERTCK_ACCEPT_INVALID_CERTIFICATES = 2,
DC_CERTCK_AUTO = 0,
DC_CERTCK_STRICT = 1,
DC_CHAT_ID_ALLDONE_HINT = 7,

View File

@@ -55,5 +55,5 @@
"test:mocha": "mocha node/test/test.mjs --growl --reporter=spec --bail --exit"
},
"types": "node/dist/index.d.ts",
"version": "1.142.12"
"version": "1.142.6"
}

View File

@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "deltachat"
version = "1.142.12"
version = "1.142.6"
description = "Python bindings for the Delta Chat Core library using CFFI against the Rust-implemented libdeltachat"
readme = "README.rst"
requires-python = ">=3.7"

View File

@@ -1 +1 @@
2024-09-02
2024-08-15

View File

@@ -129,7 +129,6 @@ pub enum Config {
/// True if Message Delivery Notifications (read receipts) should
/// be sent and requested.
#[strum(props(default = "1"))]
MdnsEnabled,
/// True if "Sent" folder should be watched for changes.
@@ -517,15 +516,18 @@ impl Context {
/// Returns whether MDNs should be requested.
pub(crate) async fn should_request_mdns(&self) -> Result<bool> {
match self.config_exists(Config::MdnsEnabled).await? {
true => self.get_config_bool(Config::MdnsEnabled).await,
false => Ok(!self.get_config_bool(Config::Bot).await?),
match self.get_config_bool_opt(Config::MdnsEnabled).await? {
Some(val) => Ok(val),
None => Ok(!self.get_config_bool(Config::Bot).await?),
}
}
/// Returns whether MDNs should be sent.
pub(crate) async fn should_send_mdns(&self) -> Result<bool> {
self.get_config_bool(Config::MdnsEnabled).await
Ok(self
.get_config_bool_opt(Config::MdnsEnabled)
.await?
.unwrap_or(true))
}
/// Gets configured "delete_server_after" value.
@@ -982,13 +984,9 @@ mod tests {
let t = &TestContext::new_alice().await;
assert!(t.should_request_mdns().await?);
assert!(t.should_send_mdns().await?);
// The setting should be displayed correctly.
assert!(t.get_config_bool(Config::MdnsEnabled).await?);
t.set_config_bool(Config::Bot, true).await?;
assert!(!t.should_request_mdns().await?);
assert!(t.should_send_mdns().await?);
assert!(t.get_config_bool(Config::MdnsEnabled).await?);
Ok(())
}

View File

@@ -27,7 +27,7 @@ use crate::config::{self, Config};
use crate::context::Context;
use crate::imap::{session::Session as ImapSession, Imap};
use crate::log::LogExt;
use crate::login_param::{CertificateChecks, LoginParam, ServerLoginParam};
use crate::login_param::{LoginParam, ServerLoginParam};
use crate::message::{Message, Viewtype};
use crate::oauth2::get_oauth2_addr;
use crate::provider::{Protocol, Socket, UsernamePattern};
@@ -280,21 +280,7 @@ async fn configure(ctx: &Context, param: &mut LoginParam) -> Result<()> {
param_autoconfig = None;
}
let user_strict_tls = match param.certificate_checks {
CertificateChecks::Automatic => None,
CertificateChecks::Strict => Some(true),
CertificateChecks::AcceptInvalidCertificates
| CertificateChecks::AcceptInvalidCertificates2 => Some(false),
};
let provider_strict_tls = param.provider.map(|provider| provider.opt.strict_tls);
let strict_tls = user_strict_tls.or(provider_strict_tls).unwrap_or(true);
// Do not save `CertificateChecks::Automatic` into `configured_imap_certificate_checks`.
param.certificate_checks = if strict_tls {
CertificateChecks::Strict
} else {
CertificateChecks::AcceptInvalidCertificates
};
let strict_tls = param.strict_tls();
progress!(ctx, 500);

View File

@@ -38,16 +38,6 @@ impl DerefMut for Client {
}
}
/// Converts port number to ALPN list.
fn alpn(port: u16) -> &'static [&'static str] {
if port == 993 {
// Do not request ALPN on standard port.
&[]
} else {
&["imap"]
}
}
/// Determine server capabilities.
///
/// If server supports ID capability, send our client ID.
@@ -167,7 +157,7 @@ impl Client {
}
async fn connect_secure(addr: SocketAddr, hostname: &str, strict_tls: bool) -> Result<Self> {
let tls_stream = connect_tls_inner(addr, hostname, strict_tls, alpn(addr.port())).await?;
let tls_stream = connect_tls_inner(addr, hostname, strict_tls, "imap").await?;
let buffered_stream = BufWriter::new(tls_stream);
let session_stream: Box<dyn SessionStream> = Box::new(buffered_stream);
let mut client = Client::new(session_stream);
@@ -207,7 +197,7 @@ impl Client {
let buffered_tcp_stream = client.into_inner();
let tcp_stream = buffered_tcp_stream.into_inner();
let tls_stream = wrap_tls(strict_tls, host, &[], tcp_stream)
let tls_stream = wrap_tls(strict_tls, host, "imap", tcp_stream)
.await
.context("STARTTLS upgrade failed")?;
@@ -227,7 +217,7 @@ impl Client {
let socks5_stream = socks5_config
.connect(context, domain, port, strict_tls)
.await?;
let tls_stream = wrap_tls(strict_tls, domain, alpn(port), socks5_stream).await?;
let tls_stream = wrap_tls(strict_tls, domain, "imap", socks5_stream).await?;
let buffered_stream = BufWriter::new(tls_stream);
let session_stream: Box<dyn SessionStream> = Box::new(buffered_stream);
let mut client = Client::new(session_stream);
@@ -280,7 +270,7 @@ impl Client {
let buffered_socks5_stream = client.into_inner();
let socks5_stream: Socks5Stream<_> = buffered_socks5_stream.into_inner();
let tls_stream = wrap_tls(strict_tls, hostname, &[], socks5_stream)
let tls_stream = wrap_tls(strict_tls, hostname, "imap", socks5_stream)
.await
.context("STARTTLS upgrade failed")?;
let buffered_stream = BufWriter::new(tls_stream);

View File

@@ -2,7 +2,7 @@
use std::fmt;
use anyhow::{ensure, Context as _, Result};
use anyhow::{ensure, Result};
use crate::constants::{DC_LP_AUTH_FLAGS, DC_LP_AUTH_NORMAL, DC_LP_AUTH_OAUTH2};
use crate::context::Context;
@@ -10,36 +10,66 @@ use crate::provider::Socket;
use crate::provider::{get_provider_by_id, Provider};
use crate::socks::Socks5Config;
/// User entered setting for certificate checks.
///
/// Should be saved into `imap_certificate_checks` before running configuration.
#[derive(Copy, Clone, Debug, Default, Display, FromPrimitive, ToPrimitive, PartialEq, Eq)]
#[repr(u32)]
#[strum(serialize_all = "snake_case")]
pub enum CertificateChecks {
/// Same as AcceptInvalidCertificates if stored in the database
/// as `configured_{imap,smtp}_certificate_checks`.
///
/// Previous Delta Chat versions stored this in `configured_*`
/// if Automatic configuration
/// was selected, configuration with strict TLS checks failed
/// and configuration without strict TLS checks succeeded.
///
/// Currently Delta Chat stores only
/// `Strict` or `AcceptInvalidCertificates` variants
/// in `configured_*` settings.
///
/// `Automatic` in `{imap,smtp}_certificate_checks`
/// means that provider database setting should be taken.
pub enum EnteredCertificateChecks {
/// `Automatic` means that provider database setting should be taken.
/// If there is no provider database setting for certificate checks,
/// `Automatic` is the same as `Strict`.
/// check certificates strictly.
#[default]
Automatic = 0,
/// Ensure that TLS certificate is valid for the server hostname.
Strict = 1,
/// Same as AcceptInvalidCertificates
/// Previously known as AcceptInvalidHostnames, now deprecated.
AcceptInvalidCertificates2 = 2,
/// Accept certificates that are expired, self-signed
/// or otherwise not valid for the server hostname.
AcceptInvalidCertificates = 2,
AcceptInvalidCertificates = 3,
/// Alias for `AcceptInvalidCertificates`
/// for API compatibility.
AcceptInvalidCertificates2 = 3,
}
/// Values saved into `imap_certificate_checks`.
#[derive(Copy, Clone, Debug, Default, Display, FromPrimitive, ToPrimitive, PartialEq, Eq)]
#[repr(u32)]
#[strum(serialize_all = "snake_case")]
pub enum ConfiguredCertificateChecks {
/// Use configuration from the provider database.
/// If there is no provider database setting for certificate checks,
/// accept invalid certificates.
///
/// Must not be saved by new versions.
///
/// Previous Delta Chat versions before core 1.133.0
/// stored this in `configured_imap_certificate_checks`
/// if Automatic configuration
/// was selected, configuration with strict TLS checks failed
/// and configuration without strict TLS checks succeeded.
OldAutomatic = 0,
/// Ensure that TLS certificate is valid for the server hostname.
Strict = 1,
/// Accept certificates that are expired, self-signed
/// or otherwise not valid for the server hostname.
AcceptInvalidCertificates = 2,
/// Accept certificates that are expired, self-signed
/// or otherwise not valid for the server hostname.
///
/// Alias to `AcceptInvalidCertificates` for compatibility.
AcceptInvalidCertificates2 = 3,
/// Use configuration from the provider database.
/// If there is no provider database setting for certificate checks,
/// apply strict checks to TLS certificates.
Automatic = 4,
}
/// Login parameters for a single server, either IMAP or SMTP
@@ -132,8 +162,7 @@ impl LoginParam {
let key = &format!("{prefix}imap_certificate_checks");
let certificate_checks =
if let Some(certificate_checks) = sql.get_raw_config_int(key).await? {
num_traits::FromPrimitive::from_i32(certificate_checks)
.with_context(|| format!("Invalid {key} value"))?
num_traits::FromPrimitive::from_i32(certificate_checks).unwrap()
} else {
Default::default()
};
@@ -266,9 +295,7 @@ impl LoginParam {
| CertificateChecks::AcceptInvalidCertificates2 => Some(false),
};
let provider_strict_tls = self.provider.map(|provider| provider.opt.strict_tls);
user_strict_tls
.or(provider_strict_tls)
.unwrap_or(self.socks5_config.is_some())
user_strict_tls.or(provider_strict_tls).unwrap_or(true)
}
}

View File

@@ -726,18 +726,18 @@ impl MimeFactory {
} else if header_name == "autocrypt" {
unprotected_headers.push(header.clone());
} else if header_name == "from" {
// Unencrypted securejoin messages should _not_ include the display name:
if is_encrypted || !is_securejoin_message {
protected_headers.push(header.clone());
protected_headers.push(header.clone());
if is_encrypted && verified || is_securejoin_message {
unprotected_headers.push(
Header::new_with_value(
header.name,
vec![Address::new_mailbox(self.from_addr.clone())],
)
.unwrap(),
);
} else {
unprotected_headers.push(header);
}
unprotected_headers.push(
Header::new_with_value(
header.name,
vec![Address::new_mailbox(self.from_addr.clone())],
)
.unwrap(),
);
} else if header_name == "to" {
protected_headers.push(header.clone());
if is_encrypted {
@@ -902,11 +902,12 @@ impl MimeFactory {
.fold(message, |message, header| message.header(header.clone()));
if skip_autocrypt || !context.get_config_bool(Config::SignUnencrypted).await? {
// Deduplicate unprotected headers that also are in the protected headers:
let protected: HashSet<&str> =
HashSet::from_iter(protected_headers.iter().map(|h| h.name.as_str()));
unprotected_headers.retain(|h| !protected.contains(&h.name.as_str()));
let protected: HashSet<Header> = HashSet::from_iter(protected_headers.into_iter());
for h in unprotected_headers.split_off(0) {
if !protected.contains(&h) {
unprotected_headers.push(h);
}
}
message
} else {
let message = message.header(get_content_type_directives_header());

View File

@@ -114,7 +114,7 @@ pub(crate) async fn connect_tls_inner(
addr: SocketAddr,
host: &str,
strict_tls: bool,
alpn: &[&str],
alpn: &str,
) -> Result<TlsStream<Pin<Box<TimeoutStream<TcpStream>>>>> {
let tcp_stream = connect_tcp_inner(addr).await?;
let tls_stream = wrap_tls(strict_tls, host, alpn, tcp_stream).await?;

View File

@@ -1,7 +1,6 @@
//! DNS resolution and cache.
use anyhow::{Context as _, Result};
use std::collections::HashMap;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
use std::str::FromStr;
use tokio::net::lookup_host;
@@ -10,7 +9,6 @@ use tokio::time::timeout;
use super::load_connection_timestamp;
use crate::context::Context;
use crate::tools::time;
use once_cell::sync::Lazy;
/// Inserts entry into DNS cache
/// or updates existing one with a new timestamp.
@@ -108,399 +106,6 @@ pub(crate) async fn update_connect_timestamp(
Ok(())
}
static DNS_PRELOAD: Lazy<HashMap<&'static str, Vec<IpAddr>>> = Lazy::new(|| {
HashMap::from([
(
"mail.sangham.net",
vec![
IpAddr::V4(Ipv4Addr::new(159, 69, 186, 85)),
IpAddr::V6(Ipv6Addr::new(0x2a01, 0x4f8, 0xc17, 0x798c, 0, 0, 0, 1)),
],
),
(
"nine.testrun.org",
vec![
IpAddr::V4(Ipv4Addr::new(116, 202, 233, 236)),
IpAddr::V4(Ipv4Addr::new(128, 140, 126, 197)),
IpAddr::V4(Ipv4Addr::new(49, 12, 116, 128)),
IpAddr::V6(Ipv6Addr::new(0x2a01, 0x4f8, 0x241, 0x4ce8, 0, 0, 0, 2)),
],
),
(
"disroot.org",
vec![IpAddr::V4(Ipv4Addr::new(178, 21, 23, 139))],
),
(
"imap.gmail.com",
vec![
IpAddr::V4(Ipv4Addr::new(142, 250, 110, 108)),
IpAddr::V4(Ipv4Addr::new(142, 250, 110, 109)),
IpAddr::V4(Ipv4Addr::new(66, 102, 1, 108)),
IpAddr::V4(Ipv4Addr::new(66, 102, 1, 109)),
IpAddr::V6(Ipv6Addr::new(0x2a00, 0x1450, 0x400c, 0xc1f, 0, 0, 0, 0x6c)),
IpAddr::V6(Ipv6Addr::new(0x2a00, 0x1450, 0x400c, 0xc1f, 0, 0, 0, 0x6d)),
],
),
(
"smtp.gmail.com",
vec![
IpAddr::V4(Ipv4Addr::new(142, 250, 110, 109)),
IpAddr::V6(Ipv6Addr::new(0x2a00, 0x1450, 0x4013, 0xc04, 0, 0, 0, 0x6c)),
],
),
(
"mail.autistici.org",
vec![
IpAddr::V4(Ipv4Addr::new(198, 167, 222, 108)),
IpAddr::V4(Ipv4Addr::new(82, 94, 249, 234)),
IpAddr::V4(Ipv4Addr::new(93, 190, 126, 19)),
],
),
(
"smtp.autistici.org",
vec![
IpAddr::V4(Ipv4Addr::new(198, 167, 222, 108)),
IpAddr::V4(Ipv4Addr::new(82, 94, 249, 234)),
IpAddr::V4(Ipv4Addr::new(93, 190, 126, 19)),
],
),
(
"daleth.cafe",
vec![IpAddr::V4(Ipv4Addr::new(37, 27, 6, 204))],
),
(
"imap.163.com",
vec![IpAddr::V4(Ipv4Addr::new(111, 124, 203, 45))],
),
(
"smtp.163.com",
vec![IpAddr::V4(Ipv4Addr::new(103, 129, 252, 45))],
),
(
"imap.aol.com",
vec![
IpAddr::V4(Ipv4Addr::new(212, 82, 101, 33)),
IpAddr::V4(Ipv4Addr::new(87, 248, 98, 69)),
],
),
(
"smtp.aol.com",
vec![IpAddr::V4(Ipv4Addr::new(87, 248, 97, 31))],
),
(
"mail.arcor.de",
vec![IpAddr::V4(Ipv4Addr::new(2, 207, 150, 234))],
),
(
"imap.arcor.de",
vec![IpAddr::V4(Ipv4Addr::new(2, 207, 150, 230))],
),
(
"imap.fastmail.com",
vec![
IpAddr::V4(Ipv4Addr::new(103, 168, 172, 43)),
IpAddr::V4(Ipv4Addr::new(103, 168, 172, 58)),
],
),
(
"smtp.fastmail.com",
vec![
IpAddr::V4(Ipv4Addr::new(103, 168, 172, 45)),
IpAddr::V4(Ipv4Addr::new(103, 168, 172, 60)),
],
),
(
"imap.gmx.net",
vec![
IpAddr::V4(Ipv4Addr::new(212, 227, 17, 170)),
IpAddr::V4(Ipv4Addr::new(212, 227, 17, 186)),
],
),
(
"imap.mail.de",
vec![IpAddr::V4(Ipv4Addr::new(62, 201, 172, 16))],
),
(
"smtp.mailbox.org",
vec![IpAddr::V4(Ipv4Addr::new(185, 97, 174, 196))],
),
(
"imap.mailbox.org",
vec![IpAddr::V4(Ipv4Addr::new(185, 97, 174, 199))],
),
(
"imap.naver.com",
vec![IpAddr::V4(Ipv4Addr::new(125, 209, 238, 153))],
),
(
"imap.ouvaton.coop",
vec![IpAddr::V4(Ipv4Addr::new(194, 36, 166, 20))],
),
(
"imap.purelymail.com",
vec![IpAddr::V4(Ipv4Addr::new(18, 204, 123, 63))],
),
(
"imap.tiscali.it",
vec![IpAddr::V4(Ipv4Addr::new(213, 205, 33, 10))],
),
(
"smtp.tiscali.it",
vec![IpAddr::V4(Ipv4Addr::new(213, 205, 33, 13))],
),
(
"imap.web.de",
vec![
IpAddr::V4(Ipv4Addr::new(212, 227, 17, 162)),
IpAddr::V4(Ipv4Addr::new(212, 227, 17, 178)),
],
),
(
"imap.ziggo.nl",
vec![IpAddr::V4(Ipv4Addr::new(84, 116, 6, 3))],
),
(
"imap.zoho.eu",
vec![IpAddr::V4(Ipv4Addr::new(185, 230, 214, 25))],
),
(
"imaps.bluewin.ch",
vec![
IpAddr::V4(Ipv4Addr::new(16, 62, 253, 42)),
IpAddr::V4(Ipv4Addr::new(16, 63, 141, 244)),
IpAddr::V4(Ipv4Addr::new(16, 63, 146, 183)),
],
),
(
"mail.buzon.uy",
vec![IpAddr::V4(Ipv4Addr::new(185, 101, 93, 79))],
),
(
"mail.ecloud.global",
vec![IpAddr::V4(Ipv4Addr::new(95, 217, 246, 96))],
),
(
"mail.ende.in.net",
vec![IpAddr::V4(Ipv4Addr::new(95, 217, 5, 72))],
),
(
"mail.gmx.net",
vec![
IpAddr::V4(Ipv4Addr::new(212, 227, 17, 168)),
IpAddr::V4(Ipv4Addr::new(212, 227, 17, 190)),
],
),
(
"mail.infomaniak.com",
vec![
IpAddr::V4(Ipv4Addr::new(83, 166, 143, 44)),
IpAddr::V4(Ipv4Addr::new(83, 166, 143, 45)),
],
),
(
"mail.mymagenta.at",
vec![IpAddr::V4(Ipv4Addr::new(80, 109, 253, 241))],
),
(
"mail.nubo.coop",
vec![IpAddr::V4(Ipv4Addr::new(79, 99, 201, 10))],
),
(
"mail.riseup.net",
vec![
IpAddr::V4(Ipv4Addr::new(198, 252, 153, 70)),
IpAddr::V4(Ipv4Addr::new(198, 252, 153, 71)),
],
),
(
"mail.systemausfall.org",
vec![
IpAddr::V4(Ipv4Addr::new(51, 75, 71, 249)),
IpAddr::V4(Ipv4Addr::new(80, 153, 252, 42)),
],
),
(
"mail.systemli.org",
vec![IpAddr::V4(Ipv4Addr::new(93, 190, 126, 36))],
),
(
"mehl.cloud",
vec![IpAddr::V4(Ipv4Addr::new(95, 217, 223, 172))],
),
(
"mx.freenet.de",
vec![
IpAddr::V4(Ipv4Addr::new(195, 4, 92, 210)),
IpAddr::V4(Ipv4Addr::new(195, 4, 92, 211)),
IpAddr::V4(Ipv4Addr::new(195, 4, 92, 212)),
IpAddr::V4(Ipv4Addr::new(195, 4, 92, 213)),
],
),
(
"newyear.aktivix.org",
vec![IpAddr::V4(Ipv4Addr::new(162, 247, 75, 192))],
),
(
"pimap.schulon.org",
vec![IpAddr::V4(Ipv4Addr::new(194, 77, 246, 20))],
),
(
"posteo.de",
vec![
IpAddr::V4(Ipv4Addr::new(185, 67, 36, 168)),
IpAddr::V4(Ipv4Addr::new(185, 67, 36, 169)),
],
),
(
"psmtp.schulon.org",
vec![IpAddr::V4(Ipv4Addr::new(194, 77, 246, 20))],
),
(
"secureimap.t-online.de",
vec![
IpAddr::V4(Ipv4Addr::new(194, 25, 134, 114)),
IpAddr::V4(Ipv4Addr::new(194, 25, 134, 115)),
IpAddr::V4(Ipv4Addr::new(194, 25, 134, 50)),
IpAddr::V4(Ipv4Addr::new(194, 25, 134, 51)),
],
),
(
"securesmtp.t-online.de",
vec![
IpAddr::V4(Ipv4Addr::new(194, 25, 134, 110)),
IpAddr::V4(Ipv4Addr::new(194, 25, 134, 46)),
],
),
(
"smtp.aliyun.com",
vec![IpAddr::V4(Ipv4Addr::new(47, 246, 136, 232))],
),
(
"smtp.mail.de",
vec![IpAddr::V4(Ipv4Addr::new(62, 201, 172, 21))],
),
(
"smtp.mail.ru",
vec![
IpAddr::V4(Ipv4Addr::new(217, 69, 139, 160)),
IpAddr::V4(Ipv4Addr::new(94, 100, 180, 160)),
],
),
(
"imap.mail.yahoo.com",
vec![
IpAddr::V4(Ipv4Addr::new(87, 248, 103, 8)),
IpAddr::V4(Ipv4Addr::new(212, 82, 101, 24)),
],
),
(
"smtp.mail.yahoo.com",
vec![IpAddr::V4(Ipv4Addr::new(87, 248, 97, 36))],
),
(
"imap.mailo.com",
vec![IpAddr::V4(Ipv4Addr::new(213, 182, 54, 20))],
),
(
"smtp.mailo.com",
vec![IpAddr::V4(Ipv4Addr::new(213, 182, 54, 20))],
),
(
"smtp.naver.com",
vec![IpAddr::V4(Ipv4Addr::new(125, 209, 238, 155))],
),
(
"smtp.ouvaton.coop",
vec![IpAddr::V4(Ipv4Addr::new(194, 36, 166, 20))],
),
(
"smtp.purelymail.com",
vec![IpAddr::V4(Ipv4Addr::new(18, 204, 123, 63))],
),
(
"imap.qq.com",
vec![IpAddr::V4(Ipv4Addr::new(43, 129, 255, 54))],
),
(
"smtp.qq.com",
vec![IpAddr::V4(Ipv4Addr::new(43, 129, 255, 54))],
),
(
"imap.rambler.ru",
vec![
IpAddr::V4(Ipv4Addr::new(81, 19, 77, 169)),
IpAddr::V4(Ipv4Addr::new(81, 19, 77, 171)),
IpAddr::V4(Ipv4Addr::new(81, 19, 77, 168)),
IpAddr::V4(Ipv4Addr::new(81, 19, 77, 170)),
],
),
(
"smtp.rambler.ru",
vec![
IpAddr::V4(Ipv4Addr::new(81, 19, 77, 165)),
IpAddr::V4(Ipv4Addr::new(81, 19, 77, 167)),
IpAddr::V4(Ipv4Addr::new(81, 19, 77, 166)),
IpAddr::V4(Ipv4Addr::new(81, 19, 77, 164)),
],
),
(
"imap.vivaldi.net",
vec![IpAddr::V4(Ipv4Addr::new(31, 209, 137, 15))],
),
(
"smtp.vivaldi.net",
vec![IpAddr::V4(Ipv4Addr::new(31, 209, 137, 12))],
),
(
"imap.vodafonemail.de",
vec![IpAddr::V4(Ipv4Addr::new(2, 207, 150, 230))],
),
(
"smtp.vodafonemail.de",
vec![IpAddr::V4(Ipv4Addr::new(2, 207, 150, 234))],
),
(
"smtp.web.de",
vec![
IpAddr::V4(Ipv4Addr::new(213, 165, 67, 108)),
IpAddr::V4(Ipv4Addr::new(213, 165, 67, 124)),
],
),
(
"imap.yandex.com",
vec![IpAddr::V4(Ipv4Addr::new(77, 88, 21, 125))],
),
(
"smtp.yandex.com",
vec![IpAddr::V4(Ipv4Addr::new(77, 88, 21, 158))],
),
(
"smtp.ziggo.nl",
vec![IpAddr::V4(Ipv4Addr::new(84, 116, 6, 3))],
),
(
"smtp.zoho.eu",
vec![IpAddr::V4(Ipv4Addr::new(185, 230, 212, 164))],
),
(
"smtpauths.bluewin.ch",
vec![IpAddr::V4(Ipv4Addr::new(195, 186, 120, 54))],
),
(
"stinpriza.net",
vec![IpAddr::V4(Ipv4Addr::new(5, 9, 122, 184))],
),
(
"undernet.uy",
vec![IpAddr::V4(Ipv4Addr::new(167, 62, 254, 153))],
),
(
"webbox222.server-home.org",
vec![IpAddr::V4(Ipv4Addr::new(91, 203, 111, 88))],
),
])
});
/// Load hardcoded cache if everything else fails.
///
/// See <https://support.delta.chat/t/no-dns-resolution-result/2778> and
@@ -509,10 +114,61 @@ static DNS_PRELOAD: Lazy<HashMap<&'static str, Vec<IpAddr>>> = Lazy::new(|| {
/// In the future we may pre-resolve all provider database addresses
/// and build them in.
fn load_hardcoded_cache(hostname: &str, port: u16) -> Vec<SocketAddr> {
if let Some(ips) = DNS_PRELOAD.get(hostname) {
ips.iter().map(|ip| SocketAddr::new(*ip, port)).collect()
} else {
Vec::new()
match hostname {
"mail.sangham.net" => {
vec![
SocketAddr::new(
IpAddr::V6(Ipv6Addr::new(0x2a01, 0x4f8, 0xc17, 0x798c, 0, 0, 0, 1)),
port,
),
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(159, 69, 186, 85)), port),
]
}
"nine.testrun.org" => {
vec![
SocketAddr::new(
IpAddr::V6(Ipv6Addr::new(0x2a01, 0x4f8, 0x241, 0x4ce8, 0, 0, 0, 2)),
port,
),
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(116, 202, 233, 236)), port),
]
}
"disroot.org" => {
vec![SocketAddr::new(
IpAddr::V4(Ipv4Addr::new(178, 21, 23, 139)),
port,
)]
}
"mail.riseup.net" => {
vec![
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(198, 252, 153, 70)), port),
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(198, 252, 153, 71)), port),
]
}
"imap.gmail.com" => {
vec![
SocketAddr::new(
IpAddr::V6(Ipv6Addr::new(0x2a00, 0x1450, 0x400c, 0xc1f, 0, 0, 0, 0x6c)),
port,
),
SocketAddr::new(
IpAddr::V6(Ipv6Addr::new(0x2a00, 0x1450, 0x400c, 0xc1f, 0, 0, 0, 0x6d)),
port,
),
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(142, 250, 110, 109)), port),
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(142, 250, 110, 108)), port),
]
}
"smtp.gmail.com" => {
vec![
SocketAddr::new(
IpAddr::V6(Ipv6Addr::new(0x2a00, 0x1450, 0x4013, 0xc04, 0, 0, 0, 0x6c)),
port,
),
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(142, 250, 110, 109)), port),
]
}
_ => Vec::new(),
}
}

View File

@@ -32,10 +32,10 @@ pub fn build_tls(strict_tls: bool, alpns: &[&str]) -> TlsConnector {
pub async fn wrap_tls<T: AsyncRead + AsyncWrite + Unpin>(
strict_tls: bool,
hostname: &str,
alpn: &[&str],
alpn: &str,
stream: T,
) -> Result<TlsStream<T>> {
let tls = build_tls(strict_tls, alpn);
let tls = build_tls(strict_tls, &[alpn]);
let tls_stream = tls.connect(hostname, stream).await?;
Ok(tls_stream)
}

View File

@@ -637,10 +637,6 @@ pub(crate) async fn observe_securejoin_on_other_device(
return Ok(HandshakeMessage::Ignore);
};
peerstate.set_verified(key.clone(), fingerprint, addr)?;
if matches!(step, "vg-member-added" | "vc-contact-confirm") {
peerstate.backward_verified_key_id =
Some(context.get_config_i64(Config::KeyId).await?).filter(|&id| id > 0);
}
peerstate.prefer_encrypt = EncryptPreference::Mutual;
peerstate.save_to_db(&context.sql).await?;
@@ -847,7 +843,6 @@ mod tests {
);
let sent = bob.pop_sent_msg().await;
assert!(!sent.payload.contains("Bob Examplenet"));
assert_eq!(sent.recipient(), EmailAddress::new(alice_addr).unwrap());
let msg = alice.parse_msg(&sent).await;
assert!(!msg.was_encrypted());
@@ -865,7 +860,6 @@ mod tests {
);
let sent = alice.pop_sent_msg().await;
assert!(!sent.payload.contains("Alice Exampleorg"));
let msg = bob.parse_msg(&sent).await;
assert!(msg.was_encrypted());
assert_eq!(

View File

@@ -16,16 +16,6 @@ use crate::provider::Socket;
use crate::socks::Socks5Config;
use crate::tools::time;
/// Converts port number to ALPN list.
fn alpn(port: u16) -> &'static [&'static str] {
if port == 465 {
// Do not request ALPN on standard port.
&[]
} else {
&["smtp"]
}
}
/// Returns TLS, STARTTLS or plaintext connection
/// using SOCKS5 or direct connection depending on the given configuration.
///
@@ -99,12 +89,11 @@ pub(crate) async fn connect_stream(
async fn skip_smtp_greeting<R: tokio::io::AsyncBufReadExt + Unpin>(stream: &mut R) -> Result<()> {
let mut line = String::with_capacity(512);
loop {
line.clear();
let read = stream.read_line(&mut line).await?;
if read == 0 {
bail!("Unexpected EOF while reading SMTP greeting.");
}
if line.starts_with("220-") {
if line.starts_with("220- ") {
continue;
} else if line.starts_with("220 ") {
return Ok(());
@@ -124,7 +113,7 @@ async fn connect_secure_socks5(
let socks5_stream = socks5_config
.connect(context, hostname, port, strict_tls)
.await?;
let tls_stream = wrap_tls(strict_tls, hostname, alpn(port), socks5_stream).await?;
let tls_stream = wrap_tls(strict_tls, hostname, "smtp", socks5_stream).await?;
let mut buffered_stream = BufStream::new(tls_stream);
skip_smtp_greeting(&mut buffered_stream).await?;
let session_stream: Box<dyn SessionBufStream> = Box::new(buffered_stream);
@@ -146,7 +135,7 @@ async fn connect_starttls_socks5(
let client = SmtpClient::new().smtp_utf8(true);
let transport = SmtpTransport::new(client, BufStream::new(socks5_stream)).await?;
let tcp_stream = transport.starttls().await?.into_inner();
let tls_stream = wrap_tls(strict_tls, hostname, &[], tcp_stream)
let tls_stream = wrap_tls(strict_tls, hostname, "smtp", tcp_stream)
.await
.context("STARTTLS upgrade failed")?;
let buffered_stream = BufStream::new(tls_stream);
@@ -174,7 +163,7 @@ async fn connect_secure(
hostname: &str,
strict_tls: bool,
) -> Result<Box<dyn SessionBufStream>> {
let tls_stream = connect_tls_inner(addr, hostname, strict_tls, alpn(addr.port())).await?;
let tls_stream = connect_tls_inner(addr, hostname, strict_tls, "smtp").await?;
let mut buffered_stream = BufStream::new(tls_stream);
skip_smtp_greeting(&mut buffered_stream).await?;
let session_stream: Box<dyn SessionBufStream> = Box::new(buffered_stream);
@@ -192,7 +181,7 @@ async fn connect_starttls(
let client = async_smtp::SmtpClient::new().smtp_utf8(true);
let transport = async_smtp::SmtpTransport::new(client, BufStream::new(tcp_stream)).await?;
let tcp_stream = transport.starttls().await?.into_inner();
let tls_stream = wrap_tls(strict_tls, host, &[], tcp_stream)
let tls_stream = wrap_tls(strict_tls, host, "smtp", tcp_stream)
.await
.context("STARTTLS upgrade failed")?;
@@ -208,19 +197,3 @@ async fn connect_insecure(addr: SocketAddr) -> Result<Box<dyn SessionBufStream>>
let session_stream: Box<dyn SessionBufStream> = Box::new(buffered_stream);
Ok(session_stream)
}
#[cfg(test)]
mod tests {
use tokio::io::BufReader;
use super::*;
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_skip_smtp_greeting() -> Result<()> {
let greeting = b"220-server261.web-hosting.com ESMTP Exim 4.96.2 #2 Sat, 24 Aug 2024 12:25:53 -0400 \r\n\
220-We do not authorize the use of this system to transport unsolicited,\r\n\
220 and/or bulk e-mail.\r\n";
let mut buffered_stream = BufReader::new(&greeting[..]);
skip_smtp_greeting(&mut buffered_stream).await
}
}

View File

@@ -2,7 +2,7 @@
//!
//! This private module is only compiled for test runs.
#![allow(clippy::indexing_slicing)]
use std::collections::{BTreeMap, HashSet};
use std::collections::BTreeMap;
use std::fmt::Write;
use std::ops::{Deref, DerefMut};
use std::panic;
@@ -477,36 +477,6 @@ impl TestContext {
update_msg_state(&self.ctx, msg_id, MessageState::OutDelivered)
.await
.expect("failed to update message state");
let payload_headers = payload.split("\r\n\r\n").next().unwrap().lines();
let payload_header_names: Vec<_> = payload_headers
.map(|h| h.split(':').next().unwrap())
.collect();
// Check that we are sending exactly one From, Subject, Date, To, Message-ID, and MIME-Version header:
for header in &[
"From",
"Subject",
"Date",
"To",
"Message-ID",
"MIME-Version",
] {
assert_eq!(
payload_header_names.iter().filter(|h| *h == header).count(),
1,
"This sent email should contain the header {header} exactly 1 time:\n{payload}"
);
}
// Check that we aren't sending any header twice:
let mut hash_set = HashSet::new();
for header_name in payload_header_names {
assert!(
hash_set.insert(header_name),
"This sent email shouldn't contain the header {header_name} multiple times:\n{payload}"
);
}
Some(SentMessage {
payload,
sender_msg_id: msg_id,

View File

@@ -881,7 +881,7 @@ async fn test_verified_member_added_reordering() -> Result<()> {
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_no_unencrypted_name_if_encrypted() -> Result<()> {
async fn test_no_unencrypted_name_if_verified() -> Result<()> {
let mut tcm = TestContextManager::new();
for verified in [false, true] {
let alice = tcm.alice().await;
@@ -898,7 +898,7 @@ async fn test_no_unencrypted_name_if_encrypted() -> Result<()> {
let chat_id = bob.create_chat(&alice).await.id;
let msg = &bob.send_text(chat_id, "hi").await;
assert_eq!(msg.payload.contains("Bob Smith"), false);
assert_eq!(msg.payload.contains("Bob Smith"), !verified);
assert!(msg.payload.contains("BEGIN PGP MESSAGE"));
let msg = alice.recv_msg(msg).await;