aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrkowalewski <[email protected]>2021-04-29 08:34:10 +0200
committerGitHub <[email protected]>2021-04-29 08:34:10 +0200
commit48482fece0683f3422191a374861d878b6554b85 (patch)
tree92e85ced72cc386a8813b705c3cc42fba980b6c8
parent1dc1d4df724a7159243f7558557ef2ba951dfbc5 (diff)
parent2b4dd6f137730abe48506affbe5c8f36a86772fb (diff)
downloadvaultwarden-48482fece0683f3422191a374861d878b6554b85.tar.gz
vaultwarden-48482fece0683f3422191a374861d878b6554b85.zip
Merge branch 'main' into fix-libressl-332
-rw-r--r--.dockerignore2
-rw-r--r--.editorconfig23
-rw-r--r--.env.template31
-rw-r--r--.gitattributes2
-rw-r--r--.github/ISSUE_TEMPLATE/bug_report.md14
-rw-r--r--.github/ISSUE_TEMPLATE/config.yml4
-rw-r--r--.github/workflows/build.yml33
-rw-r--r--.github/workflows/hadolint.yml3
-rw-r--r--Cargo.lock472
-rw-r--r--Cargo.toml19
-rw-r--r--README.md61
-rw-r--r--build.rs14
-rw-r--r--docker/Dockerfile.buildx2
-rw-r--r--docker/Dockerfile.j234
-rw-r--r--docker/amd64/Dockerfile21
-rw-r--r--docker/amd64/Dockerfile.alpine21
-rw-r--r--docker/arm64/Dockerfile21
-rw-r--r--docker/armv6/Dockerfile21
-rw-r--r--docker/armv7/Dockerfile21
-rw-r--r--docker/armv7/Dockerfile.alpine21
-rwxr-xr-xdocker/start.sh10
-rw-r--r--hooks/README.md2
-rwxr-xr-xhooks/build2
-rwxr-xr-xhooks/push2
-rw-r--r--rust-toolchain2
-rw-r--r--rustfmt.toml5
-rw-r--r--src/api/admin.rs88
-rw-r--r--src/api/core/accounts.rs12
-rw-r--r--src/api/core/ciphers.rs139
-rw-r--r--src/api/core/folders.rs10
-rw-r--r--src/api/core/mod.rs29
-rw-r--r--src/api/core/organizations.rs58
-rw-r--r--src/api/core/sends.rs47
-rw-r--r--src/api/core/two_factor/authenticator.rs25
-rw-r--r--src/api/core/two_factor/duo.rs19
-rw-r--r--src/api/core/two_factor/email.rs9
-rw-r--r--src/api/core/two_factor/mod.rs8
-rw-r--r--src/api/core/two_factor/u2f.rs24
-rw-r--r--src/api/icons.rs119
-rw-r--r--src/api/identity.rs53
-rw-r--r--src/api/mod.rs9
-rw-r--r--src/api/notifications.rs32
-rw-r--r--src/api/web.rs8
-rw-r--r--src/auth.rs33
-rw-r--r--src/config.rs49
-rw-r--r--src/crypto.rs4
-rw-r--r--src/db/mod.rs73
-rw-r--r--src/db/models/attachment.rs1
-rw-r--r--src/db/models/cipher.rs63
-rw-r--r--src/db/models/collection.rs31
-rw-r--r--src/db/models/favorite.rs24
-rw-r--r--src/db/models/folder.rs1
-rw-r--r--src/db/models/mod.rs4
-rw-r--r--src/db/models/org_policy.rs8
-rw-r--r--src/db/models/organization.rs31
-rw-r--r--src/db/models/send.rs22
-rw-r--r--src/db/models/user.rs12
-rw-r--r--src/error.rs10
-rw-r--r--src/mail.rs26
-rw-r--r--src/main.rs78
-rw-r--r--src/static/global_domains.json3
-rw-r--r--src/static/images/fallback-icon.pngbin0 -> 331 bytes
-rw-r--r--src/static/templates/admin/base.hbs4
-rw-r--r--src/static/templates/admin/diagnostics.hbs21
-rw-r--r--src/static/templates/admin/settings.hbs6
-rw-r--r--src/static/templates/email/change_email.hbs2
-rw-r--r--src/static/templates/email/change_email.html.hbs4
-rw-r--r--src/static/templates/email/delete_account.hbs2
-rw-r--r--src/static/templates/email/delete_account.html.hbs4
-rw-r--r--src/static/templates/email/invite_accepted.hbs4
-rw-r--r--src/static/templates/email/invite_accepted.html.hbs6
-rw-r--r--src/static/templates/email/invite_confirmed.hbs2
-rw-r--r--src/static/templates/email/invite_confirmed.html.hbs4
-rw-r--r--src/static/templates/email/new_device_logged_in.hbs2
-rw-r--r--src/static/templates/email/new_device_logged_in.html.hbs4
-rw-r--r--src/static/templates/email/pw_hint_none.hbs2
-rw-r--r--src/static/templates/email/pw_hint_none.html.hbs4
-rw-r--r--src/static/templates/email/pw_hint_some.hbs2
-rw-r--r--src/static/templates/email/pw_hint_some.html.hbs4
-rw-r--r--src/static/templates/email/send_org_invite.hbs2
-rw-r--r--src/static/templates/email/send_org_invite.html.hbs4
-rw-r--r--src/static/templates/email/smtp_test.hbs4
-rw-r--r--src/static/templates/email/smtp_test.html.hbs6
-rw-r--r--src/static/templates/email/twofactor_email.hbs2
-rw-r--r--src/static/templates/email/twofactor_email.html.hbs4
-rw-r--r--src/static/templates/email/verify_email.hbs2
-rw-r--r--src/static/templates/email/verify_email.html.hbs4
-rw-r--r--src/static/templates/email/welcome.hbs2
-rw-r--r--src/static/templates/email/welcome.html.hbs4
-rw-r--r--src/static/templates/email/welcome_must_verify.hbs2
-rw-r--r--src/static/templates/email/welcome_must_verify.html.hbs4
-rw-r--r--src/util.rs47
92 files changed, 1241 insertions, 948 deletions
diff --git a/.dockerignore b/.dockerignore
index b3e43a23..69f51d2a 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -4,6 +4,8 @@ target
# Data folder
data
.env
+.env.template
+.gitattributes
# IDE files
.vscode
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 00000000..27c2a5e3
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,23 @@
+# EditorConfig is awesome: https://EditorConfig.org
+
+# top-most EditorConfig file
+root = true
+
+[*]
+end_of_line = lf
+charset = utf-8
+
+[*.{rs,py}]
+indent_style = space
+indent_size = 4
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[*.{yml,yaml}]
+indent_style = space
+indent_size = 2
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[Makefile]
+indent_style = tab
diff --git a/.env.template b/.env.template
index 34e0e294..3af3a049 100644
--- a/.env.template
+++ b/.env.template
@@ -1,4 +1,4 @@
-## Bitwarden_RS Configuration File
+## Vaultwarden Configuration File
## Uncomment any of the following lines to change the defaults
##
## Be aware that most of these settings will be overridden if they were changed
@@ -36,9 +36,9 @@
## Automatically reload the templates for every request, slow, use only for development
# RELOAD_TEMPLATES=false
-## Client IP Header, used to identify the IP of the client, defaults to "X-Client-IP"
+## Client IP Header, used to identify the IP of the client, defaults to "X-Real-IP"
## Set to the string "none" (without quotes), to disable any headers and just use the remote IP
-# IP_HEADER=X-Client-IP
+# IP_HEADER=X-Real-IP
## Cache time-to-live for successfully obtained icons, in seconds (0 is "forever")
# ICON_CACHE_TTL=2592000
@@ -56,6 +56,23 @@
# WEBSOCKET_ADDRESS=0.0.0.0
# WEBSOCKET_PORT=3012
+## Job scheduler settings
+##
+## Job schedules use a cron-like syntax (as parsed by https://crates.io/crates/cron),
+## and are always in terms of UTC time (regardless of your local time zone settings).
+##
+## How often (in ms) the job scheduler thread checks for jobs that need running.
+## Set to 0 to globally disable scheduled jobs.
+# JOB_POLL_INTERVAL_MS=30000
+##
+## Cron schedule of the job that checks for Sends past their deletion date.
+## Defaults to hourly (5 minutes after the hour). Set blank to disable this job.
+# SEND_PURGE_SCHEDULE="0 5 * * * *"
+##
+## Cron schedule of the job that checks for trashed items to delete permanently.
+## Defaults to daily (5 minutes after midnight). Set blank to disable this job.
+# TRASH_PURGE_SCHEDULE="0 5 0 * * *"
+
## Enable extended logging, which shows timestamps and targets in the logs
# EXTENDED_LOGGING=true
@@ -82,7 +99,7 @@
## Enable WAL for the DB
## Set to false to avoid enabling WAL during startup.
## Note that if the DB already has WAL enabled, you will also need to disable WAL in the DB,
-## this setting only prevents bitwarden_rs from automatically enabling it on start.
+## this setting only prevents vaultwarden from automatically enabling it on start.
## Please read project wiki page about this setting first before changing the value as it can
## cause performance degradation or might render the service unable to start.
# ENABLE_DB_WAL=true
@@ -170,7 +187,7 @@
## Invitations org admins to invite users, even when signups are disabled
# INVITATIONS_ALLOWED=true
## Name shown in the invitation emails that don't come from a specific organization
-# INVITATION_ORG_NAME=Bitwarden_RS
+# INVITATION_ORG_NAME=Vaultwarden
## Per-organization attachment limit (KB)
## Limit in kilobytes for an organization attachments, once the limit is exceeded it won't be possible to upload more
@@ -242,8 +259,8 @@
## To make sure the email links are pointing to the correct host, set the DOMAIN variable.
## Note: if SMTP_USERNAME is specified, SMTP_PASSWORD is mandatory
# SMTP_HOST=smtp.domain.tld
-# SMTP_FROM_NAME=Bitwarden_RS
+# SMTP_FROM_NAME=Vaultwarden
# SMTP_PORT=587 # Ports 587 (submission) and 25 (smtp) are standard without encryption and with encryption via STARTTLS (Explicit TLS). Port 465 is outdated and used with Implicit TLS.
# SMTP_SSL=true # (Explicit) - This variable by default configures Explicit STARTTLS, it will upgrade an insecure connection to a secure one. Unless SMTP_EXPLICIT_TLS is set to true. Either port 587 or 25 are default.
# SMTP_EXPLICIT_TLS=true # (Implicit) - N.B. This variable configures Implicit TLS. It's currently mislabelled (see bug #851) - SMTP_SSL Needs to be set to true for this option to work. Usually port 465 is used here.
diff --git a/.gitattributes b/.gitattributes
index 20701478..b33a6211 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,3 +1,3 @@
# Ignore vendored scripts in GitHub stats
-src/static/* linguist-vendored
+src/static/scripts/* linguist-vendored
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index 8c79cf2d..128c5f58 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -1,6 +1,6 @@
---
name: Bug report
-about: Use this ONLY for bugs in bitwarden_rs itself. Use the Discourse forum (link below) to request features or get help with usage/configuration. If in doubt, use the forum.
+about: Use this ONLY for bugs in vaultwarden itself. Use the Discourse forum (link below) to request features or get help with usage/configuration. If in doubt, use the forum.
title: ''
labels: ''
assignees: ''
@@ -8,11 +8,11 @@ assignees: ''
---
<!--
# ###
- NOTE: Please update to the latest version of bitwarden_rs before reporting an issue!
+ NOTE: Please update to the latest version of vaultwarden before reporting an issue!
This saves you and us a lot of time and troubleshooting.
See:
- * https://github.com/dani-garcia/bitwarden_rs/issues/1180
- * https://github.com/dani-garcia/bitwarden_rs/wiki/Updating-the-bitwarden-image
+ * https://github.com/dani-garcia/vaultwarden/issues/1180
+ * https://github.com/dani-garcia/vaultwarden/wiki/Updating-the-vaultwarden-image
# ###
-->
@@ -37,9 +37,9 @@ such as passwords, IP addresses, and DNS names as appropriate.
-->
<!-- The version number, obtained from the logs (at startup) or the admin diagnostics page -->
-<!-- This is NOT the version number shown on the web vault, which is versioned separately from bitwarden_rs -->
+<!-- This is NOT the version number shown on the web vault, which is versioned separately from vaultwarden -->
<!-- Remember to check if your issue exists on the latest version first! -->
-* bitwarden_rs version:
+* vaultwarden version:
<!-- How the server was installed: Docker image, OS package, built from source, etc. -->
* Install method:
@@ -54,7 +54,7 @@ such as passwords, IP addresses, and DNS names as appropriate.
### Steps to reproduce
<!-- Tell us how to reproduce this issue. What parameters did you set (differently from the defaults)
-and how did you start bitwarden_rs? -->
+and how did you start vaultwarden? -->
### Expected behaviour
<!-- Tell us what you expected to happen -->
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index 072be117..7ecd420d 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -3,6 +3,6 @@ contact_links:
- name: Discourse forum for bitwarden_rs
url: https://bitwardenrs.discourse.group/
about: Use this forum to request features or get help with usage/configuration.
- - name: GitHub Discussions for bitwarden_rs
- url: https://github.com/dani-garcia/bitwarden_rs/discussions
+ - name: GitHub Discussions for vaultwarden
+ url: https://github.com/dani-garcia/vaultwarden/discussions
about: An alternative to the Discourse forum, if this is easier for you.
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 81151f17..bcb16381 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -2,23 +2,21 @@ name: Build
on:
push:
- # Ignore when there are only changes done too one of these paths
- paths-ignore:
- - "**.md"
- - "**.txt"
- - "azure-pipelines.yml"
- - "docker/**"
- - "hooks/**"
- - "tools/**"
pull_request:
# Ignore when there are only changes done too one of these paths
paths-ignore:
- "**.md"
- "**.txt"
+ - ".dockerignore"
+ - ".env.template"
+ - ".gitattributes"
+ - ".gitignore"
- "azure-pipelines.yml"
- "docker/**"
- "hooks/**"
- "tools/**"
+ - ".github/FUNDING.yml"
+ - ".github/ISSUE_TEMPLATE/**"
jobs:
build:
@@ -91,7 +89,7 @@ jobs:
with:
profile: minimal
target: ${{ matrix.target-triple }}
- components: clippy
+ components: clippy, rustfmt
# End Uses the rust-toolchain file to determine version
@@ -113,6 +111,15 @@ jobs:
# End Run cargo clippy
+ # Run cargo fmt
+ - name: '`cargo fmt`'
+ uses: actions-rs/cargo@v1
+ with:
+ command: fmt
+ args: --all -- --check
+ # End Run cargo fmt
+
+
# Build the binary
- name: '`cargo build --release --features ${{ matrix.features }} --target ${{ matrix.target-triple }}`'
uses: actions-rs/cargo@v1
@@ -126,8 +133,8 @@ jobs:
- name: Upload artifact
uses: actions/upload-artifact@v2
with:
- name: bitwarden_rs-${{ matrix.target-triple }}${{ matrix.ext }}
- path: target/${{ matrix.target-triple }}/release/bitwarden_rs${{ matrix.ext }}
+ name: vaultwarden-${{ matrix.target-triple }}${{ matrix.ext }}
+ path: target/${{ matrix.target-triple }}/release/vaultwarden${{ matrix.ext }}
# End Upload artifact to Github Actions
@@ -138,7 +145,7 @@ jobs:
# uses: Shopify/upload-to-release@1
# if: startsWith(github.ref, 'refs/tags/')
# with:
- # name: bitwarden_rs-${{ matrix.target-triple }}${{ matrix.ext }}
- # path: target/${{ matrix.target-triple }}/release/bitwarden_rs${{ matrix.ext }}
+ # name: vaultwarden-${{ matrix.target-triple }}${{ matrix.ext }}
+ # path: target/${{ matrix.target-triple }}/release/vaultwarden${{ matrix.ext }}
# repo-token: ${{ secrets.GITHUB_TOKEN }}
# End Upload to github actions release
diff --git a/.github/workflows/hadolint.yml b/.github/workflows/hadolint.yml
index 7b799554..f2cd9732 100644
--- a/.github/workflows/hadolint.yml
+++ b/.github/workflows/hadolint.yml
@@ -1,6 +1,7 @@
name: Hadolint
on:
+ push:
pull_request:
# Ignore when there are only changes done too one of these paths
paths:
@@ -24,7 +25,7 @@ jobs:
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: 1.19.0
+ HADOLINT_VERSION: 2.0.0
# End Download hadolint
# Test Dockerfiles
diff --git a/Cargo.lock b/Cargo.lock
index 2bcc26a5..952b7635 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -27,6 +27,35 @@ dependencies = [
]
[[package]]
+name = "alloc-no-stdlib"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5192ec435945d87bc2f70992b4d818154b5feede43c09fb7592146374eac90a6"
+
+[[package]]
+name = "alloc-stdlib"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "697ed7edc0f1711de49ce108c541623a0af97c6c60b2f6e2b65229847ac843c2"
+dependencies = [
+ "alloc-no-stdlib",
+]
+
+[[package]]
+name = "async-compression"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b72c1f1154e234325b50864a349b9c8e56939e266a4c307c0f159812df2f9537"
+dependencies = [
+ "brotli",
+ "flate2",
+ "futures-core",
+ "memchr",
+ "pin-project-lite",
+ "tokio",
+]
+
+[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -116,55 +145,6 @@ dependencies = [
]
[[package]]
-name = "bitwarden_rs"
-version = "1.0.0"
-dependencies = [
- "backtrace",
- "chashmap",
- "chrono",
- "chrono-tz",
- "data-encoding",
- "data-url",
- "diesel",
- "diesel_migrations",
- "dotenv",
- "fern",
- "handlebars",
- "html5ever",
- "idna 0.2.2",
- "jsonwebtoken",
- "lettre",
- "libsqlite3-sys",
- "log 0.4.14",
- "markup5ever_rcdom",
- "multipart",
- "newline-converter",
- "num-derive",
- "num-traits",
- "oath",
- "once_cell",
- "openssl",
- "parity-ws",
- "paste",
- "percent-encoding 2.1.0",
- "pico-args",
- "rand 0.8.3",
- "regex",
- "reqwest",
- "ring",
- "rmpv",
- "rocket",
- "rocket_contrib",
- "serde",
- "serde_json",
- "syslog",
- "time 0.2.26",
- "u2f",
- "uuid",
- "yubico",
-]
-
-[[package]]
name = "block-buffer"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -195,6 +175,27 @@ dependencies = [
]
[[package]]
+name = "brotli"
+version = "3.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f29919120f08613aadcd4383764e00526fc9f18b6c0895814faeed0dd78613e"
+dependencies = [
+ "alloc-no-stdlib",
+ "alloc-stdlib",
+ "brotli-decompressor",
+]
+
+[[package]]
+name = "brotli-decompressor"
+version = "2.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1052e1c3b8d4d80eb84a8b94f0a1498797b5fb96314c001156a1c761940ef4ec"
+dependencies = [
+ "alloc-no-stdlib",
+ "alloc-stdlib",
+]
+
+[[package]]
name = "buf_redux"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -298,9 +299,9 @@ dependencies = [
[[package]]
name = "const_fn"
-version = "0.4.5"
+version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28b9d6de7f49e22cf97ad17fc4036ece69300032f45f78f30b4a4482cdc3f4a6"
+checksum = "076a6803b0dacd6a88cfe64deba628b01533ff5ef265687e6938280c1afd0a28"
[[package]]
name = "constant_time_eq"
@@ -342,6 +343,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634"
[[package]]
+name = "crc32fast"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a"
+dependencies = [
+ "cfg-if 1.0.0",
+]
+
+[[package]]
+name = "cron"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e009ed0b762cf7a967a34dfdc67d5967d3f828f12901d37081432c3dd1668f8f"
+dependencies = [
+ "chrono",
+ "nom 4.1.1",
+ "once_cell",
+]
+
+[[package]]
name = "crypto-mac"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -399,9 +420,9 @@ version = "0.3.0"
source = "git+https://github.com/SergioBenitez/Devise.git?rev=e58b3ac9a#e58b3ac9afc3b6ff10a8aaf02a3e768a8f530089"
dependencies = [
"bitflags",
- "proc-macro2 1.0.24",
+ "proc-macro2 1.0.26",
"quote 1.0.9",
- "syn 1.0.64",
+ "syn 1.0.69",
]
[[package]]
@@ -427,9 +448,9 @@ version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45f5098f628d02a7a0f68ddba586fb61e80edec3bdc1be3b921f4ceec60858d3"
dependencies = [
- "proc-macro2 1.0.24",
+ "proc-macro2 1.0.26",
"quote 1.0.9",
- "syn 1.0.64",
+ "syn 1.0.69",
]
[[package]]
@@ -492,6 +513,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
[[package]]
+name = "either"
+version = "1.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
+
+[[package]]
name = "encoding_rs"
version = "0.8.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -526,6 +553,18 @@ dependencies = [
]
[[package]]
+name = "flate2"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd3aec53de10fe96d7d8c565eb17f2c687bb5518a2ec453b5b1252964526abe0"
+dependencies = [
+ "cfg-if 1.0.0",
+ "crc32fast",
+ "libc",
+ "miniz_oxide",
+]
+
+[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -596,9 +635,9 @@ dependencies = [
[[package]]
name = "futures"
-version = "0.3.13"
+version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f55667319111d593ba876406af7c409c0ebb44dc4be6132a783ccf163ea14c1"
+checksum = "a9d5813545e459ad3ca1bff9915e9ad7f1a47dc6a91b627ce321d5863b7dd253"
dependencies = [
"futures-channel",
"futures-core",
@@ -611,9 +650,9 @@ dependencies = [
[[package]]
name = "futures-channel"
-version = "0.3.13"
+version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c2dd2df839b57db9ab69c2c9d8f3e8c81984781937fe2807dc6dcf3b2ad2939"
+checksum = "ce79c6a52a299137a6013061e0cf0e688fce5d7f1bc60125f520912fdb29ec25"
dependencies = [
"futures-core",
"futures-sink",
@@ -621,15 +660,15 @@ dependencies = [
[[package]]
name = "futures-core"
-version = "0.3.13"
+version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "15496a72fabf0e62bdc3df11a59a3787429221dd0710ba8ef163d6f7a9112c94"
+checksum = "098cd1c6dda6ca01650f1a37a794245eb73181d0d4d4e955e2f3c37db7af1815"
[[package]]
name = "futures-executor"
-version = "0.3.13"
+version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "891a4b7b96d84d5940084b2a37632dd65deeae662c114ceaa2c879629c9c0ad1"
+checksum = "10f6cb7042eda00f0049b1d2080aa4b93442997ee507eb3828e8bd7577f94c9d"
dependencies = [
"futures-core",
"futures-task",
@@ -638,39 +677,39 @@ dependencies = [
[[package]]
name = "futures-io"
-version = "0.3.13"
+version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d71c2c65c57704c32f5241c1223167c2c3294fd34ac020c807ddbe6db287ba59"
+checksum = "365a1a1fb30ea1c03a830fdb2158f5236833ac81fa0ad12fe35b29cddc35cb04"
[[package]]
name = "futures-macro"
-version = "0.3.13"
+version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea405816a5139fb39af82c2beb921d52143f556038378d6db21183a5c37fbfb7"
+checksum = "668c6733a182cd7deb4f1de7ba3bf2120823835b3bcfbeacf7d2c4a773c1bb8b"
dependencies = [
"proc-macro-hack",
- "proc-macro2 1.0.24",
+ "proc-macro2 1.0.26",
"quote 1.0.9",
- "syn 1.0.64",
+ "syn 1.0.69",
]
[[package]]
name = "futures-sink"
-version = "0.3.13"
+version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85754d98985841b7d4f5e8e6fbfa4a4ac847916893ec511a2917ccd8525b8bb3"
+checksum = "5c5629433c555de3d82861a7a4e3794a4c40040390907cfbfd7143a92a426c23"
[[package]]
name = "futures-task"
-version = "0.3.13"
+version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa189ef211c15ee602667a6fcfe1c1fd9e07d42250d2156382820fba33c9df80"
+checksum = "ba7aa51095076f3ba6d9a1f702f74bd05ec65f555d70d2033d55ba8d69f581bc"
[[package]]
name = "futures-util"
-version = "0.3.13"
+version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1812c7ab8aedf8d6f2701a43e1243acdbcc2b36ab26e2ad421eb99ac963d96d1"
+checksum = "3c144ad54d60f23927f0a6b6d816e4271278b64f005ad65e4e35291d2de9c025"
dependencies = [
"futures-channel",
"futures-core",
@@ -770,9 +809,9 @@ dependencies = [
[[package]]
name = "handlebars"
-version = "3.5.3"
+version = "3.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cdb0867bbc5a3da37a753e78021d5fcf8a4db00e18dd2dd90fd36e24190e162d"
+checksum = "580b6f551b29a3a02436318aed09ba1c58eea177dc49e39beac627ad356730a5"
dependencies = [
"log 0.4.14",
"pest",
@@ -839,16 +878,16 @@ dependencies = [
"log 0.4.14",
"mac",
"markup5ever",
- "proc-macro2 1.0.24",
+ "proc-macro2 1.0.26",
"quote 1.0.9",
- "syn 1.0.64",
+ "syn 1.0.69",
]
[[package]]
name = "http"
-version = "0.2.3"
+version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7245cd7449cc792608c3c8a9eaf69bd4eabbabf802713748fd739c98b82f0747"
+checksum = "527e8c9ac747e28542699a951517aa9a6945af506cd1f2e1b53a576c17b6cc11"
dependencies = [
"bytes 1.0.1",
"fnv",
@@ -868,9 +907,9 @@ dependencies = [
[[package]]
name = "httparse"
-version = "1.3.5"
+version = "1.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "615caabe2c3160b313d52ccc905335f4ed5f10881dd63dc5699d47e90be85691"
+checksum = "bc35c995b9d93ec174cf9a27d425c7892722101e14993cd227fdb51d70cf9589"
[[package]]
name = "httpdate"
@@ -899,9 +938,9 @@ dependencies = [
[[package]]
name = "hyper"
-version = "0.14.4"
+version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e8e946c2b1349055e0b72ae281b238baf1a3ea7307c7e9f9d64673bdd9c26ac7"
+checksum = "8bf09f61b52cfcf4c00de50df88ae423d6c02354e385a86341133b5338630ad1"
dependencies = [
"bytes 1.0.1",
"futures-channel",
@@ -940,7 +979,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
dependencies = [
"bytes 1.0.1",
- "hyper 0.14.4",
+ "hyper 0.14.5",
"native-tls",
"tokio",
"tokio-native-tls",
@@ -1026,10 +1065,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
[[package]]
+name = "job_scheduler"
+version = "1.2.1"
+source = "git+https://github.com/jjlin/job_scheduler?rev=ee023418dbba2bfe1e30a5fd7d937f9e33739806#ee023418dbba2bfe1e30a5fd7d937f9e33739806"
+dependencies = [
+ "chrono",
+ "cron",
+ "uuid",
+]
+
+[[package]]
name = "js-sys"
-version = "0.3.49"
+version = "0.3.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc15e39392125075f60c95ba416f5381ff6c3a948ff02ab12464715adf56c821"
+checksum = "2d99f9e3e84b8f67f846ef5b4cbbc3b1c29f6c759fcbce6f01aa0e73d932a24c"
dependencies = [
"wasm-bindgen",
]
@@ -1088,7 +1137,7 @@ dependencies = [
"idna 0.2.2",
"mime 0.3.16",
"native-tls",
- "nom",
+ "nom 6.1.2",
"once_cell",
"quoted_printable",
"rand 0.8.3",
@@ -1100,9 +1149,9 @@ dependencies = [
[[package]]
name = "libc"
-version = "0.2.91"
+version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8916b1f6ca17130ec6568feccee27c156ad12037880833a3b842a823236502e7"
+checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41"
[[package]]
name = "libsqlite3-sys"
@@ -1117,9 +1166,9 @@ dependencies = [
[[package]]
name = "lock_api"
-version = "0.4.2"
+version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312"
+checksum = "5a3c91c24eae6777794bb1997ad98bbb87daf92890acab859f7eaa4320333176"
dependencies = [
"scopeguard",
]
@@ -1223,9 +1272,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9753f12909fd8d923f75ae5c3258cae1ed3c8ec052e1b38c93c21a6d157f789c"
dependencies = [
"migrations_internals",
- "proc-macro2 1.0.24",
+ "proc-macro2 1.0.26",
"quote 1.0.9",
- "syn 1.0.64",
+ "syn 1.0.69",
]
[[package]]
@@ -1405,6 +1454,15 @@ checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
[[package]]
name = "nom"
+version = "4.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c349f68f25f596b9f44cf0e7c69752a5c633b0550c3ff849518bfba0233774a"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "nom"
version = "6.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2"
@@ -1441,9 +1499,9 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d"
dependencies = [
- "proc-macro2 1.0.24",
+ "proc-macro2 1.0.26",
"quote 1.0.9",
- "syn 1.0.64",
+ "syn 1.0.69",
]
[[package]]
@@ -1716,9 +1774,9 @@ checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55"
dependencies = [
"pest",
"pest_meta",
- "proc-macro2 1.0.24",
+ "proc-macro2 1.0.26",
"quote 1.0.9",
- "syn 1.0.64",
+ "syn 1.0.69",
]
[[package]]
@@ -1791,9 +1849,9 @@ version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a490329918e856ed1b083f244e3bfe2d8c4f336407e4ea9e1a9f479ff09049e5"
dependencies = [
- "proc-macro2 1.0.24",
+ "proc-macro2 1.0.26",
"quote 1.0.9",
- "syn 1.0.64",
+ "syn 1.0.69",
]
[[package]]
@@ -1858,9 +1916,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
-version = "1.0.24"
+version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
+checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
dependencies = [
"unicode-xid 0.2.1",
]
@@ -1892,14 +1950,14 @@ version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
dependencies = [
- "proc-macro2 1.0.24",
+ "proc-macro2 1.0.26",
]
[[package]]
name = "quoted_printable"
-version = "0.4.2"
+version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "47b080c5db639b292ac79cbd34be0cfc5d36694768d8341109634d90b86930e2"
+checksum = "1238256b09923649ec89b08104c4dfe9f6cb2fea734a5db5384e44916d59e9c5"
[[package]]
name = "r2d2"
@@ -2048,9 +2106,9 @@ dependencies = [
[[package]]
name = "redox_syscall"
-version = "0.2.5"
+version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9"
+checksum = "8270314b5ccceb518e7e578952f0b72b88222d02e8f77f5ecf7abbb673539041"
dependencies = [
"bitflags",
]
@@ -2083,10 +2141,11 @@ dependencies = [
[[package]]
name = "reqwest"
-version = "0.11.2"
+version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf12057f289428dbf5c591c74bf10392e4a8003f993405a902f20117019022d4"
+checksum = "2296f2fac53979e8ccbc4a1136b25dcefd37be9ed7e4a1f6b05a6029c84ff124"
dependencies = [
+ "async-compression",
"base64 0.13.0",
"bytes 1.0.1",
"encoding_rs",
@@ -2094,7 +2153,7 @@ dependencies = [
"futures-util",
"http",
"http-body",
- "hyper 0.14.4",
+ "hyper 0.14.5",
"hyper-tls",
"ipnet",
"js-sys",
@@ -2109,6 +2168,8 @@ dependencies = [
"serde_urlencoded",
"tokio",
"tokio-native-tls",
+ "tokio-socks",
+ "tokio-util",
"url 2.2.1",
"wasm-bindgen",
"wasm-bindgen-futures",
@@ -2296,9 +2357,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "sct"
-version = "0.6.0"
+version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3042af939fca8c3453b7af0f1c66e533a15a86169e39de2657310ade8f98d3c"
+checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce"
dependencies = [
"ring",
"untrusted",
@@ -2306,9 +2367,9 @@ dependencies = [
[[package]]
name = "security-framework"
-version = "2.1.2"
+version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d493c5f39e02dfb062cd8f33301f90f9b13b650e8c1b1d0fd75c19dd64bff69d"
+checksum = "3670b1d2fdf6084d192bc71ead7aabe6c06aa2ea3fbd9cc3ac111fa5c2b1bd84"
dependencies = [
"bitflags",
"core-foundation",
@@ -2319,9 +2380,9 @@ dependencies = [
[[package]]
name = "security-framework-sys"
-version = "2.1.1"
+version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dee48cdde5ed250b0d3252818f646e174ab414036edb884dde62d80a3ac6082d"
+checksum = "3676258fd3cfe2c9a0ec99ce3038798d847ce3e4bb17746373eb9f0f1ac16339"
dependencies = [
"core-foundation-sys",
"libc",
@@ -2357,9 +2418,9 @@ version = "1.0.125"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d"
dependencies = [
- "proc-macro2 1.0.24",
+ "proc-macro2 1.0.26",
"quote 1.0.9",
- "syn 1.0.64",
+ "syn 1.0.69",
]
[[package]]
@@ -2482,11 +2543,10 @@ checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
[[package]]
name = "socket2"
-version = "0.3.19"
+version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e"
+checksum = "9e3dfc207c526015c632472a77be09cf1b6e46866581aecae5cc38fb4235dea2"
dependencies = [
- "cfg-if 1.0.0",
"libc",
"winapi 0.3.9",
]
@@ -2538,11 +2598,11 @@ version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef"
dependencies = [
- "proc-macro2 1.0.24",
+ "proc-macro2 1.0.26",
"quote 1.0.9",
"serde",
"serde_derive",
- "syn 1.0.64",
+ "syn 1.0.69",
]
[[package]]
@@ -2552,13 +2612,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11"
dependencies = [
"base-x",
- "proc-macro2 1.0.24",
+ "proc-macro2 1.0.26",
"quote 1.0.9",
"serde",
"serde_derive",
"serde_json",
"sha1",
- "syn 1.0.64",
+ "syn 1.0.69",
]
[[package]]
@@ -2588,7 +2648,7 @@ checksum = "f24c8e5e19d22a726626f1a5e16fe15b132dcf21d10177fa5a45ce7962996b97"
dependencies = [
"phf_generator",
"phf_shared",
- "proc-macro2 1.0.24",
+ "proc-macro2 1.0.26",
"quote 1.0.9",
]
@@ -2611,11 +2671,11 @@ dependencies = [
[[package]]
name = "syn"
-version = "1.0.64"
+version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fd9d1e9976102a03c542daa2eff1b43f9d72306342f3f8b3ed5fb8908195d6f"
+checksum = "48fe99c6bd8b1cc636890bcc071842de909d902c81ac7dab53ba33c421ab8ffb"
dependencies = [
- "proc-macro2 1.0.24",
+ "proc-macro2 1.0.26",
"quote 1.0.9",
"unicode-xid 0.2.1",
]
@@ -2664,6 +2724,26 @@ dependencies = [
]
[[package]]
+name = "thiserror"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0"
+dependencies = [
+ "proc-macro2 1.0.26",
+ "quote 1.0.9",
+ "syn 1.0.69",
+]
+
+[[package]]
name = "threadpool"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2715,17 +2795,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5c3be1edfad6027c69f5491cf4cb310d1a71ecd6af742788c6ff8bced86b8fa"
dependencies = [
"proc-macro-hack",
- "proc-macro2 1.0.24",
+ "proc-macro2 1.0.26",
"quote 1.0.9",
"standback",
- "syn 1.0.64",
+ "syn 1.0.69",
]
[[package]]
name = "tinyvec"
-version = "1.1.1"
+version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "317cca572a0e89c3ce0ca1f1bdc9369547fe318a683418e42ac8f59d14701023"
+checksum = "5b5220f05bb7de7f3f53c7c065e1199b3172696fe2db9f9c4d8ad9b4ee74c342"
dependencies = [
"tinyvec_macros",
]
@@ -2738,9 +2818,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "tokio"
-version = "1.4.0"
+version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "134af885d758d645f0f0505c9a8b3f9bf8a348fd822e112ab5248138348f1722"
+checksum = "83f0c8e7c0addab50b663055baf787d0af7f413a46e6e7fb9559a4e4db7137a5"
dependencies = [
"autocfg",
"bytes 1.0.1",
@@ -2762,10 +2842,22 @@ dependencies = [
]
[[package]]
+name = "tokio-socks"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51165dfa029d2a65969413a6cc96f354b86b464498702f174a4efa13608fd8c0"
+dependencies = [
+ "either",
+ "futures-util",
+ "thiserror",
+ "tokio",
+]
+
+[[package]]
name = "tokio-util"
-version = "0.6.5"
+version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5143d049e85af7fbc36f5454d990e62c2df705b3589f123b71f441b6b59f443f"
+checksum = "940a12c99365c31ea8dd9ba04ec1be183ffe4920102bb7122c2f515437601e8e"
dependencies = [
"bytes 1.0.1",
"futures-core",
@@ -2797,11 +2889,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01ebdc2bb4498ab1ab5f5b73c5803825e60199229ccba0698170e3be0e7f959f"
dependencies = [
"cfg-if 1.0.0",
+ "log 0.4.14",
"pin-project-lite",
+ "tracing-attributes",
"tracing-core",
]
[[package]]
+name = "tracing-attributes"
+version = "0.1.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c42e6fa53307c8a17e4ccd4dc81cf5ec38db9209f59b222210375b54ee40d1e2"
+dependencies = [
+ "proc-macro2 1.0.26",
+ "quote 1.0.9",
+ "syn 1.0.69",
+]
+
+[[package]]
name = "tracing-core"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2886,9 +2991,9 @@ dependencies = [
[[package]]
name = "unicode-bidi"
-version = "0.3.4"
+version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
+checksum = "eeb8be209bb1c96b7c177c7420d26e04eccacb0eeae6b980e35fcb74678107e0"
dependencies = [
"matches",
]
@@ -2959,6 +3064,57 @@ dependencies = [
]
[[package]]
+name = "vaultwarden"
+version = "1.0.0"
+dependencies = [
+ "backtrace",
+ "chashmap",
+ "chrono",
+ "chrono-tz",
+ "data-encoding",
+ "data-url",
+ "diesel",
+ "diesel_migrations",
+ "dotenv",
+ "fern",
+ "handlebars",
+ "html5ever",
+ "idna 0.2.2",
+ "job_scheduler",
+ "jsonwebtoken",
+ "lettre",
+ "libsqlite3-sys",
+ "log 0.4.14",
+ "markup5ever_rcdom",
+ "multipart",
+ "newline-converter",
+ "num-derive",
+ "num-traits",
+ "oath",
+ "once_cell",
+ "openssl",
+ "parity-ws",
+ "paste",
+ "percent-encoding 2.1.0",
+ "pico-args",
+ "rand 0.8.3",
+ "regex",
+ "reqwest",
+ "ring",
+ "rmpv",
+ "rocket",
+ "rocket_contrib",
+ "serde",
+ "serde_json",
+ "syslog",
+ "time 0.2.26",
+ "tracing",
+ "u2f",
+ "uuid",
+ "yubico",
+]
+
+[[package]]
name = "vcpkg"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3011,9 +3167,9 @@ checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
[[package]]
name = "wasm-bindgen"
-version = "0.2.72"
+version = "0.2.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8fe8f61dba8e5d645a4d8132dc7a0a66861ed5e1045d2c0ed940fab33bac0fbe"
+checksum = "83240549659d187488f91f33c0f8547cbfef0b2088bc470c116d1d260ef623d9"
dependencies = [
"cfg-if 1.0.0",
"serde",
@@ -3023,24 +3179,24 @@ dependencies = [
[[package]]
name = "wasm-bindgen-backend"
-version = "0.2.72"
+version = "0.2.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "046ceba58ff062da072c7cb4ba5b22a37f00a302483f7e2a6cdc18fedbdc1fd3"
+checksum = "ae70622411ca953215ca6d06d3ebeb1e915f0f6613e3b495122878d7ebec7dae"
dependencies = [
"bumpalo",
"lazy_static",
"log 0.4.14",
- "proc-macro2 1.0.24",
+ "proc-macro2 1.0.26",
"quote 1.0.9",
- "syn 1.0.64",
+ "syn 1.0.69",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-futures"
-version = "0.4.22"
+version = "0.4.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73157efb9af26fb564bb59a009afd1c7c334a44db171d280690d0c3faaec3468"
+checksum = "81b8b767af23de6ac18bf2168b690bed2902743ddf0fb39252e36f9e2bfc63ea"
dependencies = [
"cfg-if 1.0.0",
"js-sys",
@@ -3050,9 +3206,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
-version = "0.2.72"
+version = "0.2.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ef9aa01d36cda046f797c57959ff5f3c615c9cc63997a8d545831ec7976819b"
+checksum = "3e734d91443f177bfdb41969de821e15c516931c3c3db3d318fa1b68975d0f6f"
dependencies = [
"quote 1.0.9",
"wasm-bindgen-macro-support",
@@ -3060,28 +3216,28 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
-version = "0.2.72"
+version = "0.2.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96eb45c1b2ee33545a813a92dbb53856418bf7eb54ab34f7f7ff1448a5b3735d"
+checksum = "d53739ff08c8a68b0fdbcd54c372b8ab800b1449ab3c9d706503bc7dd1621b2c"
dependencies = [
- "proc-macro2 1.0.24",
+ "proc-macro2 1.0.26",
"quote 1.0.9",
- "syn 1.0.64",
+ "syn 1.0.69",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
-version = "0.2.72"
+version = "0.2.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b7148f4696fb4960a346eaa60bbfb42a1ac4ebba21f750f75fc1375b098d5ffa"
+checksum = "d9a543ae66aa233d14bb765ed9af4a33e81b8b58d1584cf1b47ff8cd0b9e4489"
[[package]]
name = "web-sys"
-version = "0.3.49"
+version = "0.3.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "59fe19d70f5dacc03f6e46777213facae5ac3801575d56ca6cbd4c93dcd12310"
+checksum = "a905d57e488fec8861446d3393670fb50d27a262344013181c2cdf9fff5481be"
dependencies = [
"js-sys",
"wasm-bindgen",
diff --git a/Cargo.toml b/Cargo.toml
index 078393aa..1e6ad73d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,10 +1,10 @@
[package]
-name = "bitwarden_rs"
+name = "vaultwarden"
version = "1.0.0"
authors = ["Daniel García <[email protected]>"]
edition = "2018"
-repository = "https://github.com/dani-garcia/bitwarden_rs"
+repository = "https://github.com/dani-garcia/vaultwarden"
readme = "README.md"
license = "GPL-3.0-only"
publish = false
@@ -32,7 +32,7 @@ rocket = { version = "0.5.0-dev", features = ["tls"], default-features = false }
rocket_contrib = "0.5.0-dev"
# HTTP client
-reqwest = { version = "0.11.2", features = ["blocking", "json"] }
+reqwest = { version = "0.11.3", features = ["blocking", "json", "gzip", "brotli", "socks"] }
# multipart/form-data support
multipart = { version = "0.17.1", features = ["server"], default-features = false }
@@ -73,6 +73,9 @@ chrono = { version = "0.4.19", features = ["serde"] }
chrono-tz = "0.5.3"
time = "0.2.26"
+# Job scheduler
+job_scheduler = "1.2.1"
+
# TOTP library
oath = "0.10.2"
@@ -99,11 +102,12 @@ num-traits = "0.2.14"
num-derive = "0.3.3"
# Email libraries
+tracing = { version = "0.1.25", features = ["log"] } # Needed to have lettre trace logging used when SMTP_DEBUG is enabled.
lettre = { version = "0.10.0-beta.3", features = ["smtp-transport", "builder", "serde", "native-tls", "hostname", "tracing"], default-features = false }
newline-converter = "0.2.0"
# Template library
-handlebars = { version = "3.5.3", features = ["dir_source"] }
+handlebars = { version = "3.5.4", features = ["dir_source"] }
# For favicon extraction from main website
html5ever = "0.25.1"
@@ -135,3 +139,10 @@ rocket_contrib = { git = 'https://github.com/SergioBenitez/Rocket', rev = '263e3
# For favicon extraction from main website
data-url = { git = 'https://github.com/servo/rust-url', package="data-url", rev = '540ede02d0771824c0c80ff9f57fe8eff38b1291' }
+
+# The maintainer of the `job_scheduler` crate doesn't seem to have responded
+# to any issues or PRs for almost a year (as of April 2021). This hopefully
+# temporary fork updates Cargo.toml to use more up-to-date dependencies.
+# In particular, `cron` has since implemented parsing of some common syntax
+# that wasn't previously supported (https://github.com/zslayton/cron/pull/64).
+job_scheduler = { git = 'https://github.com/jjlin/job_scheduler', rev = 'ee023418dbba2bfe1e30a5fd7d937f9e33739806' }
diff --git a/README.md b/README.md
index 169923dd..a6003b44 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,14 @@
-### This is a Bitwarden server API implementation written in Rust compatible with [upstream Bitwarden clients](https://bitwarden.com/#download)*, perfect for self-hosted deployment where running the official resource-heavy service might not be ideal.
+### Alternative implementation of the Bitwarden server API written in Rust and compatible with [upstream Bitwarden clients](https://bitwarden.com/#download)*, perfect for self-hosted deployment where running the official resource-heavy service might not be ideal.
---
-[![Travis Build Status](https://travis-ci.org/dani-garcia/bitwarden_rs.svg?branch=master)](https://travis-ci.org/dani-garcia/bitwarden_rs)
-[![Docker Pulls](https://img.shields.io/docker/pulls/bitwardenrs/server.svg)](https://hub.docker.com/r/bitwardenrs/server)
-[![Dependency Status](https://deps.rs/repo/github/dani-garcia/bitwarden_rs/status.svg)](https://deps.rs/repo/github/dani-garcia/bitwarden_rs)
-[![GitHub Release](https://img.shields.io/github/release/dani-garcia/bitwarden_rs.svg)](https://github.com/dani-garcia/bitwarden_rs/releases/latest)
-[![GPL-3.0 Licensed](https://img.shields.io/github/license/dani-garcia/bitwarden_rs.svg)](https://github.com/dani-garcia/bitwarden_rs/blob/master/LICENSE.txt)
-[![Matrix Chat](https://img.shields.io/matrix/bitwarden_rs:matrix.org.svg?logo=matrix)](https://matrix.to/#/#bitwarden_rs:matrix.org)
+[![Docker Pulls](https://img.shields.io/docker/pulls/bitwardenrs/server.svg)](https://hub.docker.com/r/vaultwarden/server)
+[![Dependency Status](https://deps.rs/repo/github/dani-garcia/vaultwarden/status.svg)](https://deps.rs/repo/github/dani-garcia/vaultwarden)
+[![GitHub Release](https://img.shields.io/github/release/dani-garcia/vaultwarden.svg)](https://github.com/dani-garcia/vaultwarden/releases/latest)
+[![GPL-3.0 Licensed](https://img.shields.io/github/license/dani-garcia/vaultwarden.svg)](https://github.com/dani-garcia/vaultwarden/blob/master/LICENSE.txt)
+[![Matrix Chat](https://img.shields.io/matrix/vaultwarden:matrix.org.svg?logo=matrix)](https://matrix.to/#/#vaultwarden:matrix.org)
-Image is based on [Rust implementation of Bitwarden API](https://github.com/dani-garcia/bitwarden_rs).
+Image is based on [Rust implementation of Bitwarden API](https://github.com/dani-garcia/vaultwarden).
**This project is not associated with the [Bitwarden](https://bitwarden.com/) project nor 8bit Solutions LLC.**
@@ -33,29 +32,57 @@ Basically full implementation of Bitwarden API is provided including:
Pull the docker image and mount a volume from the host for persistent storage:
```sh
-docker pull bitwardenrs/server:latest
-docker run -d --name bitwarden -v /bw-data/:/data/ -p 80:80 bitwardenrs/server:latest
+docker pull vaultwarden/server:latest
+docker run -d --name vaultwarden -v /vw-data/:/data/ -p 80:80 vaultwarden/server:latest
```
This will preserve any persistent data under /bw-data/, you can adapt the path to whatever suits you.
**IMPORTANT**: Some web browsers, like Chrome, disallow the use of Web Crypto APIs in insecure contexts. In this case, you might get an error like `Cannot read property 'importKey'`. To solve this problem, you need to access the web vault from HTTPS.
-This can be configured in [bitwarden_rs directly](https://github.com/dani-garcia/bitwarden_rs/wiki/Enabling-HTTPS) or using a third-party reverse proxy ([some examples](https://github.com/dani-garcia/bitwarden_rs/wiki/Proxy-examples)).
+This can be configured in [vaultwarden directly](https://github.com/dani-garcia/vaultwarden/wiki/Enabling-HTTPS) or using a third-party reverse proxy ([some examples](https://github.com/dani-garcia/vaultwarden/wiki/Proxy-examples)).
If you have an available domain name, you can get HTTPS certificates with [Let's Encrypt](https://letsencrypt.org/), or you can generate self-signed certificates with utilities like [mkcert](https://github.com/FiloSottile/mkcert). Some proxies automatically do this step, like Caddy (see examples linked above).
## Usage
-See the [bitwarden_rs wiki](https://github.com/dani-garcia/bitwarden_rs/wiki) for more information on how to configure and run the bitwarden_rs server.
+See the [vaultwarden wiki](https://github.com/dani-garcia/vaultwarden/wiki) for more information on how to configure and run the vaultwarden server.
## Get in touch
-To ask a question, offer suggestions or new features or to get help configuring or installing the software, please [use the forum](https://bitwardenrs.discourse.group/).
+To ask a question, offer suggestions or new features or to get help configuring or installing the software, please [use the forum](https://vaultwarden.discourse.group/).
-If you spot any bugs or crashes with bitwarden_rs itself, please [create an issue](https://github.com/dani-garcia/bitwarden_rs/issues/). Make sure there aren't any similar issues open, though!
+If you spot any bugs or crashes with vaultwarden itself, please [create an issue](https://github.com/dani-garcia/vaultwarden/issues/). Make sure there aren't any similar issues open, though!
-If you prefer to chat, we're usually hanging around at [#bitwarden_rs:matrix.org](https://matrix.to/#/#bitwarden_rs:matrix.org) room on Matrix. Feel free to join us!
+If you prefer to chat, we're usually hanging around at [#vaultwarden:matrix.org](https://matrix.to/#/#vaultwarden:matrix.org) room on Matrix. Feel free to join us!
### Sponsors
Thanks for your contribution to the project!
-- [@ChonoN](https://github.com/ChonoN)
-- [@themightychris](https://github.com/themightychris)
+<table>
+ <tr>
+ <td align="center">
+ <a href="https://github.com/netdadaltd">
+ <img src="https://avatars.githubusercontent.com/u/77323954?s=75&v=4" width="75px;" alt="netdadaltd"/>
+ <br />
+ <sub><b>netDada Ltd.</b></sub>
+ </a>
+ </td>
+ </tr>
+</table>
+
+<br/>
+
+<table>
+ <tr>
+ <td align="center">
+ <a href="https://github.com/ChonoN" style="width: 75px">
+ <sub><b>ChonoN</b></sub>
+ </a>
+ </td>
+ </tr>
+ <tr>
+ <td align="center">
+ <a href="https://github.com/themightychris">
+ <sub><b>themightychris</b></sub>
+ </a>
+ </td>
+ </tr>
+</table>
diff --git a/build.rs b/build.rs
index 0277d21e..39c16095 100644
--- a/build.rs
+++ b/build.rs
@@ -1,7 +1,7 @@
-use std::process::Command;
use std::env;
+use std::process::Command;
-fn main() {
+fn main() {
// This allow using #[cfg(sqlite)] instead of #[cfg(feature = "sqlite")], which helps when trying to add them through macros
#[cfg(feature = "sqlite")]
println!("cargo:rustc-cfg=sqlite");
@@ -11,8 +11,10 @@ fn main() {
println!("cargo:rustc-cfg=postgresql");
#[cfg(not(any(feature = "sqlite", feature = "mysql", feature = "postgresql")))]
- compile_error!("You need to enable one DB backend. To build with previous defaults do: cargo build --features sqlite");
-
+ compile_error!(
+ "You need to enable one DB backend. To build with previous defaults do: cargo build --features sqlite"
+ );
+
if let Ok(version) = env::var("BWRS_VERSION") {
println!("cargo:rustc-env=BWRS_VERSION={}", version);
println!("cargo:rustc-env=CARGO_PKG_VERSION={}", version);
@@ -56,12 +58,12 @@ fn read_git_info() -> Result<(), std::io::Error> {
// Combined version
let version = if let Some(exact) = exact_tag {
exact
- } else if &branch != "master" {
+ } else if &branch != "main" && &branch != "master" {
format!("{}-{} ({})", last_tag, rev_short, branch)
} else {
format!("{}-{}", last_tag, rev_short)
};
-
+
println!("cargo:rustc-env=BWRS_VERSION={}", version);
println!("cargo:rustc-env=CARGO_PKG_VERSION={}", version);
diff --git a/docker/Dockerfile.buildx b/docker/Dockerfile.buildx
index 9faf3968..ed0d23b3 100644
--- a/docker/Dockerfile.buildx
+++ b/docker/Dockerfile.buildx
@@ -1,7 +1,7 @@
# The cross-built images have the build arch (`amd64`) embedded in the image
# manifest, rather than the target arch. For example:
#
-# $ docker inspect bitwardenrs/server:latest-armv7 | jq -r '.[]|.Architecture'
+# $ docker inspect vaultwarden/server:latest-armv7 | jq -r '.[]|.Architecture'
# amd64
#
# Recent versions of Docker have started printing a warning when the image's
diff --git a/docker/Dockerfile.j2 b/docker/Dockerfile.j2
index 7793ff2d..94f910b0 100644
--- a/docker/Dockerfile.j2
+++ b/docker/Dockerfile.j2
@@ -1,10 +1,10 @@
# This file was generated using a Jinja2 template.
# Please make your changes in `Dockerfile.j2` and then `make` the individual Dockerfiles.
-{% set build_stage_base_image = "rust:1.50" %}
+{% set build_stage_base_image = "rust:1.51" %}
{% if "alpine" in target_file %}
{% if "amd64" in target_file %}
-{% set build_stage_base_image = "clux/muslrust:nightly-2021-02-22" %}
+{% set build_stage_base_image = "clux/muslrust:nightly-2021-04-14" %}
{% set runtime_stage_base_image = "alpine:3.13" %}
{% set package_arch_target = "x86_64-unknown-linux-musl" %}
{% elif "armv7" in target_file %}
@@ -44,26 +44,26 @@
# https://docs.docker.com/develop/develop-images/multistage-build/
# https://whitfin.io/speeding-up-rust-docker-builds/
####################### VAULT BUILD IMAGE #######################
-{% set vault_version = "2.19.0" %}
-{% set vault_image_digest = "sha256:8747cfaa2c6d87d1749e119dd884697e8099389aa9aca30a4d73d4ff796fe0e4" %}
+{% set vault_version = "2.19.0d" %}
+{% set vault_image_digest = "sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233" %}
# The web-vault digest specifies a particular web-vault build on Docker Hub.
# Using the digest instead of the tag name provides better security,
# as the digest of an image is immutable, whereas a tag name can later
# be changed to point to a malicious image.
#
# To verify the current digest for a given tag name:
-# - From https://hub.docker.com/r/bitwardenrs/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.
# - From the command line:
-# $ docker pull bitwardenrs/web-vault:v{{ vault_version }}
-# $ docker image inspect --format "{{ '{{' }}.RepoDigests}}" bitwardenrs/web-vault:v{{ vault_version }}
-# [bitwardenrs/web-vault@{{ vault_image_digest }}]
+# $ docker pull vaultwarden/web-vault:v{{ vault_version }}
+# $ docker image inspect --format "{{ '{{' }}.RepoDigests}}" vaultwarden/web-vault:v{{ vault_version }}
+# [vaultwarden/web-vault@{{ vault_image_digest }}]
#
# - Conversely, to get the tag name from the digest:
-# $ docker image inspect --format "{{ '{{' }}.RepoTags}}" bitwardenrs/web-vault@{{ vault_image_digest }}
-# [bitwardenrs/web-vault:v{{ vault_version }}]
+# $ docker image inspect --format "{{ '{{' }}.RepoTags}}" vaultwarden/web-vault@{{ vault_image_digest }}
+# [vaultwarden/web-vault:v{{ vault_version }}]
#
-FROM bitwardenrs/web-vault@{{ vault_image_digest }} as vault
+FROM vaultwarden/web-vault@{{ vault_image_digest }} as vault
########################## BUILD IMAGE ##########################
FROM {{ build_stage_base_image }} as build
@@ -189,7 +189,7 @@ RUN touch src/main.rs
RUN cargo build --features ${DB} --release{{ package_arch_target_param }}
{% if "alpine" in target_file %}
{% if "armv7" in target_file %}
-RUN musl-strip target/{{ package_arch_target }}/release/bitwarden_rs
+RUN musl-strip target/{{ package_arch_target }}/release/vaultwarden
{% endif %}
{% endif %}
@@ -215,9 +215,6 @@ RUN apk add --no-cache \
openssl \
curl \
dumb-init \
-{% if "sqlite" in features %}
- sqlite \
-{% endif %}
{% if "mysql" in features %}
mariadb-connector-c \
{% endif %}
@@ -232,7 +229,6 @@ RUN apt-get update && apt-get install -y \
ca-certificates \
curl \
dumb-init \
- sqlite3 \
libmariadb-dev-compat \
libpq5 \
&& rm -rf /var/lib/apt/lists/*
@@ -250,12 +246,13 @@ EXPOSE 3012
# Copies the files from the context (Rocket.toml file and web-vault)
# and the binary from the "build" stage to the current stage
+WORKDIR /
COPY Rocket.toml .
COPY --from=vault /web-vault ./web-vault
{% if package_arch_target is defined %}
-COPY --from=build /app/target/{{ package_arch_target }}/release/bitwarden_rs .
+COPY --from=build /app/target/{{ package_arch_target }}/release/vaultwarden .
{% else %}
-COPY --from=build /app/target/release/bitwarden_rs .
+COPY --from=build /app/target/release/vaultwarden .
{% endif %}
COPY docker/healthcheck.sh /healthcheck.sh
@@ -264,6 +261,5 @@ COPY docker/start.sh /start.sh
HEALTHCHECK --interval=60s --timeout=10s CMD ["/healthcheck.sh"]
# Configures the startup!
-WORKDIR /
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
CMD ["/start.sh"]
diff --git a/docker/amd64/Dockerfile b/docker/amd64/Dockerfile
index 08cdb1a8..8152461f 100644
--- a/docker/amd64/Dockerfile
+++ b/docker/amd64/Dockerfile
@@ -11,21 +11,21 @@
# be changed to point to a malicious image.
#
# To verify the current digest for a given tag name:
-# - From https://hub.docker.com/r/bitwardenrs/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.
# - From the command line:
-# $ docker pull bitwardenrs/web-vault:v2.19.0
-# $ docker image inspect --format "{{.RepoDigests}}" bitwardenrs/web-vault:v2.19.0
-# [bitwardenrs/web-vault@sha256:8747cfaa2c6d87d1749e119dd884697e8099389aa9aca30a4d73d4ff796fe0e4]
+# $ docker pull vaultwarden/web-vault:v2.19.0d
+# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.19.0d
+# [vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233]
#
# - Conversely, to get the tag name from the digest:
-# $ docker image inspect --format "{{.RepoTags}}" bitwardenrs/web-vault@sha256:8747cfaa2c6d87d1749e119dd884697e8099389aa9aca30a4d73d4ff796fe0e4
-# [bitwardenrs/web-vault:v2.19.0]
+# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233
+# [vaultwarden/web-vault:v2.19.0d]
#
-FROM bitwardenrs/web-vault@sha256:8747cfaa2c6d87d1749e119dd884697e8099389aa9aca30a4d73d4ff796fe0e4 as vault
+FROM vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233 as vault
########################## BUILD IMAGE ##########################
-FROM rust:1.50 as build
+FROM rust:1.51 as build
# Debian-based builds support multidb
ARG DB=sqlite,mysql,postgresql
@@ -86,7 +86,6 @@ RUN apt-get update && apt-get install -y \
ca-certificates \
curl \
dumb-init \
- sqlite3 \
libmariadb-dev-compat \
libpq5 \
&& rm -rf /var/lib/apt/lists/*
@@ -98,9 +97,10 @@ EXPOSE 3012
# Copies the files from the context (Rocket.toml file and web-vault)
# and the binary from the "build" stage to the current stage
+WORKDIR /
COPY Rocket.toml .
COPY --from=vault /web-vault ./web-vault
-COPY --from=build /app/target/release/bitwarden_rs .
+COPY --from=build /app/target/release/vaultwarden .
COPY docker/healthcheck.sh /healthcheck.sh
COPY docker/start.sh /start.sh
@@ -108,6 +108,5 @@ COPY docker/start.sh /start.sh
HEALTHCHECK --interval=60s --timeout=10s CMD ["/healthcheck.sh"]
# Configures the startup!
-WORKDIR /
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
CMD ["/start.sh"]
diff --git a/docker/amd64/Dockerfile.alpine b/docker/amd64/Dockerfile.alpine
index 71d63132..d5462bfe 100644
--- a/docker/amd64/Dockerfile.alpine
+++ b/docker/amd64/Dockerfile.alpine
@@ -11,21 +11,21 @@
# be changed to point to a malicious image.
#
# To verify the current digest for a given tag name:
-# - From https://hub.docker.com/r/bitwardenrs/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.
# - From the command line:
-# $ docker pull bitwardenrs/web-vault:v2.19.0
-# $ docker image inspect --format "{{.RepoDigests}}" bitwardenrs/web-vault:v2.19.0
-# [bitwardenrs/web-vault@sha256:8747cfaa2c6d87d1749e119dd884697e8099389aa9aca30a4d73d4ff796fe0e4]
+# $ docker pull vaultwarden/web-vault:v2.19.0d
+# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.19.0d
+# [vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233]
#
# - Conversely, to get the tag name from the digest:
-# $ docker image inspect --format "{{.RepoTags}}" bitwardenrs/web-vault@sha256:8747cfaa2c6d87d1749e119dd884697e8099389aa9aca30a4d73d4ff796fe0e4
-# [bitwardenrs/web-vault:v2.19.0]
+# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233
+# [vaultwarden/web-vault:v2.19.0d]
#
-FROM bitwardenrs/web-vault@sha256:8747cfaa2c6d87d1749e119dd884697e8099389aa9aca30a4d73d4ff796fe0e4 as vault
+FROM vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233 as vault
########################## BUILD IMAGE ##########################
-FROM clux/muslrust:nightly-2021-02-22 as build
+FROM clux/muslrust:nightly-2021-04-14 as build
# Alpine-based AMD64 (musl) does not support mysql/mariadb during compile time.
ARG DB=sqlite,postgresql
@@ -82,7 +82,6 @@ RUN apk add --no-cache \
openssl \
curl \
dumb-init \
- sqlite \
postgresql-libs \
ca-certificates
@@ -93,9 +92,10 @@ EXPOSE 3012
# Copies the files from the context (Rocket.toml file and web-vault)
# and the binary from the "build" stage to the current stage
+WORKDIR /
COPY Rocket.toml .
COPY --from=vault /web-vault ./web-vault
-COPY --from=build /app/target/x86_64-unknown-linux-musl/release/bitwarden_rs .
+COPY --from=build /app/target/x86_64-unknown-linux-musl/release/vaultwarden .
COPY docker/healthcheck.sh /healthcheck.sh
COPY docker/start.sh /start.sh
@@ -103,6 +103,5 @@ COPY docker/start.sh /start.sh
HEALTHCHECK --interval=60s --timeout=10s CMD ["/healthcheck.sh"]
# Configures the startup!
-WORKDIR /
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
CMD ["/start.sh"]
diff --git a/docker/arm64/Dockerfile b/docker/arm64/Dockerfile
index c6faf743..3669c4fb 100644
--- a/docker/arm64/Dockerfile
+++ b/docker/arm64/Dockerfile
@@ -11,21 +11,21 @@
# be changed to point to a malicious image.
#
# To verify the current digest for a given tag name:
-# - From https://hub.docker.com/r/bitwardenrs/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.
# - From the command line:
-# $ docker pull bitwardenrs/web-vault:v2.19.0
-# $ docker image inspect --format "{{.RepoDigests}}" bitwardenrs/web-vault:v2.19.0
-# [bitwardenrs/web-vault@sha256:8747cfaa2c6d87d1749e119dd884697e8099389aa9aca30a4d73d4ff796fe0e4]
+# $ docker pull vaultwarden/web-vault:v2.19.0d
+# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.19.0d
+# [vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233]
#
# - Conversely, to get the tag name from the digest:
-# $ docker image inspect --format "{{.RepoTags}}" bitwardenrs/web-vault@sha256:8747cfaa2c6d87d1749e119dd884697e8099389aa9aca30a4d73d4ff796fe0e4
-# [bitwardenrs/web-vault:v2.19.0]
+# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233
+# [vaultwarden/web-vault:v2.19.0d]
#
-FROM bitwardenrs/web-vault@sha256:8747cfaa2c6d87d1749e119dd884697e8099389aa9aca30a4d73d4ff796fe0e4 as vault
+FROM vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233 as vault
########################## BUILD IMAGE ##########################
-FROM rust:1.50 as build
+FROM rust:1.51 as build
# Debian-based builds support multidb
ARG DB=sqlite,mysql,postgresql
@@ -129,7 +129,6 @@ RUN apt-get update && apt-get install -y \
ca-certificates \
curl \
dumb-init \
- sqlite3 \
libmariadb-dev-compat \
libpq5 \
&& rm -rf /var/lib/apt/lists/*
@@ -144,9 +143,10 @@ EXPOSE 3012
# Copies the files from the context (Rocket.toml file and web-vault)
# and the binary from the "build" stage to the current stage
+WORKDIR /
COPY Rocket.toml .
COPY --from=vault /web-vault ./web-vault
-COPY --from=build /app/target/aarch64-unknown-linux-gnu/release/bitwarden_rs .
+COPY --from=build /app/target/aarch64-unknown-linux-gnu/release/vaultwarden .
COPY docker/healthcheck.sh /healthcheck.sh
COPY docker/start.sh /start.sh
@@ -154,6 +154,5 @@ COPY docker/start.sh /start.sh
HEALTHCHECK --interval=60s --timeout=10s CMD ["/healthcheck.sh"]
# Configures the startup!
-WORKDIR /
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
CMD ["/start.sh"]
diff --git a/docker/armv6/Dockerfile b/docker/armv6/Dockerfile
index c095e8c9..5cfcacf5 100644
--- a/docker/armv6/Dockerfile
+++ b/docker/armv6/Dockerfile
@@ -11,21 +11,21 @@
# be changed to point to a malicious image.
#
# To verify the current digest for a given tag name:
-# - From https://hub.docker.com/r/bitwardenrs/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.
# - From the command line:
-# $ docker pull bitwardenrs/web-vault:v2.19.0
-# $ docker image inspect --format "{{.RepoDigests}}" bitwardenrs/web-vault:v2.19.0
-# [bitwardenrs/web-vault@sha256:8747cfaa2c6d87d1749e119dd884697e8099389aa9aca30a4d73d4ff796fe0e4]
+# $ docker pull vaultwarden/web-vault:v2.19.0d
+# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.19.0d
+# [vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233]
#
# - Conversely, to get the tag name from the digest:
-# $ docker image inspect --format "{{.RepoTags}}" bitwardenrs/web-vault@sha256:8747cfaa2c6d87d1749e119dd884697e8099389aa9aca30a4d73d4ff796fe0e4
-# [bitwardenrs/web-vault:v2.19.0]
+# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233
+# [vaultwarden/web-vault:v2.19.0d]
#
-FROM bitwardenrs/web-vault@sha256:8747cfaa2c6d87d1749e119dd884697e8099389aa9aca30a4d73d4ff796fe0e4 as vault
+FROM vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233 as vault
########################## BUILD IMAGE ##########################
-FROM rust:1.50 as build
+FROM rust:1.51 as build
# Debian-based builds support multidb
ARG DB=sqlite,mysql,postgresql
@@ -129,7 +129,6 @@ RUN apt-get update && apt-get install -y \
ca-certificates \
curl \
dumb-init \
- sqlite3 \
libmariadb-dev-compat \
libpq5 \
&& rm -rf /var/lib/apt/lists/*
@@ -144,9 +143,10 @@ EXPOSE 3012
# Copies the files from the context (Rocket.toml file and web-vault)
# and the binary from the "build" stage to the current stage
+WORKDIR /
COPY Rocket.toml .
COPY --from=vault /web-vault ./web-vault
-COPY --from=build /app/target/arm-unknown-linux-gnueabi/release/bitwarden_rs .
+COPY --from=build /app/target/arm-unknown-linux-gnueabi/release/vaultwarden .
COPY docker/healthcheck.sh /healthcheck.sh
COPY docker/start.sh /start.sh
@@ -154,6 +154,5 @@ COPY docker/start.sh /start.sh
HEALTHCHECK --interval=60s --timeout=10s CMD ["/healthcheck.sh"]
# Configures the startup!
-WORKDIR /
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
CMD ["/start.sh"]
diff --git a/docker/armv7/Dockerfile b/docker/armv7/Dockerfile
index a880d061..09c1cf43 100644
--- a/docker/armv7/Dockerfile
+++ b/docker/armv7/Dockerfile
@@ -11,21 +11,21 @@
# be changed to point to a malicious image.
#
# To verify the current digest for a given tag name:
-# - From https://hub.docker.com/r/bitwardenrs/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.
# - From the command line:
-# $ docker pull bitwardenrs/web-vault:v2.19.0
-# $ docker image inspect --format "{{.RepoDigests}}" bitwardenrs/web-vault:v2.19.0
-# [bitwardenrs/web-vault@sha256:8747cfaa2c6d87d1749e119dd884697e8099389aa9aca30a4d73d4ff796fe0e4]
+# $ docker pull vaultwarden/web-vault:v2.19.0d
+# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.19.0d
+# [vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233]
#
# - Conversely, to get the tag name from the digest:
-# $ docker image inspect --format "{{.RepoTags}}" bitwardenrs/web-vault@sha256:8747cfaa2c6d87d1749e119dd884697e8099389aa9aca30a4d73d4ff796fe0e4
-# [bitwardenrs/web-vault:v2.19.0]
+# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233
+# [vaultwarden/web-vault:v2.19.0d]
#
-FROM bitwardenrs/web-vault@sha256:8747cfaa2c6d87d1749e119dd884697e8099389aa9aca30a4d73d4ff796fe0e4 as vault
+FROM vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233 as vault
########################## BUILD IMAGE ##########################
-FROM rust:1.50 as build
+FROM rust:1.51 as build
# Debian-based builds support multidb
ARG DB=sqlite,mysql,postgresql
@@ -129,7 +129,6 @@ RUN apt-get update && apt-get install -y \
ca-certificates \
curl \
dumb-init \
- sqlite3 \
libmariadb-dev-compat \
libpq5 \
&& rm -rf /var/lib/apt/lists/*
@@ -144,9 +143,10 @@ EXPOSE 3012
# Copies the files from the context (Rocket.toml file and web-vault)
# and the binary from the "build" stage to the current stage
+WORKDIR /
COPY Rocket.toml .
COPY --from=vault /web-vault ./web-vault
-COPY --from=build /app/target/armv7-unknown-linux-gnueabihf/release/bitwarden_rs .
+COPY --from=build /app/target/armv7-unknown-linux-gnueabihf/release/vaultwarden .
COPY docker/healthcheck.sh /healthcheck.sh
COPY docker/start.sh /start.sh
@@ -154,6 +154,5 @@ COPY docker/start.sh /start.sh
HEALTHCHECK --interval=60s --timeout=10s CMD ["/healthcheck.sh"]
# Configures the startup!
-WORKDIR /
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
CMD ["/start.sh"]
diff --git a/docker/armv7/Dockerfile.alpine b/docker/armv7/Dockerfile.alpine
index 7a7e4433..f9e6cc4d 100644
--- a/docker/armv7/Dockerfile.alpine
+++ b/docker/armv7/Dockerfile.alpine
@@ -11,18 +11,18 @@
# be changed to point to a malicious image.
#
# To verify the current digest for a given tag name:
-# - From https://hub.docker.com/r/bitwardenrs/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.
# - From the command line:
-# $ docker pull bitwardenrs/web-vault:v2.19.0
-# $ docker image inspect --format "{{.RepoDigests}}" bitwardenrs/web-vault:v2.19.0
-# [bitwardenrs/web-vault@sha256:8747cfaa2c6d87d1749e119dd884697e8099389aa9aca30a4d73d4ff796fe0e4]
+# $ docker pull vaultwarden/web-vault:v2.19.0d
+# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.19.0d
+# [vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233]
#
# - Conversely, to get the tag name from the digest:
-# $ docker image inspect --format "{{.RepoTags}}" bitwardenrs/web-vault@sha256:8747cfaa2c6d87d1749e119dd884697e8099389aa9aca30a4d73d4ff796fe0e4
-# [bitwardenrs/web-vault:v2.19.0]
+# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233
+# [vaultwarden/web-vault:v2.19.0d]
#
-FROM bitwardenrs/web-vault@sha256:8747cfaa2c6d87d1749e119dd884697e8099389aa9aca30a4d73d4ff796fe0e4 as vault
+FROM vaultwarden/web-vault@sha256:a7bd6bc4db33bd45f723c4b1ac90918b7f80204560683cfc8efd9efd03a9b233 as vault
########################## BUILD IMAGE ##########################
FROM messense/rust-musl-cross:armv7-musleabihf as build
@@ -67,7 +67,7 @@ RUN touch src/main.rs
# Builds again, this time it'll just be
# your actual source files being built
RUN cargo build --features ${DB} --release --target=armv7-unknown-linux-musleabihf
-RUN musl-strip target/armv7-unknown-linux-musleabihf/release/bitwarden_rs
+RUN musl-strip target/armv7-unknown-linux-musleabihf/release/vaultwarden
######################## RUNTIME IMAGE ########################
# Create a new stage with a minimal image
@@ -86,7 +86,6 @@ RUN apk add --no-cache \
openssl \
curl \
dumb-init \
- sqlite \
ca-certificates
RUN mkdir /data
@@ -99,9 +98,10 @@ EXPOSE 3012
# Copies the files from the context (Rocket.toml file and web-vault)
# and the binary from the "build" stage to the current stage
+WORKDIR /
COPY Rocket.toml .
COPY --from=vault /web-vault ./web-vault
-COPY --from=build /app/target/armv7-unknown-linux-musleabihf/release/bitwarden_rs .
+COPY --from=build /app/target/armv7-unknown-linux-musleabihf/release/vaultwarden .
COPY docker/healthcheck.sh /healthcheck.sh
COPY docker/start.sh /start.sh
@@ -109,6 +109,5 @@ COPY docker/start.sh /start.sh
HEALTHCHECK --interval=60s --timeout=10s CMD ["/healthcheck.sh"]
# Configures the startup!
-WORKDIR /
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
CMD ["/start.sh"]
diff --git a/docker/start.sh b/docker/start.sh
index 39f591c2..993ddbd9 100755
--- a/docker/start.sh
+++ b/docker/start.sh
@@ -1,15 +1,15 @@
#!/bin/sh
-if [ -r /etc/bitwarden_rs.sh ]; then
- . /etc/bitwarden_rs.sh
+if [ -r /etc/vaultwarden.sh ]; then
+ . /etc/vaultwarden.sh
fi
-if [ -d /etc/bitwarden_rs.d ]; then
- for f in /etc/bitwarden_rs.d/*.sh; do
+if [ -d /etc/vaultwarden.d ]; then
+ for f in /etc/vaultwarden.d/*.sh; do
if [ -r $f ]; then
. $f
fi
done
fi
-exec /bitwarden_rs "${@}"
+exec /vaultwarden "${@}"
diff --git a/hooks/README.md b/hooks/README.md
index 0ad0383f..d198452e 100644
--- a/hooks/README.md
+++ b/hooks/README.md
@@ -10,7 +10,7 @@ Docker Hub hooks provide these predefined [environment variables](https://docs.d
* `DOCKER_TAG`: the Docker repository tag being built.
* `IMAGE_NAME`: the name and tag of the Docker repository being built. (This variable is a combination of `DOCKER_REPO:DOCKER_TAG`.)
-The current multi-arch image build relies on the original bitwarden_rs Dockerfiles, which use cross-compilation for architectures other than `amd64`, and don't yet support all arch/distro combinations. However, cross-compilation is much faster than QEMU-based builds (e.g., using `docker buildx`). This situation may need to be revisited at some point.
+The current multi-arch image build relies on the original vaultwarden Dockerfiles, which use cross-compilation for architectures other than `amd64`, and don't yet support all arch/distro combinations. However, cross-compilation is much faster than QEMU-based builds (e.g., using `docker buildx`). This situation may need to be revisited at some point.
## References
diff --git a/hooks/build b/hooks/build
index eeead8b4..f18c58bf 100755
--- a/hooks/build
+++ b/hooks/build
@@ -22,7 +22,7 @@ fi
LABELS=(
# https://github.com/opencontainers/image-spec/blob/master/annotations.md
org.opencontainers.image.created="$(date --utc --iso-8601=seconds)"
- org.opencontainers.image.documentation="https://github.com/dani-garcia/bitwarden_rs/wiki"
+ org.opencontainers.image.documentation="https://github.com/dani-garcia/vaultwarden/wiki"
org.opencontainers.image.licenses="GPL-3.0-only"
org.opencontainers.image.revision="${SOURCE_COMMIT}"
org.opencontainers.image.source="${SOURCE_REPOSITORY_URL}"
diff --git a/hooks/push b/hooks/push
index 7b32da2e..f50e48b9 100755
--- a/hooks/push
+++ b/hooks/push
@@ -103,7 +103,7 @@ docker buildx build \
# (https://github.com/moby/moby/issues/41017).
#
# Note that we use `arm32v6` instead of `armv6` to be consistent with the
-# existing bitwarden_rs tags, which adhere to the naming conventions of the
+# existing vaultwarden tags, which adhere to the naming conventions of the
# Docker per-architecture repos (e.g., https://hub.docker.com/u/arm32v6).
# Unfortunately, these per-arch repo names aren't always consistent with the
# corresponding platform (OS/arch/variant) IDs, particularly in the case of
diff --git a/rust-toolchain b/rust-toolchain
index 4fb94d9b..8e3f2d47 100644
--- a/rust-toolchain
+++ b/rust-toolchain
@@ -1 +1 @@
-nightly-2021-02-22 \ No newline at end of file
+nightly-2021-04-14 \ No newline at end of file
diff --git a/rustfmt.toml b/rustfmt.toml
index 679c7ab8..630b42b2 100644
--- a/rustfmt.toml
+++ b/rustfmt.toml
@@ -1,2 +1,7 @@
version = "Two"
+edition = "2018"
max_width = 120
+newline_style = "Unix"
+use_small_heuristics = "Off"
+struct_lit_single_line = false
+overflow_delimited_expr = true
diff --git a/src/api/admin.rs b/src/api/admin.rs
index d484407a..6e168e7a 100644
--- a/src/api/admin.rs
+++ b/src/api/admin.rs
@@ -1,9 +1,8 @@
use once_cell::sync::Lazy;
use serde::de::DeserializeOwned;
use serde_json::Value;
-use std::{env, process::Command, time::Duration};
+use std::{env, time::Duration};
-use reqwest::{blocking::Client, header::USER_AGENT};
use rocket::{
http::{Cookie, Cookies, SameSite},
request::{self, FlashMessage, Form, FromRequest, Outcome, Request},
@@ -19,7 +18,7 @@ use crate::{
db::{backup_database, get_sql_server_version, models::*, DbConn, DbConnType},
error::{Error, MapResult},
mail,
- util::{format_naive_datetime_local, get_display_size, is_running_in_docker},
+ util::{format_naive_datetime_local, get_display_size, get_reqwest_client, is_running_in_docker},
CONFIG,
};
@@ -64,12 +63,8 @@ static DB_TYPE: Lazy<&str> = Lazy::new(|| {
.unwrap_or("Unknown")
});
-static CAN_BACKUP: Lazy<bool> = Lazy::new(|| {
- DbConnType::from_url(&CONFIG.database_url())
- .map(|t| t == DbConnType::sqlite)
- .unwrap_or(false)
- && Command::new("sqlite3").arg("-version").status().is_ok()
-});
+static CAN_BACKUP: Lazy<bool> =
+ Lazy::new(|| DbConnType::from_url(&CONFIG.database_url()).map(|t| t == DbConnType::sqlite).unwrap_or(false));
#[get("/")]
fn admin_disabled() -> &'static str {
@@ -142,7 +137,12 @@ fn admin_url(referer: Referer) -> String {
fn admin_login(flash: Option<FlashMessage>) -> ApiResult<Html<String>> {
// If there is an error, show it
let msg = flash.map(|msg| format!("{}: {}", msg.name(), msg.msg()));
- let json = json!({"page_content": "admin/login", "version": VERSION, "error": msg, "urlpath": CONFIG.domain_path()});
+ let json = json!({
+ "page_content": "admin/login",
+ "version": VERSION,
+ "error": msg,
+ "urlpath": CONFIG.domain_path()
+ });
// Return the page
let text = CONFIG.render_template(BASE_TEMPLATE, &json)?;
@@ -166,10 +166,7 @@ fn post_admin_login(
// If the token is invalid, redirect to login page
if !_validate_token(&data.token) {
error!("Invalid admin token. IP: {}", ip.ip);
- Err(Flash::error(
- Redirect::to(admin_url(referer)),
- "Invalid admin token, please try again.",
- ))
+ Err(Flash::error(Redirect::to(admin_url(referer)), "Invalid admin token, please try again."))
} else {
// If the token received is valid, generate JWT and save it as a cookie
let claims = generate_admin_claims();
@@ -329,7 +326,8 @@ fn get_users_json(_token: AdminToken, conn: DbConn) -> Json<Value> {
fn users_overview(_token: AdminToken, conn: DbConn) -> ApiResult<Html<String>> {
let users = User::get_all(&conn);
let dt_fmt = "%Y-%m-%d %H:%M:%S %Z";
- let users_json: Vec<Value> = users.iter()
+ let users_json: Vec<Value> = users
+ .iter()
.map(|u| {
let mut usr = u.to_json(&conn);
usr["cipher_count"] = json!(Cipher::count_owned_by_user(&u.uuid, &conn));
@@ -339,7 +337,7 @@ fn users_overview(_token: AdminToken, conn: DbConn) -> ApiResult<Html<String>> {
usr["created_at"] = json!(format_naive_datetime_local(&u.created_at, dt_fmt));
usr["last_active"] = match u.last_active(&conn) {
Some(dt) => json!(format_naive_datetime_local(&dt, dt_fmt)),
- None => json!("Never")
+ None => json!("Never"),
};
usr
})
@@ -424,7 +422,6 @@ fn update_user_org_type(data: Json<UserOrgTypeData>, _token: AdminToken, conn: D
user_to_edit.save(&conn)
}
-
#[post("/users/update_revision")]
fn update_revision_users(_token: AdminToken, conn: DbConn) -> EmptyResult {
User::update_all_revisions(&conn)
@@ -433,7 +430,8 @@ fn update_revision_users(_token: AdminToken, conn: DbConn) -> EmptyResult {
#[get("/organizations/overview")]
fn organizations_overview(_token: AdminToken, conn: DbConn) -> ApiResult<Html<String>> {
let organizations = Organization::get_all(&conn);
- let organizations_json: Vec<Value> = organizations.iter()
+ let organizations_json: Vec<Value> = organizations
+ .iter()
.map(|o| {
let mut org = o.to_json();
org["user_count"] = json!(UserOrganization::count_by_org(&o.uuid, &conn));
@@ -470,26 +468,15 @@ struct GitCommit {
}
fn get_github_api<T: DeserializeOwned>(url: &str) -> Result<T, Error> {
- let github_api = Client::builder().build()?;
+ let github_api = get_reqwest_client();
- Ok(github_api
- .get(url)
- .timeout(Duration::from_secs(10))
- .header(USER_AGENT, "Bitwarden_RS")
- .send()?
- .error_for_status()?
- .json::<T>()?)
+ Ok(github_api.get(url).timeout(Duration::from_secs(10)).send()?.error_for_status()?.json::<T>()?)
}
fn has_http_access() -> bool {
- let http_access = Client::builder().build().unwrap();
-
- match http_access
- .head("https://github.com/dani-garcia/bitwarden_rs")
- .timeout(Duration::from_secs(10))
- .header(USER_AGENT, "Bitwarden_RS")
- .send()
- {
+ let http_access = get_reqwest_client();
+
+ match http_access.head("https://github.com/dani-garcia/vaultwarden").timeout(Duration::from_secs(10)).send() {
Ok(r) => r.status().is_success(),
_ => false,
}
@@ -502,9 +489,16 @@ fn diagnostics(_token: AdminToken, ip_header: IpHeader, conn: DbConn) -> ApiResu
use std::net::ToSocketAddrs;
// Get current running versions
- let vault_version_path = format!("{}/{}", CONFIG.web_vault_folder(), "version.json");
- let vault_version_str = read_file_string(&vault_version_path)?;
- let web_vault_version: WebVaultVersion = serde_json::from_str(&vault_version_str)?;
+ let web_vault_version: WebVaultVersion =
+ match read_file_string(&format!("{}/{}", CONFIG.web_vault_folder(), "bwrs-version.json")) {
+ Ok(s) => serde_json::from_str(&s)?,
+ _ => match read_file_string(&format!("{}/{}", CONFIG.web_vault_folder(), "version.json")) {
+ Ok(s) => serde_json::from_str(&s)?,
+ _ => WebVaultVersion {
+ version: String::from("Version file missing"),
+ },
+ },
+ };
// Execute some environment checks
let running_within_docker = is_running_in_docker();
@@ -524,11 +518,11 @@ fn diagnostics(_token: AdminToken, ip_header: IpHeader, conn: DbConn) -> ApiResu
// TODO: Maybe we need to cache this using a LazyStatic or something. Github only allows 60 requests per hour, and we use 3 here already.
let (latest_release, latest_commit, latest_web_build) = if has_http_access {
(
- match get_github_api::<GitRelease>("https://api.github.com/repos/dani-garcia/bitwarden_rs/releases/latest") {
+ match get_github_api::<GitRelease>("https://api.github.com/repos/dani-garcia/vaultwarden/releases/latest") {
Ok(r) => r.tag_name,
_ => "-".to_string(),
},
- match get_github_api::<GitCommit>("https://api.github.com/repos/dani-garcia/bitwarden_rs/commits/master") {
+ match get_github_api::<GitCommit>("https://api.github.com/repos/dani-garcia/vaultwarden/commits/main") {
Ok(mut c) => {
c.sha.truncate(8);
c.sha
@@ -540,7 +534,9 @@ fn diagnostics(_token: AdminToken, ip_header: IpHeader, conn: DbConn) -> ApiResu
if running_within_docker {
"-".to_string()
} else {
- match get_github_api::<GitRelease>("https://api.github.com/repos/dani-garcia/bw_web_builds/releases/latest") {
+ match get_github_api::<GitRelease>(
+ "https://api.github.com/repos/dani-garcia/bw_web_builds/releases/latest",
+ ) {
Ok(r) => r.tag_name.trim_start_matches('v').to_string(),
_ => "-".to_string(),
}
@@ -552,14 +548,15 @@ fn diagnostics(_token: AdminToken, ip_header: IpHeader, conn: DbConn) -> ApiResu
let ip_header_name = match &ip_header.0 {
Some(h) => h,
- _ => ""
+ _ => "",
};
let diagnostics_json = json!({
"dns_resolved": dns_resolved,
- "web_vault_version": web_vault_version.version,
"latest_release": latest_release,
"latest_commit": latest_commit,
+ "web_vault_enabled": &CONFIG.web_vault_enabled(),
+ "web_vault_version": web_vault_version.version,
"latest_web_build": latest_web_build,
"running_within_docker": running_within_docker,
"has_http_access": has_http_access,
@@ -571,6 +568,7 @@ fn diagnostics(_token: AdminToken, ip_header: IpHeader, conn: DbConn) -> ApiResu
"db_type": *DB_TYPE,
"db_version": get_sql_server_version(&conn),
"admin_url": format!("{}/diagnostics", admin_url(Referer(None))),
+ "server_time_local": Local::now().format("%Y-%m-%d %H:%M:%S %Z").to_string(),
"server_time": Utc::now().format("%Y-%m-%d %H:%M:%S UTC").to_string(), // Run the date/time check as the last item to minimize the difference
});
@@ -596,11 +594,11 @@ fn delete_config(_token: AdminToken) -> EmptyResult {
}
#[post("/config/backup_db")]
-fn backup_db(_token: AdminToken) -> EmptyResult {
+fn backup_db(_token: AdminToken, conn: DbConn) -> EmptyResult {
if *CAN_BACKUP {
- backup_database()
+ backup_database(&conn)
} else {
- err!("Can't back up current DB (either it's not SQLite or the 'sqlite' binary is not present)");
+ err!("Can't back up current DB (Only SQLite supports this feature)");
}
}
diff --git a/src/api/core/accounts.rs b/src/api/core/accounts.rs
index 6e45a947..3888075b 100644
--- a/src/api/core/accounts.rs
+++ b/src/api/core/accounts.rs
@@ -95,7 +95,7 @@ fn register(data: JsonUpcase<RegisterData>, conn: DbConn) -> EmptyResult {
}
None => {
// Order is important here; the invitation check must come first
- // because the bitwarden_rs admin can invite anyone, regardless
+ // because the vaultwarden admin can invite anyone, regardless
// of other signup restrictions.
if Invitation::take(&data.Email, &conn) || CONFIG.is_signup_allowed(&data.Email) {
User::new(data.Email.clone())
@@ -320,15 +320,7 @@ fn post_rotatekey(data: JsonUpcase<KeyData>, headers: Headers, conn: DbConn, nt:
err!("The cipher is not owned by the user")
}
- update_cipher_from_data(
- &mut saved_cipher,
- cipher_data,
- &headers,
- false,
- &conn,
- &nt,
- UpdateType::CipherUpdate,
- )?
+ update_cipher_from_data(&mut saved_cipher, cipher_data, &headers, false, &conn, &nt, UpdateType::CipherUpdate)?
}
// Update user data
diff --git a/src/api/core/ciphers.rs b/src/api/core/ciphers.rs
index 7b0de205..0f655f76 100644
--- a/src/api/core/ciphers.rs
+++ b/src/api/core/ciphers.rs
@@ -13,7 +13,7 @@ use crate::{
api::{self, EmptyResult, JsonResult, JsonUpcase, Notify, PasswordData, UpdateType},
auth::Headers,
crypto,
- db::{models::*, DbConn},
+ db::{models::*, DbConn, DbPool},
CONFIG,
};
@@ -25,7 +25,7 @@ pub fn routes() -> Vec<Route> {
// whether the user is an owner/admin of the relevant org, and if so,
// allows the operation unconditionally.
//
- // bitwarden_rs factors in the org owner/admin status as part of
+ // vaultwarden factors in the org owner/admin status as part of
// determining the write accessibility of a cipher, so most
// admin/non-admin implementations can be shared.
routes![
@@ -77,6 +77,15 @@ pub fn routes() -> Vec<Route> {
]
}
+pub fn purge_trashed_ciphers(pool: DbPool) {
+ debug!("Purging trashed ciphers");
+ if let Ok(conn) = pool.get() {
+ Cipher::purge_trash(&conn);
+ } else {
+ error!("Failed to get DB connection while purging trashed ciphers")
+ }
+}
+
#[derive(FromForm, Default)]
struct SyncData {
#[form(field = "excludeDomains")]
@@ -91,24 +100,18 @@ fn sync(data: Form<SyncData>, headers: Headers, conn: DbConn) -> Json<Value> {
let folders_json: Vec<Value> = folders.iter().map(Folder::to_json).collect();
let collections = Collection::find_by_user_uuid(&headers.user.uuid, &conn);
- let collections_json: Vec<Value> = collections.iter()
- .map(|c| c.to_json_details(&headers.user.uuid, &conn))
- .collect();
+ let collections_json: Vec<Value> =
+ collections.iter().map(|c| c.to_json_details(&headers.user.uuid, &conn)).collect();
let policies = OrgPolicy::find_by_user(&headers.user.uuid, &conn);
let policies_json: Vec<Value> = policies.iter().map(OrgPolicy::to_json).collect();
let ciphers = Cipher::find_by_user_visible(&headers.user.uuid, &conn);
- let ciphers_json: Vec<Value> = ciphers
- .iter()
- .map(|c| c.to_json(&headers.host, &headers.user.uuid, &conn))
- .collect();
+ let ciphers_json: Vec<Value> =
+ ciphers.iter().map(|c| c.to_json(&headers.host, &headers.user.uuid, &conn)).collect();
let sends = Send::find_by_user(&headers.user.uuid, &conn);
- let sends_json: Vec<Value> = sends
- .iter()
- .map(|s| s.to_json())
- .collect();
+ let sends_json: Vec<Value> = sends.iter().map(|s| s.to_json()).collect();
let domains_json = if data.exclude_domains {
Value::Null
@@ -124,6 +127,7 @@ fn sync(data: Form<SyncData>, headers: Headers, conn: DbConn) -> Json<Value> {
"Ciphers": ciphers_json,
"Domains": domains_json,
"Sends": sends_json,
+ "unofficialServer": true,
"Object": "sync"
}))
}
@@ -132,10 +136,8 @@ fn sync(data: Form<SyncData>, headers: Headers, conn: DbConn) -> Json<Value> {
fn get_ciphers(headers: Headers, conn: DbConn) -> Json<Value> {
let ciphers = Cipher::find_by_user_visible(&headers.user.uuid, &conn);
- let ciphers_json: Vec<Value> = ciphers
- .iter()
- .map(|c| c.to_json(&headers.host, &headers.user.uuid, &conn))
- .collect();
+ let ciphers_json: Vec<Value> =
+ ciphers.iter().map(|c| c.to_json(&headers.host, &headers.user.uuid, &conn)).collect();
Json(json!({
"Data": ciphers_json,
@@ -236,7 +238,7 @@ fn post_ciphers_create(data: JsonUpcase<ShareCipherData>, headers: Headers, conn
// Check if there are one more more collections selected when this cipher is part of an organization.
// err if this is not the case before creating an empty cipher.
- if data.Cipher.OrganizationId.is_some() && data.CollectionIds.is_empty() {
+ if data.Cipher.OrganizationId.is_some() && data.CollectionIds.is_empty() {
err!("You must select at least one collection.");
}
@@ -278,17 +280,12 @@ fn post_ciphers(data: JsonUpcase<CipherData>, headers: Headers, conn: DbConn, nt
/// allowed to delete or share such ciphers to an org, however.
///
/// Ref: https://bitwarden.com/help/article/policies/#personal-ownership
-fn enforce_personal_ownership_policy(
- data: &CipherData,
- headers: &Headers,
- conn: &DbConn
-) -> EmptyResult {
+fn enforce_personal_ownership_policy(data: &CipherData, headers: &Headers, conn: &DbConn) -> EmptyResult {
if data.OrganizationId.is_none() {
let user_uuid = &headers.user.uuid;
let policy_type = OrgPolicyType::PersonalOwnership;
if OrgPolicy::is_applicable_to_user(user_uuid, policy_type, conn) {
- err!("Due to an Enterprise Policy, you are restricted from \
- saving items to your personal vault.")
+ err!("Due to an Enterprise Policy, you are restricted from saving items to your personal vault.")
}
}
Ok(())
@@ -307,11 +304,12 @@ pub fn update_cipher_from_data(
// Check that the client isn't updating an existing cipher with stale data.
if let Some(dt) = data.LastKnownRevisionDate {
- match NaiveDateTime::parse_from_str(&dt, "%+") { // ISO 8601 format
- Err(err) =>
- warn!("Error parsing LastKnownRevisionDate '{}': {}", dt, err),
- Ok(dt) if cipher.updated_at.signed_duration_since(dt).num_seconds() > 1 =>
- err!("The client copy of this cipher is out of date. Resync the client and try again."),
+ match NaiveDateTime::parse_from_str(&dt, "%+") {
+ // ISO 8601 format
+ Err(err) => warn!("Error parsing LastKnownRevisionDate '{}': {}", dt, err),
+ Ok(dt) if cipher.updated_at.signed_duration_since(dt).num_seconds() > 1 => {
+ err!("The client copy of this cipher is out of date. Resync the client and try again.")
+ }
Ok(_) => (),
}
}
@@ -384,12 +382,9 @@ pub fn update_cipher_from_data(
// But, we at least know we do not need to store and return this specific key.
fn _clean_cipher_data(mut json_data: Value) -> Value {
if json_data.is_array() {
- json_data.as_array_mut()
- .unwrap()
- .iter_mut()
- .for_each(|ref mut f| {
- f.as_object_mut().unwrap().remove("Response");
- });
+ json_data.as_array_mut().unwrap().iter_mut().for_each(|ref mut f| {
+ f.as_object_mut().unwrap().remove("Response");
+ });
};
json_data
}
@@ -411,13 +406,13 @@ pub fn update_cipher_from_data(
data["Uris"] = _clean_cipher_data(data["Uris"].clone());
}
data
- },
+ }
None => err!("Data missing"),
};
cipher.name = data.Name;
cipher.notes = data.Notes;
- cipher.fields = data.Fields.map(|f| _clean_cipher_data(f).to_string() );
+ cipher.fields = data.Fields.map(|f| _clean_cipher_data(f).to_string());
cipher.data = type_data.to_string();
cipher.password_history = data.PasswordHistory.map(|f| f.to_string());
@@ -592,11 +587,8 @@ fn post_collections_admin(
}
let posted_collections: HashSet<String> = data.CollectionIds.iter().cloned().collect();
- let current_collections: HashSet<String> = cipher
- .get_collections(&headers.user.uuid, &conn)
- .iter()
- .cloned()
- .collect();
+ let current_collections: HashSet<String> =
+ cipher.get_collections(&headers.user.uuid, &conn).iter().cloned().collect();
for collection in posted_collections.symmetric_difference(&current_collections) {
match Collection::find_by_uuid(&collection, &conn) {
@@ -832,24 +824,25 @@ fn post_attachment(
let file_name = HEXLOWER.encode(&crypto::get_random(vec![0; 10]));
let path = base_path.join(&file_name);
- let size = match field.data.save().memory_threshold(0).size_limit(size_limit).with_path(path.clone()) {
- SaveResult::Full(SavedData::File(_, size)) => size as i32,
- SaveResult::Full(other) => {
- std::fs::remove_file(path).ok();
- error = Some(format!("Attachment is not a file: {:?}", other));
- return;
- }
- SaveResult::Partial(_, reason) => {
- std::fs::remove_file(path).ok();
- error = Some(format!("Attachment size limit exceeded with this file: {:?}", reason));
- return;
- }
- SaveResult::Error(e) => {
- std::fs::remove_file(path).ok();
- error = Some(format!("Error: {:?}", e));
- return;
- }
- };
+ let size =
+ match field.data.save().memory_threshold(0).size_limit(size_limit).with_path(path.clone()) {
+ SaveResult::Full(SavedData::File(_, size)) => size as i32,
+ SaveResult::Full(other) => {
+ std::fs::remove_file(path).ok();
+ error = Some(format!("Attachment is not a file: {:?}", other));
+ return;
+ }
+ SaveResult::Partial(_, reason) => {
+ std::fs::remove_file(path).ok();
+ error = Some(format!("Attachment size limit exceeded with this file: {:?}", reason));
+ return;
+ }
+ SaveResult::Error(e) => {
+ std::fs::remove_file(path).ok();
+ error = Some(format!("Error: {:?}", e));
+ return;
+ }
+ };
let mut attachment = Attachment::new(file_name, cipher.uuid.clone(), name, size);
attachment.akey = attachment_key.clone();
@@ -984,12 +977,22 @@ fn delete_cipher_selected_admin(data: JsonUpcase<Value>, headers: Headers, conn:
}
#[post("/ciphers/delete-admin", data = "<data>")]
-fn delete_cipher_selected_post_admin(data: JsonUpcase<Value>, headers: Headers, conn: DbConn, nt: Notify) -> EmptyResult {
+fn delete_cipher_selected_post_admin(
+ data: JsonUpcase<Value>,
+ headers: Headers,
+ conn: DbConn,
+ nt: Notify,
+) -> EmptyResult {
delete_cipher_selected_post(data, headers, conn, nt)
}
#[put("/ciphers/delete-admin", data = "<data>")]
-fn delete_cipher_selected_put_admin(data: JsonUpcase<Value>, headers: Headers, conn: DbConn, nt: Notify) -> EmptyResult {
+fn delete_cipher_selected_put_admin(
+ data: JsonUpcase<Value>,
+ headers: Headers,
+ conn: DbConn,
+ nt: Notify,
+) -> EmptyResult {
delete_cipher_selected_put(data, headers, conn, nt)
}
@@ -1140,7 +1143,13 @@ fn _delete_cipher_by_uuid(uuid: &str, headers: &Headers, conn: &DbConn, soft_del
Ok(())
}
-fn _delete_multiple_ciphers(data: JsonUpcase<Value>, headers: Headers, conn: DbConn, soft_delete: bool, nt: Notify) -> EmptyResult {
+fn _delete_multiple_ciphers(
+ data: JsonUpcase<Value>,
+ headers: Headers,
+ conn: DbConn,
+ soft_delete: bool,
+ nt: Notify,
+) -> EmptyResult {
let data: Value = data.into_inner().data;
let uuids = match data.get("Ids") {
@@ -1192,7 +1201,7 @@ fn _restore_multiple_ciphers(data: JsonUpcase<Value>, headers: &Headers, conn: &
for uuid in uuids {
match _restore_cipher_by_uuid(uuid, headers, conn, nt) {
Ok(json) => ciphers.push(json.into_inner()),
- err => return err
+ err => return err,
}
}
diff --git a/src/api/core/folders.rs b/src/api/core/folders.rs
index 2779fe61..57ec7f18 100644
--- a/src/api/core/folders.rs
+++ b/src/api/core/folders.rs
@@ -8,15 +8,7 @@ use crate::{
};
pub fn routes() -> Vec<rocket::Route> {
- routes![
- get_folders,
- get_folder,
- post_folders,
- post_folder,
- put_folder,
- delete_folder_post,
- delete_folder,
- ]
+ routes![get_folders, get_folder, post_folders, post_folder, put_folder, delete_folder_post, delete_folder,]
}
#[get("/folders")]
diff --git a/src/api/core/mod.rs b/src/api/core/mod.rs
index 36e83f0e..6f9db9bc 100644
--- a/src/api/core/mod.rs
+++ b/src/api/core/mod.rs
@@ -2,20 +2,15 @@ mod accounts;
mod ciphers;
mod folders;
mod organizations;
-pub mod two_factor;
mod sends;
+pub mod two_factor;
-pub use sends::start_send_deletion_scheduler;
+pub use ciphers::purge_trashed_ciphers;
+pub use sends::purge_sends;
pub fn routes() -> Vec<Route> {
- let mut mod_routes = routes![
- clear_device_token,
- put_device_token,
- get_eq_domains,
- post_eq_domains,
- put_eq_domains,
- hibp_breach,
- ];
+ let mut mod_routes =
+ routes![clear_device_token, put_device_token, get_eq_domains, post_eq_domains, put_eq_domains, hibp_breach,];
let mut routes = Vec::new();
routes.append(&mut accounts::routes());
@@ -32,9 +27,9 @@ pub fn routes() -> Vec<Route> {
//
// Move this somewhere else
//
+use rocket::response::Response;
use rocket::Route;
use rocket_contrib::json::Json;
-use rocket::response::Response;
use serde_json::Value;
use crate::{
@@ -42,6 +37,7 @@ use crate::{
auth::Headers,
db::DbConn,
error::Error,
+ util::get_reqwest_client,
};
#[put("/devices/identifier/<uuid>/clear-token")]
@@ -146,22 +142,15 @@ fn put_eq_domains(data: JsonUpcase<EquivDomainData>, headers: Headers, conn: DbC
#[get("/hibp/breach?<username>")]
fn hibp_breach(username: String) -> JsonResult {
- let user_agent = "Bitwarden_RS";
let url = format!(
"https://haveibeenpwned.com/api/v3/breachedaccount/{}?truncateResponse=false&includeUnverified=false",
username
);
- use reqwest::{blocking::Client, header::USER_AGENT};
-
if let Some(api_key) = crate::CONFIG.hibp_api_key() {
- let hibp_client = Client::builder().build()?;
+ let hibp_client = get_reqwest_client();
- let res = hibp_client
- .get(&url)
- .header(USER_AGENT, user_agent)
- .header("hibp-api-key", api_key)
- .send()?;
+ let res = hibp_client.get(&url).header("hibp-api-key", api_key).send()?;
// If we get a 404, return a 404, it means no breached accounts
if res.status() == 404 {
diff --git a/src/api/core/organizations.rs b/src/api/core/organizations.rs
index 5698c187..cfe3932e 100644
--- a/src/api/core/organizations.rs
+++ b/src/api/core/organizations.rs
@@ -5,7 +5,7 @@ use serde_json::Value;
use crate::{
api::{EmptyResult, JsonResult, JsonUpcase, JsonUpcaseVec, Notify, NumberOrString, PasswordData, UpdateType},
- auth::{decode_invite, AdminHeaders, Headers, OwnerHeaders, ManagerHeaders, ManagerHeadersLoose},
+ auth::{decode_invite, AdminHeaders, Headers, ManagerHeaders, ManagerHeadersLoose, OwnerHeaders},
db::{models::*, DbConn},
mail, CONFIG,
};
@@ -333,7 +333,12 @@ fn post_organization_collection_delete_user(
}
#[delete("/organizations/<org_id>/collections/<col_id>")]
-fn delete_organization_collection(org_id: String, col_id: String, _headers: ManagerHeaders, conn: DbConn) -> EmptyResult {
+fn delete_organization_collection(
+ org_id: String,
+ col_id: String,
+ _headers: ManagerHeaders,
+ conn: DbConn,
+) -> EmptyResult {
match Collection::find_by_uuid(&col_id, &conn) {
None => err!("Collection not found"),
Some(collection) => {
@@ -426,9 +431,7 @@ fn put_collection_users(
continue;
}
- CollectionUser::save(&user.user_uuid, &coll_id,
- d.ReadOnly, d.HidePasswords,
- &conn)?;
+ CollectionUser::save(&user.user_uuid, &coll_id, d.ReadOnly, d.HidePasswords, &conn)?;
}
Ok(())
@@ -443,10 +446,8 @@ struct OrgIdData {
#[get("/ciphers/organization-details?<data..>")]
fn get_org_details(data: Form<OrgIdData>, headers: Headers, conn: DbConn) -> Json<Value> {
let ciphers = Cipher::find_by_org(&data.organization_id, &conn);
- let ciphers_json: Vec<Value> = ciphers
- .iter()
- .map(|c| c.to_json(&headers.host, &headers.user.uuid, &conn))
- .collect();
+ let ciphers_json: Vec<Value> =
+ ciphers.iter().map(|c| c.to_json(&headers.host, &headers.user.uuid, &conn)).collect();
Json(json!({
"Data": ciphers_json,
@@ -544,9 +545,7 @@ fn send_invite(org_id: String, data: JsonUpcase<InviteData>, headers: AdminHeade
match Collection::find_by_uuid_and_org(&col.Id, &org_id, &conn) {
None => err!("Collection not found in Organization"),
Some(collection) => {
- CollectionUser::save(&user.uuid, &collection.uuid,
- col.ReadOnly, col.HidePasswords,
- &conn)?;
+ CollectionUser::save(&user.uuid, &collection.uuid, col.ReadOnly, col.HidePasswords, &conn)?;
}
}
}
@@ -801,9 +800,13 @@ fn edit_user(
match Collection::find_by_uuid_and_org(&col.Id, &org_id, &conn) {
None => err!("Collection not found in Organization"),
Some(collection) => {
- CollectionUser::save(&user_to_edit.user_uuid, &collection.uuid,
- col.ReadOnly, col.HidePasswords,
- &conn)?;
+ CollectionUser::save(
+ &user_to_edit.user_uuid,
+ &collection.uuid,
+ col.ReadOnly,
+ col.HidePasswords,
+ &conn,
+ )?;
}
}
}
@@ -899,16 +902,8 @@ fn post_org_import(
.into_iter()
.map(|cipher_data| {
let mut cipher = Cipher::new(cipher_data.Type, cipher_data.Name.clone());
- update_cipher_from_data(
- &mut cipher,
- cipher_data,
- &headers,
- false,
- &conn,
- &nt,
- UpdateType::CipherCreate,
- )
- .ok();
+ update_cipher_from_data(&mut cipher, cipher_data, &headers, false, &conn, &nt, UpdateType::CipherCreate)
+ .ok();
cipher
})
.collect();
@@ -989,7 +984,13 @@ struct PolicyData {
}
#[put("/organizations/<org_id>/policies/<pol_type>", data = "<data>")]
-fn put_policy(org_id: String, pol_type: i32, data: Json<PolicyData>, _headers: AdminHeaders, conn: DbConn) -> JsonResult {
+fn put_policy(
+ org_id: String,
+ pol_type: i32,
+ data: Json<PolicyData>,
+ _headers: AdminHeaders,
+ conn: DbConn,
+) -> JsonResult {
let data: PolicyData = data.into_inner();
let pol_type_enum = match OrgPolicyType::from_i32(pol_type) {
@@ -1127,8 +1128,7 @@ fn import(org_id: String, data: JsonUpcase<OrgImportData>, headers: Headers, con
// If user is not part of the organization, but it exists
} else if UserOrganization::find_by_email_and_org(&user_data.Email, &org_id, &conn).is_none() {
- if let Some (user) = User::find_by_mail(&user_data.Email, &conn) {
-
+ if let Some(user) = User::find_by_mail(&user_data.Email, &conn) {
let user_org_status = if CONFIG.mail_enabled() {
UserOrgStatus::Invited as i32
} else {
@@ -1164,7 +1164,7 @@ fn import(org_id: String, data: JsonUpcase<OrgImportData>, headers: Headers, con
// If this flag is enabled, any user that isn't provided in the Users list will be removed (by default they will be kept unless they have Deleted == true)
if data.OverwriteExisting {
for user_org in UserOrganization::find_by_org_and_type(&org_id, UserOrgType::User as i32, &conn) {
- if let Some (user_email) = User::find_by_uuid(&user_org.user_uuid, &conn).map(|u| u.email) {
+ if let Some(user_email) = User::find_by_uuid(&user_org.user_uuid, &conn).map(|u| u.email) {
if !data.Users.iter().any(|u| u.Email == user_email) {
user_org.delete(&conn)?;
}
diff --git a/src/api/core/sends.rs b/src/api/core/sends.rs
index ec6809a2..4cedf055 100644
--- a/src/api/core/sends.rs
+++ b/src/api/core/sends.rs
@@ -9,39 +9,23 @@ use serde_json::Value;
use crate::{
api::{ApiResult, EmptyResult, JsonResult, JsonUpcase, Notify, UpdateType},
auth::{Headers, Host},
- db::{models::*, DbConn},
+ db::{models::*, DbConn, DbPool},
CONFIG,
};
const SEND_INACCESSIBLE_MSG: &str = "Send does not exist or is no longer available";
pub fn routes() -> Vec<rocket::Route> {
- routes![
- post_send,
- post_send_file,
- post_access,
- post_access_file,
- put_send,
- delete_send,
- put_remove_password
- ]
+ routes![post_send, post_send_file, post_access, post_access_file, put_send, delete_send, put_remove_password]
}
-pub fn start_send_deletion_scheduler(pool: crate::db::DbPool) {
- std::thread::spawn(move || {
- loop {
- if let Ok(conn) = pool.get() {
- info!("Initiating send deletion");
- for send in Send::find_all(&conn) {
- if chrono::Utc::now().naive_utc() >= send.deletion_date {
- send.delete(&conn).ok();
- }
- }
- }
-
- std::thread::sleep(std::time::Duration::from_secs(3600));
- }
- });
+pub fn purge_sends(pool: DbPool) {
+ debug!("Purging sends");
+ if let Ok(conn) = pool.get() {
+ Send::purge(&conn);
+ } else {
+ error!("Failed to get DB connection while purging sends")
+ }
}
#[derive(Deserialize)]
@@ -179,13 +163,7 @@ fn post_send_file(data: Data, content_type: &ContentType, headers: Headers, conn
None => err!("No model entry present"),
};
- let size = match data_entry
- .data
- .save()
- .memory_threshold(0)
- .size_limit(size_limit)
- .with_path(&file_path)
- {
+ let size = match data_entry.data.save().memory_threshold(0).size_limit(size_limit).with_path(&file_path) {
SaveResult::Full(SavedData::File(_, size)) => size as i32,
SaveResult::Full(other) => {
std::fs::remove_file(&file_path).ok();
@@ -206,10 +184,7 @@ fn post_send_file(data: Data, content_type: &ContentType, headers: Headers, conn
if let Some(o) = data_value.as_object_mut() {
o.insert(String::from("Id"), Value::String(file_id));
o.insert(String::from("Size"), Value::Number(size.into()));
- o.insert(
- String::from("SizeName"),
- Value::String(crate::util::get_display_size(size)),
- );
+ o.insert(String::from("SizeName"), Value::String(crate::util::get_display_size(size)));
}
send.data = serde_json::to_string(&data_value)?;
diff --git a/src/api/core/two_factor/authenticator.rs b/src/api/core/two_factor/authenticator.rs
index f4bd5df5..2d076b27 100644
--- a/src/api/core/two_factor/authenticator.rs
+++ b/src/api/core/two_factor/authenticator.rs
@@ -17,11 +17,7 @@ use crate::{
pub use crate::config::CONFIG;
pub fn routes() -> Vec<Route> {
- routes![
- generate_authenticator,
- activate_authenticator,
- activate_authenticator_put,
- ]
+ routes![generate_authenticator, activate_authenticator, activate_authenticator_put,]
}
#[post("/two-factor/get-authenticator", data = "<data>")]
@@ -141,7 +137,7 @@ pub fn validate_totp_code(user_uuid: &str, totp_code: u64, secret: &str, ip: &Cl
// The amount of steps back and forward in time
// Also check if we need to disable time drifted TOTP codes.
// If that is the case, we set the steps to 0 so only the current TOTP is valid.
- let steps: i64 = if CONFIG.authenticator_disable_time_drift() { 0 } else { 1 };
+ let steps = !CONFIG.authenticator_disable_time_drift() as i64;
for step in -steps..=steps {
let time_step = current_timestamp / 30i64 + step;
@@ -163,22 +159,11 @@ pub fn validate_totp_code(user_uuid: &str, totp_code: u64, secret: &str, ip: &Cl
twofactor.save(&conn)?;
return Ok(());
} else if generated == totp_code && time_step <= twofactor.last_used as i64 {
- warn!(
- "This or a TOTP code within {} steps back and forward has already been used!",
- steps
- );
- err!(format!(
- "Invalid TOTP code! Server time: {} IP: {}",
- current_time.format("%F %T UTC"),
- ip.ip
- ));
+ warn!("This or a TOTP code within {} steps back and forward has already been used!", steps);
+ err!(format!("Invalid TOTP code! Server time: {} IP: {}", current_time.format("%F %T UTC"), ip.ip));
}
}
// Else no valide code received, deny access
- err!(format!(
- "Invalid TOTP code! Server time: {} IP: {}",
- current_time.format("%F %T UTC"),
- ip.ip
- ));
+ err!(format!("Invalid TOTP code! Server time: {} IP: {}", current_time.format("%F %T UTC"), ip.ip));
}
diff --git a/src/api/core/two_factor/duo.rs b/src/api/core/two_factor/duo.rs
index 18eda4b2..5ca87085 100644
--- a/src/api/core/two_factor/duo.rs
+++ b/src/api/core/two_factor/duo.rs
@@ -12,6 +12,7 @@ use crate::{
DbConn,
},
error::MapResult,
+ util::get_reqwest_client,
CONFIG,
};
@@ -59,7 +60,11 @@ impl DuoData {
ik.replace_range(digits.., replaced);
sk.replace_range(digits.., replaced);
- Self { host, ik, sk }
+ Self {
+ host,
+ ik,
+ sk,
+ }
}
}
@@ -185,9 +190,7 @@ fn activate_duo_put(data: JsonUpcase<EnableDuoData>, headers: Headers, conn: DbC
}
fn duo_api_request(method: &str, path: &str, params: &str, data: &DuoData) -> EmptyResult {
- const AGENT: &str = "bitwarden_rs:Duo/1.0 (Rust)";
-
- use reqwest::{blocking::Client, header::*, Method};
+ use reqwest::{header, Method};
use std::str::FromStr;
// https://duo.com/docs/authapi#api-details
@@ -199,11 +202,13 @@ fn duo_api_request(method: &str, path: &str, params: &str, data: &DuoData) -> Em
let m = Method::from_str(method).unwrap_or_default();
- Client::new()
+ let client = get_reqwest_client();
+
+ client
.request(m, &url)
.basic_auth(username, Some(password))
- .header(USER_AGENT, AGENT)
- .header(DATE, date)
+ .header(header::USER_AGENT, "vaultwarden:Duo/1.0 (Rust)")
+ .header(header::DATE, date)
.send()?
.error_for_status()?;
diff --git a/src/api/core/two_factor/email.rs b/src/api/core/two_factor/email.rs
index 6aa6e013..c47f9498 100644
--- a/src/api/core/two_factor/email.rs
+++ b/src/api/core/two_factor/email.rs
@@ -125,11 +125,7 @@ fn send_email(data: JsonUpcase<SendEmailData>, headers: Headers, conn: DbConn) -
let twofactor_data = EmailTokenData::new(data.Email, generated_token);
// Uses EmailVerificationChallenge as type to show that it's not verified yet.
- let twofactor = TwoFactor::new(
- user.uuid,
- TwoFactorType::EmailVerificationChallenge,
- twofactor_data.to_json(),
- );
+ let twofactor = TwoFactor::new(user.uuid, TwoFactorType::EmailVerificationChallenge, twofactor_data.to_json());
twofactor.save(&conn)?;
mail::send_token(&twofactor_data.email, &twofactor_data.last_token.map_res("Token is empty")?)?;
@@ -186,7 +182,8 @@ fn email(data: JsonUpcase<EmailData>, headers: Headers, conn: DbConn) -> JsonRes
/// Validate the email code when used as TwoFactor token mechanism
pub fn validate_email_code_str(user_uuid: &str, token: &str, data: &str, conn: &DbConn) -> EmptyResult {
let mut email_data = EmailTokenData::from_json(&data)?;
- let mut twofactor = TwoFactor::find_by_user_and_type(&user_uuid, TwoFactorType::Email as i32, &conn).map_res("Two factor not found")?;
+ let mut twofactor = TwoFactor::find_by_user_and_type(&user_uuid, TwoFactorType::Email as i32, &conn)
+ .map_res("Two factor not found")?;
let issued_token = match &email_data.last_token {
Some(t) => t,
_ => err!("No token available"),
diff --git a/src/api/core/two_factor/mod.rs b/src/api/core/two_factor/mod.rs
index a3dfd319..0d0d2bd2 100644
--- a/src/api/core/two_factor/mod.rs
+++ b/src/api/core/two_factor/mod.rs
@@ -20,13 +20,7 @@ pub mod u2f;
pub mod yubikey;
pub fn routes() -> Vec<Route> {
- let mut routes = routes![
- get_twofactor,
- get_recover,
- recover,
- disable_twofactor,
- disable_twofactor_put,
- ];
+ let mut routes = routes![get_twofactor, get_recover, recover, disable_twofactor, disable_twofactor_put,];
routes.append(&mut authenticator::routes());
routes.append(&mut duo::routes());
diff --git a/src/api/core/two_factor/u2f.rs b/src/api/core/two_factor/u2f.rs
index f841240b..3455beab 100644
--- a/src/api/core/two_factor/u2f.rs
+++ b/src/api/core/two_factor/u2f.rs
@@ -28,13 +28,7 @@ static APP_ID: Lazy<String> = Lazy::new(|| format!("{}/app-id.json", &CONFIG.dom
static U2F: Lazy<U2f> = Lazy::new(|| U2f::new(APP_ID.clone()));
pub fn routes() -> Vec<Route> {
- routes![
- generate_u2f,
- generate_u2f_challenge,
- activate_u2f,
- activate_u2f_put,
- delete_u2f,
- ]
+ routes![generate_u2f, generate_u2f_challenge, activate_u2f, activate_u2f_put, delete_u2f,]
}
#[post("/two-factor/get-u2f", data = "<data>")]
@@ -161,10 +155,7 @@ fn activate_u2f(data: JsonUpcase<EnableU2FData>, headers: Headers, conn: DbConn)
let response: RegisterResponseCopy = serde_json::from_str(&data.DeviceResponse)?;
- let error_code = response
- .error_code
- .clone()
- .map_or("0".into(), NumberOrString::into_string);
+ let error_code = response.error_code.clone().map_or("0".into(), NumberOrString::into_string);
if error_code != "0" {
err!("Error registering U2F token")
@@ -300,20 +291,13 @@ fn _old_parse_registrations(registations: &str) -> Vec<Registration> {
let regs: Vec<Value> = serde_json::from_str(registations).expect("Can't parse Registration data");
- regs.into_iter()
- .map(|r| serde_json::from_value(r).unwrap())
- .map(|Helper(r)| r)
- .collect()
+ regs.into_iter().map(|r| serde_json::from_value(r).unwrap()).map(|Helper(r)| r).collect()
}
pub fn generate_u2f_login(user_uuid: &str, conn: &DbConn) -> ApiResult<U2fSignRequest> {
let challenge = _create_u2f_challenge(user_uuid, TwoFactorType::U2fLoginChallenge, conn);
- let registrations: Vec<_> = get_u2f_registrations(user_uuid, conn)?
- .1
- .into_iter()
- .map(|r| r.reg)
- .collect();
+ let registrations: Vec<_> = get_u2f_registrations(user_uuid, conn)?.1.into_iter().map(|r| r.reg).collect();
if registrations.is_empty() {
err!("No U2F devices registered")
diff --git a/src/api/icons.rs b/src/api/icons.rs
index 747569c6..33849bbb 100644
--- a/src/api/icons.rs
+++ b/src/api/icons.rs
@@ -12,14 +12,16 @@ use regex::Regex;
use reqwest::{blocking::Client, blocking::Response, header, Url};
use rocket::{http::ContentType, http::Cookie, response::Content, Route};
-use crate::{error::Error, util::Cached, CONFIG};
+use crate::{
+ error::Error,
+ util::{get_reqwest_client_builder, Cached},
+ CONFIG,
+};
pub fn routes() -> Vec<Route> {
routes![icon]
}
-const ALLOWED_CHARS: &str = "_-.";
-
static CLIENT: Lazy<Client> = Lazy::new(|| {
// Generate the default headers
let mut default_headers = header::HeaderMap::new();
@@ -27,31 +29,47 @@ static CLIENT: Lazy<Client> = Lazy::new(|| {
default_headers.insert(header::ACCEPT_LANGUAGE, header::HeaderValue::from_static("en-US,en;q=0.8"));
default_headers.insert(header::CACHE_CONTROL, header::HeaderValue::from_static("no-cache"));
default_headers.insert(header::PRAGMA, header::HeaderValue::from_static("no-cache"));
- default_headers.insert(header::ACCEPT, header::HeaderValue::from_static("text/html,application/xhtml+xml,application/xml; q=0.9,image/webp,image/apng,*/*;q=0.8"));
+ default_headers.insert(
+ header::ACCEPT,
+ header::HeaderValue::from_static(
+ "text/html,application/xhtml+xml,application/xml; q=0.9,image/webp,image/apng,*/*;q=0.8",
+ ),
+ );
// Reuse the client between requests
- Client::builder()
+ get_reqwest_client_builder()
.timeout(Duration::from_secs(CONFIG.icon_download_timeout()))
.default_headers(default_headers)
.build()
- .unwrap()
+ .expect("Failed to build icon client")
});
// Build Regex only once since this takes a lot of time.
static ICON_REL_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"(?i)icon$|apple.*icon").unwrap());
+static ICON_REL_BLACKLIST: Lazy<Regex> = Lazy::new(|| Regex::new(r"(?i)mask-icon").unwrap());
static ICON_SIZE_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"(?x)(\d+)\D*(\d+)").unwrap());
// Special HashMap which holds the user defined Regex to speedup matching the regex.
static ICON_BLACKLIST_REGEX: Lazy<RwLock<HashMap<String, Regex>>> = Lazy::new(|| RwLock::new(HashMap::new()));
#[get("/<domain>/icon.png")]
-fn icon(domain: String) -> Option<Cached<Content<Vec<u8>>>> {
+fn icon(domain: String) -> Cached<Content<Vec<u8>>> {
+ const FALLBACK_ICON: &[u8] = include_bytes!("../static/images/fallback-icon.png");
+
if !is_valid_domain(&domain) {
warn!("Invalid domain: {}", domain);
- return None;
+ return Cached::ttl(
+ Content(ContentType::new("image", "png"), FALLBACK_ICON.to_vec()),
+ CONFIG.icon_cache_negttl(),
+ );
}
- get_icon(&domain).map(|icon| Cached::ttl(Content(ContentType::new("image", "x-icon"), icon), CONFIG.icon_cache_ttl()))
+ match get_icon(&domain) {
+ Some((icon, icon_type)) => {
+ Cached::ttl(Content(ContentType::new("image", icon_type), icon), CONFIG.icon_cache_ttl())
+ }
+ _ => Cached::ttl(Content(ContentType::new("image", "png"), FALLBACK_ICON.to_vec()), CONFIG.icon_cache_negttl()),
+ }
}
/// Returns if the domain provided is valid or not.
@@ -59,6 +77,8 @@ fn icon(domain: String) -> Option<Cached<Content<Vec<u8>>>> {
/// This does some manual checks and makes use of Url to do some basic checking.
/// domains can't be larger then 63 characters (not counting multiple subdomains) according to the RFC's, but we limit the total size to 255.
fn is_valid_domain(domain: &str) -> bool {
+ const ALLOWED_CHARS: &str = "_-.";
+
// If parsing the domain fails using Url, it will not work with reqwest.
if let Err(parse_error) = Url::parse(format!("https://{}", domain).as_str()) {
debug!("Domain parse error: '{}' - {:?}", domain, parse_error);
@@ -69,7 +89,10 @@ fn is_valid_domain(domain: &str) -> bool {
|| domain.starts_with('-')
|| domain.ends_with('-')
{
- debug!("Domain validation error: '{}' is either empty, contains '..', starts with an '.', starts or ends with a '-'", domain);
+ debug!(
+ "Domain validation error: '{}' is either empty, contains '..', starts with an '.', starts or ends with a '-'",
+ domain
+ );
return false;
} else if domain.len() > 255 {
debug!("Domain validation error: '{}' exceeds 255 characters", domain);
@@ -238,7 +261,7 @@ fn is_domain_blacklisted(domain: &str) -> bool {
is_blacklisted
}
-fn get_icon(domain: &str) -> Option<Vec<u8>> {
+fn get_icon(domain: &str) -> Option<(Vec<u8>, String)> {
let path = format!("{}/{}.png", CONFIG.icon_cache_folder(), domain);
// Check for expiration of negatively cached copy
@@ -247,7 +270,11 @@ fn get_icon(domain: &str) -> Option<Vec<u8>> {
}
if let Some(icon) = get_cached_icon(&path) {
- return Some(icon);
+ let icon_type = match get_icon_type(&icon) {
+ Some(x) => x,
+ _ => "x-icon",
+ };
+ return Some((icon, icon_type.to_string()));
}
if CONFIG.disable_icon_download() {
@@ -256,9 +283,9 @@ fn get_icon(domain: &str) -> Option<Vec<u8>> {
// Get the icon, or None in case of error
match download_icon(&domain) {
- Ok(icon) => {
+ Ok((icon, icon_type)) => {
save_icon(&path, &icon);
- Some(icon)
+ Some((icon, icon_type.unwrap_or("x-icon").to_string()))
}
Err(e) => {
error!("Error downloading icon: {:?}", e);
@@ -319,7 +346,6 @@ fn icon_is_expired(path: &str) -> bool {
expired.unwrap_or(true)
}
-#[derive(Debug)]
struct Icon {
priority: u8,
href: String,
@@ -327,12 +353,20 @@ struct Icon {
impl Icon {
const fn new(priority: u8, href: String) -> Self {
- Self { href, priority }
+ Self {
+ href,
+ priority,
+ }
}
}
fn get_favicons_node(node: &std::rc::Rc<markup5ever_rcdom::Node>, icons: &mut Vec<Icon>, url: &Url) {
- if let markup5ever_rcdom::NodeData::Element { name, attrs, .. } = &node.data {
+ if let markup5ever_rcdom::NodeData::Element {
+ name,
+ attrs,
+ ..
+ } = &node.data
+ {
if name.local.as_ref() == "link" {
let mut has_rel = false;
let mut href = None;
@@ -343,7 +377,8 @@ fn get_favicons_node(node: &std::rc::Rc<markup5ever_rcdom::Node>, icons: &mut Ve
let attr_name = attr.name.local.as_ref();
let attr_value = attr.value.as_ref();
- if attr_name == "rel" && ICON_REL_REGEX.is_match(attr_value) {
+ if attr_name == "rel" && ICON_REL_REGEX.is_match(attr_value) && !ICON_REL_BLACKLIST.is_match(attr_value)
+ {
has_rel = true;
} else if attr_name == "href" {
href = Some(attr_value);
@@ -486,10 +521,10 @@ fn get_icon_url(domain: &str) -> Result<IconUrlResult, Error> {
iconlist.sort_by_key(|x| x.priority);
// There always is an icon in the list, so no need to check if it exists, and just return the first one
- Ok(IconUrlResult{
+ Ok(IconUrlResult {
iconlist,
cookies: cookie_str,
- referer
+ referer,
})
}
@@ -510,9 +545,7 @@ fn get_page_with_cookies(url: &str, cookie_str: &str, referer: &str) -> Result<R
client = client.header("Referer", referer)
}
- client.send()?
- .error_for_status()
- .map_err(Into::into)
+ client.send()?.error_for_status().map_err(Into::into)
}
/// Returns a Integer with the priority of the type of the icon which to prefer.
@@ -594,7 +627,7 @@ fn parse_sizes(sizes: Option<&str>) -> (u16, u16) {
(width, height)
}
-fn download_icon(domain: &str) -> Result<Vec<u8>, Error> {
+fn download_icon(domain: &str) -> Result<(Vec<u8>, Option<&str>), Error> {
if is_domain_blacklisted(domain) {
err!("Domain is blacklisted", domain)
}
@@ -602,6 +635,7 @@ fn download_icon(domain: &str) -> Result<Vec<u8>, Error> {
let icon_result = get_icon_url(&domain)?;
let mut buffer = Vec::new();
+ let mut icon_type: Option<&str> = None;
use data_url::DataUrl;
@@ -613,29 +647,43 @@ fn download_icon(domain: &str) -> Result<Vec<u8>, Error> {
Ok((body, _fragment)) => {
// Also check if the size is atleast 67 bytes, which seems to be the smallest png i could create
if body.len() >= 67 {
+ // Check if the icon type is allowed, else try an icon from the list.
+ icon_type = get_icon_type(&body);
+ if icon_type.is_none() {
+ debug!("Icon from {} data:image uri, is not a valid image type", domain);
+ continue;
+ }
+ info!("Extracted icon from data:image uri for {}", domain);
buffer = body;
break;
}
}
- _ => warn!("data uri is invalid"),
+ _ => warn!("Extracted icon from data:image uri is invalid"),
};
} else {
match get_page_with_cookies(&icon.href, &icon_result.cookies, &icon_result.referer) {
Ok(mut res) => {
- info!("Downloaded icon from {}", icon.href);
res.copy_to(&mut buffer)?;
+ // Check if the icon type is allowed, else try an icon from the list.
+ icon_type = get_icon_type(&buffer);
+ if icon_type.is_none() {
+ buffer.clear();
+ debug!("Icon from {}, is not a valid image type", icon.href);
+ continue;
+ }
+ info!("Downloaded icon from {}", icon.href);
break;
- },
+ }
_ => warn!("Download failed for {}", icon.href),
};
}
}
if buffer.is_empty() {
- err!("Empty response")
+ err!("Empty response downloading icon")
}
- Ok(buffer)
+ Ok((buffer, icon_type))
}
fn save_icon(path: &str, icon: &[u8]) {
@@ -647,7 +695,18 @@ fn save_icon(path: &str, icon: &[u8]) {
create_dir_all(&CONFIG.icon_cache_folder()).expect("Error creating icon cache");
}
Err(e) => {
- info!("Icon save error: {:?}", e);
+ warn!("Icon save error: {:?}", e);
}
}
}
+
+fn get_icon_type(bytes: &[u8]) -> Option<&'static str> {
+ match bytes {
+ [137, 80, 78, 71, ..] => Some("png"),
+ [0, 0, 1, 0, ..] => Some("x-icon"),
+ [82, 73, 70, 70, ..] => Some("webp"),
+ [255, 216, 255, ..] => Some("jpeg"),
+ [66, 77, ..] => Some("bmp"),
+ _ => None,
+ }
+}
diff --git a/src/api/identity.rs b/src/api/identity.rs
index dcfe607a..31f686c2 100644
--- a/src/api/identity.rs
+++ b/src/api/identity.rs
@@ -72,7 +72,8 @@ fn _refresh_login(data: ConnectData, conn: DbConn) -> JsonResult {
"Kdf": user.client_kdf_type,
"KdfIterations": user.client_kdf_iter,
"ResetMasterPassword": false, // TODO: according to official server seems something like: user.password_hash.is_empty(), but would need testing
- "scope": "api offline_access"
+ "scope": "api offline_access",
+ "unofficialServer": true,
})))
}
@@ -87,34 +88,28 @@ fn _password_login(data: ConnectData, conn: DbConn, ip: &ClientIp) -> JsonResult
let username = data.username.as_ref().unwrap();
let user = match User::find_by_mail(username, &conn) {
Some(user) => user,
- None => err!(
- "Username or password is incorrect. Try again",
- format!("IP: {}. Username: {}.", ip.ip, username)
- ),
+ None => err!("Username or password is incorrect. Try again", format!("IP: {}. Username: {}.", ip.ip, username)),
};
// Check password
let password = data.password.as_ref().unwrap();
if !user.check_valid_password(password) {
- err!(
- "Username or password is incorrect. Try again",
- format!("IP: {}. Username: {}.", ip.ip, username)
- )
+ err!("Username or password is incorrect. Try again", format!("IP: {}. Username: {}.", ip.ip, username))
}
// Check if the user is disabled
if !user.enabled {
- err!(
- "This user has been disabled",
- format!("IP: {}. Username: {}.", ip.ip, username)
- )
+ err!("This user has been disabled", format!("IP: {}. Username: {}.", ip.ip, username))
}
let now = Local::now();
if user.verified_at.is_none() && CONFIG.mail_enabled() && CONFIG.signups_verify() {
let now = now.naive_utc();
- if user.last_verifying_at.is_none() || now.signed_duration_since(user.last_verifying_at.unwrap()).num_seconds() > CONFIG.signups_verify_resend_time() as i64 {
+ if user.last_verifying_at.is_none()
+ || now.signed_duration_since(user.last_verifying_at.unwrap()).num_seconds()
+ > CONFIG.signups_verify_resend_time() as i64
+ {
let resend_limit = CONFIG.signups_verify_resend_limit() as i32;
if resend_limit == 0 || user.login_verify_count < resend_limit {
// We want to send another email verification if we require signups to verify
@@ -134,10 +129,7 @@ fn _password_login(data: ConnectData, conn: DbConn, ip: &ClientIp) -> JsonResult
}
// We still want the login to fail until they actually verified the email address
- err!(
- "Please verify your email before trying again.",
- format!("IP: {}. Username: {}.", ip.ip, username)
- )
+ err!("Please verify your email before trying again.", format!("IP: {}. Username: {}.", ip.ip, username))
}
let (mut device, new_device) = get_device(&data, &conn, &user);
@@ -168,11 +160,12 @@ fn _password_login(data: ConnectData, conn: DbConn, ip: &ClientIp) -> JsonResult
"Key": user.akey,
"PrivateKey": user.private_key,
//"TwoFactorToken": "11122233333444555666777888999"
-
+
"Kdf": user.client_kdf_type,
"KdfIterations": user.client_kdf_iter,
"ResetMasterPassword": false,// TODO: Same as above
- "scope": "api offline_access"
+ "scope": "api offline_access",
+ "unofficialServer": true,
});
if let Some(token) = twofactor_token {
@@ -234,9 +227,7 @@ fn twofactor_auth(
None => err_json!(_json_err_twofactor(&twofactor_ids, user_uuid, conn)?, "2FA token not provided"),
};
- let selected_twofactor = twofactors
- .into_iter()
- .find(|tf| tf.atype == selected_id && tf.enabled);
+ let selected_twofactor = twofactors.into_iter().find(|tf| tf.atype == selected_id && tf.enabled);
use crate::api::core::two_factor as _tf;
use crate::crypto::ct_eq;
@@ -245,18 +236,26 @@ fn twofactor_auth(
let mut remember = data.two_factor_remember.unwrap_or(0);
match TwoFactorType::from_i32(selected_id) {
- Some(TwoFactorType::Authenticator) => _tf::authenticator::validate_totp_code_str(user_uuid, twofactor_code, &selected_data?, ip, conn)?,
+ Some(TwoFactorType::Authenticator) => {
+ _tf::authenticator::validate_totp_code_str(user_uuid, twofactor_code, &selected_data?, ip, conn)?
+ }
Some(TwoFactorType::U2f) => _tf::u2f::validate_u2f_login(user_uuid, twofactor_code, conn)?,
Some(TwoFactorType::YubiKey) => _tf::yubikey::validate_yubikey_login(twofactor_code, &selected_data?)?,
- Some(TwoFactorType::Duo) => _tf::duo::validate_duo_login(data.username.as_ref().unwrap(), twofactor_code, conn)?,
- Some(TwoFactorType::Email) => _tf::email::validate_email_code_str(user_uuid, twofactor_code, &selected_data?, conn)?,
+ Some(TwoFactorType::Duo) => {
+ _tf::duo::validate_duo_login(data.username.as_ref().unwrap(), twofactor_code, conn)?
+ }
+ Some(TwoFactorType::Email) => {
+ _tf::email::validate_email_code_str(user_uuid, twofactor_code, &selected_data?, conn)?
+ }
Some(TwoFactorType::Remember) => {
match device.twofactor_remember {
Some(ref code) if !CONFIG.disable_2fa_remember() && ct_eq(code, twofactor_code) => {
remember = 1; // Make sure we also return the token here, otherwise it will only remember the first time
}
- _ => err_json!(_json_err_twofactor(&twofactor_ids, user_uuid, conn)?, "2FA Remember token not provided"),
+ _ => {
+ err_json!(_json_err_twofactor(&twofactor_ids, user_uuid, conn)?, "2FA Remember token not provided")
+ }
}
}
_ => err!("Invalid two factor provider"),
diff --git a/src/api/mod.rs b/src/api/mod.rs
index 840c65ff..7312aeec 100644
--- a/src/api/mod.rs
+++ b/src/api/mod.rs
@@ -10,8 +10,9 @@ use serde_json::Value;
pub use crate::api::{
admin::routes as admin_routes,
+ core::purge_sends,
+ core::purge_trashed_ciphers,
core::routes as core_routes,
- core::start_send_deletion_scheduler,
icons::routes as icons_routes,
identity::routes as identity_routes,
notifications::routes as notifications_routes,
@@ -54,9 +55,9 @@ impl NumberOrString {
use std::num::ParseIntError as PIE;
match self {
NumberOrString::Number(n) => Ok(n),
- NumberOrString::String(s) => s
- .parse()
- .map_err(|e: PIE| crate::Error::new("Can't convert to number", e.to_string())),
+ NumberOrString::String(s) => {
+ s.parse().map_err(|e: PIE| crate::Error::new("Can't convert to number", e.to_string()))
+ }
}
}
}
diff --git a/src/api/notifications.rs b/src/api/notifications.rs
index 8876937d..a64ea9d8 100644
--- a/src/api/notifications.rs
+++ b/src/api/notifications.rs
@@ -4,12 +4,7 @@ use rocket::Route;
use rocket_contrib::json::Json;
use serde_json::Value as JsonValue;
-use crate::{
- api::EmptyResult,
- auth::Headers,
- db::DbConn,
- Error, CONFIG,
-};
+use crate::{api::EmptyResult, auth::Headers, db::DbConn, Error, CONFIG};
pub fn routes() -> Vec<Route> {
routes![negotiate, websockets_err]
@@ -19,12 +14,16 @@ static SHOW_WEBSOCKETS_MSG: AtomicBool = AtomicBool::new(true);
#[get("/hub")]
fn websockets_err() -> EmptyResult {
- if CONFIG.websocket_enabled() && SHOW_WEBSOCKETS_MSG.compare_exchange(true, false, Ordering::Relaxed, Ordering::Relaxed).is_ok() {
- err!("
+ if CONFIG.websocket_enabled()
+ && SHOW_WEBSOCKETS_MSG.compare_exchange(true, false, Ordering::Relaxed, Ordering::Relaxed).is_ok()
+ {
+ err!(
+ "
###########################################################
'/notifications/hub' should be proxied to the websocket server or notifications won't work.
Go to the Wiki for more info, or disable WebSockets setting WEBSOCKET_ENABLED=false.
- ###########################################################################################\n")
+ ###########################################################################################\n"
+ )
} else {
Err(Error::empty())
}
@@ -204,9 +203,7 @@ impl Handler for WsHandler {
let handler_insert = self.out.clone();
let handler_update = self.out.clone();
- self.users
- .map
- .upsert(user_uuid, || vec![handler_insert], |ref mut v| v.push(handler_update));
+ self.users.map.upsert(user_uuid, || vec![handler_insert], |ref mut v| v.push(handler_update));
// Schedule a ping to keep the connection alive
self.out.timeout(PING_MS, PING)
@@ -216,7 +213,11 @@ impl Handler for WsHandler {
if let Message::Text(text) = msg.clone() {
let json = &text[..text.len() - 1]; // Remove last char
- if let Ok(InitialMessage { protocol, version }) = from_str::<InitialMessage>(json) {
+ if let Ok(InitialMessage {
+ protocol,
+ version,
+ }) = from_str::<InitialMessage>(json)
+ {
if &protocol == "messagepack" && version == 1 {
return self.out.send(&INITIAL_RESPONSE[..]); // Respond to initial message
}
@@ -295,10 +296,7 @@ impl WebSocketUsers {
// NOTE: The last modified date needs to be updated before calling these methods
pub fn send_user_update(&self, ut: UpdateType, user: &User) {
let data = create_update(
- vec![
- ("UserId".into(), user.uuid.clone().into()),
- ("Date".into(), serialize_date(user.updated_at)),
- ],
+ vec![("UserId".into(), user.uuid.clone().into()), ("Date".into(), serialize_date(user.updated_at))],
ut,
);
diff --git a/src/api/web.rs b/src/api/web.rs
index 90e572a8..29c64ae4 100644
--- a/src/api/web.rs
+++ b/src/api/web.rs
@@ -83,11 +83,15 @@ fn static_files(filename: String) -> Result<Content<&'static [u8]>, Error> {
"hibp.png" => Ok(Content(ContentType::PNG, include_bytes!("../static/images/hibp.png"))),
"bootstrap.css" => Ok(Content(ContentType::CSS, include_bytes!("../static/scripts/bootstrap.css"))),
- "bootstrap-native.js" => Ok(Content(ContentType::JavaScript, include_bytes!("../static/scripts/bootstrap-native.js"))),
+ "bootstrap-native.js" => {
+ Ok(Content(ContentType::JavaScript, include_bytes!("../static/scripts/bootstrap-native.js")))
+ }
"identicon.js" => Ok(Content(ContentType::JavaScript, include_bytes!("../static/scripts/identicon.js"))),
"datatables.js" => Ok(Content(ContentType::JavaScript, include_bytes!("../static/scripts/datatables.js"))),
"datatables.css" => Ok(Content(ContentType::CSS, include_bytes!("../static/scripts/datatables.css"))),
- "jquery-3.5.1.slim.js" => Ok(Content(ContentType::JavaScript, include_bytes!("../static/scripts/jquery-3.5.1.slim.js"))),
+ "jquery-3.5.1.slim.js" => {
+ Ok(Content(ContentType::JavaScript, include_bytes!("../static/scripts/jquery-3.5.1.slim.js")))
+ }
_ => err!(format!("Static file not found: {}", filename)),
}
}
diff --git a/src/auth.rs b/src/auth.rs
index 59d1370d..516583c0 100644
--- a/src/auth.rs
+++ b/src/auth.rs
@@ -223,10 +223,9 @@ use crate::db::{
};
pub struct Host {
- pub host: String
+ pub host: String,
}
-
impl<'a, 'r> FromRequest<'a, 'r> for Host {
type Error = &'static str;
@@ -261,7 +260,9 @@ impl<'a, 'r> FromRequest<'a, 'r> for Host {
format!("{}://{}", protocol, host)
};
- Outcome::Success(Host { host })
+ Outcome::Success(Host {
+ host,
+ })
}
}
@@ -317,10 +318,8 @@ impl<'a, 'r> FromRequest<'a, 'r> for Headers {
};
if user.security_stamp != claims.sstamp {
- if let Some(stamp_exception) = user
- .stamp_exception
- .as_deref()
- .and_then(|s| serde_json::from_str::<UserStampException>(s).ok())
+ if let Some(stamp_exception) =
+ user.stamp_exception.as_deref().and_then(|s| serde_json::from_str::<UserStampException>(s).ok())
{
let current_route = match request.route().and_then(|r| r.name) {
Some(name) => name,
@@ -338,7 +337,11 @@ impl<'a, 'r> FromRequest<'a, 'r> for Headers {
}
}
- Outcome::Success(Headers { host, device, user })
+ Outcome::Success(Headers {
+ host,
+ device,
+ user,
+ })
}
}
@@ -506,7 +509,11 @@ impl<'a, 'r> FromRequest<'a, 'r> for ManagerHeaders {
};
if !headers.org_user.has_full_access() {
- match CollectionUser::find_by_collection_and_user(&col_id, &headers.org_user.user_uuid, &conn) {
+ match CollectionUser::find_by_collection_and_user(
+ &col_id,
+ &headers.org_user.user_uuid,
+ &conn,
+ ) {
Some(_) => (),
None => err_handler!("The current user isn't a manager for this collection"),
}
@@ -636,10 +643,10 @@ impl<'a, 'r> FromRequest<'a, 'r> for ClientIp {
None
};
- let ip = ip
- .or_else(|| req.remote().map(|r| r.ip()))
- .unwrap_or_else(|| "0.0.0.0".parse().unwrap());
+ let ip = ip.or_else(|| req.remote().map(|r| r.ip())).unwrap_or_else(|| "0.0.0.0".parse().unwrap());
- Outcome::Success(ClientIp { ip })
+ Outcome::Success(ClientIp {
+ ip,
+ })
}
}
diff --git a/src/config.rs b/src/config.rs
index 6c41c975..fa7db32c 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -316,6 +316,17 @@ make_config! {
/// Websocket port
websocket_port: u16, false, def, 3012;
},
+ jobs {
+ /// Job scheduler poll interval |> How often the job scheduler thread checks for jobs to run.
+ /// Set to 0 to globally disable scheduled jobs.
+ job_poll_interval_ms: u64, false, def, 30_000;
+ /// Send purge schedule |> Cron schedule of the job that checks for Sends past their deletion date.
+ /// Defaults to hourly. Set blank to disable this job.
+ send_purge_schedule: String, false, def, "0 5 * * * *".to_string();
+ /// Trash purge schedule |> Cron schedule of the job that checks for trashed items to delete permanently.
+ /// Defaults to daily. Set blank to disable this job.
+ trash_purge_schedule: String, false, def, "0 5 0 * * *".to_string();
+ },
/// General settings
settings {
@@ -339,11 +350,16 @@ make_config! {
/// Per-organization attachment limit (KB) |> Limit in kilobytes for an organization attachments, once the limit is exceeded it won't be possible to upload more
org_attachment_limit: i64, true, option;
+ /// Trash auto-delete days |> Number of days to wait before auto-deleting a trashed item.
+ /// If unset, trashed items are not auto-deleted. This setting applies globally, so make
+ /// sure to inform all users of any changes to this setting.
+ trash_auto_delete_days: i64, true, option;
+
/// Disable icon downloads |> Set to true to disable icon downloading, this would still serve icons from
/// $ICON_CACHE_FOLDER, but it won't produce any external network request. Needs to set $ICON_CACHE_TTL to 0,
/// otherwise it will delete them and they won't be downloaded again.
disable_icon_download: bool, true, def, false;
- /// Allow new signups |> Controls whether new users can register. Users can be invited by the bitwarden_rs admin even if this is disabled
+ /// Allow new signups |> Controls whether new users can register. Users can be invited by the vaultwarden admin even if this is disabled
signups_allowed: bool, true, def, true;
/// Require email verification on signups. This will prevent logins from succeeding until the address has been verified
signups_verify: bool, true, def, false;
@@ -369,7 +385,7 @@ make_config! {
admin_token: Pass, true, option;
/// Invitation organization name |> Name shown in the invitation emails that don't come from a specific organization
- invitation_org_name: String, true, def, "Bitwarden_RS".to_string();
+ invitation_org_name: String, true, def, "Vaultwarden".to_string();
},
/// Advanced settings
@@ -418,7 +434,7 @@ make_config! {
/// Log level
log_level: String, false, def, "Info".to_string();
- /// Enable DB WAL |> Turning this off might lead to worse performance, but might help if using bitwarden_rs on some exotic filesystems,
+ /// Enable DB WAL |> Turning this off might lead to worse performance, but might help if using vaultwarden on some exotic filesystems,
/// that do not support WAL. Please make sure you read project wiki on the topic before changing this setting.
enable_db_wal: bool, false, def, true;
@@ -473,7 +489,7 @@ make_config! {
/// From Address
smtp_from: String, true, def, String::new();
/// From Name
- smtp_from_name: String, true, def, "Bitwarden_RS".to_string();
+ smtp_from_name: String, true, def, "Vaultwarden".to_string();
/// Username
smtp_username: String, true, option;
/// Password
@@ -511,10 +527,7 @@ fn validate_config(cfg: &ConfigItems) -> Result<(), Error> {
let limit = 256;
if cfg.database_max_conns < 1 || cfg.database_max_conns > limit {
- err!(format!(
- "`DATABASE_MAX_CONNS` contains an invalid value. Ensure it is between 1 and {}.",
- limit,
- ));
+ err!(format!("`DATABASE_MAX_CONNS` contains an invalid value. Ensure it is between 1 and {}.", limit,));
}
let dom = cfg.domain.to_lowercase();
@@ -855,9 +868,7 @@ fn case_helper<'reg, 'rc>(
rc: &mut RenderContext<'reg, 'rc>,
out: &mut dyn Output,
) -> HelperResult {
- let param = h
- .param(0)
- .ok_or_else(|| RenderError::new("Param not found for helper \"case\""))?;
+ let param = h.param(0).ok_or_else(|| RenderError::new("Param not found for helper \"case\""))?;
let value = param.value().clone();
if h.params().iter().skip(1).any(|x| x.value() == &value) {
@@ -874,21 +885,15 @@ fn js_escape_helper<'reg, 'rc>(
_rc: &mut RenderContext<'reg, 'rc>,
out: &mut dyn Output,
) -> HelperResult {
- let param = h
- .param(0)
- .ok_or_else(|| RenderError::new("Param not found for helper \"js_escape\""))?;
+ let param = h.param(0).ok_or_else(|| RenderError::new("Param not found for helper \"js_escape\""))?;
- let no_quote = h
- .param(1)
- .is_some();
+ let no_quote = h.param(1).is_some();
- let value = param
- .value()
- .as_str()
- .ok_or_else(|| RenderError::new("Param for helper \"js_escape\" is not a String"))?;
+ let value =
+ param.value().as_str().ok_or_else(|| RenderError::new("Param for helper \"js_escape\" is not a String"))?;
let mut escaped_value = value.replace('\\', "").replace('\'', "\\x22").replace('\"', "\\x27");
- if ! no_quote {
+ if !no_quote {
escaped_value = format!("&quot;{}&quot;", escaped_value);
}
diff --git a/src/crypto.rs b/src/crypto.rs
index ecff2ce0..43b8fc7d 100644
--- a/src/crypto.rs
+++ b/src/crypto.rs
@@ -47,9 +47,7 @@ pub fn get_random_64() -> Vec<u8> {
pub fn get_random(mut array: Vec<u8>) -> Vec<u8> {
use ring::rand::{SecureRandom, SystemRandom};
- SystemRandom::new()
- .fill(&mut array)
- .expect("Error generating random values");
+ SystemRandom::new().fill(&mut array).expect("Error generating random values");
array
}
diff --git a/src/db/mod.rs b/src/db/mod.rs
index 19191582..5ab4ba36 100644
--- a/src/db/mod.rs
+++ b/src/db/mod.rs
@@ -1,5 +1,3 @@
-use std::process::Command;
-
use chrono::prelude::*;
use diesel::r2d2::{ConnectionManager, Pool, PooledConnection};
use rocket::{
@@ -25,7 +23,6 @@ pub mod __mysql_schema;
#[path = "schemas/postgresql/schema.rs"]
pub mod __postgresql_schema;
-
// This is used to generate the main DbConn and DbPool enums, which contain one variant for each database supported
macro_rules! generate_connections {
( $( $name:ident: $ty:ty ),+ ) => {
@@ -110,7 +107,6 @@ impl DbConnType {
}
}
-
#[macro_export]
macro_rules! db_run {
// Same for all dbs
@@ -144,6 +140,7 @@ macro_rules! db_run {
// Different code for each db
( @raw $conn:ident: $( $($db:ident),+ $body:block )+ ) => {
#[allow(unused)] use diesel::prelude::*;
+ #[allow(unused_variables)]
match $conn {
$($(
#[cfg($db)]
@@ -155,7 +152,6 @@ macro_rules! db_run {
};
}
-
pub trait FromDb {
type Output;
#[allow(clippy::wrong_self_convention)]
@@ -221,51 +217,35 @@ macro_rules! db_object {
// Reexport the models, needs to be after the macros are defined so it can access them
pub mod models;
-/// Creates a back-up of the database using sqlite3
-pub fn backup_database() -> Result<(), Error> {
- use std::path::Path;
- let db_url = CONFIG.database_url();
- let db_path = Path::new(&db_url).parent().unwrap();
-
- let now: DateTime<Utc> = Utc::now();
- let file_date = now.format("%Y%m%d").to_string();
- let backup_command: String = format!("{}{}{}", ".backup 'db_", file_date, ".sqlite3'");
-
- Command::new("sqlite3")
- .current_dir(db_path)
- .args(&["db.sqlite3", &backup_command])
- .output()
- .expect("Can't open database, sqlite3 is not available, make sure it's installed and available on the PATH");
+/// Creates a back-up of the sqlite database
+/// MySQL/MariaDB and PostgreSQL are not supported.
+pub fn backup_database(conn: &DbConn) -> Result<(), Error> {
+ db_run! {@raw conn:
+ postgresql, mysql {
+ err!("PostgreSQL and MySQL/MariaDB do not support this backup feature");
+ }
+ sqlite {
+ use std::path::Path;
+ let db_url = CONFIG.database_url();
+ let db_path = Path::new(&db_url).parent().unwrap().to_string_lossy();
+ let file_date = Utc::now().format("%Y%m%d_%H%M%S").to_string();
+ diesel::sql_query(format!("VACUUM INTO '{}/db_{}.sqlite3'", db_path, file_date)).execute(conn)?;
+ }
+ }
Ok(())
}
-
-use diesel::sql_types::Text;
-#[derive(QueryableByName,Debug)]
-struct SqlVersion {
- #[sql_type = "Text"]
- version: String,
-}
-
/// Get the SQL Server version
pub fn get_sql_server_version(conn: &DbConn) -> String {
db_run! {@raw conn:
postgresql, mysql {
- match diesel::sql_query("SELECT version() AS version;").get_result::<SqlVersion>(conn).ok() {
- Some(v) => {
- v.version
- },
- _ => "Unknown".to_string()
- }
+ no_arg_sql_function!(version, diesel::sql_types::Text);
+ diesel::select(version).get_result::<String>(conn).unwrap_or_else(|_| "Unknown".to_string())
}
sqlite {
- match diesel::sql_query("SELECT sqlite_version() AS version;").get_result::<SqlVersion>(conn).ok() {
- Some(v) => {
- v.version
- },
- _ => "Unknown".to_string()
- }
+ no_arg_sql_function!(sqlite_version, diesel::sql_types::Text);
+ diesel::select(sqlite_version).get_result::<String>(conn).unwrap_or_else(|_| "Unknown".to_string())
}
}
}
@@ -308,8 +288,7 @@ mod sqlite_migrations {
use diesel::{Connection, RunQueryDsl};
// Make sure the database is up to date (create if it doesn't exist, or run the migrations)
- let connection =
- diesel::sqlite::SqliteConnection::establish(&crate::CONFIG.database_url())?;
+ let connection = diesel::sqlite::SqliteConnection::establish(&crate::CONFIG.database_url())?;
// Disable Foreign Key Checks during migration
// Scoped to a connection.
@@ -319,9 +298,7 @@ mod sqlite_migrations {
// Turn on WAL in SQLite
if crate::CONFIG.enable_db_wal() {
- diesel::sql_query("PRAGMA journal_mode=wal")
- .execute(&connection)
- .expect("Failed to turn on WAL");
+ diesel::sql_query("PRAGMA journal_mode=wal").execute(&connection).expect("Failed to turn on WAL");
}
embedded_migrations::run_with_output(&connection, &mut std::io::stdout())?;
@@ -337,8 +314,7 @@ mod mysql_migrations {
pub fn run_migrations() -> Result<(), super::Error> {
use diesel::{Connection, RunQueryDsl};
// Make sure the database is up to date (create if it doesn't exist, or run the migrations)
- let connection =
- diesel::mysql::MysqlConnection::establish(&crate::CONFIG.database_url())?;
+ let connection = diesel::mysql::MysqlConnection::establish(&crate::CONFIG.database_url())?;
// Disable Foreign Key Checks during migration
// Scoped to a connection/session.
@@ -359,8 +335,7 @@ mod postgresql_migrations {
pub fn run_migrations() -> Result<(), super::Error> {
use diesel::{Connection, RunQueryDsl};
// Make sure the database is up to date (create if it doesn't exist, or run the migrations)
- let connection =
- diesel::pg::PgConnection::establish(&crate::CONFIG.database_url())?;
+ let connection = diesel::pg::PgConnection::establish(&crate::CONFIG.database_url())?;
// Disable Foreign Key Checks during migration
// FIXME: Per https://www.postgresql.org/docs/12/sql-set-constraints.html,
diff --git a/src/db/models/attachment.rs b/src/db/models/attachment.rs
index 6a8fc5b0..76bc474e 100644
--- a/src/db/models/attachment.rs
+++ b/src/db/models/attachment.rs
@@ -59,7 +59,6 @@ use crate::error::MapResult;
/// Database methods
impl Attachment {
-
pub fn save(&self, conn: &DbConn) -> EmptyResult {
db_run! { conn:
sqlite, mysql {
diff --git a/src/db/models/cipher.rs b/src/db/models/cipher.rs
index 365865f8..09247c44 100644
--- a/src/db/models/cipher.rs
+++ b/src/db/models/cipher.rs
@@ -1,15 +1,10 @@
-use chrono::{NaiveDateTime, Utc};
+use chrono::{Duration, NaiveDateTime, Utc};
use serde_json::Value;
+use crate::CONFIG;
+
use super::{
- Attachment,
- CollectionCipher,
- Favorite,
- FolderCipher,
- Organization,
- User,
- UserOrgStatus,
- UserOrgType,
+ Attachment, CollectionCipher, Favorite, FolderCipher, Organization, User, UserOrgStatus, UserOrgType,
UserOrganization,
};
@@ -91,16 +86,16 @@ impl Cipher {
};
let fields_json = self.fields.as_ref().and_then(|s| serde_json::from_str(s).ok()).unwrap_or(Value::Null);
- let password_history_json = self.password_history.as_ref().and_then(|s| serde_json::from_str(s).ok()).unwrap_or(Value::Null);
+ let password_history_json =
+ self.password_history.as_ref().and_then(|s| serde_json::from_str(s).ok()).unwrap_or(Value::Null);
- let (read_only, hide_passwords) =
- match self.get_access_restrictions(&user_uuid, conn) {
- Some((ro, hp)) => (ro, hp),
- None => {
- error!("Cipher ownership assertion failure");
- (true, true)
- },
- };
+ let (read_only, hide_passwords) = match self.get_access_restrictions(&user_uuid, conn) {
+ Some((ro, hp)) => (ro, hp),
+ None => {
+ error!("Cipher ownership assertion failure");
+ (true, true)
+ }
+ };
// Get the type_data or a default to an empty json object '{}'.
// If not passing an empty object, mobile clients will crash.
@@ -130,7 +125,7 @@ impl Cipher {
// There are three types of cipher response models in upstream
// Bitwarden: "cipherMini", "cipher", and "cipherDetails" (in order
- // of increasing level of detail). bitwarden_rs currently only
+ // of increasing level of detail). vaultwarden currently only
// supports the "cipherDetails" type, though it seems like the
// Bitwarden clients will ignore extra fields.
//
@@ -195,12 +190,10 @@ impl Cipher {
None => {
// Belongs to Organization, need to update affected users
if let Some(ref org_uuid) = self.organization_uuid {
- UserOrganization::find_by_cipher_and_org(&self.uuid, &org_uuid, conn)
- .iter()
- .for_each(|user_org| {
- User::update_uuid_revision(&user_org.user_uuid, conn);
- user_uuids.push(user_org.user_uuid.clone())
- });
+ UserOrganization::find_by_cipher_and_org(&self.uuid, &org_uuid, conn).iter().for_each(|user_org| {
+ User::update_uuid_revision(&user_org.user_uuid, conn);
+ user_uuids.push(user_org.user_uuid.clone())
+ });
}
}
};
@@ -271,6 +264,17 @@ impl Cipher {
Ok(())
}
+ /// Purge all ciphers that are old enough to be auto-deleted.
+ pub fn purge_trash(conn: &DbConn) {
+ if let Some(auto_delete_days) = CONFIG.trash_auto_delete_days() {
+ let now = Utc::now().naive_utc();
+ let dt = now - Duration::days(auto_delete_days);
+ for cipher in Self::find_deleted_before(&dt, conn) {
+ cipher.delete(&conn).ok();
+ }
+ }
+ }
+
pub fn move_to_folder(&self, folder_uuid: Option<String>, user_uuid: &str, conn: &DbConn) -> EmptyResult {
User::update_uuid_revision(user_uuid, conn);
@@ -511,6 +515,15 @@ impl Cipher {
}}
}
+ /// Find all ciphers that were deleted before the specified datetime.
+ pub fn find_deleted_before(dt: &NaiveDateTime, conn: &DbConn) -> Vec<Self> {
+ db_run! {conn: {
+ ciphers::table
+ .filter(ciphers::deleted_at.lt(dt))
+ .load::<CipherDb>(conn).expect("Error loading ciphers").from_db()
+ }}
+ }
+
pub fn get_collections(&self, user_id: &str, conn: &DbConn) -> Vec<String> {
db_run! {conn: {
ciphers_collections::table
diff --git a/src/db/models/collection.rs b/src/db/models/collection.rs
index 5fbc3128..88e11c6e 100644
--- a/src/db/models/collection.rs
+++ b/src/db/models/collection.rs
@@ -1,6 +1,6 @@
use serde_json::Value;
-use super::{Organization, UserOrgStatus, UserOrgType, UserOrganization, User, Cipher};
+use super::{Cipher, Organization, User, UserOrgStatus, UserOrgType, UserOrganization};
db_object! {
#[derive(Identifiable, Queryable, Insertable, Associations, AsChangeset)]
@@ -127,11 +127,9 @@ impl Collection {
}
pub fn update_users_revision(&self, conn: &DbConn) {
- UserOrganization::find_by_collection_and_org(&self.uuid, &self.org_uuid, conn)
- .iter()
- .for_each(|user_org| {
- User::update_uuid_revision(&user_org.user_uuid, conn);
- });
+ UserOrganization::find_by_collection_and_org(&self.uuid, &self.org_uuid, conn).iter().for_each(|user_org| {
+ User::update_uuid_revision(&user_org.user_uuid, conn);
+ });
}
pub fn find_by_uuid(uuid: &str, conn: &DbConn) -> Option<Self> {
@@ -170,10 +168,7 @@ impl Collection {
}
pub fn find_by_organization_and_user_uuid(org_uuid: &str, user_uuid: &str, conn: &DbConn) -> Vec<Self> {
- Self::find_by_user_uuid(user_uuid, conn)
- .into_iter()
- .filter(|c| c.org_uuid == org_uuid)
- .collect()
+ Self::find_by_user_uuid(user_uuid, conn).into_iter().filter(|c| c.org_uuid == org_uuid).collect()
}
pub fn find_by_organization(org_uuid: &str, conn: &DbConn) -> Vec<Self> {
@@ -284,7 +279,13 @@ impl CollectionUser {
}}
}
- pub fn save(user_uuid: &str, collection_uuid: &str, read_only: bool, hide_passwords: bool, conn: &DbConn) -> EmptyResult {
+ pub fn save(
+ user_uuid: &str,
+ collection_uuid: &str,
+ read_only: bool,
+ hide_passwords: bool,
+ conn: &DbConn,
+ ) -> EmptyResult {
User::update_uuid_revision(&user_uuid, conn);
db_run! { conn:
@@ -374,11 +375,9 @@ impl CollectionUser {
}
pub fn delete_all_by_collection(collection_uuid: &str, conn: &DbConn) -> EmptyResult {
- CollectionUser::find_by_collection(&collection_uuid, conn)
- .iter()
- .for_each(|collection| {
- User::update_uuid_revision(&collection.user_uuid, conn);
- });
+ CollectionUser::find_by_collection(&collection_uuid, conn).iter().for_each(|collection| {
+ User::update_uuid_revision(&collection.user_uuid, conn);
+ });
db_run! { conn: {
diesel::delete(users_collections::table.filter(users_collections::collection_uuid.eq(collection_uuid)))
diff --git a/src/db/models/favorite.rs b/src/db/models/favorite.rs
index 4f610f21..2fc20380 100644
--- a/src/db/models/favorite.rs
+++ b/src/db/models/favorite.rs
@@ -20,7 +20,7 @@ use crate::error::MapResult;
impl Favorite {
// Returns whether the specified cipher is a favorite of the specified user.
pub fn is_favorite(cipher_uuid: &str, user_uuid: &str, conn: &DbConn) -> bool {
- db_run!{ conn: {
+ db_run! { conn: {
let query = favorites::table
.filter(favorites::cipher_uuid.eq(cipher_uuid))
.filter(favorites::user_uuid.eq(user_uuid))
@@ -36,19 +36,19 @@ impl Favorite {
match (old, new) {
(false, true) => {
User::update_uuid_revision(user_uuid, &conn);
- db_run!{ conn: {
- diesel::insert_into(favorites::table)
- .values((
- favorites::user_uuid.eq(user_uuid),
- favorites::cipher_uuid.eq(cipher_uuid),
- ))
- .execute(conn)
- .map_res("Error adding favorite")
- }}
+ db_run! { conn: {
+ diesel::insert_into(favorites::table)
+ .values((
+ favorites::user_uuid.eq(user_uuid),
+ favorites::cipher_uuid.eq(cipher_uuid),
+ ))
+ .execute(conn)
+ .map_res("Error adding favorite")
+ }}
}
(true, false) => {
User::update_uuid_revision(user_uuid, &conn);
- db_run!{ conn: {
+ db_run! { conn: {
diesel::delete(
favorites::table
.filter(favorites::user_uuid.eq(user_uuid))
@@ -59,7 +59,7 @@ impl Favorite {
}}
}
// Otherwise, the favorite status is already what it should be.
- _ => Ok(())
+ _ => Ok(()),
}
}
diff --git a/src/db/models/folder.rs b/src/db/models/folder.rs
index b5bbcc79..ec83d117 100644
--- a/src/db/models/folder.rs
+++ b/src/db/models/folder.rs
@@ -109,7 +109,6 @@ impl Folder {
User::update_uuid_revision(&self.user_uuid, conn);
FolderCipher::delete_all_by_folder(&self.uuid, &conn)?;
-
db_run! { conn: {
diesel::delete(folders::table.filter(folders::uuid.eq(&self.uuid)))
.execute(conn)
diff --git a/src/db/models/mod.rs b/src/db/models/mod.rs
index a4fb635b..2179b7f0 100644
--- a/src/db/models/mod.rs
+++ b/src/db/models/mod.rs
@@ -6,9 +6,9 @@ mod favorite;
mod folder;
mod org_policy;
mod organization;
+mod send;
mod two_factor;
mod user;
-mod send;
pub use self::attachment::Attachment;
pub use self::cipher::Cipher;
@@ -18,6 +18,6 @@ pub use self::favorite::Favorite;
pub use self::folder::{Folder, FolderCipher};
pub use self::org_policy::{OrgPolicy, OrgPolicyType};
pub use self::organization::{Organization, UserOrgStatus, UserOrgType, UserOrganization};
+pub use self::send::{Send, SendType};
pub use self::two_factor::{TwoFactor, TwoFactorType};
pub use self::user::{Invitation, User, UserStampException};
-pub use self::send::{Send, SendType}; \ No newline at end of file
diff --git a/src/db/models/org_policy.rs b/src/db/models/org_policy.rs
index 0707eccc..1a040fc1 100644
--- a/src/db/models/org_policy.rs
+++ b/src/db/models/org_policy.rs
@@ -4,7 +4,7 @@ use crate::api::EmptyResult;
use crate::db::DbConn;
use crate::error::MapResult;
-use super::{Organization, UserOrganization, UserOrgStatus, UserOrgType};
+use super::{Organization, UserOrgStatus, UserOrgType, UserOrganization};
db_object! {
#[derive(Identifiable, Queryable, Insertable, Associations, AsChangeset)]
@@ -20,8 +20,7 @@ db_object! {
}
}
-#[derive(Copy, Clone)]
-#[derive(num_derive::FromPrimitive)]
+#[derive(Copy, Clone, num_derive::FromPrimitive)]
pub enum OrgPolicyType {
TwoFactorAuthentication = 0,
MasterPassword = 1,
@@ -175,7 +174,8 @@ impl OrgPolicy {
/// and the user is not an owner or admin of that org. This is only useful for checking
/// applicability of policy types that have these particular semantics.
pub fn is_applicable_to_user(user_uuid: &str, policy_type: OrgPolicyType, conn: &DbConn) -> bool {
- for policy in OrgPolicy::find_by_user(user_uuid, conn) { // Returns confirmed users only.
+ // Returns confirmed users only.
+ for policy in OrgPolicy::find_by_user(user_uuid, conn) {
if policy.enabled && policy.has_type(policy_type) {
let org_uuid = &policy.org_uuid;
if let Some(user) = UserOrganization::find_by_user_and_org(user_uuid, org_uuid, conn) {
diff --git a/src/db/models/organization.rs b/src/db/models/organization.rs
index 1eeb04d2..c5d36ff7 100644
--- a/src/db/models/organization.rs
+++ b/src/db/models/organization.rs
@@ -1,8 +1,8 @@
+use num_traits::FromPrimitive;
use serde_json::Value;
use std::cmp::Ordering;
-use num_traits::FromPrimitive;
-use super::{CollectionUser, User, OrgPolicy};
+use super::{CollectionUser, OrgPolicy, User};
db_object! {
#[derive(Identifiable, Queryable, Insertable, AsChangeset)]
@@ -35,8 +35,7 @@ pub enum UserOrgStatus {
Confirmed = 2,
}
-#[derive(Copy, Clone, PartialEq, Eq)]
-#[derive(num_derive::FromPrimitive)]
+#[derive(Copy, Clone, PartialEq, Eq, num_derive::FromPrimitive)]
pub enum UserOrgType {
Owner = 0,
Admin = 1,
@@ -190,11 +189,9 @@ use crate::error::MapResult;
/// Database methods
impl Organization {
pub fn save(&self, conn: &DbConn) -> EmptyResult {
- UserOrganization::find_by_org(&self.uuid, conn)
- .iter()
- .for_each(|user_org| {
- User::update_uuid_revision(&user_org.user_uuid, conn);
- });
+ UserOrganization::find_by_org(&self.uuid, conn).iter().for_each(|user_org| {
+ User::update_uuid_revision(&user_org.user_uuid, conn);
+ });
db_run! { conn:
sqlite, mysql {
@@ -236,7 +233,6 @@ impl Organization {
UserOrganization::delete_all_by_organization(&self.uuid, &conn)?;
OrgPolicy::delete_all_by_organization(&self.uuid, &conn)?;
-
db_run! { conn: {
diesel::delete(organizations::table.filter(organizations::uuid.eq(self.uuid)))
.execute(conn)
@@ -347,11 +343,13 @@ impl UserOrganization {
let collections = CollectionUser::find_by_organization_and_user_uuid(&self.org_uuid, &self.user_uuid, conn);
collections
.iter()
- .map(|c| json!({
- "Id": c.collection_uuid,
- "ReadOnly": c.read_only,
- "HidePasswords": c.hide_passwords,
- }))
+ .map(|c| {
+ json!({
+ "Id": c.collection_uuid,
+ "ReadOnly": c.read_only,
+ "HidePasswords": c.hide_passwords,
+ })
+ })
.collect()
};
@@ -446,8 +444,7 @@ impl UserOrganization {
}
pub fn has_full_access(&self) -> bool {
- (self.access_all || self.atype >= UserOrgType::Admin) &&
- self.has_status(UserOrgStatus::Confirmed)
+ (self.access_all || self.atype >= UserOrgType::Admin) && self.has_status(UserOrgStatus::Confirmed)
}
pub fn find_by_uuid(uuid: &str, conn: &DbConn) -> Option<Self> {
diff --git a/src/db/models/send.rs b/src/db/models/send.rs
index 0356d818..0644b1e1 100644
--- a/src/db/models/send.rs
+++ b/src/db/models/send.rs
@@ -205,6 +205,13 @@ impl Send {
}}
}
+ /// Purge all sends that are past their deletion date.
+ pub fn purge(conn: &DbConn) {
+ for send in Self::find_by_past_deletion_date(&conn) {
+ send.delete(&conn).ok();
+ }
+ }
+
pub fn update_users_revision(&self, conn: &DbConn) {
match &self.user_uuid {
Some(user_uuid) => {
@@ -223,12 +230,6 @@ impl Send {
Ok(())
}
- pub fn find_all(conn: &DbConn) -> Vec<Self> {
- db_run! {conn: {
- sends::table.load::<SendDb>(conn).expect("Error loading sends").from_db()
- }}
- }
-
pub fn find_by_access_id(access_id: &str, conn: &DbConn) -> Option<Self> {
use data_encoding::BASE64URL_NOPAD;
use uuid::Uuid;
@@ -271,4 +272,13 @@ impl Send {
.load::<SendDb>(conn).expect("Error loading sends").from_db()
}}
}
+
+ pub fn find_by_past_deletion_date(conn: &DbConn) -> Vec<Self> {
+ let now = Utc::now().naive_utc();
+ db_run! {conn: {
+ sends::table
+ .filter(sends::deletion_date.lt(now))
+ .load::<SendDb>(conn).expect("Error loading sends").from_db()
+ }}
+ }
}
diff --git a/src/db/models/user.rs b/src/db/models/user.rs
index fdd2dcae..5c29eaa6 100644
--- a/src/db/models/user.rs
+++ b/src/db/models/user.rs
@@ -63,8 +63,8 @@ enum UserStatus {
#[derive(Serialize, Deserialize)]
pub struct UserStampException {
- pub route: String,
- pub security_stamp: String
+ pub route: String,
+ pub security_stamp: String,
}
/// Local methods
@@ -162,7 +162,7 @@ impl User {
pub fn set_stamp_exception(&mut self, route_exception: &str) {
let stamp_exception = UserStampException {
route: route_exception.to_string(),
- security_stamp: self.security_stamp.to_string()
+ security_stamp: self.security_stamp.to_string(),
};
self.stamp_exception = Some(serde_json::to_string(&stamp_exception).unwrap_or_default());
}
@@ -341,14 +341,16 @@ impl User {
pub fn last_active(&self, conn: &DbConn) -> Option<NaiveDateTime> {
match Device::find_latest_active_by_user(&self.uuid, conn) {
Some(device) => Some(device.updated_at),
- None => None
+ None => None,
}
}
}
impl Invitation {
pub const fn new(email: String) -> Self {
- Self { email }
+ Self {
+ email,
+ }
}
pub fn save(&self, conn: &DbConn) -> EmptyResult {
diff --git a/src/error.rs b/src/error.rs
index a0b28a4b..e8fa7613 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -33,10 +33,10 @@ macro_rules! make_error {
};
}
+use diesel::r2d2::PoolError as R2d2Err;
use diesel::result::Error as DieselErr;
use diesel::ConnectionError as DieselConErr;
use diesel_migrations::RunMigrationsError as DieselMigErr;
-use diesel::r2d2::PoolError as R2d2Err;
use handlebars::RenderError as HbErr;
use jsonwebtoken::errors::Error as JwtErr;
use regex::Error as RegexErr;
@@ -191,18 +191,14 @@ use rocket::response::{self, Responder, Response};
impl<'r> Responder<'r> for Error {
fn respond_to(self, _: &Request) -> response::Result<'r> {
match self.error {
- ErrorKind::EmptyError(_) => {} // Don't print the error in this situation
+ ErrorKind::EmptyError(_) => {} // Don't print the error in this situation
ErrorKind::SimpleError(_) => {} // Don't print the error in this situation
_ => error!(target: "error", "{:#?}", self),
};
let code = Status::from_code(self.error_code).unwrap_or(Status::BadRequest);
- Response::build()
- .status(code)
- .header(ContentType::JSON)
- .sized_body(Cursor::new(format!("{}", self)))
- .ok()
+ Response::build().status(code).header(ContentType::JSON).sized_body(Cursor::new(format!("{}", self))).ok()
}
}
diff --git a/src/mail.rs b/src/mail.rs
index cd9edd9e..025a1a9a 100644
--- a/src/mail.rs
+++ b/src/mail.rs
@@ -1,4 +1,4 @@
-use std::{str::FromStr};
+use std::str::FromStr;
use chrono::{DateTime, Local};
use percent_encoding::{percent_encode, NON_ALPHANUMERIC};
@@ -62,11 +62,13 @@ fn mailer() -> SmtpTransport {
let mut selected_mechanisms = vec![];
for wanted_mechanism in mechanism.split(',') {
for m in &allowed_mechanisms {
- if m.to_string().to_lowercase() == wanted_mechanism.trim_matches(|c| c == '"' || c == '\'' || c == ' ').to_lowercase() {
+ if m.to_string().to_lowercase()
+ == wanted_mechanism.trim_matches(|c| c == '"' || c == '\'' || c == ' ').to_lowercase()
+ {
selected_mechanisms.push(*m);
}
}
- };
+ }
if !selected_mechanisms.is_empty() {
smtp_client.authentication(selected_mechanisms)
@@ -316,31 +318,23 @@ fn send_email(address: &str, subject: &str, body_html: String, body_text: String
let smtp_from = &CONFIG.smtp_from();
let email = Message::builder()
- .message_id(Some(format!("<{}@{}>", crate::util::get_uuid(), smtp_from.split('@').collect::<Vec<&str>>()[1] )))
+ .message_id(Some(format!("<{}@{}>", crate::util::get_uuid(), smtp_from.split('@').collect::<Vec<&str>>()[1])))
.to(Mailbox::new(None, Address::from_str(&address)?))
- .from(Mailbox::new(
- Some(CONFIG.smtp_from_name()),
- Address::from_str(smtp_from)?,
- ))
+ .from(Mailbox::new(Some(CONFIG.smtp_from_name()), Address::from_str(smtp_from)?))
.subject(subject)
- .multipart(
- MultiPart::alternative()
- .singlepart(text)
- .singlepart(html)
- )?;
+ .multipart(MultiPart::alternative().singlepart(text).singlepart(html))?;
match mailer().send(&email) {
Ok(_) => Ok(()),
// Match some common errors and make them more user friendly
Err(e) => {
-
if e.is_client() {
- err!(format!("SMTP Client error: {}", e));
+ err!(format!("SMTP Client error: {}", e));
} else if e.is_transient() {
err!(format!("SMTP 4xx error: {:?}", e));
} else if e.is_permanent() {
err!(format!("SMTP 5xx error: {:?}", e));
- } else if e.is_timeout() {
+ } else if e.is_timeout() {
err!(format!("SMTP timeout error: {:?}", e));
} else {
Err(e.into())
diff --git a/src/main.rs b/src/main.rs
index 50975c66..cfd945ad 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -16,6 +16,7 @@ extern crate diesel;
#[macro_use]
extern crate diesel_migrations;
+use job_scheduler::{Job, JobScheduler};
use std::{
fs::create_dir_all,
panic,
@@ -23,6 +24,7 @@ use std::{
process::{exit, Command},
str::FromStr,
thread,
+ time::Duration,
};
#[macro_use]
@@ -56,14 +58,16 @@ fn main() {
create_icon_cache_folder();
- launch_rocket(extra_debug);
+ let pool = create_db_pool();
+ schedule_jobs(pool.clone());
+ launch_rocket(pool, extra_debug); // Blocks until program termination.
}
const HELP: &str = "\
- A Bitwarden API server written in Rust
+ Alternative implementation of the Bitwarden server API written in Rust
USAGE:
- bitwarden_rs
+ vaultwarden
FLAGS:
-h, --help Prints help information
@@ -75,18 +79,18 @@ fn parse_args() {
let mut pargs = pico_args::Arguments::from_env();
if pargs.contains(["-h", "--help"]) {
- println!("bitwarden_rs {}", option_env!("BWRS_VERSION").unwrap_or(NO_VERSION));
+ println!("vaultwarden {}", option_env!("BWRS_VERSION").unwrap_or(NO_VERSION));
print!("{}", HELP);
exit(0);
} else if pargs.contains(["-v", "--version"]) {
- println!("bitwarden_rs {}", option_env!("BWRS_VERSION").unwrap_or(NO_VERSION));
+ println!("vaultwarden {}", option_env!("BWRS_VERSION").unwrap_or(NO_VERSION));
exit(0);
}
}
fn launch_info() {
println!("/--------------------------------------------------------------------\\");
- println!("| Starting Bitwarden_RS |");
+ println!("| Starting Vaultwarden |");
if let Some(version) = option_env!("BWRS_VERSION") {
println!("|{:^68}|", format!("Version {}", version));
@@ -98,7 +102,7 @@ fn launch_info() {
println!("| Send usage/configuration questions or feature requests to: |");
println!("| https://bitwardenrs.discourse.group/ |");
println!("| Report suspected bugs/issues in the software itself at: |");
- println!("| https://github.com/dani-garcia/bitwarden_rs/issues/new |");
+ println!("| https://github.com/dani-garcia/vaultwarden/issues/new |");
println!("\\--------------------------------------------------------------------/\n");
}
@@ -123,7 +127,9 @@ fn init_logging(level: log::LevelFilter) -> Result<(), fern::InitError> {
// Enable smtp debug logging only specifically for smtp when need.
// This can contain sensitive information we do not want in the default debug/trace logging.
if CONFIG.smtp_debug() {
- println!("[WARNING] SMTP Debugging is enabled (SMTP_DEBUG=true). Sensitive information could be disclosed via logs!");
+ println!(
+ "[WARNING] SMTP Debugging is enabled (SMTP_DEBUG=true). Sensitive information could be disclosed via logs!"
+ );
println!("[WARNING] Only enable SMTP_DEBUG during troubleshooting!\n");
logger = logger.level_for("lettre::transport::smtp", log::LevelFilter::Debug)
} else {
@@ -201,7 +207,7 @@ fn chain_syslog(logger: fern::Dispatch) -> fern::Dispatch {
let syslog_fmt = syslog::Formatter3164 {
facility: syslog::Facility::LOG_USER,
hostname: None,
- process: "bitwarden_rs".into(),
+ process: "vaultwarden".into(),
pid: 0,
};
@@ -294,24 +300,27 @@ fn check_web_vault() {
let index_path = Path::new(&CONFIG.web_vault_folder()).join("index.html");
if !index_path.exists() {
- error!("Web vault is not found at '{}'. To install it, please follow the steps in: ", CONFIG.web_vault_folder());
- error!("https://github.com/dani-garcia/bitwarden_rs/wiki/Building-binary#install-the-web-vault");
+ error!(
+ "Web vault is not found at '{}'. To install it, please follow the steps in: ",
+ CONFIG.web_vault_folder()
+ );
+ error!("https://github.com/dani-garcia/vaultwarden/wiki/Building-binary#install-the-web-vault");
error!("You can also set the environment variable 'WEB_VAULT_ENABLED=false' to disable it");
exit(1);
}
}
-fn launch_rocket(extra_debug: bool) {
- let pool = match util::retry_db(db::DbPool::from_config, CONFIG.db_connection_retries()) {
+fn create_db_pool() -> db::DbPool {
+ match util::retry_db(db::DbPool::from_config, CONFIG.db_connection_retries()) {
Ok(p) => p,
Err(e) => {
error!("Error creating database pool: {:?}", e);
exit(1);
}
- };
-
- api::start_send_deletion_scheduler(pool.clone());
+ }
+}
+fn launch_rocket(pool: db::DbPool, extra_debug: bool) {
let basepath = &CONFIG.domain_path();
// If adding more paths here, consider also adding them to
@@ -334,3 +343,40 @@ fn launch_rocket(extra_debug: bool) {
// The launch will restore the original logging level
error!("Launch error {:#?}", result);
}
+
+fn schedule_jobs(pool: db::DbPool) {
+ if CONFIG.job_poll_interval_ms() == 0 {
+ info!("Job scheduler disabled.");
+ return;
+ }
+ thread::Builder::new()
+ .name("job-scheduler".to_string())
+ .spawn(move || {
+ let mut sched = JobScheduler::new();
+
+ // Purge sends that are past their deletion date.
+ if !CONFIG.send_purge_schedule().is_empty() {
+ sched.add(Job::new(CONFIG.send_purge_schedule().parse().unwrap(), || {
+ api::purge_sends(pool.clone());
+ }));
+ }
+
+ // Purge trashed items that are old enough to be auto-deleted.
+ if !CONFIG.trash_purge_schedule().is_empty() {
+ sched.add(Job::new(CONFIG.trash_purge_schedule().parse().unwrap(), || {
+ api::purge_trashed_ciphers(pool.clone());
+ }));
+ }
+
+ // Periodically check for jobs to run. We probably won't need any
+ // jobs that run more often than once a minute, so a default poll
+ // interval of 30 seconds should be sufficient. Users who want to
+ // schedule jobs to run more frequently for some reason can reduce
+ // the poll interval accordingly.
+ loop {
+ sched.tick();
+ thread::sleep(Duration::from_millis(CONFIG.job_poll_interval_ms()));
+ }
+ })
+ .expect("Error spawning job scheduler thread");
+}
diff --git a/src/static/global_domains.json b/src/static/global_domains.json
index 4a475f92..f7809f51 100644
--- a/src/static/global_domains.json
+++ b/src/static/global_domains.json
@@ -772,7 +772,8 @@
"stackoverflow.com",
"serverfault.com",
"mathoverflow.net",
- "askubuntu.com"
+ "askubuntu.com",
+ "stackapps.com"
],
"Excluded": false
},
diff --git a/src/static/images/fallback-icon.png b/src/static/images/fallback-icon.png
new file mode 100644
index 00000000..e30b532e
--- /dev/null
+++ b/src/static/images/fallback-icon.png
Binary files differ
diff --git a/src/static/templates/admin/base.hbs b/src/static/templates/admin/base.hbs
index e4f1ec85..e476309d 100644
--- a/src/static/templates/admin/base.hbs
+++ b/src/static/templates/admin/base.hbs
@@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<meta name="robots" content="noindex,nofollow" />
<link rel="icon" type="image/png" href="{{urlpath}}/bwrs_static/shield-white.png">
- <title>Bitwarden_rs Admin Panel</title>
+ <title>Vaultwarden Admin Panel</title>
<link rel="stylesheet" href="{{urlpath}}/bwrs_static/bootstrap.css" />
<style>
body {
@@ -83,7 +83,7 @@
<body class="bg-light">
<nav class="navbar navbar-expand-md navbar-dark bg-dark mb-4 shadow fixed-top">
<div class="container-xl">
- <a class="navbar-brand" href="{{urlpath}}/admin"><img class="pr-1" src="{{urlpath}}/bwrs_static/shield-white.png">Bitwarden_rs Admin</a>
+ <a class="navbar-brand" href="{{urlpath}}/admin"><img class="pr-1" src="{{urlpath}}/bwrs_static/shield-white.png">Vaultwarden Admin</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarCollapse"
aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
diff --git a/src/static/templates/admin/diagnostics.hbs b/src/static/templates/admin/diagnostics.hbs
index 8d7901db..3a498c63 100644
--- a/src/static/templates/admin/diagnostics.hbs
+++ b/src/static/templates/admin/diagnostics.hbs
@@ -20,6 +20,7 @@
<dd class="col-sm-7">
<span id="server-latest">{{diagnostics.latest_release}}<span id="server-latest-commit" class="d-none">-{{diagnostics.latest_commit}}</span></span>
</dd>
+ {{#if diagnostics.web_vault_enabled}}
<dt class="col-sm-5">Web Installed
<span class="badge badge-success d-none" id="web-success" title="Latest version is installed.">Ok</span>
<span class="badge badge-warning d-none" id="web-warning" title="There seems to be an update available.">Update</span>
@@ -35,6 +36,13 @@
<span id="web-latest">{{diagnostics.latest_web_build}}</span>
</dd>
{{/unless}}
+ {{/if}}
+ {{#unless diagnostics.web_vault_enabled}}
+ <dt class="col-sm-5">Web Installed</dt>
+ <dd class="col-sm-7">
+ <span id="web-installed">Web Vault is disabled</span>
+ </dd>
+ {{/unless}}
<dt class="col-sm-5">Database</dt>
<dd class="col-sm-7">
<span><b>{{diagnostics.db_type}}:</b> {{diagnostics.db_version}}</span>
@@ -118,7 +126,10 @@
<dd class="col-sm-7">
<span id="dns-resolved">{{diagnostics.dns_resolved}}</span>
</dd>
-
+ <dt class="col-sm-5">Date & Time (Local)</dt>
+ <dd class="col-sm-7">
+ <span><b>Server:</b> {{diagnostics.server_time_local}}</span>
+ </dd>
<dt class="col-sm-5">Date & Time (UTC)
<span class="badge badge-success d-none" id="time-success" title="Time offsets seem to be correct.">Ok</span>
<span class="badge badge-danger d-none" id="time-warning" title="Time offsets are too mouch at drift.">Error</span>
@@ -148,8 +159,8 @@
<dl class="row">
<dd class="col-sm-12">
If you need support please check the following links first before you create a new issue:
- <a href="https://bitwardenrs.discourse.group/" target="_blank" rel="noreferrer">Bitwarden_RS Forum</a>
- | <a href="https://github.com/dani-garcia/bitwarden_rs/discussions" target="_blank" rel="noreferrer">Github Discussions</a>
+ <a href="https://bitwardenrs.discourse.group/" target="_blank" rel="noreferrer">Vaultwarden Forum</a>
+ | <a href="https://github.com/dani-garcia/vaultwarden/discussions" target="_blank" rel="noreferrer">Github Discussions</a>
</dd>
</dl>
<dl class="row">
@@ -211,7 +222,7 @@
}
// ================================
- // Version check for both bitwarden_rs and web-vault
+ // Version check for both vaultwarden and web-vault
let serverInstalled = document.getElementById('server-installed').innerText;
let serverLatest = document.getElementById('server-latest').innerText;
let serverLatestCommit = document.getElementById('server-latest-commit').innerText.replace('-', '');
@@ -294,7 +305,7 @@
async function generateSupportString() {
supportString = "### Your environment (Generated via diagnostics page)\n";
- supportString += "* Bitwarden_rs version: v{{ version }}\n";
+ supportString += "* Vaultwarden version: v{{ version }}\n";
supportString += "* Web-vault version: v{{ diagnostics.web_vault_version }}\n";
supportString += "* Running within Docker: {{ diagnostics.running_within_docker }}\n";
supportString += "* Uses a reverse proxy: {{ diagnostics.ip_header_exists }}\n";
diff --git a/src/static/templates/admin/settings.hbs b/src/static/templates/admin/settings.hbs
index 0b8c6277..819fc231 100644
--- a/src/static/templates/admin/settings.hbs
+++ b/src/static/templates/admin/settings.hbs
@@ -116,7 +116,11 @@
data-target="#g_database">Backup Database</button></div>
<div id="g_database" class="card-body collapse" data-parent="#config-form">
<div class="small mb-3">
- NOTE: A local installation of sqlite3 is required for this section to work.
+ WARNING: This function only creates a backup copy of the SQLite database.
+ This does not include any configuration or file attachment data that may
+ also be needed to fully restore a vaultwarden instance. For details on
+ how to perform complete backups, refer to the wiki page on
+ <a href="https://github.com/dani-garcia/vaultwarden/wiki/Backing-up-your-vault">backups</a>.
</div>
<button type="button" class="btn btn-primary" onclick="backupDatabase();">Backup Database</button>
</div>
diff --git a/src/static/templates/email/change_email.hbs b/src/static/templates/email/change_email.hbs
index d2ed2d8f..170af6f9 100644
--- a/src/static/templates/email/change_email.hbs
+++ b/src/static/templates/email/change_email.hbs
@@ -5,4 +5,4 @@ To finalize changing your email address enter the following code in web vault: {
If you did not try to change an email address, you can safely ignore this email.
===
-Github: https://github.com/dani-garcia/bitwarden_rs
+Github: https://github.com/dani-garcia/vaultwarden
diff --git a/src/static/templates/email/change_email.html.hbs b/src/static/templates/email/change_email.html.hbs
index 94a7dcaa..e28af645 100644
--- a/src/static/templates/email/change_email.html.hbs
+++ b/src/static/templates/email/change_email.html.hbs
@@ -4,7 +4,7 @@ Your Email Change
<head>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
- <title>Bitwarden_rs</title>
+ <title>Vaultwarden</title>
</head>
<body style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; height: 100%; line-height: 25px; width: 100% !important;" bgcolor="#f6f6f6">
<style type="text/css">
@@ -113,7 +113,7 @@ Your Email Change
<td class="aligncenter social-icons" align="center" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 15px 0 0 0;" valign="top">
<table cellpadding="0" cellspacing="0" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0 auto;">
<tr style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0;">
- <td style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 0 10px;" valign="top"><a href="https://github.com/dani-garcia/bitwarden_rs" target="_blank" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; text-decoration: underline;"><img src="{{url}}/bwrs_static/mail-github.png" alt="GitHub" width="30" height="30" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; border: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0; max-width: 100%;" /></a></td>
+ <td style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 0 10px;" valign="top"><a href="https://github.com/dani-garcia/vaultwarden" target="_blank" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; text-decoration: underline;"><img src="{{url}}/bwrs_static/mail-github.png" alt="GitHub" width="30" height="30" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; border: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0; max-width: 100%;" /></a></td>
</tr>
</table>
</td>
diff --git a/src/static/templates/email/delete_account.hbs b/src/static/templates/email/delete_account.hbs
index b8b6c8c2..0c5b7268 100644
--- a/src/static/templates/email/delete_account.hbs
+++ b/src/static/templates/email/delete_account.hbs
@@ -7,4 +7,4 @@ Delete Your Account: {{url}}/#/verify-recover-delete?userId={{user_id}}&token={{
If you did not request this email to delete your account, you can safely ignore this email.
===
-Github: https://github.com/dani-garcia/bitwarden_rs
+Github: https://github.com/dani-garcia/vaultwarden
diff --git a/src/static/templates/email/delete_account.html.hbs b/src/static/templates/email/delete_account.html.hbs
index 2330a337..400c963f 100644
--- a/src/static/templates/email/delete_account.html.hbs
+++ b/src/static/templates/email/delete_account.html.hbs
@@ -4,7 +4,7 @@ Delete Your Account
<head>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
- <title>Bitwarden_rs</title>
+ <title>Vaultwarden</title>
</head>
<body style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; height: 100%; line-height: 25px; width: 100% !important;" bgcolor="#f6f6f6">
<style type="text/css">
@@ -121,7 +121,7 @@ Delete Your Account
<td class="aligncenter social-icons" align="center" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 15px 0 0 0;" valign="top">
<table cellpadding="0" cellspacing="0" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0 auto;">
<tr style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0;">
- <td style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 0 10px;" valign="top"><a href="https://github.com/dani-garcia/bitwarden_rs" target="_blank" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; text-decoration: underline;"><img src="{{url}}/bwrs_static/mail-github.png" alt="GitHub" width="30" height="30" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; border: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0; max-width: 100%;" /></a></td>
+ <td style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 0 10px;" valign="top"><a href="https://github.com/dani-garcia/vaultwarden" target="_blank" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; text-decoration: underline;"><img src="{{url}}/bwrs_static/mail-github.png" alt="GitHub" width="30" height="30" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; border: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0; max-width: 100%;" /></a></td>
</tr>
</table>
</td>
diff --git a/src/static/templates/email/invite_accepted.hbs b/src/static/templates/email/invite_accepted.hbs
index 641ce7f4..2f74cf7c 100644
--- a/src/static/templates/email/invite_accepted.hbs
+++ b/src/static/templates/email/invite_accepted.hbs
@@ -1,7 +1,7 @@
Invitation to {{{org_name}}} accepted
<!---------------->
Your invitation for *{{email}}* to join *{{org_name}}* was accepted.
-Please log in via {{url}} to the bitwarden_rs server and confirm them from the organization management page.
+Please log in via {{url}} to the vaultwarden server and confirm them from the organization management page.
===
-Github: https://github.com/dani-garcia/bitwarden_rs
+Github: https://github.com/dani-garcia/vaultwarden
diff --git a/src/static/templates/email/invite_accepted.html.hbs b/src/static/templates/email/invite_accepted.html.hbs
index 32c0f468..5c259e24 100644
--- a/src/static/templates/email/invite_accepted.html.hbs
+++ b/src/static/templates/email/invite_accepted.html.hbs
@@ -4,7 +4,7 @@ Invitation to {{{org_name}}} accepted
<head>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
- <title>Bitwarden_rs</title>
+ <title>Vaultwarden</title>
</head>
<body style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; height: 100%; line-height: 25px; width: 100% !important;" bgcolor="#f6f6f6">
<style type="text/css">
@@ -101,7 +101,7 @@ Invitation to {{{org_name}}} accepted
</tr>
<tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
<td class="content-block" style="font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; margin: 0; -webkit-font-smoothing: antialiased; padding: 0 0 10px; -webkit-text-size-adjust: none;" valign="top">
- Please <a href="{{url}}/">log in</a> to the bitwarden_rs server and confirm them from the organization management page.
+ Please <a href="{{url}}/">log in</a> to the vaultwarden server and confirm them from the organization management page.
</td>
</tr>
<tr style="margin: 0; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; box-sizing: border-box; font-size: 16px; color: #333; line-height: 25px; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none;">
@@ -118,7 +118,7 @@ Invitation to {{{org_name}}} accepted
<td class="aligncenter social-icons" align="center" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 15px 0 0 0;" valign="top">
<table cellpadding="0" cellspacing="0" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0 auto;">
<tr style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0;">
- <td style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 0 10px;" valign="top"><a href="https://github.com/dani-garcia/bitwarden_rs" target="_blank" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; text-decoration: underline;"><img src="{{url}}/bwrs_static/mail-github.png" alt="GitHub" width="30" height="30" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; border: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0; max-width: 100%;" /></a></td>
+ <td style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 0 10px;" valign="top"><a href="https://github.com/dani-garcia/vaultwarden" target="_blank" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; text-decoration: underline;"><img src="{{url}}/bwrs_static/mail-github.png" alt="GitHub" width="30" height="30" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; border: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0; max-width: 100%;" /></a></td>
</tr>
</table>
</td>
diff --git a/src/static/templates/email/invite_confirmed.hbs b/src/static/templates/email/invite_confirmed.hbs
index f4fa2a9b..aedce133 100644
--- a/src/static/templates/email/invite_confirmed.hbs
+++ b/src/static/templates/email/invite_confirmed.hbs
@@ -4,4 +4,4 @@ Your invitation to join *{{org_name}}* was confirmed.
It will now appear under the Organizations the next time you log in to the web vault at {{url}}.
===
-Github: https://github.com/dani-garcia/bitwarden_rs
+Github: https://github.com/dani-garcia/vaultwarden
diff --git a/src/static/templates/email/invite_confirmed.html.hbs b/src/static/templates/email/invite_confirmed.html.hbs
index 3f07a74c..4b064201 100644
--- a/src/static/templates/email/invite_confirmed.html.hbs
+++ b/src/static/templates/email/invite_confirmed.html.hbs
@@ -4,7 +4,7 @@ Invitation to {{{org_name}}} confirmed
<head>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
- <title>Bitwarden_rs</title>
+ <title>Vaultwarden</title>
</head>
<body style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; height: 100%; line-height: 25px; width: 100% !important;" bgcolor="#f6f6f6">
<style type="text/css">
@@ -114,7 +114,7 @@ Invitation to {{{org_name}}} confirmed
<td class="aligncenter social-icons" align="center" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 15px 0 0 0;" valign="top">
<table cellpadding="0" cellspacing="0" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0 auto;">
<tr style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0;">
- <td style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 0 10px;" valign="top"><a href="https://github.com/dani-garcia/bitwarden_rs" target="_blank" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; text-decoration: underline;"><img src="{{url}}/bwrs_static/mail-github.png" alt="GitHub" width="30" height="30" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; border: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0; max-width: 100%;" /></a></td>
+ <td style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 0 10px;" valign="top"><a href="https://github.com/dani-garcia/vaultwarden" target="_blank" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; text-decoration: underline;"><img src="{{url}}/bwrs_static/mail-github.png" alt="GitHub" width="30" height="30" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; border: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0; max-width: 100%;" /></a></td>
</tr>
</table>
</td>
diff --git a/src/static/templates/email/new_device_logged_in.hbs b/src/static/templates/email/new_device_logged_in.hbs
index 1c14fde1..ef9047c9 100644
--- a/src/static/templates/email/new_device_logged_in.hbs
+++ b/src/static/templates/email/new_device_logged_in.hbs
@@ -9,4 +9,4 @@ Your account was just logged into from a new device.
You can deauthorize all devices that have access to your account from the web vault ( {{url}} ) under Settings > My Account > Deauthorize Sessions.
===
-Github: https://github.com/dani-garcia/bitwarden_rs
+Github: https://github.com/dani-garcia/vaultwarden
diff --git a/src/static/templates/email/new_device_logged_in.html.hbs b/src/static/templates/email/new_device_logged_in.html.hbs
index 20d4eaa8..6b20939f 100644
--- a/src/static/templates/email/new_device_logged_in.html.hbs
+++ b/src/static/templates/email/new_device_logged_in.html.hbs
@@ -4,7 +4,7 @@ New Device Logged In From {{{device}}}
<head>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
- <title>Bitwarden_rs</title>
+ <title>Vaultwarden</title>
</head>
<body style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; height: 100%; line-height: 25px; width: 100% !important;" bgcolor="#f6f6f6">
<style type="text/css">
@@ -128,7 +128,7 @@ New Device Logged In From {{{device}}}
<td class="aligncenter social-icons" align="center" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 15px 0 0 0;" valign="top">
<table cellpadding="0" cellspacing="0" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0 auto;">
<tr style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0;">
- <td style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 0 10px;" valign="top"><a href="https://github.com/dani-garcia/bitwarden_rs" target="_blank" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; text-decoration: underline;"><img src="{{url}}/bwrs_static/mail-github.png" alt="GitHub" width="30" height="30" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; border: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0; max-width: 100%;" /></a></td>
+ <td style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 0 10px;" valign="top"><a href="https://github.com/dani-garcia/vaultwarden" target="_blank" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; text-decoration: underline;"><img src="{{url}}/bwrs_static/mail-github.png" alt="GitHub" width="30" height="30" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; border: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0; max-width: 100%;" /></a></td>
</tr>
</table>
</td>
diff --git a/src/static/templates/email/pw_hint_none.hbs b/src/static/templates/email/pw_hint_none.hbs
index b62a65bf..0caeb45c 100644
--- a/src/static/templates/email/pw_hint_none.hbs
+++ b/src/static/templates/email/pw_hint_none.hbs
@@ -7,4 +7,4 @@ If you cannot remember your master password, there is no way to recover your dat
If you did not request your master password hint you can safely ignore this email.
===
-Github: https://github.com/dani-garcia/bitwarden_rs
+Github: https://github.com/dani-garcia/vaultwarden
diff --git a/src/static/templates/email/pw_hint_none.html.hbs b/src/static/templates/email/pw_hint_none.html.hbs
index 8a4855d5..5d49b4e4 100644
--- a/src/static/templates/email/pw_hint_none.html.hbs
+++ b/src/static/templates/email/pw_hint_none.html.hbs
@@ -4,7 +4,7 @@ Sorry, you have no password hint...
<head>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
- <title>Bitwarden_rs</title>
+ <title>Vaultwarden</title>
</head>
<body style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; height: 100%; line-height: 25px; width: 100% !important;" bgcolor="#f6f6f6">
<style type="text/css">
@@ -118,7 +118,7 @@ Sorry, you have no password hint...
<td class="aligncenter social-icons" align="center" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 15px 0 0 0;" valign="top">
<table cellpadding="0" cellspacing="0" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0 auto;">
<tr style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0;">
- <td style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 0 10px;" valign="top"><a href="https://github.com/dani-garcia/bitwarden_rs" target="_blank" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; text-decoration: underline;"><img src="{{url}}/bwrs_static/mail-github.png" alt="GitHub" width="30" height="30" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; border: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0; max-width: 100%;" /></a></td>
+ <td style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 0 10px;" valign="top"><a href="https://github.com/dani-garcia/vaultwarden" target="_blank" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; text-decoration: underline;"><img src="{{url}}/bwrs_static/mail-github.png" alt="GitHub" width="30" height="30" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; border: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0; max-width: 100%;" /></a></td>
</tr>
</table>
</td>
diff --git a/src/static/templates/email/pw_hint_some.hbs b/src/static/templates/email/pw_hint_some.hbs
index ba783ab1..8778921d 100644
--- a/src/static/templates/email/pw_hint_some.hbs
+++ b/src/static/templates/email/pw_hint_some.hbs
@@ -10,4 +10,4 @@ If you cannot remember your master password, there is no way to recover your dat
If you did not request your master password hint you can safely ignore this email.
===
-Github: https://github.com/dani-garcia/bitwarden_rs
+Github: https://github.com/dani-garcia/vaultwarden
diff --git a/src/static/templates/email/pw_hint_some.html.hbs b/src/static/templates/email/pw_hint_some.html.hbs
index 0cd26b17..42cd827b 100644
--- a/src/static/templates/email/pw_hint_some.html.hbs
+++ b/src/static/templates/email/pw_hint_some.html.hbs
@@ -4,7 +4,7 @@ Your master password hint
<head>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
- <title>Bitwarden_rs</title>
+ <title>Vaultwarden</title>
</head>
<body style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; height: 100%; line-height: 25px; width: 100% !important;" bgcolor="#f6f6f6">
<style type="text/css">
@@ -124,7 +124,7 @@ Your master password hint
<td class="aligncenter social-icons" align="center" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 15px 0 0 0;" valign="top">
<table cellpadding="0" cellspacing="0" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0 auto;">
<tr style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0;">
- <td style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 0 10px;" valign="top"><a href="https://github.com/dani-garcia/bitwarden_rs" target="_blank" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; text-decoration: underline;"><img src="{{url}}/bwrs_static/mail-github.png" alt="GitHub" width="30" height="30" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; border: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0; max-width: 100%;" /></a></td>
+ <td style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 0 10px;" valign="top"><a href="https://github.com/dani-garcia/vaultwarden" target="_blank" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; text-decoration: underline;"><img src="{{url}}/bwrs_static/mail-github.png" alt="GitHub" width="30" height="30" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; border: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0; max-width: 100%;" /></a></td>
</tr>
</table>
</td>
diff --git a/src/static/templates/email/send_org_invite.hbs b/src/static/templates/email/send_org_invite.hbs
index efe1d287..65bf4400 100644
--- a/src/static/templates/email/send_org_invite.hbs
+++ b/src/static/templates/email/send_org_invite.hbs
@@ -9,4 +9,4 @@ Click here to join: {{url}}/#/accept-organization/?organizationId={{org_id}}&org
If you do not wish to join this organization, you can safely ignore this email.
===
-Github: https://github.com/dani-garcia/bitwarden_rs
+Github: https://github.com/dani-garcia/vaultwarden
diff --git a/src/static/templates/email/send_org_invite.html.hbs b/src/static/templates/email/send_org_invite.html.hbs
index 3326e852..88eca499 100644
--- a/src/static/templates/email/send_org_invite.html.hbs
+++ b/src/static/templates/email/send_org_invite.html.hbs
@@ -4,7 +4,7 @@ Join {{{org_name}}}
<head>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
- <title>Bitwarden_rs</title>
+ <title>Vaultwarden</title>
</head>
<body style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; height: 100%; line-height: 25px; width: 100% !important;" bgcolor="#f6f6f6">
<style type="text/css">
@@ -121,7 +121,7 @@ Join {{{org_name}}}
<td class="aligncenter social-icons" align="center" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 15px 0 0 0;" valign="top">
<table cellpadding="0" cellspacing="0" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0 auto;">
<tr style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0;">
- <td style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 0 10px;" valign="top"><a href="https://github.com/dani-garcia/bitwarden_rs" target="_blank" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; text-decoration: underline;"><img src="{{url}}/bwrs_static/mail-github.png" alt="GitHub" width="30" height="30" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; border: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0; max-width: 100%;" /></a></td>
+ <td style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 0 10px;" valign="top"><a href="https://github.com/dani-garcia/vaultwarden" target="_blank" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; text-decoration: underline;"><img src="{{url}}/bwrs_static/mail-github.png" alt="GitHub" width="30" height="30" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; border: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0; max-width: 100%;" /></a></td>
</tr>
</table>
</td>
diff --git a/src/static/templates/email/smtp_test.hbs b/src/static/templates/email/smtp_test.hbs
index cc37993d..593d305d 100644
--- a/src/static/templates/email/smtp_test.hbs
+++ b/src/static/templates/email/smtp_test.hbs
@@ -1,8 +1,8 @@
-Bitwarden_rs SMTP Test
+Vaultwarden SMTP Test
<!---------------->
This is a test email to verify the SMTP configuration for {{url}}.
When you can read this email it is probably configured correctly.
===
-Github: https://github.com/dani-garcia/bitwarden_rs
+Github: https://github.com/dani-garcia/vaultwarden
diff --git a/src/static/templates/email/smtp_test.html.hbs b/src/static/templates/email/smtp_test.html.hbs
index dbff4502..910b0dde 100644
--- a/src/static/templates/email/smtp_test.html.hbs
+++ b/src/static/templates/email/smtp_test.html.hbs
@@ -1,10 +1,10 @@
-Bitwarden_rs SMTP Test
+Vaultwarden SMTP Test
<!---------------->
<html xmlns="http://www.w3.org/1999/xhtml" xmlns="http://www.w3.org/1999/xhtml" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0;">
<head>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
- <title>Bitwarden_rs</title>
+ <title>Vaultwarden</title>
</head>
<body style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; height: 100%; line-height: 25px; width: 100% !important;" bgcolor="#f6f6f6">
<style type="text/css">
@@ -113,7 +113,7 @@ Bitwarden_rs SMTP Test
<td class="aligncenter social-icons" align="center" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 15px 0 0 0;" valign="top">
<table cellpadding="0" cellspacing="0" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0 auto;">
<tr style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0;">
- <td style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 0 10px;" valign="top"><a href="https://github.com/dani-garcia/bitwarden_rs" target="_blank" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; text-decoration: underline;"><img src="{{url}}/bwrs_static/mail-github.png" alt="GitHub" width="30" height="30" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; border: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0; max-width: 100%;" /></a></td>
+ <td style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 0 10px;" valign="top"><a href="https://github.com/dani-garcia/vaultwarden" target="_blank" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; text-decoration: underline;"><img src="{{url}}/bwrs_static/mail-github.png" alt="GitHub" width="30" height="30" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; border: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0; max-width: 100%;" /></a></td>
</tr>
</table>
</td>
diff --git a/src/static/templates/email/twofactor_email.hbs b/src/static/templates/email/twofactor_email.hbs
index ca2745f6..78d160e7 100644
--- a/src/static/templates/email/twofactor_email.hbs
+++ b/src/static/templates/email/twofactor_email.hbs
@@ -5,4 +5,4 @@ Your two-step verification code is: {{token}}
Use this code to complete logging in with Bitwarden.
===
-Github: https://github.com/dani-garcia/bitwarden_rs
+Github: https://github.com/dani-garcia/vaultwarden
diff --git a/src/static/templates/email/twofactor_email.html.hbs b/src/static/templates/email/twofactor_email.html.hbs
index 36bf58eb..eebefb68 100644
--- a/src/static/templates/email/twofactor_email.html.hbs
+++ b/src/static/templates/email/twofactor_email.html.hbs
@@ -4,7 +4,7 @@ Your Two-step Login Verification Code
<head>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
- <title>Bitwarden_rs</title>
+ <title>Vaultwarden</title>
</head>
<body style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; height: 100%; line-height: 25px; width: 100% !important;" bgcolor="#f6f6f6">
<style type="text/css">
@@ -113,7 +113,7 @@ Your Two-step Login Verification Code
<td class="aligncenter social-icons" align="center" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 15px 0 0 0;" valign="top">
<table cellpadding="0" cellspacing="0" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0 auto;">
<tr style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0;">
- <td style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 0 10px;" valign="top"><a href="https://github.com/dani-garcia/bitwarden_rs" target="_blank" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; text-decoration: underline;"><img src="{{url}}/bwrs_static/mail-github.png" alt="GitHub" width="30" height="30" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; border: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0; max-width: 100%;" /></a></td>
+ <td style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 0 10px;" valign="top"><a href="https://github.com/dani-garcia/vaultwarden" target="_blank" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; text-decoration: underline;"><img src="{{url}}/bwrs_static/mail-github.png" alt="GitHub" width="30" height="30" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; border: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0; max-width: 100%;" /></a></td>
</tr>
</table>
</td>
diff --git a/src/static/templates/email/verify_email.hbs b/src/static/templates/email/verify_email.hbs
index 7dabc80e..2996ad58 100644
--- a/src/static/templates/email/verify_email.hbs
+++ b/src/static/templates/email/verify_email.hbs
@@ -7,4 +7,4 @@ Verify Email Address Now: {{url}}/#/verify-email/?userId={{user_id}}&token={{tok
If you did not request to verify your account, you can safely ignore this email.
===
-Github: https://github.com/dani-garcia/bitwarden_rs
+Github: https://github.com/dani-garcia/vaultwarden
diff --git a/src/static/templates/email/verify_email.html.hbs b/src/static/templates/email/verify_email.html.hbs
index 44d76d2e..a1ae9a87 100644
--- a/src/static/templates/email/verify_email.html.hbs
+++ b/src/static/templates/email/verify_email.html.hbs
@@ -4,7 +4,7 @@ Verify Your Email
<head>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
- <title>Bitwarden_rs</title>
+ <title>Vaultwarden</title>
</head>
<body style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; height: 100%; line-height: 25px; width: 100% !important;" bgcolor="#f6f6f6">
<style type="text/css">
@@ -121,7 +121,7 @@ Verify Your Email
<td class="aligncenter social-icons" align="center" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 15px 0 0 0;" valign="top">
<table cellpadding="0" cellspacing="0" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0 auto;">
<tr style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0;">
- <td style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 0 10px;" valign="top"><a href="https://github.com/dani-garcia/bitwarden_rs" target="_blank" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; text-decoration: underline;"><img src="{{url}}/bwrs_static/mail-github.png" alt="GitHub" width="30" height="30" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; border: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0; max-width: 100%;" /></a></td>
+ <td style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 0 10px;" valign="top"><a href="https://github.com/dani-garcia/vaultwarden" target="_blank" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; text-decoration: underline;"><img src="{{url}}/bwrs_static/mail-github.png" alt="GitHub" width="30" height="30" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; border: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0; max-width: 100%;" /></a></td>
</tr>
</table>
</td>
diff --git a/src/static/templates/email/welcome.hbs b/src/static/templates/email/welcome.hbs
index 30bf6d6c..c6e1006f 100644
--- a/src/static/templates/email/welcome.hbs
+++ b/src/static/templates/email/welcome.hbs
@@ -5,4 +5,4 @@ Thank you for creating an account at {{url}}. You may now log in with your new a
If you did not request to create an account, you can safely ignore this email.
===
-Github: https://github.com/dani-garcia/bitwarden_rs
+Github: https://github.com/dani-garcia/vaultwarden
diff --git a/src/static/templates/email/welcome.html.hbs b/src/static/templates/email/welcome.html.hbs
index 41b8398d..3b20d945 100644
--- a/src/static/templates/email/welcome.html.hbs
+++ b/src/static/templates/email/welcome.html.hbs
@@ -4,7 +4,7 @@ Welcome
<head>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
- <title>Bitwarden_rs</title>
+ <title>Vaultwarden</title>
</head>
<body style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; height: 100%; line-height: 25px; width: 100% !important;" bgcolor="#f6f6f6">
<style type="text/css">
@@ -113,7 +113,7 @@ Welcome
<td class="aligncenter social-icons" align="center" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 15px 0 0 0;" valign="top">
<table cellpadding="0" cellspacing="0" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0 auto;">
<tr style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0;">
- <td style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 0 10px;" valign="top"><a href="https://github.com/dani-garcia/bitwarden_rs" target="_blank" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; text-decoration: underline;"><img src="{{url}}/bwrs_static/mail-github.png" alt="GitHub" width="30" height="30" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; border: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0; max-width: 100%;" /></a></td>
+ <td style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 0 10px;" valign="top"><a href="https://github.com/dani-garcia/vaultwarden" target="_blank" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; text-decoration: underline;"><img src="{{url}}/bwrs_static/mail-github.png" alt="GitHub" width="30" height="30" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; border: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0; max-width: 100%;" /></a></td>
</tr>
</table>
</td>
diff --git a/src/static/templates/email/welcome_must_verify.hbs b/src/static/templates/email/welcome_must_verify.hbs
index a21666e6..1bed3d64 100644
--- a/src/static/templates/email/welcome_must_verify.hbs
+++ b/src/static/templates/email/welcome_must_verify.hbs
@@ -7,4 +7,4 @@ Verify Email Address Now: {{url}}/#/verify-email/?userId={{user_id}}&token={{tok
If you did not request to create an account, you can safely ignore this email.
===
-Github: https://github.com/dani-garcia/bitwarden_rs
+Github: https://github.com/dani-garcia/vaultwarden
diff --git a/src/static/templates/email/welcome_must_verify.html.hbs b/src/static/templates/email/welcome_must_verify.html.hbs
index 90133008..7d114fb1 100644
--- a/src/static/templates/email/welcome_must_verify.html.hbs
+++ b/src/static/templates/email/welcome_must_verify.html.hbs
@@ -4,7 +4,7 @@ Welcome
<head>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
- <title>Bitwarden_rs</title>
+ <title>Vaultwarden</title>
</head>
<body style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; height: 100%; line-height: 25px; width: 100% !important;" bgcolor="#f6f6f6">
<style type="text/css">
@@ -121,7 +121,7 @@ Welcome
<td class="aligncenter social-icons" align="center" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 15px 0 0 0;" valign="top">
<table cellpadding="0" cellspacing="0" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0 auto;">
<tr style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0;">
- <td style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 0 10px;" valign="top"><a href="https://github.com/dani-garcia/bitwarden_rs" target="_blank" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; text-decoration: underline;"><img src="{{url}}/bwrs_static/mail-github.png" alt="GitHub" width="30" height="30" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; border: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0; max-width: 100%;" /></a></td>
+ <td style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; padding: 0 10px;" valign="top"><a href="https://github.com/dani-garcia/vaultwarden" target="_blank" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; box-sizing: border-box; color: #999; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 12px; line-height: 20px; margin: 0; text-decoration: underline;"><img src="{{url}}/bwrs_static/mail-github.png" alt="GitHub" width="30" height="30" style="-webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; border: none; box-sizing: border-box; color: #333; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; line-height: 25px; margin: 0; max-width: 100%;" /></a></td>
</tr>
</table>
</td>
diff --git a/src/util.rs b/src/util.rs
index feafa467..b33f5890 100644
--- a/src/util.rs
+++ b/src/util.rs
@@ -28,7 +28,10 @@ impl Fairing for AppHeaders {
res.set_raw_header("X-Frame-Options", "SAMEORIGIN");
res.set_raw_header("X-Content-Type-Options", "nosniff");
res.set_raw_header("X-XSS-Protection", "1; mode=block");
- let csp = format!("frame-ancestors 'self' chrome-extension://nngceckbapebfimnlniiiahkandclblb moz-extension://* {};", CONFIG.allowed_iframe_ancestors());
+ let csp = format!(
+ "frame-ancestors 'self' chrome-extension://nngceckbapebfimnlniiiahkandclblb moz-extension://* {};",
+ CONFIG.allowed_iframe_ancestors()
+ );
res.set_raw_header("Content-Security-Policy", csp);
// Disable cache unless otherwise specified
@@ -124,14 +127,8 @@ impl<'r, R: Responder<'r>> Responder<'r> for Cached<R> {
// Log all the routes from the main paths list, and the attachments endpoint
// Effectively ignores, any static file route, and the alive endpoint
-const LOGGED_ROUTES: [&str; 6] = [
- "/api",
- "/admin",
- "/identity",
- "/icons",
- "/notifications/hub/negotiate",
- "/attachments",
-];
+const LOGGED_ROUTES: [&str; 6] =
+ ["/api", "/admin", "/identity", "/icons", "/notifications/hub/negotiate", "/attachments"];
// Boolean is extra debug, when true, we ignore the whitelist above and also print the mounts
pub struct BetterLogging(pub bool);
@@ -158,7 +155,11 @@ impl Fairing for BetterLogging {
}
let config = rocket.config();
- let scheme = if config.tls_enabled() { "https" } else { "http" };
+ let scheme = if config.tls_enabled() {
+ "https"
+ } else {
+ "http"
+ };
let addr = format!("{}://{}:{}", &scheme, &config.address, &config.port);
info!(target: "start", "Rocket has launched from {}", addr);
}
@@ -293,8 +294,7 @@ where
use std::env;
-pub fn get_env_str_value(key: &str) -> Option<String>
-{
+pub fn get_env_str_value(key: &str) -> Option<String> {
let key_file = format!("{}_FILE", key);
let value_from_env = env::var(key);
let value_file = env::var(&key_file);
@@ -304,9 +304,9 @@ pub fn get_env_str_value(key: &str) -> Option<String>
(Ok(v_env), Err(_)) => Some(v_env),
(Err(_), Ok(v_file)) => match fs::read_to_string(v_file) {
Ok(content) => Some(content.trim().to_string()),
- Err(e) => panic!("Failed to load {}: {:?}", key, e)
+ Err(e) => panic!("Failed to load {}: {:?}", key, e),
},
- _ => None
+ _ => None,
}
}
@@ -478,7 +478,6 @@ pub fn retry<F, T, E>(func: F, max_tries: u32) -> Result<T, E>
where
F: Fn() -> Result<T, E>,
{
- use std::{thread::sleep, time::Duration};
let mut tries = 0;
loop {
@@ -497,12 +496,13 @@ where
}
}
+use std::{thread::sleep, time::Duration};
+
pub fn retry_db<F, T, E>(func: F, max_tries: u32) -> Result<T, E>
where
F: Fn() -> Result<T, E>,
E: std::error::Error,
{
- use std::{thread::sleep, time::Duration};
let mut tries = 0;
loop {
@@ -522,3 +522,18 @@ where
}
}
}
+
+use reqwest::{
+ blocking::{Client, ClientBuilder},
+ header,
+};
+
+pub fn get_reqwest_client() -> Client {
+ get_reqwest_client_builder().build().expect("Failed to build client")
+}
+
+pub fn get_reqwest_client_builder() -> ClientBuilder {
+ let mut headers = header::HeaderMap::new();
+ headers.insert(header::USER_AGENT, header::HeaderValue::from_static("Vaultwarden"));
+ Client::builder().default_headers(headers).timeout(Duration::from_secs(10))
+}