bump pimalaya-oauth2 0.0.4 with async

This commit is contained in:
Clément DOUIN 2023-07-20 11:43:28 +02:00
parent fff82498ba
commit a8bd265181
No known key found for this signature in database
GPG key ID: 353E4A18EE0FAB72
11 changed files with 849 additions and 118 deletions

755
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
[package]
name = "himalaya"
description = "CLI to manage your emails."
version = "0.8.4"
version = "0.8.4-beta"
authors = ["soywod <clement.douin@posteo.net>"]
edition = "2021"
license = "MIT"
@ -45,9 +45,9 @@ indicatif = "0.17"
log = "0.4"
md5 = "0.7.0"
once_cell = "1.16.0"
pimalaya-email = "=0.14.0"
pimalaya-email = { git = "https://git.sr.ht/~soywod/pimalaya", default-features = false }
pimalaya-keyring = "=0.0.5"
pimalaya-oauth2 = "=0.0.3"
pimalaya-oauth2 = "=0.0.4"
pimalaya-process = "=0.0.5"
pimalaya-secret = "=0.0.5"
serde = { version = "1.0", features = ["derive"] }

View file

@ -84,7 +84,7 @@ pub struct DeserializedConfig {
impl DeserializedConfig {
/// Tries to create a config from an optional path.
pub fn from_opt_path(path: Option<&str>) -> Result<Self> {
pub async fn from_opt_path(path: Option<&str>) -> Result<Self> {
debug!("path: {:?}", path);
let config = if let Some(path) = path.map(PathBuf::from).or_else(Self::path) {
@ -104,7 +104,7 @@ impl DeserializedConfig {
process::exit(0);
}
wizard::configure()?
wizard::configure().await?
};
if config.accounts.is_empty() {
@ -179,15 +179,15 @@ mod tests {
use super::*;
fn make_config(config: &str) -> Result<DeserializedConfig> {
async fn make_config(config: &str) -> Result<DeserializedConfig> {
let mut file = NamedTempFile::new().unwrap();
write!(file, "{}", config).unwrap();
DeserializedConfig::from_opt_path(file.into_temp_path().to_str())
DeserializedConfig::from_opt_path(file.into_temp_path().to_str()).await
}
#[test]
fn empty_config() {
let config = make_config("");
#[tokio::test]
async fn empty_config() {
let config = make_config("").await;
assert_eq!(
config.unwrap_err().root_cause().to_string(),
@ -195,9 +195,9 @@ mod tests {
);
}
#[test]
fn account_missing_email_field() {
let config = make_config("[account]");
#[tokio::test]
async fn account_missing_email_field() {
let config = make_config("[account]").await;
assert!(config
.unwrap_err()
@ -206,12 +206,13 @@ mod tests {
.contains("missing field `email`"));
}
#[test]
fn account_missing_backend_field() {
#[tokio::test]
async fn account_missing_backend_field() {
let config = make_config(
"[account]
email = \"test@localhost\"",
);
)
.await;
assert!(config
.unwrap_err()
@ -220,13 +221,14 @@ mod tests {
.contains("missing field `backend`"));
}
#[test]
fn account_invalid_backend_field() {
#[tokio::test]
async fn account_invalid_backend_field() {
let config = make_config(
"[account]
email = \"test@localhost\"
backend = \"bad\"",
);
)
.await;
assert!(config
.unwrap_err()
@ -235,14 +237,15 @@ mod tests {
.contains("unknown variant `bad`"));
}
#[test]
fn imap_account_missing_host_field() {
#[tokio::test]
async fn imap_account_missing_host_field() {
let config = make_config(
"[account]
email = \"test@localhost\"
sender = \"none\"
backend = \"imap\"",
);
)
.await;
assert!(config
.unwrap_err()
@ -251,15 +254,16 @@ mod tests {
.contains("missing field `imap-host`"));
}
#[test]
fn account_backend_imap_missing_port_field() {
#[tokio::test]
async fn account_backend_imap_missing_port_field() {
let config = make_config(
"[account]
email = \"test@localhost\"
sender = \"none\"
backend = \"imap\"
imap-host = \"localhost\"",
);
)
.await;
assert!(config
.unwrap_err()
@ -268,8 +272,8 @@ mod tests {
.contains("missing field `imap-port`"));
}
#[test]
fn account_backend_imap_missing_login_field() {
#[tokio::test]
async fn account_backend_imap_missing_login_field() {
let config = make_config(
"[account]
email = \"test@localhost\"
@ -277,7 +281,8 @@ mod tests {
backend = \"imap\"
imap-host = \"localhost\"
imap-port = 993",
);
)
.await;
assert!(config
.unwrap_err()
@ -286,8 +291,8 @@ mod tests {
.contains("missing field `imap-login`"));
}
#[test]
fn account_backend_imap_missing_passwd_cmd_field() {
#[tokio::test]
async fn account_backend_imap_missing_passwd_cmd_field() {
let config = make_config(
"[account]
email = \"test@localhost\"
@ -296,7 +301,8 @@ mod tests {
imap-host = \"localhost\"
imap-port = 993
imap-login = \"login\"",
);
)
.await;
assert!(config
.unwrap_err()
@ -305,14 +311,15 @@ mod tests {
.contains("missing field `imap-auth`"));
}
#[test]
fn account_backend_maildir_missing_root_dir_field() {
#[tokio::test]
async fn account_backend_maildir_missing_root_dir_field() {
let config = make_config(
"[account]
email = \"test@localhost\"
sender = \"none\"
backend = \"maildir\"",
);
)
.await;
assert!(config
.unwrap_err()
@ -322,14 +329,15 @@ mod tests {
}
#[cfg(feature = "notmuch-backend")]
#[test]
fn account_backend_notmuch_missing_db_path_field() {
#[tokio::test]
async fn account_backend_notmuch_missing_db_path_field() {
let config = make_config(
"[account]
email = \"test@localhost\"
sender = \"none\"
backend = \"notmuch\"",
);
)
.await;
assert!(config
.unwrap_err()
@ -338,13 +346,14 @@ mod tests {
.contains("missing field `notmuch-db-path`"));
}
#[test]
fn account_missing_sender_field() {
#[tokio::test]
async fn account_missing_sender_field() {
let config = make_config(
"[account]
email = \"test@localhost\"
backend = \"none\"",
);
)
.await;
assert!(config
.unwrap_err()
@ -353,14 +362,15 @@ mod tests {
.contains("missing field `sender`"));
}
#[test]
fn account_invalid_sender_field() {
#[tokio::test]
async fn account_invalid_sender_field() {
let config = make_config(
"[account]
email = \"test@localhost\"
backend = \"none\"
sender = \"bad\"",
);
)
.await;
assert!(config
.unwrap_err()
@ -369,14 +379,15 @@ mod tests {
.contains("unknown variant `bad`, expected one of `none`, `smtp`, `sendmail`"),);
}
#[test]
fn account_smtp_sender_missing_host_field() {
#[tokio::test]
async fn account_smtp_sender_missing_host_field() {
let config = make_config(
"[account]
email = \"test@localhost\"
backend = \"none\"
sender = \"smtp\"",
);
)
.await;
assert!(config
.unwrap_err()
@ -385,15 +396,16 @@ mod tests {
.contains("missing field `smtp-host`"));
}
#[test]
fn account_smtp_sender_missing_port_field() {
#[tokio::test]
async fn account_smtp_sender_missing_port_field() {
let config = make_config(
"[account]
email = \"test@localhost\"
backend = \"none\"
sender = \"smtp\"
smtp-host = \"localhost\"",
);
)
.await;
assert!(config
.unwrap_err()
@ -402,8 +414,8 @@ mod tests {
.contains("missing field `smtp-port`"));
}
#[test]
fn account_smtp_sender_missing_login_field() {
#[tokio::test]
async fn account_smtp_sender_missing_login_field() {
let config = make_config(
"[account]
email = \"test@localhost\"
@ -411,7 +423,8 @@ mod tests {
sender = \"smtp\"
smtp-host = \"localhost\"
smtp-port = 25",
);
)
.await;
assert!(config
.unwrap_err()
@ -420,8 +433,8 @@ mod tests {
.contains("missing field `smtp-login`"));
}
#[test]
fn account_smtp_sender_missing_auth_field() {
#[tokio::test]
async fn account_smtp_sender_missing_auth_field() {
let config = make_config(
"[account]
email = \"test@localhost\"
@ -430,7 +443,8 @@ mod tests {
smtp-host = \"localhost\"
smtp-port = 25
smtp-login = \"login\"",
);
)
.await;
assert!(config
.unwrap_err()
@ -439,14 +453,15 @@ mod tests {
.contains("missing field `smtp-auth`"));
}
#[test]
fn account_sendmail_sender_missing_cmd_field() {
#[tokio::test]
async fn account_sendmail_sender_missing_cmd_field() {
let config = make_config(
"[account]
email = \"test@localhost\"
backend = \"none\"
sender = \"sendmail\"",
);
)
.await;
assert!(config
.unwrap_err()
@ -456,8 +471,8 @@ mod tests {
}
#[cfg(feature = "smtp-sender")]
#[test]
fn account_smtp_sender_minimum_config() {
#[tokio::test]
async fn account_smtp_sender_minimum_config() {
use pimalaya_email::sender::SenderConfig;
let config = make_config(
@ -470,7 +485,8 @@ mod tests {
smtp-login = \"login\"
smtp-auth = \"passwd\"
smtp-passwd = { cmd = \"echo password\" }",
);
)
.await;
assert_eq!(
config.unwrap(),
@ -493,18 +509,19 @@ mod tests {
)]),
..DeserializedConfig::default()
}
);
)
}
#[test]
fn account_sendmail_sender_minimum_config() {
#[tokio::test]
async fn account_sendmail_sender_minimum_config() {
let config = make_config(
"[account]
email = \"test@localhost\"
backend = \"none\"
sender = \"sendmail\"
sendmail-cmd = \"echo send\"",
);
)
.await;
assert_eq!(
config.unwrap(),
@ -521,11 +538,11 @@ mod tests {
)]),
..DeserializedConfig::default()
}
);
)
}
#[test]
fn account_backend_imap_minimum_config() {
#[tokio::test]
async fn account_backend_imap_minimum_config() {
let config = make_config(
"[account]
email = \"test@localhost\"
@ -536,7 +553,8 @@ mod tests {
imap-login = \"login\"
imap-auth = \"passwd\"
imap-passwd = { cmd = \"echo password\" }",
);
)
.await;
assert_eq!(
config.unwrap(),
@ -559,17 +577,19 @@ mod tests {
)]),
..DeserializedConfig::default()
}
);
)
}
#[test]
fn account_backend_maildir_minimum_config() {
#[tokio::test]
async fn account_backend_maildir_minimum_config() {
let config = make_config(
"[account]
email = \"test@localhost\"
sender = \"none\"
backend = \"maildir\"
maildir-root-dir = \"/tmp/maildir\"",
);
)
.await;
assert_eq!(
config.unwrap(),
@ -586,19 +606,20 @@ mod tests {
)]),
..DeserializedConfig::default()
}
);
)
}
#[cfg(feature = "notmuch-backend")]
#[test]
fn account_backend_notmuch_minimum_config() {
#[tokio::test]
async fn account_backend_notmuch_minimum_config() {
let config = make_config(
"[account]
email = \"test@localhost\"
sender = \"none\"
backend = \"notmuch\"
notmuch-db-path = \"/tmp/notmuch.db\"",
);
)
.await;
assert_eq!(
config.unwrap(),

View file

@ -30,12 +30,12 @@ macro_rules! wizard_log {
pub(crate) static THEME: Lazy<ColorfulTheme> = Lazy::new(ColorfulTheme::default);
pub(crate) fn configure() -> Result<DeserializedConfig> {
pub(crate) async fn configure() -> Result<DeserializedConfig> {
wizard_log!("Configuring your first account:");
let mut config = DeserializedConfig::default();
while let Some((name, account_config)) = account::wizard::configure()? {
while let Some((name, account_config)) = account::wizard::configure().await? {
config.accounts.insert(name, account_config);
if !Confirm::new()

View file

@ -258,6 +258,7 @@ impl DeserializedAccountConfig {
sender
},
pgp: Default::default(),
}
}
}

View file

@ -6,7 +6,7 @@ use crate::{backend, config::wizard::THEME, sender};
use super::DeserializedAccountConfig;
pub(crate) fn configure() -> Result<Option<(String, DeserializedAccountConfig)>> {
pub(crate) async fn configure() -> Result<Option<(String, DeserializedAccountConfig)>> {
let mut config = DeserializedAccountConfig::default();
let account_name = Input::with_theme(&*THEME)
@ -31,9 +31,9 @@ pub(crate) fn configure() -> Result<Option<(String, DeserializedAccountConfig)>>
.interact()?,
);
config.backend = backend::wizard::configure(&account_name, &config.email)?;
config.backend = backend::wizard::configure(&account_name, &config.email).await?;
config.sender = sender::wizard::configure(&account_name, &config.email)?;
config.sender = sender::wizard::configure(&account_name, &config.email).await?;
Ok(Some((account_name, config)))
}

View file

@ -30,7 +30,7 @@ const KEYRING: &str = "Ask my password, then save it in my system's global keyri
const RAW: &str = "Ask my password, then save it in the configuration file (not safe)";
const CMD: &str = "Ask me a shell command that exposes my password";
pub(crate) fn configure(account_name: &str, email: &str) -> Result<BackendConfig> {
pub(crate) async fn configure(account_name: &str, email: &str) -> Result<BackendConfig> {
let mut config = ImapConfig::default();
config.host = Input::with_theme(&*THEME)
@ -201,8 +201,9 @@ pub(crate) fn configure(account_name: &str, email: &str) -> Result<BackendConfig
println!("{}", redirect_url.to_string());
println!("");
let (access_token, refresh_token) =
auth_code_grant.wait_for_redirection(&client, csrf_token)?;
let (access_token, refresh_token) = auth_code_grant
.wait_for_redirection(&client, csrf_token)
.await?;
Secret::new_keyring_entry(format!("{account_name}-imap-oauth2-access-token"))
.set_keyring_entry_secret(access_token)?;

View file

@ -26,7 +26,7 @@ const BACKENDS: &[&str] = &[
NONE,
];
pub(crate) fn configure(account_name: &str, email: &str) -> Result<BackendConfig> {
pub(crate) async fn configure(account_name: &str, email: &str) -> Result<BackendConfig> {
let backend = Select::with_theme(&*THEME)
.with_prompt("Email backend")
.items(BACKENDS)
@ -35,7 +35,7 @@ pub(crate) fn configure(account_name: &str, email: &str) -> Result<BackendConfig
match backend {
#[cfg(feature = "imap-backend")]
Some(idx) if BACKENDS[idx] == IMAP => imap::wizard::configure(account_name, email),
Some(idx) if BACKENDS[idx] == IMAP => imap::wizard::configure(account_name, email).await,
Some(idx) if BACKENDS[idx] == MAILDIR => maildir::wizard::configure(),
#[cfg(feature = "notmuch-backend")]
Some(idx) if BACKENDS[idx] == NOTMUCH => notmuch::wizard::configure(),

View file

@ -30,7 +30,7 @@ const KEYRING: &str = "Ask the password, then save it in my system's global keyr
const RAW: &str = "Ask the password, then save it in the configuration file (not safe)";
const CMD: &str = "Use a shell command that exposes the password";
pub(crate) fn configure(account_name: &str, email: &str) -> Result<SenderConfig> {
pub(crate) async fn configure(account_name: &str, email: &str) -> Result<SenderConfig> {
let mut config = SmtpConfig::default();
config.host = Input::with_theme(&*THEME)
@ -201,8 +201,9 @@ pub(crate) fn configure(account_name: &str, email: &str) -> Result<SenderConfig>
println!("{}", redirect_url.to_string());
println!("");
let (access_token, refresh_token) =
auth_code_grant.wait_for_redirection(&client, csrf_token)?;
let (access_token, refresh_token) = auth_code_grant
.wait_for_redirection(&client, csrf_token)
.await?;
Secret::new_keyring_entry(format!("{account_name}-smtp-oauth2-access-token"))
.set_keyring_entry_secret(access_token)?;

View file

@ -20,7 +20,7 @@ const SENDERS: &[&str] = &[
NONE,
];
pub(crate) fn configure(account_name: &str, email: &str) -> Result<SenderConfig> {
pub(crate) async fn configure(account_name: &str, email: &str) -> Result<SenderConfig> {
let sender = Select::with_theme(&*THEME)
.with_prompt("Email sender")
.items(SENDERS)
@ -29,7 +29,7 @@ pub(crate) fn configure(account_name: &str, email: &str) -> Result<SenderConfig>
match sender {
#[cfg(feature = "smtp-sender")]
Some(n) if SENDERS[n] == SMTP => smtp::wizard::configure(account_name, email),
Some(n) if SENDERS[n] == SMTP => smtp::wizard::configure(account_name, email).await,
Some(n) if SENDERS[n] == SENDMAIL => sendmail::wizard::configure(),
_ => Ok(SenderConfig::None),
}

View file

@ -61,7 +61,7 @@ async fn main() -> Result<()> {
let raw_args: Vec<String> = env::args().collect();
if raw_args.len() > 1 && raw_args[1].starts_with("mailto:") {
let url = Url::parse(&raw_args[1])?;
let config = DeserializedConfig::from_opt_path(None)?;
let config = DeserializedConfig::from_opt_path(None).await?;
let account_config = config.to_account_config(None)?;
let mut backend = BackendBuilder::new(account_config.clone()).build().await?;
let mut sender = SenderBuilder::new(account_config.clone()).build().await?;
@ -99,7 +99,7 @@ async fn main() -> Result<()> {
_ => (),
}
let config = DeserializedConfig::from_opt_path(config::args::parse_arg(&m))?;
let config = DeserializedConfig::from_opt_path(config::args::parse_arg(&m)).await?;
let account_config = config.to_account_config(account::args::parse_arg(&m))?;
let folder = folder::args::parse_source_arg(&m);
let disable_cache = cache::args::parse_disable_cache_flag(&m);