From b25f715364946e626c7d5ca299609085ba8e1d47 Mon Sep 17 00:00:00 2001 From: Timshel Date: Tue, 7 Jul 2026 15:58:34 +0200 Subject: [PATCH 01/15] Fix enforce blocked (#7246) Co-authored-by: Timshel --- src/api/icons.rs | 2 +- src/http_client.rs | 44 +++++++++++++++++++++++++++++--------------- src/sso_client.rs | 11 ++++++++--- 3 files changed, 38 insertions(+), 19 deletions(-) diff --git a/src/api/icons.rs b/src/api/icons.rs index 02a14844..81191e38 100644 --- a/src/api/icons.rs +++ b/src/api/icons.rs @@ -65,7 +65,7 @@ static CLIENT: LazyLock = LazyLock::new(|| { let icon_download_timeout = Duration::from_secs(CONFIG.icon_download_timeout()); let pool_idle_timeout = Duration::from_secs(10); // Reuse the client between requests - get_reqwest_client_builder() + get_reqwest_client_builder(true) .cookie_provider(Arc::clone(&cookie_store)) .timeout(icon_download_timeout) .pool_max_idle_per_host(5) // Configure the Hyper Pool to only have max 5 idle connections diff --git a/src/http_client.rs b/src/http_client.rs index 232ba7da..205b1cc3 100644 --- a/src/http_client.rs +++ b/src/http_client.rs @@ -18,7 +18,7 @@ use crate::{CONFIG, util::is_global}; pub fn make_http_request(method: reqwest::Method, url: &str) -> Result { static INSTANCE: LazyLock = - LazyLock::new(|| get_reqwest_client_builder().build().expect("Failed to build client")); + LazyLock::new(|| get_reqwest_client_builder(true).build().expect("Failed to build client")); let Ok(url) = url::Url::parse(url) else { err!("Invalid URL"); @@ -32,7 +32,7 @@ pub fn make_http_request(method: reqwest::Method, url: &str) -> Result ClientBuilder { +pub fn get_reqwest_client_builder(enforce_block: bool) -> ClientBuilder { let mut headers = header::HeaderMap::new(); headers.insert(header::USER_AGENT, header::HeaderValue::from_static("Vaultwarden")); @@ -55,7 +55,7 @@ pub fn get_reqwest_client_builder() -> ClientBuilder { Client::builder() .default_headers(headers) .redirect(redirect_policy) - .dns_resolver(CustomDnsResolver::instance()) + .dns_resolver(CustomDns::instance(enforce_block)) .timeout(Duration::from_secs(10)) } @@ -210,6 +210,11 @@ impl fmt::Display for CustomHttpClientError { impl std::error::Error for CustomHttpClientError {} +pub struct CustomDns { + enforce_block: bool, + resolver: Arc, +} + #[derive(Debug, Clone)] enum CustomDnsResolver { Default(), @@ -217,12 +222,18 @@ enum CustomDnsResolver { } type BoxError = Box; -impl CustomDnsResolver { - fn instance() -> Arc { +impl CustomDns { + fn instance(enforce_block: bool) -> Self { static INSTANCE: LazyLock> = LazyLock::new(CustomDnsResolver::new); - Arc::clone(&*INSTANCE) + + CustomDns { + enforce_block, + resolver: Arc::clone(&*INSTANCE), + } } +} +impl CustomDnsResolver { fn new() -> Arc { TokioResolver::builder(TokioRuntimeProvider::default()) .and_then(|mut builder| { @@ -239,30 +250,32 @@ impl CustomDnsResolver { } // Note that we get an iterator of addresses, but we only grab the first one for convenience - async fn resolve_domain(&self, name: &str) -> Result, BoxError> { - pre_resolve(name)?; + async fn resolve_domain(&self, name: &str, enforce_block: bool) -> Result, BoxError> { + pre_resolve(name, enforce_block)?; let results: Vec = match self { Self::Default() => tokio::net::lookup_host((name, 0)).await?.collect(), Self::Hickory(r) => r.lookup_ip(name).await?.iter().map(|i| SocketAddr::new(i, 0)).collect(), }; - for addr in &results { - post_resolve(name, addr.ip())?; + if enforce_block { + for addr in &results { + post_resolve(name, addr.ip())?; + } } Ok(results) } } -fn pre_resolve(name: &str) -> Result<(), CustomHttpClientError> { +fn pre_resolve(name: &str, enforce_block: bool) -> Result<(), CustomHttpClientError> { let Ok(host) = get_valid_host(name) else { return Err(CustomHttpClientError::Invalid { domain: name.to_owned(), }); }; - if should_block_host(&host).is_err() { + if enforce_block && should_block_host(&host).is_err() { return Err(CustomHttpClientError::Blocked { domain: name.to_owned(), }); @@ -282,12 +295,13 @@ fn post_resolve(name: &str, ip: IpAddr) -> Result<(), CustomHttpClientError> { } } -impl Resolve for CustomDnsResolver { +impl Resolve for CustomDns { fn resolve(&self, name: Name) -> Resolving { - let this = self.clone(); + let enforce_block = self.enforce_block; + let this = Arc::clone(&self.resolver); Box::pin(async move { let name = name.as_str(); - let results = this.resolve_domain(name).await?; + let results = this.resolve_domain(name, enforce_block).await?; if results.is_empty() { warn!("Unable to resolve {name} to any valid IP address"); } diff --git a/src/sso_client.rs b/src/sso_client.rs index 355fffcb..4f25970e 100644 --- a/src/sso_client.rs +++ b/src/sso_client.rs @@ -71,7 +71,7 @@ pub struct OidcHttpClient { impl OidcHttpClient { fn new() -> Result { - get_reqwest_client_builder().redirect(reqwest::redirect::Policy::none()).build().map(|client| Self { + get_reqwest_client_builder(false).redirect(reqwest::redirect::Policy::none()).build().map(|client| Self { client, }) } @@ -83,7 +83,10 @@ impl<'c> AsyncHttpClient<'c> for OidcHttpClient { fn call(&'c self, request: HttpRequest) -> Self::Future { Box::pin(async move { - let response = self.client.execute(request.try_into().map_err(Box::new)?).await.map_err(Box::new)?; + let response = self.client.execute(request.try_into().map_err(Box::new)?).await.map_err(|e| { + debug!("Request failed {e:?}"); + Box::new(e) + })?; let mut builder = http::Response::builder().status(response.status()).version(response.version()); @@ -91,7 +94,9 @@ impl<'c> AsyncHttpClient<'c> for OidcHttpClient { builder = builder.header(name, value); } - builder.body(response.bytes().await.map_err(Box::new)?.to_vec()).map_err(HttpClientError::Http) + let body = response.bytes().await.map_err(Box::new)?; + debug!("Response body {}", String::from_utf8_lossy(&body)); + builder.body(body.to_vec()).map_err(HttpClientError::Http) }) } } From ec7fa137b7afd15ab13af6dcecc530661e62cd45 Mon Sep 17 00:00:00 2001 From: Timshel Date: Tue, 7 Jul 2026 15:58:41 +0200 Subject: [PATCH 02/15] Admin password recovery endpoint change (#7270) * Admin password recovery endpoint change * Use default to keep compatibility --------- Co-authored-by: Timshel --- playwright/tests/organization.smtp.spec.ts | 34 +++++++++++++++++ src/api/core/organizations.rs | 43 ++++++++++++++++++++-- 2 files changed, 73 insertions(+), 4 deletions(-) diff --git a/playwright/tests/organization.smtp.spec.ts b/playwright/tests/organization.smtp.spec.ts index 35dfcdb1..2be5fec1 100644 --- a/playwright/tests/organization.smtp.spec.ts +++ b/playwright/tests/organization.smtp.spec.ts @@ -40,6 +40,16 @@ test('Invite users', async ({ page }) => { await createAccount(test, page, users.user1, mail1Buffer); await orgs.create(test, page, 'Test'); + + await test.step(`Set account recovery`, async () => { + await orgs.policies(test, page, 'Test'); + await page.getByRole('button', { name: 'Account recovery' }).click(); + await page.getByRole('checkbox', { name: 'Turn on' }).check(); + await page.getByRole('checkbox', { name: 'Require new members' }).check(); + await page.getByRole('button', { name: 'Save' }).click(); + await utils.checkNotification(page, 'Edited policy Account recovery'); + }); + await orgs.members(test, page, 'Test'); await orgs.invite(test, page, 'Test', users.user2.email); await orgs.invite(test, page, 'Test', users.user3.email, { @@ -117,3 +127,27 @@ test('Organization is visible', async ({ page }) => { await page.getByRole('button', { name: 'vault: Test', exact: true }).click(); await expect(page.getByLabel('Filter: Default collection')).toBeVisible(); }); + +test('Recover user password', async ({ page }) => { + await logUser(test, page, users.user1, mail1Buffer); + + let newPassword = "TotoNewPassword"; + + await orgs.members(test, page, 'Test'); + await test.step(`Rrcover ${users.user2.email}`, async () => { + await expect(page.getByRole('heading', { name: 'Members' })).toBeVisible(); + await page.getByRole('row').filter({hasText: users.user2.email}).getByLabel('Options').click(); + await page.getByRole('menuitem', { name: 'Recover account' }).click(); + await page.getByRole('textbox', { name: 'New master password (required)', exact: true }).fill(newPassword); + await page.getByRole('textbox', { name: 'Confirm new master password (' }).fill(newPassword); + await page.getByRole('button', { name: 'Save' }).click(); + await utils.checkNotification(page, 'Password reset success'); + }); + + let user2 = { + email: users.user2.email, + name: users.user2.name, + password: newPassword, + }; + await logUser(test, page, user2, mail2Buffer); +}); diff --git a/src/api/core/organizations.rs b/src/api/core/organizations.rs index dd68cd5b..736e687d 100644 --- a/src/api/core/organizations.rs +++ b/src/api/core/organizations.rs @@ -96,6 +96,7 @@ pub fn routes() -> Vec { put_reset_password_enrollment, get_reset_password_details, put_reset_password, + put_recover_account, get_org_export, post_api_key, rotate_api_key, @@ -2875,9 +2876,14 @@ struct OrganizationUserResetPasswordEnrollmentRequest { #[derive(Deserialize)] #[serde(rename_all = "camelCase")] -struct OrganizationUserResetPasswordRequest { +struct OrganizationUserRecoverAccountRequest { new_master_password_hash: String, key: String, + + #[serde(default)] + reset_master_password: bool, + #[serde(default)] + reset_two_factor: bool, } // Upstream reports this is the renamed endpoint instead of `/keys` @@ -2905,12 +2911,43 @@ async fn get_organization_keys(org_id: OrganizationId, headers: OrgMemberHeaders get_organization_public_key(org_id, headers, conn).await } +// Will allow to reset 2FA too +// https://github.com/bitwarden/clients/blob/web-v2026.4.2/libs/admin-console/src/common/organization-user/models/requests/organization-user-reset-password.request.ts +#[put("/organizations//users//recover-account", data = "")] +async fn put_recover_account( + org_id: OrganizationId, + member_id: MembershipId, + headers: AdminHeaders, + data: Json, + conn: DbConn, + nt: Notify<'_>, +) -> EmptyResult { + let req = data.into_inner(); + if req.reset_master_password && !req.reset_two_factor { + recover_account(org_id, member_id, headers, req, conn, nt).await + } else { + err!("Unsupported operation") + } +} + +// Deprecated since `v2026.4.2` #[put("/organizations//users//reset-password", data = "")] async fn put_reset_password( org_id: OrganizationId, member_id: MembershipId, headers: AdminHeaders, - data: Json, + data: Json, + conn: DbConn, + nt: Notify<'_>, +) -> EmptyResult { + recover_account(org_id, member_id, headers, data.into_inner(), conn, nt).await +} + +async fn recover_account( + org_id: OrganizationId, + member_id: MembershipId, + headers: AdminHeaders, + reset_request: OrganizationUserRecoverAccountRequest, conn: DbConn, nt: Notify<'_>, ) -> EmptyResult { @@ -2944,8 +2981,6 @@ async fn put_reset_password( err!(format!("Error sending user reset password email: {e:#?}")); } - let reset_request = data.into_inner(); - let mut user = user; user.set_password(reset_request.new_master_password_hash.as_str(), Some(reset_request.key), true, None, &conn) .await?; From fddc16d2b87878e938f0dabaede9d728e827fd50 Mon Sep 17 00:00:00 2001 From: kvdb Date: Tue, 7 Jul 2026 15:58:54 +0200 Subject: [PATCH 03/15] fix(sends): emit hideEmail as non-null boolean in sync response (#7283) The /api/sync response serialized a Send hide_email field directly from Option, so a NULL value in the sends table (the column is Nullable with no default) produced "hideEmail": null. The Bitwarden Android client deserializes SyncResponseJson.Send.hideEmail as a non-null Kotlin Boolean and aborts the entire sync with a JsonDecodingException when it encounters null. Web, desktop and CLI clients coerce null to false, so only accounts with at least one Send are affected and only on Android. Default None to false at the serialization boundary, matching the official Bitwarden server where hideEmail is non-nullable. This needs no database migration and fixes both legacy NULL rows and any future NULLs. The hide_email field stays Option internally. --- src/db/models/send.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/db/models/send.rs b/src/db/models/send.rs index 0a2f1a2a..a35bcf8d 100644 --- a/src/db/models/send.rs +++ b/src/db/models/send.rs @@ -161,7 +161,7 @@ impl Send { "password": self.password_hash.as_deref().map(|h| BASE64URL_NOPAD.encode(h)), "authType": if self.password_hash.is_some() { SendAuthType::Password as i32 } else { SendAuthType::None as i32 }, "disabled": self.disabled, - "hideEmail": self.hide_email, + "hideEmail": self.hide_email.unwrap_or(false), "revisionDate": format_date(&self.revision_date), "expirationDate": self.expiration_date.as_ref().map(format_date), From a16b5afaaa5f9c546566a3d0cc0102f43b3edb95 Mon Sep 17 00:00:00 2001 From: Timshel Date: Tue, 7 Jul 2026 15:59:06 +0200 Subject: [PATCH 04/15] Org membership delete remove Invitation (#7284) Co-authored-by: Timshel --- src/api/core/organizations.rs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/api/core/organizations.rs b/src/api/core/organizations.rs index 736e687d..af2c45e3 100644 --- a/src/api/core/organizations.rs +++ b/src/api/core/organizations.rs @@ -1090,9 +1090,13 @@ async fn send_invite( err!(format!("User already in organization: {email}")) } - // automatically accept existing users if mail is disabled - if !CONFIG.mail_enabled() && !user.password_hash.is_empty() { - member_status = MembershipStatus::Accepted as i32; + if !CONFIG.mail_enabled() { + if user.password_hash.is_empty() { + Invitation::new(email).save(&conn).await?; + } else { + // automatically accept existing users if mail is disabled + member_status = MembershipStatus::Accepted as i32; + } } user } @@ -1714,6 +1718,15 @@ async fn delete_member_impl( if let Some(user) = User::find_by_uuid(&member_to_delete.user_uuid, conn).await { nt.send_user_update(UpdateType::SyncOrgKeys, &user, headers.device.push_uuid.as_ref(), conn).await; + + if !CONFIG.mail_enabled() + && !Membership::find_invited_by_user(&user.uuid, conn) + .await + .into_iter() + .any(|m| m.uuid != member_to_delete.uuid) + { + Invitation::take(&user.email, conn).await; + } } member_to_delete.delete(conn).await From a058a35ccddf48e77665bcf9b3f5fc2711f63f87 Mon Sep 17 00:00:00 2001 From: Timshel Date: Tue, 7 Jul 2026 15:59:17 +0200 Subject: [PATCH 05/15] [v2026.5.0] Registration request update (#7295) * Registration request update * Review fix --------- Co-authored-by: Timshel --- src/api/core/accounts.rs | 116 ++++++++++++++++++++++++++++++++++----- 1 file changed, 103 insertions(+), 13 deletions(-) diff --git a/src/api/core/accounts.rs b/src/api/core/accounts.rs index 954b35bd..623edf24 100644 --- a/src/api/core/accounts.rs +++ b/src/api/core/accounts.rs @@ -97,14 +97,11 @@ pub struct RegisterData { email: String, #[serde(flatten)] - kdf: KDFData, + compat: RegisterDataCompat, - #[serde(alias = "userSymmetricKey")] - key: String, #[serde(alias = "userAsymmetricKeys")] keys: Option, - master_password_hash: String, master_password_hint: Option, name: Option, @@ -119,17 +116,73 @@ pub struct RegisterData { org_invite_token: Option, } +impl RegisterData { + fn hash(&self) -> String { + self.compat.fold(|rdc| &rdc.master_password_hash, |rdcu| &rdcu.master_password_authentication.hash).to_owned() + } + + fn kdf(&self) -> &KDFData { + self.compat.fold(|rdc| &rdc.kdf, |rdcu| &rdcu.master_password_authentication.kdf) + } + + fn key(&self) -> String { + self.compat.fold(|rdc| &rdc.key, |rdcu| &rdcu.master_password_unlock.key).to_owned() + } + + // When comparing with salt, email need to be normalized: + // - https://github.com/bitwarden/clients/blob/web-v2026.5.0/libs/common/src/key-management/master-password/services/master-password.service.ts#L171 + fn unprocessable(&self) -> bool { + let mut unprocessable = false; + *self.compat.fold( + |_| &false, + |rdcu| { + let email = self.email.trim().to_lowercase(); + unprocessable = rdcu.master_password_authentication.kdf != rdcu.master_password_unlock.kdf + || rdcu.master_password_authentication.salt != email + || rdcu.master_password_unlock.salt != email; + &unprocessable + }, + ) + } +} + #[derive(Debug, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct SetPasswordData { +struct RegisterDataOld { #[serde(flatten)] kdf: KDFData, + #[serde(alias = "userSymmetricKey")] key: String, - keys: Option, + + #[serde(alias = "masterPasswordHash")] master_password_hash: String, - master_password_hint: Option, - org_identifier: Option, +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +struct RegisterDataCur { + master_password_authentication: MasterPasswordAuthentication, + master_password_unlock: MasterPasswordUnlock, +} + +#[derive(Debug, Deserialize)] +#[serde(untagged)] +enum RegisterDataCompat { + RegisterDataOld(RegisterDataOld), + RegisterDataCur(RegisterDataCur), +} + +impl RegisterDataCompat { + fn fold<'a, T>( + &'a self, + fct: impl FnOnce(&'a RegisterDataOld) -> &'a T, + fcu: impl FnOnce(&'a RegisterDataCur) -> &'a T, + ) -> &'a T { + match self { + RegisterDataCompat::RegisterDataOld(rdc) => fct(rdc), + RegisterDataCompat::RegisterDataCur(rdcu) => fcu(rdcu), + } + } } #[derive(Debug, Deserialize)] @@ -139,6 +192,39 @@ struct KeysData { public_key: String, } +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct MasterPasswordAuthentication { + kdf: KDFData, + salt: String, + + #[serde(alias = "masterPasswordAuthenticationHash")] + hash: String, +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct MasterPasswordUnlock { + kdf: KDFData, + salt: String, + + #[serde(alias = "masterKeyWrappedUserKey")] + key: String, +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SetPasswordData { + #[serde(flatten)] + kdf: KDFData, + + key: String, + keys: Option, + master_password_hash: String, + master_password_hint: Option, + org_identifier: Option, +} + /// Trims whitespace from password hints, and converts blank password hints to `None`. fn clean_password_hint(password_hint: Option<&String>) -> Option { match password_hint { @@ -177,6 +263,10 @@ pub async fn register(data: Json, email_verification: bool, conn: let mut pending_emergency_access = None; + if data.unprocessable() { + err_code!("Unexpected RegisterData format", Status::UnprocessableEntity.code); + } + // First, validate the provided verification tokens if email_verification { match ( @@ -257,8 +347,8 @@ pub async fn register(data: Json, email_verification: bool, conn: err!("Registration not allowed or user already exists") } - if let Some(token) = data.org_invite_token { - let claims = decode_invite(&token)?; + if let Some(token) = data.org_invite_token.as_ref() { + let claims = decode_invite(token)?; if claims.email == email { // Verify the email address when signing up via a valid invite token email_verified = true; @@ -296,9 +386,9 @@ pub async fn register(data: Json, email_verification: bool, conn: // Make sure we don't leave a lingering invitation. Invitation::take(&email, &conn).await; - set_kdf_data(&mut user, &data.kdf)?; + set_kdf_data(&mut user, data.kdf())?; - user.set_password(&data.master_password_hash, Some(data.key), true, None, &conn).await?; + user.set_password(&data.hash(), Some(data.key()), true, None, &conn).await?; user.password_hint = password_hint; // Add extra fields if present From 7320a1db4b1124d53c2fe316ced8cd3acb2c0a1c Mon Sep 17 00:00:00 2001 From: Timshel Date: Tue, 7 Jul 2026 15:59:26 +0200 Subject: [PATCH 06/15] PutPolicy now using vnext format (#7296) Co-authored-by: Timshel --- src/api/core/organizations.rs | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/api/core/organizations.rs b/src/api/core/organizations.rs index af2c45e3..68c9c1c5 100644 --- a/src/api/core/organizations.rs +++ b/src/api/core/organizations.rs @@ -2034,18 +2034,27 @@ struct PolicyData { data: Option, } +#[derive(Deserialize)] +struct PutPolicy { + policy: PolicyData, + // Ignore metadata for now as we do not yet support this + // "metadata": { + // "defaultUserCollectionName": "2.xx|xx==|xx=" + // } +} + #[put("/organizations//policies/", data = "")] async fn put_policy( org_id: OrganizationId, pol_type: i32, - data: Json, + data: Json, headers: AdminHeaders, conn: DbConn, ) -> JsonResult { if org_id != headers.org_id { err!("Organization not found", "Organization id's do not match"); } - let data: PolicyData = data.into_inner(); + let data: PolicyData = data.into_inner().policy; let Some(pol_type_enum) = OrgPolicyType::from_i32(pol_type) else { err!("Invalid or unsupported policy type") @@ -2153,26 +2162,16 @@ async fn put_policy( Ok(Json(policy.to_json())) } -#[derive(Deserialize)] -struct PolicyDataVnext { - policy: PolicyData, - // Ignore metadata for now as we do not yet support this - // "metadata": { - // "defaultUserCollectionName": "2.xx|xx==|xx=" - // } -} - +// Deprecated with client v2026.5.0 #[put("/organizations//policies//vnext", data = "")] async fn put_policy_vnext( org_id: OrganizationId, pol_type: i32, - data: Json, + data: Json, headers: AdminHeaders, conn: DbConn, ) -> JsonResult { - let data: PolicyDataVnext = data.into_inner(); - let policy: PolicyData = data.policy; - put_policy(org_id, pol_type, Json(policy), headers, conn).await + put_policy(org_id, pol_type, data, headers, conn).await } #[get("/plans")] From 5c5e8e1a6ff8ad1fb8d2b170a71f14f8e96d3d35 Mon Sep 17 00:00:00 2001 From: Timshel Date: Tue, 7 Jul 2026 15:59:36 +0200 Subject: [PATCH 07/15] 2026.6.0 send support (#7346) * 2026.6.0 send support * Prevent creating and editing a Send with email verification * Review fixes --------- Co-authored-by: Timshel --- playwright/tests/send.spec.ts | 72 ++++++++++++++++ src/api/core/sends.rs | 53 ++++++++++-- src/api/identity.rs | 21 ++++- src/auth.rs | 15 ++++ src/auth/send.rs | 156 ++++++++++++++++++++++++++++++++++ src/error.rs | 24 ++++-- 6 files changed, 329 insertions(+), 12 deletions(-) create mode 100644 playwright/tests/send.spec.ts create mode 100644 src/auth/send.rs diff --git a/playwright/tests/send.spec.ts b/playwright/tests/send.spec.ts new file mode 100644 index 00000000..d27c3ffc --- /dev/null +++ b/playwright/tests/send.spec.ts @@ -0,0 +1,72 @@ +import { test, expect, type Page, type TestInfo } from '@playwright/test'; +import * as OTPAuth from "otpauth"; + +import * as utils from "../global-utils"; +import { createAccount } from './setups/user'; + +let users = utils.loadEnv(); + +test.beforeAll('Setup', async ({ browser }, testInfo: TestInfo) => { + await utils.startVault(browser, testInfo, {}); +}); + +test.afterAll('Teardown', async ({}) => { + utils.stopVault(); +}); + +test('Send', async ({ browser, page }) => { + await createAccount(test, page, users.user1); + + const send_url = await test.step('Create', async () => { + await page.getByRole('link', { name: 'Send' }).click(); + await expect(page.locator('#main-content').getByText('Send', { exact: true })).toBeVisible(); + + await page.getByRole('button', { name: 'New', exact: true }).click(); + await page.getByRole('menuitem', { name: 'Text' }).click(); + + await page.getByRole('textbox', { name: 'Send name (required)' }).fill('Test'); + await page.getByRole('textbox', { name: 'Text to share (required)' }).fill('test'); + await page.getByRole('button', { name: 'Save' }).click(); + + await page.locator('footer').getByRole('button', { name: 'Copy link' }).click(); + + return await page.evaluate(() => navigator.clipboard.readText()); + }); + + const context2 = await browser.newContext(); + const page2 = await context2.newPage(); + + await test.step('View', async () => { + await page2.goto(send_url, { waitUntil: 'domcontentloaded' }); + await expect(page2.getByRole('heading', { name: 'View Send' })).toBeVisible(); + await expect(await page2.getByRole('paragraph').filter({ hasText: 'Test' })).toBeVisible(); + }); + + const pwd_url = await test.step('Create with password', async () => { + await page.getByRole('link', { name: 'Send' }).click(); + await expect(page.locator('#main-content').getByText('Send', { exact: true })).toBeVisible(); + + await page.getByRole('button', { name: 'New', exact: true }).click(); + await page.getByRole('menuitem', { name: 'Text' }).click(); + + await page.getByRole('textbox', { name: 'Send name (required)' }).fill('Password'); + await page.getByRole('textbox', { name: 'Text to share (required)' }).fill('password'); + await page.getByRole('combobox', { name: 'Who can view' }).click(); + await page.getByText('Anyone with a password set by you').click(); + await page.getByRole('textbox', { name: 'Password (required)' }).fill('password'); + + await page.getByRole('button', { name: 'Save' }).click(); + await page.locator('footer').getByRole('button', { name: 'Copy link' }).click(); + + return await page.evaluate(() => navigator.clipboard.readText()); + }); + + await test.step('View with password', async () => { + await page2.goto(pwd_url, { waitUntil: 'domcontentloaded' }); + await expect(page2.getByRole('heading', { name: 'Enter the password to view' })).toBeVisible(); + await page2.getByRole('textbox', { name: 'Password (required)' }).fill('password'); + await page2.getByRole('button', { name: 'Continue' }).click(); + await expect(page2.getByRole('heading', { name: 'View Send' })).toBeVisible(); + await expect(await page2.getByRole('paragraph').filter({ hasText: 'Password' })).toBeVisible(); + }); +}); diff --git a/src/api/core/sends.rs b/src/api/core/sends.rs index 2a7e06c1..fb3ee48f 100644 --- a/src/api/core/sends.rs +++ b/src/api/core/sends.rs @@ -12,7 +12,7 @@ use serde_json::Value; use crate::{ CONFIG, api::{ApiResult, EmptyResult, JsonResult, Notify, UpdateType}, - auth::{ClientIp, Headers, Host}, + auth::{ClientIp, Headers, Host, SendHeaders}, config::PathType, db::{ DbConn, DbPool, @@ -48,7 +48,9 @@ pub fn routes() -> Vec { post_send, post_send_file, post_access, + post_access_legacy, post_access_file, + post_access_file_legacy, put_send, delete_send, put_remove_password, @@ -78,6 +80,7 @@ pub struct SendData { deletion_date: DateTime, disabled: bool, hide_email: Option, + emails: Option, // Data field name: String, @@ -148,6 +151,10 @@ fn create_send(data: SendData, user_id: UserId) -> ApiResult { ); } + if data.emails.is_some() { + err!("Sends with email verification is not supported"); + } + let mut send = Send::new(data.r#type, data.name, data_str, data.key, data.deletion_date.naive_utc()); send.user_uuid = Some(user_id); send.notes = data.notes; @@ -371,7 +378,7 @@ pub struct SendFileData { } // https://github.com/bitwarden/server/blob/9ebe16587175b1c0e9208f84397bb75d0d595510/src/Api/Tools/Controllers/SendsController.cs#L195 -#[post("/sends//file/", format = "multipart/form-data", data = "")] +#[post("/sends//file/", format = "multipart/form-data", data = "", rank = 2)] async fn post_send_file_v2_data( send_id: SendId, file_id: SendFileId, @@ -441,14 +448,23 @@ async fn post_send_file_v2_data( Ok(()) } +#[post("/sends/access")] +async fn post_access(headers: SendHeaders, conn: DbConn, nt: Notify<'_>) -> JsonResult { + let Some(send) = Send::find_by_uuid(&headers.send_id, &conn).await else { + err_code!(SEND_INACCESSIBLE_MSG, 404) + }; + process_access(send, conn, nt).await +} + #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct SendAccessData { pub password: Option, } +// Legacy since web-2026.6.0 #[post("/sends/access/", data = "")] -async fn post_access( +async fn post_access_legacy( access_id: &str, data: Json, conn: DbConn, @@ -494,6 +510,10 @@ async fn post_access( send.save(&conn).await?; + process_access(send, conn, nt).await +} + +async fn process_access(send: Send, conn: DbConn, nt: Notify<'_>) -> JsonResult { nt.send_send_update( UpdateType::SyncSendUpdate, &send, @@ -506,8 +526,23 @@ async fn post_access( Ok(Json(send.to_json_access(&conn).await)) } -#[post("/sends//access/file/", data = "")] +#[post("/sends/access/file/", rank = 1)] async fn post_access_file( + file_id: SendFileId, + headers: SendHeaders, + host: Host, + conn: DbConn, + nt: Notify<'_>, +) -> JsonResult { + let Some(send) = Send::find_by_uuid(&headers.send_id, &conn).await else { + err_code!(SEND_INACCESSIBLE_MSG, 404) + }; + process_access_file(send, file_id, host, conn, nt).await +} + +// Legacy since web-2026.6.0 +#[post("/sends//access/file/", data = "")] +async fn post_access_file_legacy( send_id: SendId, file_id: SendFileId, data: Json, @@ -551,6 +586,10 @@ async fn post_access_file( send.save(&conn).await?; + process_access_file(send, file_id, host, conn, nt).await +} + +async fn process_access_file(send: Send, file_id: SendFileId, host: Host, conn: DbConn, nt: Notify<'_>) -> JsonResult { nt.send_send_update( UpdateType::SyncSendUpdate, &send, @@ -563,7 +602,7 @@ async fn post_access_file( Ok(Json(json!({ "object": "send-fileDownload", "id": file_id, - "url": download_url(&host, &send_id, &file_id).await?, + "url": download_url(&host, &send.uuid, &file_id).await?, }))) } @@ -601,6 +640,10 @@ async fn put_send(send_id: SendId, data: Json, headers: Headers, conn: err!("Send not found", "Send send_id is invalid or does not belong to user") }; + if data.emails.is_some() { + err!("Sends with email verification is not supported"); + } + update_send_from_data(&mut send, data, &headers, &conn, &nt, UpdateType::SyncSendUpdate).await?; Ok(Json(send.to_json())) diff --git a/src/api/identity.rs b/src/api/identity.rs index 3962827d..1597698f 100644 --- a/src/api/identity.rs +++ b/src/api/identity.rs @@ -31,8 +31,8 @@ use crate::{ DbConn, models::{ AuthRequest, AuthRequestId, Device, DeviceId, EventType, Invitation, OIDCCodeResponseError, - OrganizationApiKey, OrganizationId, SsoAuth, SsoUser, TwoFactor, TwoFactorIncomplete, TwoFactorType, User, - UserId, + OrganizationApiKey, OrganizationId, SendId, SsoAuth, SsoUser, TwoFactor, TwoFactorIncomplete, + TwoFactorType, User, UserId, }, }, error::MapResult, @@ -108,6 +108,19 @@ async fn login( sso_login(data, &mut user_id, &conn, &client_header.ip, client_version.as_ref()).await } "authorization_code" => err!("SSO sign-in is not available"), + "send_access" => { + check_is_some(data.client_id.as_ref(), "client_id cannot be blank")?; + check_is_some(data.send_id.as_ref(), "send_id cannot be blank")?; + + let tokens = auth::SendTokens::generate_tokens( + data.send_id.as_ref().unwrap(), + data.password_hash_b64, + &client_header.ip, + &conn, + ) + .await?; + Ok(Json(tokens.to_json())) + } t => err!("Invalid type", t), }; @@ -1144,6 +1157,10 @@ struct ConnectData { code: Option, #[field(name = uncased("code_verifier"))] code_verifier: Option, + + // Needed for send access + send_id: Option, + password_hash_b64: Option, } fn check_is_some(value: Option<&T>, msg: &str) -> EmptyResult { if value.is_none() { diff --git a/src/auth.rs b/src/auth.rs index 2ad95036..88a59b4b 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -1,3 +1,8 @@ +#[path = "auth/send.rs"] +pub mod send; +pub type SendTokens = send::SendTokens; +pub type SendHeaders = send::SendHeaders; + use std::{ env, net::IpAddr, @@ -487,6 +492,16 @@ pub struct BasicJwtClaims { pub sub: String, } +impl BasicJwtClaims { + pub fn expires_in(&self) -> i64 { + self.exp - Utc::now().timestamp() + } + + pub fn token(&self) -> String { + encode_jwt(&self) + } +} + pub fn generate_delete_claims(uuid: String) -> BasicJwtClaims { let time_now = Utc::now(); let expire_hours = i64::from(CONFIG.invitation_expiration_hours()); diff --git a/src/auth/send.rs b/src/auth/send.rs new file mode 100644 index 00000000..84500b6a --- /dev/null +++ b/src/auth/send.rs @@ -0,0 +1,156 @@ +use chrono::{TimeDelta, Utc}; + +use rocket::request::{FromRequest, Outcome, Request}; + +use crate::{ + api::ApiResult, + auth, + auth::{BasicJwtClaims, ClientIp}, + db::{ + DbConn, + models::{Send, SendId}, + }, + error::{Error, ErrorKind}, +}; + +fn generate_send_access_claims(send_id: &SendId) -> BasicJwtClaims { + let time_now = Utc::now(); + BasicJwtClaims { + nbf: time_now.timestamp(), + exp: (time_now + TimeDelta::try_minutes(2).unwrap()).timestamp(), + iss: auth::JWT_SEND_ISSUER.to_string(), + sub: format!("{send_id}"), + } +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct SendTokens { + pub access_claims: BasicJwtClaims, +} + +impl SendTokens { + pub fn as_send_id(access_id: &str) -> Option { + data_encoding::BASE64URL_NOPAD + .decode(access_id.as_bytes()) + .ok() + .and_then(|uuid_vec| uuid::Uuid::from_slice(&uuid_vec).ok().map(|u| SendId::from(u.to_string()))) + } + + pub fn to_json(&self) -> serde_json::Value { + json!({ + "access_token": self.access_claims.token(), + "expires_in": self.access_claims.expires_in(), + "token_type": "Bearer", + "scope": "api.send.access", + }) + } + + fn expected_error(msg: &str, error_type: &str) -> ApiResult { + let err = json!({ + "kind": "expected_server", + "error": "invalid_request", + "send_access_error_type": error_type, + }); + + Err(Error::new_msg(msg).with_kind(ErrorKind::Json(err)).silent()) + } + + fn invalid_error(msg: &str, error_type: &str, silent: bool) -> ApiResult { + let err = json!({ + "kind": "expected_server", + "error": "invalid_grant", + "send_access_error_type": error_type, + }); + + Err(Error::new_msg(msg).with_kind(ErrorKind::Json(err)).with_code(404).with_silent(silent)) + } + + pub async fn generate_tokens( + access_id: &str, + password: Option, + ip: &ClientIp, + conn: &DbConn, + ) -> ApiResult { + let Some(send_id) = Self::as_send_id(access_id) else { + return Self::invalid_error(&format!("Can't convert {access_id}"), "send_id_invalid", false); + }; + + let Some(mut send) = Send::find_by_uuid(&send_id, conn).await else { + return Self::invalid_error(&format!("Can't find {send_id}"), "send_id_invalid", false); + }; + + if let Some(max_access_count) = send.max_access_count + && send.access_count >= max_access_count + { + return Self::invalid_error(&format!("Send {send_id}, max access reached"), "send_id_invalid", true); + } + + if let Some(expiration) = send.expiration_date + && Utc::now().naive_utc() >= expiration + { + return Self::invalid_error(&format!("Send {send_id}, expired"), "send_id_invalid", true); + } + + if Utc::now().naive_utc() >= send.deletion_date { + return Self::invalid_error(&format!("Send {send_id}, past deletion"), "send_id_invalid", true); + } + + if send.disabled { + return Self::invalid_error(&format!("Send {send_id}, disabled"), "send_id_invalid", true); + } + + if send.password_hash.is_some() { + match password { + Some(ref p) if send.check_password(p) => { /* Nothing to do here */ } + Some(_) => { + return Self::invalid_error( + &format!("Send {send_id}, Invalid password from {}", ip.ip), + "password_hash_b64_invalid", + false, + ); + } + None => return Self::expected_error("Password required", "password_hash_b64_required"), + } + } + + send.access_count += 1; + send.save(conn).await?; + + Ok(Self { + access_claims: generate_send_access_claims(&send_id), + }) + } +} + +pub struct SendHeaders { + pub send_id: SendId, +} + +#[rocket::async_trait] +impl<'r> FromRequest<'r> for SendHeaders { + type Error = &'static str; + + async fn from_request(request: &'r Request<'_>) -> Outcome { + let headers = request.headers(); + + // Get access_token + let access_token: &str = if let Some(a) = headers.get_one("Authorization") { + if let Some(split) = a.rsplit("Bearer ").next() { + split + } else { + err_handler!("No access token provided") + } + } else { + err_handler!("No access token provided") + }; + + // Check JWT token is valid and get send_id + let Ok(claims) = auth::decode_send(access_token) else { + err_handler!("Invalid claim") + }; + + Outcome::Success(SendHeaders { + send_id: claims.sub.into(), + }) + } +} diff --git a/src/error.rs b/src/error.rs index d075dfe5..ecbc8199 100644 --- a/src/error.rs +++ b/src/error.rs @@ -15,14 +15,14 @@ macro_rules! make_error { #[derive(Debug)] pub struct ErrorEvent { pub event: EventType } - pub struct Error { message: String, kind: ErrorKind, code: u16, event: Option } + pub struct Error { message: String, kind: ErrorKind, code: u16, event: Option, silent: bool } $(impl From<$ty> for Error { fn from(err: $ty) -> Self { Error::from((stringify!($name), err)) } })+ $(impl> From<(S, $ty)> for Error { fn from(val: (S, $ty)) -> Self { - Error { message: val.0.into(), kind: ErrorKind::$name(val.1), code: BAD_REQUEST, event: None } + Error { message: val.0.into(), kind: ErrorKind::$name(val.1), code: BAD_REQUEST, event: None, silent: false } } })+ impl StdError for Error { @@ -172,6 +172,18 @@ impl Error { pub fn message(&self) -> &str { &self.message } + + #[must_use] + pub fn silent(mut self) -> Self { + self.silent = true; + self + } + + #[must_use] + pub fn with_silent(mut self, silent: bool) -> Self { + self.silent = silent; + self + } } pub trait MapResult { @@ -309,9 +321,11 @@ use rocket::{ impl Responder<'_, 'static> for Error { fn respond_to(self, _: &Request<'_>) -> response::Result<'static> { - match self.kind { - ErrorKind::Empty(_) | ErrorKind::Simple(_) | ErrorKind::Compact(_) => {} // Don't print the error in this situation - _ => error!(target: "error", "{self:#?}"), + if !self.silent { + match self.kind { + ErrorKind::Empty(_) | ErrorKind::Simple(_) | ErrorKind::Compact(_) => {} // Don't print the error in this situation + _ => error!(target: "error", "{self:#?}"), + } } let code = Status::from_code(self.code).unwrap_or(Status::BadRequest); From 5447ee6af27b9780e14a7c6ebe7a330820df8f48 Mon Sep 17 00:00:00 2001 From: Timshel Date: Tue, 7 Jul 2026 15:59:48 +0200 Subject: [PATCH 08/15] SSO use ClientSecretPost if ClientSecretBasic is not available (#7357) Co-authored-by: Timshel --- src/sso_client.rs | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/src/sso_client.rs b/src/sso_client.rs index 4f25970e..ff39b0b0 100644 --- a/src/sso_client.rs +++ b/src/sso_client.rs @@ -1,16 +1,16 @@ -use std::{borrow::Cow, future::Future, pin::Pin, sync::LazyLock, time::Duration}; +use std::{borrow::Cow, collections::HashSet, future::Future, pin::Pin, sync::LazyLock, time::Duration}; use openidconnect::{ - AccessToken, AsyncHttpClient, AuthDisplay, AuthPrompt, AuthenticationFlow, AuthorizationCode, AuthorizationRequest, - ClientId, ClientSecret, CsrfToken, EmptyAdditionalClaims, EmptyExtraTokenFields, EndpointNotSet, EndpointSet, - HttpClientError, HttpRequest, HttpResponse, IdTokenClaims, IdTokenFields, Nonce, OAuth2TokenResponse, - PkceCodeChallenge, PkceCodeVerifier, RefreshToken, ResponseType, Scope, StandardErrorResponse, + AccessToken, AsyncHttpClient, AuthDisplay, AuthPrompt, AuthType, AuthenticationFlow, AuthorizationCode, + AuthorizationRequest, ClientId, ClientSecret, CsrfToken, EmptyAdditionalClaims, EmptyExtraTokenFields, + EndpointNotSet, EndpointSet, HttpClientError, HttpRequest, HttpResponse, IdTokenClaims, IdTokenFields, Nonce, + OAuth2TokenResponse, PkceCodeChallenge, PkceCodeVerifier, RefreshToken, ResponseType, Scope, StandardErrorResponse, StandardTokenResponse, core::{ - CoreAuthDisplay, CoreAuthPrompt, CoreClient, CoreErrorResponseType, CoreGenderClaim, CoreIdTokenVerifier, - CoreJsonWebKey, CoreJweContentEncryptionAlgorithm, CoreJwsSigningAlgorithm, CoreProviderMetadata, - CoreResponseType, CoreRevocableToken, CoreRevocationErrorResponse, CoreTokenIntrospectionResponse, - CoreTokenResponse, CoreTokenType, CoreUserInfoClaims, + CoreAuthDisplay, CoreAuthPrompt, CoreClient, CoreClientAuthMethod, CoreErrorResponseType, CoreGenderClaim, + CoreIdTokenVerifier, CoreJsonWebKey, CoreJweContentEncryptionAlgorithm, CoreJwsSigningAlgorithm, + CoreProviderMetadata, CoreResponseType, CoreRevocableToken, CoreRevocationErrorResponse, + CoreTokenIntrospectionResponse, CoreTokenResponse, CoreTokenType, CoreUserInfoClaims, }, http, url, }; @@ -119,7 +119,21 @@ impl Client { Ok(metadata) => metadata, }; - let base_client = CoreClient::from_provider_metadata(provider_metadata, client_id, Some(client_secret)); + let auth_methods: Option> = provider_metadata + .token_endpoint_auth_methods_supported() + .map(|v| v.iter().map(ToOwned::to_owned).collect()); + + let mut base_client = CoreClient::from_provider_metadata(provider_metadata, client_id, Some(client_secret)); + + if let Some(am) = auth_methods { + if am.contains(&CoreClientAuthMethod::ClientSecretBasic) { + base_client = base_client.set_auth_type(AuthType::BasicAuth); // Default + } else if am.contains(&CoreClientAuthMethod::ClientSecretPost) { + base_client = base_client.set_auth_type(AuthType::RequestBody); + } else { + err!(format!("No supported auth_methods (only basic or request body), advertised: {am:?}")); + } + } let token_uri = if let Some(uri) = base_client.token_uri() { uri.clone() From 4720cdbe8660a40b40754046fe3763eb34c735f5 Mon Sep 17 00:00:00 2001 From: pilotstew Date: Tue, 7 Jul 2026 08:59:57 -0500 Subject: [PATCH 09/15] Add `pm-26340-linux-biometrics-v2` feature flag (#7358) Co-authored-by: Claude Opus 4.8 --- .env.template | 1 + src/config.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/.env.template b/.env.template index a12559ad..0d922774 100644 --- a/.env.template +++ b/.env.template @@ -378,6 +378,7 @@ ## - "ssh-agent-v2": Enable newer SSH agent support. (Desktop >= 2026.2.1) ## - "ssh-key-vault-item": Enable the creation and use of SSH key vault items. (Clients >= 2024.12.0) ## - "pm-25373-windows-biometrics-v2": Enable the new implementation of biometrics on Windows. (Desktop >= 2025.11.0) +## - "pm-26340-linux-biometrics-v2": Enable the new implementation of biometrics on Linux. (Desktop >= 2025.11.0) ## - "anon-addy-self-host-alias": Enable configuring self-hosted Anon Addy alias generator. (Android >= 2025.3.0, iOS >= 2025.4.0) ## - "simple-login-self-host-alias": Enable configuring self-hosted Simple Login alias generator. (Android >= 2025.3.0, iOS >= 2025.4.0) ## - "mutual-tls": Enable the use of mutual TLS on Android (Clients >= 2025.2.0) diff --git a/src/config.rs b/src/config.rs index 3656d0d9..49281b6c 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1404,6 +1404,7 @@ pub const SUPPORTED_FEATURE_FLAGS: &[&str] = &[ // Key Management Team "ssh-key-vault-item", "pm-25373-windows-biometrics-v2", + "pm-26340-linux-biometrics-v2", // Mobile Team "anon-addy-self-host-alias", "simple-login-self-host-alias", From 64d28ab66e10cee86ef62d1c4874c1919daa7e69 Mon Sep 17 00:00:00 2001 From: Denis Pisarev Date: Wed, 8 Jul 2026 22:08:20 +0200 Subject: [PATCH 10/15] improve CI (#6991) * ci: remove dead BASE_TAGS reference in release bake step steps.determine-version doesn't exist in docker-build; the expression resolves to empty string. The HCL default (testing) would have applied, but it's moot - the bake uses push-by-digest=true so tags are only set in merge-manifests. Dead code. * ci: replace unsecured curl hadolint download with an official action hadolint/hadolint-action uses a Docker-based runner with hadolint pre-bundled in ghcr.io/hadolint/hadolint:v2.14.0-debian,so no binary downloaded at runtime. Pinning the action to a commit SHA covers the Dockerfile that specifies the image version, closing the supply-chain gap from the previous unverified curl | sudo install. Split {debian,alpine}: the action takes a single dockerfile argument, so debian and alpine are linted separately. * ci: pin ubuntu-latest to ubuntu-24.04 in merge-manifests and zizmor ubuntu-latest is a moving target that can silently change the runner OS on the next GitHub-side update. All other jobs in this repo already pin to ubuntu-24.04; this makes merge-manifests and zizmor consistent. * ci: return BASE_TAGS - it's needed for bake step --- .github/workflows/hadolint.yml | 21 +++++++++++---------- .github/workflows/release.yml | 2 +- .github/workflows/zizmor.yml | 2 +- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/.github/workflows/hadolint.yml b/.github/workflows/hadolint.yml index 074bf2fc..917ba54a 100644 --- a/.github/workflows/hadolint.yml +++ b/.github/workflows/hadolint.yml @@ -30,14 +30,6 @@ jobs: driver-opts: | network=host - # Download hadolint - https://github.com/hadolint/hadolint/releases - - name: Download hadolint - run: | - sudo curl -L https://github.com/hadolint/hadolint/releases/download/v${HADOLINT_VERSION}/hadolint-$(uname -s)-$(uname -m) -o /usr/local/bin/hadolint && \ - sudo chmod +x /usr/local/bin/hadolint - env: - HADOLINT_VERSION: 2.14.0 - # End Download hadolint # Checkout the repo - name: Checkout uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 @@ -46,8 +38,17 @@ jobs: # End Checkout the repo # Test Dockerfiles with hadolint - - name: Run hadolint - run: hadolint docker/Dockerfile.{debian,alpine} + # Uses the Docker-based action (hadolint pre-bundled in ghcr.io/hadolint/hadolint:v2.14.0-debian) + # so no binary is downloaded at runtime. Pinned by commit SHA for supply-chain safety. + - name: Run hadolint on Dockerfile.debian + uses: hadolint/hadolint-action@2332a7b74a6de0dda2e2221d575162eba76ba5e5 # v3.3.0 + with: + dockerfile: docker/Dockerfile.debian + + - name: Run hadolint on Dockerfile.alpine + uses: hadolint/hadolint-action@2332a7b74a6de0dda2e2221d575162eba76ba5e5 # v3.3.0 + with: + dockerfile: docker/Dockerfile.alpine # End Test Dockerfiles with hadolint # Test Dockerfiles with docker build checks diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3c6d8574..d4ef21b9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -249,7 +249,7 @@ jobs: merge-manifests: name: Merge manifests - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 needs: docker-build environment: name: release diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml index 1036b1ce..36163e39 100644 --- a/.github/workflows/zizmor.yml +++ b/.github/workflows/zizmor.yml @@ -14,7 +14,7 @@ on: jobs: zizmor: name: Run zizmor - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 permissions: security-events: write # To write the security report steps: From 169aa5efcc8d94684ff3bc813a00e6bcc0cc537a Mon Sep 17 00:00:00 2001 From: Mathijs van Veluw Date: Wed, 8 Jul 2026 22:10:29 +0200 Subject: [PATCH 11/15] Misc updates and fixes (#7406) * Misc updates and fixes - Updated Rust to v1.96.1 - Updated all the crates - Updated GitHub Actions - Updated the web-vault to v2026.6.2 - Updated Alpine to v3.24 - Fixed several clippy lints - The `send` UUID wrappers didn't need the special namespace anymore since an updated crate, so removed this extra mod. Signed-off-by: BlackDex * Update MSRV to v1.94.1 Signed-off-by: BlackDex --------- Signed-off-by: BlackDex --- .github/workflows/build.yml | 2 +- .github/workflows/check-templates.yml | 2 +- .github/workflows/hadolint.yml | 4 +- .github/workflows/release.yml | 28 +- .github/workflows/trivy.yml | 4 +- .github/workflows/typos.yml | 4 +- .github/workflows/zizmor.yml | 4 +- .pre-commit-config.yaml | 2 +- Cargo.lock | 618 ++++++++++---------------- Cargo.toml | 32 +- docker/DockerSettings.yaml | 8 +- docker/Dockerfile.alpine | 22 +- docker/Dockerfile.debian | 14 +- macros/Cargo.toml | 4 +- rust-toolchain.toml | 2 +- src/api/core/ciphers.rs | 6 +- src/api/core/events.rs | 6 +- src/api/core/organizations.rs | 6 +- src/db/models/cipher.rs | 2 +- src/db/models/mod.rs | 5 +- src/db/models/organization.rs | 4 +- src/db/models/send.rs | 75 ++-- 22 files changed, 355 insertions(+), 499 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 79bbddfa..c9e8442e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -62,7 +62,7 @@ jobs: # Checkout the repo - name: "Checkout" - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false fetch-depth: 0 diff --git a/.github/workflows/check-templates.yml b/.github/workflows/check-templates.yml index 6be812c4..d9e139db 100644 --- a/.github/workflows/check-templates.yml +++ b/.github/workflows/check-templates.yml @@ -20,7 +20,7 @@ jobs: steps: # Checkout the repo - name: "Checkout" - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false # End Checkout the repo diff --git a/.github/workflows/hadolint.yml b/.github/workflows/hadolint.yml index 917ba54a..60fafe9e 100644 --- a/.github/workflows/hadolint.yml +++ b/.github/workflows/hadolint.yml @@ -20,7 +20,7 @@ jobs: steps: # Start Docker Buildx - name: Setup Docker Buildx - uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 + uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0 # https://github.com/moby/buildkit/issues/3969 # Also set max parallelism to 2, the default of 4 breaks GitHub Actions and causes OOMKills with: @@ -32,7 +32,7 @@ jobs: # Checkout the repo - name: Checkout - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false # End Checkout the repo diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d4ef21b9..cbd32451 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -58,13 +58,13 @@ jobs: steps: - name: Initialize QEMU binfmt support - uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 # v4.1.0 + uses: docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4.2.0 with: platforms: "arm64,arm" # Start Docker Buildx - name: Setup Docker Buildx - uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0 + uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0 # https://github.com/moby/buildkit/issues/3969 # Also set max parallelism to 2, the default of 4 breaks GitHub Actions and causes OOMKills with: @@ -77,7 +77,7 @@ jobs: # Checkout the repo - name: Checkout - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # We need fetch-depth of 0 so we also get all the tag metadata with: persist-credentials: false @@ -106,7 +106,7 @@ jobs: # Login to Docker Hub - name: Login to Docker Hub - uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 + uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} @@ -121,7 +121,7 @@ jobs: # Login to GitHub Container Registry - name: Login to GitHub Container Registry - uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 + uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0 with: registry: ghcr.io username: ${{ github.repository_owner }} @@ -137,7 +137,7 @@ jobs: # Login to Quay.io - name: Login to Quay.io - uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 + uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0 with: registry: quay.io username: ${{ secrets.QUAY_USERNAME }} @@ -185,7 +185,7 @@ jobs: - name: Bake ${{ matrix.base_image }} containers id: bake_vw - uses: docker/bake-action@6614cfa25eff9a0b2b2697efb0b6159e7680d584 # v7.2.0 + uses: docker/bake-action@d3418bd7d0e9324001bca92fa8ba175ea7e6dc9b # v7.3.0 env: BASE_TAGS: "${{ steps.determine-version.outputs.BASE_TAGS }}" SOURCE_COMMIT: "${{ env.SOURCE_COMMIT }}" @@ -237,7 +237,7 @@ jobs: # Upload artifacts to Github Actions and Attest the binaries - name: Attest binaries - uses: actions/attest@59d89421af93a897026c735860bf21b6eb4f7b26 # v4.1.0 + uses: actions/attest@a1948c3f048ba23858d222213b7c278aabede763 # v4.1.1 with: subject-path: vaultwarden-${{ env.NORMALIZED_ARCH }} @@ -272,7 +272,7 @@ jobs: # Login to Docker Hub - name: Login to Docker Hub - uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 + uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} @@ -287,7 +287,7 @@ jobs: # Login to GitHub Container Registry - name: Login to GitHub Container Registry - uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 + uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0 with: registry: ghcr.io username: ${{ github.repository_owner }} @@ -303,7 +303,7 @@ jobs: # Login to Quay.io - name: Login to Quay.io - uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0 + uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0 with: registry: quay.io username: ${{ secrets.QUAY_USERNAME }} @@ -365,7 +365,7 @@ jobs: # Attest container images - name: Attest - docker.io - ${{ matrix.base_image }} if: ${{ vars.DOCKERHUB_REPO != '' && env.DIGEST_SHA != ''}} - uses: actions/attest@59d89421af93a897026c735860bf21b6eb4f7b26 # v4.1.0 + uses: actions/attest@a1948c3f048ba23858d222213b7c278aabede763 # v4.1.1 with: subject-name: ${{ vars.DOCKERHUB_REPO }} subject-digest: ${{ env.DIGEST_SHA }} @@ -373,7 +373,7 @@ jobs: - name: Attest - ghcr.io - ${{ matrix.base_image }} if: ${{ vars.GHCR_REPO != '' && env.DIGEST_SHA != ''}} - uses: actions/attest@59d89421af93a897026c735860bf21b6eb4f7b26 # v4.1.0 + uses: actions/attest@a1948c3f048ba23858d222213b7c278aabede763 # v4.1.1 with: subject-name: ${{ vars.GHCR_REPO }} subject-digest: ${{ env.DIGEST_SHA }} @@ -381,7 +381,7 @@ jobs: - name: Attest - quay.io - ${{ matrix.base_image }} if: ${{ vars.QUAY_REPO != '' && env.DIGEST_SHA != ''}} - uses: actions/attest@59d89421af93a897026c735860bf21b6eb4f7b26 # v4.1.0 + uses: actions/attest@a1948c3f048ba23858d222213b7c278aabede763 # v4.1.1 with: subject-name: ${{ vars.QUAY_REPO }} subject-digest: ${{ env.DIGEST_SHA }} diff --git a/.github/workflows/trivy.yml b/.github/workflows/trivy.yml index 542be807..eaf89350 100644 --- a/.github/workflows/trivy.yml +++ b/.github/workflows/trivy.yml @@ -33,7 +33,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false @@ -50,6 +50,6 @@ jobs: severity: CRITICAL,HIGH - name: Upload Trivy scan results to GitHub Security tab - uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2 + uses: github/codeql-action/upload-sarif@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0 with: sarif_file: 'trivy-results.sarif' diff --git a/.github/workflows/typos.yml b/.github/workflows/typos.yml index a574641c..e906b5bd 100644 --- a/.github/workflows/typos.yml +++ b/.github/workflows/typos.yml @@ -16,11 +16,11 @@ jobs: steps: # Checkout the repo - name: Checkout - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false # End Checkout the repo # When this version is updated, do not forget to update this in `.pre-commit-config.yaml` too - name: Spell Check Repo - uses: crate-ci/typos@37bb98842b0d8c4ffebdb75301a13db0267cef89 # v1.47.2 + uses: crate-ci/typos@bee27e3a4fd1ea2111cf90ab89cd076c870fce14 # v1.48.0 diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml index 36163e39..b8f66cbe 100644 --- a/.github/workflows/zizmor.yml +++ b/.github/workflows/zizmor.yml @@ -19,12 +19,12 @@ jobs: security-events: write # To write the security report steps: - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - name: Run zizmor - uses: zizmorcore/zizmor-action@5f14fd08f7cf1cb1609c1e344975f152c7ee938d # v0.5.6 + uses: zizmorcore/zizmor-action@192e21d79ab29983730a13d1382995c2307fbcaa # v0.5.7 with: # intentionally not scanning the entire repository, # since it contains integration tests. diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8010e67f..35a0140e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,7 +18,7 @@ repos: # When this version is updated, do not forget to update this in `.github/workflows/typos.yaml` too - repo: https://github.com/crate-ci/typos - rev: 37bb98842b0d8c4ffebdb75301a13db0267cef89 # v1.47.2 + rev: bee27e3a4fd1ea2111cf90ab89cd076c870fce14 # v1.48.0 hooks: - id: typos diff --git a/Cargo.lock b/Cargo.lock index 2826b092..0715098c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -48,9 +48,9 @@ checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" [[package]] name = "alloc-stdlib" -version = "0.2.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +checksum = "0e76a019e91224d279006ff972f1e984179a6e9feb050adba6ce8274aef23195" dependencies = [ "alloc-no-stdlib", ] @@ -72,15 +72,15 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.102" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" [[package]] name = "arc-swap" -version = "1.9.1" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a3a1fd6f75306b68087b831f025c712524bcb19aad54e557b1129cfa0a2b207" +checksum = "c049c0be4daef0b145cb3555416b3b8ef5b7888a38aea1a3a155801fe7b0810b" dependencies = [ "rustversion", ] @@ -380,7 +380,7 @@ dependencies = [ "bytes", "fastrand", "hex", - "http 1.4.1", + "http 1.4.2", "sha1 0.10.6", "time", "tokio", @@ -403,9 +403,9 @@ dependencies = [ [[package]] name = "aws-runtime" -version = "1.7.4" +version = "1.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ed8e8c52d2dc2390ad9f15647fe663f71e9780b4262c190fbb823a32721566" +checksum = "6c9b9de216a988dd54b754a82a7660cfe14cee4f6782ae4524470972fa0ccb39" dependencies = [ "aws-credential-types", "aws-sigv4", @@ -418,7 +418,7 @@ dependencies = [ "bytes", "bytes-utils", "fastrand", - "http 1.4.1", + "http 1.4.2", "http-body 1.0.1", "percent-encoding", "pin-project-lite", @@ -428,9 +428,9 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "1.101.0" +version = "1.102.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b647baea49ff551960b904f905681e9b4765a6c4ea08631e89dc52d8bd3f5896" +checksum = "8c82b3ac19f1431854f7ace3a7531674633e286bfdde21976893bfee36fd493b" dependencies = [ "arc-swap", "aws-credential-types", @@ -446,16 +446,16 @@ dependencies = [ "bytes", "fastrand", "http 0.2.12", - "http 1.4.1", + "http 1.4.2", "regex-lite", "tracing", ] [[package]] name = "aws-sdk-ssooidc" -version = "1.103.0" +version = "1.104.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ae401c65ff288aa7873117fe535cd32b7b1bb0bc43751d28901a1d5f20636b9" +checksum = "321000d2b4c5519ee573f73167f612efd7329322d9b26969ad1979f0427f1913" dependencies = [ "arc-swap", "aws-credential-types", @@ -471,16 +471,16 @@ dependencies = [ "bytes", "fastrand", "http 0.2.12", - "http 1.4.1", + "http 1.4.2", "regex-lite", "tracing", ] [[package]] name = "aws-sdk-sts" -version = "1.106.0" +version = "1.107.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c80de7bb7d03e9ca8c9fd7b489f20f3948d3f3be91a7953591347d238115408" +checksum = "3d0d328ba962af23ecfa3c9f23b98d3d35e325fa218d7f13d17a6bf522f8a560" dependencies = [ "arc-swap", "aws-credential-types", @@ -497,7 +497,7 @@ dependencies = [ "aws-types", "fastrand", "http 0.2.12", - "http 1.4.1", + "http 1.4.2", "regex-lite", "tracing", ] @@ -517,7 +517,7 @@ dependencies = [ "hex", "hmac 0.13.0", "http 0.2.12", - "http 1.4.1", + "http 1.4.2", "percent-encoding", "sha2 0.11.0", "time", @@ -526,9 +526,9 @@ dependencies = [ [[package]] name = "aws-smithy-async" -version = "1.2.14" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffcaf626bdda484571968400c326a244598634dc75fd451325a54ad1a59acfc" +checksum = "f02e407fb3b54891734224b9ffac8a71fdd35f542500fa1af95754a6b2beb316" dependencies = [ "futures-util", "pin-project-lite", @@ -547,7 +547,7 @@ dependencies = [ "bytes-utils", "futures-core", "futures-util", - "http 1.4.1", + "http 1.4.2", "http-body 1.0.1", "http-body-util", "percent-encoding", @@ -601,7 +601,7 @@ dependencies = [ "bytes", "fastrand", "http 0.2.12", - "http 1.4.1", + "http 1.4.2", "http-body 0.4.6", "http-body 1.0.1", "http-body-util", @@ -613,16 +613,16 @@ dependencies = [ [[package]] name = "aws-smithy-runtime-api" -version = "1.12.3" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9db177daa6ba8afb9ee1aefcf548c907abcf52065e394ee11a92780057fe0e8c" +checksum = "22ed1ebe6e0a95ea84570225f5a8208dec4b8f77e61a9b0d6f51773fcb4612f0" dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api-macros", "aws-smithy-types", "bytes", "http 0.2.12", - "http 1.4.1", + "http 1.4.2", "pin-project-lite", "tokio", "tracing", @@ -631,9 +631,9 @@ dependencies = [ [[package]] name = "aws-smithy-runtime-api-macros" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d7396fd9500589e62e460e987ecb671bad374934e55ec3b5f498cc7a8a8a7b7" +checksum = "221eaa237ddf1ca79b60d1372aad77e47f9c0ea5b3ce5099da8c61d027dc77b3" dependencies = [ "proc-macro2", "quote", @@ -648,20 +648,20 @@ checksum = "7442cb268338f0eb8278140a107c046756aa01093d8ef5e99628d34ae09c94f5" dependencies = [ "aws-smithy-runtime-api", "aws-smithy-types", - "http 1.4.1", + "http 1.4.2", ] [[package]] name = "aws-smithy-types" -version = "1.4.9" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53f93074121a1be41317b9aa607143ae17900631f7f59a99f2b905d519d6783b" +checksum = "d6dc683efb34b9e755675b37fedbe0103141e5b6df7bdc9eb6967756a8c167d8" dependencies = [ "base64-simd", "bytes", "bytes-utils", "http 0.2.12", - "http 1.4.1", + "http 1.4.2", "http-body 0.4.6", "http-body 1.0.1", "http-body-util", @@ -764,9 +764,15 @@ checksum = "383d29d513d8764dcdc42ea295d979eb99c3c9f00607b3692cf68a431f7dca72" [[package]] name = "bitflags" -version = "2.12.1" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84d7ced0ae9557296835c32bf1b1e02b44c746701f898460fb000d7eaa84f00a" +checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" [[package]] name = "blake2" @@ -788,9 +794,9 @@ dependencies = [ [[package]] name = "block-buffer" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" dependencies = [ "hybrid-array", ] @@ -819,9 +825,9 @@ dependencies = [ [[package]] name = "brotli" -version = "8.0.3" +version = "8.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8119e4516436f5708bbc474a9d395bf12f1b5395e93a92a56e647ac3388c8610" +checksum = "5cc91aac060a7a1e25823bdccbfb6af1875b88f17c6daac97894eed8207166b3" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -830,9 +836,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "5.0.1" +version = "5.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5962523e1b92ce1b5e793d9169b9943eece10d39f62550bc04bb605d75b94924" +checksum = "3a32acac15fe1967bc3986b2a6347dffc965602354ea6f450ad07e8bfd253583" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -867,9 +873,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.11.1" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" [[package]] name = "bytes-utils" @@ -883,9 +889,9 @@ dependencies = [ [[package]] name = "cached" -version = "1.1.0" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4863037a22757575c62f4f52c71bc833c7989c696c35eda5c83a4f36599b2bbd" +checksum = "dc0df7748fe2f601e376916ab19e7bfc2c74461b8abe3bce2ce20036ad8de38f" dependencies = [ "ahash", "cached_proc_macro", @@ -899,9 +905,9 @@ dependencies = [ [[package]] name = "cached_proc_macro" -version = "1.1.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b7a89b3ceb2f9166826b0d21b670a8720dbaeb3397428d1c7603e0ffacdfd37" +checksum = "66e734c52502e6cf54dce2ba07108906b04b8fe57f4f5e3ef7d58267b4abf060" dependencies = [ "darling 0.20.11", "proc-macro2", @@ -926,9 +932,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.63" +version = "1.2.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "556e016178bb5662a08681bbe0f00f8e17631781a4dfc8c45e466e4b185ec27f" +checksum = "f5d6cac793997bd970000024b2934968efe83b382de4fdcf4fcb46b6ee4ad996" dependencies = [ "find-msvc-tools", "jobserver", @@ -944,9 +950,9 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "chacha20" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" +checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" dependencies = [ "cfg-if", "cpufeatures 0.3.0", @@ -1189,27 +1195,27 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.15" +version = "0.5.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +checksum = "d85363c37faeca707aef026efa9f3b34d077bce547e48f770770625c6013679e" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.9.18" +version = "0.9.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.21" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" [[package]] name = "crunchy" @@ -1414,6 +1420,37 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be1e0bca6c3637f992fc1cc7cbc52a78c1ef6db076dbf1059c4323d6a2048376" +[[package]] +name = "defmt" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2953bfe4f93bbd20cc71198842756f77d161884c99ebbabc41d80231ded88d1" +dependencies = [ + "bitflags 1.3.2", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad9c72e7ca2137e0dc3813245a0d282fd6daad32fd800af018306a9169b5fe8" +dependencies = [ + "defmt-parser", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "defmt-parser" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" +dependencies = [ + "thiserror 2.0.18", +] + [[package]] name = "der" version = "0.7.10" @@ -1445,7 +1482,6 @@ version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" dependencies = [ - "powerfmt", "serde_core", ] @@ -1529,7 +1565,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b035a542cf7abf01f2e3c4d5a7acbaebfefe120ae4efc7bde3df98186e4b8af7" dependencies = [ - "bitflags", + "bitflags 2.13.0", "proc-macro2", "proc-macro2-diagnostics", "quote", @@ -1543,7 +1579,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29fe29a87fb84c631ffb3ba21798c4b1f3a964701ba78f0dce4bf8668562ec88" dependencies = [ "bigdecimal", - "bitflags", + "bitflags 2.13.0", "byteorder", "chrono", "diesel_derives", @@ -1564,9 +1600,9 @@ dependencies = [ [[package]] name = "diesel-derive-newtype" -version = "2.1.2" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5adf688c584fe33726ce0e2898f608a2a92578ac94a4a92fcecf73214fe0716" +checksum = "4c9c687e77914afc18b1e797d523ace0e5f08dc7805285bcdabd8646ea8d4de7" dependencies = [ "proc-macro2", "quote", @@ -1624,7 +1660,7 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" dependencies = [ - "block-buffer 0.12.0", + "block-buffer 0.12.1", "const-oid 0.10.2", "crypto-common 0.2.2", "ctutils", @@ -1897,12 +1933,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foldhash" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" - [[package]] name = "foldhash" version = "0.2.0" @@ -2093,16 +2123,14 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" dependencies = [ "cfg-if", "libc", "r-efi 6.0.0", "rand_core 0.10.1", - "wasip2", - "wasip3", ] [[package]] @@ -2172,16 +2200,16 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "171fefbc92fe4a4de27e0698d6a5b392d6a0e333506bc49133760b3bcf948733" +checksum = "6cb093c84e8bd9b188d4c4a8cb6579fc016968d14c99882163cd3ff402a4f155" dependencies = [ "atomic-waker", "bytes", "fnv", "futures-core", "futures-sink", - "http 1.4.1", + "http 1.4.2", "indexmap 2.14.0", "slab", "tokio", @@ -2202,9 +2230,9 @@ dependencies = [ [[package]] name = "handlebars" -version = "6.4.1" +version = "6.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d43ccdfe15a81ab0a8af639e90254227c9a46afd9c5f5b6ec7efaa345c4b0f00" +checksum = "f26569a2763497b7bd3fbd19374b774ea6038c5293678771259cd534d49740ff" dependencies = [ "derive_builder", "log", @@ -2233,15 +2261,6 @@ dependencies = [ "allocator-api2", ] -[[package]] -name = "hashbrown" -version = "0.15.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" -dependencies = [ - "foldhash 0.1.5", -] - [[package]] name = "hashbrown" version = "0.16.1" @@ -2250,7 +2269,7 @@ checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" dependencies = [ "allocator-api2", "equivalent", - "foldhash 0.2.0", + "foldhash", ] [[package]] @@ -2293,7 +2312,7 @@ dependencies = [ "idna", "ipnet", "jni", - "rand 0.10.1", + "rand 0.10.2", "thiserror 2.0.18", "tinyvec", "tokio", @@ -2313,7 +2332,7 @@ dependencies = [ "jni", "once_cell", "prefix-trie", - "rand 0.10.1", + "rand 0.10.2", "ring", "thiserror 2.0.18", "tinyvec", @@ -2338,7 +2357,7 @@ dependencies = [ "ndk-context", "once_cell", "parking_lot", - "rand 0.10.1", + "rand 0.10.2", "resolv-conf", "smallvec", "system-configuration", @@ -2387,9 +2406,9 @@ dependencies = [ [[package]] name = "html5gum" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12d29324a6ba370667998f63c6dd2b2511e2297f07e827f69026684907adc3b5" +checksum = "428502d3ec1742c35e015871aef742bc4722a9acfcb616b8ff79b519922e1c36" dependencies = [ "jetscii", ] @@ -2407,9 +2426,9 @@ dependencies = [ [[package]] name = "http" -version = "1.4.1" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8be7462df143984c4598a256ef469b251d7d7f9e271135073e78fc535414f3d0" +checksum = "6970f50e31d6fc17d3fa27329444bfa74e196cf62e95052a3f6fee181dba6425" dependencies = [ "bytes", "itoa", @@ -2433,7 +2452,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.4.1", + "http 1.4.2", ] [[package]] @@ -2444,7 +2463,7 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", - "http 1.4.1", + "http 1.4.2", "http-body 1.0.1", "pin-project-lite", ] @@ -2463,9 +2482,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hybrid-array" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9155a582abd142abc056962c29e3ce5ff2ad5469f4246b537ed42c5deba857da" +checksum = "818356c5132c1fede50f837ca96afbe78ff42413047f4abb886217845e1b6c8c" dependencies = [ "typenum", ] @@ -2504,7 +2523,7 @@ dependencies = [ "futures-channel", "futures-core", "h2", - "http 1.4.1", + "http 1.4.2", "http-body 1.0.1", "httparse", "itoa", @@ -2520,10 +2539,10 @@ version = "0.27.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" dependencies = [ - "http 1.4.1", + "http 1.4.2", "hyper 1.10.1", "hyper-util", - "rustls 0.23.40", + "rustls 0.23.41", "tokio", "tokio-rustls 0.26.4", "tower-service", @@ -2539,7 +2558,7 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.4.1", + "http 1.4.2", "http-body 1.0.1", "hyper 1.10.1", "ipnet", @@ -2660,12 +2679,6 @@ dependencies = [ "zerovec", ] -[[package]] -name = "id-arena" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" - [[package]] name = "ident_case" version = "1.0.1" @@ -2788,10 +2801,11 @@ checksum = "47f142fe24a9c9944451e8349de0a56af5f3e7226dc46f3ed4d4ecc0b85af75e" [[package]] name = "jiff" -version = "0.2.28" +version = "0.2.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4603d3033e49e2b0e31229fcab20a5d40089c607d975cd9c80551dc69eed9102" +checksum = "ccfe6121cbe750cf81efa362d85c0bde7ea298ec43092d3a193baca59cdbd634" dependencies = [ + "defmt", "jiff-static", "jiff-tzdb-platform", "js-sys", @@ -2805,9 +2819,9 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.28" +version = "0.2.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "782d32378dddf207193ac91cefb848ad41abb58195c95168e1291227a0832b47" +checksum = "e165e897f662d428f3cd3828a919dbe067c2d42bb1031eede74ef9d27ecdedd2" dependencies = [ "proc-macro2", "quote", @@ -2816,9 +2830,9 @@ dependencies = [ [[package]] name = "jiff-tzdb" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c900ef84826f1338a557697dc8fc601df9ca9af4ac137c7fb61d4c6f2dfd3076" +checksum = "6142247df1a93c2b3587402a19710be3e6e942f1581a1702e76408f2c21d6590" [[package]] name = "jiff-tzdb-platform" @@ -2891,23 +2905,22 @@ dependencies = [ [[package]] name = "jobserver" -version = "0.1.34" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" dependencies = [ - "getrandom 0.3.4", + "getrandom 0.4.3", "libc", ] [[package]] name = "js-sys" -version = "0.3.99" +version = "0.3.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "142bc4740e452c1e57ade0cbc129f139c9093e354346f0872ef985f4f5cf5f11" +checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" dependencies = [ "cfg-if", "futures-util", - "once_cell", "wasm-bindgen", ] @@ -2962,12 +2975,6 @@ dependencies = [ "spin", ] -[[package]] -name = "leb128fmt" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" - [[package]] name = "lettre" version = "0.11.22" @@ -2989,7 +2996,7 @@ dependencies = [ "nom 8.0.0", "percent-encoding", "quoted_printable", - "rustls 0.23.40", + "rustls 0.23.41", "rustls-native-certs", "serde", "socket2 0.6.4", @@ -3060,9 +3067,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.32" +version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953f07c43838f8e6f9758cab68bf5bed85465e7587ebe0b823f1bcd81978ad3a" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" dependencies = [ "value-bag", ] @@ -3120,9 +3127,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.8.1" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" [[package]] name = "migrations_internals" @@ -3216,7 +3223,7 @@ dependencies = [ "bytes", "encoding_rs", "futures-util", - "http 1.4.1", + "http 1.4.2", "httparse", "memchr", "mime", @@ -3228,9 +3235,9 @@ dependencies = [ [[package]] name = "mysqlclient-sys" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "822bc60a9459abe384dd85d81ac59167ed2da99fba6eb810000e6ab64d9404b2" +checksum = "b72511f8f6991fe4ac86421ea0625630fd94e360b906cc59720506499f9e8f3b" dependencies = [ "pkg-config", "semver", @@ -3279,9 +3286,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.6" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367" dependencies = [ "num-integer", "num-traits", @@ -3331,20 +3338,19 @@ dependencies = [ [[package]] name = "num-iter" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +checksum = "c92800bd69a1eac91786bcfe9da64a897eb72911b8dc3095decbd07429e8048b" dependencies = [ - "autocfg", "num-integer", "num-traits", ] [[package]] name = "num-modular" -version = "0.6.1" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17bb261bf36fa7d83f4c294f834e91256769097b3cb505d44831e0a179ac647f" +checksum = "fc41a1374056e9672221567958a66c16be12d0e2c1b408761e14d901c237d5e0" [[package]] name = "num-order" @@ -3393,7 +3399,7 @@ dependencies = [ "base64 0.22.1", "chrono", "getrandom 0.2.17", - "http 1.4.1", + "http 1.4.2", "rand 0.8.6", "serde", "serde_json", @@ -3443,7 +3449,7 @@ dependencies = [ "base64 0.22.1", "bytes", "futures", - "http 1.4.1", + "http 1.4.2", "http-body 1.0.1", "jiff", "log", @@ -3484,7 +3490,7 @@ dependencies = [ "base64 0.22.1", "bytes", "crc32c", - "http 1.4.1", + "http 1.4.2", "log", "md-5", "opendal-core", @@ -3507,7 +3513,7 @@ dependencies = [ "dyn-clone", "ed25519-dalek", "hmac 0.12.1", - "http 1.4.1", + "http 1.4.2", "itertools", "log", "oauth2", @@ -3529,11 +3535,11 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.80" +version = "0.10.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a45fa2aa886c42762255da344f0a0d313e254066c46aad76f300c3d3da62d967" +checksum = "77823a27f0babb03091cb9ed9ef80af3b39dbc82f97e8fa530374b7dafd87a45" dependencies = [ - "bitflags", + "bitflags 2.13.0", "cfg-if", "foreign-types", "libc", @@ -3560,18 +3566,18 @@ checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] name = "openssl-src" -version = "300.6.0+3.6.2" +version = "300.6.1+3.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8e8cbfd3a4a8c8f089147fd7aaa33cf8c7450c4d09f8f80698a0cf093abeff4" +checksum = "46eb8fb9fb3b61ce1c0f8a026c4c1a0714d3a9e138e7fbde78753ce2babc3846" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.116" +version = "0.9.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28a22dc7140cda5f096e5e7724a6962ca81a7f8bfd2979f9b18c11af56318c4" +checksum = "b47e7e6bb2c38cd930d25a23b40fa52e068c10e85f3e03a7f5ba5aaca5713695" dependencies = [ "cc", "libc", @@ -3741,9 +3747,9 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.8.6" +version = "2.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0848c601009d37dfa3430c4666e147e49cdcf1b92ecd3e63657d8a5f19da662" +checksum = "47627dd7305c6a2d6c8c6bcd24c5a4c17dbbf425f4f9c5313e724b38fc9782e9" dependencies = [ "memchr", "ucd-trie", @@ -3751,9 +3757,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.8.6" +version = "2.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11f486f1ea21e6c10ed15d5a7c77165d0ee443402f0780849d1768e7d9d6fe77" +checksum = "4b4254325ecad416ab689e27ba51da03ba01a9632bc6e108f5fe7c3c4ad29d58" dependencies = [ "pest", "pest_generator", @@ -3761,9 +3767,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.8.6" +version = "2.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8040c4647b13b210a963c1ed407c1ff4fdfa01c31d6d2a098218702e6664f94f" +checksum = "6c4c0e91ead7a8f7acecbca6f003fc2e8282b1dbe2dd9c9d2f16aba42995e0a7" dependencies = [ "pest", "pest_meta", @@ -3774,12 +3780,11 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.8.6" +version = "2.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89815c69d36021a140146f26659a81d6c2afa33d216d736dd4be5381a7362220" +checksum = "f9744bc48116fee06334924bb5f2bad41eed5e89bd26e29b0b799f9a3f82c210" dependencies = [ "pest", - "sha2 0.10.9", ] [[package]] @@ -3990,16 +3995,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "prettyplease" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" -dependencies = [ - "proc-macro2", - "syn", -] - [[package]] name = "primeorder" version = "0.13.6" @@ -4090,9 +4085,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.45" +version = "1.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" dependencies = [ "proc-macro2", ] @@ -4149,12 +4144,12 @@ dependencies = [ [[package]] name = "rand" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" +checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" dependencies = [ "chacha20", - "getrandom 0.4.2", + "getrandom 0.4.3", "rand_core 0.10.1", ] @@ -4208,7 +4203,7 @@ version = "11.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" dependencies = [ - "bitflags", + "bitflags 2.13.0", ] [[package]] @@ -4217,7 +4212,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags", + "bitflags 2.13.0", ] [[package]] @@ -4242,9 +4237,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.12.3" +version = "1.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba" dependencies = [ "aho-corasick", "memchr", @@ -4271,9 +4266,9 @@ checksum = "cab834c73d247e67f4fae452806d17d3c7501756d98c8808d7c9c7aa7d18f973" [[package]] name = "regex-syntax" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" [[package]] name = "reopen" @@ -4296,7 +4291,7 @@ dependencies = [ "bytes", "form_urlencoded", "hex", - "http 1.4.1", + "http 1.4.2", "log", "percent-encoding", "quick-xml 0.40.1", @@ -4321,7 +4316,7 @@ dependencies = [ "futures", "hex", "hmac 0.13.0", - "http 1.4.1", + "http 1.4.2", "jiff", "log", "percent-encoding", @@ -4359,7 +4354,7 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http 1.4.1", + "http 1.4.2", "http-body 1.0.1", "http-body-util", "hyper 1.10.1", @@ -4370,7 +4365,7 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", - "rustls 0.23.40", + "rustls 0.23.41", "rustls-pki-types", "rustls-platform-verifier", "serde", @@ -4619,7 +4614,7 @@ version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags", + "bitflags 2.13.0", "errno", "libc", "linux-raw-sys", @@ -4640,9 +4635,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.40" +version = "0.23.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b" +checksum = "6b92b125634d9b795e7beca796cc790df15a7fb38323bf3196fda83292d06b1f" dependencies = [ "log", "once_cell", @@ -4676,9 +4671,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.14.1" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9" +checksum = "764899a24af3980067ee14bc143654f297b22eaebfe3c7b6b211920a5a59b046" dependencies = [ "zeroize", ] @@ -4694,7 +4689,7 @@ dependencies = [ "jni", "log", "once_cell", - "rustls 0.23.40", + "rustls 0.23.41", "rustls-native-certs", "rustls-platform-verifier-android", "rustls-webpki 0.103.13", @@ -4733,9 +4728,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" [[package]] name = "ryu" @@ -4856,7 +4851,7 @@ version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ - "bitflags", + "bitflags 2.13.0", "core-foundation 0.10.1", "core-foundation-sys", "libc", @@ -4935,6 +4930,7 @@ version = "1.0.150" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" dependencies = [ + "indexmap 2.14.0", "itoa", "memchr", "serde", @@ -5161,9 +5157,9 @@ checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" -version = "1.15.1" +version = "1.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" [[package]] name = "socket2" @@ -5273,9 +5269,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.117" +version = "2.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" dependencies = [ "proc-macro2", "quote", @@ -5320,7 +5316,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" dependencies = [ - "bitflags", + "bitflags 2.13.0", "core-foundation 0.9.4", "system-configuration-sys", ] @@ -5348,7 +5344,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.4.2", + "getrandom 0.4.3", "once_cell", "rustix", "windows-sys 0.61.2", @@ -5414,12 +5410,11 @@ dependencies = [ [[package]] name = "time" -version = "0.3.47" +version = "0.3.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +checksum = "18dfaaeddcb932337b5e7866ee7d0ce9b76d2fd092997146f187ec09b4558a50" dependencies = [ "deranged", - "itoa", "libc", "num-conv", "num_threads", @@ -5431,15 +5426,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" [[package]] name = "time-macros" -version = "0.2.27" +version = "0.2.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +checksum = "c431b87111666e491a90baa837f914fb45cd5dc3c268591b0220ff5057f2085f" dependencies = [ "num-conv", "time-core", @@ -5523,7 +5518,7 @@ version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ - "rustls 0.23.40", + "rustls 0.23.41", "tokio", ] @@ -5670,11 +5665,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" dependencies = [ "async-compression", - "bitflags", + "bitflags 2.13.0", "bytes", "futures-core", "futures-util", - "http 1.4.1", + "http 1.4.2", "http-body 1.0.1", "http-body-util", "pin-project-lite", @@ -5775,7 +5770,7 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http 1.4.1", + "http 1.4.2", "httparse", "log", "rand 0.8.6", @@ -5873,11 +5868,11 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "uuid" -version = "1.23.2" +version = "1.23.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d258b83ceec21034727ecee8c382cfa6c3e133699b0742c64571814fb420c9f7" +checksum = "bf80a72845275afea99e7f2b434723d3bc7e38470fcd1c7ed39a599c73319a53" dependencies = [ - "getrandom 0.4.2", + "getrandom 0.4.3", "js-sys", "serde_core", "wasm-bindgen", @@ -5926,7 +5921,7 @@ dependencies = [ "handlebars", "hickory-resolver", "html5gum", - "http 1.4.1", + "http 1.4.2", "job_scheduler_ng", "jsonwebtoken", "lettre", @@ -5943,7 +5938,7 @@ dependencies = [ "pastey 0.2.3", "percent-encoding", "pico-args", - "rand 0.10.1", + "rand 0.10.2", "regex", "reqsign-aws-v4", "reqsign-core", @@ -5953,7 +5948,7 @@ dependencies = [ "rocket", "rocket_ws", "rpassword", - "rustls 0.23.40", + "rustls 0.23.41", "semver", "serde", "serde_json", @@ -6019,27 +6014,18 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.3+wasi-0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" -dependencies = [ - "wit-bindgen 0.57.1", -] - -[[package]] -name = "wasip3" -version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +version = "1.0.4+wasi-0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" dependencies = [ - "wit-bindgen 0.51.0", + "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.122" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed04576f974d2b2fba0f38c51dbc5518011e38c36bf1143164be765528fd409" +checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" dependencies = [ "cfg-if", "once_cell", @@ -6050,9 +6036,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.72" +version = "0.4.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9473dbd2991ae90b6291c3c32c30c6187ac49aa32f9905d1cce280ec1e110b0f" +checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d" dependencies = [ "js-sys", "wasm-bindgen", @@ -6060,9 +6046,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.122" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "916151b09da36bd82f6615cbf3a419e2f0ba23a03c6160e8e92eb6bd4aa1dec6" +checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -6070,9 +6056,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.122" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "299047362ccbfce148b67ab7e73349f77748e00c8296f9542adfad2ad82c5c5e" +checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" dependencies = [ "bumpalo", "proc-macro2", @@ -6083,35 +6069,13 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.122" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a929b2c61f11ba3e9bc35b50c1f25cb38e0e892c0c231ae2b8cf78d5dad4437" +checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" dependencies = [ "unicode-ident", ] -[[package]] -name = "wasm-encoder" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" -dependencies = [ - "leb128fmt", - "wasmparser", -] - -[[package]] -name = "wasm-metadata" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" -dependencies = [ - "anyhow", - "indexmap 2.14.0", - "wasm-encoder", - "wasmparser", -] - [[package]] name = "wasm-streams" version = "0.5.0" @@ -6125,23 +6089,11 @@ dependencies = [ "web-sys", ] -[[package]] -name = "wasmparser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" -dependencies = [ - "bitflags", - "hashbrown 0.15.5", - "indexmap 2.14.0", - "semver", -] - [[package]] name = "web-sys" -version = "0.3.99" +version = "0.3.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621441cfc37b84979402712047321980c178f299193a3589d05b99e8763436" +checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141" dependencies = [ "js-sys", "wasm-bindgen", @@ -6227,18 +6179,18 @@ dependencies = [ [[package]] name = "webpki-root-certs" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31141ce3fc3e300ae89b78c0dd67f9708061d1d2eda54b8209346fd6be9a92c" +checksum = "0d46a5a140e6f7afeccd8eae97eff335163939eac8b929834875168b29b3d267" dependencies = [ "rustls-pki-types", ] [[package]] name = "which" -version = "8.0.2" +version = "8.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81995fafaaaf6ae47a7d0cc83c67caf92aeb7e5331650ae6ff856f7c0c60c459" +checksum = "48d7cd18d4acb58fb3cdfe9ea54e6cd96a4e7d4cc45c56338b236e82dad47248" dependencies = [ "libc", ] @@ -6531,100 +6483,12 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" -[[package]] -name = "wit-bindgen" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" -dependencies = [ - "wit-bindgen-rust-macro", -] - [[package]] name = "wit-bindgen" version = "0.57.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" -[[package]] -name = "wit-bindgen-core" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" -dependencies = [ - "anyhow", - "heck", - "wit-parser", -] - -[[package]] -name = "wit-bindgen-rust" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" -dependencies = [ - "anyhow", - "heck", - "indexmap 2.14.0", - "prettyplease", - "syn", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", -] - -[[package]] -name = "wit-bindgen-rust-macro" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" -dependencies = [ - "anyhow", - "prettyplease", - "proc-macro2", - "quote", - "syn", - "wit-bindgen-core", - "wit-bindgen-rust", -] - -[[package]] -name = "wit-component" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" -dependencies = [ - "anyhow", - "bitflags", - "indexmap 2.14.0", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-encoder", - "wasm-metadata", - "wasmparser", - "wit-parser", -] - -[[package]] -name = "wit-parser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" -dependencies = [ - "anyhow", - "id-arena", - "indexmap 2.14.0", - "log", - "semver", - "serde", - "serde_derive", - "serde_json", - "unicode-xid", - "wasmparser", -] - [[package]] name = "writeable" version = "0.6.3" @@ -6720,18 +6584,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.50" +version = "0.8.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b065d4f0e55f82fae73202e189638116a87c55ab6b8e6c2721e13dd9d854ad1" +checksum = "75726053136156d419e285b9b7eddaaea9e3fea6ce32eed44a89901f0bd98de1" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.50" +version = "0.8.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b631b19d36a892ab55420c92dbc83ccd79274f25be714855d3074aa71cab639" +checksum = "4714fd92cf900833d49538023a9b3915155210801d1c1169eba513b2addefd71" dependencies = [ "proc-macro2", "quote", @@ -6761,18 +6625,18 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.8.2" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" dependencies = [ "zeroize_derive", ] [[package]] name = "zeroize_derive" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" +checksum = "3c50655cbb0fe3fc43170059e702f1ce5e19b84cec58dc87b037a09935c2f328" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 47c17f59..909570e7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace.package] edition = "2024" -rust-version = "1.94.0" +rust-version = "1.94.1" license = "AGPL-3.0-only" repository = "https://github.com/dani-garcia/vaultwarden" publish = false @@ -65,7 +65,7 @@ syslog = "7.0.0" macros = { path = "./macros" } # Logging -log = "0.4.32" +log = "0.4.33" fern = { version = "0.7.1", features = ["syslog-7", "reopen-1"] } # We need the `log` feature for `tracing` to enable logging for several crates to work, like lettre or webauthn-rs tracing = { version = "0.1.44", features = ["log"] } @@ -116,24 +116,24 @@ derive_more = { version = "2.1.1", features = [ "from", "into", ] } -diesel-derive-newtype = "2.1.2" +diesel-derive-newtype = "2.1.3" # SQLite, statically bundled unless the `sqlite_system` feature is enabled libsqlite3-sys = { version = "0.37.0", optional = true } # Crypto-related libraries -rand = "0.10.1" +rand = "0.10.2" ring = "0.17.14" -rustls = { version = "0.23.40", features = ["ring", "std"], default-features = false } +rustls = { version = "0.23.41", features = ["ring", "std"], default-features = false } subtle = "2.6.1" # UUID generation -uuid = { version = "1.23.2", features = ["v4"] } +uuid = { version = "1.23.4", features = ["v4"] } # Date and time libraries chrono = { version = "0.4.45", default-features = false, features = ["clock", "serde"] } chrono-tz = "0.10.4" -time = "0.3.47" +time = "0.3.53" # Job scheduler job_scheduler_ng = "2.4.0" @@ -179,7 +179,7 @@ percent-encoding = "2.3.2" # URL encoding library used for URL's in the emails email_address = "0.2.9" # HTML Template library -handlebars = { version = "6.4.1", features = ["dir_source"] } +handlebars = { version = "6.4.2", features = ["dir_source"] } # HTTP client (Used for favicons, version check, DUO and HIBP API) reqwest = { version = "0.13.4", default-features = false, features = [ @@ -203,25 +203,25 @@ reqwest = { version = "0.13.4", default-features = false, features = [ hickory-resolver = "0.26.1" # Favicon extraction libraries -html5gum = "0.8.3" -regex = { version = "1.12.3", default-features = false, features = [ +html5gum = "0.8.4" +regex = { version = "1.12.4", default-features = false, features = [ "perf", "std", "unicode-perl", ] } data-url = "0.3.2" -bytes = "1.11.1" +bytes = "1.12.1" svg-hush = "0.9.6" # Cache function results (Used for version check and favicon fetching) -cached = { version = "1.1.0", features = ["async"] } +cached = { version = "2.0.2", features = ["async"] } # Used for custom short lived cookie jar during favicon extraction cookie = "0.18.1" cookie_store = "0.22.1" # Used by U2F, JWT and PostgreSQL -openssl = "0.10.80" +openssl = "0.10.81" # CLI argument parsing pico-args = "0.5.0" @@ -241,7 +241,7 @@ semver = "1.0.28" # Mainly used for the musl builds, since the default musl malloc is very slow mimalloc = { version = "0.1.52", optional = true, default-features = false, features = ["secure"] } -which = "8.0.2" +which = "8.0.4" # Argon2 library with support for the PHC format argon2 = "0.5.3" @@ -263,8 +263,8 @@ aws-config = { version = "1.8.18", optional = true, default-features = false, fe "sso", ] } aws-credential-types = { version = "1.2.14", optional = true } -aws-smithy-runtime-api = { version = "1.12.3", optional = true } -http = { version = "1.4.1", optional = true } +aws-smithy-runtime-api = { version = "1.13.0", optional = true } +http = { version = "1.4.2", optional = true } reqsign-aws-v4 = { version = "3.0.1", optional = true } reqsign-core = { version = "3.0.1", optional = true } diff --git a/docker/DockerSettings.yaml b/docker/DockerSettings.yaml index 5f2c16cf..1d765305 100644 --- a/docker/DockerSettings.yaml +++ b/docker/DockerSettings.yaml @@ -1,13 +1,13 @@ --- -vault_version: "v2026.4.1" -vault_image_digest: "sha256:ca2a4251c4e63c9ad428262b4dd452789a1b9f6fce71da351e93dceed0d2edbe" +vault_version: "v2026.6.2" +vault_image_digest: "sha256:f004f72a5d357b87483839500a517da3d1b4ea0a57b9731989d298cccea7d02a" # Cross Compile Docker Helper Scripts v1.9.0 # 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 xx_image_digest: "sha256:c64defb9ed5a91eacb37f96ccc3d4cd72521c4bd18d5442905b95e2226b0e707" -rust_version: 1.96.0 # Rust version to be used +rust_version: 1.96.1 # Rust version to be used debian_version: trixie # Debian release name to be used -alpine_version: "3.23" # Alpine version to be used +alpine_version: "3.24" # Alpine version to be used # For which platforms/architectures will we try to build images platforms: ["linux/amd64", "linux/arm64", "linux/arm/v7", "linux/arm/v6"] # Determine the build images per OS/Arch diff --git a/docker/Dockerfile.alpine b/docker/Dockerfile.alpine index 373d944b..7bea0d0d 100644 --- a/docker/Dockerfile.alpine +++ b/docker/Dockerfile.alpine @@ -19,23 +19,23 @@ # - 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:v2026.4.1 -# $ docker image inspect --format "{{.RepoDigests}}" docker.io/vaultwarden/web-vault:v2026.4.1 -# [docker.io/vaultwarden/web-vault@sha256:ca2a4251c4e63c9ad428262b4dd452789a1b9f6fce71da351e93dceed0d2edbe] +# $ docker pull docker.io/vaultwarden/web-vault:v2026.6.2 +# $ docker image inspect --format "{{.RepoDigests}}" docker.io/vaultwarden/web-vault:v2026.6.2 +# [docker.io/vaultwarden/web-vault@sha256:f004f72a5d357b87483839500a517da3d1b4ea0a57b9731989d298cccea7d02a] # # - Conversely, to get the tag name from the digest: -# $ docker image inspect --format "{{.RepoTags}}" docker.io/vaultwarden/web-vault@sha256:ca2a4251c4e63c9ad428262b4dd452789a1b9f6fce71da351e93dceed0d2edbe -# [docker.io/vaultwarden/web-vault:v2026.4.1] +# $ docker image inspect --format "{{.RepoTags}}" docker.io/vaultwarden/web-vault@sha256:f004f72a5d357b87483839500a517da3d1b4ea0a57b9731989d298cccea7d02a +# [docker.io/vaultwarden/web-vault:v2026.6.2] # -FROM --platform=linux/amd64 docker.io/vaultwarden/web-vault@sha256:ca2a4251c4e63c9ad428262b4dd452789a1b9f6fce71da351e93dceed0d2edbe AS vault +FROM --platform=linux/amd64 docker.io/vaultwarden/web-vault@sha256:f004f72a5d357b87483839500a517da3d1b4ea0a57b9731989d298cccea7d02a AS vault ########################## ALPINE BUILD IMAGES ########################## ## NOTE: The Alpine Base Images do not support other platforms then linux/amd64 and linux/arm64 ## And for Alpine we define all build images here, they will only be loaded when actually used -FROM --platform=$BUILDPLATFORM ghcr.io/blackdex/rust-musl:x86_64-musl-stable-1.96.0 AS build_amd64 -FROM --platform=$BUILDPLATFORM ghcr.io/blackdex/rust-musl:aarch64-musl-stable-1.96.0 AS build_arm64 -FROM --platform=$BUILDPLATFORM ghcr.io/blackdex/rust-musl:armv7-musleabihf-stable-1.96.0 AS build_armv7 -FROM --platform=$BUILDPLATFORM ghcr.io/blackdex/rust-musl:arm-musleabi-stable-1.96.0 AS build_armv6 +FROM --platform=$BUILDPLATFORM ghcr.io/blackdex/rust-musl:x86_64-musl-stable-1.96.1 AS build_amd64 +FROM --platform=$BUILDPLATFORM ghcr.io/blackdex/rust-musl:aarch64-musl-stable-1.96.1 AS build_arm64 +FROM --platform=$BUILDPLATFORM ghcr.io/blackdex/rust-musl:armv7-musleabihf-stable-1.96.1 AS build_armv7 +FROM --platform=$BUILDPLATFORM ghcr.io/blackdex/rust-musl:arm-musleabi-stable-1.96.1 AS build_armv6 ########################## BUILD IMAGE ########################## # hadolint ignore=DL3006 @@ -126,7 +126,7 @@ RUN source /env-cargo && \ # To uninstall: docker run --privileged --rm tonistiigi/binfmt --uninstall 'qemu-*' # # We need to add `--platform` here, because of a podman bug: https://github.com/containers/buildah/issues/4742 -FROM --platform=$TARGETPLATFORM docker.io/library/alpine:3.23 +FROM --platform=$TARGETPLATFORM docker.io/library/alpine:3.24 ENV ROCKET_PROFILE="release" \ ROCKET_ADDRESS=0.0.0.0 \ diff --git a/docker/Dockerfile.debian b/docker/Dockerfile.debian index 85afb0f5..5de9fdb5 100644 --- a/docker/Dockerfile.debian +++ b/docker/Dockerfile.debian @@ -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:v2026.4.1 -# $ docker image inspect --format "{{.RepoDigests}}" docker.io/vaultwarden/web-vault:v2026.4.1 -# [docker.io/vaultwarden/web-vault@sha256:ca2a4251c4e63c9ad428262b4dd452789a1b9f6fce71da351e93dceed0d2edbe] +# $ docker pull docker.io/vaultwarden/web-vault:v2026.6.2 +# $ docker image inspect --format "{{.RepoDigests}}" docker.io/vaultwarden/web-vault:v2026.6.2 +# [docker.io/vaultwarden/web-vault@sha256:f004f72a5d357b87483839500a517da3d1b4ea0a57b9731989d298cccea7d02a] # # - Conversely, to get the tag name from the digest: -# $ docker image inspect --format "{{.RepoTags}}" docker.io/vaultwarden/web-vault@sha256:ca2a4251c4e63c9ad428262b4dd452789a1b9f6fce71da351e93dceed0d2edbe -# [docker.io/vaultwarden/web-vault:v2026.4.1] +# $ docker image inspect --format "{{.RepoTags}}" docker.io/vaultwarden/web-vault@sha256:f004f72a5d357b87483839500a517da3d1b4ea0a57b9731989d298cccea7d02a +# [docker.io/vaultwarden/web-vault:v2026.6.2] # -FROM --platform=linux/amd64 docker.io/vaultwarden/web-vault@sha256:ca2a4251c4e63c9ad428262b4dd452789a1b9f6fce71da351e93dceed0d2edbe AS vault +FROM --platform=linux/amd64 docker.io/vaultwarden/web-vault@sha256:f004f72a5d357b87483839500a517da3d1b4ea0a57b9731989d298cccea7d02a AS vault ########################## Cross Compile Docker Helper Scripts ########################## ## We use the linux/amd64 no matter which Build Platform, since these are all bash scripts @@ -36,7 +36,7 @@ FROM --platform=linux/amd64 docker.io/tonistiigi/xx@sha256:c64defb9ed5a91eacb37f ########################## BUILD IMAGE ########################## # hadolint ignore=DL3006 -FROM --platform=$BUILDPLATFORM docker.io/library/rust:1.96.0-slim-trixie AS build +FROM --platform=$BUILDPLATFORM docker.io/library/rust:1.96.1-slim-trixie AS build COPY --from=xx / / ARG TARGETARCH ARG TARGETVARIANT diff --git a/macros/Cargo.toml b/macros/Cargo.toml index eb3bd670..d36b3e46 100644 --- a/macros/Cargo.toml +++ b/macros/Cargo.toml @@ -13,8 +13,8 @@ path = "src/lib.rs" proc-macro = true [dependencies] -quote = "1.0.45" -syn = "2.0.117" +quote = "1.0.46" +syn = "2.0.118" [lints] workspace = true diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 2a813a32..6c32b3e0 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "1.96.0" +channel = "1.96.1" components = [ "rustfmt", "clippy" ] profile = "minimal" diff --git a/src/api/core/ciphers.rs b/src/api/core/ciphers.rs index 6b9994cf..14e9f72f 100644 --- a/src/api/core/ciphers.rs +++ b/src/api/core/ciphers.rs @@ -2135,9 +2135,9 @@ impl CipherSyncData { // Organization Sync does not support Folders, Favorites, or Archives. // If these are set, it will cause issues in the web-vault. CipherSyncType::Organization => { - cipher_folders = HashMap::with_capacity(0); - cipher_favorites = HashSet::with_capacity(0); - cipher_archives = HashMap::with_capacity(0); + cipher_folders = HashMap::new(); + cipher_favorites = HashSet::new(); + cipher_archives = HashMap::new(); } } diff --git a/src/api/core/events.rs b/src/api/core/events.rs index b6e2bacd..698a890f 100644 --- a/src/api/core/events.rs +++ b/src/api/core/events.rs @@ -52,7 +52,7 @@ async fn get_org_events(org_id: OrganizationId, data: EventRange, headers: Admin .map(Event::to_json) .collect() } else { - Vec::with_capacity(0) + Vec::new() }; Ok(Json(json!({ @@ -78,7 +78,7 @@ async fn get_cipher_events(cipher_id: CipherId, data: EventRange, headers: Heade Event::find_by_cipher_uuid(&cipher_id, &start_date, &end_date, &conn).await.iter().map(Event::to_json).collect() } else { - Vec::with_capacity(0) + Vec::new() }; Ok(Json(json!({ @@ -115,7 +115,7 @@ async fn get_user_events( .map(Event::to_json) .collect() } else { - Vec::with_capacity(0) + Vec::new() }; Ok(Json(json!({ diff --git a/src/api/core/organizations.rs b/src/api/core/organizations.rs index 68c9c1c5..c7e79aed 100644 --- a/src/api/core/organizations.rs +++ b/src/api/core/organizations.rs @@ -470,7 +470,7 @@ async fn get_org_collections_details(org_id: OrganizationId, headers: ManagerHea .map(CollectionGroup::to_json_details_for_group) .collect() } else { - Vec::with_capacity(0) + Vec::new() }; let mut json_object = col.to_json_details(&headers.user.uuid, None, &conn).await; @@ -806,7 +806,7 @@ async fn get_org_collection_detail( } else { // The Bitwarden clients seem to call this API regardless of whether groups are enabled, // so just act as if there are no groups. - Vec::with_capacity(0) + Vec::new() }; // Generate a HashMap to get the correct MembershipType per user to determine the manage permission @@ -2458,7 +2458,7 @@ async fn get_groups_data( } else { // The Bitwarden clients seem to call this API regardless of whether groups are enabled, // so just act as if there are no groups. - Vec::with_capacity(0) + Vec::new() }; Ok(Json(json!({ diff --git a/src/db/models/cipher.rs b/src/db/models/cipher.rs index 3852ceff..8357c9eb 100644 --- a/src/db/models/cipher.rs +++ b/src/db/models/cipher.rs @@ -320,7 +320,7 @@ impl Cipher { if let Some(cipher_collections) = cipher_sync_data.cipher_collections.get(&self.uuid) { Cow::from(cipher_collections) } else { - Cow::from(Vec::with_capacity(0)) + Cow::from(Vec::new()) } } else { Cow::from(self.get_admin_collections(user_uuid.clone(), conn).await) diff --git a/src/db/models/mod.rs b/src/db/models/mod.rs index 1cacbcac..0ed8ef91 100644 --- a/src/db/models/mod.rs +++ b/src/db/models/mod.rs @@ -34,10 +34,7 @@ pub use self::organization::{ Membership, MembershipId, MembershipStatus, MembershipType, OrgApiKeyId, Organization, OrganizationApiKey, OrganizationId, }; -pub use self::send::{ - Send, SendType, - id::{SendFileId, SendId}, -}; +pub use self::send::{Send, SendFileId, SendId, SendType}; pub use self::sso_auth::{OIDCAuthenticatedUser, OIDCCodeResponseError, SsoAuth}; pub use self::two_factor::{TwoFactor, TwoFactorType}; pub use self::two_factor_duo_context::TwoFactorDuoContext; diff --git a/src/db/models/organization.rs b/src/db/models/organization.rs index d604add4..72b1df0b 100644 --- a/src/db/models/organization.rs +++ b/src/db/models/organization.rs @@ -550,7 +550,7 @@ impl Membership { } else { // The Bitwarden clients seem to call this API regardless of whether groups are enabled, // so just act as if there are no groups. - Vec::with_capacity(0) + Vec::new() }; // Check if a user is in a group which has access to all collections @@ -604,7 +604,7 @@ impl Membership { }) .collect() } else { - Vec::with_capacity(0) + Vec::new() }; // HACK: Convert the manager type to a custom type diff --git a/src/db/models/send.rs b/src/db/models/send.rs index a35bcf8d..48159e8a 100644 --- a/src/db/models/send.rs +++ b/src/db/models/send.rs @@ -1,6 +1,10 @@ +use std::path::Path; + use chrono::{NaiveDateTime, Utc}; use data_encoding::BASE64URL_NOPAD; +use derive_more::{AsRef, Deref, Display, From}; use diesel::prelude::*; +use macros::{IdFromParam, UuidFromParam}; use serde_json::Value; use uuid::Uuid; @@ -14,7 +18,6 @@ use crate::{ }; use super::{OrganizationId, User, UserId}; -use id::SendId; #[derive(Identifiable, Queryable, Insertable, AsChangeset)] #[diesel(table_name = sends)] @@ -335,47 +338,39 @@ impl Send { } } -// separate namespace to avoid name collision with std::marker::Send -pub mod id { - use derive_more::{AsRef, Deref, Display, From}; - use macros::{IdFromParam, UuidFromParam}; - use std::marker::Send; - use std::path::Path; - - #[derive( - Clone, - Debug, - AsRef, - Deref, - DieselNewType, - Display, - From, - FromForm, - Hash, - PartialEq, - Eq, - Serialize, - Deserialize, - UuidFromParam, - )] - pub struct SendId(String); - - impl AsRef for SendId { - #[inline] - fn as_ref(&self) -> &Path { - Path::new(&self.0) - } +#[derive( + Clone, + Debug, + AsRef, + Deref, + DieselNewType, + Display, + From, + FromForm, + Hash, + PartialEq, + Eq, + Serialize, + Deserialize, + UuidFromParam, +)] +pub struct SendId(String); + +impl AsRef for SendId { + #[inline] + fn as_ref(&self) -> &Path { + Path::new(&self.0) } +} - #[derive( - Clone, Debug, AsRef, Deref, Display, From, FromForm, Hash, PartialEq, Eq, Serialize, Deserialize, IdFromParam, - )] - pub struct SendFileId(String); +#[derive( + Clone, Debug, AsRef, Deref, Display, From, FromForm, Hash, PartialEq, Eq, Serialize, Deserialize, IdFromParam, +)] +pub struct SendFileId(String); - impl AsRef for SendFileId { - #[inline] - fn as_ref(&self) -> &Path { - Path::new(&self.0) - } +impl AsRef for SendFileId { + #[inline] + fn as_ref(&self) -> &Path { + Path::new(&self.0) } } From 4a9bcb069465e20e487c5e8cad6fdad8b2301a94 Mon Sep 17 00:00:00 2001 From: Timshel Date: Tue, 21 Jul 2026 17:59:40 +0000 Subject: [PATCH 12/15] Remove old compatibility code (#7434) Co-authored-by: Timshel --- src/db/models/cipher.rs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/db/models/cipher.rs b/src/db/models/cipher.rs index 8357c9eb..2fa6260a 100644 --- a/src/db/models/cipher.rs +++ b/src/db/models/cipher.rs @@ -306,16 +306,6 @@ impl Cipher { type_data_json = Value::Null; } - // Clone the type_data and add some default value. - let mut data_json = type_data_json.clone(); - - // NOTE: This was marked as *Backwards Compatibility Code*, but as of January 2021 this is still being used by upstream - // data_json should always contain the following keys with every atype - data_json["fields"] = json!(fields_json); - data_json["name"] = json!(self.name); - data_json["notes"] = json!(self.notes); - data_json["passwordHistory"] = Value::Array(password_history_json.clone()); - let collection_ids = if let Some(cipher_sync_data) = cipher_sync_data { if let Some(cipher_collections) = cipher_sync_data.cipher_collections.get(&self.uuid) { Cow::from(cipher_collections) @@ -355,8 +345,6 @@ impl Cipher { "notes": self.notes, "fields": fields_json, - "data": data_json, - "passwordHistory": password_history_json, // All Cipher types are included by default as null, but only the matching one will be populated From 683a23e43c5a440cab80300f47cb0d2639e616fa Mon Sep 17 00:00:00 2001 From: Daniel Date: Tue, 21 Jul 2026 22:54:10 +0300 Subject: [PATCH 13/15] Fix compilation with newer `rust-musl` version (#7453) --- docker/Dockerfile.alpine | 2 +- docker/Dockerfile.j2 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/Dockerfile.alpine b/docker/Dockerfile.alpine index 7bea0d0d..494411fb 100644 --- a/docker/Dockerfile.alpine +++ b/docker/Dockerfile.alpine @@ -66,7 +66,7 @@ RUN USER=root cargo new --bin /app WORKDIR /app # Environment variables for Cargo on Alpine based builds -RUN echo "export CARGO_TARGET=${RUST_MUSL_CROSS_TARGET}" >> /env-cargo && \ +RUN echo "export CARGO_TARGET=${CARGO_BUILD_TARGET}" >> /env-cargo && \ # Output the current contents of the file cat /env-cargo diff --git a/docker/Dockerfile.j2 b/docker/Dockerfile.j2 index f7a056ff..5e33d512 100644 --- a/docker/Dockerfile.j2 +++ b/docker/Dockerfile.j2 @@ -106,7 +106,7 @@ WORKDIR /app {% if base == "alpine" %} # Environment variables for Cargo on Alpine based builds -RUN echo "export CARGO_TARGET=${RUST_MUSL_CROSS_TARGET}" >> /env-cargo && \ +RUN echo "export CARGO_TARGET=${CARGO_BUILD_TARGET}" >> /env-cargo && \ # Output the current contents of the file cat /env-cargo From 660faee68e3406d33244b67eadc18524c47674c2 Mon Sep 17 00:00:00 2001 From: Tom <83423411+tom27052006@users.noreply.github.com> Date: Tue, 21 Jul 2026 22:06:45 +0200 Subject: [PATCH 14/15] Fix custom role dialog selectors (#7442) --- src/static/templates/scss/vaultwarden.scss.hbs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/static/templates/scss/vaultwarden.scss.hbs b/src/static/templates/scss/vaultwarden.scss.hbs index 477cdd34..5bbe5db2 100644 --- a/src/static/templates/scss/vaultwarden.scss.hbs +++ b/src/static/templates/scss/vaultwarden.scss.hbs @@ -116,8 +116,8 @@ app-security > app-two-factor-setup > form { } /* Hide unsupported Custom Role options */ -bit-dialog div.tw-ml-4:has(bit-form-control input), -bit-dialog div.tw-col-span-4:has(input[formcontrolname*="access"], input[formcontrolname*="manage"]) { +:is(bit-dialog, [bit-dialog]) div.tw-ml-4:has(bit-form-control input), +:is(bit-dialog, [bit-dialog]) div.tw-col-span-4:has(input[formcontrolname*="access"], input[formcontrolname*="manage"]) { @extend %vw-hide; } From 5040bcb7c0d23623cd7ed39f3aed6ec2bd5c2377 Mon Sep 17 00:00:00 2001 From: Timshel Date: Fri, 24 Jul 2026 14:40:34 +0000 Subject: [PATCH 15/15] Remove unused fields (#7458) Co-authored-by: Timshel --- src/api/core/accounts.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/api/core/accounts.rs b/src/api/core/accounts.rs index 623edf24..120c6a19 100644 --- a/src/api/core/accounts.rs +++ b/src/api/core/accounts.rs @@ -693,10 +693,6 @@ struct UnlockData { #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct ChangeKdfData { - #[allow(dead_code)] - new_master_password_hash: String, - #[allow(dead_code)] - key: String, authentication_data: AuthenticationData, unlock_data: UnlockData, master_password_hash: String,