aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2020-04-20 00:05:01 -0400
committerJesse Luehrs <doy@tozt.net>2020-04-20 00:05:01 -0400
commit9db9908cd3aa97933a543800d69945484a81e62a (patch)
treebea0d991a4ae2fafda577aafc63b3f5e8bfdc875
parent19f9dc4877039c87de94080ac554cfa169e9cd71 (diff)
downloadrbw-9db9908cd3aa97933a543800d69945484a81e62a.tar.gz
rbw-9db9908cd3aa97933a543800d69945484a81e62a.zip
add folder as an option for list fields
-rw-r--r--src/api.rs32
-rw-r--r--src/bin/rbw/commands.rs23
-rw-r--r--src/db.rs1
3 files changed, 54 insertions, 2 deletions
diff --git a/src/api.rs b/src/api.rs
index 4de1285..eeca762 100644
--- a/src/api.rs
+++ b/src/api.rs
@@ -75,12 +75,16 @@ struct SyncRes {
ciphers: Vec<SyncResCipher>,
#[serde(rename = "Profile")]
profile: SyncResProfile,
+ #[serde(rename = "Folders")]
+ folders: Vec<SyncResFolder>,
}
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
struct SyncResCipher {
#[serde(rename = "Id")]
id: String,
+ #[serde(rename = "FolderId")]
+ folder_id: Option<String>,
#[serde(rename = "Name")]
name: String,
#[serde(rename = "Login")]
@@ -93,7 +97,10 @@ struct SyncResCipher {
impl SyncResCipher {
// TODO: handle other kinds of entries other than login
- fn to_entry(&self) -> Option<crate::db::Entry> {
+ fn to_entry(
+ &self,
+ folders: &[SyncResFolder],
+ ) -> Option<crate::db::Entry> {
if let Some(login) = &self.login {
let history = if let Some(history) = &self.password_history {
history
@@ -106,8 +113,20 @@ impl SyncResCipher {
} else {
vec![]
};
+ let folder = if let Some(folder_id) = &self.folder_id {
+ let mut folder_name = None;
+ for folder in folders {
+ if &folder.id == folder_id {
+ folder_name = Some(folder.name.clone());
+ }
+ }
+ folder_name
+ } else {
+ None
+ };
Some(crate::db::Entry {
id: self.id.clone(),
+ folder,
name: self.name.clone(),
username: login.username.clone(),
password: login.password.clone(),
@@ -126,6 +145,14 @@ struct SyncResProfile {
key: String,
}
+#[derive(serde::Deserialize, Debug, Clone)]
+struct SyncResFolder {
+ #[serde(rename = "Id")]
+ id: String,
+ #[serde(rename = "Name")]
+ name: String,
+}
+
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
struct SyncResLogin {
#[serde(rename = "Username")]
@@ -301,10 +328,11 @@ impl Client {
reqwest::StatusCode::OK => {
let sync_res: SyncRes =
res.json().await.context(crate::error::Reqwest)?;
+ let folders = sync_res.folders.clone();
let ciphers = sync_res
.ciphers
.iter()
- .filter_map(SyncResCipher::to_entry)
+ .filter_map(|cipher| cipher.to_entry(&folders))
.collect();
Ok((sync_res.profile.key, ciphers))
}
diff --git a/src/bin/rbw/commands.rs b/src/bin/rbw/commands.rs
index ee30950..6c9d18c 100644
--- a/src/bin/rbw/commands.rs
+++ b/src/bin/rbw/commands.rs
@@ -4,6 +4,7 @@ use anyhow::Context as _;
#[cfg_attr(test, derive(Eq, PartialEq))]
struct DecryptedCipher {
id: String,
+ folder: Option<String>,
name: String,
username: Option<String>,
password: Option<String>,
@@ -22,6 +23,7 @@ enum ListField {
Name,
Id,
User,
+ Folder,
}
impl std::convert::TryFrom<&str> for ListField {
@@ -32,6 +34,7 @@ impl std::convert::TryFrom<&str> for ListField {
"name" => Self::Name,
"id" => Self::Id,
"user" => Self::User,
+ "folder" => Self::Folder,
_ => return Err(anyhow::anyhow!("unknown field {}", s)),
})
}
@@ -127,6 +130,11 @@ pub fn list(fields: &[&str]) -> anyhow::Result<()> {
.as_ref()
.map(std::string::ToString::to_string)
.unwrap_or_else(|| "".to_string()),
+ ListField::Folder => cipher
+ .folder
+ .as_ref()
+ .map(std::string::ToString::to_string)
+ .unwrap_or_else(|| "".to_string()),
})
.collect();
println!("{}", values.join("\t"));
@@ -610,6 +618,18 @@ fn find_entry_raw(
}
fn decrypt_cipher(entry: &rbw::db::Entry) -> anyhow::Result<DecryptedCipher> {
+ let folder = entry
+ .folder
+ .as_ref()
+ .map(|folder| crate::actions::decrypt(folder))
+ .transpose();
+ let folder = match folder {
+ Ok(folder) => folder,
+ Err(e) => {
+ log::warn!("failed to decrypt folder name: {}", e);
+ None
+ }
+ };
let username = entry
.username
.as_ref()
@@ -658,6 +678,7 @@ fn decrypt_cipher(entry: &rbw::db::Entry) -> anyhow::Result<DecryptedCipher> {
.collect::<anyhow::Result<_>>()?;
Ok(DecryptedCipher {
id: entry.id.clone(),
+ folder,
name: crate::actions::decrypt(&entry.name)?,
username,
password,
@@ -780,6 +801,7 @@ mod test {
(
rbw::db::Entry {
id: "irrelevant".to_string(),
+ folder: None,
name: "this is the encrypted name".to_string(),
username: username
.map(|_| "this is the encrypted username".to_string()),
@@ -789,6 +811,7 @@ mod test {
},
DecryptedCipher {
id: "irrelevant".to_string(),
+ folder: None,
name: name.to_string(),
username: username.map(std::string::ToString::to_string),
password: None,
diff --git a/src/db.rs b/src/db.rs
index 9a02598..206e888 100644
--- a/src/db.rs
+++ b/src/db.rs
@@ -8,6 +8,7 @@ use tokio::io::{AsyncReadExt as _, AsyncWriteExt as _};
)]
pub struct Entry {
pub id: String,
+ pub folder: Option<String>,
pub name: String,
pub username: Option<String>,
pub password: Option<String>,