mirror of
https://github.com/dani-garcia/vaultwarden.git
synced 2025-11-29 16:12: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_version: "v2025.9.1"
|
||||||
vault_image_digest: "sha256:41c2b51c87882248f405d5a0ab37210d2672a312ec5d4f3b9afcdbbe8eb9d57d"
|
vault_image_digest: "sha256:15a126ca967cd2efc4c9625fec49f0b972a3f7d7d81d7770bb0a2502d5e4b8a4"
|
||||||
# Cross Compile Docker Helper Scripts v1.6.1
|
# 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
|
# 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
|
# 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,
|
# - 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.
|
# click the tag name to view the digest of the image it currently points to.
|
||||||
# - From the command line:
|
# - From the command line:
|
||||||
# $ docker pull docker.io/vaultwarden/web-vault:v2025.8.0
|
# $ docker pull docker.io/vaultwarden/web-vault:v2025.9.1
|
||||||
# $ docker image inspect --format "{{.RepoDigests}}" docker.io/vaultwarden/web-vault:v2025.8.0
|
# $ docker image inspect --format "{{.RepoDigests}}" docker.io/vaultwarden/web-vault:v2025.9.1
|
||||||
# [docker.io/vaultwarden/web-vault@sha256:41c2b51c87882248f405d5a0ab37210d2672a312ec5d4f3b9afcdbbe8eb9d57d]
|
# [docker.io/vaultwarden/web-vault@sha256:15a126ca967cd2efc4c9625fec49f0b972a3f7d7d81d7770bb0a2502d5e4b8a4]
|
||||||
#
|
#
|
||||||
# - Conversely, to get the tag name from the digest:
|
# - Conversely, to get the tag name from the digest:
|
||||||
# $ docker image inspect --format "{{.RepoTags}}" docker.io/vaultwarden/web-vault@sha256:41c2b51c87882248f405d5a0ab37210d2672a312ec5d4f3b9afcdbbe8eb9d57d
|
# $ docker image inspect --format "{{.RepoTags}}" docker.io/vaultwarden/web-vault@sha256:15a126ca967cd2efc4c9625fec49f0b972a3f7d7d81d7770bb0a2502d5e4b8a4
|
||||||
# [docker.io/vaultwarden/web-vault:v2025.8.0]
|
# [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 ##########################
|
########################## ALPINE BUILD IMAGES ##########################
|
||||||
## NOTE: The Alpine Base Images do not support other platforms then linux/amd64
|
## 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,
|
# - 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.
|
# click the tag name to view the digest of the image it currently points to.
|
||||||
# - From the command line:
|
# - From the command line:
|
||||||
# $ docker pull docker.io/vaultwarden/web-vault:v2025.8.0
|
# $ docker pull docker.io/vaultwarden/web-vault:v2025.9.1
|
||||||
# $ docker image inspect --format "{{.RepoDigests}}" docker.io/vaultwarden/web-vault:v2025.8.0
|
# $ docker image inspect --format "{{.RepoDigests}}" docker.io/vaultwarden/web-vault:v2025.9.1
|
||||||
# [docker.io/vaultwarden/web-vault@sha256:41c2b51c87882248f405d5a0ab37210d2672a312ec5d4f3b9afcdbbe8eb9d57d]
|
# [docker.io/vaultwarden/web-vault@sha256:15a126ca967cd2efc4c9625fec49f0b972a3f7d7d81d7770bb0a2502d5e4b8a4]
|
||||||
#
|
#
|
||||||
# - Conversely, to get the tag name from the digest:
|
# - Conversely, to get the tag name from the digest:
|
||||||
# $ docker image inspect --format "{{.RepoTags}}" docker.io/vaultwarden/web-vault@sha256:41c2b51c87882248f405d5a0ab37210d2672a312ec5d4f3b9afcdbbe8eb9d57d
|
# $ docker image inspect --format "{{.RepoTags}}" docker.io/vaultwarden/web-vault@sha256:15a126ca967cd2efc4c9625fec49f0b972a3f7d7d81d7770bb0a2502d5e4b8a4
|
||||||
# [docker.io/vaultwarden/web-vault:v2025.8.0]
|
# [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 ##########################
|
########################## Cross Compile Docker Helper Scripts ##########################
|
||||||
## We use the linux/amd64 no matter which Build Platform, since these are all bash 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 let Some(identifier) = data.org_identifier {
|
||||||
if identifier != crate::sso::FAKE_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"),
|
None => err!("Failed to retrieve the associated organization"),
|
||||||
Some(org) => org,
|
Some(org) => org,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -773,8 +773,8 @@ async fn post_collections_update(
|
|||||||
err!("Cipher doesn't exist")
|
err!("Cipher doesn't exist")
|
||||||
};
|
};
|
||||||
|
|
||||||
if !cipher.is_write_accessible_to_user(&headers.user.uuid, &mut conn).await {
|
if !cipher.is_in_editable_collection_by_user(&headers.user.uuid, &mut conn).await {
|
||||||
err!("Cipher is not write accessible")
|
err!("Collection cannot be changed")
|
||||||
}
|
}
|
||||||
|
|
||||||
let posted_collections = HashSet::<CollectionId>::from_iter(data.collection_ids);
|
let posted_collections = HashSet::<CollectionId>::from_iter(data.collection_ids);
|
||||||
@@ -850,8 +850,8 @@ async fn post_collections_admin(
|
|||||||
err!("Cipher doesn't exist")
|
err!("Cipher doesn't exist")
|
||||||
};
|
};
|
||||||
|
|
||||||
if !cipher.is_write_accessible_to_user(&headers.user.uuid, &mut conn).await {
|
if !cipher.is_in_editable_collection_by_user(&headers.user.uuid, &mut conn).await {
|
||||||
err!("Cipher is not write accessible")
|
err!("Collection cannot be changed")
|
||||||
}
|
}
|
||||||
|
|
||||||
let posted_collections = HashSet::<CollectionId>::from_iter(data.collection_ids);
|
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
|
// 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
|
// The returned `Id` will then be passed to `get_master_password_policy` which will mainly ignore it
|
||||||
#[get("/organizations/<identifier>/auto-enroll-status")]
|
#[get("/organizations/<identifier>/auto-enroll-status")]
|
||||||
async fn get_auto_enroll_status(identifier: &str, headers: Headers, mut conn: DbConn) -> JsonResult {
|
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,
|
None => None,
|
||||||
}
|
}
|
||||||
} else {
|
} 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 {
|
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)
|
let identifiers = match Organization::find_org_user_email(&data.email, &mut conn)
|
||||||
.await
|
.await
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|o| o.name)
|
.map(|o| (o.name, o.uuid.to_string()))
|
||||||
.collect::<Vec<String>>()
|
.collect::<Vec<(String, String)>>()
|
||||||
{
|
{
|
||||||
v if !v.is_empty() => v,
|
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!({
|
Ok(Json(json!({
|
||||||
"object": "list",
|
"object": "list",
|
||||||
"data": identifiers.into_iter().map(|identifier| json!({
|
"data": identifiers.into_iter().map(|(name, identifier)| json!({
|
||||||
"organizationName": identifier, // appear unused
|
"organizationName": name, // appear unused
|
||||||
"organizationIdentifier": identifier,
|
"organizationIdentifier": identifier,
|
||||||
"domainName": CONFIG.domain(), // appear unused
|
"domainName": CONFIG.domain(), // appear unused
|
||||||
})).collect::<Vec<Value>>()
|
})).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 {
|
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()
|
self.get_access_restrictions(user_uuid, None, conn).await.is_some()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ pub enum OrgPolicyType {
|
|||||||
// AutomaticAppLogIn = 12,
|
// AutomaticAppLogIn = 12,
|
||||||
// FreeFamiliesSponsorshipPolicy = 13,
|
// FreeFamiliesSponsorshipPolicy = 13,
|
||||||
RemoveUnlockWithPin = 14,
|
RemoveUnlockWithPin = 14,
|
||||||
|
RestrictedItemTypes = 15,
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://github.com/bitwarden/server/blob/9ebe16587175b1c0e9208f84397bb75d0d595510/src/Core/AdminConsole/Models/Data/Organizations/Policies/SendOptionsPolicyData.cs#L5
|
// 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();
|
self.updated_at = Utc::now().naive_utc();
|
||||||
|
|
||||||
db_run! {conn:
|
db_run! {conn:
|
||||||
sqlite, mysql {
|
mysql {
|
||||||
match diesel::replace_into(users::table)
|
let value = UserDb::to_db(self);
|
||||||
.values(UserDb::to_db(self))
|
diesel::insert_into(users::table)
|
||||||
.execute(conn)
|
.values(&value)
|
||||||
{
|
.on_conflict(diesel::dsl::DuplicatedKeys)
|
||||||
Ok(_) => Ok(()),
|
.do_update()
|
||||||
// Record already exists and causes a Foreign Key Violation because replace_into() wants to delete the record first.
|
.set(&value)
|
||||||
Err(diesel::result::Error::DatabaseError(diesel::result::DatabaseErrorKind::ForeignKeyViolation, _)) => {
|
|
||||||
diesel::update(users::table)
|
|
||||||
.filter(users::uuid.eq(&self.uuid))
|
|
||||||
.set(UserDb::to_db(self))
|
|
||||||
.execute(conn)
|
.execute(conn)
|
||||||
.map_res("Error saving user")
|
.map_res("Error saving user")
|
||||||
}
|
}
|
||||||
Err(e) => Err(e.into()),
|
postgresql, sqlite {
|
||||||
}.map_res("Error saving user")
|
|
||||||
}
|
|
||||||
postgresql {
|
|
||||||
let value = UserDb::to_db(self);
|
let value = UserDb::to_db(self);
|
||||||
diesel::insert_into(users::table) // Insert or update
|
diesel::insert_into(users::table) // Insert or update
|
||||||
.values(&value)
|
.values(&value)
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ use crate::{
|
|||||||
CONFIG,
|
CONFIG,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub static FAKE_IDENTIFIER: &str = "Vaultwarden";
|
pub static FAKE_IDENTIFIER: &str = "VW_DUMMY_IDENTIFIER_FOR_OIDC";
|
||||||
|
|
||||||
static AC_CACHE: Lazy<Cache<OIDCState, AuthenticatedUser>> =
|
static AC_CACHE: Lazy<Cache<OIDCState, AuthenticatedUser>> =
|
||||||
Lazy::new(|| Cache::builder().max_capacity(1000).time_to_live(Duration::from_secs(10 * 60)).build());
|
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!");
|
alert("Required parameters not found!");
|
||||||
return false;
|
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 != null) {
|
||||||
if (input_email == email) {
|
if (input_email == email) {
|
||||||
_delete(`${BASE_URL}/admin/users/${id}/sso`,
|
_delete(`${BASE_URL}/admin/users/${id}/sso`,
|
||||||
"User SSO Associtation deleted correctly",
|
"User SSO association deleted correctly",
|
||||||
"Error deleting user SSO association"
|
"Error deleting user SSO association"
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user