mirror of
https://github.com/dani-garcia/vaultwarden.git
synced 2026-05-08 12:34:43 +02:00
Merge branch 'main' into feature/prometheus-metrics
This commit is contained in:
commit
2a1ef5f9a9
19 changed files with 477 additions and 315 deletions
1
.gitattributes
vendored
1
.gitattributes
vendored
|
|
@ -1,3 +1,2 @@
|
|||
# Ignore vendored scripts in GitHub stats
|
||||
src/static/scripts/* linguist-vendored
|
||||
|
||||
|
|
|
|||
18
.github/workflows/release.yml
vendored
18
.github/workflows/release.yml
vendored
|
|
@ -106,7 +106,7 @@ jobs:
|
|||
|
||||
# Login to Docker Hub
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
|
||||
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.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@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
|
||||
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.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@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
|
||||
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.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@82490499d2e5613fcead7e128237ef0b0ea210f7 # v7.0.0
|
||||
uses: docker/bake-action@a66e1c87e2eca0503c343edf1d208c716d54b8a8 # v7.1.0
|
||||
env:
|
||||
BASE_TAGS: "${{ steps.determine-version.outputs.BASE_TAGS }}"
|
||||
SOURCE_COMMIT: "${{ env.SOURCE_COMMIT }}"
|
||||
|
|
@ -222,7 +222,7 @@ jobs:
|
|||
touch "${RUNNER_TEMP}/digests/${digest#sha256:}"
|
||||
|
||||
- name: Upload digest
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: digests-${{ env.NORMALIZED_ARCH }}-${{ matrix.base_image }}
|
||||
path: ${{ runner.temp }}/digests/*
|
||||
|
|
@ -242,7 +242,7 @@ jobs:
|
|||
subject-path: vaultwarden-${{ env.NORMALIZED_ARCH }}
|
||||
|
||||
- name: Upload binaries as artifacts
|
||||
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: vaultwarden-${{ env.SOURCE_VERSION }}-linux-${{ env.NORMALIZED_ARCH }}-${{ matrix.base_image }}
|
||||
path: vaultwarden-${{ env.NORMALIZED_ARCH }}
|
||||
|
|
@ -272,7 +272,7 @@ jobs:
|
|||
|
||||
# Login to Docker Hub
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
|
||||
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.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@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
|
||||
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.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@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
|
||||
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
||||
with:
|
||||
registry: quay.io
|
||||
username: ${{ secrets.QUAY_USERNAME }}
|
||||
|
|
|
|||
2
.github/workflows/trivy.yml
vendored
2
.github/workflows/trivy.yml
vendored
|
|
@ -50,6 +50,6 @@ jobs:
|
|||
severity: CRITICAL,HIGH
|
||||
|
||||
- name: Upload Trivy scan results to GitHub Security tab
|
||||
uses: github/codeql-action/upload-sarif@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1
|
||||
uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
|
||||
with:
|
||||
sarif_file: 'trivy-results.sarif'
|
||||
|
|
|
|||
2
.github/workflows/typos.yml
vendored
2
.github/workflows/typos.yml
vendored
|
|
@ -23,4 +23,4 @@ jobs:
|
|||
|
||||
# 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@631208b7aac2daa8b707f55e7331f9112b0e062d # v1.44.0
|
||||
uses: crate-ci/typos@cf5f1c29a8ac336af8568821ec41919923b05a83 # v1.45.1
|
||||
|
|
|
|||
2
.github/workflows/zizmor.yml
vendored
2
.github/workflows/zizmor.yml
vendored
|
|
@ -24,7 +24,7 @@ jobs:
|
|||
persist-credentials: false
|
||||
|
||||
- name: Run zizmor
|
||||
uses: zizmorcore/zizmor-action@71321a20a9ded102f6e9ce5718a2fcec2c4f70d8 # v0.5.2
|
||||
uses: zizmorcore/zizmor-action@b1d7e1fb5de872772f31590499237e7cce841e8e # v0.5.3
|
||||
with:
|
||||
# intentionally not scanning the entire repository,
|
||||
# since it contains integration tests.
|
||||
|
|
|
|||
|
|
@ -1,58 +1,60 @@
|
|||
---
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: 3e8a8703264a2f4a69428a0aa4dcb512790b2c8c # v6.0.0
|
||||
hooks:
|
||||
- id: check-yaml
|
||||
- id: check-json
|
||||
- id: check-toml
|
||||
- id: mixed-line-ending
|
||||
args: ["--fix=no"]
|
||||
- id: end-of-file-fixer
|
||||
exclude: "(.*js$|.*css$)"
|
||||
- id: check-case-conflict
|
||||
- id: check-merge-conflict
|
||||
- id: detect-private-key
|
||||
- id: check-symlinks
|
||||
- id: forbid-submodules
|
||||
- repo: local
|
||||
- id: check-yaml
|
||||
- id: check-json
|
||||
- id: check-toml
|
||||
- id: mixed-line-ending
|
||||
args: [ "--fix=no" ]
|
||||
- id: end-of-file-fixer
|
||||
exclude: "(.*js$|.*css$)"
|
||||
- id: check-case-conflict
|
||||
- id: check-merge-conflict
|
||||
- id: detect-private-key
|
||||
- id: check-symlinks
|
||||
- id: forbid-submodules
|
||||
|
||||
# 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: cf5f1c29a8ac336af8568821ec41919923b05a83 # v1.45.1
|
||||
hooks:
|
||||
- id: fmt
|
||||
name: fmt
|
||||
description: Format files with cargo fmt.
|
||||
entry: cargo fmt
|
||||
language: system
|
||||
always_run: true
|
||||
pass_filenames: false
|
||||
args: ["--", "--check"]
|
||||
- id: cargo-test
|
||||
name: cargo test
|
||||
description: Test the package for errors.
|
||||
entry: cargo test
|
||||
language: system
|
||||
args: ["--features", "sqlite,mysql,postgresql", "--"]
|
||||
types_or: [rust, file]
|
||||
files: (Cargo.toml|Cargo.lock|rust-toolchain.toml|rustfmt.toml|.*\.rs$)
|
||||
pass_filenames: false
|
||||
- id: cargo-clippy
|
||||
name: cargo clippy
|
||||
description: Lint Rust sources
|
||||
entry: cargo clippy
|
||||
language: system
|
||||
args: ["--features", "sqlite,mysql,postgresql", "--", "-D", "warnings"]
|
||||
types_or: [rust, file]
|
||||
files: (Cargo.toml|Cargo.lock|rust-toolchain.toml|rustfmt.toml|.*\.rs$)
|
||||
pass_filenames: false
|
||||
- id: check-docker-templates
|
||||
name: check docker templates
|
||||
description: Check if the Docker templates are updated
|
||||
language: system
|
||||
entry: sh
|
||||
args:
|
||||
- "-c"
|
||||
- "cd docker && make"
|
||||
# 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: 631208b7aac2daa8b707f55e7331f9112b0e062d # v1.44.0
|
||||
hooks:
|
||||
- id: typos
|
||||
- id: typos
|
||||
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: fmt
|
||||
name: fmt
|
||||
description: Format files with cargo fmt.
|
||||
entry: cargo fmt
|
||||
language: system
|
||||
always_run: true
|
||||
pass_filenames: false
|
||||
args: [ "--", "--check" ]
|
||||
- id: cargo-test
|
||||
name: cargo test
|
||||
description: Test the package for errors.
|
||||
entry: cargo test
|
||||
language: system
|
||||
args: [ "--features", "sqlite,mysql,postgresql", "--" ]
|
||||
types_or: [ rust, file ]
|
||||
files: (Cargo.toml|Cargo.lock|rust-toolchain.toml|rustfmt.toml|.*\.rs$)
|
||||
pass_filenames: false
|
||||
- id: cargo-clippy
|
||||
name: cargo clippy
|
||||
description: Lint Rust sources
|
||||
entry: cargo clippy
|
||||
language: system
|
||||
args: [ "--features", "sqlite,mysql,postgresql", "--", "-D", "warnings" ]
|
||||
types_or: [ rust, file ]
|
||||
files: (Cargo.toml|Cargo.lock|rust-toolchain.toml|rustfmt.toml|.*\.rs$)
|
||||
pass_filenames: false
|
||||
- id: check-docker-templates
|
||||
name: check docker templates
|
||||
description: Check if the Docker templates are updated
|
||||
language: system
|
||||
entry: sh
|
||||
args:
|
||||
- "-c"
|
||||
- "cd docker && make"
|
||||
|
|
|
|||
508
Cargo.lock
generated
508
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
18
Cargo.toml
18
Cargo.toml
|
|
@ -1,6 +1,6 @@
|
|||
[workspace.package]
|
||||
edition = "2021"
|
||||
rust-version = "1.92.0"
|
||||
rust-version = "1.93.0"
|
||||
license = "AGPL-3.0-only"
|
||||
repository = "https://github.com/dani-garcia/vaultwarden"
|
||||
publish = false
|
||||
|
|
@ -84,7 +84,7 @@ once_cell = "1.20.2"
|
|||
|
||||
# Async futures
|
||||
futures = "0.3.32"
|
||||
tokio = { version = "1.50.0", features = ["rt-multi-thread", "fs", "io-util", "parking_lot", "time", "signal", "net"] }
|
||||
tokio = { version = "1.52.1", features = ["rt-multi-thread", "fs", "io-util", "parking_lot", "time", "signal", "net"] }
|
||||
tokio-util = { version = "0.7.18", features = ["compat"]}
|
||||
|
||||
# A generic serialization/deserialization framework
|
||||
|
|
@ -103,12 +103,12 @@ diesel-derive-newtype = "2.1.2"
|
|||
libsqlite3-sys = { version = "0.36.0", features = ["bundled"], optional = true }
|
||||
|
||||
# Crypto-related libraries
|
||||
rand = "0.10.0"
|
||||
rand = "0.10.1"
|
||||
ring = "0.17.14"
|
||||
subtle = "2.6.1"
|
||||
|
||||
# UUID generation
|
||||
uuid = { version = "1.23.0", features = ["v4"] }
|
||||
uuid = { version = "1.23.1", features = ["v4"] }
|
||||
|
||||
# Date and time libraries
|
||||
chrono = { version = "0.4.44", features = ["clock", "serde"], default-features = false }
|
||||
|
|
@ -141,7 +141,7 @@ webauthn-rs-core = "0.5.4"
|
|||
url = "2.5.8"
|
||||
|
||||
# Email libraries
|
||||
lettre = { version = "0.11.20", features = ["smtp-transport", "sendmail-transport", "builder", "serde", "hostname", "tracing", "tokio1-rustls", "ring", "rustls-native-certs"], default-features = false }
|
||||
lettre = { version = "0.11.21", features = ["smtp-transport", "sendmail-transport", "builder", "serde", "hostname", "tracing", "tokio1-rustls", "ring", "rustls-native-certs"], default-features = false }
|
||||
percent-encoding = "2.3.2" # URL encoding library used for URL's in the emails
|
||||
email_address = "0.2.9"
|
||||
|
||||
|
|
@ -150,7 +150,7 @@ handlebars = { version = "6.4.0", features = ["dir_source"] }
|
|||
|
||||
# HTTP client (Used for favicons, version check, DUO and HIBP API)
|
||||
reqwest = { version = "0.12.28", features = ["rustls-tls", "rustls-tls-native-roots", "stream", "json", "deflate", "gzip", "brotli", "zstd", "socks", "cookies", "charset", "http2", "system-proxy"], default-features = false}
|
||||
hickory-resolver = "0.25.2"
|
||||
hickory-resolver = "0.26.0"
|
||||
|
||||
# Favicon extraction libraries
|
||||
html5gum = "0.8.3"
|
||||
|
|
@ -167,7 +167,7 @@ cookie = "0.18.1"
|
|||
cookie_store = "0.22.1"
|
||||
|
||||
# Used by U2F, JWT and PostgreSQL
|
||||
openssl = "0.10.76"
|
||||
openssl = "0.10.77"
|
||||
|
||||
# CLI argument parsing
|
||||
pico-args = "0.5.0"
|
||||
|
|
@ -181,7 +181,7 @@ openidconnect = { version = "4.0.1", features = ["reqwest", "rustls-tls"] }
|
|||
moka = { version = "0.12.15", features = ["future"] }
|
||||
|
||||
# Check client versions for specific features.
|
||||
semver = "1.0.27"
|
||||
semver = "1.0.28"
|
||||
|
||||
# Allow overriding the default memory allocator
|
||||
# Mainly used for the musl builds, since the default musl malloc is very slow
|
||||
|
|
@ -208,7 +208,7 @@ opendal = { version = "0.55.0", features = ["services-fs"], default-features = f
|
|||
anyhow = { version = "1.0.102", optional = true }
|
||||
aws-config = { version = "1.8.15", features = ["behavior-version-latest", "rt-tokio", "credentials-process", "sso"], default-features = false, optional = true }
|
||||
aws-credential-types = { version = "1.2.14", optional = true }
|
||||
aws-smithy-runtime-api = { version = "1.11.6", optional = true }
|
||||
aws-smithy-runtime-api = { version = "1.12.0", optional = true }
|
||||
http = { version = "1.4.0", optional = true }
|
||||
reqsign = { version = "0.16.5", optional = true }
|
||||
|
||||
|
|
|
|||
|
|
@ -2,4 +2,4 @@
|
|||
# see diesel.rs/guides/configuring-diesel-cli
|
||||
|
||||
[print_schema]
|
||||
file = "src/db/schema.rs"
|
||||
file = "src/db/schema.rs"
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ vault_image_digest: "sha256:37c8661fa59dcdfbd3baa8366b6e950ef292b15adfeff1f57812
|
|||
# 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.94.1 # Rust version to be used
|
||||
rust_version: 1.95.0 # Rust version to be used
|
||||
debian_version: trixie # Debian release name to be used
|
||||
alpine_version: "3.23" # Alpine version to be used
|
||||
# For which platforms/architectures will we try to build images
|
||||
|
|
|
|||
|
|
@ -32,10 +32,10 @@ FROM --platform=linux/amd64 docker.io/vaultwarden/web-vault@sha256:37c8661fa59dc
|
|||
########################## 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.94.1 AS build_amd64
|
||||
FROM --platform=$BUILDPLATFORM ghcr.io/blackdex/rust-musl:aarch64-musl-stable-1.94.1 AS build_arm64
|
||||
FROM --platform=$BUILDPLATFORM ghcr.io/blackdex/rust-musl:armv7-musleabihf-stable-1.94.1 AS build_armv7
|
||||
FROM --platform=$BUILDPLATFORM ghcr.io/blackdex/rust-musl:arm-musleabi-stable-1.94.1 AS build_armv6
|
||||
FROM --platform=$BUILDPLATFORM ghcr.io/blackdex/rust-musl:x86_64-musl-stable-1.95.0 AS build_amd64
|
||||
FROM --platform=$BUILDPLATFORM ghcr.io/blackdex/rust-musl:aarch64-musl-stable-1.95.0 AS build_arm64
|
||||
FROM --platform=$BUILDPLATFORM ghcr.io/blackdex/rust-musl:armv7-musleabihf-stable-1.95.0 AS build_armv7
|
||||
FROM --platform=$BUILDPLATFORM ghcr.io/blackdex/rust-musl:arm-musleabi-stable-1.95.0 AS build_armv6
|
||||
|
||||
########################## BUILD IMAGE ##########################
|
||||
# hadolint ignore=DL3006
|
||||
|
|
|
|||
|
|
@ -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.94.1-slim-trixie AS build
|
||||
FROM --platform=$BUILDPLATFORM docker.io/library/rust:1.95.0-slim-trixie AS build
|
||||
COPY --from=xx / /
|
||||
ARG TARGETARCH
|
||||
ARG TARGETVARIANT
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
[toolchain]
|
||||
channel = "1.94.1"
|
||||
channel = "1.95.0"
|
||||
components = [ "rustfmt", "clippy" ]
|
||||
profile = "minimal"
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ use crate::{
|
|||
error::{Error, MapResult},
|
||||
http_client::make_http_request,
|
||||
mail,
|
||||
sso::FAKE_SSO_IDENTIFIER,
|
||||
util::{
|
||||
container_base_image, format_naive_datetime_local, get_active_web_release, get_display_size,
|
||||
is_running_in_container, parse_experimental_client_feature_flags, FeatureFlagFilter, NumberOrString,
|
||||
|
|
@ -315,7 +316,11 @@ async fn invite_user(data: Json<InviteData>, _token: AdminToken, conn: DbConn) -
|
|||
|
||||
async fn _generate_invite(user: &User, conn: &DbConn) -> EmptyResult {
|
||||
if CONFIG.mail_enabled() {
|
||||
let org_id: OrganizationId = FAKE_ADMIN_UUID.to_string().into();
|
||||
let org_id: OrganizationId = if CONFIG.sso_enabled() {
|
||||
FAKE_SSO_IDENTIFIER.into()
|
||||
} else {
|
||||
FAKE_ADMIN_UUID.into()
|
||||
};
|
||||
let member_id: MembershipId = FAKE_ADMIN_UUID.to_string().into();
|
||||
mail::send_invite(user, org_id, member_id, &CONFIG.invitation_org_name(), None).await
|
||||
} else {
|
||||
|
|
@ -518,7 +523,11 @@ async fn resend_user_invite(user_id: UserId, _token: AdminToken, conn: DbConn) -
|
|||
}
|
||||
|
||||
if CONFIG.mail_enabled() {
|
||||
let org_id: OrganizationId = FAKE_ADMIN_UUID.to_string().into();
|
||||
let org_id: OrganizationId = if CONFIG.sso_enabled() {
|
||||
FAKE_SSO_IDENTIFIER.into()
|
||||
} else {
|
||||
FAKE_ADMIN_UUID.into()
|
||||
};
|
||||
let member_id: MembershipId = FAKE_ADMIN_UUID.to_string().into();
|
||||
mail::send_invite(&user, org_id, member_id, &CONFIG.invitation_org_name(), None).await
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -374,7 +374,7 @@ async fn post_set_password(data: Json<SetPasswordData>, headers: Headers, conn:
|
|||
}
|
||||
|
||||
if let Some(identifier) = data.org_identifier {
|
||||
if identifier != crate::sso::FAKE_IDENTIFIER && identifier != crate::api::admin::FAKE_ADMIN_UUID {
|
||||
if identifier != crate::sso::FAKE_SSO_IDENTIFIER && identifier != crate::api::admin::FAKE_ADMIN_UUID {
|
||||
let Some(org) = Organization::find_by_uuid(&identifier.into(), &conn).await else {
|
||||
err!("Failed to retrieve the associated organization")
|
||||
};
|
||||
|
|
|
|||
|
|
@ -20,7 +20,8 @@ use crate::{
|
|||
DbConn,
|
||||
},
|
||||
mail,
|
||||
util::{convert_json_key_lcase_first, get_uuid, NumberOrString},
|
||||
sso::FAKE_SSO_IDENTIFIER,
|
||||
util::{convert_json_key_lcase_first, NumberOrString},
|
||||
CONFIG,
|
||||
};
|
||||
|
||||
|
|
@ -64,6 +65,7 @@ pub fn routes() -> Vec<Route> {
|
|||
post_org_import,
|
||||
list_policies,
|
||||
list_policies_token,
|
||||
get_dummy_master_password_policy,
|
||||
get_master_password_policy,
|
||||
get_policy,
|
||||
put_policy,
|
||||
|
|
@ -353,7 +355,7 @@ async fn get_user_collections(headers: Headers, conn: DbConn) -> Json<Value> {
|
|||
// The returned `Id` will then be passed to `get_master_password_policy` which will mainly ignore it
|
||||
#[get("/organizations/<identifier>/auto-enroll-status")]
|
||||
async fn get_auto_enroll_status(identifier: &str, headers: Headers, conn: DbConn) -> JsonResult {
|
||||
let org = if identifier == crate::sso::FAKE_IDENTIFIER {
|
||||
let org = if identifier == FAKE_SSO_IDENTIFIER {
|
||||
match Membership::find_main_user_org(&headers.user.uuid, &conn).await {
|
||||
Some(member) => Organization::find_by_uuid(&member.org_uuid, &conn).await,
|
||||
None => None,
|
||||
|
|
@ -363,7 +365,7 @@ async fn get_auto_enroll_status(identifier: &str, headers: Headers, conn: DbConn
|
|||
};
|
||||
|
||||
let (id, identifier, rp_auto_enroll) = match org {
|
||||
None => (get_uuid(), identifier.to_string(), false),
|
||||
None => (identifier.to_string(), identifier.to_string(), false),
|
||||
Some(org) => (
|
||||
org.uuid.to_string(),
|
||||
org.uuid.to_string(),
|
||||
|
|
@ -924,7 +926,7 @@ async fn get_org_domain_sso_verified(data: Json<OrgDomainDetails>, conn: DbConn)
|
|||
.collect::<Vec<(String, String)>>()
|
||||
{
|
||||
v if !v.is_empty() => v,
|
||||
_ => vec![(crate::sso::FAKE_IDENTIFIER.to_string(), crate::sso::FAKE_IDENTIFIER.to_string())],
|
||||
_ => vec![(FAKE_SSO_IDENTIFIER.to_string(), FAKE_SSO_IDENTIFIER.to_string())],
|
||||
};
|
||||
|
||||
Ok(Json(json!({
|
||||
|
|
@ -1905,7 +1907,7 @@ async fn post_bulk_collections(data: Json<BulkCollectionsData>, headers: Headers
|
|||
})
|
||||
.collect();
|
||||
|
||||
// Verify if all the collections requested exists and are writeable for the user, else abort
|
||||
// Verify if all the collections requested exists and are writable for the user, else abort
|
||||
for collection_uuid in &data.collection_ids {
|
||||
match user_collections.get(collection_uuid) {
|
||||
Some(collection) if collection.is_writable_by_user(&headers.user.uuid, &conn).await => (),
|
||||
|
|
@ -1975,9 +1977,19 @@ async fn list_policies_token(org_id: OrganizationId, token: &str, conn: DbConn)
|
|||
})))
|
||||
}
|
||||
|
||||
// Called during the SSO enrollment.
|
||||
// Return the org policy if it exists, otherwise use the default one.
|
||||
#[get("/organizations/<org_id>/policies/master-password", rank = 1)]
|
||||
// Called during the SSO enrollment return the default policy
|
||||
#[get("/organizations/vaultwarden-dummy-oidc-identifier/policies/master-password", rank = 1)]
|
||||
fn get_dummy_master_password_policy() -> JsonResult {
|
||||
let (enabled, data) = match CONFIG.sso_master_password_policy_value() {
|
||||
Some(policy) if CONFIG.sso_enabled() => (true, policy.to_string()),
|
||||
_ => (false, "null".to_string()),
|
||||
};
|
||||
let policy = OrgPolicy::new(FAKE_SSO_IDENTIFIER.into(), OrgPolicyType::MasterPassword, enabled, data);
|
||||
Ok(Json(policy.to_json()))
|
||||
}
|
||||
|
||||
// Called during the SSO enrollment return the org policy if it exists
|
||||
#[get("/organizations/<org_id>/policies/master-password", rank = 2)]
|
||||
async fn get_master_password_policy(org_id: OrganizationId, _headers: OrgMemberHeaders, conn: DbConn) -> JsonResult {
|
||||
let policy =
|
||||
OrgPolicy::find_by_org_and_type(&org_id, OrgPolicyType::MasterPassword, &conn).await.unwrap_or_else(|| {
|
||||
|
|
@ -1992,7 +2004,7 @@ async fn get_master_password_policy(org_id: OrganizationId, _headers: OrgMemberH
|
|||
Ok(Json(policy.to_json()))
|
||||
}
|
||||
|
||||
#[get("/organizations/<org_id>/policies/<pol_type>", rank = 2)]
|
||||
#[get("/organizations/<org_id>/policies/<pol_type>", rank = 3)]
|
||||
async fn get_policy(org_id: OrganizationId, pol_type: i32, headers: AdminHeaders, conn: DbConn) -> JsonResult {
|
||||
if org_id != headers.org_id {
|
||||
err!("Organization not found", "Organization id's do not match");
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ use chrono::Utc;
|
|||
use num_traits::FromPrimitive;
|
||||
use rocket::{
|
||||
form::{Form, FromForm},
|
||||
http::Status,
|
||||
response::Redirect,
|
||||
serde::json::Json,
|
||||
Route,
|
||||
|
|
@ -12,7 +11,7 @@ use serde_json::Value;
|
|||
use crate::{
|
||||
api::{
|
||||
core::{
|
||||
accounts::{PreloginData, RegisterData, _prelogin, _register, kdf_upgrade},
|
||||
accounts::{_prelogin, _register, kdf_upgrade, PreloginData, RegisterData},
|
||||
log_user_event,
|
||||
two_factor::{
|
||||
authenticator, duo, duo_oidc, email, enforce_2fa_policy, is_twofactor_provider_usable, webauthn,
|
||||
|
|
@ -140,12 +139,14 @@ async fn login(
|
|||
login_result
|
||||
}
|
||||
|
||||
// Return Status::Unauthorized to trigger logout
|
||||
async fn _refresh_login(data: ConnectData, conn: &DbConn, ip: &ClientIp) -> JsonResult {
|
||||
// Extract token
|
||||
let refresh_token = match data.refresh_token {
|
||||
Some(token) => token,
|
||||
None => err_code!("Missing refresh_token", Status::Unauthorized.code),
|
||||
// When a refresh token is invalid or missing we need to respond with an HTTP BadRequest (400)
|
||||
// It also needs to return a json which holds at least a key `error` with the value `invalid_grant`
|
||||
// See the link below for details
|
||||
// https://github.com/bitwarden/clients/blob/2ee158e720a5e7dbe3641caf80b569e97a1dd91b/libs/common/src/services/api.service.ts#L1786-L1797
|
||||
|
||||
let Some(refresh_token) = data.refresh_token else {
|
||||
err_json!(json!({"error": "invalid_grant"}), "Missing refresh_token")
|
||||
};
|
||||
|
||||
// ---
|
||||
|
|
@ -156,7 +157,10 @@ async fn _refresh_login(data: ConnectData, conn: &DbConn, ip: &ClientIp) -> Json
|
|||
// let members = Membership::find_confirmed_by_user(&user.uuid, conn).await;
|
||||
match auth::refresh_tokens(ip, &refresh_token, data.client_id, conn).await {
|
||||
Err(err) => {
|
||||
err_code!(format!("Unable to refresh login credentials: {}", err.message()), Status::Unauthorized.code)
|
||||
err_json!(
|
||||
json!({"error": "invalid_grant"}),
|
||||
format!("Unable to refresh login credentials: {}", err.message())
|
||||
)
|
||||
}
|
||||
Ok((mut device, auth_tokens)) => {
|
||||
// Save to update `device.updated_at` to track usage and toggle new status
|
||||
|
|
@ -763,7 +767,10 @@ async fn twofactor_auth(
|
|||
}
|
||||
|
||||
let selected_id = data.two_factor_provider.unwrap_or(twofactor_ids[0]); // If we aren't given a two factor provider, assume the first one
|
||||
if !twofactor_ids.contains(&selected_id) {
|
||||
// Ignore Remember and RecoveryCode Types during this check, these are special
|
||||
if ![TwoFactorType::Remember as i32, TwoFactorType::RecoveryCode as i32].contains(&selected_id)
|
||||
&& !twofactor_ids.contains(&selected_id)
|
||||
{
|
||||
err_json!(
|
||||
_json_err_twofactor(&twofactor_ids, &user.uuid, data, client_version, conn).await?,
|
||||
"Invalid two factor provider"
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use std::{
|
|||
time::Duration,
|
||||
};
|
||||
|
||||
use hickory_resolver::{name_server::TokioConnectionProvider, TokioResolver};
|
||||
use hickory_resolver::{net::runtime::TokioRuntimeProvider, TokioResolver};
|
||||
use regex::Regex;
|
||||
use reqwest::{
|
||||
dns::{Name, Resolve, Resolving},
|
||||
|
|
@ -184,35 +184,35 @@ impl CustomDnsResolver {
|
|||
}
|
||||
|
||||
fn new() -> Arc<Self> {
|
||||
match TokioResolver::builder(TokioConnectionProvider::default()) {
|
||||
Ok(mut builder) => {
|
||||
if CONFIG.dns_prefer_ipv6() {
|
||||
builder.options_mut().ip_strategy = hickory_resolver::config::LookupIpStrategy::Ipv6thenIpv4;
|
||||
TokioResolver::builder(TokioRuntimeProvider::default())
|
||||
.and_then(|mut builder| {
|
||||
// Hickory's default since v0.26 is `Ipv6AndIpv4`, which sorts IPv6 first
|
||||
// This might cause issues on IPv4 only systems or containers
|
||||
// Unless someone enabled DNS_PREFER_IPV6, use Ipv4AndIpv6, which returns IPv4 first which was our previous default
|
||||
if !CONFIG.dns_prefer_ipv6() {
|
||||
builder.options_mut().ip_strategy = hickory_resolver::config::LookupIpStrategy::Ipv4AndIpv6;
|
||||
}
|
||||
let resolver = builder.build();
|
||||
Arc::new(Self::Hickory(Arc::new(resolver)))
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("Error creating Hickory resolver, falling back to default: {e:?}");
|
||||
Arc::new(Self::Default())
|
||||
}
|
||||
}
|
||||
builder.build()
|
||||
})
|
||||
.inspect_err(|e| warn!("Error creating Hickory resolver, falling back to default: {e:?}"))
|
||||
.map(|resolver| Arc::new(Self::Hickory(Arc::new(resolver))))
|
||||
.unwrap_or_else(|_| Arc::new(Self::Default()))
|
||||
}
|
||||
|
||||
// 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<Option<SocketAddr>, BoxError> {
|
||||
async fn resolve_domain(&self, name: &str) -> Result<Vec<SocketAddr>, BoxError> {
|
||||
pre_resolve(name)?;
|
||||
|
||||
let result = match self {
|
||||
Self::Default() => tokio::net::lookup_host(name).await?.next(),
|
||||
Self::Hickory(r) => r.lookup_ip(name).await?.iter().next().map(|a| SocketAddr::new(a, 0)),
|
||||
let results: Vec<SocketAddr> = 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(),
|
||||
};
|
||||
|
||||
if let Some(addr) = &result {
|
||||
for addr in &results {
|
||||
post_resolve(name, addr.ip())?;
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
Ok(results)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -242,8 +242,11 @@ impl Resolve for CustomDnsResolver {
|
|||
let this = self.clone();
|
||||
Box::pin(async move {
|
||||
let name = name.as_str();
|
||||
let result = this.resolve_domain(name).await?;
|
||||
Ok::<reqwest::dns::Addrs, _>(Box::new(result.into_iter()))
|
||||
let results = this.resolve_domain(name).await?;
|
||||
if results.is_empty() {
|
||||
warn!("Unable to resolve {name} to any valid IP address");
|
||||
}
|
||||
Ok::<reqwest::dns::Addrs, _>(Box::new(results.into_iter()))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ use crate::{
|
|||
CONFIG,
|
||||
};
|
||||
|
||||
pub static FAKE_IDENTIFIER: &str = "VW_DUMMY_IDENTIFIER_FOR_OIDC";
|
||||
pub static FAKE_SSO_IDENTIFIER: &str = "vaultwarden-dummy-oidc-identifier";
|
||||
|
||||
static SSO_JWT_ISSUER: LazyLock<String> = LazyLock::new(|| format!("{}|sso", CONFIG.domain_origin()));
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue