mirror of
https://github.com/dani-garcia/vaultwarden.git
synced 2026-05-24 13:00:21 +03:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7cf0c5d67e | |||
| b04ed75f9f | |||
| 0ed8ab68f7 | |||
| dfebee57ec | |||
| bfe420a018 | |||
| e7e4b9a86d | |||
| bb549986e6 |
@@ -1,3 +1,2 @@
|
|||||||
# Ignore vendored scripts in GitHub stats
|
# Ignore vendored scripts in GitHub stats
|
||||||
src/static/scripts/* linguist-vendored
|
src/static/scripts/* linguist-vendored
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Run Trivy vulnerability scanner
|
- name: Run Trivy vulnerability scanner
|
||||||
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # v0.35.0
|
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
|
||||||
env:
|
env:
|
||||||
TRIVY_DB_REPOSITORY: docker.io/aquasec/trivy-db:2,public.ecr.aws/aquasecurity/trivy-db:2,ghcr.io/aquasecurity/trivy-db:2
|
TRIVY_DB_REPOSITORY: docker.io/aquasec/trivy-db:2,public.ecr.aws/aquasecurity/trivy-db:2,ghcr.io/aquasecurity/trivy-db:2
|
||||||
TRIVY_JAVA_DB_REPOSITORY: docker.io/aquasec/trivy-java-db:1,public.ecr.aws/aquasecurity/trivy-java-db:1,ghcr.io/aquasecurity/trivy-java-db:1
|
TRIVY_JAVA_DB_REPOSITORY: docker.io/aquasec/trivy-java-db:1,public.ecr.aws/aquasecurity/trivy-java-db:1,ghcr.io/aquasecurity/trivy-java-db:1
|
||||||
@@ -50,6 +50,6 @@ jobs:
|
|||||||
severity: CRITICAL,HIGH
|
severity: CRITICAL,HIGH
|
||||||
|
|
||||||
- name: Upload Trivy scan results to GitHub Security tab
|
- 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:
|
with:
|
||||||
sarif_file: 'trivy-results.sarif'
|
sarif_file: 'trivy-results.sarif'
|
||||||
|
|||||||
@@ -23,4 +23,4 @@ jobs:
|
|||||||
|
|
||||||
# When this version is updated, do not forget to update this in `.pre-commit-config.yaml` too
|
# When this version is updated, do not forget to update this in `.pre-commit-config.yaml` too
|
||||||
- name: Spell Check Repo
|
- name: Spell Check Repo
|
||||||
uses: crate-ci/typos@02ea592e44b3a53c302f697cddca7641cd051c3d # v1.45.0
|
uses: crate-ci/typos@cf5f1c29a8ac336af8568821ec41919923b05a83 # v1.45.1
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: Run zizmor
|
- name: Run zizmor
|
||||||
uses: zizmorcore/zizmor-action@71321a20a9ded102f6e9ce5718a2fcec2c4f70d8 # v0.5.2
|
uses: zizmorcore/zizmor-action@b1d7e1fb5de872772f31590499237e7cce841e8e # v0.5.3
|
||||||
with:
|
with:
|
||||||
# intentionally not scanning the entire repository,
|
# intentionally not scanning the entire repository,
|
||||||
# since it contains integration tests.
|
# since it contains integration tests.
|
||||||
|
|||||||
+55
-53
@@ -1,58 +1,60 @@
|
|||||||
---
|
---
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: 3e8a8703264a2f4a69428a0aa4dcb512790b2c8c # v6.0.0
|
rev: 3e8a8703264a2f4a69428a0aa4dcb512790b2c8c # v6.0.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: check-yaml
|
- id: check-yaml
|
||||||
- id: check-json
|
- id: check-json
|
||||||
- id: check-toml
|
- id: check-toml
|
||||||
- id: mixed-line-ending
|
- id: mixed-line-ending
|
||||||
args: ["--fix=no"]
|
args: [ "--fix=no" ]
|
||||||
- id: end-of-file-fixer
|
- id: end-of-file-fixer
|
||||||
exclude: "(.*js$|.*css$)"
|
exclude: "(.*js$|.*css$)"
|
||||||
- id: check-case-conflict
|
- id: check-case-conflict
|
||||||
- id: check-merge-conflict
|
- id: check-merge-conflict
|
||||||
- id: detect-private-key
|
- id: detect-private-key
|
||||||
- id: check-symlinks
|
- id: check-symlinks
|
||||||
- id: forbid-submodules
|
- id: forbid-submodules
|
||||||
- repo: local
|
|
||||||
|
# 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:
|
hooks:
|
||||||
- id: fmt
|
- id: typos
|
||||||
name: fmt
|
|
||||||
description: Format files with cargo fmt.
|
- repo: local
|
||||||
entry: cargo fmt
|
hooks:
|
||||||
language: system
|
- id: fmt
|
||||||
always_run: true
|
name: fmt
|
||||||
pass_filenames: false
|
description: Format files with cargo fmt.
|
||||||
args: ["--", "--check"]
|
entry: cargo fmt
|
||||||
- id: cargo-test
|
language: system
|
||||||
name: cargo test
|
always_run: true
|
||||||
description: Test the package for errors.
|
pass_filenames: false
|
||||||
entry: cargo test
|
args: [ "--", "--check" ]
|
||||||
language: system
|
- id: cargo-test
|
||||||
args: ["--features", "sqlite,mysql,postgresql", "--"]
|
name: cargo test
|
||||||
types_or: [rust, file]
|
description: Test the package for errors.
|
||||||
files: (Cargo.toml|Cargo.lock|rust-toolchain.toml|rustfmt.toml|.*\.rs$)
|
entry: cargo test
|
||||||
pass_filenames: false
|
language: system
|
||||||
- id: cargo-clippy
|
args: [ "--features", "sqlite,mysql,postgresql", "--" ]
|
||||||
name: cargo clippy
|
types_or: [ rust, file ]
|
||||||
description: Lint Rust sources
|
files: (Cargo.toml|Cargo.lock|rust-toolchain.toml|rustfmt.toml|.*\.rs$)
|
||||||
entry: cargo clippy
|
pass_filenames: false
|
||||||
language: system
|
- id: cargo-clippy
|
||||||
args: ["--features", "sqlite,mysql,postgresql", "--", "-D", "warnings"]
|
name: cargo clippy
|
||||||
types_or: [rust, file]
|
description: Lint Rust sources
|
||||||
files: (Cargo.toml|Cargo.lock|rust-toolchain.toml|rustfmt.toml|.*\.rs$)
|
entry: cargo clippy
|
||||||
pass_filenames: false
|
language: system
|
||||||
- id: check-docker-templates
|
args: [ "--features", "sqlite,mysql,postgresql", "--", "-D", "warnings" ]
|
||||||
name: check docker templates
|
types_or: [ rust, file ]
|
||||||
description: Check if the Docker templates are updated
|
files: (Cargo.toml|Cargo.lock|rust-toolchain.toml|rustfmt.toml|.*\.rs$)
|
||||||
language: system
|
pass_filenames: false
|
||||||
entry: sh
|
- id: check-docker-templates
|
||||||
args:
|
name: check docker templates
|
||||||
- "-c"
|
description: Check if the Docker templates are updated
|
||||||
- "cd docker && make"
|
language: system
|
||||||
# When this version is updated, do not forget to update this in `.github/workflows/typos.yaml` too
|
entry: sh
|
||||||
- repo: https://github.com/crate-ci/typos
|
args:
|
||||||
rev: 02ea592e44b3a53c302f697cddca7641cd051c3d # v1.45.0
|
- "-c"
|
||||||
hooks:
|
- "cd docker && make"
|
||||||
- id: typos
|
|
||||||
|
|||||||
Generated
+356
-153
File diff suppressed because it is too large
Load Diff
+8
-8
@@ -1,6 +1,6 @@
|
|||||||
[workspace.package]
|
[workspace.package]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = "1.92.0"
|
rust-version = "1.93.0"
|
||||||
license = "AGPL-3.0-only"
|
license = "AGPL-3.0-only"
|
||||||
repository = "https://github.com/dani-garcia/vaultwarden"
|
repository = "https://github.com/dani-garcia/vaultwarden"
|
||||||
publish = false
|
publish = false
|
||||||
@@ -79,7 +79,7 @@ dashmap = "6.1.0"
|
|||||||
|
|
||||||
# Async futures
|
# Async futures
|
||||||
futures = "0.3.32"
|
futures = "0.3.32"
|
||||||
tokio = { version = "1.51.1", 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"]}
|
tokio-util = { version = "0.7.18", features = ["compat"]}
|
||||||
|
|
||||||
# A generic serialization/deserialization framework
|
# A generic serialization/deserialization framework
|
||||||
@@ -103,7 +103,7 @@ ring = "0.17.14"
|
|||||||
subtle = "2.6.1"
|
subtle = "2.6.1"
|
||||||
|
|
||||||
# UUID generation
|
# UUID generation
|
||||||
uuid = { version = "1.23.0", features = ["v4"] }
|
uuid = { version = "1.23.1", features = ["v4"] }
|
||||||
|
|
||||||
# Date and time libraries
|
# Date and time libraries
|
||||||
chrono = { version = "0.4.44", features = ["clock", "serde"], default-features = false }
|
chrono = { version = "0.4.44", features = ["clock", "serde"], default-features = false }
|
||||||
@@ -145,7 +145,7 @@ handlebars = { version = "6.4.0", features = ["dir_source"] }
|
|||||||
|
|
||||||
# HTTP client (Used for favicons, version check, DUO and HIBP API)
|
# 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}
|
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
|
# Favicon extraction libraries
|
||||||
html5gum = "0.8.3"
|
html5gum = "0.8.3"
|
||||||
@@ -162,7 +162,7 @@ cookie = "0.18.1"
|
|||||||
cookie_store = "0.22.1"
|
cookie_store = "0.22.1"
|
||||||
|
|
||||||
# Used by U2F, JWT and PostgreSQL
|
# Used by U2F, JWT and PostgreSQL
|
||||||
openssl = "0.10.76"
|
openssl = "0.10.78"
|
||||||
|
|
||||||
# CLI argument parsing
|
# CLI argument parsing
|
||||||
pico-args = "0.5.0"
|
pico-args = "0.5.0"
|
||||||
@@ -180,7 +180,7 @@ semver = "1.0.28"
|
|||||||
|
|
||||||
# Allow overriding the default memory allocator
|
# Allow overriding the default memory allocator
|
||||||
# Mainly used for the musl builds, since the default musl malloc is very slow
|
# Mainly used for the musl builds, since the default musl malloc is very slow
|
||||||
mimalloc = { version = "0.1.48", features = ["secure"], default-features = false, optional = true }
|
mimalloc = { version = "0.1.50", features = ["secure"], default-features = false, optional = true }
|
||||||
|
|
||||||
which = "8.0.2"
|
which = "8.0.2"
|
||||||
|
|
||||||
@@ -198,9 +198,9 @@ opendal = { version = "0.55.0", features = ["services-fs"], default-features = f
|
|||||||
|
|
||||||
# For retrieving AWS credentials, including temporary SSO credentials
|
# For retrieving AWS credentials, including temporary SSO credentials
|
||||||
anyhow = { version = "1.0.102", optional = true }
|
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-config = { version = "1.8.16", features = ["behavior-version-latest", "rt-tokio", "credentials-process", "sso"], default-features = false, optional = true }
|
||||||
aws-credential-types = { version = "1.2.14", 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 }
|
http = { version = "1.4.0", optional = true }
|
||||||
reqsign = { version = "0.16.5", optional = true }
|
reqsign = { version = "0.16.5", optional = true }
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -2,4 +2,4 @@
|
|||||||
# see diesel.rs/guides/configuring-diesel-cli
|
# see diesel.rs/guides/configuring-diesel-cli
|
||||||
|
|
||||||
[print_schema]
|
[print_schema]
|
||||||
file = "src/db/schema.rs"
|
file = "src/db/schema.rs"
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
---
|
---
|
||||||
vault_version: "v2026.2.0"
|
vault_version: "v2026.3.1"
|
||||||
vault_image_digest: "sha256:37c8661fa59dcdfbd3baa8366b6e950ef292b15adfeff1f57812b075c1fd3447"
|
vault_image_digest: "sha256:c1b1f212333f95bff4ef8d00e8e3589c4ae8eda018691f28f8bddc7e971dd767"
|
||||||
# Cross Compile Docker Helper Scripts v1.9.0
|
# 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
|
# We use the linux/amd64 platform shell scripts since there is no difference between the different platform scripts
|
||||||
# https://github.com/tonistiigi/xx | https://hub.docker.com/r/tonistiigi/xx/tags
|
# https://github.com/tonistiigi/xx | https://hub.docker.com/r/tonistiigi/xx/tags
|
||||||
xx_image_digest: "sha256:c64defb9ed5a91eacb37f96ccc3d4cd72521c4bd18d5442905b95e2226b0e707"
|
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
|
debian_version: trixie # Debian release name to be used
|
||||||
alpine_version: "3.23" # Alpine version to be used
|
alpine_version: "3.23" # Alpine version to be used
|
||||||
# For which platforms/architectures will we try to build images
|
# For which platforms/architectures will we try to build images
|
||||||
|
|||||||
+10
-10
@@ -19,23 +19,23 @@
|
|||||||
# - From https://hub.docker.com/r/vaultwarden/web-vault/tags,
|
# - From https://hub.docker.com/r/vaultwarden/web-vault/tags,
|
||||||
# click the tag name to view the digest of the image it currently points to.
|
# click the tag name to view the digest of the image it currently points to.
|
||||||
# - From the command line:
|
# - From the command line:
|
||||||
# $ docker pull docker.io/vaultwarden/web-vault:v2026.2.0
|
# $ docker pull docker.io/vaultwarden/web-vault:v2026.3.1
|
||||||
# $ docker image inspect --format "{{.RepoDigests}}" docker.io/vaultwarden/web-vault:v2026.2.0
|
# $ docker image inspect --format "{{.RepoDigests}}" docker.io/vaultwarden/web-vault:v2026.3.1
|
||||||
# [docker.io/vaultwarden/web-vault@sha256:37c8661fa59dcdfbd3baa8366b6e950ef292b15adfeff1f57812b075c1fd3447]
|
# [docker.io/vaultwarden/web-vault@sha256:c1b1f212333f95bff4ef8d00e8e3589c4ae8eda018691f28f8bddc7e971dd767]
|
||||||
#
|
#
|
||||||
# - Conversely, to get the tag name from the digest:
|
# - Conversely, to get the tag name from the digest:
|
||||||
# $ docker image inspect --format "{{.RepoTags}}" docker.io/vaultwarden/web-vault@sha256:37c8661fa59dcdfbd3baa8366b6e950ef292b15adfeff1f57812b075c1fd3447
|
# $ docker image inspect --format "{{.RepoTags}}" docker.io/vaultwarden/web-vault@sha256:c1b1f212333f95bff4ef8d00e8e3589c4ae8eda018691f28f8bddc7e971dd767
|
||||||
# [docker.io/vaultwarden/web-vault:v2026.2.0]
|
# [docker.io/vaultwarden/web-vault:v2026.3.1]
|
||||||
#
|
#
|
||||||
FROM --platform=linux/amd64 docker.io/vaultwarden/web-vault@sha256:37c8661fa59dcdfbd3baa8366b6e950ef292b15adfeff1f57812b075c1fd3447 AS vault
|
FROM --platform=linux/amd64 docker.io/vaultwarden/web-vault@sha256:c1b1f212333f95bff4ef8d00e8e3589c4ae8eda018691f28f8bddc7e971dd767 AS vault
|
||||||
|
|
||||||
########################## ALPINE BUILD IMAGES ##########################
|
########################## ALPINE BUILD IMAGES ##########################
|
||||||
## NOTE: The Alpine Base Images do not support other platforms then linux/amd64 and linux/arm64
|
## 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
|
## 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:x86_64-musl-stable-1.95.0 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:aarch64-musl-stable-1.95.0 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:armv7-musleabihf-stable-1.95.0 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:arm-musleabi-stable-1.95.0 AS build_armv6
|
||||||
|
|
||||||
########################## BUILD IMAGE ##########################
|
########################## BUILD IMAGE ##########################
|
||||||
# hadolint ignore=DL3006
|
# hadolint ignore=DL3006
|
||||||
|
|||||||
@@ -19,15 +19,15 @@
|
|||||||
# - From https://hub.docker.com/r/vaultwarden/web-vault/tags,
|
# - From https://hub.docker.com/r/vaultwarden/web-vault/tags,
|
||||||
# click the tag name to view the digest of the image it currently points to.
|
# click the tag name to view the digest of the image it currently points to.
|
||||||
# - From the command line:
|
# - From the command line:
|
||||||
# $ docker pull docker.io/vaultwarden/web-vault:v2026.2.0
|
# $ docker pull docker.io/vaultwarden/web-vault:v2026.3.1
|
||||||
# $ docker image inspect --format "{{.RepoDigests}}" docker.io/vaultwarden/web-vault:v2026.2.0
|
# $ docker image inspect --format "{{.RepoDigests}}" docker.io/vaultwarden/web-vault:v2026.3.1
|
||||||
# [docker.io/vaultwarden/web-vault@sha256:37c8661fa59dcdfbd3baa8366b6e950ef292b15adfeff1f57812b075c1fd3447]
|
# [docker.io/vaultwarden/web-vault@sha256:c1b1f212333f95bff4ef8d00e8e3589c4ae8eda018691f28f8bddc7e971dd767]
|
||||||
#
|
#
|
||||||
# - Conversely, to get the tag name from the digest:
|
# - Conversely, to get the tag name from the digest:
|
||||||
# $ docker image inspect --format "{{.RepoTags}}" docker.io/vaultwarden/web-vault@sha256:37c8661fa59dcdfbd3baa8366b6e950ef292b15adfeff1f57812b075c1fd3447
|
# $ docker image inspect --format "{{.RepoTags}}" docker.io/vaultwarden/web-vault@sha256:c1b1f212333f95bff4ef8d00e8e3589c4ae8eda018691f28f8bddc7e971dd767
|
||||||
# [docker.io/vaultwarden/web-vault:v2026.2.0]
|
# [docker.io/vaultwarden/web-vault:v2026.3.1]
|
||||||
#
|
#
|
||||||
FROM --platform=linux/amd64 docker.io/vaultwarden/web-vault@sha256:37c8661fa59dcdfbd3baa8366b6e950ef292b15adfeff1f57812b075c1fd3447 AS vault
|
FROM --platform=linux/amd64 docker.io/vaultwarden/web-vault@sha256:c1b1f212333f95bff4ef8d00e8e3589c4ae8eda018691f28f8bddc7e971dd767 AS vault
|
||||||
|
|
||||||
########################## Cross Compile Docker Helper Scripts ##########################
|
########################## Cross Compile Docker Helper Scripts ##########################
|
||||||
## We use the linux/amd64 no matter which Build Platform, since these are all bash scripts
|
## We use the linux/amd64 no matter which Build Platform, since these are all bash scripts
|
||||||
@@ -36,7 +36,7 @@ FROM --platform=linux/amd64 docker.io/tonistiigi/xx@sha256:c64defb9ed5a91eacb37f
|
|||||||
|
|
||||||
########################## BUILD IMAGE ##########################
|
########################## BUILD IMAGE ##########################
|
||||||
# hadolint ignore=DL3006
|
# 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 / /
|
COPY --from=xx / /
|
||||||
ARG TARGETARCH
|
ARG TARGETARCH
|
||||||
ARG TARGETVARIANT
|
ARG TARGETVARIANT
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
[toolchain]
|
[toolchain]
|
||||||
channel = "1.94.1"
|
channel = "1.95.0"
|
||||||
components = [ "rustfmt", "clippy" ]
|
components = [ "rustfmt", "clippy" ]
|
||||||
profile = "minimal"
|
profile = "minimal"
|
||||||
|
|||||||
+11
-2
@@ -30,6 +30,7 @@ use crate::{
|
|||||||
error::{Error, MapResult},
|
error::{Error, MapResult},
|
||||||
http_client::make_http_request,
|
http_client::make_http_request,
|
||||||
mail,
|
mail,
|
||||||
|
sso::FAKE_SSO_IDENTIFIER,
|
||||||
util::{
|
util::{
|
||||||
container_base_image, format_naive_datetime_local, get_active_web_release, get_display_size,
|
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,
|
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 {
|
async fn _generate_invite(user: &User, conn: &DbConn) -> EmptyResult {
|
||||||
if CONFIG.mail_enabled() {
|
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();
|
let member_id: MembershipId = FAKE_ADMIN_UUID.to_string().into();
|
||||||
mail::send_invite(user, org_id, member_id, &CONFIG.invitation_org_name(), None).await
|
mail::send_invite(user, org_id, member_id, &CONFIG.invitation_org_name(), None).await
|
||||||
} else {
|
} else {
|
||||||
@@ -518,7 +523,11 @@ async fn resend_user_invite(user_id: UserId, _token: AdminToken, conn: DbConn) -
|
|||||||
}
|
}
|
||||||
|
|
||||||
if CONFIG.mail_enabled() {
|
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();
|
let member_id: MembershipId = FAKE_ADMIN_UUID.to_string().into();
|
||||||
mail::send_invite(&user, org_id, member_id, &CONFIG.invitation_org_name(), None).await
|
mail::send_invite(&user, org_id, member_id, &CONFIG.invitation_org_name(), None).await
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -374,7 +374,7 @@ async fn post_set_password(data: Json<SetPasswordData>, headers: Headers, conn:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(identifier) = data.org_identifier {
|
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 {
|
let Some(org) = Organization::find_by_uuid(&identifier.into(), &conn).await else {
|
||||||
err!("Failed to retrieve the associated organization")
|
err!("Failed to retrieve the associated organization")
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -20,7 +20,8 @@ use crate::{
|
|||||||
DbConn,
|
DbConn,
|
||||||
},
|
},
|
||||||
mail,
|
mail,
|
||||||
util::{convert_json_key_lcase_first, get_uuid, NumberOrString},
|
sso::FAKE_SSO_IDENTIFIER,
|
||||||
|
util::{convert_json_key_lcase_first, NumberOrString},
|
||||||
CONFIG,
|
CONFIG,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -64,6 +65,7 @@ pub fn routes() -> Vec<Route> {
|
|||||||
post_org_import,
|
post_org_import,
|
||||||
list_policies,
|
list_policies,
|
||||||
list_policies_token,
|
list_policies_token,
|
||||||
|
get_dummy_master_password_policy,
|
||||||
get_master_password_policy,
|
get_master_password_policy,
|
||||||
get_policy,
|
get_policy,
|
||||||
put_policy,
|
put_policy,
|
||||||
@@ -99,6 +101,7 @@ pub fn routes() -> Vec<Route> {
|
|||||||
get_billing_metadata,
|
get_billing_metadata,
|
||||||
get_billing_warnings,
|
get_billing_warnings,
|
||||||
get_auto_enroll_status,
|
get_auto_enroll_status,
|
||||||
|
get_self_host_billing_metadata,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -353,7 +356,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
|
// The returned `Id` will then be passed to `get_master_password_policy` which will mainly ignore it
|
||||||
#[get("/organizations/<identifier>/auto-enroll-status")]
|
#[get("/organizations/<identifier>/auto-enroll-status")]
|
||||||
async fn get_auto_enroll_status(identifier: &str, headers: Headers, conn: DbConn) -> JsonResult {
|
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 {
|
match Membership::find_main_user_org(&headers.user.uuid, &conn).await {
|
||||||
Some(member) => Organization::find_by_uuid(&member.org_uuid, &conn).await,
|
Some(member) => Organization::find_by_uuid(&member.org_uuid, &conn).await,
|
||||||
None => None,
|
None => None,
|
||||||
@@ -363,7 +366,7 @@ async fn get_auto_enroll_status(identifier: &str, headers: Headers, conn: DbConn
|
|||||||
};
|
};
|
||||||
|
|
||||||
let (id, identifier, rp_auto_enroll) = match org {
|
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) => (
|
Some(org) => (
|
||||||
org.uuid.to_string(),
|
org.uuid.to_string(),
|
||||||
org.uuid.to_string(),
|
org.uuid.to_string(),
|
||||||
@@ -924,7 +927,7 @@ async fn get_org_domain_sso_verified(data: Json<OrgDomainDetails>, conn: DbConn)
|
|||||||
.collect::<Vec<(String, String)>>()
|
.collect::<Vec<(String, String)>>()
|
||||||
{
|
{
|
||||||
v if !v.is_empty() => v,
|
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!({
|
Ok(Json(json!({
|
||||||
@@ -1975,9 +1978,19 @@ async fn list_policies_token(org_id: OrganizationId, token: &str, conn: DbConn)
|
|||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called during the SSO enrollment.
|
// Called during the SSO enrollment return the default policy
|
||||||
// Return the org policy if it exists, otherwise use the default one.
|
#[get("/organizations/vaultwarden-dummy-oidc-identifier/policies/master-password", rank = 1)]
|
||||||
#[get("/organizations/<org_id>/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 {
|
async fn get_master_password_policy(org_id: OrganizationId, _headers: OrgMemberHeaders, conn: DbConn) -> JsonResult {
|
||||||
let policy =
|
let policy =
|
||||||
OrgPolicy::find_by_org_and_type(&org_id, OrgPolicyType::MasterPassword, &conn).await.unwrap_or_else(|| {
|
OrgPolicy::find_by_org_and_type(&org_id, OrgPolicyType::MasterPassword, &conn).await.unwrap_or_else(|| {
|
||||||
@@ -1992,7 +2005,7 @@ async fn get_master_password_policy(org_id: OrganizationId, _headers: OrgMemberH
|
|||||||
Ok(Json(policy.to_json()))
|
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 {
|
async fn get_policy(org_id: OrganizationId, pol_type: i32, headers: AdminHeaders, conn: DbConn) -> JsonResult {
|
||||||
if org_id != headers.org_id {
|
if org_id != headers.org_id {
|
||||||
err!("Organization not found", "Organization id's do not match");
|
err!("Organization not found", "Organization id's do not match");
|
||||||
@@ -2201,6 +2214,15 @@ fn get_billing_warnings(_org_id: OrganizationId, _headers: OrgMemberHeaders) ->
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[get("/organizations/<_org_id>/billing/vnext/self-host/metadata")]
|
||||||
|
fn get_self_host_billing_metadata(_org_id: OrganizationId, _headers: OrgMemberHeaders) -> Json<Value> {
|
||||||
|
// Prevent a 404 error, which also causes Javascript errors.
|
||||||
|
Json(json!({
|
||||||
|
"isOnSecretsManagerStandalone": false, // Secrets Manager is not supported by Vaultwarden
|
||||||
|
"organizationOccupiedSeats": 0 // Vaultwarden does not count seats
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
fn _empty_data_json() -> Value {
|
fn _empty_data_json() -> Value {
|
||||||
json!({
|
json!({
|
||||||
"object": "list",
|
"object": "list",
|
||||||
|
|||||||
+16
-9
@@ -2,7 +2,6 @@ use chrono::Utc;
|
|||||||
use num_traits::FromPrimitive;
|
use num_traits::FromPrimitive;
|
||||||
use rocket::{
|
use rocket::{
|
||||||
form::{Form, FromForm},
|
form::{Form, FromForm},
|
||||||
http::Status,
|
|
||||||
response::Redirect,
|
response::Redirect,
|
||||||
serde::json::Json,
|
serde::json::Json,
|
||||||
Route,
|
Route,
|
||||||
@@ -12,7 +11,7 @@ use serde_json::Value;
|
|||||||
use crate::{
|
use crate::{
|
||||||
api::{
|
api::{
|
||||||
core::{
|
core::{
|
||||||
accounts::{PreloginData, RegisterData, _prelogin, _register, kdf_upgrade},
|
accounts::{_prelogin, _register, kdf_upgrade, PreloginData, RegisterData},
|
||||||
log_user_event,
|
log_user_event,
|
||||||
two_factor::{
|
two_factor::{
|
||||||
authenticator, duo, duo_oidc, email, enforce_2fa_policy, is_twofactor_provider_usable, webauthn,
|
authenticator, duo, duo_oidc, email, enforce_2fa_policy, is_twofactor_provider_usable, webauthn,
|
||||||
@@ -131,12 +130,14 @@ async fn login(
|
|||||||
login_result
|
login_result
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return Status::Unauthorized to trigger logout
|
|
||||||
async fn _refresh_login(data: ConnectData, conn: &DbConn, ip: &ClientIp) -> JsonResult {
|
async fn _refresh_login(data: ConnectData, conn: &DbConn, ip: &ClientIp) -> JsonResult {
|
||||||
// Extract token
|
// When a refresh token is invalid or missing we need to respond with an HTTP BadRequest (400)
|
||||||
let refresh_token = match data.refresh_token {
|
// It also needs to return a json which holds at least a key `error` with the value `invalid_grant`
|
||||||
Some(token) => token,
|
// See the link below for details
|
||||||
None => err_code!("Missing refresh_token", Status::Unauthorized.code),
|
// 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")
|
||||||
};
|
};
|
||||||
|
|
||||||
// ---
|
// ---
|
||||||
@@ -147,7 +148,10 @@ async fn _refresh_login(data: ConnectData, conn: &DbConn, ip: &ClientIp) -> Json
|
|||||||
// let members = Membership::find_confirmed_by_user(&user.uuid, conn).await;
|
// let members = Membership::find_confirmed_by_user(&user.uuid, conn).await;
|
||||||
match auth::refresh_tokens(ip, &refresh_token, data.client_id, conn).await {
|
match auth::refresh_tokens(ip, &refresh_token, data.client_id, conn).await {
|
||||||
Err(err) => {
|
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)) => {
|
Ok((mut device, auth_tokens)) => {
|
||||||
// Save to update `device.updated_at` to track usage and toggle new status
|
// Save to update `device.updated_at` to track usage and toggle new status
|
||||||
@@ -754,7 +758,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
|
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!(
|
err_json!(
|
||||||
_json_err_twofactor(&twofactor_ids, &user.uuid, data, client_version, conn).await?,
|
_json_err_twofactor(&twofactor_ids, &user.uuid, data, client_version, conn).await?,
|
||||||
"Invalid two factor provider"
|
"Invalid two factor provider"
|
||||||
|
|||||||
+24
-21
@@ -6,7 +6,7 @@ use std::{
|
|||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
use hickory_resolver::{name_server::TokioConnectionProvider, TokioResolver};
|
use hickory_resolver::{net::runtime::TokioRuntimeProvider, TokioResolver};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use reqwest::{
|
use reqwest::{
|
||||||
dns::{Name, Resolve, Resolving},
|
dns::{Name, Resolve, Resolving},
|
||||||
@@ -184,35 +184,35 @@ impl CustomDnsResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn new() -> Arc<Self> {
|
fn new() -> Arc<Self> {
|
||||||
match TokioResolver::builder(TokioConnectionProvider::default()) {
|
TokioResolver::builder(TokioRuntimeProvider::default())
|
||||||
Ok(mut builder) => {
|
.and_then(|mut builder| {
|
||||||
if CONFIG.dns_prefer_ipv6() {
|
// Hickory's default since v0.26 is `Ipv6AndIpv4`, which sorts IPv6 first
|
||||||
builder.options_mut().ip_strategy = hickory_resolver::config::LookupIpStrategy::Ipv6thenIpv4;
|
// 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();
|
builder.build()
|
||||||
Arc::new(Self::Hickory(Arc::new(resolver)))
|
})
|
||||||
}
|
.inspect_err(|e| warn!("Error creating Hickory resolver, falling back to default: {e:?}"))
|
||||||
Err(e) => {
|
.map(|resolver| Arc::new(Self::Hickory(Arc::new(resolver))))
|
||||||
warn!("Error creating Hickory resolver, falling back to default: {e:?}");
|
.unwrap_or_else(|_| Arc::new(Self::Default()))
|
||||||
Arc::new(Self::Default())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note that we get an iterator of addresses, but we only grab the first one for convenience
|
// 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)?;
|
pre_resolve(name)?;
|
||||||
|
|
||||||
let result = match self {
|
let results: Vec<SocketAddr> = match self {
|
||||||
Self::Default() => tokio::net::lookup_host(name).await?.next(),
|
Self::Default() => tokio::net::lookup_host((name, 0)).await?.collect(),
|
||||||
Self::Hickory(r) => r.lookup_ip(name).await?.iter().next().map(|a| SocketAddr::new(a, 0)),
|
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())?;
|
post_resolve(name, addr.ip())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(result)
|
Ok(results)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,8 +242,11 @@ impl Resolve for CustomDnsResolver {
|
|||||||
let this = self.clone();
|
let this = self.clone();
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let name = name.as_str();
|
let name = name.as_str();
|
||||||
let result = this.resolve_domain(name).await?;
|
let results = this.resolve_domain(name).await?;
|
||||||
Ok::<reqwest::dns::Addrs, _>(Box::new(result.into_iter()))
|
if results.is_empty() {
|
||||||
|
warn!("Unable to resolve {name} to any valid IP address");
|
||||||
|
}
|
||||||
|
Ok::<reqwest::dns::Addrs, _>(Box::new(results.into_iter()))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -17,7 +17,7 @@ use crate::{
|
|||||||
CONFIG,
|
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()));
|
static SSO_JWT_ISSUER: LazyLock<String> = LazyLock::new(|| format!("{}|sso", CONFIG.domain_origin()));
|
||||||
|
|
||||||
|
|||||||
@@ -137,6 +137,14 @@ bit-nav-logo bit-nav-item .bwi-shield {
|
|||||||
app-user-layout app-danger-zone button:nth-child(1) {
|
app-user-layout app-danger-zone button:nth-child(1) {
|
||||||
@extend %vw-hide;
|
@extend %vw-hide;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Hide unsupported Forwarding email alias options */
|
||||||
|
ng-dropdown-panel div.ng-dropdown-panel-items div:has(> [title="Firefox Relay"]) {
|
||||||
|
@extend %vw-hide;
|
||||||
|
}
|
||||||
|
ng-dropdown-panel div.ng-dropdown-panel-items div:has(> [title="DuckDuckGo"]) {
|
||||||
|
@extend %vw-hide;
|
||||||
|
}
|
||||||
/**** END Static Vaultwarden Changes ****/
|
/**** END Static Vaultwarden Changes ****/
|
||||||
/**** START Dynamic Vaultwarden Changes ****/
|
/**** START Dynamic Vaultwarden Changes ****/
|
||||||
{{#if signup_disabled}}
|
{{#if signup_disabled}}
|
||||||
|
|||||||
Reference in New Issue
Block a user