From b478c545addf151c9db86484b52ed66bab16fb91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20DOUIN?= Date: Sat, 6 May 2023 15:04:55 +0200 Subject: [PATCH] refactor imap oauth2 and password config using sub crates from lib --- Cargo.lock | 35 ++++++++++++-- Cargo.toml | 8 +++- src/config/prelude.rs | 88 ++++++++++++++++++++++++++++------ src/domain/account/handlers.rs | 16 ++----- src/main.rs | 2 +- 5 files changed, 117 insertions(+), 32 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8f444ad..b54203a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1147,6 +1147,9 @@ dependencies = [ "log", "once_cell", "pimalaya-email", + "pimalaya-keyring", + "pimalaya-process", + "pimalaya-secret", "serde", "serde_json", "shellexpand", @@ -2098,7 +2101,6 @@ dependencies = [ [[package]] name = "pimalaya-email" version = "0.7.1" -source = "git+https://git.sr.ht/~soywod/pimalaya#22db3ec886536897c54b72d4ab7d20beff0ffecc" dependencies = [ "ammonia", "chrono", @@ -2107,7 +2109,6 @@ dependencies = [ "html-escape", "imap", "imap-proto", - "keyring", "lettre", "log", "mail-parser", @@ -2120,6 +2121,7 @@ dependencies = [ "once_cell", "ouroboros", "pimalaya-oauth2", + "pimalaya-secret", "proc-lock", "rayon", "regex", @@ -2136,10 +2138,18 @@ dependencies = [ "webpki-roots", ] +[[package]] +name = "pimalaya-keyring" +version = "0.0.1" +dependencies = [ + "keyring", + "log", + "thiserror", +] + [[package]] name = "pimalaya-oauth2" version = "0.0.1" -source = "git+https://git.sr.ht/~soywod/pimalaya#22db3ec886536897c54b72d4ab7d20beff0ffecc" dependencies = [ "log", "oauth2", @@ -2148,6 +2158,25 @@ dependencies = [ "url", ] +[[package]] +name = "pimalaya-process" +version = "0.0.1" +dependencies = [ + "log", + "thiserror", +] + +[[package]] +name = "pimalaya-secret" +version = "0.0.1" +dependencies = [ + "log", + "pimalaya-keyring", + "pimalaya-oauth2", + "pimalaya-process", + "thiserror", +] + [[package]] name = "pin-project-lite" version = "0.2.9" diff --git a/Cargo.toml b/Cargo.toml index 245ed59..e4507b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,15 +43,19 @@ clap = "4.0" clap_complete = "4.0" clap_mangen = "0.2" console = "0.15.2" -dirs = "4.0.0" dialoguer = "0.10.2" +dirs = "4.0.0" email_address = "0.2.4" env_logger = "0.8" erased-serde = "0.3" -pimalaya-email = { git = "https://git.sr.ht/~soywod/pimalaya" } indicatif = "0.17" log = "0.4" once_cell = "1.16.0" +# pimalaya-email = { 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 ad36f49..79d2669 100644 --- a/src/config/prelude.rs +++ b/src/config/prelude.rs @@ -1,8 +1,11 @@ use pimalaya_email::{ folder::sync::Strategy as SyncFoldersStrategy, EmailHooks, EmailSender, EmailTextPlainFormat, - ImapAuthConfig, MaildirConfig, OAuth2ClientSecret, OAuth2Config, OAuth2Method, OAuth2Scopes, - SendmailConfig, SmtpConfig, + ImapAuthConfig, MaildirConfig, OAuth2Config, OAuth2Method, OAuth2Scopes, SendmailConfig, + SmtpConfig, }; +use pimalaya_keyring::Entry; +use pimalaya_process::Cmd; +use pimalaya_secret::Secret; use serde::{Deserialize, Serialize}; use std::{collections::HashSet, path::PathBuf}; @@ -12,6 +15,14 @@ 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, Default, Eq, PartialEq, Deserialize, Serialize)] #[serde(remote = "SmtpConfig")] struct SmtpConfigDef { @@ -47,7 +58,7 @@ pub struct ImapConfigDef { pub insecure: Option, #[serde(rename = "imap-login")] pub login: String, - #[serde(rename = "imap-auth", with = "ImapAuthConfigDef")] + #[serde(flatten, with = "ImapAuthConfigDef")] pub auth: ImapAuthConfig, #[serde(rename = "imap-notify-cmd")] pub notify_cmd: Option, @@ -58,26 +69,44 @@ pub struct ImapConfigDef { } #[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] -#[serde(remote = "ImapAuthConfig", rename_all = "kebab-case")] +#[serde(remote = "ImapAuthConfig", tag = "imap-auth", rename_all = "lowercase")] pub enum ImapAuthConfigDef { #[serde(skip)] None, - RawPasswd(String), - PasswdCmd(String), - #[serde(with = "OAuth2ConfigDef", rename = "oauth2")] + #[serde(with = "PasswdDef")] + Passwd(Secret), + #[serde(with = "OAuth2ConfigDef")] OAuth2(OAuth2Config), } +#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] +#[serde(remote = "Secret", rename_all = "kebab-case")] +pub enum PasswdDef { + #[serde(rename = "imap-passwd")] + Raw(String), + #[serde(rename = "imap-passwd-cmd", with = "CmdDef")] + Cmd(Cmd), + #[serde(rename = "imap-passwd-keyring", with = "EntryDef")] + Keyring(Entry), +} + #[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] #[serde(remote = "OAuth2Config", rename_all = "kebab-case")] pub struct OAuth2ConfigDef { - #[serde(with = "OAuth2MethodDef")] + #[serde(rename = "imap-oauth2-method", with = "OAuth2MethodDef")] pub method: OAuth2Method, + #[serde(rename = "imap-oauth2-client-id")] pub client_id: String, - #[serde(with = "OAuth2ClientSecretDef")] - pub client_secret: OAuth2ClientSecret, + #[serde(flatten, with = "ClientSecretDef")] + 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 = "AccessTokenDef")] + pub access_token: Secret, + #[serde(flatten, with = "RefreshTokenDef")] + pub refresh_token: Secret, #[serde(flatten, with = "OAuth2ScopesDef")] pub scopes: OAuth2Scopes, #[serde(default)] @@ -85,24 +114,53 @@ pub struct OAuth2ConfigDef { } #[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] -#[serde(remote = "OAuth2ClientSecret", rename_all = "kebab-case")] -pub enum OAuth2ClientSecretDef { +#[serde(remote = "Secret", rename_all = "kebab-case")] +pub enum ClientSecretDef { + #[serde(rename = "imap-oauth2-client-secret")] Raw(String), - Cmd(String), - Keyring, + #[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 = "OAuth2Method", rename_all = "lowercase")] +#[serde(remote = "Secret", rename_all = "kebab-case")] +pub enum AccessTokenDef { + #[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", rename_all = "kebab-case")] +pub enum RefreshTokenDef { + #[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 = "OAuth2Method")] pub enum OAuth2MethodDef { + #[serde(rename = "xoauth2", alias = "XOAUTH2")] XOAuth2, + #[serde(rename = "oauthbearer", alias = "OAUTHBEARER")] OAuthBearer, } #[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] #[serde(remote = "OAuth2Scopes", rename_all = "kebab-case")] pub enum OAuth2ScopesDef { + #[serde(rename = "imap-oauth2-scope")] Scope(String), + #[serde(rename = "imap-oauth2-scopes")] Scopes(Vec), } diff --git a/src/domain/account/handlers.rs b/src/domain/account/handlers.rs index 79f7921..c354941 100644 --- a/src/domain/account/handlers.rs +++ b/src/domain/account/handlers.rs @@ -17,27 +17,21 @@ use crate::{ }; /// Configure the current selected account -pub fn configure( - account_config: &AccountConfig, - backend_config: &BackendConfig, - reset: bool, -) -> Result<()> { +pub fn configure(backend_config: &BackendConfig, reset: bool) -> Result<()> { info!("entering the configure account handler"); match backend_config { BackendConfig::None => (), BackendConfig::Maildir(_) => (), #[cfg(feature = "imap-backend")] BackendConfig::Imap(imap_config) => { - imap_config.auth.configure( - &account_config.name, - reset, - configure_oauth2_client_secret, - )?; + imap_config + .auth + .configure(reset, configure_oauth2_client_secret)?; } #[cfg(feature = "notmuch-backend")] BackendConfig::Notmuch(config) => (), }; - println!("Account {} configured!", account_config.name); + println!("Account successfully configured!"); Ok(()) } diff --git a/src/main.rs b/src/main.rs index f6fff46..15e6834 100644 --- a/src/main.rs +++ b/src/main.rs @@ -138,7 +138,7 @@ fn main() -> Result<()> { return Ok(()); } Some(account::args::Cmd::Configure(reset)) => { - return account::handlers::configure(&account_config, &backend_config, reset); + return account::handlers::configure(&backend_config, reset); } _ => (), }