aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2023-02-18 20:40:08 -0500
committerJesse Luehrs <doy@tozt.net>2023-02-18 20:40:08 -0500
commit9d9d5dac7a2e342a35482756ef7c92d045f8f835 (patch)
tree21fa0b05cd89a8a47fad6e766d609649805f45e3
parent323a4a954afc3ec7f7bcda0fd914219c7c2d146d (diff)
downloadrbw-9d9d5dac7a2e342a35482756ef7c92d045f8f835.tar.gz
rbw-9d9d5dac7a2e342a35482756ef7c92d045f8f835.zip
refactor client cert handling
-rw-r--r--src/actions.rs2
-rw-r--r--src/api.rs61
-rw-r--r--src/bin/rbw/commands.rs3
-rw-r--r--src/config.rs6
-rw-r--r--src/error.rs12
5 files changed, 56 insertions, 28 deletions
diff --git a/src/actions.rs b/src/actions.rs
index a7829a4..ca5e448 100644
--- a/src/actions.rs
+++ b/src/actions.rs
@@ -5,7 +5,7 @@ fn api_client() -> Result<(crate::api::Client, crate::config::Config)> {
let client = crate::api::Client::new(
&config.base_url(),
&config.identity_url(),
- &config.client_cert_path(),
+ config.client_cert_path(),
);
Ok((client, config))
}
diff --git a/src/api.rs b/src/api.rs
index 44d0fe0..b6cb4d4 100644
--- a/src/api.rs
+++ b/src/api.rs
@@ -8,8 +8,7 @@ use crate::json::{
DeserializeJsonWithPath as _, DeserializeJsonWithPathAsync as _,
};
-use std::fs::File;
-use std::io::Read;
+use tokio::io::AsyncReadExt as _;
#[derive(
serde_repr::Serialize_repr,
@@ -554,7 +553,7 @@ struct FoldersPostReq {
pub struct Client {
base_url: String,
identity_url: String,
- client_cert_path: String,
+ client_cert_path: Option<std::path::PathBuf>,
}
impl Client {
@@ -562,29 +561,45 @@ impl Client {
pub fn new(
base_url: &str,
identity_url: &str,
- client_cert_path: &str,
+ client_cert_path: Option<&std::path::Path>,
) -> Self {
Self {
base_url: base_url.to_string(),
identity_url: identity_url.to_string(),
- client_cert_path: client_cert_path.to_string(),
+ client_cert_path: client_cert_path
+ .map(std::path::Path::to_path_buf),
}
}
- fn reqwest_client(&self) -> reqwest::Client {
- if self.client_cert_path.is_empty() {
- reqwest::Client::new()
- } else {
+ async fn reqwest_client(&self) -> Result<reqwest::Client> {
+ if let Some(client_cert_path) = self.client_cert_path.as_ref() {
let mut buf = Vec::new();
- let mut f =
- File::open(&self.client_cert_path).expect("cert not found");
- f.read_to_end(&mut buf).expect("cert read failed");
- let pem =
- reqwest::Identity::from_pem(&buf).expect("invalid cert");
- reqwest::Client::builder()
- .identity(pem)
- .build()
- .expect("wtv")
+ let mut f = tokio::fs::File::open(client_cert_path)
+ .await
+ .map_err(|e| Error::LoadClientCert {
+ source: e,
+ file: client_cert_path.clone(),
+ })?;
+ f.read_to_end(&mut buf).await.map_err(|e| {
+ Error::LoadClientCert {
+ source: e,
+ file: client_cert_path.clone(),
+ }
+ })?;
+ let pem = reqwest::Identity::from_pem(&buf).map_err(|e| {
+ Error::LoadClientCertReqwest {
+ source: e,
+ file: client_cert_path.clone(),
+ }
+ })?;
+ Ok(reqwest::Client::builder().identity(pem).build().map_err(
+ |e| Error::LoadClientCertReqwest {
+ source: e,
+ file: client_cert_path.clone(),
+ },
+ )?)
+ } else {
+ Ok(reqwest::Client::new())
}
}
@@ -592,7 +607,7 @@ impl Client {
let prelogin = PreloginReq {
email: email.to_string(),
};
- let client = self.reqwest_client();
+ let client = self.reqwest_client().await?;
let res = client
.post(&self.api_url("/accounts/prelogin"))
.json(&prelogin)
@@ -627,7 +642,7 @@ impl Client {
two_factor_token: None,
two_factor_provider: None,
};
- let client = self.reqwest_client();
+ let client = self.reqwest_client().await?;
let res = client
.post(&self.identity_url("/connect/token"))
.form(&connect_req)
@@ -668,7 +683,7 @@ impl Client {
#[allow(clippy::as_conversions)]
two_factor_provider: two_factor_provider.map(|ty| ty as u32),
};
- let client = self.reqwest_client();
+ let client = self.reqwest_client().await?;
let res = client
.post(&self.identity_url("/connect/token"))
.form(&connect_req)
@@ -702,7 +717,7 @@ impl Client {
std::collections::HashMap<String, String>,
Vec<crate::db::Entry>,
)> {
- let client = self.reqwest_client();
+ let client = self.reqwest_client().await?;
let res = client
.get(&self.api_url("/sync"))
.header("Authorization", format!("Bearer {access_token}"))
@@ -1098,7 +1113,7 @@ impl Client {
client_id: "desktop".to_string(),
refresh_token: refresh_token.to_string(),
};
- let client = self.reqwest_client();
+ let client = self.reqwest_client().await?;
let res = client
.post(&self.identity_url("/connect/token"))
.form(&connect_req)
diff --git a/src/bin/rbw/commands.rs b/src/bin/rbw/commands.rs
index dda35e8..a2516d6 100644
--- a/src/bin/rbw/commands.rs
+++ b/src/bin/rbw/commands.rs
@@ -617,7 +617,8 @@ pub fn config_set(key: &str, value: &str) -> anyhow::Result<()> {
"base_url" => config.base_url = Some(value.to_string()),
"identity_url" => config.identity_url = Some(value.to_string()),
"client_cert_path" => {
- config.client_cert_path = Some(value.to_string());
+ config.client_cert_path =
+ Some(std::path::PathBuf::from(value.to_string()));
}
"lock_timeout" => {
let timeout = value
diff --git a/src/config.rs b/src/config.rs
index 8209ddb..91aa449 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -12,7 +12,7 @@ pub struct Config {
pub lock_timeout: u64,
#[serde(default = "default_pinentry")]
pub pinentry: String,
- pub client_cert_path: Option<String>,
+ pub client_cert_path: Option<std::path::PathBuf>,
// backcompat, no longer generated in new configs
#[serde(skip_serializing)]
pub device_id: Option<String>,
@@ -151,8 +151,8 @@ impl Config {
}
#[must_use]
- pub fn client_cert_path(&self) -> String {
- self.client_cert_path.clone().unwrap_or_default()
+ pub fn client_cert_path(&self) -> Option<&std::path::Path> {
+ self.client_cert_path.as_deref()
}
#[must_use]
diff --git a/src/error.rs b/src/error.rs
index 41d0d4a..d165a92 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -118,6 +118,18 @@ pub enum Error {
file: std::path::PathBuf,
},
+ #[error("failed to load client cert from {}", .file.display())]
+ LoadClientCert {
+ source: tokio::io::Error,
+ file: std::path::PathBuf,
+ },
+
+ #[error("failed to load client cert from {}", .file.display())]
+ LoadClientCertReqwest {
+ source: reqwest::Error,
+ file: std::path::PathBuf,
+ },
+
#[error("invalid padding")]
Padding,