Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,23 @@ flag will show the output as JSON. In addition to matching against the name,
you can pass a UUID as the name to search for the entry with that id, or a
URL to search for an entry with a matching website entry.

### Organizations and collections

Entries shared with you through an organization are part of your vault, and
`rbw list --fields name,org,collection` will show which organization and
collections each entry belongs to. When multiple entries share a name, you
can disambiguate with `--org <name>` or `--collection <name>` on `rbw get`
(as well as `code`, `edit`, `remove`, `history`, and `search`).

`rbw add` and `rbw generate` can create entries directly in an organization
with `--org <name> --collection <name>` (an organization entry must be
placed in at least one collection, and `--collection` may be given multiple
times). `rbw edit --set-collection <name>` replaces the set of collections
an existing organization entry belongs to without editing its contents,
which allows moving entries between collections of the same organization. Moving entries into or out of
an organization is not currently supported, and neither is creating or
managing the collections themselves.

*Note to users of the official Bitwarden server (at bitwarden.com)*: The
official server has a tendency to detect command line traffic as bot traffic
(see [this issue](https://github.com/bitwarden/cli/issues/383) for details). In
Expand Down
82 changes: 53 additions & 29 deletions src/actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,21 +112,17 @@ pub fn unlock<S: std::hash::BuildHasher>(

let protected_private_key =
crate::cipherstring::CipherString::new(protected_private_key)?;
let private_key =
match protected_private_key.decrypt_locked_symmetric(&key) {
Ok(private_key) => crate::locked::PrivateKey::new(private_key),
Err(e) => return Err(e),
};
let private_key = crate::locked::PrivateKey::new(
protected_private_key.decrypt_locked_symmetric(&key)?,
);

let mut org_keys = std::collections::HashMap::new();
for (org_id, protected_org_key) in protected_org_keys {
let protected_org_key =
crate::cipherstring::CipherString::new(protected_org_key)?;
let org_key =
match protected_org_key.decrypt_locked_asymmetric(&private_key) {
Ok(org_key) => crate::locked::Keys::new(org_key),
Err(e) => return Err(e),
};
let org_key = crate::locked::Keys::new(
protected_org_key.decrypt_locked_asymmetric(&private_key)?,
);
org_keys.insert(org_id.clone(), org_key);
}

Expand All @@ -136,15 +132,7 @@ pub fn unlock<S: std::hash::BuildHasher>(
pub async fn sync(
access_token: &str,
refresh_token: &str,
) -> Result<(
Option<String>,
(
String,
String,
std::collections::HashMap<String, String>,
Vec<crate::db::Entry>,
),
)> {
) -> Result<(Option<String>, crate::api::SyncData)> {
with_exchange_refresh_token_async(
access_token,
refresh_token,
Expand All @@ -156,40 +144,55 @@ pub async fn sync(
.await
}

async fn sync_once(
access_token: &str,
) -> Result<(
String,
String,
std::collections::HashMap<String, String>,
Vec<crate::db::Entry>,
)> {
async fn sync_once(access_token: &str) -> Result<crate::api::SyncData> {
let (client, _) = api_client_async().await?;
client.sync(access_token).await
}

#[allow(clippy::too_many_arguments)]
pub fn add(
access_token: &str,
refresh_token: &str,
name: &str,
data: &crate::db::EntryData,
notes: Option<&str>,
folder_id: Option<&str>,
org_id: Option<&str>,
collection_ids: &[String],
) -> Result<(Option<String>, ())> {
with_exchange_refresh_token(access_token, refresh_token, |access_token| {
add_once(access_token, name, data, notes, folder_id)
add_once(
access_token,
name,
data,
notes,
folder_id,
org_id,
collection_ids,
)
})
}

#[allow(clippy::too_many_arguments)]
fn add_once(
access_token: &str,
name: &str,
data: &crate::db::EntryData,
notes: Option<&str>,
folder_id: Option<&str>,
org_id: Option<&str>,
collection_ids: &[String],
) -> Result<()> {
let (client, _) = api_client()?;
client.add(access_token, name, data, notes, folder_id)?;
client.add(
access_token,
name,
data,
notes,
folder_id,
org_id,
collection_ids,
)?;
Ok(())
}

Expand Down Expand Up @@ -246,6 +249,27 @@ fn edit_once(
Ok(())
}

pub fn set_collections(
access_token: &str,
refresh_token: &str,
id: &str,
collection_ids: &[String],
) -> Result<(Option<String>, ())> {
with_exchange_refresh_token(access_token, refresh_token, |access_token| {
set_collections_once(access_token, id, collection_ids)
})
}

fn set_collections_once(
access_token: &str,
id: &str,
collection_ids: &[String],
) -> Result<()> {
let (client, _) = api_client()?;
client.set_collections(access_token, id, collection_ids)?;
Ok(())
}

pub fn remove(
access_token: &str,
refresh_token: &str,
Expand Down
Loading
Loading