add dns_prefill attribute to entered login params and implement parsing

for it
This commit is contained in:
Simon Laux
2026-01-16 22:42:42 +01:00
parent 659d21aa9d
commit 252fc8480e
5 changed files with 65 additions and 1 deletions

View File

@@ -54,6 +54,9 @@ pub struct EnteredLoginParam {
/// If true, login via OAUTH2 (not recommended anymore).
/// Default: false
pub oauth2: Option<bool>,
/// IP addresses for prefilling DNS
pub dns_prefill: Vec<String>,
}
impl From<dc::EnteredLoginParam> for EnteredLoginParam {
@@ -75,6 +78,7 @@ impl From<dc::EnteredLoginParam> for EnteredLoginParam {
smtp_password: param.smtp.password.into_option(),
certificate_checks: certificate_checks.into_option(),
oauth2: param.oauth2.into_option(),
dns_prefill: param.dns_prefill,
}
}
}
@@ -101,6 +105,7 @@ impl TryFrom<EnteredLoginParam> for dc::EnteredLoginParam {
},
certificate_checks: param.certificate_checks.unwrap_or_default().into(),
oauth2: param.oauth2.unwrap_or_default(),
dns_prefill: param.dns_prefill,
})
}
}

View File

@@ -97,6 +97,9 @@ pub struct EnteredLoginParam {
/// If true, login via OAUTH2 (not recommended anymore)
pub oauth2: bool,
/// IP addresses for prefilling DNS
pub dns_prefill: Vec<String>,
}
impl EnteredLoginParam {
@@ -191,6 +194,7 @@ impl EnteredLoginParam {
},
certificate_checks,
oauth2,
dns_prefill: Default::default(),
})
}
@@ -360,6 +364,7 @@ mod tests {
},
certificate_checks: Default::default(),
oauth2: false,
dns_prefill: Default::default(),
};
param.save(&t).await?;
assert_eq!(

View File

@@ -12,6 +12,7 @@ use percent_encoding::{NON_ALPHANUMERIC, percent_decode_str, percent_encode};
use rand::TryRngCore as _;
use rand::distr::{Alphanumeric, SampleString};
use serde::Deserialize;
use url::Url;
use crate::config::Config;
use crate::contact::{Contact, ContactId, Origin};
@@ -656,6 +657,7 @@ async fn decode_ideltachat(context: &Context, prefix: &str, qr: &str) -> Result<
/// scheme: `DCACCOUNT:example.org`
/// or `DCACCOUNT:https://example.org/new`
/// or `DCACCOUNT:https://example.org/new_email?t=1w_7wDjgjelxeX884x96v3`
/// or `dcaccount:example.org?a=127.0.0.1,[::1]`
fn decode_account(qr: &str) -> Result<Qr> {
let payload = qr
.get(DCACCOUNT_SCHEME.len()..)
@@ -784,9 +786,33 @@ pub(crate) async fn login_param_from_account_qr(
if !payload.starts_with(HTTPS_SCHEME) {
let rng = &mut rand::rngs::OsRng.unwrap_err();
let username = Alphanumeric.sample_string(rng, 9);
let addr = username + "@" + payload;
let host = if let Some(start_of_query) = payload.find("?") {
payload
.get(..start_of_query)
.context("failed to ignore query part")?
} else {
payload
};
let addr = username + "@" + host;
let password = Alphanumeric.sample_string(rng, 50);
let dns_prefill: Vec<String> = match Url::parse(qr) {
Ok(url) => {
let options = url.query_pairs();
let parameter_map: BTreeMap<String, String> = options
.map(|(key, value)| (key.into_owned(), value.into_owned()))
.collect();
parameter_map
.get("a")
.map(|ips| ips.split(",").map(|s| s.to_owned()).collect())
.unwrap_or_default()
}
Err(err) => {
error!(context, "error parsing parameter of account url: {err}");
Default::default()
}
};
let param = EnteredLoginParam {
addr,
imap: EnteredServerLoginParam {
@@ -796,6 +822,7 @@ pub(crate) async fn login_param_from_account_qr(
smtp: Default::default(),
certificate_checks: EnteredCertificateChecks::Strict,
oauth2: false,
dns_prefill,
};
return Ok(param);
}
@@ -816,6 +843,7 @@ pub(crate) async fn login_param_from_account_qr(
smtp: Default::default(),
certificate_checks: EnteredCertificateChecks::Strict,
oauth2: false,
dns_prefill: Default::default(),
};
Ok(param)

View File

@@ -191,6 +191,7 @@ pub(crate) fn login_param_from_login_qr(
},
certificate_checks: certificate_checks.unwrap_or_default(),
oauth2: false,
dns_prefill: Default::default(),
};
Ok(param)
}

View File

@@ -711,6 +711,31 @@ async fn test_decode_account() -> Result<()> {
Ok(())
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_decode_account_with_dns_prefill() -> Result<()> {
let ctx = &TestContext::new().await;
for (qr, prefill_ips) in [
(
"dcaccount:example.org?a=127.0.0.1,[::1]",
vec!["127.0.0.1", "[::1]"],
),
(
"DCACCOUNT:example.org?a=127.0.0.1,[::1]",
vec!["127.0.0.1", "[::1]"],
),
("dcaccount:example.org?a=[::1]", vec!["[::1]"]),
("DCACCOUNT:example.org?a=127.0.0.1", vec!["127.0.0.1"]),
] {
let param = login_param_from_account_qr(ctx, qr).await?;
println!("addr {}", param.addr);
assert!(param.addr.ends_with("example.org"));
assert_eq!(param.dns_prefill, prefill_ips);
}
Ok(())
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_decode_tg_socks_proxy() -> Result<()> {
let t = TestContext::new().await;