diff --git a/Cargo.lock b/Cargo.lock index 1fd3036..f0634dd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2101,7 +2101,7 @@ dependencies = [ [[package]] name = "pimalaya-email" version = "0.7.1" -source = "git+https://git.sr.ht/~soywod/pimalaya#5474a733194623c74665c8d37066974cf3fe4477" +source = "git+https://git.sr.ht/~soywod/pimalaya#524f8049566845369f55300a20843c48dfe7a620" dependencies = [ "ammonia", "chrono", @@ -2142,7 +2142,7 @@ dependencies = [ [[package]] name = "pimalaya-keyring" version = "0.0.1" -source = "git+https://git.sr.ht/~soywod/pimalaya#5474a733194623c74665c8d37066974cf3fe4477" +source = "git+https://git.sr.ht/~soywod/pimalaya#524f8049566845369f55300a20843c48dfe7a620" dependencies = [ "keyring", "log", @@ -2152,7 +2152,7 @@ dependencies = [ [[package]] name = "pimalaya-oauth2" version = "0.0.1" -source = "git+https://git.sr.ht/~soywod/pimalaya#5474a733194623c74665c8d37066974cf3fe4477" +source = "git+https://git.sr.ht/~soywod/pimalaya#524f8049566845369f55300a20843c48dfe7a620" dependencies = [ "log", "oauth2", @@ -2164,7 +2164,7 @@ dependencies = [ [[package]] name = "pimalaya-process" version = "0.0.1" -source = "git+https://git.sr.ht/~soywod/pimalaya#5474a733194623c74665c8d37066974cf3fe4477" +source = "git+https://git.sr.ht/~soywod/pimalaya#524f8049566845369f55300a20843c48dfe7a620" dependencies = [ "log", "thiserror", @@ -2173,7 +2173,7 @@ dependencies = [ [[package]] name = "pimalaya-secret" version = "0.0.1" -source = "git+https://git.sr.ht/~soywod/pimalaya#5474a733194623c74665c8d37066974cf3fe4477" +source = "git+https://git.sr.ht/~soywod/pimalaya#524f8049566845369f55300a20843c48dfe7a620" dependencies = [ "log", "pimalaya-keyring", diff --git a/Cargo.toml b/Cargo.toml index 15f0b2e..3585f73 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,6 +55,10 @@ pimalaya-email = { git = "https://git.sr.ht/~soywod/pimalaya" } pimalaya-keyring = { git = "https://git.sr.ht/~soywod/pimalaya" } pimalaya-process = { git = "https://git.sr.ht/~soywod/pimalaya" } pimalaya-secret = { git = "https://git.sr.ht/~soywod/pimalaya" } +# pimalaya-email = { path = "/home/soywod/sourcehut/pimalaya/email" } +# pimalaya-keyring = { path = "/home/soywod/sourcehut/pimalaya/keyring" } +# pimalaya-process = { path = "/home/soywod/sourcehut/pimalaya/process" } +# pimalaya-secret = { path = "/home/soywod/sourcehut/pimalaya/secret" } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" shellexpand = "2.1" diff --git a/src/config/prelude.rs b/src/config/prelude.rs index de766f0..919efd2 100644 --- a/src/config/prelude.rs +++ b/src/config/prelude.rs @@ -1,7 +1,7 @@ use pimalaya_email::{ folder::sync::Strategy as SyncFoldersStrategy, EmailHooks, EmailSender, EmailTextPlainFormat, - ImapAuthConfig, MaildirConfig, OAuth2Config, OAuth2Method, OAuth2Scopes, SendmailConfig, - SmtpAuthConfig, SmtpConfig, + ImapAuthConfig, MaildirConfig, OAuth2Config, OAuth2Method, OAuth2Scopes, PasswdConfig, + SendmailConfig, SmtpAuthConfig, SmtpConfig, }; use pimalaya_keyring::Entry; use pimalaya_process::Cmd; @@ -15,14 +15,50 @@ use pimalaya_email::ImapConfig; #[cfg(feature = "notmuch-backend")] use pimalaya_email::NotmuchConfig; -#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] -#[serde(remote = "Cmd", from = "String")] -pub struct CmdDef; - #[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] #[serde(remote = "Entry", from = "String")] pub struct EntryDef; +#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] +#[serde(remote = "Cmd", from = "String")] +pub struct SingleCmdDef; + +#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] +#[serde(remote = "Cmd", from = "Vec")] +pub struct PipelineDef; + +#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] +#[serde(remote = "Cmd", from = "SingleCmdOrPipeline")] +pub struct SingleCmdOrPipelineDef; + +#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] +#[serde(untagged)] +pub enum SingleCmdOrPipeline { + #[serde(with = "SingleCmdDef")] + SingleCmd(Cmd), + #[serde(with = "PipelineDef")] + Pipeline(Cmd), +} + +impl From for Cmd { + fn from(cmd: SingleCmdOrPipeline) -> Cmd { + match cmd { + SingleCmdOrPipeline::SingleCmd(cmd) => cmd, + SingleCmdOrPipeline::Pipeline(cmd) => cmd, + } + } +} + +#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] +#[serde(remote = "Secret", rename_all = "kebab-case")] +pub enum SecretDef { + Raw(String), + #[serde(with = "SingleCmdOrPipelineDef")] + Cmd(Cmd), + #[serde(with = "EntryDef")] + Keyring(Entry), +} + #[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] #[serde(remote = "OAuth2Method")] pub enum OAuth2MethodDef { @@ -32,110 +68,6 @@ pub enum OAuth2MethodDef { OAuthBearer, } -#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] -#[serde(remote = "SmtpConfig")] -struct SmtpConfigDef { - #[serde(rename = "smtp-host")] - pub host: String, - #[serde(rename = "smtp-port")] - pub port: u16, - #[serde(rename = "smtp-ssl")] - pub ssl: Option, - #[serde(rename = "smtp-starttls")] - pub starttls: Option, - #[serde(rename = "smtp-insecure")] - pub insecure: Option, - #[serde(rename = "smtp-login")] - pub login: String, - #[serde(flatten, with = "SmtpAuthConfigDef")] - pub auth: SmtpAuthConfig, -} - -#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] -#[serde(remote = "SmtpAuthConfig", tag = "smtp-auth")] -pub enum SmtpAuthConfigDef { - #[serde(rename = "passwd", alias = "password", with = "SmtpPasswdDef")] - Passwd(Secret), - #[serde(rename = "oauth2", with = "SmtpOAuth2ConfigDef")] - OAuth2(OAuth2Config), -} - -#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] -#[serde(remote = "Secret", rename_all = "kebab-case")] -pub enum SmtpPasswdDef { - #[serde(rename = "smtp-passwd")] - Raw(String), - #[serde(rename = "smtp-passwd-cmd", with = "CmdDef")] - Cmd(Cmd), - #[serde(rename = "smtp-passwd-keyring", with = "EntryDef")] - Keyring(Entry), -} - -#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] -#[serde(remote = "OAuth2Config")] -pub struct SmtpOAuth2ConfigDef { - #[serde(rename = "smtp-oauth2-method", with = "OAuth2MethodDef")] - pub method: OAuth2Method, - #[serde(rename = "smtp-oauth2-client-id")] - pub client_id: String, - #[serde(flatten, with = "SmtpOAuth2ClientSecretDef")] - pub client_secret: Secret, - #[serde(rename = "smtp-oauth2-auth-url")] - pub auth_url: String, - #[serde(rename = "smtp-oauth2-token-url")] - pub token_url: String, - #[serde(flatten, with = "SmtpOAuth2AccessTokenDef")] - pub access_token: Secret, - #[serde(flatten, with = "SmtpOAuth2RefreshTokenDef")] - pub refresh_token: Secret, - #[serde(flatten, with = "SmtpOAuth2ScopesDef")] - pub scopes: OAuth2Scopes, - #[serde(rename = "smtp-oauth2-pkce", default)] - pub pkce: bool, -} - -#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] -#[serde(remote = "Secret")] -pub enum SmtpOAuth2ClientSecretDef { - #[serde(rename = "smtp-oauth2-client-secret")] - Raw(String), - #[serde(rename = "smtp-oauth2-client-secret-cmd", with = "CmdDef")] - Cmd(Cmd), - #[serde(rename = "smtp-oauth2-client-secret-keyring", with = "EntryDef")] - Keyring(Entry), -} - -#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] -#[serde(remote = "Secret")] -pub enum SmtpOAuth2AccessTokenDef { - #[serde(rename = "smtp-oauth2-access-token")] - Raw(String), - #[serde(rename = "smtp-oauth2-access-token-cmd", with = "CmdDef")] - Cmd(Cmd), - #[serde(rename = "smtp-oauth2-access-token-keyring", with = "EntryDef")] - Keyring(Entry), -} - -#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] -#[serde(remote = "Secret")] -pub enum SmtpOAuth2RefreshTokenDef { - #[serde(rename = "smtp-oauth2-refresh-token")] - Raw(String), - #[serde(rename = "smtp-oauth2-refresh-token-cmd", with = "CmdDef")] - Cmd(Cmd), - #[serde(rename = "smtp-oauth2-refresh-token-keyring", with = "EntryDef")] - Keyring(Entry), -} - -#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] -#[serde(remote = "OAuth2Scopes")] -pub enum SmtpOAuth2ScopesDef { - #[serde(rename = "smtp-oauth2-scope")] - Scope(String), - #[serde(rename = "smtp-oauth2-scopes")] - Scopes(Vec), -} - #[cfg(feature = "imap-backend")] #[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] #[serde(remote = "ImapConfig")] @@ -165,39 +97,35 @@ pub struct ImapConfigDef { #[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] #[serde(remote = "ImapAuthConfig", tag = "imap-auth")] pub enum ImapAuthConfigDef { - #[serde(rename = "passwd", alias = "password", with = "ImapPasswdDef")] - Passwd(Secret), + #[serde(rename = "passwd", alias = "password", with = "ImapPasswdConfigDef")] + Passwd(#[serde(default)] PasswdConfig), #[serde(rename = "oauth2", with = "ImapOAuth2ConfigDef")] OAuth2(OAuth2Config), } #[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] -#[serde(remote = "Secret", rename_all = "kebab-case")] -pub enum ImapPasswdDef { - #[serde(rename = "imap-passwd")] - Raw(String), - #[serde(rename = "imap-passwd-cmd", with = "CmdDef")] - Cmd(Cmd), - #[serde(rename = "imap-passwd-keyring", with = "EntryDef")] - Keyring(Entry), +#[serde(remote = "PasswdConfig")] +pub struct ImapPasswdConfigDef { + #[serde(rename = "imap-passwd", with = "SecretDef", default)] + pub passwd: Secret, } #[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] #[serde(remote = "OAuth2Config")] pub struct ImapOAuth2ConfigDef { - #[serde(rename = "imap-oauth2-method", with = "OAuth2MethodDef")] + #[serde(rename = "imap-oauth2-method", with = "OAuth2MethodDef", default)] pub method: OAuth2Method, #[serde(rename = "imap-oauth2-client-id")] pub client_id: String, - #[serde(flatten, with = "ImapOAuth2ClientSecretDef")] + #[serde(rename = "imap-oauth2-client-secret", with = "SecretDef", default)] pub client_secret: Secret, #[serde(rename = "imap-oauth2-auth-url")] pub auth_url: String, #[serde(rename = "imap-oauth2-token-url")] pub token_url: String, - #[serde(flatten, with = "ImapOAuth2AccessTokenDef")] + #[serde(rename = "imap-oauth2-access-token", with = "SecretDef", default)] pub access_token: Secret, - #[serde(flatten, with = "ImapOAuth2RefreshTokenDef")] + #[serde(rename = "imap-oauth2-refresh-token", with = "SecretDef", default)] pub refresh_token: Secret, #[serde(flatten, with = "ImapOAuth2ScopesDef")] pub scopes: OAuth2Scopes, @@ -205,39 +133,6 @@ pub struct ImapOAuth2ConfigDef { pub pkce: bool, } -#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] -#[serde(remote = "Secret")] -pub enum ImapOAuth2ClientSecretDef { - #[serde(rename = "imap-oauth2-client-secret")] - Raw(String), - #[serde(rename = "imap-oauth2-client-secret-cmd", with = "CmdDef")] - Cmd(Cmd), - #[serde(rename = "imap-oauth2-client-secret-keyring", with = "EntryDef")] - Keyring(Entry), -} - -#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] -#[serde(remote = "Secret")] -pub enum ImapOAuth2AccessTokenDef { - #[serde(rename = "imap-oauth2-access-token")] - Raw(String), - #[serde(rename = "imap-oauth2-access-token-cmd", with = "CmdDef")] - Cmd(Cmd), - #[serde(rename = "imap-oauth2-access-token-keyring", with = "EntryDef")] - Keyring(Entry), -} - -#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] -#[serde(remote = "Secret")] -pub enum ImapOAuth2RefreshTokenDef { - #[serde(rename = "imap-oauth2-refresh-token")] - Raw(String), - #[serde(rename = "imap-oauth2-refresh-token-cmd", with = "CmdDef")] - Cmd(Cmd), - #[serde(rename = "imap-oauth2-refresh-token-keyring", with = "EntryDef")] - Keyring(Entry), -} - #[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] #[serde(remote = "OAuth2Scopes")] pub enum ImapOAuth2ScopesDef { @@ -287,6 +182,73 @@ pub enum EmailSenderDef { Sendmail(SendmailConfig), } +#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] +#[serde(remote = "SmtpConfig")] +struct SmtpConfigDef { + #[serde(rename = "smtp-host")] + pub host: String, + #[serde(rename = "smtp-port")] + pub port: u16, + #[serde(rename = "smtp-ssl")] + pub ssl: Option, + #[serde(rename = "smtp-starttls")] + pub starttls: Option, + #[serde(rename = "smtp-insecure")] + pub insecure: Option, + #[serde(rename = "smtp-login")] + pub login: String, + #[serde(flatten, with = "SmtpAuthConfigDef")] + pub auth: SmtpAuthConfig, +} + +#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] +#[serde(remote = "SmtpAuthConfig", tag = "smtp-auth")] +pub enum SmtpAuthConfigDef { + #[serde(rename = "passwd", alias = "password", with = "SmtpPasswdConfigDef")] + Passwd(#[serde(default)] PasswdConfig), + #[serde(rename = "oauth2", with = "SmtpOAuth2ConfigDef")] + OAuth2(OAuth2Config), +} + +#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)] +#[serde(remote = "PasswdConfig", default)] +pub struct SmtpPasswdConfigDef { + #[serde(rename = "smtp-passwd", with = "SecretDef", default)] + pub passwd: Secret, +} + +#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] +#[serde(remote = "OAuth2Config")] +pub struct SmtpOAuth2ConfigDef { + #[serde(rename = "smtp-oauth2-method", with = "OAuth2MethodDef", default)] + pub method: OAuth2Method, + #[serde(rename = "smtp-oauth2-client-id")] + pub client_id: String, + #[serde(rename = "smtp-oauth2-client-secret", with = "SecretDef", default)] + pub client_secret: Secret, + #[serde(rename = "smtp-oauth2-auth-url")] + pub auth_url: String, + #[serde(rename = "smtp-oauth2-token-url")] + pub token_url: String, + #[serde(rename = "smtp-oauth2-access-token", with = "SecretDef", default)] + pub access_token: Secret, + #[serde(rename = "smtp-oauth2-refresh-token", with = "SecretDef", default)] + pub refresh_token: Secret, + #[serde(flatten, with = "SmtpOAuth2ScopesDef")] + pub scopes: OAuth2Scopes, + #[serde(rename = "smtp-oauth2-pkce", default)] + pub pkce: bool, +} + +#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] +#[serde(remote = "OAuth2Scopes")] +pub enum SmtpOAuth2ScopesDef { + #[serde(rename = "smtp-oauth2-scope")] + Scope(String), + #[serde(rename = "smtp-oauth2-scopes")] + Scopes(Vec), +} + #[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)] #[serde(remote = "SendmailConfig", rename_all = "kebab-case")] pub struct SendmailConfigDef { diff --git a/src/config/wizard/imap.rs b/src/config/wizard/imap.rs index c6afa41..3cb2c8a 100644 --- a/src/config/wizard/imap.rs +++ b/src/config/wizard/imap.rs @@ -1,7 +1,6 @@ use anyhow::Result; use dialoguer::{Input, Select}; use pimalaya_email::ImapConfig; -use std::io; use crate::account::{ DeserializedAccountConfig, DeserializedBaseAccountConfig, DeserializedImapAccountConfig, @@ -59,11 +58,3 @@ pub(crate) fn configure(base: DeserializedBaseAccountConfig) -> Result io::Result { - Input::with_theme(&*THEME) - .with_prompt("Enter your OAuth 2.0 client secret:") - .report(false) - .interact() -} diff --git a/src/config/wizard/mod.rs b/src/config/wizard/mod.rs index 443ac81..8a12709 100644 --- a/src/config/wizard/mod.rs +++ b/src/config/wizard/mod.rs @@ -11,10 +11,10 @@ use super::DeserializedConfig; use crate::account::{DeserializedAccountConfig, DeserializedBaseAccountConfig}; use anyhow::{anyhow, Result}; use console::style; -use dialoguer::{theme::ColorfulTheme, Confirm, Input, Select}; +use dialoguer::{theme::ColorfulTheme, Confirm, Input, Password, Select}; use log::trace; use once_cell::sync::Lazy; -use std::{fs, process}; +use std::{fs, io, process}; const BACKENDS: &[&str] = &[ "Maildir", @@ -163,3 +163,20 @@ fn configure_base() -> Result { Ok(base_account_config) } + +pub(crate) fn prompt_passwd(prompt: &str) -> io::Result { + Password::with_theme(&*THEME) + .with_prompt(prompt) + .with_confirmation( + "Confirm password:", + "Passwords do not match, please try again.", + ) + .interact() +} + +pub(crate) fn prompt_secret(prompt: &str) -> io::Result { + Input::with_theme(&*THEME) + .with_prompt(prompt) + .report(false) + .interact() +} diff --git a/src/domain/account/config.rs b/src/domain/account/config.rs index 4fd3d01..0e4f1c9 100644 --- a/src/domain/account/config.rs +++ b/src/domain/account/config.rs @@ -5,7 +5,7 @@ use pimalaya_email::{ folder::sync::Strategy as SyncFoldersStrategy, AccountConfig, BackendConfig, EmailHooks, - EmailSender, EmailTextPlainFormat, MaildirConfig, + EmailSender, EmailTextPlainFormat, ImapAuthConfig, MaildirConfig, }; use serde::{Deserialize, Serialize}; use std::{collections::HashMap, path::PathBuf}; @@ -46,10 +46,29 @@ impl DeserializedAccountConfig { BackendConfig::Maildir(config.backend.clone()), ), #[cfg(feature = "imap-backend")] - DeserializedAccountConfig::Imap(config) => ( - config.base.to_account_config(name, global_config), - BackendConfig::Imap(config.backend.clone()), - ), + DeserializedAccountConfig::Imap(config) => { + let mut imap_config = config.backend.clone(); + + match &mut imap_config.auth { + ImapAuthConfig::Passwd(secret) => { + secret.replace_undefined_entry_with(format!("{name}-imap-passwd")); + } + ImapAuthConfig::OAuth2(config) => { + config.client_secret.replace_undefined_entry_with(format!( + "{name}-imap-oauth2-client-secret" + )); + config.access_token.replace_undefined_entry_with(format!( + "{name}-imap-oauth2-access-token" + )); + config.refresh_token.replace_undefined_entry_with(format!( + "{name}-imap-oauth2-refresh-token" + )); + } + }; + + let account_config = config.base.to_account_config(name, global_config); + (account_config, BackendConfig::Imap(imap_config)) + } #[cfg(feature = "notmuch-backend")] DeserializedAccountConfig::Notmuch(config) => ( config.base.to_account_config(name, global_config), diff --git a/src/domain/account/handlers.rs b/src/domain/account/handlers.rs index b4d5606..5fe4fe1 100644 --- a/src/domain/account/handlers.rs +++ b/src/domain/account/handlers.rs @@ -7,11 +7,14 @@ use indicatif::{MultiProgress, ProgressBar, ProgressStyle}; use log::{info, trace, warn}; use pimalaya_email::{ folder::sync::Strategy as SyncFoldersStrategy, AccountConfig, Backend, BackendConfig, - BackendSyncBuilder, BackendSyncProgressEvent, EmailSender, + BackendSyncBuilder, BackendSyncProgressEvent, EmailSender, ImapAuthConfig, SmtpAuthConfig, }; use crate::{ - config::{wizard::imap::configure_oauth2_client_secret, DeserializedConfig}, + config::{ + wizard::{prompt_passwd, prompt_secret}, + DeserializedConfig, + }, printer::{PrintTableOpts, Printer}, Accounts, }; @@ -27,8 +30,11 @@ pub fn configure( if reset { #[cfg(feature = "imap-backend")] if let BackendConfig::Imap(imap_config) = backend_config { - println!("Resetting IMAP secrets…"); - if let Err(err) = imap_config.auth.reset() { + let reset = match &imap_config.auth { + ImapAuthConfig::Passwd(passwd) => passwd.reset(), + ImapAuthConfig::OAuth2(oauth2) => oauth2.reset(), + }; + if let Err(err) = reset { warn!("error while resetting imap secrets, skipping it"); warn!("{err}"); } @@ -36,8 +42,11 @@ pub fn configure( #[cfg(feature = "smtp-sender")] if let EmailSender::Smtp(smtp_config) = &account_config.email_sender { - println!("Resetting SMTP secrets…"); - if let Err(err) = smtp_config.auth.reset() { + let reset = match &smtp_config.auth { + SmtpAuthConfig::Passwd(passwd) => passwd.reset(), + SmtpAuthConfig::OAuth2(oauth2) => oauth2.reset(), + }; + if let Err(err) = reset { warn!("error while resetting smtp secrets, skipping it"); warn!("{err}"); } @@ -46,14 +55,26 @@ pub fn configure( #[cfg(feature = "imap-backend")] if let BackendConfig::Imap(imap_config) = backend_config { - println!("Configuring IMAP secrets…"); - imap_config.auth.configure(configure_oauth2_client_secret)?; + match &imap_config.auth { + ImapAuthConfig::Passwd(passwd) => { + passwd.configure(|| prompt_passwd("Enter your IMAP password:")) + } + ImapAuthConfig::OAuth2(oauth2) => { + oauth2.configure(|| prompt_secret("Enter your IMAP OAuth 2.0 client secret:")) + } + }?; } #[cfg(feature = "smtp-sender")] if let EmailSender::Smtp(smtp_config) = &account_config.email_sender { - println!("Configuring SMTP secrets…"); - smtp_config.auth.configure(configure_oauth2_client_secret)?; + match &smtp_config.auth { + SmtpAuthConfig::Passwd(passwd) => { + passwd.configure(|| prompt_passwd("Enter your SMTP password:")) + } + SmtpAuthConfig::OAuth2(oauth2) => { + oauth2.configure(|| prompt_secret("Enter your SMTP OAuth 2.0 client secret:")) + } + }?; } println!("Account successfully configured!");