mirror of
https://github.com/dani-garcia/vaultwarden.git
synced 2025-11-29 08:02:34 +02:00
Compare commits
4 Commits
a2ad1dc7c3
...
3f010a50af
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3f010a50af | ||
|
|
e83faad8d2 | ||
|
|
a79cd40ea9 | ||
|
|
b1d84298cc |
@@ -1,6 +1,6 @@
|
||||
---
|
||||
vault_version: "v2025.8.0"
|
||||
vault_image_digest: "sha256:41c2b51c87882248f405d5a0ab37210d2672a312ec5d4f3b9afcdbbe8eb9d57d"
|
||||
vault_version: "v2025.9.1"
|
||||
vault_image_digest: "sha256:15a126ca967cd2efc4c9625fec49f0b972a3f7d7d81d7770bb0a2502d5e4b8a4"
|
||||
# Cross Compile Docker Helper Scripts v1.6.1
|
||||
# We use the linux/amd64 platform shell scripts since there is no difference between the different platform scripts
|
||||
# https://github.com/tonistiigi/xx | https://hub.docker.com/r/tonistiigi/xx/tags
|
||||
|
||||
@@ -19,15 +19,15 @@
|
||||
# - From https://hub.docker.com/r/vaultwarden/web-vault/tags,
|
||||
# click the tag name to view the digest of the image it currently points to.
|
||||
# - From the command line:
|
||||
# $ docker pull docker.io/vaultwarden/web-vault:v2025.8.0
|
||||
# $ docker image inspect --format "{{.RepoDigests}}" docker.io/vaultwarden/web-vault:v2025.8.0
|
||||
# [docker.io/vaultwarden/web-vault@sha256:41c2b51c87882248f405d5a0ab37210d2672a312ec5d4f3b9afcdbbe8eb9d57d]
|
||||
# $ docker pull docker.io/vaultwarden/web-vault:v2025.9.1
|
||||
# $ docker image inspect --format "{{.RepoDigests}}" docker.io/vaultwarden/web-vault:v2025.9.1
|
||||
# [docker.io/vaultwarden/web-vault@sha256:15a126ca967cd2efc4c9625fec49f0b972a3f7d7d81d7770bb0a2502d5e4b8a4]
|
||||
#
|
||||
# - Conversely, to get the tag name from the digest:
|
||||
# $ docker image inspect --format "{{.RepoTags}}" docker.io/vaultwarden/web-vault@sha256:41c2b51c87882248f405d5a0ab37210d2672a312ec5d4f3b9afcdbbe8eb9d57d
|
||||
# [docker.io/vaultwarden/web-vault:v2025.8.0]
|
||||
# $ docker image inspect --format "{{.RepoTags}}" docker.io/vaultwarden/web-vault@sha256:15a126ca967cd2efc4c9625fec49f0b972a3f7d7d81d7770bb0a2502d5e4b8a4
|
||||
# [docker.io/vaultwarden/web-vault:v2025.9.1]
|
||||
#
|
||||
FROM --platform=linux/amd64 docker.io/vaultwarden/web-vault@sha256:41c2b51c87882248f405d5a0ab37210d2672a312ec5d4f3b9afcdbbe8eb9d57d AS vault
|
||||
FROM --platform=linux/amd64 docker.io/vaultwarden/web-vault@sha256:15a126ca967cd2efc4c9625fec49f0b972a3f7d7d81d7770bb0a2502d5e4b8a4 AS vault
|
||||
|
||||
########################## ALPINE BUILD IMAGES ##########################
|
||||
## NOTE: The Alpine Base Images do not support other platforms then linux/amd64
|
||||
|
||||
@@ -19,15 +19,15 @@
|
||||
# - From https://hub.docker.com/r/vaultwarden/web-vault/tags,
|
||||
# click the tag name to view the digest of the image it currently points to.
|
||||
# - From the command line:
|
||||
# $ docker pull docker.io/vaultwarden/web-vault:v2025.8.0
|
||||
# $ docker image inspect --format "{{.RepoDigests}}" docker.io/vaultwarden/web-vault:v2025.8.0
|
||||
# [docker.io/vaultwarden/web-vault@sha256:41c2b51c87882248f405d5a0ab37210d2672a312ec5d4f3b9afcdbbe8eb9d57d]
|
||||
# $ docker pull docker.io/vaultwarden/web-vault:v2025.9.1
|
||||
# $ docker image inspect --format "{{.RepoDigests}}" docker.io/vaultwarden/web-vault:v2025.9.1
|
||||
# [docker.io/vaultwarden/web-vault@sha256:15a126ca967cd2efc4c9625fec49f0b972a3f7d7d81d7770bb0a2502d5e4b8a4]
|
||||
#
|
||||
# - Conversely, to get the tag name from the digest:
|
||||
# $ docker image inspect --format "{{.RepoTags}}" docker.io/vaultwarden/web-vault@sha256:41c2b51c87882248f405d5a0ab37210d2672a312ec5d4f3b9afcdbbe8eb9d57d
|
||||
# [docker.io/vaultwarden/web-vault:v2025.8.0]
|
||||
# $ docker image inspect --format "{{.RepoTags}}" docker.io/vaultwarden/web-vault@sha256:15a126ca967cd2efc4c9625fec49f0b972a3f7d7d81d7770bb0a2502d5e4b8a4
|
||||
# [docker.io/vaultwarden/web-vault:v2025.9.1]
|
||||
#
|
||||
FROM --platform=linux/amd64 docker.io/vaultwarden/web-vault@sha256:41c2b51c87882248f405d5a0ab37210d2672a312ec5d4f3b9afcdbbe8eb9d57d AS vault
|
||||
FROM --platform=linux/amd64 docker.io/vaultwarden/web-vault@sha256:15a126ca967cd2efc4c9625fec49f0b972a3f7d7d81d7770bb0a2502d5e4b8a4 AS vault
|
||||
|
||||
########################## Cross Compile Docker Helper Scripts ##########################
|
||||
## We use the linux/amd64 no matter which Build Platform, since these are all bash scripts
|
||||
|
||||
@@ -367,7 +367,7 @@ async fn post_set_password(data: Json<SetPasswordData>, headers: Headers, mut co
|
||||
|
||||
if let Some(identifier) = data.org_identifier {
|
||||
if identifier != crate::sso::FAKE_IDENTIFIER {
|
||||
let org = match Organization::find_by_name(&identifier, &mut conn).await {
|
||||
let org = match Organization::find_by_uuid(&identifier.into(), &mut conn).await {
|
||||
None => err!("Failed to retrieve the associated organization"),
|
||||
Some(org) => org,
|
||||
};
|
||||
|
||||
@@ -773,8 +773,8 @@ async fn post_collections_update(
|
||||
err!("Cipher doesn't exist")
|
||||
};
|
||||
|
||||
if !cipher.is_write_accessible_to_user(&headers.user.uuid, &mut conn).await {
|
||||
err!("Cipher is not write accessible")
|
||||
if !cipher.is_in_editable_collection_by_user(&headers.user.uuid, &mut conn).await {
|
||||
err!("Collection cannot be changed")
|
||||
}
|
||||
|
||||
let posted_collections = HashSet::<CollectionId>::from_iter(data.collection_ids);
|
||||
@@ -850,8 +850,8 @@ async fn post_collections_admin(
|
||||
err!("Cipher doesn't exist")
|
||||
};
|
||||
|
||||
if !cipher.is_write_accessible_to_user(&headers.user.uuid, &mut conn).await {
|
||||
err!("Cipher is not write accessible")
|
||||
if !cipher.is_in_editable_collection_by_user(&headers.user.uuid, &mut conn).await {
|
||||
err!("Collection cannot be changed")
|
||||
}
|
||||
|
||||
let posted_collections = HashSet::<CollectionId>::from_iter(data.collection_ids);
|
||||
|
||||
@@ -339,7 +339,7 @@ async fn get_user_collections(headers: Headers, mut conn: DbConn) -> Json<Value>
|
||||
}
|
||||
|
||||
// Called during the SSO enrollment
|
||||
// The `identifier` should be the value returned by `get_org_domain_sso_details`
|
||||
// The `identifier` should be the value returned by `get_org_domain_sso_verified`
|
||||
// The returned `Id` will then be passed to `get_master_password_policy` which will mainly ignore it
|
||||
#[get("/organizations/<identifier>/auto-enroll-status")]
|
||||
async fn get_auto_enroll_status(identifier: &str, headers: Headers, mut conn: DbConn) -> JsonResult {
|
||||
@@ -349,7 +349,7 @@ async fn get_auto_enroll_status(identifier: &str, headers: Headers, mut conn: Db
|
||||
None => None,
|
||||
}
|
||||
} else {
|
||||
Organization::find_by_name(identifier, &mut conn).await
|
||||
Organization::find_by_uuid(&identifier.into(), &mut conn).await
|
||||
};
|
||||
|
||||
let (id, identifier, rp_auto_enroll) = match org {
|
||||
@@ -977,17 +977,17 @@ async fn get_org_domain_sso_verified(data: Json<OrgDomainDetails>, mut conn: DbC
|
||||
let identifiers = match Organization::find_org_user_email(&data.email, &mut conn)
|
||||
.await
|
||||
.into_iter()
|
||||
.map(|o| o.name)
|
||||
.collect::<Vec<String>>()
|
||||
.map(|o| (o.name, o.uuid.to_string()))
|
||||
.collect::<Vec<(String, String)>>()
|
||||
{
|
||||
v if !v.is_empty() => v,
|
||||
_ => vec![crate::sso::FAKE_IDENTIFIER.to_string()],
|
||||
_ => vec![(crate::sso::FAKE_IDENTIFIER.to_string(), crate::sso::FAKE_IDENTIFIER.to_string())],
|
||||
};
|
||||
|
||||
Ok(Json(json!({
|
||||
"object": "list",
|
||||
"data": identifiers.into_iter().map(|identifier| json!({
|
||||
"organizationName": identifier, // appear unused
|
||||
"data": identifiers.into_iter().map(|(name, identifier)| json!({
|
||||
"organizationName": name, // appear unused
|
||||
"organizationIdentifier": identifier,
|
||||
"domainName": CONFIG.domain(), // appear unused
|
||||
})).collect::<Vec<Value>>()
|
||||
|
||||
@@ -717,6 +717,15 @@ impl Cipher {
|
||||
}
|
||||
}
|
||||
|
||||
// used for checking if collection can be edited (only if user has access to a collection they
|
||||
// can write to and also passwords are not hidden to prevent privilege escalation)
|
||||
pub async fn is_in_editable_collection_by_user(&self, user_uuid: &UserId, conn: &mut DbConn) -> bool {
|
||||
match self.get_access_restrictions(user_uuid, None, conn).await {
|
||||
Some((read_only, hide_passwords, manage)) => (!read_only && !hide_passwords) || manage,
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn is_accessible_to_user(&self, user_uuid: &UserId, conn: &mut DbConn) -> bool {
|
||||
self.get_access_restrictions(user_uuid, None, conn).await.is_some()
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ pub enum OrgPolicyType {
|
||||
// AutomaticAppLogIn = 12,
|
||||
// FreeFamiliesSponsorshipPolicy = 13,
|
||||
RemoveUnlockWithPin = 14,
|
||||
RestrictedItemTypes = 15,
|
||||
}
|
||||
|
||||
// https://github.com/bitwarden/server/blob/9ebe16587175b1c0e9208f84397bb75d0d595510/src/Core/AdminConsole/Models/Data/Organizations/Policies/SendOptionsPolicyData.cs#L5
|
||||
|
||||
@@ -283,24 +283,17 @@ impl User {
|
||||
self.updated_at = Utc::now().naive_utc();
|
||||
|
||||
db_run! {conn:
|
||||
sqlite, mysql {
|
||||
match diesel::replace_into(users::table)
|
||||
.values(UserDb::to_db(self))
|
||||
.execute(conn)
|
||||
{
|
||||
Ok(_) => Ok(()),
|
||||
// Record already exists and causes a Foreign Key Violation because replace_into() wants to delete the record first.
|
||||
Err(diesel::result::Error::DatabaseError(diesel::result::DatabaseErrorKind::ForeignKeyViolation, _)) => {
|
||||
diesel::update(users::table)
|
||||
.filter(users::uuid.eq(&self.uuid))
|
||||
.set(UserDb::to_db(self))
|
||||
mysql {
|
||||
let value = UserDb::to_db(self);
|
||||
diesel::insert_into(users::table)
|
||||
.values(&value)
|
||||
.on_conflict(diesel::dsl::DuplicatedKeys)
|
||||
.do_update()
|
||||
.set(&value)
|
||||
.execute(conn)
|
||||
.map_res("Error saving user")
|
||||
}
|
||||
Err(e) => Err(e.into()),
|
||||
}.map_res("Error saving user")
|
||||
}
|
||||
postgresql {
|
||||
postgresql, sqlite {
|
||||
let value = UserDb::to_db(self);
|
||||
diesel::insert_into(users::table) // Insert or update
|
||||
.values(&value)
|
||||
|
||||
@@ -19,7 +19,7 @@ use crate::{
|
||||
CONFIG,
|
||||
};
|
||||
|
||||
pub static FAKE_IDENTIFIER: &str = "Vaultwarden";
|
||||
pub static FAKE_IDENTIFIER: &str = "VW_DUMMY_IDENTIFIER_FOR_OIDC";
|
||||
|
||||
static AC_CACHE: Lazy<Cache<OIDCState, AuthenticatedUser>> =
|
||||
Lazy::new(|| Cache::builder().max_capacity(1000).time_to_live(Duration::from_secs(10 * 60)).build());
|
||||
|
||||
4
src/static/scripts/admin_users.js
vendored
4
src/static/scripts/admin_users.js
vendored
@@ -33,11 +33,11 @@ function deleteSSOUser(event) {
|
||||
alert("Required parameters not found!");
|
||||
return false;
|
||||
}
|
||||
const input_email = prompt(`To delete user "${email}", please type the email below`);
|
||||
const input_email = prompt(`To delete user "${email}" SSO association, please type the email below`);
|
||||
if (input_email != null) {
|
||||
if (input_email == email) {
|
||||
_delete(`${BASE_URL}/admin/users/${id}/sso`,
|
||||
"User SSO Associtation deleted correctly",
|
||||
"User SSO association deleted correctly",
|
||||
"Error deleting user SSO association"
|
||||
);
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user