Compare commits

..

49 Commits

Author SHA1 Message Date
Daniel García
45122bed9e Update web vault to v2.25.1b 2022-01-30 21:33:13 +01:00
Daniel García
0876d4a5fd Merge pull request #2257 from jjlin/email-token
Increase length limit for email token generation
2022-01-29 00:05:38 +01:00
Jeremy Lin
7d552dbdc8 Increase length limit for email token generation
The current limit of 19 is an artifact of the implementation, which can be
easily rewritten in terms of a more general string generation function.
The new limit is 255 (max value of a `u8`); using a larger type would
probably be overkill.
2022-01-24 01:17:00 -08:00
Daniel García
9a60eb04c2 Update web vault to 2.25.1 and rust base images to march rust-toolchain, the official rust images don't have nightly builds, so just use the latest 2022-01-24 00:15:25 +01:00
Daniel García
1b99da91fb Merge branch 'dscottboggs-fix/CVE-2022-21658' into main 2022-01-24 00:03:52 +01:00
Daniel García
a64a400c9c Merge branch 'fix/CVE-2022-21658' of https://github.com/dscottboggs/vaultwarden into dscottboggs-fix/CVE-2022-21658 2022-01-24 00:03:46 +01:00
D. Scott Boggs
85c0aa1619 Bump rust version to mitigate CVE-2022-21658 2022-01-23 17:51:36 -05:00
Daniel García
19e78e3509 Merge branch 'jjlin-api-key' into main 2022-01-23 23:50:42 +01:00
Daniel García
bf6330374c Merge branch 'api-key' of https://github.com/jjlin/vaultwarden into jjlin-api-key 2022-01-23 23:50:34 +01:00
Daniel García
e639d9063b Merge branch 'iamdoubz-iamdoubz-feature-to-permissions-policy-patch' into main 2022-01-23 23:44:17 +01:00
Daniel García
4a88e7ec78 Merge branch 'iamdoubz-feature-to-permissions-policy-patch' of https://github.com/iamdoubz/vaultwarden into iamdoubz-iamdoubz-feature-to-permissions-policy-patch 2022-01-23 23:44:08 +01:00
Daniel García
65dad5a9d1 Merge branch 'jjlin-icons' into main 2022-01-23 23:43:30 +01:00
Daniel García
ba9ad14fbb Merge branch 'icons' of https://github.com/jjlin/vaultwarden into jjlin-icons 2022-01-23 23:43:24 +01:00
Daniel García
62c7a4d491 Merge branch 'BlackDex-fix-emergency-invite-register' into main 2022-01-23 23:42:42 +01:00
Daniel García
14e3dcad8e Merge branch 'fix-emergency-invite-register' of https://github.com/BlackDex/vaultwarden into BlackDex-fix-emergency-invite-register 2022-01-23 23:42:35 +01:00
Daniel García
f4a9645b54 Remove references to "bwrs" #2195
Squashed commit of the following:

commit 1bdf1c7954e0731c95703d10118f3874ab5155d3
Merge: 8ba6e61 7257251
Author: Daniel García <dani-garcia@users.noreply.github.com>
Date:   Sun Jan 23 23:40:17 2022 +0100

    Merge branch 'remove-bwrs' of https://github.com/RealOrangeOne/vaultwarden into RealOrangeOne-remove-bwrs

commit 7257251ecf
Author: Jake Howard <git@theorangeone.net>
Date:   Thu Jan 6 17:48:18 2022 +0000

    Use `or_else` to save potentially unnecessary function call

commit 40ae81dd3c
Author: Jake Howard <git@theorangeone.net>
Date:   Wed Jan 5 21:18:24 2022 +0000

    Move $BWRS_VERSION fallback into build.rs

commit 743ef74b30
Author: Jake Howard <git@theorangeone.net>
Date:   Sat Jan 1 23:08:27 2022 +0000

    Revert "Add feature to enable use of `Option::or` in const context"

    This reverts commit fe8e043b8a.

    We want to run on stable soon, where these features are not supported

commit a1f0da638c
Author: Jake Howard <git@theorangeone.net>
Date:   Sat Jan 1 13:04:47 2022 +0000

    Rename web vault version file

    https://github.com/dani-garcia/bw_web_builds/pull/58

commit fe8e043b8a
Author: Jake Howard <git@theorangeone.net>
Date:   Sat Jan 1 12:56:44 2022 +0000

    Add feature to enable use of `Option::or` in const context

commit 687435c8b2
Author: Jake Howard <git@theorangeone.net>
Date:   Sat Jan 1 12:27:28 2022 +0000

    Continue to allow using `$BWRS_VERSION`

commit 8e2f708e50
Author: Jake Howard <git@theorangeone.net>
Date:   Fri Dec 31 11:41:34 2021 +0000

    Remove references to "bwrs"

    The only remaining one is getting the version of the web vault, which requires coordinating with the web vault patching.
2022-01-23 23:40:59 +01:00
Jeremy Lin
8f7900759f Fix scope and refresh_token for API key logins
API key logins use a scope of `api`, not `api offline_access`. Since
`offline_access` is not requested, no `refresh_token` is returned either.
2022-01-21 23:10:15 -08:00
Jeremy Lin
69ee4a70b4 Add support for API keys
This is mainly useful for CLI-based login automation.
2022-01-21 23:10:11 -08:00
iamdoubz
e4e16ed50f Upgrade Feature-Policy to Permissions-Policy
Convert old, soon to be defunct, Feature-Policy with its replacement Permissions-Policy
2022-01-12 10:36:50 -06:00
Jeremy Lin
a16c656770 Add support for legacy HTTP 301/302 redirects for external icons
At least on Android, it seems the Bitwarden mobile client responds to
HTTP 307, but not to HTTP 308 for some reason.
2022-01-08 23:40:35 -08:00
BlackDex
76b7de15de Fix emergency access invites for new users
If a new user gets invited it should check if the user is invited via
emergency access, if so, allow that user to register.
2022-01-07 18:55:48 +01:00
Daniel García
8ba6e61fd5 Merge pull request #2197 from BlackDex/issue-2196
Fix issue with Bitwarden CLI.
2022-01-02 23:47:40 +01:00
Daniel García
a30a1c9703 Merge pull request #2194 from BlackDex/issue-2154
Fixed issue #2154
2022-01-02 23:46:32 +01:00
Daniel García
76687e2df7 Merge pull request #2188 from jjlin/icons
Add config option to set the HTTP redirect code for external icons
2022-01-02 23:46:23 +01:00
BlackDex
bf5aefd129 Fix issue with Bitwarden CLI.
The CLI seems to send a String instead of an Integer for the maximum access count.
It now accepts both types and converts it to an i32 in all cases.

Fixes #2196
2021-12-31 15:59:58 +01:00
BlackDex
1fa178d1d3 Fixed issue #2154
For emergency access invitations we need to check if invites are
allowed, not if sign-ups are allowed.
2021-12-31 11:53:21 +01:00
Jeremy Lin
b7eedbcddc Add config option to set the HTTP redirect code for external icons
The default code is 307 (temporary) to make it easier to test different icon
services, but once a service has been decided on, users should ideally switch
to using permanent redirects for cacheability.
2021-12-30 23:06:52 -08:00
Daniel García
920371929b Merge pull request #2182 from RealOrangeOne/cache-expires-header
Set `Expires` header when caching responses
2021-12-30 01:38:39 +01:00
Jake Howard
6ddbe84bde Remove unnecessary return 2021-12-29 16:29:42 +00:00
Jake Howard
690d0ed1bb Add our own HTTP date formatter 2021-12-29 16:21:28 +00:00
Jake Howard
248e7dabc2 Collapse field name definition
Co-authored-by: Daniel García <dani-garcia@users.noreply.github.com>
2021-12-28 21:54:09 +00:00
Jake Howard
4584cfe3c1 Additionally set expires header when caching responses
Browsers are rather smart, but also dumb. This uses the `Expires` header
alongside `cache-control` to better prompt the browser to actually
cache.

Unfortunately, firefox still tries to "race" its own cache, in an
attempt to respond to requests faster, so still ends up making a bunch
of requests which could have been cached. Doesn't appear there's any way
around this.
2021-12-28 16:24:47 +00:00
Daniel García
cc646b1519 Merge branch 'BlackDex-multi-db-dockers' into main 2021-12-27 21:55:36 +01:00
Daniel García
e501dc6d0e Merge branch 'multi-db-dockers' of https://github.com/BlackDex/vaultwarden into BlackDex-multi-db-dockers 2021-12-27 21:55:28 +01:00
Daniel García
85ac9783f0 Merge branch 'ratelimit' into main 2021-12-27 21:55:15 +01:00
BlackDex
5b430f22bc Support all DB's for Alpine and Debian
- Using my own rust-musl build containers we now support all database
types for both Debian and Alpine.
- Added new Alpine containers for armv6 and arm64/aarch64
- The Debian builds can also be done wihout dpkg magic stuff, probably
some fixes in Rust regarding linking (Or maybe OpenSSL or Diesel), in
any case, it works now without hacking dpkg and apt.
- Updated toolchain and crates
2021-12-26 21:59:28 +01:00
Daniel García
d4eb21c2d9 Better document the new rate limiting 2021-12-25 01:12:09 +01:00
Daniel García
6bf8a9d93d Merge pull request #2171 from jjlin/global-domains
Sync global_domains.json
2021-12-25 00:55:50 +01:00
Jeremy Lin
605419ae1b Sync global_domains.json to bitwarden/server@5a8f334 (TransferWise) 2021-12-24 13:25:16 -08:00
Daniel García
b89ffb2731 Merge pull request #2170 from BlackDex/issue-2136
Small changes to icon log messages.
2021-12-24 20:40:30 +01:00
Daniel García
bda123b1eb Merge pull request #2169 from BlackDex/issue-2151
Fixed #2151
2021-12-24 20:40:07 +01:00
BlackDex
2c94ea075c Small changes to icon log messages.
As requested in #2136, some small changes on the type of log messages
and wording used.

Resolves #2136
2021-12-24 18:24:25 +01:00
BlackDex
4bd8eae07e Fixed #2151 2021-12-24 17:59:12 +01:00
Daniel García
5529264c3f Basic ratelimit for user login (including 2FA) and admin login 2021-12-22 21:48:49 +01:00
Daniel García
0a5df06e77 Merge pull request #2158 from jjlin/icons
Add support for external icon services
2021-12-22 15:46:30 +01:00
Jeremy Lin
2f9ac61a4e Add support for external icon services
If an external icon service is configured, icon requests return an HTTP
redirect to the corresponding icon at the external service.

An external service may be useful for various reasons, such as if:

* The Vaultwarden instance has no external network connectivity.
* The Vaultwarden instance has trouble handling large bursts of icon requests.
* There are concerns that an attacker may probe the instance to try to detect
  whether icons for certain sites have been cached, which would suggest that
  the instance contains entries for those sites.
* The external icon service does a better job of providing icons than the
  built-in fetcher.
2021-12-20 01:34:31 -08:00
Daniel García
840cf8740a Merge pull request #2156 from jjlin/global-domains
Sync global_domains.json
2021-12-19 17:39:45 +01:00
Jeremy Lin
d8869adf52 Sync global_domains.json to bitwarden/server@224bfb6 (Wells Fargo) 2021-12-18 16:19:05 -08:00
Jeremy Lin
a631fc0077 Sync global_domains.json to bitwarden/server@2f518fb (Ubisoft) 2021-12-18 16:19:05 -08:00
56 changed files with 1548 additions and 698 deletions

View File

@@ -129,10 +129,32 @@
## Number of times to retry the database connection during startup, with 1 second delay between each retry, set to 0 to retry indefinitely ## Number of times to retry the database connection during startup, with 1 second delay between each retry, set to 0 to retry indefinitely
# DB_CONNECTION_RETRIES=15 # DB_CONNECTION_RETRIES=15
## Icon service
## The predefined icon services are: internal, bitwarden, duckduckgo, google.
## To specify a custom icon service, set a URL template with exactly one instance of `{}`,
## which is replaced with the domain. For example: `https://icon.example.com/domain/{}`.
##
## `internal` refers to Vaultwarden's built-in icon fetching implementation.
## If an external service is set, an icon request to Vaultwarden will return an HTTP
## redirect to the corresponding icon at the external service. An external service may
## be useful if your Vaultwarden instance has no external network connectivity, or if
## you are concerned that someone may probe your instance to try to detect whether icons
## for certain sites have been cached.
# ICON_SERVICE=internal
## Icon redirect code
## The HTTP status code to use for redirects to an external icon service.
## The supported codes are 301 (legacy permanent), 302 (legacy temporary), 307 (temporary), and 308 (permanent).
## Temporary redirects are useful while testing different icon services, but once a service
## has been decided on, consider using permanent redirects for cacheability. The legacy codes
## are currently better supported by the Bitwarden clients.
# ICON_REDIRECT_CODE=302
## Disable icon downloading ## Disable icon downloading
## Set to true to disable icon downloading, this would still serve icons from $ICON_CACHE_FOLDER, ## Set to true to disable icon downloading in the internal icon service.
## but it won't produce any external network request. Needs to set $ICON_CACHE_TTL to 0, ## This still serves existing icons from $ICON_CACHE_FOLDER, without generating any external
## otherwise it will delete them and they won't be downloaded again. ## network requests. $ICON_CACHE_TTL must also be set to 0; otherwise, the existing icons
## will be deleted eventually, but won't be downloaded again.
# DISABLE_ICON_DOWNLOAD=false # DISABLE_ICON_DOWNLOAD=false
## Icon download timeout ## Icon download timeout
@@ -163,7 +185,7 @@
# EMAIL_EXPIRATION_TIME=600 # EMAIL_EXPIRATION_TIME=600
## Email token size ## Email token size
## Number of digits in an email token (min: 6, max: 19). ## Number of digits in an email 2FA token (min: 6, max: 255).
## Note that the Bitwarden clients are hardcoded to mention 6 digit codes regardless of this setting! ## Note that the Bitwarden clients are hardcoded to mention 6 digit codes regardless of this setting!
# EMAIL_TOKEN_SIZE=6 # EMAIL_TOKEN_SIZE=6
@@ -254,6 +276,17 @@
## Multiple values must be separated with a whitespace. ## Multiple values must be separated with a whitespace.
# ALLOWED_IFRAME_ANCESTORS= # ALLOWED_IFRAME_ANCESTORS=
## Number of seconds, on average, between login requests from the same IP address before rate limiting kicks in.
# LOGIN_RATELIMIT_SECONDS=60
## Allow a burst of requests of up to this size, while maintaining the average indicated by `LOGIN_RATELIMIT_SECONDS`.
## Note that this applies to both the login and the 2FA, so it's recommended to allow a burst size of at least 2.
# LOGIN_RATELIMIT_MAX_BURST=10
## Number of seconds, on average, between admin requests from the same IP address before rate limiting kicks in.
# ADMIN_RATELIMIT_SECONDS=300
## Allow a burst of requests of up to this size, while maintaining the average indicated by `ADMIN_RATELIMIT_SECONDS`.
# ADMIN_RATELIMIT_MAX_BURST=3
## Yubico (Yubikey) Settings ## Yubico (Yubikey) Settings
## Set your Client ID and Secret Key for Yubikey OTP ## Set your Client ID and Secret Key for Yubikey OTP
## You can generate it here: https://upgrade.yubico.com/getapikey/ ## You can generate it here: https://upgrade.yubico.com/getapikey/

316
Cargo.lock generated
View File

@@ -17,6 +17,12 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "ahash"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8fd72866655d1904d6b0997d0b07ba561047d070fbe29de039031c641b61217"
[[package]] [[package]]
name = "aho-corasick" name = "aho-corasick"
version = "0.7.18" version = "0.7.18"
@@ -57,13 +63,13 @@ dependencies = [
[[package]] [[package]]
name = "async-trait" name = "async-trait"
version = "0.1.51" version = "0.1.52"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e" checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3"
dependencies = [ dependencies = [
"proc-macro2 1.0.32", "proc-macro2 1.0.34",
"quote 1.0.10", "quote 1.0.10",
"syn 1.0.82", "syn 1.0.84",
] ]
[[package]] [[package]]
@@ -283,13 +289,13 @@ dependencies = [
[[package]] [[package]]
name = "chrono-tz" name = "chrono-tz"
version = "0.6.0" version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64c01c1c607d25c71bbaa67c113d6c6b36c434744b4fd66691d711b5b1bc0c8b" checksum = "58549f1842da3080ce63002102d5bc954c7bc843d4f47818e642abdc36253552"
dependencies = [ dependencies = [
"chrono", "chrono",
"chrono-tz-build", "chrono-tz-build",
"phf 0.10.0", "phf 0.10.1",
] ]
[[package]] [[package]]
@@ -299,7 +305,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db058d493fb2f65f41861bfed7e3fe6335264a9f0f92710cab5bdf01fef09069" checksum = "db058d493fb2f65f41861bfed7e3fe6335264a9f0f92710cab5bdf01fef09069"
dependencies = [ dependencies = [
"parse-zoneinfo", "parse-zoneinfo",
"phf 0.10.0", "phf 0.10.1",
"phf_codegen 0.10.0", "phf_codegen 0.10.0",
] ]
@@ -412,6 +418,16 @@ dependencies = [
"subtle", "subtle",
] ]
[[package]]
name = "dashmap"
version = "4.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c"
dependencies = [
"cfg-if 1.0.0",
"num_cpus",
]
[[package]] [[package]]
name = "data-encoding" name = "data-encoding"
version = "2.3.2" version = "2.3.2"
@@ -451,9 +467,9 @@ version = "0.3.0"
source = "git+https://github.com/SergioBenitez/Devise.git?rev=e58b3ac9a#e58b3ac9afc3b6ff10a8aaf02a3e768a8f530089" source = "git+https://github.com/SergioBenitez/Devise.git?rev=e58b3ac9a#e58b3ac9afc3b6ff10a8aaf02a3e768a8f530089"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"proc-macro2 1.0.32", "proc-macro2 1.0.34",
"quote 1.0.10", "quote 1.0.10",
"syn 1.0.82", "syn 1.0.84",
] ]
[[package]] [[package]]
@@ -479,9 +495,9 @@ version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45f5098f628d02a7a0f68ddba586fb61e80edec3bdc1be3b921f4ceec60858d3" checksum = "45f5098f628d02a7a0f68ddba586fb61e80edec3bdc1be3b921f4ceec60858d3"
dependencies = [ dependencies = [
"proc-macro2 1.0.32", "proc-macro2 1.0.34",
"quote 1.0.10", "quote 1.0.10",
"syn 1.0.82", "syn 1.0.84",
] ]
[[package]] [[package]]
@@ -532,9 +548,9 @@ checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]] [[package]]
name = "encoding_rs" name = "encoding_rs"
version = "0.8.29" version = "0.8.30"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a74ea89a0a1b98f6332de42c95baff457ada66d1cb4030f9ff151b2041a1c746" checksum = "7896dc8abb250ffdda33912550faa54c88ec8b998dec0b2c55ab224921ce11df"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
] ]
@@ -546,9 +562,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c5f0096a91d210159eceb2ff5e1c4da18388a170e1e3ce948aac9c8fdbbf595" checksum = "7c5f0096a91d210159eceb2ff5e1c4da18388a170e1e3ce948aac9c8fdbbf595"
dependencies = [ dependencies = [
"heck", "heck",
"proc-macro2 1.0.32", "proc-macro2 1.0.34",
"quote 1.0.10", "quote 1.0.10",
"syn 1.0.82", "syn 1.0.84",
] ]
[[package]] [[package]]
@@ -568,9 +584,9 @@ checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
[[package]] [[package]]
name = "fastrand" name = "fastrand"
version = "1.5.0" version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b394ed3d285a429378d3b384b9eb1285267e7df4b166df24b7a6939a04dc392e" checksum = "779d043b6a0b90cc4c0ed7ee380a6504394cee7efd7db050e3774eee387324b2"
dependencies = [ dependencies = [
"instant", "instant",
] ]
@@ -662,9 +678,9 @@ dependencies = [
[[package]] [[package]]
name = "futures" name = "futures"
version = "0.3.18" version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8cd0210d8c325c245ff06fd95a3b13689a1a276ac8cfa8e8720cb840bfb84b9e" checksum = "28560757fe2bb34e79f907794bb6b22ae8b0e5c669b638a1132f2592b19035b4"
dependencies = [ dependencies = [
"futures-channel", "futures-channel",
"futures-core", "futures-core",
@@ -677,9 +693,9 @@ dependencies = [
[[package]] [[package]]
name = "futures-channel" name = "futures-channel"
version = "0.3.18" version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fc8cd39e3dbf865f7340dce6a2d401d24fd37c6fe6c4f0ee0de8bfca2252d27" checksum = "ba3dda0b6588335f360afc675d0564c17a77a2bda81ca178a4b6081bd86c7f0b"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"futures-sink", "futures-sink",
@@ -687,15 +703,15 @@ dependencies = [
[[package]] [[package]]
name = "futures-core" name = "futures-core"
version = "0.3.18" version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "629316e42fe7c2a0b9a65b47d159ceaa5453ab14e8f0a3c5eedbb8cd55b4a445" checksum = "d0c8ff0461b82559810cdccfde3215c3f373807f5e5232b71479bff7bb2583d7"
[[package]] [[package]]
name = "futures-executor" name = "futures-executor"
version = "0.3.18" version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b808bf53348a36cab739d7e04755909b9fcaaa69b7d7e588b37b6ec62704c97" checksum = "29d6d2ff5bb10fb95c85b8ce46538a2e5f5e7fdc755623a7d4529ab8a4ed9d2a"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"futures-task", "futures-task",
@@ -704,38 +720,44 @@ dependencies = [
[[package]] [[package]]
name = "futures-io" name = "futures-io"
version = "0.3.18" version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e481354db6b5c353246ccf6a728b0c5511d752c08da7260546fc0933869daa11" checksum = "b1f9d34af5a1aac6fb380f735fe510746c38067c5bf16c7fd250280503c971b2"
[[package]] [[package]]
name = "futures-macro" name = "futures-macro"
version = "0.3.18" version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a89f17b21645bc4ed773c69af9c9a0effd4a3f1a3876eadd453469f8854e7fdd" checksum = "6dbd947adfffb0efc70599b3ddcf7b5597bb5fa9e245eb99f62b3a5f7bb8bd3c"
dependencies = [ dependencies = [
"proc-macro2 1.0.32", "proc-macro2 1.0.34",
"quote 1.0.10", "quote 1.0.10",
"syn 1.0.82", "syn 1.0.84",
] ]
[[package]] [[package]]
name = "futures-sink" name = "futures-sink"
version = "0.3.18" version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "996c6442437b62d21a32cd9906f9c41e7dc1e19a9579843fad948696769305af" checksum = "e3055baccb68d74ff6480350f8d6eb8fcfa3aa11bdc1a1ae3afdd0514617d508"
[[package]] [[package]]
name = "futures-task" name = "futures-task"
version = "0.3.18" version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dabf1872aaab32c886832f2276d2f5399887e2bd613698a02359e4ea83f8de12" checksum = "6ee7c6485c30167ce4dfb83ac568a849fe53274c831081476ee13e0dce1aad72"
[[package]]
name = "futures-timer"
version = "3.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c"
[[package]] [[package]]
name = "futures-util" name = "futures-util"
version = "0.3.18" version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d22213122356472061ac0f1ab2cee28d2bac8491410fd68c2af53d1cedb83e" checksum = "d9b5cf40b47a271f77a8b1bec03ca09044d99d2372c0de244e66430761127164"
dependencies = [ dependencies = [
"futures-channel", "futures-channel",
"futures-core", "futures-core",
@@ -803,10 +825,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
[[package]] [[package]]
name = "h2" name = "governor"
version = "0.3.7" version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fd819562fcebdac5afc5c113c3ec36f902840b70fd4fc458799c8ce4607ae55" checksum = "06c5d2f987ee8f6dff3fa1a352058dc59b990e447e4c7846aa7d804971314f7b"
dependencies = [
"dashmap",
"futures",
"futures-timer",
"no-std-compat",
"nonzero_ext",
"parking_lot 0.11.2",
"quanta",
"rand 0.8.4",
"smallvec 1.7.0",
]
[[package]]
name = "h2"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f072413d126e57991455e0a922b31e4c8ba7c2ffbebf6b78b4f8521397d65cd"
dependencies = [ dependencies = [
"bytes 1.1.0", "bytes 1.1.0",
"fnv", "fnv",
@@ -829,9 +868,9 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
[[package]] [[package]]
name = "handlebars" name = "handlebars"
version = "4.1.5" version = "4.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ad84da8f63da982543fc85fcabaee2ad1fdd809d99d64a48887e2e942ddfe46" checksum = "167fa173496c9eadd8749cca6f8339ac88e248f3ad2442791d0b743318a94fc0"
dependencies = [ dependencies = [
"log 0.4.14", "log 0.4.14",
"pest", "pest",
@@ -842,6 +881,16 @@ dependencies = [
"walkdir", "walkdir",
] ]
[[package]]
name = "hashbrown"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91b62f79061a0bc2e046024cb7ba44b08419ed238ecbd9adbd787434b9e8c25"
dependencies = [
"ahash",
"autocfg",
]
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.11.2" version = "0.11.2"
@@ -906,9 +955,9 @@ dependencies = [
"log 0.4.14", "log 0.4.14",
"mac", "mac",
"markup5ever", "markup5ever",
"proc-macro2 1.0.32", "proc-macro2 1.0.34",
"quote 1.0.10", "quote 1.0.10",
"syn 1.0.82", "syn 1.0.84",
] ]
[[package]] [[package]]
@@ -919,7 +968,7 @@ checksum = "1323096b05d41827dadeaee54c9981958c0f94e670bc94ed80037d1a7b8b186b"
dependencies = [ dependencies = [
"bytes 1.1.0", "bytes 1.1.0",
"fnv", "fnv",
"itoa", "itoa 0.4.8",
] ]
[[package]] [[package]]
@@ -966,9 +1015,9 @@ dependencies = [
[[package]] [[package]]
name = "hyper" name = "hyper"
version = "0.14.15" version = "0.14.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "436ec0091e4f20e655156a30a0df3770fe2900aa301e548e08446ec794b6953c" checksum = "b7ec3e62bdc98a2f0393a5048e4c30ef659440ea6e0e572965103e72bd836f55"
dependencies = [ dependencies = [
"bytes 1.1.0", "bytes 1.1.0",
"futures-channel", "futures-channel",
@@ -979,7 +1028,7 @@ dependencies = [
"http-body", "http-body",
"httparse", "httparse",
"httpdate", "httpdate",
"itoa", "itoa 0.4.8",
"pin-project-lite", "pin-project-lite",
"socket2 0.4.2", "socket2 0.4.2",
"tokio", "tokio",
@@ -1007,7 +1056,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
dependencies = [ dependencies = [
"bytes 1.1.0", "bytes 1.1.0",
"hyper 0.14.15", "hyper 0.14.16",
"native-tls", "native-tls",
"tokio", "tokio",
"tokio-native-tls", "tokio-native-tls",
@@ -1042,7 +1091,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"hashbrown", "hashbrown 0.11.2",
] ]
[[package]] [[package]]
@@ -1087,6 +1136,12 @@ version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
[[package]]
name = "itoa"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
[[package]] [[package]]
name = "job_scheduler" name = "job_scheduler"
version = "1.2.1" version = "1.2.1"
@@ -1171,9 +1226,9 @@ dependencies = [
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.108" version = "0.2.112"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8521a1b57e76b1ec69af7599e75e38e7b7fad6610f037db8c79b127201b5d119" checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125"
[[package]] [[package]]
name = "libsqlite3-sys" name = "libsqlite3-sys"
@@ -1306,9 +1361,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9753f12909fd8d923f75ae5c3258cae1ed3c8ec052e1b38c93c21a6d157f789c" checksum = "9753f12909fd8d923f75ae5c3258cae1ed3c8ec052e1b38c93c21a6d157f789c"
dependencies = [ dependencies = [
"migrations_internals", "migrations_internals",
"proc-macro2 1.0.32", "proc-macro2 1.0.34",
"quote 1.0.10", "quote 1.0.10",
"syn 1.0.82", "syn 1.0.84",
] ]
[[package]] [[package]]
@@ -1480,6 +1535,15 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
[[package]]
name = "no-std-compat"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c"
dependencies = [
"hashbrown 0.8.2",
]
[[package]] [[package]]
name = "nom" name = "nom"
version = "4.1.1" version = "4.1.1"
@@ -1500,6 +1564,12 @@ dependencies = [
"version_check 0.9.3", "version_check 0.9.3",
] ]
[[package]]
name = "nonzero_ext"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44a1290799eababa63ea60af0cbc3f03363e328e58f32fb0294798ed3e85f444"
[[package]] [[package]]
name = "ntapi" name = "ntapi"
version = "0.3.6" version = "0.3.6"
@@ -1526,9 +1596,9 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d"
dependencies = [ dependencies = [
"proc-macro2 1.0.32", "proc-macro2 1.0.34",
"quote 1.0.10", "quote 1.0.10",
"syn 1.0.82", "syn 1.0.84",
] ]
[[package]] [[package]]
@@ -1552,9 +1622,9 @@ dependencies = [
[[package]] [[package]]
name = "num_cpus" name = "num_cpus"
version = "1.13.0" version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
dependencies = [ dependencies = [
"hermit-abi", "hermit-abi",
"libc", "libc",
@@ -1571,9 +1641,9 @@ dependencies = [
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.8.0" version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
[[package]] [[package]]
name = "opaque-debug" name = "opaque-debug"
@@ -1609,18 +1679,18 @@ checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a"
[[package]] [[package]]
name = "openssl-src" name = "openssl-src"
version = "300.0.2+3.0.0" version = "111.17.0+1.1.1m"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14a760a11390b1a5daf72074d4f6ff1a6e772534ae191f999f57e9ee8146d1fb" checksum = "05d6a336abd10814198f66e2a91ccd7336611f30334119ca8ce300536666fcf4"
dependencies = [ dependencies = [
"cc", "cc",
] ]
[[package]] [[package]]
name = "openssl-sys" name = "openssl-sys"
version = "0.9.71" version = "0.9.72"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7df13d165e607909b363a4757a6f133f8a818a74e9d3a98d09c6128e15fa4c73" checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"cc", "cc",
@@ -1791,9 +1861,9 @@ checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55"
dependencies = [ dependencies = [
"pest", "pest",
"pest_meta", "pest_meta",
"proc-macro2 1.0.32", "proc-macro2 1.0.34",
"quote 1.0.10", "quote 1.0.10",
"syn 1.0.82", "syn 1.0.84",
] ]
[[package]] [[package]]
@@ -1818,9 +1888,9 @@ dependencies = [
[[package]] [[package]]
name = "phf" name = "phf"
version = "0.10.0" version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9fc3db1018c4b59d7d582a739436478b6035138b6aecbce989fc91c3e98409f" checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259"
dependencies = [ dependencies = [
"phf_shared 0.10.0", "phf_shared 0.10.0",
] ]
@@ -1904,9 +1974,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]] [[package]]
name = "pkg-config" name = "pkg-config"
version = "0.3.22" version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12295df4f294471248581bc09bef3c38a5e46f1e36d6a37353621a0c6c357e1f" checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe"
[[package]] [[package]]
name = "ppv-lite86" name = "ppv-lite86"
@@ -1946,18 +2016,18 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.32" version = "1.0.34"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" checksum = "2f84e92c0f7c9d58328b85a78557813e4bd845130db68d7184635344399423b1"
dependencies = [ dependencies = [
"unicode-xid 0.2.2", "unicode-xid 0.2.2",
] ]
[[package]] [[package]]
name = "psl-types" name = "psl-types"
version = "2.0.9" version = "2.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4af8f675df9e68626b5059f8909ae261b8f5c3e8ab14813ad7f6cc7a134dcafb" checksum = "e8eda7c62d9ecaafdf8b62374c006de0adf61666ae96a96ba74a37134aa4e470"
[[package]] [[package]]
name = "publicsuffix" name = "publicsuffix"
@@ -1966,11 +2036,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "292972edad6bbecc137ab84c5e36421a4a6c979ea31d3cc73540dd04315b33e1" checksum = "292972edad6bbecc137ab84c5e36421a4a6c979ea31d3cc73540dd04315b33e1"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"hashbrown", "hashbrown 0.11.2",
"idna 0.2.3", "idna 0.2.3",
"psl-types", "psl-types",
] ]
[[package]]
name = "quanta"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d98dc777a7a39b76b1a26ae9d3f691f4c1bc0455090aa0b64dfa8cb7fc34c135"
dependencies = [
"libc",
"winapi 0.3.9",
]
[[package]] [[package]]
name = "quick-error" name = "quick-error"
version = "1.2.3" version = "1.2.3"
@@ -1998,7 +2078,7 @@ version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
dependencies = [ dependencies = [
"proc-macro2 1.0.32", "proc-macro2 1.0.34",
] ]
[[package]] [[package]]
@@ -2183,9 +2263,9 @@ dependencies = [
[[package]] [[package]]
name = "reqwest" name = "reqwest"
version = "0.11.7" version = "0.11.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07bea77bc708afa10e59905c3d4af7c8fd43c9214251673095ff8b14345fcbc5" checksum = "7c4e0a76dc12a116108933f6301b95e83634e0c47b0afbed6abbaa0601e99258"
dependencies = [ dependencies = [
"async-compression", "async-compression",
"base64 0.13.0", "base64 0.13.0",
@@ -2197,7 +2277,7 @@ dependencies = [
"futures-util", "futures-util",
"http", "http",
"http-body", "http-body",
"hyper 0.14.15", "hyper 0.14.16",
"hyper-tls", "hyper-tls",
"ipnet", "ipnet",
"js-sys", "js-sys",
@@ -2361,9 +2441,9 @@ dependencies = [
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.6" version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c9613b5a66ab9ba26415184cfc41156594925a9cf3a2057e57f31ff145f6568" checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
[[package]] [[package]]
name = "safemem" name = "safemem"
@@ -2455,9 +2535,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.130" version = "1.0.132"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" checksum = "8b9875c23cf305cd1fd7eb77234cbb705f21ea6a72c637a5c6db5fe4b8e7f008"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
@@ -2483,22 +2563,22 @@ dependencies = [
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.130" version = "1.0.132"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" checksum = "ecc0db5cb2556c0e558887d9bbdcf6ac4471e83ff66cf696e5419024d1606276"
dependencies = [ dependencies = [
"proc-macro2 1.0.32", "proc-macro2 1.0.34",
"quote 1.0.10", "quote 1.0.10",
"syn 1.0.82", "syn 1.0.84",
] ]
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.72" version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0ffa0837f2dfa6fb90868c2b5468cad482e175f7dad97e7421951e663f2b527" checksum = "bcbd0344bc6533bc7ec56df11d42fb70f1b912351c0825ccb7211b59d8af7cf5"
dependencies = [ dependencies = [
"itoa", "itoa 1.0.1",
"ryu", "ryu",
"serde", "serde",
] ]
@@ -2510,7 +2590,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9" checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9"
dependencies = [ dependencies = [
"form_urlencoded", "form_urlencoded",
"itoa", "itoa 0.4.8",
"ryu", "ryu",
"serde", "serde",
] ]
@@ -2665,11 +2745,11 @@ version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef"
dependencies = [ dependencies = [
"proc-macro2 1.0.32", "proc-macro2 1.0.34",
"quote 1.0.10", "quote 1.0.10",
"serde", "serde",
"serde_derive", "serde_derive",
"syn 1.0.82", "syn 1.0.84",
] ]
[[package]] [[package]]
@@ -2679,13 +2759,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11"
dependencies = [ dependencies = [
"base-x", "base-x",
"proc-macro2 1.0.32", "proc-macro2 1.0.34",
"quote 1.0.10", "quote 1.0.10",
"serde", "serde",
"serde_derive", "serde_derive",
"serde_json", "serde_json",
"sha1", "sha1",
"syn 1.0.82", "syn 1.0.84",
] ]
[[package]] [[package]]
@@ -2716,7 +2796,7 @@ checksum = "f24c8e5e19d22a726626f1a5e16fe15b132dcf21d10177fa5a45ce7962996b97"
dependencies = [ dependencies = [
"phf_generator 0.8.0", "phf_generator 0.8.0",
"phf_shared 0.8.0", "phf_shared 0.8.0",
"proc-macro2 1.0.32", "proc-macro2 1.0.34",
"quote 1.0.10", "quote 1.0.10",
] ]
@@ -2739,11 +2819,11 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.82" version = "1.0.84"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" checksum = "ecb2e6da8ee5eb9a61068762a32fa9619cc591ceb055b3687f4cd4051ec2e06b"
dependencies = [ dependencies = [
"proc-macro2 1.0.32", "proc-macro2 1.0.34",
"quote 1.0.10", "quote 1.0.10",
"unicode-xid 0.2.2", "unicode-xid 0.2.2",
] ]
@@ -2800,9 +2880,9 @@ version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
dependencies = [ dependencies = [
"proc-macro2 1.0.32", "proc-macro2 1.0.34",
"quote 1.0.10", "quote 1.0.10",
"syn 1.0.82", "syn 1.0.84",
] ]
[[package]] [[package]]
@@ -2857,10 +2937,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f"
dependencies = [ dependencies = [
"proc-macro-hack", "proc-macro-hack",
"proc-macro2 1.0.32", "proc-macro2 1.0.34",
"quote 1.0.10", "quote 1.0.10",
"standback", "standback",
"syn 1.0.82", "syn 1.0.84",
] ]
[[package]] [[package]]
@@ -2880,11 +2960,10 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.14.0" version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70e992e41e0d2fb9f755b37446f20900f64446ef54874f40a60c78f021ac6144" checksum = "fbbf1c778ec206785635ce8ad57fe52b3009ae9e0c9f574a728f3049d3e55838"
dependencies = [ dependencies = [
"autocfg",
"bytes 1.1.0", "bytes 1.1.0",
"libc", "libc",
"memchr", "memchr",
@@ -2976,9 +3055,9 @@ version = "0.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4f480b8f81512e825f337ad51e94c1eb5d3bbdf2b363dcd01e2b19a9ffe3f8e" checksum = "f4f480b8f81512e825f337ad51e94c1eb5d3bbdf2b363dcd01e2b19a9ffe3f8e"
dependencies = [ dependencies = [
"proc-macro2 1.0.32", "proc-macro2 1.0.34",
"quote 1.0.10", "quote 1.0.10",
"syn 1.0.82", "syn 1.0.84",
] ]
[[package]] [[package]]
@@ -3064,9 +3143,9 @@ checksum = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887"
[[package]] [[package]]
name = "typenum" name = "typenum"
version = "1.14.0" version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
[[package]] [[package]]
name = "u2f" name = "u2f"
@@ -3213,6 +3292,7 @@ dependencies = [
"diesel_migrations", "diesel_migrations",
"dotenv", "dotenv",
"fern", "fern",
"governor",
"handlebars", "handlebars",
"html5ever", "html5ever",
"idna 0.2.3", "idna 0.2.3",
@@ -3321,9 +3401,9 @@ dependencies = [
"bumpalo", "bumpalo",
"lazy_static", "lazy_static",
"log 0.4.14", "log 0.4.14",
"proc-macro2 1.0.32", "proc-macro2 1.0.34",
"quote 1.0.10", "quote 1.0.10",
"syn 1.0.82", "syn 1.0.84",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@@ -3355,9 +3435,9 @@ version = "0.2.78"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab"
dependencies = [ dependencies = [
"proc-macro2 1.0.32", "proc-macro2 1.0.34",
"quote 1.0.10", "quote 1.0.10",
"syn 1.0.82", "syn 1.0.84",
"wasm-bindgen-backend", "wasm-bindgen-backend",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@@ -3380,12 +3460,11 @@ dependencies = [
[[package]] [[package]]
name = "webauthn-rs" name = "webauthn-rs"
version = "0.3.0" version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5275a4ed4cd88814475b5ec51b84886eb17691fd3171f565581eca91d3489a10" checksum = "261310333d5941ec47038eed295ee0ed6f5cee36b7575dc6c4b63ee8e7fe590c"
dependencies = [ dependencies = [
"base64 0.13.0", "base64 0.13.0",
"log 0.4.14",
"nom 4.1.1", "nom 4.1.1",
"openssl", "openssl",
"rand 0.8.4", "rand 0.8.4",
@@ -3395,6 +3474,7 @@ dependencies = [
"serde_derive", "serde_derive",
"serde_json", "serde_json",
"thiserror", "thiserror",
"tracing",
"url 2.2.2", "url 2.2.2",
] ]

View File

@@ -3,7 +3,7 @@ name = "vaultwarden"
version = "1.0.0" version = "1.0.0"
authors = ["Daniel García <dani-garcia@users.noreply.github.com>"] authors = ["Daniel García <dani-garcia@users.noreply.github.com>"]
edition = "2021" edition = "2021"
rust-version = "1.57" rust-version = "1.60"
resolver = "2" resolver = "2"
repository = "https://github.com/dani-garcia/vaultwarden" repository = "https://github.com/dani-garcia/vaultwarden"
@@ -34,7 +34,7 @@ rocket = { version = "=0.5.0-dev", features = ["tls"], default-features = false
rocket_contrib = "=0.5.0-dev" rocket_contrib = "=0.5.0-dev"
# HTTP client # HTTP client
reqwest = { version = "0.11.7", features = ["blocking", "json", "gzip", "brotli", "socks", "cookies", "trust-dns"] } reqwest = { version = "0.11.8", features = ["blocking", "json", "gzip", "brotli", "socks", "cookies", "trust-dns"] }
# Used for custom short lived cookie jar # Used for custom short lived cookie jar
cookie = "0.15.1" cookie = "0.15.1"
@@ -55,8 +55,8 @@ rmpv = "1.0.0"
chashmap = "2.2.2" chashmap = "2.2.2"
# A generic serialization/deserialization framework # A generic serialization/deserialization framework
serde = { version = "1.0.130", features = ["derive"] } serde = { version = "1.0.132", features = ["derive"] }
serde_json = "1.0.72" serde_json = "1.0.73"
# Logging # Logging
log = "0.4.14" log = "0.4.14"
@@ -78,7 +78,7 @@ uuid = { version = "0.8.2", features = ["v4"] }
# Date and time libraries # Date and time libraries
chrono = { version = "0.4.19", features = ["serde"] } chrono = { version = "0.4.19", features = ["serde"] }
chrono-tz = "0.6.0" chrono-tz = "0.6.1"
time = "0.2.27" time = "0.2.27"
# Job scheduler # Job scheduler
@@ -95,7 +95,7 @@ jsonwebtoken = "7.2.0"
# U2F library # U2F library
u2f = "0.2.0" u2f = "0.2.0"
webauthn-rs = "0.3.0" webauthn-rs = "0.3.1"
# Yubico Library # Yubico Library
yubico = { version = "0.10.0", features = ["online-tokio"], default-features = false } yubico = { version = "0.10.0", features = ["online-tokio"], default-features = false }
@@ -104,7 +104,7 @@ yubico = { version = "0.10.0", features = ["online-tokio"], default-features = f
dotenv = { version = "0.15.0", default-features = false } dotenv = { version = "0.15.0", default-features = false }
# Lazy initialization # Lazy initialization
once_cell = "1.8.0" once_cell = "1.9.0"
# Numerical libraries # Numerical libraries
num-traits = "0.2.14" num-traits = "0.2.14"
@@ -115,7 +115,7 @@ tracing = { version = "0.1.29", features = ["log"] } # Needed to have lettre tra
lettre = { version = "0.10.0-rc.4", features = ["smtp-transport", "builder", "serde", "native-tls", "hostname", "tracing"], default-features = false } lettre = { version = "0.10.0-rc.4", features = ["smtp-transport", "builder", "serde", "native-tls", "hostname", "tracing"], default-features = false }
# Template library # Template library
handlebars = { version = "4.1.5", features = ["dir_source"] } handlebars = { version = "4.1.6", features = ["dir_source"] }
# For favicon extraction from main website # For favicon extraction from main website
html5ever = "0.25.1" html5ever = "0.25.1"
@@ -139,6 +139,7 @@ backtrace = "0.3.63"
# Macro ident concatenation # Macro ident concatenation
paste = "1.0.6" paste = "1.0.6"
governor = "0.3.2"
[patch.crates-io] [patch.crates-io]
# Use newest ring # Use newest ring

View File

@@ -15,11 +15,14 @@ fn main() {
"You need to enable one DB backend. To build with previous defaults do: cargo build --features sqlite" "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") { // Support $BWRS_VERSION for legacy compatibility, but default to $VW_VERSION.
println!("cargo:rustc-env=BWRS_VERSION={}", version); // If neither exist, read from git.
let maybe_vaultwarden_version =
env::var("VW_VERSION").or_else(|_| env::var("BWRS_VERSION")).or_else(|_| version_from_git_info());
if let Ok(version) = maybe_vaultwarden_version {
println!("cargo:rustc-env=VW_VERSION={}", version);
println!("cargo:rustc-env=CARGO_PKG_VERSION={}", version); println!("cargo:rustc-env=CARGO_PKG_VERSION={}", version);
} else {
read_git_info().ok();
} }
} }
@@ -33,7 +36,13 @@ fn run(args: &[&str]) -> Result<String, std::io::Error> {
} }
/// This method reads info from Git, namely tags, branch, and revision /// This method reads info from Git, namely tags, branch, and revision
fn read_git_info() -> Result<(), std::io::Error> { /// To access these values, use:
/// - env!("GIT_EXACT_TAG")
/// - env!("GIT_LAST_TAG")
/// - env!("GIT_BRANCH")
/// - env!("GIT_REV")
/// - env!("VW_VERSION")
fn version_from_git_info() -> Result<String, std::io::Error> {
// The exact tag for the current commit, can be empty when // The exact tag for the current commit, can be empty when
// the current commit doesn't have an associated tag // the current commit doesn't have an associated tag
let exact_tag = run(&["git", "describe", "--abbrev=0", "--tags", "--exact-match"]).ok(); let exact_tag = run(&["git", "describe", "--abbrev=0", "--tags", "--exact-match"]).ok();
@@ -56,23 +65,11 @@ fn read_git_info() -> Result<(), std::io::Error> {
println!("cargo:rustc-env=GIT_REV={}", rev_short); println!("cargo:rustc-env=GIT_REV={}", rev_short);
// Combined version // Combined version
let version = if let Some(exact) = exact_tag { if let Some(exact) = exact_tag {
exact Ok(exact)
} else if &branch != "main" && &branch != "master" { } else if &branch != "main" && &branch != "master" {
format!("{}-{} ({})", last_tag, rev_short, branch) Ok(format!("{}-{} ({})", last_tag, rev_short, branch))
} else { } else {
format!("{}-{}", last_tag, rev_short) Ok(format!("{}-{}", last_tag, rev_short))
}; }
println!("cargo:rustc-env=BWRS_VERSION={}", version);
println!("cargo:rustc-env=CARGO_PKG_VERSION={}", version);
// To access these values, use:
// env!("GIT_EXACT_TAG")
// env!("GIT_LAST_TAG")
// env!("GIT_BRANCH")
// env!("GIT_REV")
// env!("BWRS_VERSION")
Ok(())
} }

View File

@@ -3,16 +3,24 @@
# This file was generated using a Jinja2 template. # This file was generated using a Jinja2 template.
# Please make your changes in `Dockerfile.j2` and then `make` the individual Dockerfiles. # Please make your changes in `Dockerfile.j2` and then `make` the individual Dockerfiles.
{% set build_stage_base_image = "rust:1.55-buster" %} {% set build_stage_base_image = "rust:1.58-buster" %}
{% if "alpine" in target_file %} {% if "alpine" in target_file %}
{% if "amd64" in target_file %} {% if "amd64" in target_file %}
{% set build_stage_base_image = "clux/muslrust:nightly-2021-10-23" %} {% set build_stage_base_image = "blackdex/rust-musl:x86_64-musl-nightly-2022-01-23" %}
{% set runtime_stage_base_image = "alpine:3.14" %} {% set runtime_stage_base_image = "alpine:3.15" %}
{% set package_arch_target = "x86_64-unknown-linux-musl" %} {% set package_arch_target = "x86_64-unknown-linux-musl" %}
{% elif "armv7" in target_file %} {% elif "armv7" in target_file %}
{% set build_stage_base_image = "messense/rust-musl-cross:armv7-musleabihf" %} {% set build_stage_base_image = "blackdex/rust-musl:armv7-musleabihf-nightly-2022-01-23" %}
{% set runtime_stage_base_image = "balenalib/armv7hf-alpine:3.14" %} {% set runtime_stage_base_image = "balenalib/armv7hf-alpine:3.15" %}
{% set package_arch_target = "armv7-unknown-linux-musleabihf" %} {% set package_arch_target = "armv7-unknown-linux-musleabihf" %}
{% elif "armv6" in target_file %}
{% set build_stage_base_image = "blackdex/rust-musl:arm-musleabi-nightly-2022-01-23" %}
{% set runtime_stage_base_image = "balenalib/rpi-alpine:3.15" %}
{% set package_arch_target = "arm-unknown-linux-musleabi" %}
{% elif "arm64" in target_file %}
{% set build_stage_base_image = "blackdex/rust-musl:aarch64-musl-nightly-2022-01-23" %}
{% set runtime_stage_base_image = "balenalib/aarch64-alpine:3.15" %}
{% set package_arch_target = "aarch64-unknown-linux-musl" %}
{% endif %} {% endif %}
{% elif "amd64" in target_file %} {% elif "amd64" in target_file %}
{% set runtime_stage_base_image = "debian:buster-slim" %} {% set runtime_stage_base_image = "debian:buster-slim" %}
@@ -51,8 +59,8 @@
# https://docs.docker.com/develop/develop-images/multistage-build/ # https://docs.docker.com/develop/develop-images/multistage-build/
# https://whitfin.io/speeding-up-rust-docker-builds/ # https://whitfin.io/speeding-up-rust-docker-builds/
####################### VAULT BUILD IMAGE ####################### ####################### VAULT BUILD IMAGE #######################
{% set vault_version = "2.25.0" %} {% set vault_version = "2.25.1b" %}
{% set vault_image_digest = "sha256:0df389deac9e83c739a1f4ff595f12f493b6c27cb4a22bb8fcaba9dc49b9b527" %} {% set vault_image_digest = "sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba" %}
# The web-vault digest specifies a particular web-vault build on Docker Hub. # The web-vault digest specifies a particular web-vault build on Docker Hub.
# Using the digest instead of the tag name provides better security, # 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 # as the digest of an image is immutable, whereas a tag name can later
@@ -75,22 +83,7 @@ FROM vaultwarden/web-vault@{{ vault_image_digest }} as vault
########################## BUILD IMAGE ########################## ########################## BUILD IMAGE ##########################
FROM {{ build_stage_base_image }} as build FROM {{ build_stage_base_image }} as build
{% if "alpine" in target_file %}
{% if "amd64" in target_file %}
# Alpine-based AMD64 (musl) does not support mysql/mariadb during compile time.
ARG DB=sqlite,postgresql
{% set features = "sqlite,postgresql" %}
{% else %}
# Alpine-based ARM (musl) only supports sqlite during compile time.
# We now also need to add vendored_openssl, because the current base image we use to build has OpenSSL removed.
ARG DB=sqlite,vendored_openssl
{% set features = "sqlite" %}
{% endif %}
{% else %}
# Debian-based builds support multidb
ARG DB=sqlite,mysql,postgresql
{% set features = "sqlite,mysql,postgresql" %}
{% endif %}
# Build time options to avoid dpkg warnings and help with reproducible builds. # Build time options to avoid dpkg warnings and help with reproducible builds.
ENV DEBIAN_FRONTEND=noninteractive \ ENV DEBIAN_FRONTEND=noninteractive \
@@ -118,51 +111,32 @@ ENV RUSTFLAGS='-C link-arg=-s'
ENV CFLAGS_armv7_unknown_linux_musleabihf="-mfpu=vfpv3-d16" ENV CFLAGS_armv7_unknown_linux_musleabihf="-mfpu=vfpv3-d16"
{% endif %} {% endif %}
{% elif "arm" in target_file %} {% elif "arm" in target_file %}
# NOTE: Any apt-get/dpkg after this stage will fail because of broken dependencies.
# For Diesel-RS migrations_macros to compile with MySQL/MariaDB we need to do some magic.
# We at least need libmariadb3:amd64 installed for the x86_64 version of libmariadb.so (client)
# We also need the libmariadb-dev-compat:amd64 but it can not be installed together with the {{ package_arch_prefix }} version.
# What we can do is a force install, because nothing important is overlapping each other.
# #
# Install required build libs for {{ package_arch_name }} architecture. # Install required build libs for {{ package_arch_name }} architecture.
# To compile both mysql and postgresql we need some extra packages for both host arch and target arch # hadolint ignore=DL3059
RUN sed 's/^deb/deb-src/' /etc/apt/sources.list > /etc/apt/sources.list.d/deb-src.list \ RUN dpkg --add-architecture {{ package_arch_name }} \
&& dpkg --add-architecture {{ package_arch_name }} \
&& apt-get update \ && apt-get update \
&& apt-get install -y \ && apt-get install -y \
--no-install-recommends \ --no-install-recommends \
libssl-dev{{ package_arch_prefix }} \ libssl-dev{{ package_arch_prefix }} \
libc6-dev{{ package_arch_prefix }} \ libc6-dev{{ package_arch_prefix }} \
libpq5{{ package_arch_prefix }} \ libpq5{{ package_arch_prefix }} \
libpq-dev \ libpq-dev{{ package_arch_prefix }} \
libmariadb3:amd64 \ libmariadb3{{ package_arch_prefix }} \
libmariadb-dev{{ package_arch_prefix }} \ libmariadb-dev{{ package_arch_prefix }} \
libmariadb-dev-compat{{ package_arch_prefix }} \ libmariadb-dev-compat{{ package_arch_prefix }} \
gcc-{{ package_cross_compiler }} \ gcc-{{ package_cross_compiler }} \
# #
# Manual install libmariadb-dev-compat:amd64 ( After this broken dependencies will break apt )
&& apt-get download libmariadb-dev-compat:amd64 \
&& dpkg --force-all -i ./libmariadb-dev-compat*.deb \
&& rm -rvf ./libmariadb-dev-compat*.deb \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* \
#
# For Diesel-RS migrations_macros to compile with PostgreSQL we need to do some magic.
# The libpq5{{ package_arch_prefix }} package seems to not provide a symlink to libpq.so.5 with the name libpq.so.
# This is only provided by the libpq-dev package which can't be installed for both arch at the same time.
# Without this specific file the ld command will fail and compilation fails with it.
&& ln -sfnr /usr/lib/{{ package_cross_compiler }}/libpq.so.5 /usr/lib/{{ package_cross_compiler }}/libpq.so \
#
# Make sure cargo has the right target config # Make sure cargo has the right target config
&& echo '[target.{{ package_arch_target }}]' >> "${CARGO_HOME}/config" \ && echo '[target.{{ package_arch_target }}]' >> "${CARGO_HOME}/config" \
&& echo 'linker = "{{ package_cross_compiler }}-gcc"' >> "${CARGO_HOME}/config" \ && echo 'linker = "{{ package_cross_compiler }}-gcc"' >> "${CARGO_HOME}/config" \
&& echo 'rustflags = ["-L/usr/lib/{{ package_cross_compiler }}"]' >> "${CARGO_HOME}/config" && echo 'rustflags = ["-L/usr/lib/{{ package_cross_compiler }}"]' >> "${CARGO_HOME}/config"
# Set arm specific environment values # Set arm specific environment values
ENV CC_{{ package_arch_target | replace("-", "_") }}="/usr/bin/{{ package_cross_compiler }}-gcc" ENV CC_{{ package_arch_target | replace("-", "_") }}="/usr/bin/{{ package_cross_compiler }}-gcc" \
ENV CROSS_COMPILE="1" CROSS_COMPILE="1" \
ENV OPENSSL_INCLUDE_DIR="/usr/include/{{ package_cross_compiler }}" OPENSSL_INCLUDE_DIR="/usr/include/{{ package_cross_compiler }}" \
ENV OPENSSL_LIB_DIR="/usr/lib/{{ package_cross_compiler }}" OPENSSL_LIB_DIR="/usr/lib/{{ package_cross_compiler }}"
{% elif "amd64" in target_file %} {% elif "amd64" in target_file %}
# Install DB packages # Install DB packages
@@ -188,6 +162,9 @@ COPY ./build.rs ./build.rs
RUN {{ mount_rust_cache -}} rustup target add {{ package_arch_target }} RUN {{ mount_rust_cache -}} rustup target add {{ package_arch_target }}
{% endif %} {% endif %}
# Configure the DB ARG as late as possible to not invalidate the cached layers above
ARG DB=sqlite,mysql,postgresql
# Builds your dependencies and removes the # Builds your dependencies and removes the
# dummy project, except the target folder # dummy project, except the target folder
# This folder contains the compiled dependencies # This folder contains the compiled dependencies
@@ -203,6 +180,7 @@ RUN touch src/main.rs
# Builds again, this time it'll just be # Builds again, this time it'll just be
# your actual source files being built # your actual source files being built
# hadolint ignore=DL3059
RUN {{ mount_rust_cache -}} cargo build --features ${DB} --release{{ package_arch_target_param }} RUN {{ mount_rust_cache -}} cargo build --features ${DB} --release{{ package_arch_target_param }}
{% if "alpine" in target_file %} {% if "alpine" in target_file %}
{% if "armv7" in target_file %} {% if "armv7" in target_file %}
@@ -216,13 +194,14 @@ RUN musl-strip target/{{ package_arch_target }}/release/vaultwarden
# because we already have a binary built # because we already have a binary built
FROM {{ runtime_stage_base_image }} FROM {{ runtime_stage_base_image }}
ENV ROCKET_ENV "staging" ENV ROCKET_ENV="staging" \
ENV ROCKET_PORT=80 ROCKET_PORT=80 \
ENV ROCKET_WORKERS=10 ROCKET_WORKERS=10
{% if "alpine" in runtime_stage_base_image %} {%- if "alpine" in runtime_stage_base_image %} \
ENV SSL_CERT_DIR=/etc/ssl/certs SSL_CERT_DIR=/etc/ssl/certs
{% endif %} {% endif %}
{% if "amd64" not in target_file %} {% if "amd64" not in target_file %}
# hadolint ignore=DL3059 # hadolint ignore=DL3059
RUN [ "cross-build-start" ] RUN [ "cross-build-start" ]
@@ -236,12 +215,6 @@ RUN mkdir /data \
tzdata \ tzdata \
curl \ curl \
dumb-init \ dumb-init \
{% if "mysql" in features %}
mariadb-connector-c \
{% endif %}
{% if "postgresql" in features %}
postgresql-libs \
{% endif %}
ca-certificates ca-certificates
{% else %} {% else %}
&& apt-get update && apt-get install -y \ && apt-get update && apt-get install -y \

View File

@@ -16,21 +16,20 @@
# - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # - From https://hub.docker.com/r/vaultwarden/web-vault/tags,
# click the tag name to view the digest of the image it currently points to. # click the tag name to view the digest of the image it currently points to.
# - From the command line: # - From the command line:
# $ docker pull vaultwarden/web-vault:v2.25.0 # $ docker pull vaultwarden/web-vault:v2.25.1b
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.25.0 # $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.25.1b
# [vaultwarden/web-vault@sha256:0df389deac9e83c739a1f4ff595f12f493b6c27cb4a22bb8fcaba9dc49b9b527] # [vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba]
# #
# - Conversely, to get the tag name from the digest: # - Conversely, to get the tag name from the digest:
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:0df389deac9e83c739a1f4ff595f12f493b6c27cb4a22bb8fcaba9dc49b9b527 # $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba
# [vaultwarden/web-vault:v2.25.0] # [vaultwarden/web-vault:v2.25.1b]
# #
FROM vaultwarden/web-vault@sha256:0df389deac9e83c739a1f4ff595f12f493b6c27cb4a22bb8fcaba9dc49b9b527 as vault FROM vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba as vault
########################## BUILD IMAGE ########################## ########################## BUILD IMAGE ##########################
FROM rust:1.55-buster as build FROM rust:1.58-buster as build
# Debian-based builds support multidb
ARG DB=sqlite,mysql,postgresql
# Build time options to avoid dpkg warnings and help with reproducible builds. # Build time options to avoid dpkg warnings and help with reproducible builds.
ENV DEBIAN_FRONTEND=noninteractive \ ENV DEBIAN_FRONTEND=noninteractive \
@@ -64,6 +63,9 @@ COPY ./rust-toolchain ./rust-toolchain
COPY ./build.rs ./build.rs COPY ./build.rs ./build.rs
# Configure the DB ARG as late as possible to not invalidate the cached layers above
ARG DB=sqlite,mysql,postgresql
# Builds your dependencies and removes the # Builds your dependencies and removes the
# dummy project, except the target folder # dummy project, except the target folder
# This folder contains the compiled dependencies # This folder contains the compiled dependencies
@@ -79,6 +81,7 @@ RUN touch src/main.rs
# Builds again, this time it'll just be # Builds again, this time it'll just be
# your actual source files being built # your actual source files being built
# hadolint ignore=DL3059
RUN cargo build --features ${DB} --release RUN cargo build --features ${DB} --release
######################## RUNTIME IMAGE ######################## ######################## RUNTIME IMAGE ########################
@@ -86,9 +89,9 @@ RUN cargo build --features ${DB} --release
# because we already have a binary built # because we already have a binary built
FROM debian:buster-slim FROM debian:buster-slim
ENV ROCKET_ENV "staging" ENV ROCKET_ENV="staging" \
ENV ROCKET_PORT=80 ROCKET_PORT=80 \
ENV ROCKET_WORKERS=10 ROCKET_WORKERS=10
# Create data folder and Install needed libraries # Create data folder and Install needed libraries

View File

@@ -16,21 +16,20 @@
# - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # - From https://hub.docker.com/r/vaultwarden/web-vault/tags,
# click the tag name to view the digest of the image it currently points to. # click the tag name to view the digest of the image it currently points to.
# - From the command line: # - From the command line:
# $ docker pull vaultwarden/web-vault:v2.25.0 # $ docker pull vaultwarden/web-vault:v2.25.1b
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.25.0 # $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.25.1b
# [vaultwarden/web-vault@sha256:0df389deac9e83c739a1f4ff595f12f493b6c27cb4a22bb8fcaba9dc49b9b527] # [vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba]
# #
# - Conversely, to get the tag name from the digest: # - Conversely, to get the tag name from the digest:
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:0df389deac9e83c739a1f4ff595f12f493b6c27cb4a22bb8fcaba9dc49b9b527 # $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba
# [vaultwarden/web-vault:v2.25.0] # [vaultwarden/web-vault:v2.25.1b]
# #
FROM vaultwarden/web-vault@sha256:0df389deac9e83c739a1f4ff595f12f493b6c27cb4a22bb8fcaba9dc49b9b527 as vault FROM vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba as vault
########################## BUILD IMAGE ########################## ########################## BUILD IMAGE ##########################
FROM clux/muslrust:nightly-2021-10-23 as build FROM blackdex/rust-musl:x86_64-musl-nightly-2022-01-23 as build
# Alpine-based AMD64 (musl) does not support mysql/mariadb during compile time.
ARG DB=sqlite,postgresql
# Build time options to avoid dpkg warnings and help with reproducible builds. # Build time options to avoid dpkg warnings and help with reproducible builds.
ENV DEBIAN_FRONTEND=noninteractive \ ENV DEBIAN_FRONTEND=noninteractive \
@@ -58,6 +57,9 @@ COPY ./build.rs ./build.rs
RUN rustup target add x86_64-unknown-linux-musl RUN rustup target add x86_64-unknown-linux-musl
# Configure the DB ARG as late as possible to not invalidate the cached layers above
ARG DB=sqlite,mysql,postgresql
# Builds your dependencies and removes the # Builds your dependencies and removes the
# dummy project, except the target folder # dummy project, except the target folder
# This folder contains the compiled dependencies # This folder contains the compiled dependencies
@@ -73,17 +75,19 @@ RUN touch src/main.rs
# Builds again, this time it'll just be # Builds again, this time it'll just be
# your actual source files being built # your actual source files being built
# hadolint ignore=DL3059
RUN cargo build --features ${DB} --release --target=x86_64-unknown-linux-musl RUN cargo build --features ${DB} --release --target=x86_64-unknown-linux-musl
######################## RUNTIME IMAGE ######################## ######################## RUNTIME IMAGE ########################
# Create a new stage with a minimal image # Create a new stage with a minimal image
# because we already have a binary built # because we already have a binary built
FROM alpine:3.14 FROM alpine:3.15
ENV ROCKET_ENV="staging" \
ROCKET_PORT=80 \
ROCKET_WORKERS=10 \
SSL_CERT_DIR=/etc/ssl/certs
ENV ROCKET_ENV "staging"
ENV ROCKET_PORT=80
ENV ROCKET_WORKERS=10
ENV SSL_CERT_DIR=/etc/ssl/certs
# Create data folder and Install needed libraries # Create data folder and Install needed libraries
@@ -93,7 +97,6 @@ RUN mkdir /data \
tzdata \ tzdata \
curl \ curl \
dumb-init \ dumb-init \
postgresql-libs \
ca-certificates ca-certificates

View File

@@ -16,21 +16,20 @@
# - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # - From https://hub.docker.com/r/vaultwarden/web-vault/tags,
# click the tag name to view the digest of the image it currently points to. # click the tag name to view the digest of the image it currently points to.
# - From the command line: # - From the command line:
# $ docker pull vaultwarden/web-vault:v2.25.0 # $ docker pull vaultwarden/web-vault:v2.25.1b
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.25.0 # $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.25.1b
# [vaultwarden/web-vault@sha256:0df389deac9e83c739a1f4ff595f12f493b6c27cb4a22bb8fcaba9dc49b9b527] # [vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba]
# #
# - Conversely, to get the tag name from the digest: # - Conversely, to get the tag name from the digest:
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:0df389deac9e83c739a1f4ff595f12f493b6c27cb4a22bb8fcaba9dc49b9b527 # $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba
# [vaultwarden/web-vault:v2.25.0] # [vaultwarden/web-vault:v2.25.1b]
# #
FROM vaultwarden/web-vault@sha256:0df389deac9e83c739a1f4ff595f12f493b6c27cb4a22bb8fcaba9dc49b9b527 as vault FROM vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba as vault
########################## BUILD IMAGE ########################## ########################## BUILD IMAGE ##########################
FROM rust:1.55-buster as build FROM rust:1.58-buster as build
# Debian-based builds support multidb
ARG DB=sqlite,mysql,postgresql
# Build time options to avoid dpkg warnings and help with reproducible builds. # Build time options to avoid dpkg warnings and help with reproducible builds.
ENV DEBIAN_FRONTEND=noninteractive \ ENV DEBIAN_FRONTEND=noninteractive \
@@ -64,6 +63,9 @@ COPY ./rust-toolchain ./rust-toolchain
COPY ./build.rs ./build.rs COPY ./build.rs ./build.rs
# Configure the DB ARG as late as possible to not invalidate the cached layers above
ARG DB=sqlite,mysql,postgresql
# Builds your dependencies and removes the # Builds your dependencies and removes the
# dummy project, except the target folder # dummy project, except the target folder
# This folder contains the compiled dependencies # This folder contains the compiled dependencies
@@ -79,6 +81,7 @@ RUN touch src/main.rs
# Builds again, this time it'll just be # Builds again, this time it'll just be
# your actual source files being built # your actual source files being built
# hadolint ignore=DL3059
RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry cargo build --features ${DB} --release RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry cargo build --features ${DB} --release
######################## RUNTIME IMAGE ######################## ######################## RUNTIME IMAGE ########################
@@ -86,9 +89,9 @@ RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.
# because we already have a binary built # because we already have a binary built
FROM debian:buster-slim FROM debian:buster-slim
ENV ROCKET_ENV "staging" ENV ROCKET_ENV="staging" \
ENV ROCKET_PORT=80 ROCKET_PORT=80 \
ENV ROCKET_WORKERS=10 ROCKET_WORKERS=10
# Create data folder and Install needed libraries # Create data folder and Install needed libraries

View File

@@ -16,21 +16,20 @@
# - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # - From https://hub.docker.com/r/vaultwarden/web-vault/tags,
# click the tag name to view the digest of the image it currently points to. # click the tag name to view the digest of the image it currently points to.
# - From the command line: # - From the command line:
# $ docker pull vaultwarden/web-vault:v2.25.0 # $ docker pull vaultwarden/web-vault:v2.25.1b
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.25.0 # $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.25.1b
# [vaultwarden/web-vault@sha256:0df389deac9e83c739a1f4ff595f12f493b6c27cb4a22bb8fcaba9dc49b9b527] # [vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba]
# #
# - Conversely, to get the tag name from the digest: # - Conversely, to get the tag name from the digest:
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:0df389deac9e83c739a1f4ff595f12f493b6c27cb4a22bb8fcaba9dc49b9b527 # $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba
# [vaultwarden/web-vault:v2.25.0] # [vaultwarden/web-vault:v2.25.1b]
# #
FROM vaultwarden/web-vault@sha256:0df389deac9e83c739a1f4ff595f12f493b6c27cb4a22bb8fcaba9dc49b9b527 as vault FROM vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba as vault
########################## BUILD IMAGE ########################## ########################## BUILD IMAGE ##########################
FROM clux/muslrust:nightly-2021-10-23 as build FROM blackdex/rust-musl:x86_64-musl-nightly-2022-01-23 as build
# Alpine-based AMD64 (musl) does not support mysql/mariadb during compile time.
ARG DB=sqlite,postgresql
# Build time options to avoid dpkg warnings and help with reproducible builds. # Build time options to avoid dpkg warnings and help with reproducible builds.
ENV DEBIAN_FRONTEND=noninteractive \ ENV DEBIAN_FRONTEND=noninteractive \
@@ -58,6 +57,9 @@ COPY ./build.rs ./build.rs
RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry rustup target add x86_64-unknown-linux-musl RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry rustup target add x86_64-unknown-linux-musl
# Configure the DB ARG as late as possible to not invalidate the cached layers above
ARG DB=sqlite,mysql,postgresql
# Builds your dependencies and removes the # Builds your dependencies and removes the
# dummy project, except the target folder # dummy project, except the target folder
# This folder contains the compiled dependencies # This folder contains the compiled dependencies
@@ -73,17 +75,19 @@ RUN touch src/main.rs
# Builds again, this time it'll just be # Builds again, this time it'll just be
# your actual source files being built # your actual source files being built
# hadolint ignore=DL3059
RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry cargo build --features ${DB} --release --target=x86_64-unknown-linux-musl RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry cargo build --features ${DB} --release --target=x86_64-unknown-linux-musl
######################## RUNTIME IMAGE ######################## ######################## RUNTIME IMAGE ########################
# Create a new stage with a minimal image # Create a new stage with a minimal image
# because we already have a binary built # because we already have a binary built
FROM alpine:3.14 FROM alpine:3.15
ENV ROCKET_ENV="staging" \
ROCKET_PORT=80 \
ROCKET_WORKERS=10 \
SSL_CERT_DIR=/etc/ssl/certs
ENV ROCKET_ENV "staging"
ENV ROCKET_PORT=80
ENV ROCKET_WORKERS=10
ENV SSL_CERT_DIR=/etc/ssl/certs
# Create data folder and Install needed libraries # Create data folder and Install needed libraries
@@ -93,7 +97,6 @@ RUN mkdir /data \
tzdata \ tzdata \
curl \ curl \
dumb-init \ dumb-init \
postgresql-libs \
ca-certificates ca-certificates

View File

@@ -16,21 +16,20 @@
# - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # - From https://hub.docker.com/r/vaultwarden/web-vault/tags,
# click the tag name to view the digest of the image it currently points to. # click the tag name to view the digest of the image it currently points to.
# - From the command line: # - From the command line:
# $ docker pull vaultwarden/web-vault:v2.25.0 # $ docker pull vaultwarden/web-vault:v2.25.1b
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.25.0 # $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.25.1b
# [vaultwarden/web-vault@sha256:0df389deac9e83c739a1f4ff595f12f493b6c27cb4a22bb8fcaba9dc49b9b527] # [vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba]
# #
# - Conversely, to get the tag name from the digest: # - Conversely, to get the tag name from the digest:
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:0df389deac9e83c739a1f4ff595f12f493b6c27cb4a22bb8fcaba9dc49b9b527 # $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba
# [vaultwarden/web-vault:v2.25.0] # [vaultwarden/web-vault:v2.25.1b]
# #
FROM vaultwarden/web-vault@sha256:0df389deac9e83c739a1f4ff595f12f493b6c27cb4a22bb8fcaba9dc49b9b527 as vault FROM vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba as vault
########################## BUILD IMAGE ########################## ########################## BUILD IMAGE ##########################
FROM rust:1.55-buster as build FROM rust:1.58-buster as build
# Debian-based builds support multidb
ARG DB=sqlite,mysql,postgresql
# Build time options to avoid dpkg warnings and help with reproducible builds. # Build time options to avoid dpkg warnings and help with reproducible builds.
ENV DEBIAN_FRONTEND=noninteractive \ ENV DEBIAN_FRONTEND=noninteractive \
@@ -45,51 +44,32 @@ ENV DEBIAN_FRONTEND=noninteractive \
RUN mkdir -pv "${CARGO_HOME}" \ RUN mkdir -pv "${CARGO_HOME}" \
&& rustup set profile minimal && rustup set profile minimal
# NOTE: Any apt-get/dpkg after this stage will fail because of broken dependencies.
# For Diesel-RS migrations_macros to compile with MySQL/MariaDB we need to do some magic.
# We at least need libmariadb3:amd64 installed for the x86_64 version of libmariadb.so (client)
# We also need the libmariadb-dev-compat:amd64 but it can not be installed together with the :arm64 version.
# What we can do is a force install, because nothing important is overlapping each other.
# #
# Install required build libs for arm64 architecture. # Install required build libs for arm64 architecture.
# To compile both mysql and postgresql we need some extra packages for both host arch and target arch # hadolint ignore=DL3059
RUN sed 's/^deb/deb-src/' /etc/apt/sources.list > /etc/apt/sources.list.d/deb-src.list \ RUN dpkg --add-architecture arm64 \
&& dpkg --add-architecture arm64 \
&& apt-get update \ && apt-get update \
&& apt-get install -y \ && apt-get install -y \
--no-install-recommends \ --no-install-recommends \
libssl-dev:arm64 \ libssl-dev:arm64 \
libc6-dev:arm64 \ libc6-dev:arm64 \
libpq5:arm64 \ libpq5:arm64 \
libpq-dev \ libpq-dev:arm64 \
libmariadb3:amd64 \ libmariadb3:arm64 \
libmariadb-dev:arm64 \ libmariadb-dev:arm64 \
libmariadb-dev-compat:arm64 \ libmariadb-dev-compat:arm64 \
gcc-aarch64-linux-gnu \ gcc-aarch64-linux-gnu \
# #
# Manual install libmariadb-dev-compat:amd64 ( After this broken dependencies will break apt )
&& apt-get download libmariadb-dev-compat:amd64 \
&& dpkg --force-all -i ./libmariadb-dev-compat*.deb \
&& rm -rvf ./libmariadb-dev-compat*.deb \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* \
#
# For Diesel-RS migrations_macros to compile with PostgreSQL we need to do some magic.
# The libpq5:arm64 package seems to not provide a symlink to libpq.so.5 with the name libpq.so.
# This is only provided by the libpq-dev package which can't be installed for both arch at the same time.
# Without this specific file the ld command will fail and compilation fails with it.
&& ln -sfnr /usr/lib/aarch64-linux-gnu/libpq.so.5 /usr/lib/aarch64-linux-gnu/libpq.so \
#
# Make sure cargo has the right target config # Make sure cargo has the right target config
&& echo '[target.aarch64-unknown-linux-gnu]' >> "${CARGO_HOME}/config" \ && echo '[target.aarch64-unknown-linux-gnu]' >> "${CARGO_HOME}/config" \
&& echo 'linker = "aarch64-linux-gnu-gcc"' >> "${CARGO_HOME}/config" \ && echo 'linker = "aarch64-linux-gnu-gcc"' >> "${CARGO_HOME}/config" \
&& echo 'rustflags = ["-L/usr/lib/aarch64-linux-gnu"]' >> "${CARGO_HOME}/config" && echo 'rustflags = ["-L/usr/lib/aarch64-linux-gnu"]' >> "${CARGO_HOME}/config"
# Set arm specific environment values # Set arm specific environment values
ENV CC_aarch64_unknown_linux_gnu="/usr/bin/aarch64-linux-gnu-gcc" ENV CC_aarch64_unknown_linux_gnu="/usr/bin/aarch64-linux-gnu-gcc" \
ENV CROSS_COMPILE="1" CROSS_COMPILE="1" \
ENV OPENSSL_INCLUDE_DIR="/usr/include/aarch64-linux-gnu" OPENSSL_INCLUDE_DIR="/usr/include/aarch64-linux-gnu" \
ENV OPENSSL_LIB_DIR="/usr/lib/aarch64-linux-gnu" OPENSSL_LIB_DIR="/usr/lib/aarch64-linux-gnu"
# Creates a dummy project used to grab dependencies # Creates a dummy project used to grab dependencies
@@ -103,6 +83,9 @@ COPY ./build.rs ./build.rs
RUN rustup target add aarch64-unknown-linux-gnu RUN rustup target add aarch64-unknown-linux-gnu
# Configure the DB ARG as late as possible to not invalidate the cached layers above
ARG DB=sqlite,mysql,postgresql
# Builds your dependencies and removes the # Builds your dependencies and removes the
# dummy project, except the target folder # dummy project, except the target folder
# This folder contains the compiled dependencies # This folder contains the compiled dependencies
@@ -118,6 +101,7 @@ RUN touch src/main.rs
# Builds again, this time it'll just be # Builds again, this time it'll just be
# your actual source files being built # your actual source files being built
# hadolint ignore=DL3059
RUN cargo build --features ${DB} --release --target=aarch64-unknown-linux-gnu RUN cargo build --features ${DB} --release --target=aarch64-unknown-linux-gnu
######################## RUNTIME IMAGE ######################## ######################## RUNTIME IMAGE ########################
@@ -125,9 +109,9 @@ RUN cargo build --features ${DB} --release --target=aarch64-unknown-linux-gnu
# because we already have a binary built # because we already have a binary built
FROM balenalib/aarch64-debian:buster FROM balenalib/aarch64-debian:buster
ENV ROCKET_ENV "staging" ENV ROCKET_ENV="staging" \
ENV ROCKET_PORT=80 ROCKET_PORT=80 \
ENV ROCKET_WORKERS=10 ROCKET_WORKERS=10
# hadolint ignore=DL3059 # hadolint ignore=DL3059
RUN [ "cross-build-start" ] RUN [ "cross-build-start" ]

View File

@@ -0,0 +1,125 @@
# syntax=docker/dockerfile:1
# This file was generated using a Jinja2 template.
# Please make your changes in `Dockerfile.j2` and then `make` the individual Dockerfiles.
# Using multistage build:
# https://docs.docker.com/develop/develop-images/multistage-build/
# https://whitfin.io/speeding-up-rust-docker-builds/
####################### VAULT BUILD IMAGE #######################
# 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/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 vaultwarden/web-vault:v2.25.1b
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.25.1b
# [vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba]
#
# - Conversely, to get the tag name from the digest:
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba
# [vaultwarden/web-vault:v2.25.1b]
#
FROM vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba as vault
########################## BUILD IMAGE ##########################
FROM blackdex/rust-musl:aarch64-musl-nightly-2022-01-23 as build
# Build time options to avoid dpkg warnings and help with reproducible builds.
ENV DEBIAN_FRONTEND=noninteractive \
LANG=C.UTF-8 \
TZ=UTC \
TERM=xterm-256color \
CARGO_HOME="/root/.cargo" \
USER="root"
# Create CARGO_HOME folder and don't download rust docs
RUN mkdir -pv "${CARGO_HOME}" \
&& rustup set profile minimal
ENV RUSTFLAGS='-C link-arg=-s'
# Creates a dummy project used to grab dependencies
RUN USER=root cargo new --bin /app
WORKDIR /app
# Copies over *only* your manifests and build files
COPY ./Cargo.* ./
COPY ./rust-toolchain ./rust-toolchain
COPY ./build.rs ./build.rs
RUN rustup target add aarch64-unknown-linux-musl
# Configure the DB ARG as late as possible to not invalidate the cached layers above
ARG DB=sqlite,mysql,postgresql
# Builds your dependencies and removes the
# dummy project, except the target folder
# This folder contains the compiled dependencies
RUN cargo build --features ${DB} --release --target=aarch64-unknown-linux-musl \
&& find . -not -path "./target*" -delete
# Copies the complete project
# To avoid copying unneeded files, use .dockerignore
COPY . .
# Make sure that we actually build the project
RUN touch src/main.rs
# Builds again, this time it'll just be
# your actual source files being built
# hadolint ignore=DL3059
RUN cargo build --features ${DB} --release --target=aarch64-unknown-linux-musl
######################## RUNTIME IMAGE ########################
# Create a new stage with a minimal image
# because we already have a binary built
FROM balenalib/aarch64-alpine:3.15
ENV ROCKET_ENV="staging" \
ROCKET_PORT=80 \
ROCKET_WORKERS=10 \
SSL_CERT_DIR=/etc/ssl/certs
# hadolint ignore=DL3059
RUN [ "cross-build-start" ]
# Create data folder and Install needed libraries
RUN mkdir /data \
&& apk add --no-cache \
openssl \
tzdata \
curl \
dumb-init \
ca-certificates
# hadolint ignore=DL3059
RUN [ "cross-build-end" ]
VOLUME /data
EXPOSE 80
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-musl/release/vaultwarden .
COPY docker/healthcheck.sh /healthcheck.sh
COPY docker/start.sh /start.sh
HEALTHCHECK --interval=60s --timeout=10s CMD ["/healthcheck.sh"]
# Configures the startup!
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
CMD ["/start.sh"]

View File

@@ -16,21 +16,20 @@
# - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # - From https://hub.docker.com/r/vaultwarden/web-vault/tags,
# click the tag name to view the digest of the image it currently points to. # click the tag name to view the digest of the image it currently points to.
# - From the command line: # - From the command line:
# $ docker pull vaultwarden/web-vault:v2.25.0 # $ docker pull vaultwarden/web-vault:v2.25.1b
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.25.0 # $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.25.1b
# [vaultwarden/web-vault@sha256:0df389deac9e83c739a1f4ff595f12f493b6c27cb4a22bb8fcaba9dc49b9b527] # [vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba]
# #
# - Conversely, to get the tag name from the digest: # - Conversely, to get the tag name from the digest:
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:0df389deac9e83c739a1f4ff595f12f493b6c27cb4a22bb8fcaba9dc49b9b527 # $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba
# [vaultwarden/web-vault:v2.25.0] # [vaultwarden/web-vault:v2.25.1b]
# #
FROM vaultwarden/web-vault@sha256:0df389deac9e83c739a1f4ff595f12f493b6c27cb4a22bb8fcaba9dc49b9b527 as vault FROM vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba as vault
########################## BUILD IMAGE ########################## ########################## BUILD IMAGE ##########################
FROM rust:1.55-buster as build FROM rust:1.58-buster as build
# Debian-based builds support multidb
ARG DB=sqlite,mysql,postgresql
# Build time options to avoid dpkg warnings and help with reproducible builds. # Build time options to avoid dpkg warnings and help with reproducible builds.
ENV DEBIAN_FRONTEND=noninteractive \ ENV DEBIAN_FRONTEND=noninteractive \
@@ -45,51 +44,32 @@ ENV DEBIAN_FRONTEND=noninteractive \
RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry mkdir -pv "${CARGO_HOME}" \ RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry mkdir -pv "${CARGO_HOME}" \
&& rustup set profile minimal && rustup set profile minimal
# NOTE: Any apt-get/dpkg after this stage will fail because of broken dependencies.
# For Diesel-RS migrations_macros to compile with MySQL/MariaDB we need to do some magic.
# We at least need libmariadb3:amd64 installed for the x86_64 version of libmariadb.so (client)
# We also need the libmariadb-dev-compat:amd64 but it can not be installed together with the :arm64 version.
# What we can do is a force install, because nothing important is overlapping each other.
# #
# Install required build libs for arm64 architecture. # Install required build libs for arm64 architecture.
# To compile both mysql and postgresql we need some extra packages for both host arch and target arch # hadolint ignore=DL3059
RUN sed 's/^deb/deb-src/' /etc/apt/sources.list > /etc/apt/sources.list.d/deb-src.list \ RUN dpkg --add-architecture arm64 \
&& dpkg --add-architecture arm64 \
&& apt-get update \ && apt-get update \
&& apt-get install -y \ && apt-get install -y \
--no-install-recommends \ --no-install-recommends \
libssl-dev:arm64 \ libssl-dev:arm64 \
libc6-dev:arm64 \ libc6-dev:arm64 \
libpq5:arm64 \ libpq5:arm64 \
libpq-dev \ libpq-dev:arm64 \
libmariadb3:amd64 \ libmariadb3:arm64 \
libmariadb-dev:arm64 \ libmariadb-dev:arm64 \
libmariadb-dev-compat:arm64 \ libmariadb-dev-compat:arm64 \
gcc-aarch64-linux-gnu \ gcc-aarch64-linux-gnu \
# #
# Manual install libmariadb-dev-compat:amd64 ( After this broken dependencies will break apt )
&& apt-get download libmariadb-dev-compat:amd64 \
&& dpkg --force-all -i ./libmariadb-dev-compat*.deb \
&& rm -rvf ./libmariadb-dev-compat*.deb \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* \
#
# For Diesel-RS migrations_macros to compile with PostgreSQL we need to do some magic.
# The libpq5:arm64 package seems to not provide a symlink to libpq.so.5 with the name libpq.so.
# This is only provided by the libpq-dev package which can't be installed for both arch at the same time.
# Without this specific file the ld command will fail and compilation fails with it.
&& ln -sfnr /usr/lib/aarch64-linux-gnu/libpq.so.5 /usr/lib/aarch64-linux-gnu/libpq.so \
#
# Make sure cargo has the right target config # Make sure cargo has the right target config
&& echo '[target.aarch64-unknown-linux-gnu]' >> "${CARGO_HOME}/config" \ && echo '[target.aarch64-unknown-linux-gnu]' >> "${CARGO_HOME}/config" \
&& echo 'linker = "aarch64-linux-gnu-gcc"' >> "${CARGO_HOME}/config" \ && echo 'linker = "aarch64-linux-gnu-gcc"' >> "${CARGO_HOME}/config" \
&& echo 'rustflags = ["-L/usr/lib/aarch64-linux-gnu"]' >> "${CARGO_HOME}/config" && echo 'rustflags = ["-L/usr/lib/aarch64-linux-gnu"]' >> "${CARGO_HOME}/config"
# Set arm specific environment values # Set arm specific environment values
ENV CC_aarch64_unknown_linux_gnu="/usr/bin/aarch64-linux-gnu-gcc" ENV CC_aarch64_unknown_linux_gnu="/usr/bin/aarch64-linux-gnu-gcc" \
ENV CROSS_COMPILE="1" CROSS_COMPILE="1" \
ENV OPENSSL_INCLUDE_DIR="/usr/include/aarch64-linux-gnu" OPENSSL_INCLUDE_DIR="/usr/include/aarch64-linux-gnu" \
ENV OPENSSL_LIB_DIR="/usr/lib/aarch64-linux-gnu" OPENSSL_LIB_DIR="/usr/lib/aarch64-linux-gnu"
# Creates a dummy project used to grab dependencies # Creates a dummy project used to grab dependencies
@@ -103,6 +83,9 @@ COPY ./build.rs ./build.rs
RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry rustup target add aarch64-unknown-linux-gnu RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry rustup target add aarch64-unknown-linux-gnu
# Configure the DB ARG as late as possible to not invalidate the cached layers above
ARG DB=sqlite,mysql,postgresql
# Builds your dependencies and removes the # Builds your dependencies and removes the
# dummy project, except the target folder # dummy project, except the target folder
# This folder contains the compiled dependencies # This folder contains the compiled dependencies
@@ -118,6 +101,7 @@ RUN touch src/main.rs
# Builds again, this time it'll just be # Builds again, this time it'll just be
# your actual source files being built # your actual source files being built
# hadolint ignore=DL3059
RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry cargo build --features ${DB} --release --target=aarch64-unknown-linux-gnu RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry cargo build --features ${DB} --release --target=aarch64-unknown-linux-gnu
######################## RUNTIME IMAGE ######################## ######################## RUNTIME IMAGE ########################
@@ -125,9 +109,9 @@ RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.
# because we already have a binary built # because we already have a binary built
FROM balenalib/aarch64-debian:buster FROM balenalib/aarch64-debian:buster
ENV ROCKET_ENV "staging" ENV ROCKET_ENV="staging" \
ENV ROCKET_PORT=80 ROCKET_PORT=80 \
ENV ROCKET_WORKERS=10 ROCKET_WORKERS=10
# hadolint ignore=DL3059 # hadolint ignore=DL3059
RUN [ "cross-build-start" ] RUN [ "cross-build-start" ]

View File

@@ -0,0 +1,125 @@
# syntax=docker/dockerfile:1
# This file was generated using a Jinja2 template.
# Please make your changes in `Dockerfile.j2` and then `make` the individual Dockerfiles.
# Using multistage build:
# https://docs.docker.com/develop/develop-images/multistage-build/
# https://whitfin.io/speeding-up-rust-docker-builds/
####################### VAULT BUILD IMAGE #######################
# 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/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 vaultwarden/web-vault:v2.25.1b
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.25.1b
# [vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba]
#
# - Conversely, to get the tag name from the digest:
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba
# [vaultwarden/web-vault:v2.25.1b]
#
FROM vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba as vault
########################## BUILD IMAGE ##########################
FROM blackdex/rust-musl:aarch64-musl-nightly-2022-01-23 as build
# Build time options to avoid dpkg warnings and help with reproducible builds.
ENV DEBIAN_FRONTEND=noninteractive \
LANG=C.UTF-8 \
TZ=UTC \
TERM=xterm-256color \
CARGO_HOME="/root/.cargo" \
USER="root"
# Create CARGO_HOME folder and don't download rust docs
RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry mkdir -pv "${CARGO_HOME}" \
&& rustup set profile minimal
ENV RUSTFLAGS='-C link-arg=-s'
# Creates a dummy project used to grab dependencies
RUN USER=root cargo new --bin /app
WORKDIR /app
# Copies over *only* your manifests and build files
COPY ./Cargo.* ./
COPY ./rust-toolchain ./rust-toolchain
COPY ./build.rs ./build.rs
RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry rustup target add aarch64-unknown-linux-musl
# Configure the DB ARG as late as possible to not invalidate the cached layers above
ARG DB=sqlite,mysql,postgresql
# Builds your dependencies and removes the
# dummy project, except the target folder
# This folder contains the compiled dependencies
RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry cargo build --features ${DB} --release --target=aarch64-unknown-linux-musl \
&& find . -not -path "./target*" -delete
# Copies the complete project
# To avoid copying unneeded files, use .dockerignore
COPY . .
# Make sure that we actually build the project
RUN touch src/main.rs
# Builds again, this time it'll just be
# your actual source files being built
# hadolint ignore=DL3059
RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry cargo build --features ${DB} --release --target=aarch64-unknown-linux-musl
######################## RUNTIME IMAGE ########################
# Create a new stage with a minimal image
# because we already have a binary built
FROM balenalib/aarch64-alpine:3.15
ENV ROCKET_ENV="staging" \
ROCKET_PORT=80 \
ROCKET_WORKERS=10 \
SSL_CERT_DIR=/etc/ssl/certs
# hadolint ignore=DL3059
RUN [ "cross-build-start" ]
# Create data folder and Install needed libraries
RUN mkdir /data \
&& apk add --no-cache \
openssl \
tzdata \
curl \
dumb-init \
ca-certificates
# hadolint ignore=DL3059
RUN [ "cross-build-end" ]
VOLUME /data
EXPOSE 80
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-musl/release/vaultwarden .
COPY docker/healthcheck.sh /healthcheck.sh
COPY docker/start.sh /start.sh
HEALTHCHECK --interval=60s --timeout=10s CMD ["/healthcheck.sh"]
# Configures the startup!
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
CMD ["/start.sh"]

View File

@@ -16,21 +16,20 @@
# - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # - From https://hub.docker.com/r/vaultwarden/web-vault/tags,
# click the tag name to view the digest of the image it currently points to. # click the tag name to view the digest of the image it currently points to.
# - From the command line: # - From the command line:
# $ docker pull vaultwarden/web-vault:v2.25.0 # $ docker pull vaultwarden/web-vault:v2.25.1b
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.25.0 # $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.25.1b
# [vaultwarden/web-vault@sha256:0df389deac9e83c739a1f4ff595f12f493b6c27cb4a22bb8fcaba9dc49b9b527] # [vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba]
# #
# - Conversely, to get the tag name from the digest: # - Conversely, to get the tag name from the digest:
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:0df389deac9e83c739a1f4ff595f12f493b6c27cb4a22bb8fcaba9dc49b9b527 # $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba
# [vaultwarden/web-vault:v2.25.0] # [vaultwarden/web-vault:v2.25.1b]
# #
FROM vaultwarden/web-vault@sha256:0df389deac9e83c739a1f4ff595f12f493b6c27cb4a22bb8fcaba9dc49b9b527 as vault FROM vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba as vault
########################## BUILD IMAGE ########################## ########################## BUILD IMAGE ##########################
FROM rust:1.55-buster as build FROM rust:1.58-buster as build
# Debian-based builds support multidb
ARG DB=sqlite,mysql,postgresql
# Build time options to avoid dpkg warnings and help with reproducible builds. # Build time options to avoid dpkg warnings and help with reproducible builds.
ENV DEBIAN_FRONTEND=noninteractive \ ENV DEBIAN_FRONTEND=noninteractive \
@@ -45,51 +44,32 @@ ENV DEBIAN_FRONTEND=noninteractive \
RUN mkdir -pv "${CARGO_HOME}" \ RUN mkdir -pv "${CARGO_HOME}" \
&& rustup set profile minimal && rustup set profile minimal
# NOTE: Any apt-get/dpkg after this stage will fail because of broken dependencies.
# For Diesel-RS migrations_macros to compile with MySQL/MariaDB we need to do some magic.
# We at least need libmariadb3:amd64 installed for the x86_64 version of libmariadb.so (client)
# We also need the libmariadb-dev-compat:amd64 but it can not be installed together with the :armel version.
# What we can do is a force install, because nothing important is overlapping each other.
# #
# Install required build libs for armel architecture. # Install required build libs for armel architecture.
# To compile both mysql and postgresql we need some extra packages for both host arch and target arch # hadolint ignore=DL3059
RUN sed 's/^deb/deb-src/' /etc/apt/sources.list > /etc/apt/sources.list.d/deb-src.list \ RUN dpkg --add-architecture armel \
&& dpkg --add-architecture armel \
&& apt-get update \ && apt-get update \
&& apt-get install -y \ && apt-get install -y \
--no-install-recommends \ --no-install-recommends \
libssl-dev:armel \ libssl-dev:armel \
libc6-dev:armel \ libc6-dev:armel \
libpq5:armel \ libpq5:armel \
libpq-dev \ libpq-dev:armel \
libmariadb3:amd64 \ libmariadb3:armel \
libmariadb-dev:armel \ libmariadb-dev:armel \
libmariadb-dev-compat:armel \ libmariadb-dev-compat:armel \
gcc-arm-linux-gnueabi \ gcc-arm-linux-gnueabi \
# #
# Manual install libmariadb-dev-compat:amd64 ( After this broken dependencies will break apt )
&& apt-get download libmariadb-dev-compat:amd64 \
&& dpkg --force-all -i ./libmariadb-dev-compat*.deb \
&& rm -rvf ./libmariadb-dev-compat*.deb \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* \
#
# For Diesel-RS migrations_macros to compile with PostgreSQL we need to do some magic.
# The libpq5:armel package seems to not provide a symlink to libpq.so.5 with the name libpq.so.
# This is only provided by the libpq-dev package which can't be installed for both arch at the same time.
# Without this specific file the ld command will fail and compilation fails with it.
&& ln -sfnr /usr/lib/arm-linux-gnueabi/libpq.so.5 /usr/lib/arm-linux-gnueabi/libpq.so \
#
# Make sure cargo has the right target config # Make sure cargo has the right target config
&& echo '[target.arm-unknown-linux-gnueabi]' >> "${CARGO_HOME}/config" \ && echo '[target.arm-unknown-linux-gnueabi]' >> "${CARGO_HOME}/config" \
&& echo 'linker = "arm-linux-gnueabi-gcc"' >> "${CARGO_HOME}/config" \ && echo 'linker = "arm-linux-gnueabi-gcc"' >> "${CARGO_HOME}/config" \
&& echo 'rustflags = ["-L/usr/lib/arm-linux-gnueabi"]' >> "${CARGO_HOME}/config" && echo 'rustflags = ["-L/usr/lib/arm-linux-gnueabi"]' >> "${CARGO_HOME}/config"
# Set arm specific environment values # Set arm specific environment values
ENV CC_arm_unknown_linux_gnueabi="/usr/bin/arm-linux-gnueabi-gcc" ENV CC_arm_unknown_linux_gnueabi="/usr/bin/arm-linux-gnueabi-gcc" \
ENV CROSS_COMPILE="1" CROSS_COMPILE="1" \
ENV OPENSSL_INCLUDE_DIR="/usr/include/arm-linux-gnueabi" OPENSSL_INCLUDE_DIR="/usr/include/arm-linux-gnueabi" \
ENV OPENSSL_LIB_DIR="/usr/lib/arm-linux-gnueabi" OPENSSL_LIB_DIR="/usr/lib/arm-linux-gnueabi"
# Creates a dummy project used to grab dependencies # Creates a dummy project used to grab dependencies
@@ -103,6 +83,9 @@ COPY ./build.rs ./build.rs
RUN rustup target add arm-unknown-linux-gnueabi RUN rustup target add arm-unknown-linux-gnueabi
# Configure the DB ARG as late as possible to not invalidate the cached layers above
ARG DB=sqlite,mysql,postgresql
# Builds your dependencies and removes the # Builds your dependencies and removes the
# dummy project, except the target folder # dummy project, except the target folder
# This folder contains the compiled dependencies # This folder contains the compiled dependencies
@@ -118,6 +101,7 @@ RUN touch src/main.rs
# Builds again, this time it'll just be # Builds again, this time it'll just be
# your actual source files being built # your actual source files being built
# hadolint ignore=DL3059
RUN cargo build --features ${DB} --release --target=arm-unknown-linux-gnueabi RUN cargo build --features ${DB} --release --target=arm-unknown-linux-gnueabi
######################## RUNTIME IMAGE ######################## ######################## RUNTIME IMAGE ########################
@@ -125,9 +109,9 @@ RUN cargo build --features ${DB} --release --target=arm-unknown-linux-gnueabi
# because we already have a binary built # because we already have a binary built
FROM balenalib/rpi-debian:buster FROM balenalib/rpi-debian:buster
ENV ROCKET_ENV "staging" ENV ROCKET_ENV="staging" \
ENV ROCKET_PORT=80 ROCKET_PORT=80 \
ENV ROCKET_WORKERS=10 ROCKET_WORKERS=10
# hadolint ignore=DL3059 # hadolint ignore=DL3059
RUN [ "cross-build-start" ] RUN [ "cross-build-start" ]

View File

@@ -0,0 +1,125 @@
# syntax=docker/dockerfile:1
# This file was generated using a Jinja2 template.
# Please make your changes in `Dockerfile.j2` and then `make` the individual Dockerfiles.
# Using multistage build:
# https://docs.docker.com/develop/develop-images/multistage-build/
# https://whitfin.io/speeding-up-rust-docker-builds/
####################### VAULT BUILD IMAGE #######################
# 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/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 vaultwarden/web-vault:v2.25.1b
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.25.1b
# [vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba]
#
# - Conversely, to get the tag name from the digest:
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba
# [vaultwarden/web-vault:v2.25.1b]
#
FROM vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba as vault
########################## BUILD IMAGE ##########################
FROM blackdex/rust-musl:arm-musleabi-nightly-2022-01-23 as build
# Build time options to avoid dpkg warnings and help with reproducible builds.
ENV DEBIAN_FRONTEND=noninteractive \
LANG=C.UTF-8 \
TZ=UTC \
TERM=xterm-256color \
CARGO_HOME="/root/.cargo" \
USER="root"
# Create CARGO_HOME folder and don't download rust docs
RUN mkdir -pv "${CARGO_HOME}" \
&& rustup set profile minimal
ENV RUSTFLAGS='-C link-arg=-s'
# Creates a dummy project used to grab dependencies
RUN USER=root cargo new --bin /app
WORKDIR /app
# Copies over *only* your manifests and build files
COPY ./Cargo.* ./
COPY ./rust-toolchain ./rust-toolchain
COPY ./build.rs ./build.rs
RUN rustup target add arm-unknown-linux-musleabi
# Configure the DB ARG as late as possible to not invalidate the cached layers above
ARG DB=sqlite,mysql,postgresql
# Builds your dependencies and removes the
# dummy project, except the target folder
# This folder contains the compiled dependencies
RUN cargo build --features ${DB} --release --target=arm-unknown-linux-musleabi \
&& find . -not -path "./target*" -delete
# Copies the complete project
# To avoid copying unneeded files, use .dockerignore
COPY . .
# Make sure that we actually build the project
RUN touch src/main.rs
# Builds again, this time it'll just be
# your actual source files being built
# hadolint ignore=DL3059
RUN cargo build --features ${DB} --release --target=arm-unknown-linux-musleabi
######################## RUNTIME IMAGE ########################
# Create a new stage with a minimal image
# because we already have a binary built
FROM balenalib/rpi-alpine:3.15
ENV ROCKET_ENV="staging" \
ROCKET_PORT=80 \
ROCKET_WORKERS=10 \
SSL_CERT_DIR=/etc/ssl/certs
# hadolint ignore=DL3059
RUN [ "cross-build-start" ]
# Create data folder and Install needed libraries
RUN mkdir /data \
&& apk add --no-cache \
openssl \
tzdata \
curl \
dumb-init \
ca-certificates
# hadolint ignore=DL3059
RUN [ "cross-build-end" ]
VOLUME /data
EXPOSE 80
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-musleabi/release/vaultwarden .
COPY docker/healthcheck.sh /healthcheck.sh
COPY docker/start.sh /start.sh
HEALTHCHECK --interval=60s --timeout=10s CMD ["/healthcheck.sh"]
# Configures the startup!
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
CMD ["/start.sh"]

View File

@@ -16,21 +16,20 @@
# - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # - From https://hub.docker.com/r/vaultwarden/web-vault/tags,
# click the tag name to view the digest of the image it currently points to. # click the tag name to view the digest of the image it currently points to.
# - From the command line: # - From the command line:
# $ docker pull vaultwarden/web-vault:v2.25.0 # $ docker pull vaultwarden/web-vault:v2.25.1b
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.25.0 # $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.25.1b
# [vaultwarden/web-vault@sha256:0df389deac9e83c739a1f4ff595f12f493b6c27cb4a22bb8fcaba9dc49b9b527] # [vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba]
# #
# - Conversely, to get the tag name from the digest: # - Conversely, to get the tag name from the digest:
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:0df389deac9e83c739a1f4ff595f12f493b6c27cb4a22bb8fcaba9dc49b9b527 # $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba
# [vaultwarden/web-vault:v2.25.0] # [vaultwarden/web-vault:v2.25.1b]
# #
FROM vaultwarden/web-vault@sha256:0df389deac9e83c739a1f4ff595f12f493b6c27cb4a22bb8fcaba9dc49b9b527 as vault FROM vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba as vault
########################## BUILD IMAGE ########################## ########################## BUILD IMAGE ##########################
FROM rust:1.55-buster as build FROM rust:1.58-buster as build
# Debian-based builds support multidb
ARG DB=sqlite,mysql,postgresql
# Build time options to avoid dpkg warnings and help with reproducible builds. # Build time options to avoid dpkg warnings and help with reproducible builds.
ENV DEBIAN_FRONTEND=noninteractive \ ENV DEBIAN_FRONTEND=noninteractive \
@@ -45,51 +44,32 @@ ENV DEBIAN_FRONTEND=noninteractive \
RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry mkdir -pv "${CARGO_HOME}" \ RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry mkdir -pv "${CARGO_HOME}" \
&& rustup set profile minimal && rustup set profile minimal
# NOTE: Any apt-get/dpkg after this stage will fail because of broken dependencies.
# For Diesel-RS migrations_macros to compile with MySQL/MariaDB we need to do some magic.
# We at least need libmariadb3:amd64 installed for the x86_64 version of libmariadb.so (client)
# We also need the libmariadb-dev-compat:amd64 but it can not be installed together with the :armel version.
# What we can do is a force install, because nothing important is overlapping each other.
# #
# Install required build libs for armel architecture. # Install required build libs for armel architecture.
# To compile both mysql and postgresql we need some extra packages for both host arch and target arch # hadolint ignore=DL3059
RUN sed 's/^deb/deb-src/' /etc/apt/sources.list > /etc/apt/sources.list.d/deb-src.list \ RUN dpkg --add-architecture armel \
&& dpkg --add-architecture armel \
&& apt-get update \ && apt-get update \
&& apt-get install -y \ && apt-get install -y \
--no-install-recommends \ --no-install-recommends \
libssl-dev:armel \ libssl-dev:armel \
libc6-dev:armel \ libc6-dev:armel \
libpq5:armel \ libpq5:armel \
libpq-dev \ libpq-dev:armel \
libmariadb3:amd64 \ libmariadb3:armel \
libmariadb-dev:armel \ libmariadb-dev:armel \
libmariadb-dev-compat:armel \ libmariadb-dev-compat:armel \
gcc-arm-linux-gnueabi \ gcc-arm-linux-gnueabi \
# #
# Manual install libmariadb-dev-compat:amd64 ( After this broken dependencies will break apt )
&& apt-get download libmariadb-dev-compat:amd64 \
&& dpkg --force-all -i ./libmariadb-dev-compat*.deb \
&& rm -rvf ./libmariadb-dev-compat*.deb \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* \
#
# For Diesel-RS migrations_macros to compile with PostgreSQL we need to do some magic.
# The libpq5:armel package seems to not provide a symlink to libpq.so.5 with the name libpq.so.
# This is only provided by the libpq-dev package which can't be installed for both arch at the same time.
# Without this specific file the ld command will fail and compilation fails with it.
&& ln -sfnr /usr/lib/arm-linux-gnueabi/libpq.so.5 /usr/lib/arm-linux-gnueabi/libpq.so \
#
# Make sure cargo has the right target config # Make sure cargo has the right target config
&& echo '[target.arm-unknown-linux-gnueabi]' >> "${CARGO_HOME}/config" \ && echo '[target.arm-unknown-linux-gnueabi]' >> "${CARGO_HOME}/config" \
&& echo 'linker = "arm-linux-gnueabi-gcc"' >> "${CARGO_HOME}/config" \ && echo 'linker = "arm-linux-gnueabi-gcc"' >> "${CARGO_HOME}/config" \
&& echo 'rustflags = ["-L/usr/lib/arm-linux-gnueabi"]' >> "${CARGO_HOME}/config" && echo 'rustflags = ["-L/usr/lib/arm-linux-gnueabi"]' >> "${CARGO_HOME}/config"
# Set arm specific environment values # Set arm specific environment values
ENV CC_arm_unknown_linux_gnueabi="/usr/bin/arm-linux-gnueabi-gcc" ENV CC_arm_unknown_linux_gnueabi="/usr/bin/arm-linux-gnueabi-gcc" \
ENV CROSS_COMPILE="1" CROSS_COMPILE="1" \
ENV OPENSSL_INCLUDE_DIR="/usr/include/arm-linux-gnueabi" OPENSSL_INCLUDE_DIR="/usr/include/arm-linux-gnueabi" \
ENV OPENSSL_LIB_DIR="/usr/lib/arm-linux-gnueabi" OPENSSL_LIB_DIR="/usr/lib/arm-linux-gnueabi"
# Creates a dummy project used to grab dependencies # Creates a dummy project used to grab dependencies
@@ -103,6 +83,9 @@ COPY ./build.rs ./build.rs
RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry rustup target add arm-unknown-linux-gnueabi RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry rustup target add arm-unknown-linux-gnueabi
# Configure the DB ARG as late as possible to not invalidate the cached layers above
ARG DB=sqlite,mysql,postgresql
# Builds your dependencies and removes the # Builds your dependencies and removes the
# dummy project, except the target folder # dummy project, except the target folder
# This folder contains the compiled dependencies # This folder contains the compiled dependencies
@@ -118,6 +101,7 @@ RUN touch src/main.rs
# Builds again, this time it'll just be # Builds again, this time it'll just be
# your actual source files being built # your actual source files being built
# hadolint ignore=DL3059
RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry cargo build --features ${DB} --release --target=arm-unknown-linux-gnueabi RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry cargo build --features ${DB} --release --target=arm-unknown-linux-gnueabi
######################## RUNTIME IMAGE ######################## ######################## RUNTIME IMAGE ########################
@@ -125,9 +109,9 @@ RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.
# because we already have a binary built # because we already have a binary built
FROM balenalib/rpi-debian:buster FROM balenalib/rpi-debian:buster
ENV ROCKET_ENV "staging" ENV ROCKET_ENV="staging" \
ENV ROCKET_PORT=80 ROCKET_PORT=80 \
ENV ROCKET_WORKERS=10 ROCKET_WORKERS=10
# hadolint ignore=DL3059 # hadolint ignore=DL3059
RUN [ "cross-build-start" ] RUN [ "cross-build-start" ]

View File

@@ -0,0 +1,125 @@
# syntax=docker/dockerfile:1
# This file was generated using a Jinja2 template.
# Please make your changes in `Dockerfile.j2` and then `make` the individual Dockerfiles.
# Using multistage build:
# https://docs.docker.com/develop/develop-images/multistage-build/
# https://whitfin.io/speeding-up-rust-docker-builds/
####################### VAULT BUILD IMAGE #######################
# 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/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 vaultwarden/web-vault:v2.25.1b
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.25.1b
# [vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba]
#
# - Conversely, to get the tag name from the digest:
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba
# [vaultwarden/web-vault:v2.25.1b]
#
FROM vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba as vault
########################## BUILD IMAGE ##########################
FROM blackdex/rust-musl:arm-musleabi-nightly-2022-01-23 as build
# Build time options to avoid dpkg warnings and help with reproducible builds.
ENV DEBIAN_FRONTEND=noninteractive \
LANG=C.UTF-8 \
TZ=UTC \
TERM=xterm-256color \
CARGO_HOME="/root/.cargo" \
USER="root"
# Create CARGO_HOME folder and don't download rust docs
RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry mkdir -pv "${CARGO_HOME}" \
&& rustup set profile minimal
ENV RUSTFLAGS='-C link-arg=-s'
# Creates a dummy project used to grab dependencies
RUN USER=root cargo new --bin /app
WORKDIR /app
# Copies over *only* your manifests and build files
COPY ./Cargo.* ./
COPY ./rust-toolchain ./rust-toolchain
COPY ./build.rs ./build.rs
RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry rustup target add arm-unknown-linux-musleabi
# Configure the DB ARG as late as possible to not invalidate the cached layers above
ARG DB=sqlite,mysql,postgresql
# Builds your dependencies and removes the
# dummy project, except the target folder
# This folder contains the compiled dependencies
RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry cargo build --features ${DB} --release --target=arm-unknown-linux-musleabi \
&& find . -not -path "./target*" -delete
# Copies the complete project
# To avoid copying unneeded files, use .dockerignore
COPY . .
# Make sure that we actually build the project
RUN touch src/main.rs
# Builds again, this time it'll just be
# your actual source files being built
# hadolint ignore=DL3059
RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry cargo build --features ${DB} --release --target=arm-unknown-linux-musleabi
######################## RUNTIME IMAGE ########################
# Create a new stage with a minimal image
# because we already have a binary built
FROM balenalib/rpi-alpine:3.15
ENV ROCKET_ENV="staging" \
ROCKET_PORT=80 \
ROCKET_WORKERS=10 \
SSL_CERT_DIR=/etc/ssl/certs
# hadolint ignore=DL3059
RUN [ "cross-build-start" ]
# Create data folder and Install needed libraries
RUN mkdir /data \
&& apk add --no-cache \
openssl \
tzdata \
curl \
dumb-init \
ca-certificates
# hadolint ignore=DL3059
RUN [ "cross-build-end" ]
VOLUME /data
EXPOSE 80
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-musleabi/release/vaultwarden .
COPY docker/healthcheck.sh /healthcheck.sh
COPY docker/start.sh /start.sh
HEALTHCHECK --interval=60s --timeout=10s CMD ["/healthcheck.sh"]
# Configures the startup!
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
CMD ["/start.sh"]

View File

@@ -16,21 +16,20 @@
# - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # - From https://hub.docker.com/r/vaultwarden/web-vault/tags,
# click the tag name to view the digest of the image it currently points to. # click the tag name to view the digest of the image it currently points to.
# - From the command line: # - From the command line:
# $ docker pull vaultwarden/web-vault:v2.25.0 # $ docker pull vaultwarden/web-vault:v2.25.1b
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.25.0 # $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.25.1b
# [vaultwarden/web-vault@sha256:0df389deac9e83c739a1f4ff595f12f493b6c27cb4a22bb8fcaba9dc49b9b527] # [vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba]
# #
# - Conversely, to get the tag name from the digest: # - Conversely, to get the tag name from the digest:
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:0df389deac9e83c739a1f4ff595f12f493b6c27cb4a22bb8fcaba9dc49b9b527 # $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba
# [vaultwarden/web-vault:v2.25.0] # [vaultwarden/web-vault:v2.25.1b]
# #
FROM vaultwarden/web-vault@sha256:0df389deac9e83c739a1f4ff595f12f493b6c27cb4a22bb8fcaba9dc49b9b527 as vault FROM vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba as vault
########################## BUILD IMAGE ########################## ########################## BUILD IMAGE ##########################
FROM rust:1.55-buster as build FROM rust:1.58-buster as build
# Debian-based builds support multidb
ARG DB=sqlite,mysql,postgresql
# Build time options to avoid dpkg warnings and help with reproducible builds. # Build time options to avoid dpkg warnings and help with reproducible builds.
ENV DEBIAN_FRONTEND=noninteractive \ ENV DEBIAN_FRONTEND=noninteractive \
@@ -45,51 +44,32 @@ ENV DEBIAN_FRONTEND=noninteractive \
RUN mkdir -pv "${CARGO_HOME}" \ RUN mkdir -pv "${CARGO_HOME}" \
&& rustup set profile minimal && rustup set profile minimal
# NOTE: Any apt-get/dpkg after this stage will fail because of broken dependencies.
# For Diesel-RS migrations_macros to compile with MySQL/MariaDB we need to do some magic.
# We at least need libmariadb3:amd64 installed for the x86_64 version of libmariadb.so (client)
# We also need the libmariadb-dev-compat:amd64 but it can not be installed together with the :armhf version.
# What we can do is a force install, because nothing important is overlapping each other.
# #
# Install required build libs for armhf architecture. # Install required build libs for armhf architecture.
# To compile both mysql and postgresql we need some extra packages for both host arch and target arch # hadolint ignore=DL3059
RUN sed 's/^deb/deb-src/' /etc/apt/sources.list > /etc/apt/sources.list.d/deb-src.list \ RUN dpkg --add-architecture armhf \
&& dpkg --add-architecture armhf \
&& apt-get update \ && apt-get update \
&& apt-get install -y \ && apt-get install -y \
--no-install-recommends \ --no-install-recommends \
libssl-dev:armhf \ libssl-dev:armhf \
libc6-dev:armhf \ libc6-dev:armhf \
libpq5:armhf \ libpq5:armhf \
libpq-dev \ libpq-dev:armhf \
libmariadb3:amd64 \ libmariadb3:armhf \
libmariadb-dev:armhf \ libmariadb-dev:armhf \
libmariadb-dev-compat:armhf \ libmariadb-dev-compat:armhf \
gcc-arm-linux-gnueabihf \ gcc-arm-linux-gnueabihf \
# #
# Manual install libmariadb-dev-compat:amd64 ( After this broken dependencies will break apt )
&& apt-get download libmariadb-dev-compat:amd64 \
&& dpkg --force-all -i ./libmariadb-dev-compat*.deb \
&& rm -rvf ./libmariadb-dev-compat*.deb \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* \
#
# For Diesel-RS migrations_macros to compile with PostgreSQL we need to do some magic.
# The libpq5:armhf package seems to not provide a symlink to libpq.so.5 with the name libpq.so.
# This is only provided by the libpq-dev package which can't be installed for both arch at the same time.
# Without this specific file the ld command will fail and compilation fails with it.
&& ln -sfnr /usr/lib/arm-linux-gnueabihf/libpq.so.5 /usr/lib/arm-linux-gnueabihf/libpq.so \
#
# Make sure cargo has the right target config # Make sure cargo has the right target config
&& echo '[target.armv7-unknown-linux-gnueabihf]' >> "${CARGO_HOME}/config" \ && echo '[target.armv7-unknown-linux-gnueabihf]' >> "${CARGO_HOME}/config" \
&& echo 'linker = "arm-linux-gnueabihf-gcc"' >> "${CARGO_HOME}/config" \ && echo 'linker = "arm-linux-gnueabihf-gcc"' >> "${CARGO_HOME}/config" \
&& echo 'rustflags = ["-L/usr/lib/arm-linux-gnueabihf"]' >> "${CARGO_HOME}/config" && echo 'rustflags = ["-L/usr/lib/arm-linux-gnueabihf"]' >> "${CARGO_HOME}/config"
# Set arm specific environment values # Set arm specific environment values
ENV CC_armv7_unknown_linux_gnueabihf="/usr/bin/arm-linux-gnueabihf-gcc" ENV CC_armv7_unknown_linux_gnueabihf="/usr/bin/arm-linux-gnueabihf-gcc" \
ENV CROSS_COMPILE="1" CROSS_COMPILE="1" \
ENV OPENSSL_INCLUDE_DIR="/usr/include/arm-linux-gnueabihf" OPENSSL_INCLUDE_DIR="/usr/include/arm-linux-gnueabihf" \
ENV OPENSSL_LIB_DIR="/usr/lib/arm-linux-gnueabihf" OPENSSL_LIB_DIR="/usr/lib/arm-linux-gnueabihf"
# Creates a dummy project used to grab dependencies # Creates a dummy project used to grab dependencies
@@ -103,6 +83,9 @@ COPY ./build.rs ./build.rs
RUN rustup target add armv7-unknown-linux-gnueabihf RUN rustup target add armv7-unknown-linux-gnueabihf
# Configure the DB ARG as late as possible to not invalidate the cached layers above
ARG DB=sqlite,mysql,postgresql
# Builds your dependencies and removes the # Builds your dependencies and removes the
# dummy project, except the target folder # dummy project, except the target folder
# This folder contains the compiled dependencies # This folder contains the compiled dependencies
@@ -118,6 +101,7 @@ RUN touch src/main.rs
# Builds again, this time it'll just be # Builds again, this time it'll just be
# your actual source files being built # your actual source files being built
# hadolint ignore=DL3059
RUN cargo build --features ${DB} --release --target=armv7-unknown-linux-gnueabihf RUN cargo build --features ${DB} --release --target=armv7-unknown-linux-gnueabihf
######################## RUNTIME IMAGE ######################## ######################## RUNTIME IMAGE ########################
@@ -125,9 +109,9 @@ RUN cargo build --features ${DB} --release --target=armv7-unknown-linux-gnueabih
# because we already have a binary built # because we already have a binary built
FROM balenalib/armv7hf-debian:buster FROM balenalib/armv7hf-debian:buster
ENV ROCKET_ENV "staging" ENV ROCKET_ENV="staging" \
ENV ROCKET_PORT=80 ROCKET_PORT=80 \
ENV ROCKET_WORKERS=10 ROCKET_WORKERS=10
# hadolint ignore=DL3059 # hadolint ignore=DL3059
RUN [ "cross-build-start" ] RUN [ "cross-build-start" ]

View File

@@ -16,22 +16,20 @@
# - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # - From https://hub.docker.com/r/vaultwarden/web-vault/tags,
# click the tag name to view the digest of the image it currently points to. # click the tag name to view the digest of the image it currently points to.
# - From the command line: # - From the command line:
# $ docker pull vaultwarden/web-vault:v2.25.0 # $ docker pull vaultwarden/web-vault:v2.25.1b
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.25.0 # $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.25.1b
# [vaultwarden/web-vault@sha256:0df389deac9e83c739a1f4ff595f12f493b6c27cb4a22bb8fcaba9dc49b9b527] # [vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba]
# #
# - Conversely, to get the tag name from the digest: # - Conversely, to get the tag name from the digest:
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:0df389deac9e83c739a1f4ff595f12f493b6c27cb4a22bb8fcaba9dc49b9b527 # $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba
# [vaultwarden/web-vault:v2.25.0] # [vaultwarden/web-vault:v2.25.1b]
# #
FROM vaultwarden/web-vault@sha256:0df389deac9e83c739a1f4ff595f12f493b6c27cb4a22bb8fcaba9dc49b9b527 as vault FROM vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba as vault
########################## BUILD IMAGE ########################## ########################## BUILD IMAGE ##########################
FROM messense/rust-musl-cross:armv7-musleabihf as build FROM blackdex/rust-musl:armv7-musleabihf-nightly-2022-01-23 as build
# Alpine-based ARM (musl) only supports sqlite during compile time.
# We now also need to add vendored_openssl, because the current base image we use to build has OpenSSL removed.
ARG DB=sqlite,vendored_openssl
# Build time options to avoid dpkg warnings and help with reproducible builds. # Build time options to avoid dpkg warnings and help with reproducible builds.
ENV DEBIAN_FRONTEND=noninteractive \ ENV DEBIAN_FRONTEND=noninteractive \
@@ -60,6 +58,9 @@ COPY ./build.rs ./build.rs
RUN rustup target add armv7-unknown-linux-musleabihf RUN rustup target add armv7-unknown-linux-musleabihf
# Configure the DB ARG as late as possible to not invalidate the cached layers above
ARG DB=sqlite,mysql,postgresql
# Builds your dependencies and removes the # Builds your dependencies and removes the
# dummy project, except the target folder # dummy project, except the target folder
# This folder contains the compiled dependencies # This folder contains the compiled dependencies
@@ -75,6 +76,7 @@ RUN touch src/main.rs
# Builds again, this time it'll just be # Builds again, this time it'll just be
# your actual source files being built # your actual source files being built
# hadolint ignore=DL3059
RUN cargo build --features ${DB} --release --target=armv7-unknown-linux-musleabihf RUN cargo build --features ${DB} --release --target=armv7-unknown-linux-musleabihf
# hadolint ignore=DL3059 # hadolint ignore=DL3059
RUN musl-strip target/armv7-unknown-linux-musleabihf/release/vaultwarden RUN musl-strip target/armv7-unknown-linux-musleabihf/release/vaultwarden
@@ -82,12 +84,13 @@ RUN musl-strip target/armv7-unknown-linux-musleabihf/release/vaultwarden
######################## RUNTIME IMAGE ######################## ######################## RUNTIME IMAGE ########################
# Create a new stage with a minimal image # Create a new stage with a minimal image
# because we already have a binary built # because we already have a binary built
FROM balenalib/armv7hf-alpine:3.14 FROM balenalib/armv7hf-alpine:3.15
ENV ROCKET_ENV="staging" \
ROCKET_PORT=80 \
ROCKET_WORKERS=10 \
SSL_CERT_DIR=/etc/ssl/certs
ENV ROCKET_ENV "staging"
ENV ROCKET_PORT=80
ENV ROCKET_WORKERS=10
ENV SSL_CERT_DIR=/etc/ssl/certs
# hadolint ignore=DL3059 # hadolint ignore=DL3059
RUN [ "cross-build-start" ] RUN [ "cross-build-start" ]

View File

@@ -16,21 +16,20 @@
# - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # - From https://hub.docker.com/r/vaultwarden/web-vault/tags,
# click the tag name to view the digest of the image it currently points to. # click the tag name to view the digest of the image it currently points to.
# - From the command line: # - From the command line:
# $ docker pull vaultwarden/web-vault:v2.25.0 # $ docker pull vaultwarden/web-vault:v2.25.1b
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.25.0 # $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.25.1b
# [vaultwarden/web-vault@sha256:0df389deac9e83c739a1f4ff595f12f493b6c27cb4a22bb8fcaba9dc49b9b527] # [vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba]
# #
# - Conversely, to get the tag name from the digest: # - Conversely, to get the tag name from the digest:
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:0df389deac9e83c739a1f4ff595f12f493b6c27cb4a22bb8fcaba9dc49b9b527 # $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba
# [vaultwarden/web-vault:v2.25.0] # [vaultwarden/web-vault:v2.25.1b]
# #
FROM vaultwarden/web-vault@sha256:0df389deac9e83c739a1f4ff595f12f493b6c27cb4a22bb8fcaba9dc49b9b527 as vault FROM vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba as vault
########################## BUILD IMAGE ########################## ########################## BUILD IMAGE ##########################
FROM rust:1.55-buster as build FROM rust:1.58-buster as build
# Debian-based builds support multidb
ARG DB=sqlite,mysql,postgresql
# Build time options to avoid dpkg warnings and help with reproducible builds. # Build time options to avoid dpkg warnings and help with reproducible builds.
ENV DEBIAN_FRONTEND=noninteractive \ ENV DEBIAN_FRONTEND=noninteractive \
@@ -45,51 +44,32 @@ ENV DEBIAN_FRONTEND=noninteractive \
RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry mkdir -pv "${CARGO_HOME}" \ RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry mkdir -pv "${CARGO_HOME}" \
&& rustup set profile minimal && rustup set profile minimal
# NOTE: Any apt-get/dpkg after this stage will fail because of broken dependencies.
# For Diesel-RS migrations_macros to compile with MySQL/MariaDB we need to do some magic.
# We at least need libmariadb3:amd64 installed for the x86_64 version of libmariadb.so (client)
# We also need the libmariadb-dev-compat:amd64 but it can not be installed together with the :armhf version.
# What we can do is a force install, because nothing important is overlapping each other.
# #
# Install required build libs for armhf architecture. # Install required build libs for armhf architecture.
# To compile both mysql and postgresql we need some extra packages for both host arch and target arch # hadolint ignore=DL3059
RUN sed 's/^deb/deb-src/' /etc/apt/sources.list > /etc/apt/sources.list.d/deb-src.list \ RUN dpkg --add-architecture armhf \
&& dpkg --add-architecture armhf \
&& apt-get update \ && apt-get update \
&& apt-get install -y \ && apt-get install -y \
--no-install-recommends \ --no-install-recommends \
libssl-dev:armhf \ libssl-dev:armhf \
libc6-dev:armhf \ libc6-dev:armhf \
libpq5:armhf \ libpq5:armhf \
libpq-dev \ libpq-dev:armhf \
libmariadb3:amd64 \ libmariadb3:armhf \
libmariadb-dev:armhf \ libmariadb-dev:armhf \
libmariadb-dev-compat:armhf \ libmariadb-dev-compat:armhf \
gcc-arm-linux-gnueabihf \ gcc-arm-linux-gnueabihf \
# #
# Manual install libmariadb-dev-compat:amd64 ( After this broken dependencies will break apt )
&& apt-get download libmariadb-dev-compat:amd64 \
&& dpkg --force-all -i ./libmariadb-dev-compat*.deb \
&& rm -rvf ./libmariadb-dev-compat*.deb \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* \
#
# For Diesel-RS migrations_macros to compile with PostgreSQL we need to do some magic.
# The libpq5:armhf package seems to not provide a symlink to libpq.so.5 with the name libpq.so.
# This is only provided by the libpq-dev package which can't be installed for both arch at the same time.
# Without this specific file the ld command will fail and compilation fails with it.
&& ln -sfnr /usr/lib/arm-linux-gnueabihf/libpq.so.5 /usr/lib/arm-linux-gnueabihf/libpq.so \
#
# Make sure cargo has the right target config # Make sure cargo has the right target config
&& echo '[target.armv7-unknown-linux-gnueabihf]' >> "${CARGO_HOME}/config" \ && echo '[target.armv7-unknown-linux-gnueabihf]' >> "${CARGO_HOME}/config" \
&& echo 'linker = "arm-linux-gnueabihf-gcc"' >> "${CARGO_HOME}/config" \ && echo 'linker = "arm-linux-gnueabihf-gcc"' >> "${CARGO_HOME}/config" \
&& echo 'rustflags = ["-L/usr/lib/arm-linux-gnueabihf"]' >> "${CARGO_HOME}/config" && echo 'rustflags = ["-L/usr/lib/arm-linux-gnueabihf"]' >> "${CARGO_HOME}/config"
# Set arm specific environment values # Set arm specific environment values
ENV CC_armv7_unknown_linux_gnueabihf="/usr/bin/arm-linux-gnueabihf-gcc" ENV CC_armv7_unknown_linux_gnueabihf="/usr/bin/arm-linux-gnueabihf-gcc" \
ENV CROSS_COMPILE="1" CROSS_COMPILE="1" \
ENV OPENSSL_INCLUDE_DIR="/usr/include/arm-linux-gnueabihf" OPENSSL_INCLUDE_DIR="/usr/include/arm-linux-gnueabihf" \
ENV OPENSSL_LIB_DIR="/usr/lib/arm-linux-gnueabihf" OPENSSL_LIB_DIR="/usr/lib/arm-linux-gnueabihf"
# Creates a dummy project used to grab dependencies # Creates a dummy project used to grab dependencies
@@ -103,6 +83,9 @@ COPY ./build.rs ./build.rs
RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry rustup target add armv7-unknown-linux-gnueabihf RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry rustup target add armv7-unknown-linux-gnueabihf
# Configure the DB ARG as late as possible to not invalidate the cached layers above
ARG DB=sqlite,mysql,postgresql
# Builds your dependencies and removes the # Builds your dependencies and removes the
# dummy project, except the target folder # dummy project, except the target folder
# This folder contains the compiled dependencies # This folder contains the compiled dependencies
@@ -118,6 +101,7 @@ RUN touch src/main.rs
# Builds again, this time it'll just be # Builds again, this time it'll just be
# your actual source files being built # your actual source files being built
# hadolint ignore=DL3059
RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry cargo build --features ${DB} --release --target=armv7-unknown-linux-gnueabihf RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry cargo build --features ${DB} --release --target=armv7-unknown-linux-gnueabihf
######################## RUNTIME IMAGE ######################## ######################## RUNTIME IMAGE ########################
@@ -125,9 +109,9 @@ RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.
# because we already have a binary built # because we already have a binary built
FROM balenalib/armv7hf-debian:buster FROM balenalib/armv7hf-debian:buster
ENV ROCKET_ENV "staging" ENV ROCKET_ENV="staging" \
ENV ROCKET_PORT=80 ROCKET_PORT=80 \
ENV ROCKET_WORKERS=10 ROCKET_WORKERS=10
# hadolint ignore=DL3059 # hadolint ignore=DL3059
RUN [ "cross-build-start" ] RUN [ "cross-build-start" ]

View File

@@ -16,22 +16,20 @@
# - From https://hub.docker.com/r/vaultwarden/web-vault/tags, # - From https://hub.docker.com/r/vaultwarden/web-vault/tags,
# click the tag name to view the digest of the image it currently points to. # click the tag name to view the digest of the image it currently points to.
# - From the command line: # - From the command line:
# $ docker pull vaultwarden/web-vault:v2.25.0 # $ docker pull vaultwarden/web-vault:v2.25.1b
# $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.25.0 # $ docker image inspect --format "{{.RepoDigests}}" vaultwarden/web-vault:v2.25.1b
# [vaultwarden/web-vault@sha256:0df389deac9e83c739a1f4ff595f12f493b6c27cb4a22bb8fcaba9dc49b9b527] # [vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba]
# #
# - Conversely, to get the tag name from the digest: # - Conversely, to get the tag name from the digest:
# $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:0df389deac9e83c739a1f4ff595f12f493b6c27cb4a22bb8fcaba9dc49b9b527 # $ docker image inspect --format "{{.RepoTags}}" vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba
# [vaultwarden/web-vault:v2.25.0] # [vaultwarden/web-vault:v2.25.1b]
# #
FROM vaultwarden/web-vault@sha256:0df389deac9e83c739a1f4ff595f12f493b6c27cb4a22bb8fcaba9dc49b9b527 as vault FROM vaultwarden/web-vault@sha256:9b82318d553d72f091e8755f5aff80eed495f90bbe5b0703522953480f5c2fba as vault
########################## BUILD IMAGE ########################## ########################## BUILD IMAGE ##########################
FROM messense/rust-musl-cross:armv7-musleabihf as build FROM blackdex/rust-musl:armv7-musleabihf-nightly-2022-01-23 as build
# Alpine-based ARM (musl) only supports sqlite during compile time.
# We now also need to add vendored_openssl, because the current base image we use to build has OpenSSL removed.
ARG DB=sqlite,vendored_openssl
# Build time options to avoid dpkg warnings and help with reproducible builds. # Build time options to avoid dpkg warnings and help with reproducible builds.
ENV DEBIAN_FRONTEND=noninteractive \ ENV DEBIAN_FRONTEND=noninteractive \
@@ -60,6 +58,9 @@ COPY ./build.rs ./build.rs
RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry rustup target add armv7-unknown-linux-musleabihf RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry rustup target add armv7-unknown-linux-musleabihf
# Configure the DB ARG as late as possible to not invalidate the cached layers above
ARG DB=sqlite,mysql,postgresql
# Builds your dependencies and removes the # Builds your dependencies and removes the
# dummy project, except the target folder # dummy project, except the target folder
# This folder contains the compiled dependencies # This folder contains the compiled dependencies
@@ -75,6 +76,7 @@ RUN touch src/main.rs
# Builds again, this time it'll just be # Builds again, this time it'll just be
# your actual source files being built # your actual source files being built
# hadolint ignore=DL3059
RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry cargo build --features ${DB} --release --target=armv7-unknown-linux-musleabihf RUN --mount=type=cache,target=/root/.cargo/git --mount=type=cache,target=/root/.cargo/registry cargo build --features ${DB} --release --target=armv7-unknown-linux-musleabihf
# hadolint ignore=DL3059 # hadolint ignore=DL3059
RUN musl-strip target/armv7-unknown-linux-musleabihf/release/vaultwarden RUN musl-strip target/armv7-unknown-linux-musleabihf/release/vaultwarden
@@ -82,12 +84,13 @@ RUN musl-strip target/armv7-unknown-linux-musleabihf/release/vaultwarden
######################## RUNTIME IMAGE ######################## ######################## RUNTIME IMAGE ########################
# Create a new stage with a minimal image # Create a new stage with a minimal image
# because we already have a binary built # because we already have a binary built
FROM balenalib/armv7hf-alpine:3.14 FROM balenalib/armv7hf-alpine:3.15
ENV ROCKET_ENV="staging" \
ROCKET_PORT=80 \
ROCKET_WORKERS=10 \
SSL_CERT_DIR=/etc/ssl/certs
ENV ROCKET_ENV "staging"
ENV ROCKET_PORT=80
ENV ROCKET_WORKERS=10
ENV SSL_CERT_DIR=/etc/ssl/certs
# hadolint ignore=DL3059 # hadolint ignore=DL3059
RUN [ "cross-build-start" ] RUN [ "cross-build-start" ]

View File

@@ -7,10 +7,5 @@ arches=(
) )
if [[ "${DOCKER_TAG}" == *alpine ]]; then if [[ "${DOCKER_TAG}" == *alpine ]]; then
# The Alpine image build currently only works for certain arches.
distro_suffix=.alpine distro_suffix=.alpine
arches=(
amd64
armv7
)
fi fi

View File

@@ -0,0 +1,2 @@
ALTER TABLE users
ADD COLUMN api_key VARCHAR(255);

View File

@@ -0,0 +1,2 @@
ALTER TABLE users
ADD COLUMN api_key TEXT;

View File

@@ -0,0 +1,2 @@
ALTER TABLE users
ADD COLUMN api_key TEXT;

View File

@@ -1 +1 @@
nightly-2021-11-05 nightly-2022-01-23

View File

@@ -21,7 +21,7 @@ use crate::{
util::{ util::{
docker_base_image, format_naive_datetime_local, get_display_size, get_reqwest_client, is_running_in_docker, docker_base_image, format_naive_datetime_local, get_display_size, get_reqwest_client, is_running_in_docker,
}, },
CONFIG, CONFIG, VERSION,
}; };
pub fn routes() -> Vec<Route> { pub fn routes() -> Vec<Route> {
@@ -74,11 +74,10 @@ fn admin_disabled() -> &'static str {
"The admin panel is disabled, please configure the 'ADMIN_TOKEN' variable to enable it" "The admin panel is disabled, please configure the 'ADMIN_TOKEN' variable to enable it"
} }
const COOKIE_NAME: &str = "BWRS_ADMIN"; const COOKIE_NAME: &str = "VW_ADMIN";
const ADMIN_PATH: &str = "/admin"; const ADMIN_PATH: &str = "/admin";
const BASE_TEMPLATE: &str = "admin/base"; const BASE_TEMPLATE: &str = "admin/base";
const VERSION: Option<&str> = option_env!("BWRS_VERSION");
fn admin_path() -> String { fn admin_path() -> String {
format!("{}{}", CONFIG.domain_path(), ADMIN_PATH) format!("{}{}", CONFIG.domain_path(), ADMIN_PATH)
@@ -166,6 +165,10 @@ fn post_admin_login(
) -> Result<Redirect, Flash<Redirect>> { ) -> Result<Redirect, Flash<Redirect>> {
let data = data.into_inner(); let data = data.into_inner();
if crate::ratelimit::check_limit_admin(&ip.ip).is_err() {
return Err(Flash::error(Redirect::to(admin_url(referer)), "Too many requests, try again later."));
}
// If the token is invalid, redirect to login page // If the token is invalid, redirect to login page
if !_validate_token(&data.token) { if !_validate_token(&data.token) {
error!("Invalid admin token. IP: {}", ip.ip); error!("Invalid admin token. IP: {}", ip.ip);
@@ -482,7 +485,7 @@ fn diagnostics(_token: AdminToken, ip_header: IpHeader, conn: DbConn) -> ApiResu
// Get current running versions // Get current running versions
let web_vault_version: WebVaultVersion = let web_vault_version: WebVaultVersion =
match read_file_string(&format!("{}/{}", CONFIG.web_vault_folder(), "bwrs-version.json")) { match read_file_string(&format!("{}/{}", CONFIG.web_vault_folder(), "vw-version.json")) {
Ok(s) => serde_json::from_str(&s)?, Ok(s) => serde_json::from_str(&s)?,
_ => match read_file_string(&format!("{}/{}", CONFIG.web_vault_folder(), "version.json")) { _ => match read_file_string(&format!("{}/{}", CONFIG.web_vault_folder(), "version.json")) {
Ok(s) => serde_json::from_str(&s)?, Ok(s) => serde_json::from_str(&s)?,

View File

@@ -34,6 +34,8 @@ pub fn routes() -> Vec<rocket::Route> {
password_hint, password_hint,
prelogin, prelogin,
verify_password, verify_password,
api_key,
rotate_api_key,
] ]
} }
@@ -87,14 +89,11 @@ fn register(data: JsonUpcase<RegisterData>, conn: DbConn) -> EmptyResult {
user_org.status = UserOrgStatus::Accepted as i32; user_org.status = UserOrgStatus::Accepted as i32;
user_org.save(&conn)?; user_org.save(&conn)?;
} }
user
} else if EmergencyAccess::find_invited_by_grantee_email(&email, &conn).is_some() {
user user
} else if CONFIG.is_signup_allowed(&email) { } else if CONFIG.is_signup_allowed(&email) {
// check if it's invited by emergency contact err!("Account with this email already exists")
match EmergencyAccess::find_invited_by_grantee_email(&data.Email, &conn) {
Some(_) => user,
_ => err!("Account with this email already exists"),
}
} else { } else {
err!("Registration not allowed or user already exists") err!("Registration not allowed or user already exists")
} }
@@ -382,7 +381,7 @@ fn post_email_token(data: JsonUpcase<EmailTokenData>, headers: Headers, conn: Db
err!("Email domain not allowed"); err!("Email domain not allowed");
} }
let token = crypto::generate_token(6)?; let token = crypto::generate_email_token(6);
if CONFIG.mail_enabled() { if CONFIG.mail_enabled() {
if let Err(e) = mail::send_change_email(&data.NewEmail, &token) { if let Err(e) = mail::send_change_email(&data.NewEmail, &token) {
@@ -647,15 +646,17 @@ fn prelogin(data: JsonUpcase<PreloginData>, conn: DbConn) -> Json<Value> {
"KdfIterations": kdf_iter "KdfIterations": kdf_iter
})) }))
} }
// https://github.com/bitwarden/server/blob/master/src/Api/Models/Request/Accounts/SecretVerificationRequestModel.cs
#[derive(Deserialize)] #[derive(Deserialize)]
#[allow(non_snake_case)] #[allow(non_snake_case)]
struct VerifyPasswordData { struct SecretVerificationRequest {
MasterPasswordHash: String, MasterPasswordHash: String,
} }
#[post("/accounts/verify-password", data = "<data>")] #[post("/accounts/verify-password", data = "<data>")]
fn verify_password(data: JsonUpcase<VerifyPasswordData>, headers: Headers) -> EmptyResult { fn verify_password(data: JsonUpcase<SecretVerificationRequest>, headers: Headers) -> EmptyResult {
let data: VerifyPasswordData = data.into_inner().data; let data: SecretVerificationRequest = data.into_inner().data;
let user = headers.user; let user = headers.user;
if !user.check_valid_password(&data.MasterPasswordHash) { if !user.check_valid_password(&data.MasterPasswordHash) {
@@ -664,3 +665,32 @@ fn verify_password(data: JsonUpcase<VerifyPasswordData>, headers: Headers) -> Em
Ok(()) Ok(())
} }
fn _api_key(data: JsonUpcase<SecretVerificationRequest>, rotate: bool, headers: Headers, conn: DbConn) -> JsonResult {
let data: SecretVerificationRequest = data.into_inner().data;
let mut user = headers.user;
if !user.check_valid_password(&data.MasterPasswordHash) {
err!("Invalid password")
}
if rotate || user.api_key.is_none() {
user.api_key = Some(crypto::generate_api_key());
user.save(&conn).expect("Error saving API key");
}
Ok(Json(json!({
"ApiKey": user.api_key,
"Object": "apiKey",
})))
}
#[post("/accounts/api-key", data = "<data>")]
fn api_key(data: JsonUpcase<SecretVerificationRequest>, headers: Headers, conn: DbConn) -> JsonResult {
_api_key(data, false, headers, conn)
}
#[post("/accounts/rotate-api-key", data = "<data>")]
fn rotate_api_key(data: JsonUpcase<SecretVerificationRequest>, headers: Headers, conn: DbConn) -> JsonResult {
_api_key(data, true, headers, conn)
}

View File

@@ -182,7 +182,7 @@ fn send_invite(data: JsonUpcase<EmergencyAccessInviteData>, headers: Headers, co
let grantee_user = match User::find_by_mail(&email, &conn) { let grantee_user = match User::find_by_mail(&email, &conn) {
None => { None => {
if !CONFIG.signups_allowed() { if !CONFIG.invitations_allowed() {
err!(format!("Grantee user does not exist: {}", email)) err!(format!("Grantee user does not exist: {}", email))
} }

View File

@@ -170,7 +170,7 @@ fn hibp_breach(username: String) -> JsonResult {
"BreachDate": "2019-08-18T00:00:00Z", "BreachDate": "2019-08-18T00:00:00Z",
"AddedDate": "2019-08-18T00:00:00Z", "AddedDate": "2019-08-18T00:00:00Z",
"Description": format!("Go to: <a href=\"https://haveibeenpwned.com/account/{account}\" target=\"_blank\" rel=\"noreferrer\">https://haveibeenpwned.com/account/{account}</a> for a manual check.<br/><br/>HaveIBeenPwned API key not set!<br/>Go to <a href=\"https://haveibeenpwned.com/API/Key\" target=\"_blank\" rel=\"noreferrer\">https://haveibeenpwned.com/API/Key</a> to purchase an API key from HaveIBeenPwned.<br/><br/>", account=username), "Description": format!("Go to: <a href=\"https://haveibeenpwned.com/account/{account}\" target=\"_blank\" rel=\"noreferrer\">https://haveibeenpwned.com/account/{account}</a> for a manual check.<br/><br/>HaveIBeenPwned API key not set!<br/>Go to <a href=\"https://haveibeenpwned.com/API/Key\" target=\"_blank\" rel=\"noreferrer\">https://haveibeenpwned.com/API/Key</a> to purchase an API key from HaveIBeenPwned.<br/><br/>", account=username),
"LogoPath": "bwrs_static/hibp.png", "LogoPath": "vw_static/hibp.png",
"PwnCount": 0, "PwnCount": 0,
"DataClasses": [ "DataClasses": [
"Error - No API key set!" "Error - No API key set!"

View File

@@ -235,7 +235,7 @@ fn get_user_collections(headers: Headers, conn: DbConn) -> Json<Value> {
} }
#[get("/organizations/<org_id>/collections")] #[get("/organizations/<org_id>/collections")]
fn get_org_collections(org_id: String, _headers: AdminHeaders, conn: DbConn) -> Json<Value> { fn get_org_collections(org_id: String, _headers: ManagerHeadersLoose, conn: DbConn) -> Json<Value> {
Json(json!({ Json(json!({
"Data": "Data":
Collection::find_by_organization(&org_id, &conn) Collection::find_by_organization(&org_id, &conn)

View File

@@ -7,7 +7,7 @@ use rocket_contrib::json::Json;
use serde_json::Value; use serde_json::Value;
use crate::{ use crate::{
api::{ApiResult, EmptyResult, JsonResult, JsonUpcase, Notify, UpdateType}, api::{ApiResult, EmptyResult, JsonResult, JsonUpcase, Notify, NumberOrString, UpdateType},
auth::{Headers, Host}, auth::{Headers, Host},
db::{models::*, DbConn, DbPool}, db::{models::*, DbConn, DbPool},
util::SafeString, util::SafeString,
@@ -42,21 +42,21 @@ pub fn purge_sends(pool: DbPool) {
#[derive(Deserialize)] #[derive(Deserialize)]
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub struct SendData { struct SendData {
pub Type: i32, Type: i32,
pub Key: String, Key: String,
pub Password: Option<String>, Password: Option<String>,
pub MaxAccessCount: Option<i32>, MaxAccessCount: Option<NumberOrString>,
pub ExpirationDate: Option<DateTime<Utc>>, ExpirationDate: Option<DateTime<Utc>>,
pub DeletionDate: DateTime<Utc>, DeletionDate: DateTime<Utc>,
pub Disabled: bool, Disabled: bool,
pub HideEmail: Option<bool>, HideEmail: Option<bool>,
// Data field // Data field
pub Name: String, Name: String,
pub Notes: Option<String>, Notes: Option<String>,
pub Text: Option<Value>, Text: Option<Value>,
pub File: Option<Value>, File: Option<Value>,
} }
/// Enforces the `Disable Send` policy. A non-owner/admin user belonging to /// Enforces the `Disable Send` policy. A non-owner/admin user belonging to
@@ -119,7 +119,10 @@ fn create_send(data: SendData, user_uuid: String) -> ApiResult<Send> {
let mut send = Send::new(data.Type, data.Name, data_str, data.Key, data.DeletionDate.naive_utc()); let mut send = Send::new(data.Type, data.Name, data_str, data.Key, data.DeletionDate.naive_utc());
send.user_uuid = Some(user_uuid); send.user_uuid = Some(user_uuid);
send.notes = data.Notes; send.notes = data.Notes;
send.max_access_count = data.MaxAccessCount; send.max_access_count = match data.MaxAccessCount {
Some(m) => Some(m.into_i32()?),
_ => None,
};
send.expiration_date = data.ExpirationDate.map(|d| d.naive_utc()); send.expiration_date = data.ExpirationDate.map(|d| d.naive_utc());
send.disabled = data.Disabled; send.disabled = data.Disabled;
send.hide_email = data.HideEmail; send.hide_email = data.HideEmail;
@@ -414,7 +417,10 @@ fn put_send(id: String, data: JsonUpcase<SendData>, headers: Headers, conn: DbCo
send.akey = data.Key; send.akey = data.Key;
send.deletion_date = data.DeletionDate.naive_utc(); send.deletion_date = data.DeletionDate.naive_utc();
send.notes = data.Notes; send.notes = data.Notes;
send.max_access_count = data.MaxAccessCount; send.max_access_count = match data.MaxAccessCount {
Some(m) => Some(m.into_i32()?),
_ => None,
};
send.expiration_date = data.ExpirationDate.map(|d| d.naive_utc()); send.expiration_date = data.ExpirationDate.map(|d| d.naive_utc());
send.hide_email = data.HideEmail; send.hide_email = data.HideEmail;
send.disabled = data.Disabled; send.disabled = data.Disabled;

View File

@@ -58,7 +58,7 @@ pub fn send_token(user_uuid: &str, conn: &DbConn) -> EmptyResult {
let type_ = TwoFactorType::Email as i32; let type_ = TwoFactorType::Email as i32;
let mut twofactor = TwoFactor::find_by_user_and_type(user_uuid, type_, conn).map_res("Two factor not found")?; let mut twofactor = TwoFactor::find_by_user_and_type(user_uuid, type_, conn).map_res("Two factor not found")?;
let generated_token = crypto::generate_token(CONFIG.email_token_size())?; let generated_token = crypto::generate_email_token(CONFIG.email_token_size());
let mut twofactor_data = EmailTokenData::from_json(&twofactor.data)?; let mut twofactor_data = EmailTokenData::from_json(&twofactor.data)?;
twofactor_data.set_token(generated_token); twofactor_data.set_token(generated_token);
@@ -123,7 +123,7 @@ fn send_email(data: JsonUpcase<SendEmailData>, headers: Headers, conn: DbConn) -
tf.delete(&conn)?; tf.delete(&conn)?;
} }
let generated_token = crypto::generate_token(CONFIG.email_token_size())?; let generated_token = crypto::generate_email_token(CONFIG.email_token_size());
let twofactor_data = EmailTokenData::new(data.Email, generated_token); let twofactor_data = EmailTokenData::new(data.Email, generated_token);
// Uses EmailVerificationChallenge as type to show that it's not verified yet. // Uses EmailVerificationChallenge as type to show that it's not verified yet.
@@ -309,18 +309,4 @@ mod tests {
// If it's smaller than 3 characters it should only show asterisks. // If it's smaller than 3 characters it should only show asterisks.
assert_eq!(result, "***@example.ext"); assert_eq!(result, "***@example.ext");
} }
#[test]
fn test_token() {
let result = crypto::generate_token(19).unwrap();
assert_eq!(result.chars().count(), 19);
}
#[test]
fn test_token_too_large() {
let result = crypto::generate_token(20);
assert!(result.is_err(), "too large token should give an error");
}
} }

View File

@@ -10,7 +10,11 @@ use std::{
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use regex::Regex; use regex::Regex;
use reqwest::{blocking::Client, blocking::Response, header}; use reqwest::{blocking::Client, blocking::Response, header};
use rocket::{http::ContentType, response::Content, Route}; use rocket::{
http::ContentType,
response::{Content, Redirect},
Route,
};
use crate::{ use crate::{
error::Error, error::Error,
@@ -19,7 +23,13 @@ use crate::{
}; };
pub fn routes() -> Vec<Route> { pub fn routes() -> Vec<Route> {
routes![icon] match CONFIG.icon_service().as_str() {
"internal" => routes![icon_internal],
"bitwarden" => routes![icon_bitwarden],
"duckduckgo" => routes![icon_duckduckgo],
"google" => routes![icon_google],
_ => routes![icon_custom],
}
} }
static CLIENT: Lazy<Client> = Lazy::new(|| { static CLIENT: Lazy<Client> = Lazy::new(|| {
@@ -50,8 +60,51 @@ static ICON_SIZE_REGEX: Lazy<Regex> = Lazy::new(|| Regex::new(r"(?x)(\d+)\D*(\d+
// Special HashMap which holds the user defined Regex to speedup matching the regex. // 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())); static ICON_BLACKLIST_REGEX: Lazy<RwLock<HashMap<String, Regex>>> = Lazy::new(|| RwLock::new(HashMap::new()));
fn icon_redirect(domain: &str, template: &str) -> Option<Redirect> {
if !is_valid_domain(domain) {
warn!("Invalid domain: {}", domain);
return None;
}
if is_domain_blacklisted(domain) {
return None;
}
let url = template.replace("{}", domain);
match CONFIG.icon_redirect_code() {
301 => Some(Redirect::moved(url)), // legacy permanent redirect
302 => Some(Redirect::found(url)), // legacy temporary redirect
307 => Some(Redirect::temporary(url)),
308 => Some(Redirect::permanent(url)),
_ => {
error!("Unexpected redirect code {}", CONFIG.icon_redirect_code());
None
}
}
}
#[get("/<domain>/icon.png")] #[get("/<domain>/icon.png")]
fn icon(domain: String) -> Cached<Content<Vec<u8>>> { fn icon_custom(domain: String) -> Option<Redirect> {
icon_redirect(&domain, &CONFIG.icon_service())
}
#[get("/<domain>/icon.png")]
fn icon_bitwarden(domain: String) -> Option<Redirect> {
icon_redirect(&domain, "https://icons.bitwarden.net/{}/icon.png")
}
#[get("/<domain>/icon.png")]
fn icon_duckduckgo(domain: String) -> Option<Redirect> {
icon_redirect(&domain, "https://icons.duckduckgo.com/ip3/{}.ico")
}
#[get("/<domain>/icon.png")]
fn icon_google(domain: String) -> Option<Redirect> {
icon_redirect(&domain, "https://www.google.com/s2/favicons?domain={}&sz=32")
}
#[get("/<domain>/icon.png")]
fn icon_internal(domain: String) -> Cached<Content<Vec<u8>>> {
const FALLBACK_ICON: &[u8] = include_bytes!("../static/images/fallback-icon.png"); const FALLBACK_ICON: &[u8] = include_bytes!("../static/images/fallback-icon.png");
if !is_valid_domain(&domain) { if !is_valid_domain(&domain) {
@@ -59,14 +112,19 @@ fn icon(domain: String) -> Cached<Content<Vec<u8>>> {
return Cached::ttl( return Cached::ttl(
Content(ContentType::new("image", "png"), FALLBACK_ICON.to_vec()), Content(ContentType::new("image", "png"), FALLBACK_ICON.to_vec()),
CONFIG.icon_cache_negttl(), CONFIG.icon_cache_negttl(),
true,
); );
} }
match get_icon(&domain) { match get_icon(&domain) {
Some((icon, icon_type)) => { Some((icon, icon_type)) => {
Cached::ttl(Content(ContentType::new("image", icon_type), icon), CONFIG.icon_cache_ttl()) Cached::ttl(Content(ContentType::new("image", icon_type), icon), CONFIG.icon_cache_ttl(), true)
} }
_ => Cached::ttl(Content(ContentType::new("image", "png"), FALLBACK_ICON.to_vec()), CONFIG.icon_cache_negttl()), _ => Cached::ttl(
Content(ContentType::new("image", "png"), FALLBACK_ICON.to_vec()),
CONFIG.icon_cache_negttl(),
true,
),
} }
} }
@@ -250,7 +308,7 @@ fn is_domain_blacklisted(domain: &str) -> bool {
// Use the pre-generate Regex stored in a Lazy HashMap. // Use the pre-generate Regex stored in a Lazy HashMap.
if regex.is_match(domain) { if regex.is_match(domain) {
warn!("Blacklisted domain: {} matched ICON_BLACKLIST_REGEX", domain); debug!("Blacklisted domain: {} matched ICON_BLACKLIST_REGEX", domain);
is_blacklisted = true; is_blacklisted = true;
} }
} }
@@ -286,7 +344,7 @@ fn get_icon(domain: &str) -> Option<(Vec<u8>, String)> {
Some((icon, icon_type.unwrap_or("x-icon").to_string())) Some((icon, icon_type.unwrap_or("x-icon").to_string()))
} }
Err(e) => { Err(e) => {
error!("Error downloading icon: {:?}", e); warn!("Unable to download icon: {:?}", e);
let miss_indicator = path + ".miss"; let miss_indicator = path + ".miss";
save_icon(&miss_indicator, &[]); save_icon(&miss_indicator, &[]);
None None
@@ -555,7 +613,7 @@ fn get_page(url: &str) -> Result<Response, Error> {
fn get_page_with_referer(url: &str, referer: &str) -> Result<Response, Error> { fn get_page_with_referer(url: &str, referer: &str) -> Result<Response, Error> {
if is_domain_blacklisted(url::Url::parse(url).unwrap().host_str().unwrap_or_default()) { if is_domain_blacklisted(url::Url::parse(url).unwrap().host_str().unwrap_or_default()) {
err!("Favicon resolves to a blacklisted domain or IP!", url); warn!("Favicon '{}' resolves to a blacklisted domain or IP!", url);
} }
let mut client = CLIENT.get(url); let mut client = CLIENT.get(url);
@@ -713,10 +771,10 @@ fn save_icon(path: &str, icon: &[u8]) {
f.write_all(icon).expect("Error writing icon file"); f.write_all(icon).expect("Error writing icon file");
} }
Err(ref e) if e.kind() == std::io::ErrorKind::NotFound => { Err(ref e) if e.kind() == std::io::ErrorKind::NotFound => {
create_dir_all(&CONFIG.icon_cache_folder()).expect("Error creating icon cache"); create_dir_all(&CONFIG.icon_cache_folder()).expect("Error creating icon cache folder");
} }
Err(e) => { Err(e) => {
warn!("Icon save error: {:?}", e); warn!("Unable to save icon: {:?}", e);
} }
} }
} }

View File

@@ -43,6 +43,13 @@ fn login(data: Form<ConnectData>, conn: DbConn, ip: ClientIp) -> JsonResult {
_password_login(data, conn, &ip) _password_login(data, conn, &ip)
} }
"client_credentials" => {
_check_is_some(&data.client_id, "client_id cannot be blank")?;
_check_is_some(&data.client_secret, "client_secret cannot be blank")?;
_check_is_some(&data.scope, "scope cannot be blank")?;
_api_key_login(data, conn, &ip)
}
t => err!("Invalid type", t), t => err!("Invalid type", t),
} }
} }
@@ -54,13 +61,15 @@ fn _refresh_login(data: ConnectData, conn: DbConn) -> JsonResult {
// Get device by refresh token // Get device by refresh token
let mut device = Device::find_by_refresh_token(&token, &conn).map_res("Invalid refresh token")?; let mut device = Device::find_by_refresh_token(&token, &conn).map_res("Invalid refresh token")?;
// COMMON let scope = "api offline_access";
let scope_vec = vec!["api".into(), "offline_access".into()];
// Common
let user = User::find_by_uuid(&device.user_uuid, &conn).unwrap(); let user = User::find_by_uuid(&device.user_uuid, &conn).unwrap();
let orgs = UserOrganization::find_confirmed_by_user(&user.uuid, &conn); let orgs = UserOrganization::find_confirmed_by_user(&user.uuid, &conn);
let (access_token, expires_in) = device.refresh_tokens(&user, orgs, scope_vec);
let (access_token, expires_in) = device.refresh_tokens(&user, orgs);
device.save(&conn)?; device.save(&conn)?;
Ok(Json(json!({ Ok(Json(json!({
"access_token": access_token, "access_token": access_token,
"expires_in": expires_in, "expires_in": expires_in,
@@ -72,7 +81,7 @@ fn _refresh_login(data: ConnectData, conn: DbConn) -> JsonResult {
"Kdf": user.client_kdf_type, "Kdf": user.client_kdf_type,
"KdfIterations": user.client_kdf_iter, "KdfIterations": user.client_kdf_iter,
"ResetMasterPassword": false, // TODO: according to official server seems something like: user.password_hash.is_empty(), but would need testing "ResetMasterPassword": false, // TODO: according to official server seems something like: user.password_hash.is_empty(), but would need testing
"scope": "api offline_access", "scope": scope,
"unofficialServer": true, "unofficialServer": true,
}))) })))
} }
@@ -83,6 +92,10 @@ fn _password_login(data: ConnectData, conn: DbConn, ip: &ClientIp) -> JsonResult
if scope != "api offline_access" { if scope != "api offline_access" {
err!("Scope not supported") err!("Scope not supported")
} }
let scope_vec = vec!["api".into(), "offline_access".into()];
// Ratelimit the login
crate::ratelimit::check_limit_login(&ip.ip)?;
// Get the user // Get the user
let username = data.username.as_ref().unwrap(); let username = data.username.as_ref().unwrap();
@@ -147,8 +160,7 @@ fn _password_login(data: ConnectData, conn: DbConn, ip: &ClientIp) -> JsonResult
// Common // Common
let orgs = UserOrganization::find_confirmed_by_user(&user.uuid, &conn); let orgs = UserOrganization::find_confirmed_by_user(&user.uuid, &conn);
let (access_token, expires_in) = device.refresh_tokens(&user, orgs, scope_vec);
let (access_token, expires_in) = device.refresh_tokens(&user, orgs);
device.save(&conn)?; device.save(&conn)?;
let mut result = json!({ let mut result = json!({
@@ -163,7 +175,7 @@ fn _password_login(data: ConnectData, conn: DbConn, ip: &ClientIp) -> JsonResult
"Kdf": user.client_kdf_type, "Kdf": user.client_kdf_type,
"KdfIterations": user.client_kdf_iter, "KdfIterations": user.client_kdf_iter,
"ResetMasterPassword": false,// TODO: Same as above "ResetMasterPassword": false,// TODO: Same as above
"scope": "api offline_access", "scope": scope,
"unofficialServer": true, "unofficialServer": true,
}); });
@@ -175,6 +187,76 @@ fn _password_login(data: ConnectData, conn: DbConn, ip: &ClientIp) -> JsonResult
Ok(Json(result)) Ok(Json(result))
} }
fn _api_key_login(data: ConnectData, conn: DbConn, ip: &ClientIp) -> JsonResult {
// Validate scope
let scope = data.scope.as_ref().unwrap();
if scope != "api" {
err!("Scope not supported")
}
let scope_vec = vec!["api".into()];
// Ratelimit the login
crate::ratelimit::check_limit_login(&ip.ip)?;
// Get the user via the client_id
let client_id = data.client_id.as_ref().unwrap();
let user_uuid = match client_id.strip_prefix("user.") {
Some(uuid) => uuid,
None => err!("Malformed client_id", format!("IP: {}.", ip.ip)),
};
let user = match User::find_by_uuid(user_uuid, &conn) {
Some(user) => user,
None => err!("Invalid client_id", format!("IP: {}.", ip.ip)),
};
// Check if the user is disabled
if !user.enabled {
err!("This user has been disabled (API key login)", format!("IP: {}. Username: {}.", ip.ip, user.email))
}
// Check API key. Note that API key logins bypass 2FA.
let client_secret = data.client_secret.as_ref().unwrap();
if !user.check_valid_api_key(client_secret) {
err!("Incorrect client_secret", format!("IP: {}. Username: {}.", ip.ip, user.email))
}
let (mut device, new_device) = get_device(&data, &conn, &user);
if CONFIG.mail_enabled() && new_device {
let now = Utc::now().naive_utc();
if let Err(e) = mail::send_new_device_logged_in(&user.email, &ip.ip.to_string(), &now, &device.name) {
error!("Error sending new device email: {:#?}", e);
if CONFIG.require_device_email() {
err!("Could not send login notification email. Please contact your administrator.")
}
}
}
// Common
let orgs = UserOrganization::find_confirmed_by_user(&user.uuid, &conn);
let (access_token, expires_in) = device.refresh_tokens(&user, orgs, scope_vec);
device.save(&conn)?;
info!("User {} logged in successfully via API key. IP: {}", user.email, ip.ip);
// Note: No refresh_token is returned. The CLI just repeats the
// client_credentials login flow when the existing token expires.
Ok(Json(json!({
"access_token": access_token,
"expires_in": expires_in,
"token_type": "Bearer",
"Key": user.akey,
"PrivateKey": user.private_key,
"Kdf": user.client_kdf_type,
"KdfIterations": user.client_kdf_iter,
"ResetMasterPassword": false, // TODO: Same as above
"scope": scope,
"unofficialServer": true,
})))
}
/// Retrieves an existing device or creates a new device from ConnectData and the User /// Retrieves an existing device or creates a new device from ConnectData and the User
fn get_device(data: &ConnectData, conn: &DbConn, user: &User) -> (Device, bool) { fn get_device(data: &ConnectData, conn: &DbConn, user: &User) -> (Device, bool) {
// On iOS, device_type sends "iOS", on others it sends a number // On iOS, device_type sends "iOS", on others it sends a number
@@ -371,17 +453,20 @@ fn _json_err_twofactor(providers: &[i32], user_uuid: &str, conn: &DbConn) -> Api
Ok(result) Ok(result)
} }
// https://github.com/bitwarden/jslib/blob/master/common/src/models/request/tokenRequest.ts
// https://github.com/bitwarden/mobile/blob/master/src/Core/Models/Request/TokenRequest.cs // https://github.com/bitwarden/mobile/blob/master/src/Core/Models/Request/TokenRequest.cs
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
#[allow(non_snake_case)] #[allow(non_snake_case)]
struct ConnectData { struct ConnectData {
grant_type: String, // refresh_token, password // refresh_token, password, client_credentials (API key)
grant_type: String,
// Needed for grant_type="refresh_token" // Needed for grant_type="refresh_token"
refresh_token: Option<String>, refresh_token: Option<String>,
// Needed for grant_type="password" // Needed for grant_type = "password" | "client_credentials"
client_id: Option<String>, // web, cli, desktop, browser, mobile client_id: Option<String>, // web, cli, desktop, browser, mobile
client_secret: Option<String>, // API key login (cli only)
password: Option<String>, password: Option<String>,
scope: Option<String>, scope: Option<String>,
username: Option<String>, username: Option<String>,
@@ -411,6 +496,7 @@ impl<'f> FromForm<'f> for ConnectData {
"granttype" => form.grant_type = value, "granttype" => form.grant_type = value,
"refreshtoken" => form.refresh_token = Some(value), "refreshtoken" => form.refresh_token = Some(value),
"clientid" => form.client_id = Some(value), "clientid" => form.client_id = Some(value),
"clientsecret" => form.client_secret = Some(value),
"password" => form.password = Some(value), "password" => form.password = Some(value),
"scope" => form.scope = Some(value), "scope" => form.scope = Some(value),
"username" => form.username = Some(value), "username" => form.username = Some(value),

View File

@@ -22,14 +22,15 @@ pub fn routes() -> Vec<Route> {
#[get("/")] #[get("/")]
fn web_index() -> Cached<Option<NamedFile>> { fn web_index() -> Cached<Option<NamedFile>> {
Cached::short(NamedFile::open(Path::new(&CONFIG.web_vault_folder()).join("index.html")).ok()) Cached::short(NamedFile::open(Path::new(&CONFIG.web_vault_folder()).join("index.html")).ok(), false)
} }
#[get("/app-id.json")] #[get("/app-id.json")]
fn app_id() -> Cached<Content<Json<Value>>> { fn app_id() -> Cached<Content<Json<Value>>> {
let content_type = ContentType::new("application", "fido.trusted-apps+json"); let content_type = ContentType::new("application", "fido.trusted-apps+json");
Cached::long(Content( Cached::long(
Content(
content_type, content_type,
Json(json!({ Json(json!({
"trustedFacets": [ "trustedFacets": [
@@ -51,12 +52,14 @@ fn app_id() -> Cached<Content<Json<Value>>> {
"android:apk-key-hash:dUGFzUzf3lmHSLBDBIv+WaFyZMI" ] "android:apk-key-hash:dUGFzUzf3lmHSLBDBIv+WaFyZMI" ]
}] }]
})), })),
)) ),
true,
)
} }
#[get("/<p..>", rank = 10)] // Only match this if the other routes don't match #[get("/<p..>", rank = 10)] // Only match this if the other routes don't match
fn web_files(p: PathBuf) -> Cached<Option<NamedFile>> { fn web_files(p: PathBuf) -> Cached<Option<NamedFile>> {
Cached::long(NamedFile::open(Path::new(&CONFIG.web_vault_folder()).join(p)).ok()) Cached::long(NamedFile::open(Path::new(&CONFIG.web_vault_folder()).join(p)).ok(), true)
} }
#[get("/attachments/<uuid>/<file_id>")] #[get("/attachments/<uuid>/<file_id>")]
@@ -74,7 +77,7 @@ fn alive(_conn: DbConn) -> Json<String> {
Json(format_date(&Utc::now().naive_utc())) Json(format_date(&Utc::now().naive_utc()))
} }
#[get("/bwrs_static/<filename>")] #[get("/vw_static/<filename>")]
fn static_files(filename: String) -> Result<Content<&'static [u8]>, Error> { fn static_files(filename: String) -> Result<Content<&'static [u8]>, Error> {
match filename.as_ref() { match filename.as_ref() {
"mail-github.png" => Ok(Content(ContentType::PNG, include_bytes!("../static/images/mail-github.png"))), "mail-github.png" => Ok(Content(ContentType::PNG, include_bytes!("../static/images/mail-github.png"))),

View File

@@ -406,9 +406,10 @@ make_config! {
/// This setting applies globally to all users. /// This setting applies globally to all users.
incomplete_2fa_time_limit: i64, true, def, 3; incomplete_2fa_time_limit: i64, true, def, 3;
/// Disable icon downloads |> Set to true to disable icon downloading, this would still serve icons from /// Disable icon downloads |> Set to true to disable icon downloading in the internal icon service.
/// $ICON_CACHE_FOLDER, but it won't produce any external network request. Needs to set $ICON_CACHE_TTL to 0, /// This still serves existing icons from $ICON_CACHE_FOLDER, without generating any external
/// otherwise it will delete them and they won't be downloaded again. /// network requests. $ICON_CACHE_TTL must also be set to 0; otherwise, the existing icons
/// will be deleted eventually, but won't be downloaded again.
disable_icon_download: bool, true, def, false; disable_icon_download: bool, true, def, false;
/// Allow new signups |> Controls whether new users can register. Users can be invited by the vaultwarden 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; signups_allowed: bool, true, def, true;
@@ -449,6 +450,19 @@ make_config! {
ip_header: String, true, def, "X-Real-IP".to_string(); ip_header: String, true, def, "X-Real-IP".to_string();
/// Internal IP header property, used to avoid recomputing each time /// Internal IP header property, used to avoid recomputing each time
_ip_header_enabled: bool, false, gen, |c| &c.ip_header.trim().to_lowercase() != "none"; _ip_header_enabled: bool, false, gen, |c| &c.ip_header.trim().to_lowercase() != "none";
/// Icon service |> The predefined icon services are: internal, bitwarden, duckduckgo, google.
/// To specify a custom icon service, set a URL template with exactly one instance of `{}`,
/// which is replaced with the domain. For example: `https://icon.example.com/domain/{}`.
/// `internal` refers to Vaultwarden's built-in icon fetching implementation. If an external
/// service is set, an icon request to Vaultwarden will return an HTTP redirect to the
/// corresponding icon at the external service.
icon_service: String, false, def, "internal".to_string();
/// Icon redirect code |> The HTTP status code to use for redirects to an external icon service.
/// The supported codes are 301 (legacy permanent), 302 (legacy temporary), 307 (temporary), and 308 (permanent).
/// Temporary redirects are useful while testing different icon services, but once a service
/// has been decided on, consider using permanent redirects for cacheability. The legacy codes
/// are currently better supported by the Bitwarden clients.
icon_redirect_code: u32, true, def, 302;
/// Positive icon cache expiry |> Number of seconds to consider that an already cached icon is fresh. After this period, the icon will be redownloaded /// Positive icon cache expiry |> Number of seconds to consider that an already cached icon is fresh. After this period, the icon will be redownloaded
icon_cache_ttl: u64, true, def, 2_592_000; icon_cache_ttl: u64, true, def, 2_592_000;
/// Negative icon cache expiry |> Number of seconds before trying to download an icon that failed again. /// Negative icon cache expiry |> Number of seconds before trying to download an icon that failed again.
@@ -503,6 +517,16 @@ make_config! {
/// Allowed iframe ancestors (Know the risks!) |> Allows other domains to embed the web vault into an iframe, useful for embedding into secure intranets /// Allowed iframe ancestors (Know the risks!) |> Allows other domains to embed the web vault into an iframe, useful for embedding into secure intranets
allowed_iframe_ancestors: String, true, def, String::new(); allowed_iframe_ancestors: String, true, def, String::new();
/// Seconds between login requests |> Number of seconds, on average, between login and 2FA requests from the same IP address before rate limiting kicks in
login_ratelimit_seconds: u64, false, def, 60;
/// Max burst size for login requests |> Allow a burst of requests of up to this size, while maintaining the average indicated by `login_ratelimit_seconds`. Note that this applies to both the login and the 2FA, so it's recommended to allow a burst size of at least 2
login_ratelimit_max_burst: u32, false, def, 10;
/// Seconds between admin requests |> Number of seconds, on average, between admin requests from the same IP address before rate limiting kicks in
admin_ratelimit_seconds: u64, false, def, 300;
/// Max burst size for login requests |> Allow a burst of requests of up to this size, while maintaining the average indicated by `admin_ratelimit_seconds`
admin_ratelimit_max_burst: u32, false, def, 3;
}, },
/// Yubikey settings /// Yubikey settings
@@ -569,8 +593,8 @@ make_config! {
email_2fa: _enable_email_2fa { email_2fa: _enable_email_2fa {
/// Enabled |> Disabling will prevent users from setting up new email 2FA and using existing email 2FA configured /// Enabled |> Disabling will prevent users from setting up new email 2FA and using existing email 2FA configured
_enable_email_2fa: bool, true, auto, |c| c._enable_smtp && c.smtp_host.is_some(); _enable_email_2fa: bool, true, auto, |c| c._enable_smtp && c.smtp_host.is_some();
/// Email token size |> Number of digits in an email token (min: 6, max: 19). Note that the Bitwarden clients are hardcoded to mention 6 digit codes regardless of this setting. /// Email token size |> Number of digits in an email 2FA token (min: 6, max: 255). Note that the Bitwarden clients are hardcoded to mention 6 digit codes regardless of this setting.
email_token_size: u32, true, def, 6; email_token_size: u8, true, def, 6;
/// Token expiration time |> Maximum time in seconds a token is valid. The time the user has to open email client and copy token. /// Token expiration time |> Maximum time in seconds a token is valid. The time the user has to open email client and copy token.
email_expiration_time: u64, true, def, 600; email_expiration_time: u64, true, def, 600;
/// Maximum attempts |> Maximum attempts before an email token is reset and a new email will need to be sent /// Maximum attempts |> Maximum attempts before an email token is reset and a new email will need to be sent
@@ -644,10 +668,6 @@ fn validate_config(cfg: &ConfigItems) -> Result<(), Error> {
if cfg._enable_email_2fa && cfg.email_token_size < 6 { if cfg._enable_email_2fa && cfg.email_token_size < 6 {
err!("`EMAIL_TOKEN_SIZE` has a minimum size of 6") err!("`EMAIL_TOKEN_SIZE` has a minimum size of 6")
} }
if cfg._enable_email_2fa && cfg.email_token_size > 19 {
err!("`EMAIL_TOKEN_SIZE` has a maximum size of 19")
}
} }
// Check if the icon blacklist regex is valid // Check if the icon blacklist regex is valid
@@ -659,6 +679,28 @@ fn validate_config(cfg: &ConfigItems) -> Result<(), Error> {
} }
} }
// Check if the icon service is valid
let icon_service = cfg.icon_service.as_str();
match icon_service {
"internal" | "bitwarden" | "duckduckgo" | "google" => (),
_ => {
if !icon_service.starts_with("http") {
err!(format!("Icon service URL `{}` must start with \"http\"", icon_service))
}
match icon_service.matches("{}").count() {
1 => (), // nominal
0 => err!(format!("Icon service URL `{}` has no placeholder \"{{}}\"", icon_service)),
_ => err!(format!("Icon service URL `{}` has more than one placeholder \"{{}}\"", icon_service)),
}
}
}
// Check if the icon redirect code is valid
match cfg.icon_redirect_code {
301 | 302 | 307 | 308 => (),
_ => err!("Only HTTP 301/302 and 307/308 redirects are supported"),
}
Ok(()) Ok(())
} }

View File

@@ -6,8 +6,6 @@ use std::num::NonZeroU32;
use data_encoding::HEXLOWER; use data_encoding::HEXLOWER;
use ring::{digest, hmac, pbkdf2}; use ring::{digest, hmac, pbkdf2};
use crate::error::Error;
static DIGEST_ALG: pbkdf2::Algorithm = pbkdf2::PBKDF2_HMAC_SHA256; static DIGEST_ALG: pbkdf2::Algorithm = pbkdf2::PBKDF2_HMAC_SHA256;
const OUTPUT_LEN: usize = digest::SHA256_OUTPUT_LEN; const OUTPUT_LEN: usize = digest::SHA256_OUTPUT_LEN;
@@ -51,6 +49,34 @@ pub fn get_random(mut array: Vec<u8>) -> Vec<u8> {
array array
} }
/// Generates a random string over a specified alphabet.
pub fn get_random_string(alphabet: &[u8], num_chars: usize) -> String {
// Ref: https://rust-lang-nursery.github.io/rust-cookbook/algorithms/randomness.html
use rand::Rng;
let mut rng = rand::thread_rng();
(0..num_chars)
.map(|_| {
let i = rng.gen_range(0..alphabet.len());
alphabet[i] as char
})
.collect()
}
/// Generates a random numeric string.
pub fn get_random_string_numeric(num_chars: usize) -> String {
const ALPHABET: &[u8] = b"0123456789";
get_random_string(ALPHABET, num_chars)
}
/// Generates a random alphanumeric string.
pub fn get_random_string_alphanum(num_chars: usize) -> String {
const ALPHABET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
abcdefghijklmnopqrstuvwxyz\
0123456789";
get_random_string(ALPHABET, num_chars)
}
pub fn generate_id(num_bytes: usize) -> String { pub fn generate_id(num_bytes: usize) -> String {
HEXLOWER.encode(&get_random(vec![0; num_bytes])) HEXLOWER.encode(&get_random(vec![0; num_bytes]))
} }
@@ -65,23 +91,15 @@ pub fn generate_attachment_id() -> String {
generate_id(10) // 80 bits generate_id(10) // 80 bits
} }
pub fn generate_token(token_size: u32) -> Result<String, Error> { /// Generates a numeric token for email-based verifications.
// A u64 can represent all whole numbers up to 19 digits long. pub fn generate_email_token(token_size: u8) -> String {
if token_size > 19 { get_random_string_numeric(token_size as usize)
err!("Token size is limited to 19 digits") }
}
let low: u64 = 0; /// Generates a personal API key.
let high: u64 = 10u64.pow(token_size); /// Upstream uses 30 chars, which is ~178 bits of entropy.
pub fn generate_api_key() -> String {
// Generate a random number in the range [low, high), then format it as a get_random_string_alphanum(30)
// token of fixed width, left-padding with 0 as needed.
use rand::{thread_rng, Rng};
let mut rng = thread_rng();
let number: u64 = rng.gen_range(low..high);
let token = format!("{:0size$}", number, size = token_size as usize);
Ok(token)
} }
// //

View File

@@ -60,7 +60,12 @@ impl Device {
self.twofactor_remember = None; self.twofactor_remember = None;
} }
pub fn refresh_tokens(&mut self, user: &super::User, orgs: Vec<super::UserOrganization>) -> (String, i64) { pub fn refresh_tokens(
&mut self,
user: &super::User,
orgs: Vec<super::UserOrganization>,
scope: Vec<String>,
) -> (String, i64) {
// If there is no refresh token, we create one // If there is no refresh token, we create one
if self.refresh_token.is_empty() { if self.refresh_token.is_empty() {
use crate::crypto; use crate::crypto;
@@ -98,7 +103,7 @@ impl Device {
sstamp: user.security_stamp.to_string(), sstamp: user.security_stamp.to_string(),
device: self.uuid.to_string(), device: self.uuid.to_string(),
scope: vec!["api".into(), "offline_access".into()], scope,
amr: vec!["Application".into()], amr: vec!["Application".into()],
}; };

View File

@@ -44,8 +44,9 @@ db_object! {
pub client_kdf_type: i32, pub client_kdf_type: i32,
pub client_kdf_iter: i32, pub client_kdf_iter: i32,
}
pub api_key: Option<String>,
}
#[derive(Identifiable, Queryable, Insertable)] #[derive(Identifiable, Queryable, Insertable)]
#[table_name = "invitations"] #[table_name = "invitations"]
@@ -110,6 +111,8 @@ impl User {
client_kdf_type: Self::CLIENT_KDF_TYPE_DEFAULT, client_kdf_type: Self::CLIENT_KDF_TYPE_DEFAULT,
client_kdf_iter: Self::CLIENT_KDF_ITER_DEFAULT, client_kdf_iter: Self::CLIENT_KDF_ITER_DEFAULT,
api_key: None,
} }
} }
@@ -130,6 +133,10 @@ impl User {
} }
} }
pub fn check_valid_api_key(&self, key: &str) -> bool {
matches!(self.api_key, Some(ref api_key) if crate::crypto::ct_eq(api_key, key))
}
/// Set the password hash generated /// Set the password hash generated
/// And resets the security_stamp. Based upon the allow_next_route the security_stamp will be different. /// And resets the security_stamp. Based upon the allow_next_route the security_stamp will be different.
/// ///

View File

@@ -178,6 +178,7 @@ table! {
excluded_globals -> Text, excluded_globals -> Text,
client_kdf_type -> Integer, client_kdf_type -> Integer,
client_kdf_iter -> Integer, client_kdf_iter -> Integer,
api_key -> Nullable<Text>,
} }
} }

View File

@@ -178,6 +178,7 @@ table! {
excluded_globals -> Text, excluded_globals -> Text,
client_kdf_type -> Integer, client_kdf_type -> Integer,
client_kdf_iter -> Integer, client_kdf_iter -> Integer,
api_key -> Nullable<Text>,
} }
} }

View File

@@ -178,6 +178,7 @@ table! {
excluded_globals -> Text, excluded_globals -> Text,
client_kdf_type -> Integer, client_kdf_type -> Integer,
client_kdf_iter -> Integer, client_kdf_iter -> Integer,
api_key -> Nullable<Text>,
} }
} }

View File

@@ -119,11 +119,13 @@ impl Error {
Empty {}.into() Empty {}.into()
} }
#[must_use]
pub fn with_msg<M: Into<String>>(mut self, msg: M) -> Self { pub fn with_msg<M: Into<String>>(mut self, msg: M) -> Self {
self.message = msg.into(); self.message = msg.into();
self self
} }
#[must_use]
pub const fn with_code(mut self, code: u16) -> Self { pub const fn with_code(mut self, code: u16) -> Self {
self.error_code = code; self.error_code = code;
self self

View File

@@ -32,6 +32,7 @@ mod crypto;
#[macro_use] #[macro_use]
mod db; mod db;
mod mail; mod mail;
mod ratelimit;
mod util; mod util;
pub use config::CONFIG; pub use config::CONFIG;
@@ -75,16 +76,18 @@ const HELP: &str = "\
-v, --version Prints the app version -v, --version Prints the app version
"; ";
pub const VERSION: Option<&str> = option_env!("VW_VERSION");
fn parse_args() { fn parse_args() {
const NO_VERSION: &str = "(Version info from Git not present)";
let mut pargs = pico_args::Arguments::from_env(); let mut pargs = pico_args::Arguments::from_env();
let version = VERSION.unwrap_or("(Version info from Git not present)");
if pargs.contains(["-h", "--help"]) { if pargs.contains(["-h", "--help"]) {
println!("vaultwarden {}", option_env!("BWRS_VERSION").unwrap_or(NO_VERSION)); println!("vaultwarden {}", version);
print!("{}", HELP); print!("{}", HELP);
exit(0); exit(0);
} else if pargs.contains(["-v", "--version"]) { } else if pargs.contains(["-v", "--version"]) {
println!("vaultwarden {}", option_env!("BWRS_VERSION").unwrap_or(NO_VERSION)); println!("vaultwarden {}", version);
exit(0); exit(0);
} }
} }
@@ -93,7 +96,7 @@ fn launch_info() {
println!("/--------------------------------------------------------------------\\"); println!("/--------------------------------------------------------------------\\");
println!("| Starting Vaultwarden |"); println!("| Starting Vaultwarden |");
if let Some(version) = option_env!("BWRS_VERSION") { if let Some(version) = VERSION {
println!("|{:^68}|", format!("Version {}", version)); println!("|{:^68}|", format!("Version {}", version));
} }

38
src/ratelimit.rs Normal file
View File

@@ -0,0 +1,38 @@
use once_cell::sync::Lazy;
use std::{net::IpAddr, num::NonZeroU32, time::Duration};
use governor::{clock::DefaultClock, state::keyed::DashMapStateStore, Quota, RateLimiter};
use crate::{Error, CONFIG};
type Limiter<T = IpAddr> = RateLimiter<T, DashMapStateStore<T>, DefaultClock>;
static LIMITER_LOGIN: Lazy<Limiter> = Lazy::new(|| {
let seconds = Duration::from_secs(CONFIG.login_ratelimit_seconds());
let burst = NonZeroU32::new(CONFIG.login_ratelimit_max_burst()).expect("Non-zero login ratelimit burst");
RateLimiter::keyed(Quota::with_period(seconds).expect("Non-zero login ratelimit seconds").allow_burst(burst))
});
static LIMITER_ADMIN: Lazy<Limiter> = Lazy::new(|| {
let seconds = Duration::from_secs(CONFIG.admin_ratelimit_seconds());
let burst = NonZeroU32::new(CONFIG.admin_ratelimit_max_burst()).expect("Non-zero admin ratelimit burst");
RateLimiter::keyed(Quota::with_period(seconds).expect("Non-zero admin ratelimit seconds").allow_burst(burst))
});
pub fn check_limit_login(ip: &IpAddr) -> Result<(), Error> {
match LIMITER_LOGIN.check_key(ip) {
Ok(_) => Ok(()),
Err(_e) => {
err_code!("Too many login requests", 429);
}
}
}
pub fn check_limit_admin(ip: &IpAddr) -> Result<(), Error> {
match LIMITER_ADMIN.check_key(ip) {
Ok(_) => Ok(()),
Err(_e) => {
err_code!("Too many admin requests", 429);
}
}
}

View File

@@ -47,7 +47,8 @@
"Type": 5, "Type": 5,
"Domains": [ "Domains": [
"wellsfargo.com", "wellsfargo.com",
"wf.com" "wf.com",
"wellsfargoadvisors.com"
], ],
"Excluded": false "Excluded": false
}, },
@@ -905,5 +906,21 @@
"protonvpn.com" "protonvpn.com"
], ],
"Excluded": false "Excluded": false
},
{
"Type": 86,
"Domains": [
"ubisoft.com",
"ubi.com"
],
"Excluded": false
},
{
"Type": 87,
"Domains": [
"transferwise.com",
"wise.com"
],
"Excluded": false
} }
] ]

View File

@@ -4,9 +4,9 @@
<meta http-equiv="content-type" content="text/html; charset=UTF-8" /> <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" /> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<meta name="robots" content="noindex,nofollow" /> <meta name="robots" content="noindex,nofollow" />
<link rel="icon" type="image/png" href="{{urlpath}}/bwrs_static/vaultwarden-icon.png"> <link rel="icon" type="image/png" href="{{urlpath}}/vw_static/vaultwarden-icon.png">
<title>Vaultwarden Admin Panel</title> <title>Vaultwarden Admin Panel</title>
<link rel="stylesheet" href="{{urlpath}}/bwrs_static/bootstrap.css" /> <link rel="stylesheet" href="{{urlpath}}/vw_static/bootstrap.css" />
<style> <style>
body { body {
padding-top: 75px; padding-top: 75px;
@@ -21,7 +21,7 @@
margin: -5px 0 0 0; margin: -5px 0 0 0;
} }
</style> </style>
<script src="{{urlpath}}/bwrs_static/identicon.js"></script> <script src="{{urlpath}}/vw_static/identicon.js"></script>
<script> <script>
'use strict'; 'use strict';
@@ -85,7 +85,7 @@
<body class="bg-light"> <body class="bg-light">
<nav class="navbar navbar-expand-md navbar-dark bg-dark mb-4 shadow fixed-top"> <nav class="navbar navbar-expand-md navbar-dark bg-dark mb-4 shadow fixed-top">
<div class="container-xl"> <div class="container-xl">
<a class="navbar-brand" href="{{urlpath}}/admin"><img class="vaultwarden-icon" src="{{urlpath}}/bwrs_static/vaultwarden-icon.png" alt="V">aultwarden Admin</a> <a class="navbar-brand" href="{{urlpath}}/admin"><img class="vaultwarden-icon" src="{{urlpath}}/vw_static/vaultwarden-icon.png" alt="V">aultwarden Admin</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse"
aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation"> aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span> <span class="navbar-toggler-icon"></span>
@@ -135,6 +135,6 @@
} }
})(); })();
</script> </script>
<script src="{{urlpath}}/bwrs_static/bootstrap-native.js"></script> <script src="{{urlpath}}/vw_static/bootstrap-native.js"></script>
</body> </body>
</html> </html>

View File

@@ -48,9 +48,9 @@
</div> </div>
</main> </main>
<link rel="stylesheet" href="{{urlpath}}/bwrs_static/datatables.css" /> <link rel="stylesheet" href="{{urlpath}}/vw_static/datatables.css" />
<script src="{{urlpath}}/bwrs_static/jquery-3.6.0.slim.js"></script> <script src="{{urlpath}}/vw_static/jquery-3.6.0.slim.js"></script>
<script src="{{urlpath}}/bwrs_static/datatables.js"></script> <script src="{{urlpath}}/vw_static/datatables.js"></script>
<script> <script>
'use strict'; 'use strict';

View File

@@ -135,9 +135,9 @@
</div> </div>
</main> </main>
<link rel="stylesheet" href="{{urlpath}}/bwrs_static/datatables.css" /> <link rel="stylesheet" href="{{urlpath}}/vw_static/datatables.css" />
<script src="{{urlpath}}/bwrs_static/jquery-3.6.0.slim.js"></script> <script src="{{urlpath}}/vw_static/jquery-3.6.0.slim.js"></script>
<script src="{{urlpath}}/bwrs_static/datatables.js"></script> <script src="{{urlpath}}/vw_static/datatables.js"></script>
<script> <script>
'use strict'; 'use strict';

View File

@@ -10,7 +10,7 @@
<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"> <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;"> <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;"> <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/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> <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}}/vw_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> </tr>
</table> </table>
</td> </td>

View File

@@ -81,7 +81,7 @@
<table class="body-wrap" 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; width: 100%;" bgcolor="#f6f6f6"> <table class="body-wrap" 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; width: 100%;" bgcolor="#f6f6f6">
<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;"> <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 valign="middle" class="aligncenter middle logo" 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; padding: 20px 0 10px;" align="center"> <td valign="middle" class="aligncenter middle logo" 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; padding: 20px 0 10px;" align="center">
<img src="{{url}}/bwrs_static/logo-gray.png" alt="" width="190" height="39" 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%;" /> <img src="{{url}}/vw_static/logo-gray.png" alt="" width="190" height="39" 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%;" />
</td> </td>
</tr> </tr>
<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;"> <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;">

View File

@@ -11,6 +11,9 @@ use rocket::{
Data, Request, Response, Rocket, Data, Request, Response, Rocket,
}; };
use std::thread::sleep;
use std::time::Duration;
use crate::CONFIG; use crate::CONFIG;
pub struct AppHeaders(); pub struct AppHeaders();
@@ -24,7 +27,7 @@ impl Fairing for AppHeaders {
} }
fn on_response(&self, _req: &Request, res: &mut Response) { fn on_response(&self, _req: &Request, res: &mut Response) {
res.set_raw_header("Feature-Policy", "accelerometer 'none'; ambient-light-sensor 'none'; autoplay 'none'; camera 'none'; encrypted-media 'none'; fullscreen 'none'; geolocation 'none'; gyroscope 'none'; magnetometer 'none'; microphone 'none'; midi 'none'; payment 'none'; picture-in-picture 'none'; sync-xhr 'self' https://haveibeenpwned.com https://2fa.directory; usb 'none'; vr 'none'"); res.set_raw_header("Permissions-Policy", "accelerometer=(), ambient-light-sensor=(), autoplay=(), camera=(), encrypted-media=(), fullscreen=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), midi=(), payment=(), picture-in-picture=(), sync-xhr=(self \"https://haveibeenpwned.com\" \"https://2fa.directory\"), usb=(), vr=()");
res.set_raw_header("Referrer-Policy", "same-origin"); res.set_raw_header("Referrer-Policy", "same-origin");
res.set_raw_header("X-Frame-Options", "SAMEORIGIN"); res.set_raw_header("X-Frame-Options", "SAMEORIGIN");
res.set_raw_header("X-Content-Type-Options", "nosniff"); res.set_raw_header("X-Content-Type-Options", "nosniff");
@@ -99,29 +102,53 @@ impl Fairing for Cors {
} }
} }
pub struct Cached<R>(R, String); pub struct Cached<R> {
response: R,
is_immutable: bool,
ttl: u64,
}
impl<R> Cached<R> { impl<R> Cached<R> {
pub fn long(r: R) -> Cached<R> { pub fn long(response: R, is_immutable: bool) -> Cached<R> {
// 7 days Self {
Self::ttl(r, 604800) response,
is_immutable,
ttl: 604800, // 7 days
}
} }
pub fn short(r: R) -> Cached<R> { pub fn short(response: R, is_immutable: bool) -> Cached<R> {
// 10 minutes Self {
Self(r, String::from("public, max-age=600")) response,
is_immutable,
ttl: 600, // 10 minutes
}
} }
pub fn ttl(r: R, ttl: u64) -> Cached<R> { pub fn ttl(response: R, ttl: u64, is_immutable: bool) -> Cached<R> {
Self(r, format!("public, immutable, max-age={}", ttl)) Self {
response,
is_immutable,
ttl,
}
} }
} }
impl<'r, R: Responder<'r>> Responder<'r> for Cached<R> { impl<'r, R: Responder<'r>> Responder<'r> for Cached<R> {
fn respond_to(self, req: &Request) -> response::Result<'r> { fn respond_to(self, req: &Request) -> response::Result<'r> {
match self.0.respond_to(req) { let cache_control_header = if self.is_immutable {
format!("public, immutable, max-age={}", self.ttl)
} else {
format!("public, max-age={}", self.ttl)
};
let time_now = chrono::Local::now();
match self.response.respond_to(req) {
Ok(mut res) => { Ok(mut res) => {
res.set_raw_header("Cache-Control", self.1); res.set_raw_header("Cache-Control", cache_control_header);
let expiry_time = time_now + chrono::Duration::seconds(self.ttl.try_into().unwrap());
res.set_raw_header("Expires", format_datetime_http(&expiry_time));
Ok(res) Ok(res)
} }
e @ Err(_) => e, e @ Err(_) => e,
@@ -409,6 +436,17 @@ pub fn format_naive_datetime_local(dt: &NaiveDateTime, fmt: &str) -> String {
format_datetime_local(&Local.from_utc_datetime(dt), fmt) format_datetime_local(&Local.from_utc_datetime(dt), fmt)
} }
/// Formats a `DateTime<Local>` as required for HTTP
///
/// https://httpwg.org/specs/rfc7231.html#http.date
pub fn format_datetime_http(dt: &DateTime<Local>) -> String {
let expiry_time: chrono::DateTime<chrono::Utc> = chrono::DateTime::from_utc(dt.naive_utc(), chrono::Utc);
// HACK: HTTP expects the date to always be GMT (UTC) rather than giving an
// offset (which would always be 0 in UTC anyway)
expiry_time.to_rfc2822().replace("+0000", "GMT")
}
// //
// Deployment environment methods // Deployment environment methods
// //
@@ -551,8 +589,6 @@ where
} }
} }
use std::{thread::sleep, time::Duration};
pub fn retry_db<F, T, E>(func: F, max_tries: u32) -> Result<T, E> pub fn retry_db<F, T, E>(func: F, max_tries: u32) -> Result<T, E>
where where
F: Fn() -> Result<T, E>, F: Fn() -> Result<T, E>,