mirror of
https://github.com/chatmail/core.git
synced 2026-08-18 06:36:29 +03:00
api!: remove all oauth support and drop DC_LP_AUTH flags
BREAKING CHANGE: removed oauth2 module, dc_get_oauth2_url FFI function, DC_LP_AUTH flags and configured/serverflags, and the oauth2 parameter/field from SMTP/IMAP clients, JSON-RPC interfaces, and CLI tools. also contains regenerated provider data after dropping oauth in the update script.
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -1412,7 +1412,6 @@ dependencies = [
|
||||
"sdp",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"sha-1",
|
||||
"sha2",
|
||||
"shadowsocks",
|
||||
|
||||
@@ -89,7 +89,6 @@ rusqlite = { workspace = true, features = ["sqlcipher"] }
|
||||
sanitize-filename = { workspace = true }
|
||||
sdp = "0.17.1"
|
||||
serde_json = { workspace = true }
|
||||
serde_urlencoded = "0.7.1"
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
sha-1 = "0.10"
|
||||
sha2 = "0.10"
|
||||
|
||||
@@ -503,7 +503,6 @@ char* dc_get_blobdir (const dc_context_t* context);
|
||||
* - `send_pw` = SMTP-password, guessed if left out
|
||||
* - `send_port` = SMTP-port, guessed if left out
|
||||
* - `send_security`= SMTP-socket, one of @ref DC_SOCKET, defaults to #DC_SOCKET_AUTO
|
||||
* - `server_flags` = IMAP-/SMTP-flags as a combination of @ref DC_LP flags, guessed if left out
|
||||
* - `proxy_enabled` = Proxy enabled. Disabled by default.
|
||||
* - `proxy_url` = Proxy URL. May contain multiple URLs separated by newline, but only the first one is used.
|
||||
* - `imap_certificate_checks` = how to check IMAP and SMTP certificates, one of the @ref DC_CERTCK flags, defaults to #DC_CERTCK_AUTO (0)
|
||||
@@ -590,36 +589,7 @@ int dc_set_config_from_qr (dc_context_t* context, const char* qr);
|
||||
char* dc_get_info (const dc_context_t* context);
|
||||
|
||||
|
||||
/**
|
||||
* Get URL that can be used to initiate an OAuth2 authorization.
|
||||
*
|
||||
* If an OAuth2 authorization is possible for a given e-mail address,
|
||||
* this function returns the URL that should be opened in a browser.
|
||||
*
|
||||
* If the user authorizes access,
|
||||
* the given redirect_uri is called by the provider.
|
||||
* It's up to the UI to handle this call.
|
||||
*
|
||||
* The provider will attach some parameters to the URL,
|
||||
* most important the parameter `code` that should be set as the `mail_pw`.
|
||||
* With `server_flags` set to #DC_LP_AUTH_OAUTH2,
|
||||
* dc_configure() can be called as usual afterwards.
|
||||
*
|
||||
* @memberof dc_context_t
|
||||
* @param context The context object.
|
||||
* @param addr E-mail address the user has entered.
|
||||
* In case the user selects a different e-mail address during
|
||||
* authorization, this is corrected in dc_configure()
|
||||
* @param redirect_uri URL that will get `code` that is used as `mail_pw` then.
|
||||
* Not all URLs are allowed here, however, the following should work:
|
||||
* `chat.delta:/PATH`, `http://localhost:PORT/PATH`,
|
||||
* `https://localhost:PORT/PATH`, `urn:ietf:wg:oauth:2.0:oob`
|
||||
* (the latter just displays the code the user can copy+paste then)
|
||||
* @return URL that can be opened in the browser to start OAuth2.
|
||||
* Returned strings must be released using dc_str_unref().
|
||||
* If OAuth2 is not possible for the given e-mail address, NULL is returned.
|
||||
*/
|
||||
char* dc_get_oauth2_url (dc_context_t* context, const char* addr, const char* redirect_uri);
|
||||
|
||||
|
||||
|
||||
#define DC_CONNECTIVITY_NOT_CONNECTED 1000
|
||||
@@ -713,7 +683,7 @@ int dc_get_push_state (dc_context_t* context);
|
||||
* to get the full configuration from well-known URLs.
|
||||
*
|
||||
* - If _more_ options as `mail_server`, `mail_port`, `send_server`,
|
||||
* `send_port`, `send_user` or `server_flags` are specified,
|
||||
* `send_port` or `send_user` are specified,
|
||||
* **autoconfigure/autodiscover is skipped**.
|
||||
*
|
||||
* While dc_configure() returns immediately,
|
||||
@@ -5736,41 +5706,6 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot);
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @defgroup DC_LP DC_LP
|
||||
*
|
||||
* Flags for configuring IMAP and SMTP servers.
|
||||
* These flags are optional
|
||||
* and may be set together with the username, password etc.
|
||||
* via dc_set_config() using the key "server_flags".
|
||||
*
|
||||
* @addtogroup DC_LP
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Force OAuth2 authorization. This flag does not skip automatic configuration.
|
||||
* Before calling dc_configure() with DC_LP_AUTH_OAUTH2 set,
|
||||
* the user has to confirm access at the URL returned by dc_get_oauth2_url().
|
||||
*/
|
||||
#define DC_LP_AUTH_OAUTH2 0x2
|
||||
|
||||
|
||||
/**
|
||||
* Force NORMAL authorization, this is the default.
|
||||
* If this flag is set, automatic configuration is skipped.
|
||||
*/
|
||||
#define DC_LP_AUTH_NORMAL 0x4
|
||||
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#define DC_LP_AUTH_FLAGS (DC_LP_AUTH_OAUTH2|DC_LP_AUTH_NORMAL) // if none of these flags are set, the default is chosen
|
||||
|
||||
/**
|
||||
* @defgroup DC_CERTCK DC_CERTCK
|
||||
*
|
||||
|
||||
@@ -401,32 +401,6 @@ pub unsafe extern "C" fn dc_get_push_state(context: *const dc_context_t) -> libc
|
||||
block_on(ctx.push_state()) as libc::c_int
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_get_oauth2_url(
|
||||
context: *mut dc_context_t,
|
||||
addr: *const libc::c_char,
|
||||
redirect: *const libc::c_char,
|
||||
) -> *mut libc::c_char {
|
||||
if context.is_null() {
|
||||
eprintln!("ignoring careless call to dc_get_oauth2_url()");
|
||||
return ptr::null_mut(); // NULL explicitly defined as "unknown"
|
||||
}
|
||||
let ctx = &*context;
|
||||
let addr = to_string_lossy(addr);
|
||||
let redirect = to_string_lossy(redirect);
|
||||
|
||||
block_on(async move {
|
||||
match oauth2::get_oauth2_url(ctx, &addr, &redirect)
|
||||
.await
|
||||
.context("dc_get_oauth2_url failed")
|
||||
.log_err(ctx)
|
||||
{
|
||||
Ok(Some(res)) => res.strdup(),
|
||||
Ok(None) | Err(_) => ptr::null_mut(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn spawn_configure(ctx: Context) {
|
||||
spawn(async move {
|
||||
ctx.configure()
|
||||
|
||||
@@ -66,10 +66,6 @@ pub struct EnteredLoginParam {
|
||||
/// invalid hostnames.
|
||||
/// Default: Automatic
|
||||
pub certificate_checks: Option<EnteredCertificateChecks>,
|
||||
|
||||
/// If true, login via OAUTH2 (not recommended anymore).
|
||||
/// Default: false
|
||||
pub oauth2: Option<bool>,
|
||||
}
|
||||
|
||||
impl From<dc::TransportListEntry> for TransportListEntry {
|
||||
@@ -100,7 +96,6 @@ impl From<dc::EnteredLoginParam> for EnteredLoginParam {
|
||||
smtp_user: param.smtp.user.into_option(),
|
||||
smtp_password: param.smtp.password.into_option(),
|
||||
certificate_checks: certificate_checks.into_option(),
|
||||
oauth2: param.oauth2.into_option(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -127,7 +122,6 @@ impl TryFrom<EnteredLoginParam> for dc::EnteredLoginParam {
|
||||
password: param.smtp_password.unwrap_or_default(),
|
||||
},
|
||||
certificate_checks: param.certificate_checks.unwrap_or_default().into(),
|
||||
oauth2: param.oauth2.unwrap_or_default(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,7 +319,6 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu
|
||||
info\n\
|
||||
set <configuration-key> [<value>]\n\
|
||||
get <configuration-key>\n\
|
||||
oauth2\n\
|
||||
configure\n\
|
||||
connect\n\
|
||||
disconnect\n\
|
||||
|
||||
@@ -11,9 +11,7 @@ use std::borrow::Cow::{self, Borrowed, Owned};
|
||||
|
||||
use anyhow::{bail, Error};
|
||||
use deltachat::chat::ChatId;
|
||||
use deltachat::config;
|
||||
use deltachat::context::*;
|
||||
use deltachat::oauth2::*;
|
||||
use deltachat::qr_code_generator::get_securejoin_qr_svg;
|
||||
use deltachat::securejoin::*;
|
||||
use deltachat::EventType;
|
||||
@@ -162,11 +160,10 @@ const IMEX_COMMANDS: [&str; 10] = [
|
||||
"stop",
|
||||
];
|
||||
|
||||
const DB_COMMANDS: [&str; 11] = [
|
||||
const DB_COMMANDS: [&str; 10] = [
|
||||
"info",
|
||||
"set",
|
||||
"get",
|
||||
"oauth2",
|
||||
"configure",
|
||||
"connect",
|
||||
"disconnect",
|
||||
@@ -425,19 +422,6 @@ async fn handle_cmd(
|
||||
"configure" => {
|
||||
ctx.configure().await?;
|
||||
}
|
||||
"oauth2" => {
|
||||
if let Some(addr) = ctx.get_config(config::Config::Addr).await? {
|
||||
if let Some(oauth2_url) =
|
||||
get_oauth2_url(&ctx, &addr, "chat.delta:/com.b44t.messenger").await?
|
||||
{
|
||||
println!("Open the following url, set mail_pw to the generated token and server_flags to 2:\n{oauth2_url}");
|
||||
} else {
|
||||
println!("OAuth2 not available for {addr}.");
|
||||
}
|
||||
} else {
|
||||
println!("oauth2: set addr first.");
|
||||
}
|
||||
}
|
||||
"clear" => {
|
||||
println!("\n\n\n");
|
||||
print!("\x1b[1;1H\x1b[2J");
|
||||
|
||||
@@ -231,14 +231,6 @@ class KeyGenType(IntEnum):
|
||||
RSA4096 = 3
|
||||
|
||||
|
||||
# "Lp" means "login parameters"
|
||||
class LpAuthFlag(IntEnum):
|
||||
"""Authorization flags."""
|
||||
|
||||
OAUTH2 = 0x2
|
||||
NORMAL = 0x4
|
||||
|
||||
|
||||
class MediaQuality(IntEnum):
|
||||
"""Media quality setting."""
|
||||
|
||||
|
||||
@@ -145,9 +145,6 @@ def process_data(data, file):
|
||||
opt = process_opt(data)
|
||||
config_defaults = process_config_defaults(data)
|
||||
|
||||
oauth2 = data.get("oauth2", "")
|
||||
oauth2 = "Some(Oauth2Authorizer::" + camel(oauth2) + ")" if oauth2 != "" else "None"
|
||||
|
||||
provider = ""
|
||||
before_login_hint = cleanstr(data.get("before_login_hint", "") or "")
|
||||
after_login_hint = cleanstr(data.get("after_login_hint", ""))
|
||||
@@ -165,7 +162,6 @@ def process_data(data, file):
|
||||
provider += " server: &[\n" + server + " ],\n"
|
||||
provider += " opt: " + opt + ",\n"
|
||||
provider += " config_defaults: " + config_defaults + ",\n"
|
||||
provider += " oauth2_authorizer: " + oauth2 + ",\n"
|
||||
provider += "};\n\n"
|
||||
else:
|
||||
raise TypeError("SMTP and IMAP must be specified together or left out both")
|
||||
@@ -180,7 +176,7 @@ def process_data(data, file):
|
||||
out_all += "// " + file.name + ": " + comment.strip(", ") + "\n"
|
||||
|
||||
# also add provider with no special things to do -
|
||||
# eg. _not_ supporting oauth2 is also an information and we can skip the mx-lookup in this case
|
||||
# eg. we can skip the mx-lookup in this case
|
||||
out_all += provider
|
||||
out_domains += domains
|
||||
out_ids += ids
|
||||
@@ -212,7 +208,7 @@ if __name__ == "__main__":
|
||||
"use crate::provider::Socket::*;\n"
|
||||
"use crate::provider::UsernamePattern::*;\n"
|
||||
"use crate::provider::{\n"
|
||||
" Config, ConfigDefault, Oauth2Authorizer, Provider, ProviderOptions, Server, Status,\n"
|
||||
" Config, ConfigDefault, Provider, ProviderOptions, Server, Status,\n"
|
||||
"};\n"
|
||||
"use std::collections::HashMap;\n\n"
|
||||
"use std::sync::LazyLock;\n\n"
|
||||
|
||||
@@ -118,15 +118,6 @@ pub enum Config {
|
||||
/// SMTP server security (e.g. TLS, STARTTLS).
|
||||
SendSecurity,
|
||||
|
||||
/// Deprecated(2026-04).
|
||||
/// Use EnteredLoginParam and add_transport{from_qr}()/list_transports() instead.
|
||||
///
|
||||
/// Whether to use OAuth 2.
|
||||
///
|
||||
/// Historically contained other bitflags, which are now deprecated.
|
||||
/// Should not be extended in the future, create new config keys instead.
|
||||
ServerFlags,
|
||||
|
||||
/// True if proxy is enabled.
|
||||
///
|
||||
/// Can be used to disable proxy without erasing known URLs.
|
||||
@@ -298,12 +289,6 @@ pub enum Config {
|
||||
/// Configured SMTP server password.
|
||||
ConfiguredSendPw,
|
||||
|
||||
/// Deprecated(2026-04).
|
||||
/// Use ConfiguredLoginParam and add_transport{from_qr}()/list_transports() instead.
|
||||
///
|
||||
/// Whether OAuth 2 is used with configured provider.
|
||||
ConfiguredServerFlags,
|
||||
|
||||
/// Configured folder for incoming messages.
|
||||
ConfiguredInboxFolder,
|
||||
|
||||
|
||||
@@ -32,7 +32,6 @@ pub use crate::login_param::EnteredLoginParam;
|
||||
use crate::login_param::{EnteredCertificateChecks, TransportListEntry};
|
||||
use crate::message::Message;
|
||||
use crate::net::proxy::ProxyConfig;
|
||||
use crate::oauth2::get_oauth2_addr;
|
||||
use crate::provider::{Protocol, Provider, Socket, UsernamePattern};
|
||||
use crate::qr::{login_param_from_account_qr, login_param_from_login_qr};
|
||||
use crate::smtp::Smtp;
|
||||
@@ -451,24 +450,7 @@ async fn get_configured_param(
|
||||
param.smtp.password.clone()
|
||||
};
|
||||
|
||||
let mut addr = param.addr.clone();
|
||||
if param.oauth2 {
|
||||
// the used oauth2 addr may differ, check this.
|
||||
// if get_oauth2_addr() is not available in the oauth2 implementation, just use the given one.
|
||||
progress!(ctx, 10);
|
||||
if let Some(oauth2_addr) = get_oauth2_addr(ctx, ¶m.addr, ¶m.imap.password)
|
||||
.await?
|
||||
.and_then(|e| e.parse().ok())
|
||||
{
|
||||
info!(ctx, "Authorized address is {}", oauth2_addr);
|
||||
addr = oauth2_addr;
|
||||
ctx.sql
|
||||
.set_raw_config("addr", Some(param.addr.as_str()))
|
||||
.await?;
|
||||
}
|
||||
progress!(ctx, 20);
|
||||
}
|
||||
// no oauth? - just continue it's no error
|
||||
let addr = param.addr.clone();
|
||||
|
||||
let parsed = EmailAddress::new(¶m.addr).context("Bad email-address")?;
|
||||
let param_domain = parsed.domain;
|
||||
@@ -618,7 +600,6 @@ async fn get_configured_param(
|
||||
ConfiguredCertificateChecks::AcceptInvalidCertificates
|
||||
}
|
||||
},
|
||||
oauth2: param.oauth2,
|
||||
};
|
||||
Ok(configured_login_param)
|
||||
}
|
||||
@@ -649,7 +630,6 @@ async fn configure(ctx: &Context, param: &EnteredLoginParam) -> Result<Option<&'
|
||||
&proxy_config2,
|
||||
&smtp_addr,
|
||||
strict_tls,
|
||||
configured_param.oauth2,
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
||||
@@ -162,25 +162,6 @@ pub const DC_DESIRED_TEXT_LINE_LEN: usize = 100;
|
||||
/// `char`s), not Unicode Grapheme Clusters.
|
||||
pub const DC_DESIRED_TEXT_LEN: usize = DC_DESIRED_TEXT_LINE_LEN * DC_DESIRED_TEXT_LINES;
|
||||
|
||||
// Flags for configuring IMAP and SMTP servers.
|
||||
// These flags are optional
|
||||
// and may be set together with the username, password etc.
|
||||
// via dc_set_config() using the key "server_flags".
|
||||
|
||||
/// Force OAuth2 authorization.
|
||||
///
|
||||
/// This flag does not skip automatic configuration.
|
||||
/// Before calling configure() with DC_LP_AUTH_OAUTH2 set,
|
||||
/// the user has to confirm access at the URL returned by dc_get_oauth2_url().
|
||||
pub const DC_LP_AUTH_OAUTH2: i32 = 0x2;
|
||||
|
||||
/// Force NORMAL authorization, this is the default.
|
||||
/// If this flag is set, automatic configuration is skipped.
|
||||
pub const DC_LP_AUTH_NORMAL: i32 = 0x4;
|
||||
|
||||
/// if none of these flags are set, the default is chosen
|
||||
pub const DC_LP_AUTH_FLAGS: i32 = DC_LP_AUTH_OAUTH2 | DC_LP_AUTH_NORMAL;
|
||||
|
||||
// max. weight of images to send w/o recoding
|
||||
pub const BALANCED_IMAGE_BYTES: usize = 500_000;
|
||||
pub const WORSE_IMAGE_BYTES: usize = 130_000;
|
||||
|
||||
@@ -231,8 +231,6 @@ pub struct InnerContext {
|
||||
/// This is a global mutex-like state for operations which should be modal in the
|
||||
/// clients.
|
||||
running_state: RwLock<RunningState>,
|
||||
/// Mutex to enforce only a single running oauth2 is running.
|
||||
pub(crate) oauth2_mutex: Mutex<()>,
|
||||
/// Mutex to prevent a race condition when a "your pw is wrong" warning is sent, resulting in multiple messages being sent.
|
||||
pub(crate) wrong_pw_warning_mutex: Mutex<()>,
|
||||
/// Mutex to prevent running housekeeping from multiple threads at once.
|
||||
@@ -484,7 +482,6 @@ impl Context {
|
||||
blobdir,
|
||||
running_state: RwLock::new(Default::default()),
|
||||
sql: Sql::new(dbfile),
|
||||
oauth2_mutex: Mutex::new(()),
|
||||
wrong_pw_warning_mutex: Mutex::new(()),
|
||||
housekeeping_mutex: Mutex::new(()),
|
||||
fetch_msgs_mutex: Mutex::new(()),
|
||||
|
||||
@@ -285,7 +285,6 @@ async fn test_get_info_completeness() {
|
||||
"send_pw",
|
||||
"send_port",
|
||||
"send_security",
|
||||
"server_flags",
|
||||
"skip_start_messages",
|
||||
"proxy_url", // May contain passwords, don't leak it to the logs.
|
||||
"socks5_enabled", // SOCKS5 options are deprecated.
|
||||
|
||||
48
src/imap.rs
48
src/imap.rs
@@ -34,7 +34,6 @@ use crate::message::{self, Message};
|
||||
use crate::mimeparser;
|
||||
use crate::net::proxy::ProxyConfig;
|
||||
use crate::net::session::SessionStream;
|
||||
use crate::oauth2::get_oauth2_access_token;
|
||||
use crate::push::encrypt_device_token;
|
||||
use crate::receive_imf::{
|
||||
ReceivedMsg, from_field_to_contact_id, get_prefetch_parent_message, receive_imf_inner,
|
||||
@@ -76,9 +75,6 @@ pub(crate) struct Imap {
|
||||
|
||||
pub(crate) idle_interrupt_receiver: Receiver<()>,
|
||||
|
||||
/// Email address.
|
||||
pub(crate) addr: String,
|
||||
|
||||
/// Login parameters.
|
||||
lp: Vec<ConfiguredServerLoginParam>,
|
||||
|
||||
@@ -90,8 +86,6 @@ pub(crate) struct Imap {
|
||||
|
||||
strict_tls: bool,
|
||||
|
||||
oauth2: bool,
|
||||
|
||||
/// Watched folder.
|
||||
pub(crate) folder: String,
|
||||
|
||||
@@ -118,12 +112,6 @@ pub(crate) struct Imap {
|
||||
pub(crate) resync_request_receiver: async_channel::Receiver<()>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct OAuth2 {
|
||||
user: String,
|
||||
access_token: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub(crate) struct ServerMetadata {
|
||||
/// IMAP METADATA `/shared/comment` as defined in
|
||||
@@ -148,17 +136,6 @@ pub(crate) struct ServerMetadata {
|
||||
pub ice_servers_expiration_timestamp: i64,
|
||||
}
|
||||
|
||||
impl async_imap::Authenticator for OAuth2 {
|
||||
type Response = String;
|
||||
|
||||
fn process(&mut self, _data: &[u8]) -> Self::Response {
|
||||
format!(
|
||||
"user={}\x01auth=Bearer {}\x01\x01",
|
||||
self.user, self.access_token
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Display, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum FolderMeaning {
|
||||
Unknown,
|
||||
@@ -250,9 +227,7 @@ impl Imap {
|
||||
let lp = param.imap.clone();
|
||||
let password = param.imap_password.clone();
|
||||
let proxy_config = ProxyConfig::load(context).await?;
|
||||
let addr = ¶m.addr;
|
||||
let strict_tls = param.strict_tls(proxy_config.is_some());
|
||||
let oauth2 = param.oauth2;
|
||||
let folder = param
|
||||
.imap_folder
|
||||
.clone()
|
||||
@@ -262,12 +237,10 @@ impl Imap {
|
||||
Ok(Imap {
|
||||
transport_id,
|
||||
idle_interrupt_receiver,
|
||||
addr: addr.to_string(),
|
||||
lp,
|
||||
password,
|
||||
proxy_config,
|
||||
strict_tls,
|
||||
oauth2,
|
||||
folder,
|
||||
authentication_failed_once: false,
|
||||
connectivity: Default::default(),
|
||||
@@ -376,25 +349,8 @@ impl Imap {
|
||||
let imap_user: &str = lp.user.as_ref();
|
||||
let imap_pw: &str = &self.password;
|
||||
|
||||
let login_res = if self.oauth2 {
|
||||
info!(context, "Logging into IMAP server with OAuth 2.");
|
||||
let addr: &str = self.addr.as_ref();
|
||||
|
||||
let token = get_oauth2_access_token(context, addr, imap_pw, true)
|
||||
.await?
|
||||
.context("IMAP could not get OAUTH token")?;
|
||||
let auth = OAuth2 {
|
||||
user: imap_user.into(),
|
||||
access_token: token,
|
||||
};
|
||||
client
|
||||
.authenticate("XOAUTH2", auth)
|
||||
.await
|
||||
.map(|session| (session, None))
|
||||
} else {
|
||||
info!(context, "Logging into IMAP server with LOGIN.");
|
||||
client.login(imap_user, imap_pw).await
|
||||
};
|
||||
info!(context, "Logging into IMAP server with LOGIN.");
|
||||
let login_res = client.login(imap_user, imap_pw).await;
|
||||
|
||||
match login_res {
|
||||
Ok((mut session, login_capabilities_opt)) => {
|
||||
|
||||
@@ -122,19 +122,6 @@ impl Client {
|
||||
Ok((session, capabilities))
|
||||
}
|
||||
|
||||
pub(crate) async fn authenticate(
|
||||
self,
|
||||
auth_type: &str,
|
||||
authenticator: impl async_imap::Authenticator,
|
||||
) -> Result<ImapSession<Box<dyn SessionStream>>> {
|
||||
let Client { inner, .. } = self;
|
||||
let session = inner
|
||||
.authenticate(auth_type, authenticator)
|
||||
.await
|
||||
.map_err(|(err, _client)| err)?;
|
||||
Ok(session)
|
||||
}
|
||||
|
||||
async fn connection_attempt(
|
||||
context: Context,
|
||||
host: String,
|
||||
|
||||
@@ -76,7 +76,6 @@ pub mod login_param;
|
||||
pub mod message;
|
||||
mod mimefactory;
|
||||
pub mod mimeparser;
|
||||
pub mod oauth2;
|
||||
mod param;
|
||||
#[cfg(not(feature = "internals"))]
|
||||
mod pgp;
|
||||
|
||||
@@ -13,7 +13,6 @@ use num_traits::ToPrimitive as _;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::constants::{DC_LP_AUTH_FLAGS, DC_LP_AUTH_OAUTH2};
|
||||
use crate::context::Context;
|
||||
pub use crate::net::proxy::ProxyConfig;
|
||||
pub use crate::provider::Socket;
|
||||
@@ -142,9 +141,6 @@ pub struct EnteredLoginParam {
|
||||
/// TLS options: whether to allow invalid certificates and/or
|
||||
/// invalid hostnames
|
||||
pub certificate_checks: EnteredCertificateChecks,
|
||||
|
||||
/// If true, login via OAUTH2 (not recommended anymore)
|
||||
pub oauth2: bool,
|
||||
}
|
||||
|
||||
impl EnteredLoginParam {
|
||||
@@ -222,12 +218,6 @@ impl EnteredLoginParam {
|
||||
.await?
|
||||
.unwrap_or_default();
|
||||
|
||||
let server_flags = context
|
||||
.get_config_parsed::<i32>(Config::ServerFlags)
|
||||
.await?
|
||||
.unwrap_or_default();
|
||||
let oauth2 = matches!(server_flags & DC_LP_AUTH_FLAGS, DC_LP_AUTH_OAUTH2);
|
||||
|
||||
Ok(EnteredLoginParam {
|
||||
addr,
|
||||
imap: EnteredImapLoginParam {
|
||||
@@ -246,7 +236,6 @@ impl EnteredLoginParam {
|
||||
password: send_pw,
|
||||
},
|
||||
certificate_checks,
|
||||
oauth2,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -303,15 +292,6 @@ impl EnteredLoginParam {
|
||||
)
|
||||
.await?;
|
||||
|
||||
let server_flags = if self.oauth2 {
|
||||
Some(DC_LP_AUTH_OAUTH2.to_string())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
context
|
||||
.set_config(Config::ServerFlags, server_flags.as_deref())
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -323,7 +303,7 @@ impl fmt::Display for EnteredLoginParam {
|
||||
|
||||
write!(
|
||||
f,
|
||||
"{} imap:{}:{}:{}:{}:{}:{} smtp:{}:{}:{}:{}:{}:{} cert_{}",
|
||||
"{} imap:{}:{}:{}:{}:{} smtp:{}:{}:{}:{}:{} cert_{}",
|
||||
unset_empty(&self.addr),
|
||||
unset_empty(&self.imap.user),
|
||||
if !self.imap.password.is_empty() {
|
||||
@@ -334,7 +314,6 @@ impl fmt::Display for EnteredLoginParam {
|
||||
unset_empty(&self.imap.server),
|
||||
self.imap.port,
|
||||
self.imap.security,
|
||||
if self.oauth2 { "OAUTH2" } else { "AUTH_NORMAL" },
|
||||
unset_empty(&self.smtp.user),
|
||||
if !self.smtp.password.is_empty() {
|
||||
pw
|
||||
@@ -344,7 +323,6 @@ impl fmt::Display for EnteredLoginParam {
|
||||
unset_empty(&self.smtp.server),
|
||||
self.smtp.port,
|
||||
self.smtp.security,
|
||||
if self.oauth2 { "OAUTH2" } else { "AUTH_NORMAL" },
|
||||
self.certificate_checks
|
||||
)
|
||||
}
|
||||
@@ -419,7 +397,6 @@ mod tests {
|
||||
password: "".to_string(),
|
||||
},
|
||||
certificate_checks: Default::default(),
|
||||
oauth2: false,
|
||||
};
|
||||
param.save_legacy(&t).await?;
|
||||
assert_eq!(
|
||||
|
||||
@@ -5,7 +5,6 @@ use bytes::Bytes;
|
||||
use http_body_util::BodyExt;
|
||||
use hyper_util::rt::TokioIo;
|
||||
use mime::Mime;
|
||||
use serde::Serialize;
|
||||
use tokio::fs;
|
||||
|
||||
use crate::blob::BlobObject;
|
||||
@@ -453,37 +452,6 @@ pub(crate) async fn post_string(context: &Context, url: &str, body: String) -> R
|
||||
Ok(response.status().is_success())
|
||||
}
|
||||
|
||||
/// Sends a POST request with x-www-form-urlencoded data.
|
||||
///
|
||||
/// Does not follow redirects.
|
||||
pub(crate) async fn post_form<T: Serialize + ?Sized>(
|
||||
context: &Context,
|
||||
url: &str,
|
||||
form: &T,
|
||||
) -> Result<Bytes> {
|
||||
let parsed_url = url
|
||||
.parse::<hyper::Uri>()
|
||||
.with_context(|| format!("Failed to parse URL {url:?}"))?;
|
||||
let scheme = parsed_url.scheme_str().context("URL has no scheme")?;
|
||||
if scheme != "https" {
|
||||
bail!("POST requests to non-HTTPS URLs are not allowed");
|
||||
}
|
||||
|
||||
let encoded_body = serde_urlencoded::to_string(form).context("Failed to encode data")?;
|
||||
let mut sender = get_http_sender(context, parsed_url.clone(), true).await?;
|
||||
let authority = parsed_url
|
||||
.authority()
|
||||
.context("URL has no authority")?
|
||||
.clone();
|
||||
let request = hyper::Request::post(parsed_url)
|
||||
.header(hyper::header::HOST, authority.as_str())
|
||||
.header("content-type", "application/x-www-form-urlencoded")
|
||||
.body(encoded_body)?;
|
||||
let response = sender.send_request(request).await?;
|
||||
let bytes = response.collect().await?.to_bytes();
|
||||
Ok(bytes)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
398
src/oauth2.rs
398
src/oauth2.rs
@@ -1,398 +0,0 @@
|
||||
//! OAuth 2 module.
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use anyhow::{Context as _, Result};
|
||||
use percent_encoding::{NON_ALPHANUMERIC, utf8_percent_encode};
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::log::warn;
|
||||
use crate::net::http::post_form;
|
||||
use crate::net::read_url_blob;
|
||||
use crate::provider;
|
||||
use crate::provider::Oauth2Authorizer;
|
||||
use crate::tools::time;
|
||||
|
||||
const OAUTH2_YANDEX: Oauth2 = Oauth2 {
|
||||
// see <https://tech.yandex.com/oauth/doc/dg/reference/auto-code-client-docpage/>
|
||||
client_id: "c4d0b6735fc8420a816d7e1303469341",
|
||||
get_code: "https://oauth.yandex.com/authorize?client_id=$CLIENT_ID&response_type=code&scope=mail%3Aimap_full%20mail%3Asmtp&force_confirm=true",
|
||||
init_token: "https://oauth.yandex.com/token?grant_type=authorization_code&code=$CODE&client_id=$CLIENT_ID&client_secret=58b8c6e94cf44fbe952da8511955dacf",
|
||||
refresh_token: "https://oauth.yandex.com/token?grant_type=refresh_token&refresh_token=$REFRESH_TOKEN&client_id=$CLIENT_ID&client_secret=58b8c6e94cf44fbe952da8511955dacf",
|
||||
get_userinfo: None,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
struct Oauth2 {
|
||||
client_id: &'static str,
|
||||
get_code: &'static str,
|
||||
init_token: &'static str,
|
||||
refresh_token: &'static str,
|
||||
get_userinfo: Option<&'static str>,
|
||||
}
|
||||
|
||||
/// OAuth 2 Access Token Response
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[allow(dead_code)]
|
||||
struct Response {
|
||||
// Should always be there according to: <https://www.oauth.com/oauth2-servers/access-tokens/access-token-response/>
|
||||
// but previous code handled its abscense.
|
||||
access_token: Option<String>,
|
||||
token_type: String,
|
||||
/// Duration of time the token is granted for, in seconds
|
||||
expires_in: Option<u64>,
|
||||
refresh_token: Option<String>,
|
||||
scope: Option<String>,
|
||||
}
|
||||
|
||||
/// Returns URL that should be opened in the browser
|
||||
/// if OAuth 2 is supported for this address.
|
||||
pub async fn get_oauth2_url(
|
||||
context: &Context,
|
||||
addr: &str,
|
||||
redirect_uri: &str,
|
||||
) -> Result<Option<String>> {
|
||||
if let Some(oauth2) = Oauth2::from_address(addr) {
|
||||
context
|
||||
.sql
|
||||
.set_raw_config("oauth2_pending_redirect_uri", Some(redirect_uri))
|
||||
.await?;
|
||||
let oauth2_url = replace_in_uri(oauth2.get_code, "$CLIENT_ID", oauth2.client_id);
|
||||
let oauth2_url = replace_in_uri(&oauth2_url, "$REDIRECT_URI", redirect_uri);
|
||||
|
||||
Ok(Some(oauth2_url))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
#[expect(clippy::arithmetic_side_effects)]
|
||||
pub(crate) async fn get_oauth2_access_token(
|
||||
context: &Context,
|
||||
addr: &str,
|
||||
code: &str,
|
||||
regenerate: bool,
|
||||
) -> Result<Option<String>> {
|
||||
if let Some(oauth2) = Oauth2::from_address(addr) {
|
||||
let lock = context.oauth2_mutex.lock().await;
|
||||
|
||||
// read generated token
|
||||
if !regenerate && !is_expired(context).await? {
|
||||
let access_token = context.sql.get_raw_config("oauth2_access_token").await?;
|
||||
if access_token.is_some() {
|
||||
// success
|
||||
return Ok(access_token);
|
||||
}
|
||||
}
|
||||
|
||||
// generate new token: build & call auth url
|
||||
let refresh_token = context.sql.get_raw_config("oauth2_refresh_token").await?;
|
||||
let refresh_token_for = context
|
||||
.sql
|
||||
.get_raw_config("oauth2_refresh_token_for")
|
||||
.await?
|
||||
.unwrap_or_else(|| "unset".into());
|
||||
|
||||
let (redirect_uri, token_url, update_redirect_uri_on_success) =
|
||||
if refresh_token.is_none() || refresh_token_for != code {
|
||||
info!(context, "Generate OAuth2 refresh_token and access_token...",);
|
||||
(
|
||||
context
|
||||
.sql
|
||||
.get_raw_config("oauth2_pending_redirect_uri")
|
||||
.await?
|
||||
.unwrap_or_else(|| "unset".into()),
|
||||
oauth2.init_token,
|
||||
true,
|
||||
)
|
||||
} else {
|
||||
info!(
|
||||
context,
|
||||
"Regenerate OAuth2 access_token by refresh_token...",
|
||||
);
|
||||
(
|
||||
context
|
||||
.sql
|
||||
.get_raw_config("oauth2_redirect_uri")
|
||||
.await?
|
||||
.unwrap_or_else(|| "unset".into()),
|
||||
oauth2.refresh_token,
|
||||
false,
|
||||
)
|
||||
};
|
||||
|
||||
// to allow easier specification of different configurations,
|
||||
// token_url is in GET-method-format, sth. as <https://domain?param1=val1¶m2=val2> -
|
||||
// convert this to POST-format ...
|
||||
let mut parts = token_url.splitn(2, '?');
|
||||
let post_url = parts.next().unwrap_or_default();
|
||||
let post_args = parts.next().unwrap_or_default();
|
||||
let mut post_param = HashMap::new();
|
||||
for key_value_pair in post_args.split('&') {
|
||||
let mut parts = key_value_pair.splitn(2, '=');
|
||||
let key = parts.next().unwrap_or_default();
|
||||
let mut value = parts.next().unwrap_or_default();
|
||||
|
||||
if value == "$CLIENT_ID" {
|
||||
value = oauth2.client_id;
|
||||
} else if value == "$REDIRECT_URI" {
|
||||
value = &redirect_uri;
|
||||
} else if value == "$CODE" {
|
||||
value = code;
|
||||
} else if value == "$REFRESH_TOKEN"
|
||||
&& let Some(refresh_token) = refresh_token.as_ref()
|
||||
{
|
||||
value = refresh_token;
|
||||
}
|
||||
|
||||
post_param.insert(key, value);
|
||||
}
|
||||
|
||||
// ... and POST
|
||||
|
||||
let response: Response = match post_form(context, post_url, &post_param).await {
|
||||
Ok(resp) => match serde_json::from_slice(&resp) {
|
||||
Ok(response) => response,
|
||||
Err(err) => {
|
||||
warn!(
|
||||
context,
|
||||
"Failed to parse OAuth2 JSON response from {token_url}: {err:#}."
|
||||
);
|
||||
return Ok(None);
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
warn!(context, "Error calling OAuth2 at {token_url}: {err:#}.");
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
|
||||
// update refresh_token if given, typically on the first round, but we update it later as well.
|
||||
if let Some(ref token) = response.refresh_token {
|
||||
context
|
||||
.sql
|
||||
.set_raw_config("oauth2_refresh_token", Some(token))
|
||||
.await?;
|
||||
context
|
||||
.sql
|
||||
.set_raw_config("oauth2_refresh_token_for", Some(code))
|
||||
.await?;
|
||||
}
|
||||
|
||||
// after that, save the access token.
|
||||
// if it's unset, we may get it in the next round as we have the refresh_token now.
|
||||
if let Some(ref token) = response.access_token {
|
||||
context
|
||||
.sql
|
||||
.set_raw_config("oauth2_access_token", Some(token))
|
||||
.await?;
|
||||
let expires_in = response
|
||||
.expires_in
|
||||
// refresh a bit before
|
||||
.map(|t| time() + t as i64 - 5)
|
||||
.unwrap_or_else(|| 0);
|
||||
context
|
||||
.sql
|
||||
.set_raw_config_int64("oauth2_timestamp_expires", expires_in)
|
||||
.await?;
|
||||
|
||||
if update_redirect_uri_on_success {
|
||||
context
|
||||
.sql
|
||||
.set_raw_config("oauth2_redirect_uri", Some(redirect_uri.as_ref()))
|
||||
.await?;
|
||||
}
|
||||
} else {
|
||||
warn!(context, "Failed to find OAuth2 access token");
|
||||
}
|
||||
|
||||
drop(lock);
|
||||
|
||||
Ok(response.access_token)
|
||||
} else {
|
||||
warn!(context, "Internal OAuth2 error: 2");
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn get_oauth2_addr(
|
||||
context: &Context,
|
||||
addr: &str,
|
||||
code: &str,
|
||||
) -> Result<Option<String>> {
|
||||
let oauth2 = match Oauth2::from_address(addr) {
|
||||
Some(o) => o,
|
||||
None => return Ok(None),
|
||||
};
|
||||
if oauth2.get_userinfo.is_none() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
if let Some(access_token) = get_oauth2_access_token(context, addr, code, false).await? {
|
||||
let addr_out = match oauth2.get_addr(context, &access_token).await {
|
||||
Ok(addr) => addr,
|
||||
Err(err) => {
|
||||
warn!(context, "Error getting addr: {err:#}.");
|
||||
None
|
||||
}
|
||||
};
|
||||
if addr_out.is_none() {
|
||||
// regenerate
|
||||
if let Some(access_token) = get_oauth2_access_token(context, addr, code, true).await? {
|
||||
Ok(oauth2
|
||||
.get_addr(context, &access_token)
|
||||
.await
|
||||
.unwrap_or_default())
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
} else {
|
||||
Ok(addr_out)
|
||||
}
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
impl Oauth2 {
|
||||
#[expect(clippy::arithmetic_side_effects)]
|
||||
fn from_address(addr: &str) -> Option<Self> {
|
||||
let addr_normalized = normalize_addr(addr);
|
||||
if let Some(domain) = addr_normalized
|
||||
.find('@')
|
||||
.map(|index| addr_normalized.split_at(index + 1).1)
|
||||
&& let Some(oauth2_authorizer) = provider::get_provider_info(domain)
|
||||
.and_then(|provider| provider.oauth2_authorizer.as_ref())
|
||||
{
|
||||
return Some(match oauth2_authorizer {
|
||||
Oauth2Authorizer::Yandex => OAUTH2_YANDEX,
|
||||
});
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
async fn get_addr(&self, context: &Context, access_token: &str) -> Result<Option<String>> {
|
||||
let userinfo_url = self.get_userinfo.unwrap_or("");
|
||||
let userinfo_url = replace_in_uri(userinfo_url, "$ACCESS_TOKEN", access_token);
|
||||
|
||||
// should returns sth. as
|
||||
// {
|
||||
// "id": "100000000831024152393",
|
||||
// "email": "NAME@gmail.com",
|
||||
// "verified_email": true,
|
||||
// "picture": "https://lh4.googleusercontent.com/-Gj5jh_9R0BY/AAAAAAAAAAI/AAAAAAAAAAA/IAjtjfjtjNA/photo.jpg"
|
||||
// }
|
||||
|
||||
let response = read_url_blob(context, &userinfo_url).await?;
|
||||
let parsed: HashMap<String, serde_json::Value> =
|
||||
serde_json::from_slice(&response.blob).context("Error getting userinfo")?;
|
||||
// CAVE: serde_json::Value.as_str() removes the quotes of json-strings
|
||||
// but serde_json::Value.to_string() does not!
|
||||
if let Some(addr) = parsed.get("email") {
|
||||
if let Some(s) = addr.as_str() {
|
||||
Ok(Some(s.to_string()))
|
||||
} else {
|
||||
warn!(context, "E-mail in userinfo is not a string: {}", addr);
|
||||
Ok(None)
|
||||
}
|
||||
} else {
|
||||
warn!(context, "E-mail missing in userinfo.");
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn is_expired(context: &Context) -> Result<bool> {
|
||||
let expire_timestamp = context
|
||||
.sql
|
||||
.get_raw_config_int64("oauth2_timestamp_expires")
|
||||
.await?
|
||||
.unwrap_or_default();
|
||||
|
||||
if expire_timestamp <= 0 {
|
||||
return Ok(false);
|
||||
}
|
||||
if expire_timestamp > time() {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn replace_in_uri(uri: &str, key: &str, value: &str) -> String {
|
||||
let value_urlencoded = utf8_percent_encode(value, NON_ALPHANUMERIC).to_string();
|
||||
uri.replace(key, &value_urlencoded)
|
||||
}
|
||||
|
||||
fn normalize_addr(addr: &str) -> &str {
|
||||
let normalized = addr.trim();
|
||||
normalized.trim_start_matches("mailto:")
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::test_utils::TestContext;
|
||||
|
||||
#[test]
|
||||
fn test_normalize_addr() {
|
||||
assert_eq!(normalize_addr(" hello@mail.de "), "hello@mail.de");
|
||||
assert_eq!(normalize_addr("mailto:hello@mail.de "), "hello@mail.de");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_replace_in_uri() {
|
||||
assert_eq!(
|
||||
replace_in_uri("helloworld", "world", "a-b c"),
|
||||
"helloa%2Db%20c"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_oauth_from_address() {
|
||||
// Delta Chat does not have working Gmail client ID anymore.
|
||||
assert_eq!(Oauth2::from_address("hello@gmail.com"), None);
|
||||
assert_eq!(Oauth2::from_address("hello@googlemail.com"), None);
|
||||
|
||||
assert_eq!(
|
||||
Oauth2::from_address("hello@yandex.com"),
|
||||
Some(OAUTH2_YANDEX)
|
||||
);
|
||||
assert_eq!(Oauth2::from_address("hello@yandex.ru"), Some(OAUTH2_YANDEX));
|
||||
assert_eq!(Oauth2::from_address("hello@web.de"), None);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_get_oauth2_addr() {
|
||||
let ctx = TestContext::new().await;
|
||||
let addr = "dignifiedquire@gmail.com";
|
||||
let code = "fail";
|
||||
let res = get_oauth2_addr(&ctx.ctx, addr, code).await.unwrap();
|
||||
// this should fail as it is an invalid password
|
||||
assert_eq!(res, None);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_get_oauth2_url() {
|
||||
let ctx = TestContext::new().await;
|
||||
let addr = "example@yandex.com";
|
||||
let redirect_uri = "chat.delta:/com.b44t.messenger";
|
||||
let res = get_oauth2_url(&ctx.ctx, addr, redirect_uri).await.unwrap();
|
||||
|
||||
assert_eq!(res, Some("https://oauth.yandex.com/authorize?client_id=c4d0b6735fc8420a816d7e1303469341&response_type=code&scope=mail%3Aimap_full%20mail%3Asmtp&force_confirm=true".into()));
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_get_oauth2_token() {
|
||||
let ctx = TestContext::new().await;
|
||||
let addr = "dignifiedquire@gmail.com";
|
||||
let code = "fail";
|
||||
let res = get_oauth2_access_token(&ctx.ctx, addr, code, false)
|
||||
.await
|
||||
.unwrap();
|
||||
// this should fail as it is an invalid password
|
||||
assert_eq!(res, None);
|
||||
}
|
||||
}
|
||||
@@ -76,13 +76,6 @@ pub enum UsernamePattern {
|
||||
Emaillocalpart = 2,
|
||||
}
|
||||
|
||||
/// Type of OAuth 2 authorization.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum Oauth2Authorizer {
|
||||
/// Yandex.
|
||||
Yandex,
|
||||
}
|
||||
|
||||
/// Email server endpoint.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Server {
|
||||
@@ -136,9 +129,6 @@ pub struct Provider {
|
||||
/// Default configuration values to set when provider is configured.
|
||||
pub config_defaults: Option<&'static [ConfigDefault]>,
|
||||
|
||||
/// Type of OAuth 2 authorization if provider supports it.
|
||||
pub oauth2_authorizer: Option<Oauth2Authorizer>,
|
||||
|
||||
/// Options with good defaults.
|
||||
pub opt: ProviderOptions,
|
||||
}
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
use crate::provider::Protocol::*;
|
||||
use crate::provider::Socket::*;
|
||||
use crate::provider::UsernamePattern::*;
|
||||
use crate::provider::{
|
||||
Config, ConfigDefault, Oauth2Authorizer, Provider, ProviderOptions, Server, Status,
|
||||
};
|
||||
use crate::provider::{Config, ConfigDefault, Provider, ProviderOptions, Server, Status};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use std::sync::LazyLock;
|
||||
@@ -35,7 +33,6 @@ static P_163: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// aktivix.org.md: aktivix.org
|
||||
@@ -63,7 +60,6 @@ static P_AKTIVIX_ORG: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// aliyun.md: aliyun.com
|
||||
@@ -91,7 +87,6 @@ static P_ALIYUN: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// aol.md: aol.com
|
||||
@@ -119,7 +114,6 @@ static P_AOL: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// arcor.de.md: arcor.de
|
||||
@@ -147,7 +141,6 @@ static P_ARCOR_DE: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// autistici.org.md: autistici.org
|
||||
@@ -175,7 +168,6 @@ static P_AUTISTICI_ORG: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// blindzeln.org.md: delta.blinzeln.de, delta.blindzeln.org
|
||||
@@ -203,7 +195,6 @@ static P_BLINDZELN_ORG: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// bluewin.ch.md: bluewin.ch
|
||||
@@ -231,7 +222,6 @@ static P_BLUEWIN_CH: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// chello.at.md: chello.at
|
||||
@@ -259,7 +249,6 @@ static P_CHELLO_AT: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// comcast.md: xfinity.com, comcast.net
|
||||
@@ -272,7 +261,6 @@ static P_COMCAST: Provider = Provider {
|
||||
server: &[],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// dismail.de.md: dismail.de
|
||||
@@ -285,7 +273,6 @@ static P_DISMAIL_DE: Provider = Provider {
|
||||
server: &[],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// disroot.md: disroot.org
|
||||
@@ -313,7 +300,6 @@ static P_DISROOT: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// e.email.md: e.email
|
||||
@@ -341,7 +327,6 @@ static P_E_EMAIL: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// espiv.net.md: espiv.net
|
||||
@@ -354,7 +339,6 @@ static P_ESPIV_NET: Provider = Provider {
|
||||
server: &[],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// example.com.md: example.com, example.org, example.net
|
||||
@@ -382,7 +366,6 @@ static P_EXAMPLE_COM: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// fastmail.md: 123mail.org, 150mail.com, 150ml.com, 16mail.com, 2-mail.com, 4email.net, 50mail.com, airpost.net, allmail.net, bestmail.us, cluemail.com, elitemail.org, emailcorner.net, emailengine.net, emailengine.org, emailgroups.net, emailplus.org, emailuser.net, eml.cc, f-m.fm, fast-email.com, fast-mail.org, fastem.com, fastemail.us, fastemailer.com, fastest.cc, fastimap.com, fastmail.cn, fastmail.co.uk, fastmail.com, fastmail.com.au, fastmail.de, fastmail.es, fastmail.fm, fastmail.fr, fastmail.im, fastmail.in, fastmail.jp, fastmail.mx, fastmail.net, fastmail.nl, fastmail.org, fastmail.se, fastmail.to, fastmail.tw, fastmail.uk, fastmail.us, fastmailbox.net, fastmessaging.com, fea.st, fmail.co.uk, fmailbox.com, fmgirl.com, fmguy.com, ftml.net, h-mail.us, hailmail.net, imap-mail.com, imap.cc, imapmail.org, inoutbox.com, internet-e-mail.com, internet-mail.org, internetemails.net, internetmailing.net, jetemail.net, justemail.net, letterboxes.org, mail-central.com, mail-page.com, mailandftp.com, mailas.com, mailbolt.com, mailc.net, mailcan.com, mailforce.net, mailftp.com, mailhaven.com, mailingaddress.org, mailite.com, mailmight.com, mailnew.com, mailsent.net, mailservice.ms, mailup.net, mailworks.org, ml1.net, mm.st, myfastmail.com, mymacmail.com, nospammail.net, ownmail.net, petml.com, postinbox.com, postpro.net, proinbox.com, promessage.com, realemail.net, reallyfast.biz, reallyfast.info, rushpost.com, sent.as, sent.at, sent.com, speedpost.net, speedymail.org, ssl-mail.com, swift-mail.com, the-fastest.net, the-quickest.com, theinternetemail.com, veryfast.biz, veryspeedy.net, warpmail.net, xsmail.com, yepmail.net, your-mail.com
|
||||
@@ -410,7 +393,6 @@ static P_FASTMAIL: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// firemail.de.md: firemail.at, firemail.de
|
||||
@@ -423,7 +405,6 @@ static P_FIREMAIL_DE: Provider = Provider {
|
||||
server: &[],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// freenet.de.md: freenet.de
|
||||
@@ -465,7 +446,6 @@ static P_FREENET_DE: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// gmail.md: gmail.com, googlemail.com, google.com
|
||||
@@ -493,7 +473,6 @@ static P_GMAIL: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// gmx.net.md: gmx.net, gmx.de, gmx.at, gmx.ch, gmx.org, gmx.eu, gmx.info, gmx.biz, gmx.com
|
||||
@@ -528,7 +507,6 @@ static P_GMX_NET: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// hermes.radio.md: *.hermes.radio, *.aco-connexion.org
|
||||
@@ -547,7 +525,6 @@ static P_HERMES_RADIO: Provider = Provider {
|
||||
key: Config::MdnsEnabled,
|
||||
value: "0",
|
||||
}]),
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// hey.com.md: hey.com
|
||||
@@ -560,7 +537,6 @@ static P_HEY_COM: Provider = Provider {
|
||||
server: &[],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// i.ua.md: i.ua
|
||||
@@ -573,7 +549,6 @@ static P_I_UA: Provider = Provider {
|
||||
server: &[],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// i3.net.md: i3.net
|
||||
@@ -586,7 +561,6 @@ static P_I3_NET: Provider = Provider {
|
||||
server: &[],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// icloud.md: icloud.com, me.com, mac.com
|
||||
@@ -614,7 +588,6 @@ static P_ICLOUD: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// infomaniak.com.md: ik.me
|
||||
@@ -645,7 +618,6 @@ static P_INFOMANIAK_COM: Provider = Provider {
|
||||
..ProviderOptions::new()
|
||||
},
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// kolst.com.md: kolst.com
|
||||
@@ -658,7 +630,6 @@ static P_KOLST_COM: Provider = Provider {
|
||||
server: &[],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// kontent.com.md: kontent.com
|
||||
@@ -671,7 +642,6 @@ static P_KONTENT_COM: Provider = Provider {
|
||||
server: &[],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// mail.com.md: email.com, groupmail.com, post.com, homemail.com, housemail.com, writeme.com, mail.com, mail-me.com, workmail.com, accountant.com, activist.com, adexec.com, allergist.com, alumni.com, alumnidirector.com, archaeologist.com, auctioneer.net, bartender.net, brew-master.com, chef.net, chemist.com, collector.org, columnist.com, comic.com, consultant.com, contractor.net, counsellor.com, deliveryman.com, diplomats.com, dr.com, engineer.com, financier.com, fireman.net, gardener.com, geologist.com, graphic-designer.com, graduate.org, hairdresser.net, instructor.net, insurer.com, journalist.com, legislator.com, lobbyist.com, minister.com, musician.org, optician.com, orthodontist.net, pediatrician.com, photographer.net, physicist.net, politician.com, presidency.com, priest.com, programmer.net, publicist.com, radiologist.net, realtyagent.com, registerednurses.com, repairman.com, representative.com, salesperson.net, secretary.net, socialworker.net, sociologist.com, songwriter.net, teachers.org, techie.com, technologist.com, therapist.net, umpire.com, worker.com, artlover.com, bikerider.com, birdlover.com, blader.com, kittymail.com, lovecat.com, marchmail.com, boardermail.com, catlover.com, clubmember.org, nonpartisan.com, petlover.com, doglover.com, greenmail.net, hackermail.com, theplate.com, bsdmail.com, computer4u.com, coolsite.net, cyberdude.com, cybergal.com, cyberservices.com, cyber-wizard.com, linuxmail.org, null.net, solution4u.com, tech-center.com, webname.com, acdcfan.com, angelic.com, discofan.com, elvisfan.com, hiphopfan.com, kissfans.com, madonnafan.com, metalfan.com, ninfan.com, ravemail.com, reggaefan.com, snakebite.com, bellair.net, californiamail.com, dallasmail.com, nycmail.com, pacific-ocean.com, pacificwest.com, sanfranmail.com, usa.com, africamail.com, asia-mail.com, australiamail.com, berlin.com, brazilmail.com, chinamail.com, dublin.com, dutchmail.com, englandmail.com, europe.com, arcticmail.com, europemail.com, germanymail.com, irelandmail.com, israelmail.com, italymail.com, koreamail.com, mexicomail.com, moscowmail.com, munich.com, asia.com, polandmail.com, safrica.com, samerica.com, scotlandmail.com, spainmail.com, swedenmail.com, swissmail.com, torontomail.com, aircraftmail.com, cash4u.com, disposable.com, execs.com, fastservice.com, instruction.com, job4u.com, net-shopping.com, planetmail.com, planetmail.net, qualityservice.com, rescueteam.com, surgical.net, atheist.com, disciples.com, muslim.com, protestant.com, reborn.com, reincarnate.com, religious.com, saintly.com, brew-meister.com, cutey.com, dbzmail.com, doramail.com, galaxyhit.com, hilarious.com, humanoid.net, hot-shot.com, inorbit.com, iname.com, innocent.com, keromail.com, myself.com, rocketship.com, toothfairy.com, toke.com, tvstar.com, uymail.com, 2trom.com
|
||||
@@ -684,7 +654,6 @@ static P_MAIL_COM: Provider = Provider {
|
||||
server: &[],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// mail.de.md: mail.de
|
||||
@@ -712,7 +681,6 @@ static P_MAIL_DE: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// mail.ru.md: mail.ru, inbox.ru, internet.ru, bk.ru, list.ru
|
||||
@@ -740,7 +708,6 @@ static P_MAIL_RU: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// mail2tor.md: mail2tor.com
|
||||
@@ -768,7 +735,6 @@ static P_MAIL2TOR: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// mailbox.org.md: mailbox.org, secure.mailbox.org
|
||||
@@ -796,7 +762,6 @@ static P_MAILBOX_ORG: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// mailo.com.md: mailo.com
|
||||
@@ -824,7 +789,6 @@ static P_MAILO_COM: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// migadu.md: migadu.com
|
||||
@@ -859,7 +823,6 @@ static P_MIGADU: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// nauta.cu.md: nauta.cu
|
||||
@@ -894,7 +857,6 @@ static P_NAUTA_CU: Provider = Provider {
|
||||
key: Config::MediaQuality,
|
||||
value: "1",
|
||||
}]),
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// naver.md: naver.com
|
||||
@@ -922,7 +884,6 @@ static P_NAVER: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// nine.testrun.org.md: nine.testrun.org
|
||||
@@ -978,7 +939,6 @@ static P_NINE_TESTRUN_ORG: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// nubo.coop.md: nubo.coop
|
||||
@@ -1006,7 +966,6 @@ static P_NUBO_COOP: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// outlook.com.md: hotmail.com, outlook.com, office365.com, outlook.com.tr, live.com, outlook.de
|
||||
@@ -1034,7 +993,6 @@ static P_OUTLOOK_COM: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// ouvaton.coop.md: ouvaton.org
|
||||
@@ -1062,7 +1020,6 @@ static P_OUVATON_COOP: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// posteo.md: posteo.de, posteo.af, posteo.at, posteo.be, posteo.ca, posteo.ch, posteo.cl, posteo.co, posteo.co.uk, posteo.com, posteo.com.br, posteo.cr, posteo.cz, posteo.dk, posteo.ee, posteo.es, posteo.eu, posteo.fi, posteo.gl, posteo.gr, posteo.hn, posteo.hr, posteo.hu, posteo.ie, posteo.in, posteo.is, posteo.it, posteo.jp, posteo.la, posteo.li, posteo.lt, posteo.lu, posteo.me, posteo.mx, posteo.my, posteo.net, posteo.nl, posteo.no, posteo.nz, posteo.org, posteo.pe, posteo.pl, posteo.pm, posteo.pt, posteo.ro, posteo.ru, posteo.se, posteo.sg, posteo.si, posteo.tn, posteo.uk, posteo.us
|
||||
@@ -1104,7 +1061,6 @@ static P_POSTEO: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// protonmail.md: protonmail.com, protonmail.ch, pm.me
|
||||
@@ -1117,7 +1073,6 @@ static P_PROTONMAIL: Provider = Provider {
|
||||
server: &[],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// purelymail.com.md: purelymail.com, cheapermail.com, placeq.com, rethinkmail.com, worldofmail.com
|
||||
@@ -1145,7 +1100,6 @@ static P_PURELYMAIL_COM: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// qq.md: qq.com, foxmail.com
|
||||
@@ -1173,7 +1127,6 @@ static P_QQ: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// rambler.ru.md: rambler.ru, autorambler.ru, myrambler.ru, rambler.ua, lenta.ru, ro.ru, r0.ru
|
||||
@@ -1208,7 +1161,6 @@ static P_RAMBLER_RU: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// riseup.net.md: riseup.net
|
||||
@@ -1236,7 +1188,6 @@ static P_RISEUP_NET: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// rogers.com.md: rogers.com
|
||||
@@ -1249,7 +1200,6 @@ static P_ROGERS_COM: Provider = Provider {
|
||||
server: &[],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// sonic.md: sonic.net
|
||||
@@ -1262,7 +1212,6 @@ static P_SONIC: Provider = Provider {
|
||||
server: &[],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// stinpriza.net.md: stinpriza.net, stinpriza.eu, el-hoyo.net
|
||||
@@ -1293,7 +1242,6 @@ static P_STINPRIZA_NET: Provider = Provider {
|
||||
..ProviderOptions::new()
|
||||
},
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// systemausfall.org.md: systemausfall.org, solidaris.me
|
||||
@@ -1321,7 +1269,6 @@ static P_SYSTEMAUSFALL_ORG: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// systemli.org.md: systemli.org
|
||||
@@ -1349,7 +1296,6 @@ static P_SYSTEMLI_ORG: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// t-online.md: t-online.de, magenta.de
|
||||
@@ -1377,7 +1323,6 @@ static P_T_ONLINE: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// tiscali.it.md: tiscali.it
|
||||
@@ -1405,7 +1350,6 @@ static P_TISCALI_IT: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// tutanota.md: tutanota.com, tutanota.de, tutamail.com, tuta.io, keemail.me
|
||||
@@ -1418,7 +1362,6 @@ static P_TUTANOTA: Provider = Provider {
|
||||
server: &[],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// ukr.net.md: ukr.net
|
||||
@@ -1446,7 +1389,6 @@ static P_UKR_NET: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// undernet.uy.md: undernet.uy
|
||||
@@ -1474,7 +1416,6 @@ static P_UNDERNET_UY: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// vfemail.md: vfemail.net
|
||||
@@ -1487,7 +1428,6 @@ static P_VFEMAIL: Provider = Provider {
|
||||
server: &[],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// vivaldi.md: vivaldi.net
|
||||
@@ -1515,7 +1455,6 @@ static P_VIVALDI: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// vk.com.md: vk.com
|
||||
@@ -1543,7 +1482,6 @@ static P_VK_COM: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// vodafone.de.md: vodafone.de, vodafonemail.de
|
||||
@@ -1571,7 +1509,6 @@ static P_VODAFONE_DE: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// web.de.md: web.de, email.de, flirt.ms, hallo.ms, kuss.ms, love.ms, magic.ms, singles.ms, cool.ms, kanzler.ms, okay.ms, party.ms, pop.ms, stars.ms, techno.ms, clever.ms, deutschland.ms, genial.ms, ich.ms, online.ms, smart.ms, wichtig.ms, action.ms, fussball.ms, joker.ms, planet.ms, power.ms
|
||||
@@ -1606,7 +1543,6 @@ static P_WEB_DE: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// wkpb.de.md: wkpb.de
|
||||
@@ -1634,7 +1570,6 @@ static P_WKPB_DE: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// yahoo.md: yahoo.com, yahoo.de, yahoo.it, yahoo.fr, yahoo.es, yahoo.se, yahoo.co.uk, yahoo.co.nz, yahoo.com.au, yahoo.com.ar, yahoo.com.br, yahoo.com.mx, myyahoo.com, ymail.com, rocketmail.com, yahoodns.net
|
||||
@@ -1662,7 +1597,6 @@ static P_YAHOO: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// yandex.ru.md: yandex.com, yandex.by, yandex.kz, yandex.ru, yandex.ua, ya.ru, narod.ru
|
||||
@@ -1690,7 +1624,6 @@ static P_YANDEX_RU: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: Some(Oauth2Authorizer::Yandex),
|
||||
};
|
||||
|
||||
// yggmail.md: yggmail
|
||||
@@ -1718,7 +1651,6 @@ static P_YGGMAIL: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// ziggo.nl.md: ziggo.nl
|
||||
@@ -1746,7 +1678,6 @@ static P_ZIGGO_NL: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
// zoho.md: zohomail.eu, zohomail.com, zoho.com
|
||||
@@ -1774,7 +1705,6 @@ static P_ZOHO: Provider = Provider {
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
pub(crate) static PROVIDER_DATA: [(&str, &Provider); 521] = [
|
||||
|
||||
@@ -841,7 +841,6 @@ pub(crate) async fn login_param_from_account_qr(
|
||||
},
|
||||
smtp: Default::default(),
|
||||
certificate_checks: EnteredCertificateChecks::Strict,
|
||||
oauth2: false,
|
||||
};
|
||||
return Ok(param);
|
||||
}
|
||||
@@ -861,7 +860,6 @@ pub(crate) async fn login_param_from_account_qr(
|
||||
},
|
||||
smtp: Default::default(),
|
||||
certificate_checks: EnteredCertificateChecks::Strict,
|
||||
oauth2: false,
|
||||
};
|
||||
|
||||
Ok(param)
|
||||
|
||||
@@ -196,7 +196,6 @@ pub(crate) fn login_param_from_login_qr(
|
||||
password: smtp_password.unwrap_or_default(),
|
||||
},
|
||||
certificate_checks: certificate_checks.unwrap_or_default(),
|
||||
oauth2: false,
|
||||
};
|
||||
Ok(param)
|
||||
}
|
||||
|
||||
@@ -100,13 +100,11 @@ impl Smtp {
|
||||
&proxy_config,
|
||||
&lp.addr,
|
||||
lp.strict_tls(proxy_config.is_some()),
|
||||
lp.oauth2,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Connect using the provided login params.
|
||||
#[expect(clippy::too_many_arguments)]
|
||||
pub async fn connect(
|
||||
&mut self,
|
||||
context: &Context,
|
||||
@@ -115,7 +113,6 @@ impl Smtp {
|
||||
proxy_config: &Option<ProxyConfig>,
|
||||
addr: &str,
|
||||
strict_tls: bool,
|
||||
oauth2: bool,
|
||||
) -> Result<()> {
|
||||
if self.is_connected() {
|
||||
warn!(context, "SMTP already connected.");
|
||||
@@ -136,8 +133,6 @@ impl Smtp {
|
||||
proxy_config,
|
||||
strict_tls,
|
||||
lp.connection.clone(),
|
||||
oauth2,
|
||||
addr,
|
||||
&lp.user,
|
||||
password,
|
||||
)
|
||||
|
||||
@@ -15,7 +15,6 @@ use crate::net::tls::{SpkiHashStore, TlsSessionStore, wrap_tls};
|
||||
use crate::net::{
|
||||
connect_tcp_inner, connect_tls_inner, run_connection_attempts, update_connection_history,
|
||||
};
|
||||
use crate::oauth2::get_oauth2_access_token;
|
||||
use crate::sql::Sql;
|
||||
use crate::tools::time;
|
||||
use crate::transport::ConnectionCandidate;
|
||||
@@ -48,14 +47,11 @@ async fn new_smtp_transport<S: AsyncBufRead + AsyncWrite + Unpin>(
|
||||
Ok(transport)
|
||||
}
|
||||
|
||||
#[expect(clippy::too_many_arguments)]
|
||||
pub(crate) async fn connect_and_auth(
|
||||
context: &Context,
|
||||
proxy_config: &Option<ProxyConfig>,
|
||||
strict_tls: bool,
|
||||
candidate: ConnectionCandidate,
|
||||
oauth2: bool,
|
||||
addr: &str,
|
||||
user: &str,
|
||||
password: &str,
|
||||
) -> Result<SmtpTransport<Box<dyn SessionBufStream>>> {
|
||||
@@ -65,31 +61,13 @@ pub(crate) async fn connect_and_auth(
|
||||
let mut transport = new_smtp_transport(session_stream).await?;
|
||||
|
||||
// Authenticate.
|
||||
let (creds, mechanism) = if oauth2 {
|
||||
// oauth2
|
||||
let access_token = get_oauth2_access_token(context, addr, password, false)
|
||||
.await
|
||||
.context("SMTP failed to get OAUTH2 access token")?;
|
||||
if access_token.is_none() {
|
||||
bail!("SMTP OAuth 2 error {addr}");
|
||||
}
|
||||
(
|
||||
async_smtp::authentication::Credentials::new(
|
||||
user.to_string(),
|
||||
access_token.unwrap_or_default(),
|
||||
),
|
||||
vec![async_smtp::authentication::Mechanism::Xoauth2],
|
||||
)
|
||||
} else {
|
||||
// plain
|
||||
(
|
||||
async_smtp::authentication::Credentials::new(user.to_string(), password.to_string()),
|
||||
vec![
|
||||
async_smtp::authentication::Mechanism::Plain,
|
||||
async_smtp::authentication::Mechanism::Login,
|
||||
],
|
||||
)
|
||||
};
|
||||
let (creds, mechanism) = (
|
||||
async_smtp::authentication::Credentials::new(user.to_string(), password.to_string()),
|
||||
vec![
|
||||
async_smtp::authentication::Mechanism::Plain,
|
||||
async_smtp::authentication::Mechanism::Login,
|
||||
],
|
||||
);
|
||||
transport
|
||||
.try_login(&creds, &mechanism)
|
||||
.await
|
||||
|
||||
@@ -645,11 +645,6 @@ impl Sql {
|
||||
self.set_raw_config(key, value).await
|
||||
}
|
||||
|
||||
/// Sets configuration for the given key to 64-bit signed integer value.
|
||||
pub async fn set_raw_config_int64(&self, key: &str, value: i64) -> Result<()> {
|
||||
self.set_raw_config(key, Some(&format!("{value}"))).await
|
||||
}
|
||||
|
||||
/// Returns 64-bit signed integer configuration value for the given key.
|
||||
pub async fn get_raw_config_int64(&self, key: &str) -> Result<Option<i64>> {
|
||||
self.get_raw_config(key)
|
||||
|
||||
@@ -226,7 +226,7 @@ impl TestContextManager {
|
||||
(
|
||||
new_addr,
|
||||
serde_json::to_string(&EnteredLoginParam{addr: new_addr.to_string(), ..Default::default()}).unwrap(),
|
||||
format!(r#"{{"addr":"{new_addr}","imap":[],"imap_user":"","imap_password":"","smtp":[],"smtp_user":"","smtp_password":"","certificate_checks":"Automatic","oauth2":false}}"#)
|
||||
format!(r#"{{"addr":"{new_addr}","imap":[],"imap_user":"","imap_password":"","smtp":[],"smtp_user":"","smtp_password":"","certificate_checks":"Automatic"}}"#)
|
||||
),
|
||||
).await.unwrap();
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::configure::server_params::{ServerParams, expand_param_vector};
|
||||
use crate::constants::{DC_LP_AUTH_FLAGS, DC_LP_AUTH_OAUTH2};
|
||||
use crate::context::Context;
|
||||
use crate::ensure_and_debug_assert;
|
||||
use crate::events::EventType;
|
||||
@@ -199,9 +198,6 @@ pub(crate) struct ConfiguredLoginParam {
|
||||
/// TLS options: whether to allow invalid certificates and/or
|
||||
/// invalid hostnames
|
||||
pub certificate_checks: ConfiguredCertificateChecks,
|
||||
|
||||
/// If true, login via OAUTH2 (not recommended anymore)
|
||||
pub oauth2: bool,
|
||||
}
|
||||
|
||||
/// JSON representation of ConfiguredLoginParam
|
||||
@@ -224,7 +220,6 @@ pub(crate) struct ConfiguredLoginParamJson {
|
||||
pub smtp_password: String,
|
||||
pub provider_id: Option<String>,
|
||||
pub certificate_checks: ConfiguredCertificateChecks,
|
||||
pub oauth2: bool,
|
||||
}
|
||||
|
||||
impl fmt::Display for ConfiguredLoginParam {
|
||||
@@ -350,12 +345,6 @@ impl ConfiguredLoginParam {
|
||||
.await?
|
||||
.context("IMAP password is not configured")?;
|
||||
|
||||
let server_flags = context
|
||||
.get_config_parsed::<i32>(Config::ConfiguredServerFlags)
|
||||
.await?
|
||||
.unwrap_or_default();
|
||||
let oauth2 = matches!(server_flags & DC_LP_AUTH_FLAGS, DC_LP_AUTH_OAUTH2);
|
||||
|
||||
let provider = context
|
||||
.get_config(Config::ConfiguredProvider)
|
||||
.await?
|
||||
@@ -583,7 +572,6 @@ impl ConfiguredLoginParam {
|
||||
smtp_password: send_pw,
|
||||
certificate_checks,
|
||||
provider,
|
||||
oauth2,
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -627,7 +615,6 @@ impl ConfiguredLoginParam {
|
||||
smtp_password: json.smtp_password,
|
||||
provider,
|
||||
certificate_checks: json.certificate_checks,
|
||||
oauth2: json.oauth2,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -663,7 +650,6 @@ impl From<ConfiguredLoginParam> for ConfiguredLoginParamJson {
|
||||
smtp_password: configured_login_param.smtp_password,
|
||||
provider_id: configured_login_param.provider.map(|p| p.id.to_string()),
|
||||
certificate_checks: configured_login_param.certificate_checks,
|
||||
oauth2: configured_login_param.oauth2,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -857,7 +843,7 @@ pub(crate) async fn add_pseudo_transport(context: &Context, addr: &str) -> Resul
|
||||
(
|
||||
addr,
|
||||
serde_json::to_string(&EnteredLoginParam{addr: addr.to_string(), ..Default::default()})?,
|
||||
format!(r#"{{"addr":"{addr}","imap":[],"imap_user":"","imap_password":"","smtp":[],"smtp_user":"","smtp_password":"","certificate_checks":"Automatic","oauth2":false}}"#)
|
||||
format!(r#"{{"addr":"{addr}","imap":[],"imap_user":"","imap_password":"","smtp":[],"smtp_user":"","smtp_password":"","certificate_checks":"Automatic"}}"#)
|
||||
),
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -49,14 +49,13 @@ async fn test_save_load_login_param() -> Result<()> {
|
||||
smtp_password: "bar".to_string(),
|
||||
provider: None,
|
||||
certificate_checks: ConfiguredCertificateChecks::Strict,
|
||||
oauth2: false,
|
||||
};
|
||||
|
||||
param
|
||||
.clone()
|
||||
.save_to_transports_table(&t, &EnteredLoginParam::default(), time())
|
||||
.await?;
|
||||
let expected_param = r#"{"addr":"alice@example.org","imap":[{"connection":{"host":"imap.example.com","port":123,"security":"Starttls"},"user":"alice"}],"imap_folder":"Folder","imap_user":"","imap_password":"foo","smtp":[{"connection":{"host":"smtp.example.com","port":456,"security":"Tls"},"user":"alice@example.org"}],"smtp_user":"","smtp_password":"bar","provider_id":null,"certificate_checks":"Strict","oauth2":false}"#;
|
||||
let expected_param = r#"{"addr":"alice@example.org","imap":[{"connection":{"host":"imap.example.com","port":123,"security":"Starttls"},"user":"alice"}],"imap_folder":"Folder","imap_user":"","imap_password":"foo","smtp":[{"connection":{"host":"smtp.example.com","port":456,"security":"Tls"},"user":"alice@example.org"}],"smtp_user":"","smtp_password":"bar","provider_id":null,"certificate_checks":"Strict"}"#;
|
||||
assert_eq!(
|
||||
t.sql
|
||||
.query_get_value::<String>("SELECT configured_param FROM transports", ())
|
||||
@@ -126,8 +125,6 @@ async fn test_posteo_alias() -> Result<()> {
|
||||
t.set_config(Config::ConfiguredSendUser, Some(user)).await?;
|
||||
t.set_config(Config::ConfiguredSendPw, Some("foobarbaz"))
|
||||
.await?;
|
||||
t.set_config(Config::ConfiguredServerFlags, Some("0"))
|
||||
.await?;
|
||||
|
||||
let param = ConfiguredLoginParam {
|
||||
addr: "alice@posteo.at".to_string(),
|
||||
@@ -174,7 +171,6 @@ async fn test_posteo_alias() -> Result<()> {
|
||||
smtp_password: "foobarbaz".to_string(),
|
||||
provider: get_provider_by_id("posteo"),
|
||||
certificate_checks: ConfiguredCertificateChecks::Strict,
|
||||
oauth2: false,
|
||||
};
|
||||
|
||||
let loaded = ConfiguredLoginParam::load_legacy(&t).await?.unwrap();
|
||||
@@ -213,8 +209,6 @@ async fn test_empty_server_list_legacy() -> Result<()> {
|
||||
.await?; // Strict
|
||||
t.set_config(Config::ConfiguredSendPw, Some("foobarbaz"))
|
||||
.await?;
|
||||
t.set_config(Config::ConfiguredServerFlags, Some("0"))
|
||||
.await?;
|
||||
|
||||
let loaded = ConfiguredLoginParam::load_legacy(&t).await?.unwrap();
|
||||
assert_eq!(loaded.provider, Some(*provider));
|
||||
@@ -293,7 +287,6 @@ fn dummy_configured_login_param(
|
||||
smtp_password: "foobarbaz".to_string(),
|
||||
provider,
|
||||
certificate_checks: ConfiguredCertificateChecks::Automatic,
|
||||
oauth2: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user