From 74870c135e43d5c9543033bd2c6fb484ff80e925 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Sun, 3 May 2020 23:57:48 -0400 Subject: maintain folder and uris when editing an entry --- CHANGELOG.md | 6 ++++++ src/actions.rs | 37 ++++++++++++++++++++------------ src/api.rs | 41 +++++++++++++++++++++++++++++------- src/bin/rbw/commands.rs | 56 +++++++++++++++++++++++++++++-------------------- src/db.rs | 2 ++ src/protocol.rs | 2 +- 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, ())> { 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, ())> { 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, #[serde(rename = "Password")] password: Option, + #[serde(rename = "Uris")] uris: Option>, } #[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, #[serde(rename = "organizationId")] organization_id: Option, 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 { .collect::>()?; 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, pub folder: Option, + pub folder_id: Option, pub name: String, pub data: EntryData, pub notes: Option, @@ -23,6 +24,7 @@ pub enum EntryData { Login { username: Option, password: Option, + uris: Vec, }, Card { cardholder_name: Option, 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 { -- cgit v1.2.3-54-g00ecf