|
@ -343,36 +343,39 @@ impl Cipher { |
|
|
db_run! {conn: { |
|
|
db_run! {conn: { |
|
|
// Check whether this cipher is in any collections accessible to the
|
|
|
// Check whether this cipher is in any collections accessible to the
|
|
|
// user. If so, retrieve the access flags for each collection.
|
|
|
// user. If so, retrieve the access flags for each collection.
|
|
|
let query = ciphers::table |
|
|
let rows = ciphers::table |
|
|
.filter(ciphers::uuid.eq(&self.uuid)) |
|
|
.filter(ciphers::uuid.eq(&self.uuid)) |
|
|
.inner_join(ciphers_collections::table.on( |
|
|
.inner_join(ciphers_collections::table.on( |
|
|
ciphers::uuid.eq(ciphers_collections::cipher_uuid))) |
|
|
ciphers::uuid.eq(ciphers_collections::cipher_uuid))) |
|
|
.inner_join(users_collections::table.on( |
|
|
.inner_join(users_collections::table.on( |
|
|
ciphers_collections::collection_uuid.eq(users_collections::collection_uuid) |
|
|
ciphers_collections::collection_uuid.eq(users_collections::collection_uuid) |
|
|
.and(users_collections::user_uuid.eq(user_uuid)))) |
|
|
.and(users_collections::user_uuid.eq(user_uuid)))) |
|
|
.select((users_collections::read_only, users_collections::hide_passwords)); |
|
|
.select((users_collections::read_only, users_collections::hide_passwords)) |
|
|
|
|
|
.load::<(bool, bool)>(conn) |
|
|
// There's an edge case where a cipher can be in multiple collections
|
|
|
.expect("Error getting access restrictions"); |
|
|
// with inconsistent access flags. For example, a cipher could be in
|
|
|
|
|
|
// one collection where the user has read-only access, but also in
|
|
|
|
|
|
// another collection where the user has read/write access. To handle
|
|
|
|
|
|
// this, we do a boolean OR of all values in each of the `read_only`
|
|
|
|
|
|
// and `hide_passwords` columns. This could ideally be done as part
|
|
|
|
|
|
// of the query, but Diesel doesn't support a max() or bool_or()
|
|
|
|
|
|
// function on booleans and this behavior isn't portable anyway.
|
|
|
|
|
|
if let Ok(vec) = query.load::<(bool, bool)>(conn) { |
|
|
|
|
|
let mut read_only = false; |
|
|
|
|
|
let mut hide_passwords = false; |
|
|
|
|
|
for (ro, hp) in vec.iter() { |
|
|
|
|
|
read_only |= ro; |
|
|
|
|
|
hide_passwords |= hp; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Some((read_only, hide_passwords)) |
|
|
if rows.is_empty() { |
|
|
} else { |
|
|
|
|
|
// This cipher isn't in any collections accessible to the user.
|
|
|
// This cipher isn't in any collections accessible to the user.
|
|
|
None |
|
|
return None; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// A cipher can be in multiple collections with inconsistent access flags.
|
|
|
|
|
|
// For example, a cipher could be in one collection where the user has
|
|
|
|
|
|
// read-only access, but also in another collection where the user has
|
|
|
|
|
|
// read/write access. For a flag to be in effect for a cipher, upstream
|
|
|
|
|
|
// requires all collections the cipher is in to have that flag set.
|
|
|
|
|
|
// Therefore, we do a boolean AND of all values in each of the `read_only`
|
|
|
|
|
|
// and `hide_passwords` columns. This could ideally be done as part of the
|
|
|
|
|
|
// query, but Diesel doesn't support a min() or bool_and() function on
|
|
|
|
|
|
// booleans and this behavior isn't portable anyway.
|
|
|
|
|
|
let mut read_only = true; |
|
|
|
|
|
let mut hide_passwords = true; |
|
|
|
|
|
for (ro, hp) in rows.iter() { |
|
|
|
|
|
read_only &= ro; |
|
|
|
|
|
hide_passwords &= hp; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Some((read_only, hide_passwords)) |
|
|
}} |
|
|
}} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|