mirror of
https://github.com/dani-garcia/vaultwarden.git
synced 2025-09-09 18:25:58 +03:00
Compare commits
2 Commits
ce70cd2cf4
...
25865efd79
Author | SHA1 | Date | |
---|---|---|---|
|
25865efd79 | ||
|
bcf627930e |
8
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
8
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -20,17 +20,17 @@ body:
|
|||||||
See here [how to enable the admin page](https://github.com/dani-garcia/vaultwarden/wiki/Enabling-admin-page).
|
See here [how to enable the admin page](https://github.com/dani-garcia/vaultwarden/wiki/Enabling-admin-page).
|
||||||
|
|
||||||
> [!IMPORTANT]
|
> [!IMPORTANT]
|
||||||
> :bangbang: Search for existing **Open _AND_ Closed** [Issues](https://github.com/dani-garcia/vaultwarden/issues?q=is%3Aissue%20) **_AND_** [Discussions](https://github.com/dani-garcia/vaultwarden/discussions?discussions_q=) regarding your topic before posting!
|
> ## :bangbang: Search for existing **Closed _AND_ Open** [Issues](https://github.com/dani-garcia/vaultwarden/issues?q=is%3Aissue%20) **_AND_** [Discussions](https://github.com/dani-garcia/vaultwarden/discussions?discussions_q=) regarding your topic before posting! :bangbang:
|
||||||
#
|
#
|
||||||
- type: checkboxes
|
- type: checkboxes
|
||||||
id: checklist
|
id: checklist
|
||||||
attributes:
|
attributes:
|
||||||
label: Prerequisites
|
label: Prerequisites
|
||||||
description: Please confirm you have completed the following before submitting an issue
|
description: Please confirm you have completed the following before submitting an issue!
|
||||||
options:
|
options:
|
||||||
- label: I have searched the existing issues and discussions
|
- label: I have searched the existing **Closed _AND_ Open** [Issues](https://github.com/dani-garcia/vaultwarden/issues?q=is%3Aissue%20) **_AND_** [Discussions](https://github.com/dani-garcia/vaultwarden/discussions?discussions_q=)
|
||||||
required: true
|
required: true
|
||||||
- label: I have read the documentation
|
- label: I have searched and read the [documentation](https://github.com/dani-garcia/vaultwarden/wiki/)
|
||||||
required: true
|
required: true
|
||||||
#
|
#
|
||||||
- id: support-string
|
- id: support-string
|
||||||
|
@@ -1924,11 +1924,21 @@ impl CipherSyncData {
|
|||||||
|
|
||||||
// Generate a HashMap with the collections_uuid as key and the CollectionGroup record
|
// Generate a HashMap with the collections_uuid as key and the CollectionGroup record
|
||||||
let user_collections_groups: HashMap<CollectionId, CollectionGroup> = if CONFIG.org_groups_enabled() {
|
let user_collections_groups: HashMap<CollectionId, CollectionGroup> = if CONFIG.org_groups_enabled() {
|
||||||
CollectionGroup::find_by_user(user_id, conn)
|
CollectionGroup::find_by_user(user_id, conn).await.into_iter().fold(
|
||||||
.await
|
HashMap::new(),
|
||||||
.into_iter()
|
|mut combined_permissions, cg| {
|
||||||
.map(|collection_group| (collection_group.collections_uuid.clone(), collection_group))
|
combined_permissions
|
||||||
.collect()
|
.entry(cg.collections_uuid.clone())
|
||||||
|
.and_modify(|existing| {
|
||||||
|
// Combine permissions: take the most permissive settings.
|
||||||
|
existing.read_only &= cg.read_only; // false if ANY group allows write
|
||||||
|
existing.hide_passwords &= cg.hide_passwords; // false if ANY group allows password view
|
||||||
|
existing.manage |= cg.manage; // true if ANY group allows manage
|
||||||
|
})
|
||||||
|
.or_insert(cg);
|
||||||
|
combined_permissions
|
||||||
|
},
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
HashMap::new()
|
HashMap::new()
|
||||||
};
|
};
|
||||||
|
@@ -609,22 +609,23 @@ impl Cipher {
|
|||||||
let mut rows: Vec<(bool, bool, bool)> = Vec::new();
|
let mut rows: Vec<(bool, bool, bool)> = Vec::new();
|
||||||
if let Some(collections) = cipher_sync_data.cipher_collections.get(&self.uuid) {
|
if let Some(collections) = cipher_sync_data.cipher_collections.get(&self.uuid) {
|
||||||
for collection in collections {
|
for collection in collections {
|
||||||
//User permissions
|
// User permissions
|
||||||
if let Some(cu) = cipher_sync_data.user_collections.get(collection) {
|
if let Some(cu) = cipher_sync_data.user_collections.get(collection) {
|
||||||
rows.push((cu.read_only, cu.hide_passwords, cu.manage));
|
rows.push((cu.read_only, cu.hide_passwords, cu.manage));
|
||||||
}
|
// Group permissions
|
||||||
|
} else if let Some(cg) = cipher_sync_data.user_collections_groups.get(collection) {
|
||||||
//Group permissions
|
|
||||||
if let Some(cg) = cipher_sync_data.user_collections_groups.get(collection) {
|
|
||||||
rows.push((cg.read_only, cg.hide_passwords, cg.manage));
|
rows.push((cg.read_only, cg.hide_passwords, cg.manage));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rows
|
rows
|
||||||
} else {
|
} else {
|
||||||
let mut access_flags = self.get_user_collections_access_flags(user_uuid, conn).await;
|
let user_permissions = self.get_user_collections_access_flags(user_uuid, conn).await;
|
||||||
access_flags.append(&mut self.get_group_collections_access_flags(user_uuid, conn).await);
|
if !user_permissions.is_empty() {
|
||||||
access_flags
|
user_permissions
|
||||||
|
} else {
|
||||||
|
self.get_group_collections_access_flags(user_uuid, conn).await
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if rows.is_empty() {
|
if rows.is_empty() {
|
||||||
@@ -633,6 +634,9 @@ impl Cipher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// A cipher can be in multiple collections with inconsistent access flags.
|
// A cipher can be in multiple collections with inconsistent access flags.
|
||||||
|
// Also, user permission overrule group permissions
|
||||||
|
// and only user permissions are returned by the code above.
|
||||||
|
//
|
||||||
// For example, a cipher could be in one collection where the user has
|
// 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-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
|
// read/write access. For a flag to be in effect for a cipher, upstream
|
||||||
@@ -641,13 +645,15 @@ impl Cipher {
|
|||||||
// and `hide_passwords` columns. This could ideally be done as part of the
|
// 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
|
// query, but Diesel doesn't support a min() or bool_and() function on
|
||||||
// booleans and this behavior isn't portable anyway.
|
// booleans and this behavior isn't portable anyway.
|
||||||
|
//
|
||||||
|
// The only exception is for the `manage` flag, that needs a boolean OR!
|
||||||
let mut read_only = true;
|
let mut read_only = true;
|
||||||
let mut hide_passwords = true;
|
let mut hide_passwords = true;
|
||||||
let mut manage = false;
|
let mut manage = false;
|
||||||
for (ro, hp, mn) in rows.iter() {
|
for (ro, hp, mn) in rows.iter() {
|
||||||
read_only &= ro;
|
read_only &= ro;
|
||||||
hide_passwords &= hp;
|
hide_passwords &= hp;
|
||||||
manage &= mn;
|
manage |= mn;
|
||||||
}
|
}
|
||||||
|
|
||||||
Some((read_only, hide_passwords, manage))
|
Some((read_only, hide_passwords, manage))
|
||||||
|
@@ -97,13 +97,13 @@ impl Collection {
|
|||||||
(
|
(
|
||||||
cu.read_only,
|
cu.read_only,
|
||||||
cu.hide_passwords,
|
cu.hide_passwords,
|
||||||
cu.manage || (is_manager && !cu.read_only && !cu.hide_passwords),
|
is_manager && (cu.manage || (!cu.read_only && !cu.hide_passwords)),
|
||||||
)
|
)
|
||||||
} else if let Some(cg) = cipher_sync_data.user_collections_groups.get(&self.uuid) {
|
} else if let Some(cg) = cipher_sync_data.user_collections_groups.get(&self.uuid) {
|
||||||
(
|
(
|
||||||
cg.read_only,
|
cg.read_only,
|
||||||
cg.hide_passwords,
|
cg.hide_passwords,
|
||||||
cg.manage || (is_manager && !cg.read_only && !cg.hide_passwords),
|
is_manager && (cg.manage || (!cg.read_only && !cg.hide_passwords)),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
(false, false, false)
|
(false, false, false)
|
||||||
@@ -114,7 +114,9 @@ impl Collection {
|
|||||||
} else {
|
} else {
|
||||||
match Membership::find_confirmed_by_user_and_org(user_uuid, &self.org_uuid, conn).await {
|
match Membership::find_confirmed_by_user_and_org(user_uuid, &self.org_uuid, conn).await {
|
||||||
Some(m) if m.has_full_access() => (false, false, m.atype >= MembershipType::Manager),
|
Some(m) if m.has_full_access() => (false, false, m.atype >= MembershipType::Manager),
|
||||||
Some(_) if self.is_manageable_by_user(user_uuid, conn).await => (false, false, true),
|
Some(m) if m.atype == MembershipType::Manager && self.is_manageable_by_user(user_uuid, conn).await => {
|
||||||
|
(false, false, true)
|
||||||
|
}
|
||||||
Some(m) => {
|
Some(m) => {
|
||||||
let is_manager = m.atype == MembershipType::Manager;
|
let is_manager = m.atype == MembershipType::Manager;
|
||||||
let read_only = !self.is_writable_by_user(user_uuid, conn).await;
|
let read_only = !self.is_writable_by_user(user_uuid, conn).await;
|
||||||
|
Reference in New Issue
Block a user