mirror of
https://github.com/soywod/himalaya.git
synced 2024-11-25 04:20:22 +00:00
improve oauth2 config deserialization and configuration
This commit is contained in:
parent
21f67bc7f5
commit
f026e48733
9 changed files with 84 additions and 32 deletions
12
Cargo.lock
generated
12
Cargo.lock
generated
|
@ -2098,6 +2098,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pimalaya-email"
|
name = "pimalaya-email"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
|
source = "git+https://git.sr.ht/~soywod/pimalaya#22db3ec886536897c54b72d4ab7d20beff0ffecc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ammonia",
|
"ammonia",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
@ -2138,6 +2139,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pimalaya-oauth2"
|
name = "pimalaya-oauth2"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
|
source = "git+https://git.sr.ht/~soywod/pimalaya#22db3ec886536897c54b72d4ab7d20beff0ffecc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"oauth2",
|
"oauth2",
|
||||||
|
@ -2650,22 +2652,22 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.152"
|
version = "1.0.160"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
|
checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.152"
|
version = "1.0.160"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
|
checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 1.0.104",
|
"syn 2.0.15",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -48,8 +48,7 @@ dialoguer = "0.10.2"
|
||||||
email_address = "0.2.4"
|
email_address = "0.2.4"
|
||||||
env_logger = "0.8"
|
env_logger = "0.8"
|
||||||
erased-serde = "0.3"
|
erased-serde = "0.3"
|
||||||
# pimalaya-email = "0.7.1"
|
pimalaya-email = { git = "https://git.sr.ht/~soywod/pimalaya" }
|
||||||
pimalaya-email = { path = "/home/soywod/sourcehut/pimalaya/email" }
|
|
||||||
indicatif = "0.17"
|
indicatif = "0.17"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
once_cell = "1.16.0"
|
once_cell = "1.16.0"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
pub mod args;
|
pub mod args;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod prelude;
|
pub mod prelude;
|
||||||
mod wizard;
|
pub(crate) mod wizard;
|
||||||
|
|
||||||
pub use config::*;
|
pub use config::*;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use pimalaya_email::{
|
use pimalaya_email::{
|
||||||
folder::sync::Strategy as SyncFoldersStrategy, EmailHooks, EmailSender, EmailTextPlainFormat,
|
folder::sync::Strategy as SyncFoldersStrategy, EmailHooks, EmailSender, EmailTextPlainFormat,
|
||||||
ImapAuthConfig, MaildirConfig, OAuth2Config, OAuth2Method, OAuth2Scopes, SendmailConfig,
|
ImapAuthConfig, MaildirConfig, OAuth2ClientSecret, OAuth2Config, OAuth2Method, OAuth2Scopes,
|
||||||
SmtpConfig,
|
SendmailConfig, SmtpConfig,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{collections::HashSet, path::PathBuf};
|
use std::{collections::HashSet, path::PathBuf};
|
||||||
|
@ -47,7 +47,7 @@ pub struct ImapConfigDef {
|
||||||
pub insecure: Option<bool>,
|
pub insecure: Option<bool>,
|
||||||
#[serde(rename = "imap-login")]
|
#[serde(rename = "imap-login")]
|
||||||
pub login: String,
|
pub login: String,
|
||||||
#[serde(flatten, with = "ImapAuthConfigDef")]
|
#[serde(rename = "imap-auth", with = "ImapAuthConfigDef")]
|
||||||
pub auth: ImapAuthConfig,
|
pub auth: ImapAuthConfig,
|
||||||
#[serde(rename = "imap-notify-cmd")]
|
#[serde(rename = "imap-notify-cmd")]
|
||||||
pub notify_cmd: Option<String>,
|
pub notify_cmd: Option<String>,
|
||||||
|
@ -57,16 +57,14 @@ pub struct ImapConfigDef {
|
||||||
pub watch_cmds: Option<Vec<String>>,
|
pub watch_cmds: Option<Vec<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
|
||||||
#[serde(remote = "ImapAuthConfig", rename_all = "kebab-case")]
|
#[serde(remote = "ImapAuthConfig", rename_all = "kebab-case")]
|
||||||
pub enum ImapAuthConfigDef {
|
pub enum ImapAuthConfigDef {
|
||||||
#[default]
|
#[serde(skip)]
|
||||||
None,
|
None,
|
||||||
#[serde(rename = "imap-passwd")]
|
RawPasswd(String),
|
||||||
Passwd(String),
|
|
||||||
#[serde(rename = "imap-passwd-cmd")]
|
|
||||||
PasswdCmd(String),
|
PasswdCmd(String),
|
||||||
#[serde(rename = "imap-oauth2", with = "OAuth2ConfigDef")]
|
#[serde(with = "OAuth2ConfigDef", rename = "oauth2")]
|
||||||
OAuth2(OAuth2Config),
|
OAuth2(OAuth2Config),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +74,8 @@ pub struct OAuth2ConfigDef {
|
||||||
#[serde(with = "OAuth2MethodDef")]
|
#[serde(with = "OAuth2MethodDef")]
|
||||||
pub method: OAuth2Method,
|
pub method: OAuth2Method,
|
||||||
pub client_id: String,
|
pub client_id: String,
|
||||||
pub client_secret: String,
|
#[serde(with = "OAuth2ClientSecretDef")]
|
||||||
|
pub client_secret: OAuth2ClientSecret,
|
||||||
pub auth_url: String,
|
pub auth_url: String,
|
||||||
pub token_url: String,
|
pub token_url: String,
|
||||||
#[serde(flatten, with = "OAuth2ScopesDef")]
|
#[serde(flatten, with = "OAuth2ScopesDef")]
|
||||||
|
@ -85,6 +84,14 @@ pub struct OAuth2ConfigDef {
|
||||||
pub pkce: bool,
|
pub pkce: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
|
||||||
|
#[serde(remote = "OAuth2ClientSecret", rename_all = "kebab-case")]
|
||||||
|
pub enum OAuth2ClientSecretDef {
|
||||||
|
Raw(String),
|
||||||
|
Cmd(String),
|
||||||
|
Keyring,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
|
||||||
#[serde(remote = "OAuth2Method", rename_all = "lowercase")]
|
#[serde(remote = "OAuth2Method", rename_all = "lowercase")]
|
||||||
pub enum OAuth2MethodDef {
|
pub enum OAuth2MethodDef {
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
use super::{SECURITY_PROTOCOLS, THEME};
|
|
||||||
use crate::account::{
|
|
||||||
DeserializedAccountConfig, DeserializedBaseAccountConfig, DeserializedImapAccountConfig,
|
|
||||||
};
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use dialoguer::{Input, Select};
|
use dialoguer::{Input, Select};
|
||||||
use pimalaya_email::ImapConfig;
|
use pimalaya_email::ImapConfig;
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
use crate::account::{
|
||||||
|
DeserializedAccountConfig, DeserializedBaseAccountConfig, DeserializedImapAccountConfig,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{SECURITY_PROTOCOLS, THEME};
|
||||||
|
|
||||||
#[cfg(feature = "imap-backend")]
|
#[cfg(feature = "imap-backend")]
|
||||||
pub(crate) fn configure(base: DeserializedBaseAccountConfig) -> Result<DeserializedAccountConfig> {
|
pub(crate) fn configure(base: DeserializedBaseAccountConfig) -> Result<DeserializedAccountConfig> {
|
||||||
|
@ -56,3 +59,11 @@ pub(crate) fn configure(base: DeserializedBaseAccountConfig) -> Result<Deseriali
|
||||||
DeserializedImapAccountConfig { base, backend },
|
DeserializedImapAccountConfig { base, backend },
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "imap-backend")]
|
||||||
|
pub(crate) fn configure_oauth2_client_secret() -> io::Result<String> {
|
||||||
|
Input::with_theme(&*THEME)
|
||||||
|
.with_prompt("Enter your OAuth 2.0 client secret:")
|
||||||
|
.report(false)
|
||||||
|
.interact()
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#[cfg(feature = "imap-backend")]
|
#[cfg(feature = "imap-backend")]
|
||||||
mod imap;
|
pub(crate) mod imap;
|
||||||
mod maildir;
|
mod maildir;
|
||||||
#[cfg(feature = "notmuch-backend")]
|
#[cfg(feature = "notmuch-backend")]
|
||||||
mod notmuch;
|
mod notmuch;
|
||||||
|
|
|
@ -10,12 +10,14 @@ use crate::{folder, ui::table};
|
||||||
|
|
||||||
const ARG_ACCOUNT: &str = "account";
|
const ARG_ACCOUNT: &str = "account";
|
||||||
const ARG_DRY_RUN: &str = "dry-run";
|
const ARG_DRY_RUN: &str = "dry-run";
|
||||||
|
const ARG_RESET: &str = "reset";
|
||||||
const CMD_ACCOUNTS: &str = "accounts";
|
const CMD_ACCOUNTS: &str = "accounts";
|
||||||
const CMD_CONFIGURE: &str = "configure";
|
const CMD_CONFIGURE: &str = "configure";
|
||||||
const CMD_LIST: &str = "list";
|
const CMD_LIST: &str = "list";
|
||||||
const CMD_SYNC: &str = "sync";
|
const CMD_SYNC: &str = "sync";
|
||||||
|
|
||||||
type DryRun = bool;
|
type DryRun = bool;
|
||||||
|
type Reset = bool;
|
||||||
|
|
||||||
/// Represents the account commands.
|
/// Represents the account commands.
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
@ -25,7 +27,7 @@ pub enum Cmd {
|
||||||
/// Represents the sync account command.
|
/// Represents the sync account command.
|
||||||
Sync(Option<SyncFoldersStrategy>, DryRun),
|
Sync(Option<SyncFoldersStrategy>, DryRun),
|
||||||
/// Configure the current selected account.
|
/// Configure the current selected account.
|
||||||
Configure,
|
Configure(Reset),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents the account command matcher.
|
/// Represents the account command matcher.
|
||||||
|
@ -54,9 +56,10 @@ pub fn matches(m: &ArgMatches) -> Result<Option<Cmd>> {
|
||||||
info!("list accounts subcommand matched");
|
info!("list accounts subcommand matched");
|
||||||
let max_table_width = table::args::parse_max_width(m);
|
let max_table_width = table::args::parse_max_width(m);
|
||||||
Some(Cmd::List(max_table_width))
|
Some(Cmd::List(max_table_width))
|
||||||
} else if let Some(_) = m.subcommand_matches(CMD_CONFIGURE) {
|
} else if let Some(m) = m.subcommand_matches(CMD_CONFIGURE) {
|
||||||
info!("configure account subcommand matched");
|
info!("configure account subcommand matched");
|
||||||
Some(Cmd::Configure)
|
let reset = parse_reset_flag(m);
|
||||||
|
Some(Cmd::Configure(reset))
|
||||||
} else {
|
} else {
|
||||||
info!("no account subcommand matched, falling back to subcommand list");
|
info!("no account subcommand matched, falling back to subcommand list");
|
||||||
Some(Cmd::List(None))
|
Some(Cmd::List(None))
|
||||||
|
@ -88,7 +91,8 @@ pub fn subcmd() -> Command {
|
||||||
.arg(dry_run()),
|
.arg(dry_run()),
|
||||||
Command::new(CMD_CONFIGURE)
|
Command::new(CMD_CONFIGURE)
|
||||||
.about("Configure the current selected account")
|
.about("Configure the current selected account")
|
||||||
.aliases(["config", "conf", "cfg"]),
|
.aliases(["config", "conf", "cfg"])
|
||||||
|
.arg(reset_flag()),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,3 +130,15 @@ Changes can be visualized with the RUST_LOG=trace environment variable.",
|
||||||
pub fn parse_dry_run_arg(m: &ArgMatches) -> bool {
|
pub fn parse_dry_run_arg(m: &ArgMatches) -> bool {
|
||||||
m.get_flag(ARG_DRY_RUN)
|
m.get_flag(ARG_DRY_RUN)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn reset_flag() -> Arg {
|
||||||
|
Arg::new(ARG_RESET)
|
||||||
|
.help("Reset the configuration")
|
||||||
|
.short('r')
|
||||||
|
.long("reset")
|
||||||
|
.action(ArgAction::SetTrue)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_reset_flag(m: &ArgMatches) -> bool {
|
||||||
|
m.get_flag(ARG_RESET)
|
||||||
|
}
|
||||||
|
|
|
@ -11,15 +11,32 @@ use pimalaya_email::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::DeserializedConfig,
|
config::{wizard::imap::configure_oauth2_client_secret, DeserializedConfig},
|
||||||
printer::{PrintTableOpts, Printer},
|
printer::{PrintTableOpts, Printer},
|
||||||
Accounts,
|
Accounts,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Configure the current selected account
|
/// Configure the current selected account
|
||||||
pub fn configure(account_config: &AccountConfig, backend_config: &BackendConfig) -> Result<()> {
|
pub fn configure(
|
||||||
|
account_config: &AccountConfig,
|
||||||
|
backend_config: &BackendConfig,
|
||||||
|
reset: bool,
|
||||||
|
) -> Result<()> {
|
||||||
info!("entering the configure account handler");
|
info!("entering the configure account handler");
|
||||||
backend_config.configure(&account_config.name)?;
|
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,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
#[cfg(feature = "notmuch-backend")]
|
||||||
|
BackendConfig::Notmuch(config) => (),
|
||||||
|
};
|
||||||
println!("Account {} configured!", account_config.name);
|
println!("Account {} configured!", account_config.name);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,8 +137,8 @@ fn main() -> Result<()> {
|
||||||
backend.close()?;
|
backend.close()?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
Some(account::args::Cmd::Configure) => {
|
Some(account::args::Cmd::Configure(reset)) => {
|
||||||
return account::handlers::configure(&account_config, &backend_config);
|
return account::handlers::configure(&account_config, &backend_config, reset);
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue