mirror of
https://github.com/chatmail/core.git
synced 2026-04-27 02:16:29 +03:00
feat: allow plain domain in dcaccount: scheme
This is similar to old `dcaccount:` with URL, but creates a 9-character username on the client and avoids making an HTTPS request. The scheme is reused to avoid the apps needing to register for the new scheme. `http` support is removed because it was not working already, there is a check that the scheme is `https` when the URL is actually used and the core has no way to make HTTP requests without TLS.
This commit is contained in:
@@ -45,8 +45,8 @@ class ACFactory:
|
||||
"""Create a new configured account."""
|
||||
addr, password = self.get_credentials()
|
||||
account = self.get_unconfigured_account()
|
||||
params = {"addr": addr, "password": password}
|
||||
yield account.add_or_update_transport.future(params)
|
||||
domain = os.getenv("CHATMAIL_DOMAIN")
|
||||
yield account.add_transport_from_qr.future(f"dcaccount:{domain}")
|
||||
|
||||
assert account.is_configured()
|
||||
return account
|
||||
|
||||
@@ -816,7 +816,7 @@ def test_configured_imap_certificate_checks(acfactory):
|
||||
alice = acfactory.new_configured_account()
|
||||
|
||||
# Certificate checks should be configured (not None)
|
||||
assert "cert_automatic" in alice.get_info().used_account_settings
|
||||
assert "cert_strict" in alice.get_info().used_account_settings
|
||||
|
||||
# "cert_old_automatic" is the value old Delta Chat core versions used
|
||||
# to mean user entered "imap_certificate_checks=0" (Automatic)
|
||||
|
||||
53
src/qr.rs
53
src/qr.rs
@@ -9,6 +9,8 @@ pub use dclogin_scheme::LoginOptions;
|
||||
pub(crate) use dclogin_scheme::login_param_from_login_qr;
|
||||
use deltachat_contact_tools::{ContactAddress, addr_normalize, may_be_valid_addr};
|
||||
use percent_encoding::{NON_ALPHANUMERIC, percent_decode_str, percent_encode};
|
||||
use rand::TryRngCore as _;
|
||||
use rand::distr::{Alphanumeric, SampleString};
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::config::Config;
|
||||
@@ -543,21 +545,29 @@ async fn decode_ideltachat(context: &Context, prefix: &str, qr: &str) -> Result<
|
||||
.with_context(|| format!("failed to decode {prefix} QR code"))
|
||||
}
|
||||
|
||||
/// scheme: `DCACCOUNT:https://example.org/new_email?t=1w_7wDjgjelxeX884x96v3`
|
||||
/// scheme: `DCACCOUNT:example.org`
|
||||
/// or `DCACCOUNT:https://example.org/new`
|
||||
/// or `DCACCOUNT:https://example.org/new_email?t=1w_7wDjgjelxeX884x96v3`
|
||||
fn decode_account(qr: &str) -> Result<Qr> {
|
||||
let payload = qr
|
||||
.get(DCACCOUNT_SCHEME.len()..)
|
||||
.context("Invalid DCACCOUNT payload")?;
|
||||
let url = url::Url::parse(payload).context("Invalid account URL")?;
|
||||
if url.scheme() == "http" || url.scheme() == "https" {
|
||||
Ok(Qr::Account {
|
||||
domain: url
|
||||
.host_str()
|
||||
.context("can't extract account setup domain")?
|
||||
.to_string(),
|
||||
})
|
||||
if payload.starts_with("https://") {
|
||||
let url = url::Url::parse(payload).context("Invalid account URL")?;
|
||||
if url.scheme() == "https" {
|
||||
Ok(Qr::Account {
|
||||
domain: url
|
||||
.host_str()
|
||||
.context("can't extract account setup domain")?
|
||||
.to_string(),
|
||||
})
|
||||
} else {
|
||||
bail!("Bad scheme for account URL: {:?}.", url.scheme());
|
||||
}
|
||||
} else {
|
||||
bail!("Bad scheme for account URL: {:?}.", url.scheme());
|
||||
Ok(Qr::Account {
|
||||
domain: payload.to_string(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -659,15 +669,30 @@ pub(crate) async fn login_param_from_account_qr(
|
||||
context: &Context,
|
||||
qr: &str,
|
||||
) -> Result<EnteredLoginParam> {
|
||||
let url_str = qr
|
||||
let payload = qr
|
||||
.get(DCACCOUNT_SCHEME.len()..)
|
||||
.context("Invalid DCACCOUNT scheme")?;
|
||||
|
||||
if !url_str.starts_with(HTTPS_SCHEME) {
|
||||
bail!("DCACCOUNT QR codes must use HTTPS scheme");
|
||||
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 password = Alphanumeric.sample_string(rng, 50);
|
||||
|
||||
let param = EnteredLoginParam {
|
||||
addr,
|
||||
imap: EnteredServerLoginParam {
|
||||
password,
|
||||
..Default::default()
|
||||
},
|
||||
smtp: Default::default(),
|
||||
certificate_checks: EnteredCertificateChecks::Strict,
|
||||
oauth2: false,
|
||||
};
|
||||
return Ok(param);
|
||||
}
|
||||
|
||||
let (response_text, response_success) = post_empty(context, url_str).await?;
|
||||
let (response_text, response_success) = post_empty(context, payload).await?;
|
||||
if response_success {
|
||||
let CreateAccountSuccessResponse { password, email } = serde_json::from_str(&response_text)
|
||||
.with_context(|| {
|
||||
|
||||
@@ -643,30 +643,20 @@ async fn test_decode_dclogin_advanced_options() -> Result<()> {
|
||||
async fn test_decode_account() -> Result<()> {
|
||||
let ctx = TestContext::new().await;
|
||||
|
||||
let qr = check_qr(
|
||||
&ctx.ctx,
|
||||
for text in [
|
||||
"DCACCOUNT:example.org",
|
||||
"dcaccount:example.org",
|
||||
"DCACCOUNT:https://example.org/new_email?t=1w_7wDjgjelxeX884x96v3",
|
||||
)
|
||||
.await?;
|
||||
assert_eq!(
|
||||
qr,
|
||||
Qr::Account {
|
||||
domain: "example.org".to_string()
|
||||
}
|
||||
);
|
||||
|
||||
// Test it again with lowercased "dcaccount:" uri scheme
|
||||
let qr = check_qr(
|
||||
&ctx.ctx,
|
||||
"dcaccount:https://example.org/new_email?t=1w_7wDjgjelxeX884x96v3",
|
||||
)
|
||||
.await?;
|
||||
assert_eq!(
|
||||
qr,
|
||||
Qr::Account {
|
||||
domain: "example.org".to_string()
|
||||
}
|
||||
);
|
||||
] {
|
||||
let qr = check_qr(&ctx.ctx, text).await?;
|
||||
assert_eq!(
|
||||
qr,
|
||||
Qr::Account {
|
||||
domain: "example.org".to_string()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -734,25 +724,6 @@ async fn test_decode_tg_socks_proxy() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_decode_account_bad_scheme() {
|
||||
let ctx = TestContext::new().await;
|
||||
let res = check_qr(
|
||||
&ctx.ctx,
|
||||
"DCACCOUNT:ftp://example.org/new_email?t=1w_7wDjgjelxeX884x96v3",
|
||||
)
|
||||
.await;
|
||||
assert!(res.is_err());
|
||||
|
||||
// Test it again with lowercased "dcaccount:" uri scheme
|
||||
let res = check_qr(
|
||||
&ctx.ctx,
|
||||
"dcaccount:ftp://example.org/new_email?t=1w_7wDjgjelxeX884x96v3",
|
||||
)
|
||||
.await;
|
||||
assert!(res.is_err());
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_set_proxy_config_from_qr() -> Result<()> {
|
||||
let t = TestContext::new().await;
|
||||
|
||||
Reference in New Issue
Block a user