aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2020-05-03 23:57:48 -0400
committerJesse Luehrs <doy@tozt.net>2020-05-03 23:57:48 -0400
commit74870c135e43d5c9543033bd2c6fb484ff80e925 (patch)
tree8f9111ba70eeae82ffd22a4207e4f7ec5b4983f1
parent96d69d5e791c352b63a8d469bf5ff3eff5c4e8f8 (diff)
downloadrbw-74870c135e43d5c9543033bd2c6fb484ff80e925.tar.gz
rbw-74870c135e43d5c9543033bd2c6fb484ff80e925.zip
maintain folder and uris when editing an entry
-rw-r--r--CHANGELOG.md6
-rw-r--r--src/actions.rs37
-rw-r--r--src/api.rs41
-rw-r--r--src/bin/rbw/commands.rs56
-rw-r--r--src/db.rs2
-rw-r--r--src/protocol.rs2
6 files changed, 100 insertions, 44 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a5505f4..3121eea 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,11 @@
# Changelog
+## [0.2.1] - 2020-05-03
+
+### Fixed
+
+* Properly maintain folder and URIs when editing an entry.
+
## [0.2.0] - 2020-05-03
### Added
diff --git a/src/actions.rs b/src/actions.rs
index 4f37e5b..172dba6 100644
--- a/src/actions.rs
+++ b/src/actions.rs
@@ -115,11 +115,10 @@ pub fn add(
name: &str,
data: &crate::db::EntryData,
notes: Option<&str>,
- uris: &[String],
folder_id: Option<&str>,
) -> Result<(Option<String>, ())> {
with_exchange_refresh_token(access_token, refresh_token, |access_token| {
- add_once(access_token, name, data, notes, uris, folder_id)
+ add_once(access_token, name, data, notes, folder_id)
})
}
@@ -128,20 +127,12 @@ fn add_once(
name: &str,
data: &crate::db::EntryData,
notes: Option<&str>,
- uris: &[String],
folder_id: Option<&str>,
) -> Result<()> {
let config = crate::config::Config::load()?;
let client =
crate::api::Client::new(&config.base_url(), &config.identity_url());
- client.add(
- access_token,
- name,
- data,
- notes,
- uris,
- folder_id.as_deref(),
- )?;
+ client.add(access_token, name, data, notes, folder_id.as_deref())?;
Ok(())
}
@@ -153,10 +144,20 @@ pub fn edit(
name: &str,
data: &crate::db::EntryData,
notes: Option<&str>,
+ folder_uuid: Option<&str>,
history: &[crate::db::HistoryEntry],
) -> Result<(Option<String>, ())> {
with_exchange_refresh_token(access_token, refresh_token, |access_token| {
- edit_once(access_token, id, org_id, name, data, notes, history)
+ edit_once(
+ access_token,
+ id,
+ org_id,
+ name,
+ data,
+ notes,
+ folder_uuid,
+ history,
+ )
})
}
@@ -167,12 +168,22 @@ fn edit_once(
name: &str,
data: &crate::db::EntryData,
notes: Option<&str>,
+ folder_uuid: Option<&str>,
history: &[crate::db::HistoryEntry],
) -> Result<()> {
let config = crate::config::Config::load()?;
let client =
crate::api::Client::new(&config.base_url(), &config.identity_url());
- client.edit(access_token, id, org_id, name, data, notes, history)?;
+ client.edit(
+ access_token,
+ id,
+ org_id,
+ name,
+ data,
+ notes,
+ folder_uuid,
+ history,
+ )?;
Ok(())
}
diff --git a/src/api.rs b/src/api.rs
index 73b970f..b306f7c 100644
--- a/src/api.rs
+++ b/src/api.rs
@@ -119,21 +119,25 @@ impl SyncResCipher {
} else {
vec![]
};
- let folder = if let Some(folder_id) = &self.folder_id {
+ let (folder, folder_id) = 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
+ (folder_name, Some(folder_id))
} else {
- None
+ (None, None)
};
let data = if let Some(login) = &self.login {
crate::db::EntryData::Login {
username: login.username.clone(),
password: login.password.clone(),
+ uris: login.uris.as_ref().map_or_else(
+ || vec![],
+ |uris| uris.iter().map(|uri| uri.uri.clone()).collect(),
+ ),
}
} else if let Some(card) = &self.card {
crate::db::EntryData::Card {
@@ -173,6 +177,7 @@ impl SyncResCipher {
id: self.id.clone(),
org_id: self.organization_id.clone(),
folder,
+ folder_id: folder_id.map(std::string::ToString::to_string),
name: self.name.clone(),
data,
notes: self.notes.clone(),
@@ -213,11 +218,13 @@ struct CipherLogin {
username: Option<String>,
#[serde(rename = "Password")]
password: Option<String>,
+ #[serde(rename = "Uris")]
uris: Option<Vec<CipherLoginUri>>,
}
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
struct CipherLoginUri {
+ #[serde(rename = "Uri")]
uri: String,
}
@@ -307,6 +314,8 @@ struct CiphersPostReq {
struct CiphersPutReq {
#[serde(rename = "type")]
ty: u32, // XXX what are the valid types?
+ #[serde(rename = "folderId")]
+ folder_id: Option<String>,
#[serde(rename = "organizationId")]
organization_id: Option<String>,
name: String,
@@ -484,7 +493,6 @@ impl Client {
name: &str,
data: &crate::db::EntryData,
notes: Option<&str>,
- uris: &[String],
folder_id: Option<&str>,
) -> Result<()> {
let mut req = CiphersPostReq {
@@ -498,7 +506,11 @@ impl Client {
secure_note: None,
};
match data {
- crate::db::EntryData::Login { username, password } => {
+ crate::db::EntryData::Login {
+ username,
+ password,
+ uris,
+ } => {
let uris = if uris.is_empty() {
None
} else {
@@ -600,10 +612,12 @@ impl Client {
name: &str,
data: &crate::db::EntryData,
notes: Option<&str>,
+ folder_uuid: Option<&str>,
history: &[crate::db::HistoryEntry],
) -> Result<()> {
let mut req = CiphersPutReq {
ty: 1,
+ folder_id: folder_uuid.map(std::string::ToString::to_string),
organization_id: org_id.map(std::string::ToString::to_string),
name: name.to_string(),
notes: notes.map(std::string::ToString::to_string),
@@ -620,11 +634,24 @@ impl Client {
.collect(),
};
match data {
- crate::db::EntryData::Login { username, password } => {
+ crate::db::EntryData::Login {
+ username,
+ password,
+ uris,
+ } => {
+ let uris = if uris.is_empty() {
+ None
+ } else {
+ Some(
+ uris.iter()
+ .map(|s| CipherLoginUri { uri: s.to_string() })
+ .collect(),
+ )
+ };
req.login = Some(CipherLogin {
username: username.clone(),
password: password.clone(),
- uris: None,
+ uris,
});
}
crate::db::EntryData::Card {
diff --git a/src/bin/rbw/commands.rs b/src/bin/rbw/commands.rs
index fa4cc39..b9be09b 100644
--- a/src/bin/rbw/commands.rs
+++ b/src/bin/rbw/commands.rs
@@ -509,9 +509,12 @@ pub fn add(
&access_token,
&refresh_token,
&name,
- &rbw::db::EntryData::Login { username, password },
+ &rbw::db::EntryData::Login {
+ username,
+ password,
+ uris,
+ },
notes.as_deref(),
- &uris,
folder_id.as_deref(),
)? {
db.access_token = Some(access_token);
@@ -598,9 +601,9 @@ pub fn generate(
&rbw::db::EntryData::Login {
username,
password: Some(password),
+ uris,
},
None,
- &uris,
folder_id.as_deref(),
)? {
db.access_token = Some(access_token);
@@ -656,12 +659,15 @@ pub fn edit(name: &str, username: Option<&str>) -> anyhow::Result<()> {
})
.transpose()?;
let mut history = entry.history.clone();
- let (entry_username, entry_password) = match &entry.data {
- rbw::db::EntryData::Login { username, password } => {
- (username, password)
- }
- _ => unreachable!(),
- };
+ let (entry_username, entry_password, entry_uris) =
+ match &entry.data {
+ rbw::db::EntryData::Login {
+ username,
+ password,
+ uris,
+ } => (username, password, uris),
+ _ => unreachable!(),
+ };
let new_history_entry = rbw::db::HistoryEntry {
last_used_date: format!(
"{}",
@@ -673,6 +679,7 @@ pub fn edit(name: &str, username: Option<&str>) -> anyhow::Result<()> {
let data = rbw::db::EntryData::Login {
username: entry_username.clone(),
password,
+ uris: entry_uris.to_vec(),
};
(data, notes, history)
}
@@ -691,6 +698,7 @@ pub fn edit(name: &str, username: Option<&str>) -> anyhow::Result<()> {
&entry.name,
&data,
notes.as_deref(),
+ entry.folder_id.as_deref(),
&history,
)? {
db.access_token = Some(access_token);
@@ -970,20 +978,20 @@ fn decrypt_cipher(entry: &rbw::db::Entry) -> anyhow::Result<DecryptedCipher> {
.collect::<anyhow::Result<_>>()?;
let data = match &entry.data {
- rbw::db::EntryData::Login { username, password } => {
- DecryptedData::Login {
- username: decrypt_field(
- "username",
- username.as_deref(),
- entry.org_id.as_deref(),
- ),
- password: decrypt_field(
- "password",
- password.as_deref(),
- entry.org_id.as_deref(),
- ),
- }
- }
+ rbw::db::EntryData::Login {
+ username, password, ..
+ } => DecryptedData::Login {
+ username: decrypt_field(
+ "username",
+ username.as_deref(),
+ entry.org_id.as_deref(),
+ ),
+ password: decrypt_field(
+ "password",
+ password.as_deref(),
+ entry.org_id.as_deref(),
+ ),
+ },
rbw::db::EntryData::Card {
cardholder_name,
number,
@@ -1278,12 +1286,14 @@ mod test {
id: "irrelevant".to_string(),
org_id: None,
folder: None,
+ folder_id: None,
name: "this is the encrypted name".to_string(),
data: rbw::db::EntryData::Login {
username: username.map(|_| {
"this is the encrypted username".to_string()
}),
password: None,
+ uris: vec![],
},
notes: None,
history: vec![],
diff --git a/src/db.rs b/src/db.rs
index 8cb27ad..324e7a5 100644
--- a/src/db.rs
+++ b/src/db.rs
@@ -10,6 +10,7 @@ pub struct Entry {
pub id: String,
pub org_id: Option<String>,
pub folder: Option<String>,
+ pub folder_id: Option<String>,
pub name: String,
pub data: EntryData,
pub notes: Option<String>,
@@ -23,6 +24,7 @@ pub enum EntryData {
Login {
username: Option<String>,
password: Option<String>,
+ uris: Vec<String>,
},
Card {
cardholder_name: Option<String>,
diff --git a/src/protocol.rs b/src/protocol.rs
index 0ab594c..cf0c278 100644
--- a/src/protocol.rs
+++ b/src/protocol.rs
@@ -1,4 +1,4 @@
-pub const VERSION: u32 = 2;
+pub const VERSION: u32 = 3;
#[derive(serde::Serialize, serde::Deserialize, Debug)]
pub struct Request {