import security/vaultwarden v1.24.0, OK abieber@, denis@
Unofficial Bitwarden compatible server written in Rust and compatible with upstream Bitwarden clients. Full implementation of Bitwarden API is provided including: - Organizations support - Attachments - Vault API support - Serving the static files for Vault interface - Website icons API - Authenticator and U2F support - YubiKey and Duo support
This commit is contained in:
parent
eb1f97ea53
commit
132a0f021c
60
security/vaultwarden/Makefile
Normal file
60
security/vaultwarden/Makefile
Normal file
@ -0,0 +1,60 @@
|
||||
BROKEN-sparc64 = ring-0.16.20 does not build on sparc64
|
||||
|
||||
COMMENT = unofficial bitwarden compatible server
|
||||
|
||||
GH_ACCOUNT = dani-garcia
|
||||
GH_PROJECT = vaultwarden
|
||||
GH_TAGNAME = 1.24.0
|
||||
|
||||
CATEGORIES = security
|
||||
|
||||
# GPL-3.0
|
||||
PERMIT_PACKAGE = Yes
|
||||
|
||||
FLAVORS = mysql postgresql
|
||||
FLAVOR ?=
|
||||
|
||||
WANTLIB += c c++abi crypto m pthread ssl
|
||||
|
||||
MASTER_SITES7 = https://files.bsd.ac/openbsd-distfiles/
|
||||
DISTFILES += vaultwarden-${GH_TAGNAME}.vendor.tgz:7
|
||||
|
||||
# as devel/cargo MODULES adds DISTFILES, GH_* didn't
|
||||
DISTFILES += ${DISTNAME}${EXTRACT_SUFX}
|
||||
|
||||
MODULES = devel/cargo
|
||||
|
||||
CONFIGURE_STYLE = cargo
|
||||
|
||||
SEPARATE_BUILD = Yes
|
||||
|
||||
RUN_DEPENDS = www/vaultwarden-web
|
||||
|
||||
MODCARGO_CRATES_SQLITE3_BUNDLED = Yes
|
||||
MODCARGO_FEATURES = sqlite
|
||||
.if ${FLAVOR:Mmysql}
|
||||
MODCARGO_FEATURES += mysql
|
||||
WANTLIB += mariadb
|
||||
LIB_DEPENDS += databases/mariadb
|
||||
.endif
|
||||
.if ${FLAVOR:Mpostgresql}
|
||||
MODCARGO_FEATURES += postgresql
|
||||
WANTLIB += pq
|
||||
LIB_DEPENDS += databases/postgresql
|
||||
.endif
|
||||
|
||||
SUBST_VARS += WRKSRC VARBASE
|
||||
|
||||
post-configure:
|
||||
mv ${WRKDIR}/myvendordir ${WRKSRC}
|
||||
${SUBST_CMD} -m 644 -c ${FILESDIR}/config.vendor ${WRKDIR}/config.vendor
|
||||
cat ${WRKDIR}/config.vendor >> ${WRKDIR}/.cargo/config
|
||||
|
||||
do-install:
|
||||
${INSTALL_DATA_DIR} ${PREFIX}/share/doc/vaultwarden
|
||||
${INSTALL_DATA} ${WRKSRC}/.env.template ${PREFIX}/share/doc/vaultwarden
|
||||
${INSTALL_PROGRAM} ${MODCARGO_TARGET_DIR}/release/vaultwarden ${PREFIX}/bin/
|
||||
|
||||
.include "crates.inc"
|
||||
|
||||
.include <bsd.port.mk>
|
375
security/vaultwarden/crates.inc
Normal file
375
security/vaultwarden/crates.inc
Normal file
@ -0,0 +1,375 @@
|
||||
MODCARGO_CRATES += addr2line 0.17.0 # Apache-2.0 OR MIT
|
||||
MODCARGO_CRATES += adler 1.0.2 # 0BSD OR MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += aho-corasick 0.7.18 # Unlicense/MIT
|
||||
MODCARGO_CRATES += alloc-no-stdlib 2.0.3 # BSD-3-Clause
|
||||
MODCARGO_CRATES += alloc-stdlib 0.2.1 # BSD-3-Clause
|
||||
MODCARGO_CRATES += ansi_term 0.12.1 # MIT
|
||||
MODCARGO_CRATES += async-compression 0.3.12 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += async-stream 0.3.2 # MIT
|
||||
MODCARGO_CRATES += async-stream-impl 0.3.2 # MIT
|
||||
MODCARGO_CRATES += async-trait 0.1.52 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += atomic 0.5.1 # Apache-2.0/MIT
|
||||
MODCARGO_CRATES += atty 0.2.14 # MIT
|
||||
MODCARGO_CRATES += autocfg 1.0.1 # Apache-2.0 OR MIT
|
||||
MODCARGO_CRATES += backtrace 0.3.64 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += base-x 0.2.8 # MIT
|
||||
MODCARGO_CRATES += base64 0.11.0 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += base64 0.12.3 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += base64 0.13.0 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += binascii 0.1.4 # MIT
|
||||
MODCARGO_CRATES += bitflags 1.3.2 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += block-buffer 0.7.3 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += block-buffer 0.9.0 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += block-padding 0.1.5 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += brotli 3.3.3 # BSD-3-Clause/MIT
|
||||
MODCARGO_CRATES += brotli-decompressor 2.3.2 # BSD-3-Clause/MIT
|
||||
MODCARGO_CRATES += bumpalo 3.9.1 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += byte-tools 0.3.1 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += byteorder 1.4.3 # Unlicense OR MIT
|
||||
MODCARGO_CRATES += bytes 0.4.12 # MIT
|
||||
MODCARGO_CRATES += bytes 1.1.0 # MIT
|
||||
MODCARGO_CRATES += cc 1.0.72 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += cfg-if 0.1.10 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += cfg-if 1.0.0 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += chashmap 2.2.2 # MIT
|
||||
MODCARGO_CRATES += chrono 0.4.19 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += chrono-tz 0.6.1 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += chrono-tz-build 0.0.2 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += const_fn 0.4.9 # Apache-2.0 OR MIT
|
||||
MODCARGO_CRATES += cookie 0.15.1 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += cookie 0.16.0 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += cookie_store 0.15.1 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += core-foundation 0.9.2 # MIT / Apache-2.0
|
||||
MODCARGO_CRATES += core-foundation-sys 0.8.3 # MIT / Apache-2.0
|
||||
MODCARGO_CRATES += cpufeatures 0.2.1 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += crc32fast 1.3.1 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += cron 0.9.0 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += crossbeam-utils 0.8.6 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += crypto-mac 0.10.1 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += crypto-mac 0.11.1 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += ctrlc 3.2.1 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += dashmap 4.0.2 # MIT
|
||||
MODCARGO_CRATES += data-encoding 2.3.2 # MIT
|
||||
MODCARGO_CRATES += data-url 0.1.1 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += devise 0.3.1 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += devise_codegen 0.3.1 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += devise_core 0.3.1 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += diesel 1.4.8 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += diesel_derives 1.4.1 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += diesel_migrations 1.4.0 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += digest 0.8.1 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += digest 0.9.0 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += discard 1.0.4 # MIT
|
||||
MODCARGO_CRATES += dotenv 0.15.0 # MIT
|
||||
MODCARGO_CRATES += either 1.6.1 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += encoding_rs 0.8.30 # COPYRIGHT
|
||||
MODCARGO_CRATES += enum-as-inner 0.3.3 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += error-chain 0.11.0 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += fake-simd 0.1.2 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += fastrand 1.7.0 # Apache-2.0 OR MIT
|
||||
MODCARGO_CRATES += fern 0.6.0 # MIT
|
||||
MODCARGO_CRATES += figment 0.10.6 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += flate2 1.0.22 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += fnv 1.0.7 # Apache-2.0 / MIT
|
||||
MODCARGO_CRATES += foreign-types 0.3.2 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += foreign-types-shared 0.1.1 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += form_urlencoded 1.0.1 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += fuchsia-cprng 0.1.1 # LICENSE
|
||||
MODCARGO_CRATES += fuchsia-zircon 0.3.3 # BSD-3-Clause
|
||||
MODCARGO_CRATES += fuchsia-zircon-sys 0.3.3 # BSD-3-Clause
|
||||
MODCARGO_CRATES += futf 0.1.4 # MIT / Apache-2.0
|
||||
MODCARGO_CRATES += futures 0.3.19 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += futures-channel 0.3.19 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += futures-core 0.3.19 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += futures-executor 0.3.19 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += futures-io 0.3.19 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += futures-macro 0.3.19 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += futures-sink 0.3.19 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += futures-task 0.3.19 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += futures-timer 3.0.2 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += futures-util 0.3.19 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += generator 0.7.0 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += generic-array 0.12.4 # MIT
|
||||
MODCARGO_CRATES += generic-array 0.14.5 # MIT
|
||||
MODCARGO_CRATES += getrandom 0.1.16 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += getrandom 0.2.4 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += gimli 0.26.1 # Apache-2.0/MIT
|
||||
MODCARGO_CRATES += glob 0.3.0 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += governor 0.4.1 # MIT
|
||||
MODCARGO_CRATES += h2 0.3.11 # MIT
|
||||
MODCARGO_CRATES += half 1.8.2 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += handlebars 4.2.1 # MIT
|
||||
MODCARGO_CRATES += hashbrown 0.11.2 # Apache-2.0/MIT
|
||||
MODCARGO_CRATES += heck 0.3.3 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += hermit-abi 0.1.19 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += hmac 0.10.1 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += hmac 0.11.0 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += hostname 0.3.1 # MIT
|
||||
MODCARGO_CRATES += html5ever 0.25.1 # MIT / Apache-2.0
|
||||
MODCARGO_CRATES += http 0.2.6 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += http-body 0.4.4 # MIT
|
||||
MODCARGO_CRATES += httparse 1.5.1 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += httpdate 1.0.2 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += hyper 0.14.16 # MIT
|
||||
MODCARGO_CRATES += hyper-tls 0.5.0 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += idna 0.1.5 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += idna 0.2.3 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += indexmap 1.8.0 # Apache-2.0/MIT
|
||||
MODCARGO_CRATES += inlinable_string 0.1.15 # Apache-2.0/MIT
|
||||
MODCARGO_CRATES += instant 0.1.12 # BSD-3-Clause
|
||||
MODCARGO_CRATES += iovec 0.1.4 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += ipconfig 0.2.2 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += ipnet 2.3.1 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += itoa 0.4.8 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += itoa 1.0.1 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += js-sys 0.3.56 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += jsonwebtoken 7.2.0 # MIT
|
||||
MODCARGO_CRATES += kernel32-sys 0.2.2 # MIT
|
||||
MODCARGO_CRATES += lazy_static 1.4.0 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += lazycell 1.3.0 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += lettre 0.10.0-rc.4 # MIT
|
||||
MODCARGO_CRATES += libc 0.2.116 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += libsqlite3-sys 0.22.2 # MIT
|
||||
MODCARGO_CRATES += linked-hash-map 0.5.4 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += lock_api 0.4.6 # Apache-2.0/MIT
|
||||
MODCARGO_CRATES += log 0.4.14 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += loom 0.5.4 # MIT
|
||||
MODCARGO_CRATES += lru-cache 0.1.2 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += mac 0.1.1 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += mach 0.3.2 # BSD-2-Clause
|
||||
MODCARGO_CRATES += maplit 1.0.2 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += markup5ever 0.10.1 # MIT / Apache-2.0
|
||||
MODCARGO_CRATES += markup5ever_rcdom 0.1.0 # MIT / Apache-2.0
|
||||
MODCARGO_CRATES += match_cfg 0.1.0 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += matchers 0.1.0 # MIT
|
||||
MODCARGO_CRATES += matches 0.1.9 # MIT
|
||||
MODCARGO_CRATES += maybe-uninit 2.0.0 # Apache-2.0 OR MIT
|
||||
MODCARGO_CRATES += memchr 2.4.1 # Unlicense/MIT
|
||||
MODCARGO_CRATES += memoffset 0.6.5 # MIT
|
||||
MODCARGO_CRATES += migrations_internals 1.4.1 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += migrations_macros 1.4.2 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += mime 0.3.16 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += minimal-lexical 0.2.1 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += miniz_oxide 0.4.4 # MIT OR Zlib OR Apache-2.0
|
||||
MODCARGO_CRATES += mio 0.6.23 # MIT
|
||||
MODCARGO_CRATES += mio 0.7.14 # MIT
|
||||
MODCARGO_CRATES += mio-extras 2.0.6 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += miow 0.2.2 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += miow 0.3.7 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += multer 2.0.2 # MIT
|
||||
MODCARGO_CRATES += mysqlclient-sys 0.2.5 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += native-tls 0.2.8 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += net2 0.2.37 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += new_debug_unreachable 1.0.4 # MIT
|
||||
MODCARGO_CRATES += nix 0.23.1 # MIT
|
||||
MODCARGO_CRATES += no-std-compat 0.4.1 # MIT
|
||||
MODCARGO_CRATES += nom 4.1.1 # MIT
|
||||
MODCARGO_CRATES += nom 7.1.0 # MIT
|
||||
MODCARGO_CRATES += nonzero_ext 0.3.0 # Apache-2.0
|
||||
MODCARGO_CRATES += ntapi 0.3.6 # Apache-2.0 OR MIT
|
||||
MODCARGO_CRATES += num-bigint 0.2.6 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += num-derive 0.3.3 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += num-integer 0.1.44 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += num-traits 0.2.14 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += num_cpus 1.13.1 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += num_threads 0.1.3 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += object 0.27.1 # Apache-2.0/MIT
|
||||
MODCARGO_CRATES += once_cell 1.9.0 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += opaque-debug 0.2.3 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += opaque-debug 0.3.0 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += openssl 0.10.38 # Apache-2.0
|
||||
MODCARGO_CRATES += openssl-probe 0.1.5 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += openssl-src 111.17.0+1.1.1m # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += openssl-sys 0.9.72 # MIT
|
||||
MODCARGO_CRATES += owning_ref 0.3.3 # MIT
|
||||
MODCARGO_CRATES += parity-ws 0.11.1 # MIT
|
||||
MODCARGO_CRATES += parking_lot 0.4.8 # Apache-2.0/MIT
|
||||
MODCARGO_CRATES += parking_lot 0.11.2 # Apache-2.0/MIT
|
||||
MODCARGO_CRATES += parking_lot_core 0.2.14 # Apache-2.0/MIT
|
||||
MODCARGO_CRATES += parking_lot_core 0.8.5 # Apache-2.0/MIT
|
||||
MODCARGO_CRATES += parse-zoneinfo 0.3.0 # MIT
|
||||
MODCARGO_CRATES += paste 1.0.6 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += pear 0.2.3 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += pear_codegen 0.2.3 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += pem 0.8.3 # MIT
|
||||
MODCARGO_CRATES += percent-encoding 1.0.1 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += percent-encoding 2.1.0 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += pest 2.1.3 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += pest_derive 2.1.0 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += pest_generator 2.1.3 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += pest_meta 2.1.3 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += phf 0.8.0 # MIT
|
||||
MODCARGO_CRATES += phf 0.10.1 # MIT
|
||||
MODCARGO_CRATES += phf_codegen 0.8.0 # MIT
|
||||
MODCARGO_CRATES += phf_codegen 0.10.0 # MIT
|
||||
MODCARGO_CRATES += phf_generator 0.8.0 # MIT
|
||||
MODCARGO_CRATES += phf_generator 0.10.0 # MIT
|
||||
MODCARGO_CRATES += phf_shared 0.8.0 # MIT
|
||||
MODCARGO_CRATES += phf_shared 0.10.0 # MIT
|
||||
MODCARGO_CRATES += pico-args 0.4.2 # MIT
|
||||
MODCARGO_CRATES += pin-project-lite 0.2.8 # Apache-2.0 OR MIT
|
||||
MODCARGO_CRATES += pin-utils 0.1.0 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += pkg-config 0.3.24 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += ppv-lite86 0.2.16 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += pq-sys 0.4.6 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += precomputed-hash 0.1.1 # MIT
|
||||
MODCARGO_CRATES += proc-macro-hack 0.5.19 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += proc-macro2 1.0.36 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += proc-macro2-diagnostics 0.9.1 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += psl-types 2.0.10 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += publicsuffix 2.1.1 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += quanta 0.9.3 # MIT
|
||||
MODCARGO_CRATES += quick-error 1.2.3 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += quick-error 2.0.1 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += quote 1.0.15 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += quoted_printable 0.4.5 # 0BSD
|
||||
MODCARGO_CRATES += r2d2 0.8.9 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += rand 0.4.6 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += rand 0.7.3 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += rand 0.8.4 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += rand_chacha 0.2.2 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += rand_chacha 0.3.1 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += rand_core 0.3.1 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += rand_core 0.4.2 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += rand_core 0.5.1 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += rand_core 0.6.3 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += rand_hc 0.2.0 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += rand_hc 0.3.1 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += rand_pcg 0.2.1 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += raw-cpuid 10.2.0 # MIT
|
||||
MODCARGO_CRATES += rdrand 0.4.0 # ISC
|
||||
MODCARGO_CRATES += redox_syscall 0.2.10 # MIT
|
||||
MODCARGO_CRATES += ref-cast 1.0.6 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += ref-cast-impl 1.0.6 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += regex 1.5.4 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += regex-automata 0.1.10 # Unlicense/MIT
|
||||
MODCARGO_CRATES += regex-syntax 0.6.25 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += remove_dir_all 0.5.3 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += reqwest 0.11.9 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += resolv-conf 0.7.0 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += ring 0.16.20 # LICENSE
|
||||
MODCARGO_CRATES += rmp 0.8.10 # MIT
|
||||
MODCARGO_CRATES += rmpv 1.0.0 # MIT
|
||||
MODCARGO_CRATES += rustc-demangle 0.1.21 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += rustc_version 0.2.3 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += rustls 0.19.1 # Apache-2.0/ISC/MIT
|
||||
MODCARGO_CRATES += rustversion 1.0.6 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += ryu 1.0.9 # Apache-2.0 OR BSL-1.0
|
||||
MODCARGO_CRATES += same-file 1.0.6 # Unlicense/MIT
|
||||
MODCARGO_CRATES += schannel 0.1.19 # MIT
|
||||
MODCARGO_CRATES += scheduled-thread-pool 0.2.5 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += scoped-tls 1.0.0 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += scopeguard 1.1.0 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += sct 0.6.1 # Apache-2.0/ISC/MIT
|
||||
MODCARGO_CRATES += security-framework 2.6.0 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += security-framework-sys 2.6.0 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += semver 0.9.0 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += semver-parser 0.7.0 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += serde 1.0.136 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += serde_cbor 0.11.2 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += serde_derive 1.0.136 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += serde_json 1.0.78 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += serde_urlencoded 0.7.1 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += sha-1 0.8.2 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += sha-1 0.9.8 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += sha1 0.6.1 # BSD-3-Clause
|
||||
MODCARGO_CRATES += sha1_smol 1.0.0 # BSD-3-Clause
|
||||
MODCARGO_CRATES += sha2 0.9.9 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += sharded-slab 0.1.4 # MIT
|
||||
MODCARGO_CRATES += signal-hook-registry 1.4.0 # Apache-2.0/MIT
|
||||
MODCARGO_CRATES += simple_asn1 0.4.1 # ISC
|
||||
MODCARGO_CRATES += siphasher 0.3.9 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += slab 0.4.5 # MIT
|
||||
MODCARGO_CRATES += smallvec 0.6.14 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += smallvec 1.8.0 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += socket2 0.3.19 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += socket2 0.4.4 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += spin 0.5.2 # MIT
|
||||
MODCARGO_CRATES += spin 0.9.2 # MIT
|
||||
MODCARGO_CRATES += stable-pattern 0.1.0 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += stable_deref_trait 1.2.0 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += standback 0.2.17 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += state 0.5.2 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += stdweb 0.4.20 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += stdweb-derive 0.5.3 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += stdweb-internal-macros 0.2.9 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += stdweb-internal-runtime 0.1.5 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += string_cache 0.8.2 # MIT / Apache-2.0
|
||||
MODCARGO_CRATES += string_cache_codegen 0.5.1 # MIT / Apache-2.0
|
||||
MODCARGO_CRATES += subtle 2.4.1 # BSD-3-Clause
|
||||
MODCARGO_CRATES += syn 1.0.86 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += syslog 4.0.1 # MIT
|
||||
MODCARGO_CRATES += tempfile 3.3.0 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += tendril 0.4.2 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += thiserror 1.0.30 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += thiserror-impl 1.0.30 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += thread_local 1.1.4 # Apache-2.0/MIT
|
||||
MODCARGO_CRATES += threadpool 1.8.1 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += time 0.1.44 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += time 0.2.27 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += time 0.3.7 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += time-macros 0.1.1 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += time-macros 0.2.3 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += time-macros-impl 0.1.2 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += tinyvec 1.5.1 # Zlib OR Apache-2.0 OR MIT
|
||||
MODCARGO_CRATES += tinyvec_macros 0.1.0 # MIT OR Apache-2.0 OR Zlib
|
||||
MODCARGO_CRATES += tokio 1.16.1 # MIT
|
||||
MODCARGO_CRATES += tokio-macros 1.7.0 # MIT
|
||||
MODCARGO_CRATES += tokio-native-tls 0.3.0 # MIT
|
||||
MODCARGO_CRATES += tokio-rustls 0.22.0 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += tokio-socks 0.5.1 # MIT
|
||||
MODCARGO_CRATES += tokio-stream 0.1.8 # MIT
|
||||
MODCARGO_CRATES += tokio-util 0.6.9 # MIT
|
||||
MODCARGO_CRATES += toml 0.5.8 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += totp-lite 1.0.3 # MIT
|
||||
MODCARGO_CRATES += tower-service 0.3.1 # MIT
|
||||
MODCARGO_CRATES += tracing 0.1.29 # MIT
|
||||
MODCARGO_CRATES += tracing-attributes 0.1.18 # MIT
|
||||
MODCARGO_CRATES += tracing-core 0.1.21 # MIT
|
||||
MODCARGO_CRATES += tracing-log 0.1.2 # MIT
|
||||
MODCARGO_CRATES += tracing-subscriber 0.3.7 # MIT
|
||||
MODCARGO_CRATES += trust-dns-proto 0.20.3 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += trust-dns-resolver 0.20.3 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += try-lock 0.2.3 # MIT
|
||||
MODCARGO_CRATES += typenum 1.15.0 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += u2f 0.2.0 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += ubyte 0.10.1 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += ucd-trie 0.1.3 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += uncased 0.9.6 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += unicode-bidi 0.3.7 # MIT / Apache-2.0
|
||||
MODCARGO_CRATES += unicode-normalization 0.1.19 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += unicode-segmentation 1.8.0 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += unicode-xid 0.2.2 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += untrusted 0.7.1 # ISC
|
||||
MODCARGO_CRATES += url 1.7.2 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += url 2.2.2 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += utf-8 0.7.6 # MIT OR Apache-2.0
|
||||
MODCARGO_CRATES += uuid 0.8.2 # Apache-2.0 OR MIT
|
||||
MODCARGO_CRATES += vcpkg 0.2.15 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += version_check 0.9.4 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += walkdir 2.3.2 # Unlicense/MIT
|
||||
MODCARGO_CRATES += want 0.3.0 # MIT
|
||||
MODCARGO_CRATES += wasi 0.9.0+wasi-snapshot-preview1 # Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT
|
||||
MODCARGO_CRATES += wasi 0.10.0+wasi-snapshot-preview1 # Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT
|
||||
MODCARGO_CRATES += wasm-bindgen 0.2.79 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += wasm-bindgen-backend 0.2.79 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += wasm-bindgen-futures 0.4.29 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += wasm-bindgen-macro 0.2.79 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += wasm-bindgen-macro-support 0.2.79 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += wasm-bindgen-shared 0.2.79 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += web-sys 0.3.56 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += webauthn-rs 0.3.2 # MPL-2.0
|
||||
MODCARGO_CRATES += webpki 0.21.4 # LICENSE
|
||||
MODCARGO_CRATES += widestring 0.4.3 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += winapi 0.2.8 # MIT
|
||||
MODCARGO_CRATES += winapi 0.3.9 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += winapi-build 0.1.1 # MIT
|
||||
MODCARGO_CRATES += winapi-i686-pc-windows-gnu 0.4.0 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += winapi-util 0.1.5 # Unlicense/MIT
|
||||
MODCARGO_CRATES += winapi-x86_64-pc-windows-gnu 0.4.0 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += winreg 0.6.2 # MIT
|
||||
MODCARGO_CRATES += winreg 0.7.0 # MIT
|
||||
MODCARGO_CRATES += ws2_32-sys 0.2.1 # MIT
|
||||
MODCARGO_CRATES += xml5ever 0.16.2 # MIT / Apache-2.0
|
||||
MODCARGO_CRATES += yansi 0.5.0 # MIT/Apache-2.0
|
||||
MODCARGO_CRATES += yubico 0.10.0 # MIT OR Apache-2.0
|
754
security/vaultwarden/distinfo
Normal file
754
security/vaultwarden/distinfo
Normal file
@ -0,0 +1,754 @@
|
||||
SHA256 (cargo/addr2line-0.17.0.tar.gz) = uezYioyDeMqROmgM2Y8PE6xnOD01mT+GyQpw4/E3gWs=
|
||||
SHA256 (cargo/adler-1.0.2.tar.gz) = 8mIBYEyHseAb09mPjV2aj8u4FejO20H/zL60v1k6Nf4=
|
||||
SHA256 (cargo/aho-corasick-0.7.18.tar.gz) = HjfP1edletpF90LW6ZyleIWAtcUp3Hj68R7ObccCZW8=
|
||||
SHA256 (cargo/alloc-no-stdlib-2.0.3.tar.gz) = Ne9HMEkK0cTq5cQyWyqV9SHQI+XIhYU/96ygpqFjHbM=
|
||||
SHA256 (cargo/alloc-stdlib-0.2.1.tar.gz) = aX7X7cDxcR3knOEIxUFiOgr5fGxgsvbitlIphHrIQ8I=
|
||||
SHA256 (cargo/ansi_term-0.12.1.tar.gz) = 1Sqbt+wM9ITFUYMKfOJ70g1n6sZH4b77VrC+TuOaVdI=
|
||||
SHA256 (cargo/async-compression-0.3.12.tar.gz) = 8r85TPu+h28KxnsTtsqBn5yfL7nsZyI8zrFVX7qxwxo=
|
||||
SHA256 (cargo/async-stream-0.3.2.tar.gz) = FxN05+OyUE4OUjbjtZJgVg+f6Uv+msObpeTpKcVZBiU=
|
||||
SHA256 (cargo/async-stream-impl-0.3.2.tar.gz) = ZI7YyNLOVAnM1XRT2dGyFLNCoNaTdqb+2h/WyuMpkwg=
|
||||
SHA256 (cargo/async-trait-0.1.52.tar.gz) = Bhp6zMqihsAR3cMJcFILmPpA4AydZEYz+ya1/GOiZeM=
|
||||
SHA256 (cargo/atomic-0.5.1.tar.gz) = uI2CZn7KdyxKoS8PE0izrmQ0JMiHZEjz971XhwMuI0w=
|
||||
SHA256 (cargo/atty-0.2.14.tar.gz) = 2bOb4Ydw0RQhzbG5lHpF3T836TCSy/N3YUgooxnV/ug=
|
||||
SHA256 (cargo/autocfg-1.0.1.tar.gz) = zbAx3XjihzHYfVbMj/70qPNsomw4/i3nAFQ+Yn+KRko=
|
||||
SHA256 (cargo/backtrace-0.3.64.tar.gz) = XhId7oAjzjOrJI2c4Uk98Dw7OKZZskAJb8vXBI/5wx8=
|
||||
SHA256 (cargo/base-x-0.2.8.tar.gz) = pFIfPj0DE3BnmzsUC+s23+SAGwmsd+MMYZQfl98+8os=
|
||||
SHA256 (cargo/base64-0.11.0.tar.gz) = tBt+pUoMnZIZneieIOWNSfAvjmmYFO8/3yZvb3SNFcc=
|
||||
SHA256 (cargo/base64-0.12.3.tar.gz) = NEHw97AniOlI5H9FfKAfHX5tksaTvBMsIrCH0xQcA/8=
|
||||
SHA256 (cargo/base64-0.13.0.tar.gz) = kE3+rFDzzauij8b1f9zdt19J7WE0ZnanjE/+VYd4Av0=
|
||||
SHA256 (cargo/binascii-0.1.4.tar.gz) = OD0p1RPYdk3NxC6ildl565nDyfAGB7NpLPaKQx99ynI=
|
||||
SHA256 (cargo/bitflags-1.3.2.tar.gz) = vvONRRY8Lx3eCUp9/TPM9ZXJKQXI+PT9wY0G+xA3cYo=
|
||||
SHA256 (cargo/block-buffer-0.7.3.tar.gz) = wJQNxEHzFokmnhCscOsQAqOh060TkOAwBDZi63/kaIs=
|
||||
SHA256 (cargo/block-buffer-0.9.0.tar.gz) = QVIRb9bp2tspGuGPwew1de1thMKWQtl4kPS0o0Fyl+Q=
|
||||
SHA256 (cargo/block-padding-0.1.5.tar.gz) = +nne27CR9Enx855T7fiNXb6V+JXa5hNajXuIH7Wvc/U=
|
||||
SHA256 (cargo/brotli-3.3.3.tar.gz) = +DjkekUdWo+lUjcfgAJN1qzpt6zfJcTD0Pm8aBb7HDk=
|
||||
SHA256 (cargo/brotli-decompressor-2.3.2.tar.gz) = Wa0tRlO/XKNq55ex9LtNvdtgzknKSu2KLOSCn2BCW4A=
|
||||
SHA256 (cargo/bumpalo-3.9.1.tar.gz) = pKRaRqsfJBLlPToK3nb/rSAlgEKUVpquOHIxoM1uCJk=
|
||||
SHA256 (cargo/byte-tools-0.3.1.tar.gz) = 47XKegSJitS81ByQxShURf9beRiZuxsKvdKiqnkSEdc=
|
||||
SHA256 (cargo/byteorder-1.4.3.tar.gz) = FMGJxT0JiUVJnN+n7MY1Z884hrMzKzEqW0WF2NOmphA=
|
||||
SHA256 (cargo/bytes-0.4.12.tar.gz) = IG/f/Pot98vhVgHvRsgT/OCWXrMobba1bFg7gUtRyBw=
|
||||
SHA256 (cargo/bytes-1.1.0.tar.gz) = xIctZ7q2NY5ZVZAnqjuRV8U9k1jFFCPBdVSAmohY4Pg=
|
||||
SHA256 (cargo/cc-1.0.72.tar.gz) = IqkTe5XqBoZOAYN1tyrft9tub2jPyN9aBNACiAUEhe4=
|
||||
SHA256 (cargo/cfg-if-0.1.10.tar.gz) = R4W90clrKoRrK9fMAuhraz2/FOflNEbE9UySo2EECCI=
|
||||
SHA256 (cargo/cfg-if-1.0.0.tar.gz) = uvHeQzl2FYi8Bhnjy8ASDuWC67dLU7Tvv3kRe9LaQP0=
|
||||
SHA256 (cargo/chashmap-2.2.2.tar.gz) = /0GjwsHjmSG5AD3hS/BDnHtjqQOWN8KR4aZJJdjd+kU=
|
||||
SHA256 (cargo/chrono-0.4.19.tar.gz) = ZwrWjJCIwqljqqKYyzaWiM8/lGXOXi1MoQ5uAJihznM=
|
||||
SHA256 (cargo/chrono-tz-0.6.1.tar.gz) = WFSfGELaMIDOYwAhAtW8lUx7yEPU9HgY5kKr3DYlNVI=
|
||||
SHA256 (cargo/chrono-tz-build-0.0.2.tar.gz) = 2wWNST+y9l9Bhhv+1+P+YzUmSp8PknEMq1vfAf7wkGk=
|
||||
SHA256 (cargo/const_fn-0.4.9.tar.gz) = +9zctthvccXpdAmtRYmK8Ry8mVtO6BEtWQlaKNN2yTU=
|
||||
SHA256 (cargo/cookie-0.15.1.tar.gz) = 1fHHcn5GA5flarxL3cHUngehrXj8mOsuHI8DKlii+A0=
|
||||
SHA256 (cargo/cookie-0.16.0.tar.gz) = lNRwbeGw+lsTInDN3/qFhRZgN4IuJgqUT+FhrNE3ygU=
|
||||
SHA256 (cargo/cookie_store-0.15.1.tar.gz) = s/cDTAky3Db1vY7Dc2jZcTRoCUNYJPJ3yzuCmfxWFnw=
|
||||
SHA256 (cargo/core-foundation-0.9.2.tar.gz) = aIjhBVG7k+Qk2N8dB/GotPzrAAGjpLBIv8R1VJRvR7M=
|
||||
SHA256 (cargo/core-foundation-sys-0.8.3.tar.gz) = WCfOv0ZwRouHct0ZGFZ2iu3LGwJ4oE+Yn3dmNRkXudw=
|
||||
SHA256 (cargo/cpufeatures-0.2.1.tar.gz) = lQWUKPZt9WtjQx/bThlH7SGQWGr1xaiotxEivfWn9Gk=
|
||||
SHA256 (cargo/crc32fast-1.3.1.tar.gz) = oiCcMQ4ph29/Cych5+JrhK/xeKo9pdCR+b+/R2aeYOM=
|
||||
SHA256 (cargo/cron-0.9.0.tar.gz) = 4AntC3Ys96lno039xn1ZZ9P4KPEpAdNwgUMsPdFmj48=
|
||||
SHA256 (cargo/crossbeam-utils-0.8.6.tar.gz) = z8rgPts0+UfmSs2xwz7BaYJOIGV+nsthzvbIx03LgSA=
|
||||
SHA256 (cargo/crypto-mac-0.10.1.tar.gz) = v/BwCOxwHoAo4s64+D8OQnTuYr0tvcT+//LpqRgkCBo=
|
||||
SHA256 (cargo/crypto-mac-0.11.1.tar.gz) = sdGob0kjbCFfJx1AiS1fyVBJBVFACwLvNgaSwpgVxxQ=
|
||||
SHA256 (cargo/ctrlc-3.2.1.tar.gz) = oZxs7f/cjAOjNG1yPrIL2FoTNiu5bcKsAAhCxjgex78=
|
||||
SHA256 (cargo/dashmap-4.0.2.tar.gz) = 53pDso0GaN8JQRywvJqMKtxA+aBIr+hj4F/UMlHo45w=
|
||||
SHA256 (cargo/data-encoding-2.3.2.tar.gz) = PuI5PEqRQp3/tL7fGfTWq/J9inMsjOSYAwXXguVCbVc=
|
||||
SHA256 (cargo/data-url-0.1.1.tar.gz) = OjC/znArz6lOkG74JCHywOYcB2rXYDDBbuXS6aMv4ZM=
|
||||
SHA256 (cargo/devise-0.3.1.tar.gz) = UMdYCwcvHIR2FI8W4KDV3t3at4famNhsUILF6e2KtZU=
|
||||
SHA256 (cargo/devise_codegen-0.3.1.tar.gz) = Ejxz56blGwXHX+GhsvTiQTmepXQO2BCw4+bKzZ2157I=
|
||||
SHA256 (cargo/devise_core-0.3.1.tar.gz) = hB70b0eH2Ql0BcrE5w+4ZE/AN7Um6MFAVCR8AmPEANA=
|
||||
SHA256 (cargo/diesel-1.4.8.tar.gz) = soE17Pa31Ea0PifiJWIqA4zE4pMKECL1HNuXraGbjk0=
|
||||
SHA256 (cargo/diesel_derives-1.4.1.tar.gz) = RfUJj2KNAqeg9o3bpYb7YegO3sO9wb47kh9M7sYIWNM=
|
||||
SHA256 (cargo/diesel_migrations-1.4.0.tar.gz) = vzzehBM1Pcf11y+ozguZpWCjWdLF7x5YF8pzHNkAj0w=
|
||||
SHA256 (cargo/digest-0.8.1.tar.gz) = 89DIyHUjEvlxPv05f/Y6y5+FWFr78XkoLnIOdwSVTdU=
|
||||
SHA256 (cargo/digest-0.9.0.tar.gz) = 091g0QgKV6BasDI3cEngWRQV0rMa/XAoNW2/PMbcsGY=
|
||||
SHA256 (cargo/discard-1.0.4.tar.gz) = IS0PV1TLZ2mTf0UBzA5n9PRIPI0sPh6SLuntvkq0x8A=
|
||||
SHA256 (cargo/dotenv-0.15.0.tar.gz) = d8kLre3M9BBeyhAHVqCxKJ4ZH2/L2t087h0vYU+X2o8=
|
||||
SHA256 (cargo/either-1.6.1.tar.gz) = 541PHMSuM7v8FX7V1aXvO8KSJzA9WVhh3rI4/OxOlFc=
|
||||
SHA256 (cargo/encoding_rs-0.8.30.tar.gz) = eJbcirslD/3aM5ElUPqlTIjsi5mN7AssVasiSSHOEd8=
|
||||
SHA256 (cargo/enum-as-inner-0.3.3.tar.gz) = fF8AlqkdIQFZ7Osv9eHE2hg4ihcOHjzpSKrJyP279ZU=
|
||||
SHA256 (cargo/error-chain-0.11.0.tar.gz) = /1EdXcQ11wP0lxvDmWR8m8OOIMtBRS47n+tHZUGe0/M=
|
||||
SHA256 (cargo/fake-simd-0.1.2.tar.gz) = 6IqKzykdr7WcLZbo9Zgo84OLsacDmII63lGoTeam3u0=
|
||||
SHA256 (cargo/fastrand-1.7.0.tar.gz) = w/zwzuU1GchmwJtd4fbFb/nWRxAfgcGWT6Yy4UiJbN8=
|
||||
SHA256 (cargo/fern-0.6.0.tar.gz) = jJpIIPDMyKev1nw5oPGg9LB8oXJRZCcaZJOdeuua8GU=
|
||||
SHA256 (cargo/figment-0.10.6.tar.gz) = eQtCkscmGKu6tQ94ekdwFP4VY0+WKR3kVnLORq/hIt8=
|
||||
SHA256 (cargo/flate2-1.0.22.tar.gz) = HmmI6JfBycSF9DtHpSnO9C/eBUf52NQacGJRjx2PxT8=
|
||||
SHA256 (cargo/fnv-1.0.7.tar.gz) = P57skY0/JAad7LmvFVTK18iA4tokqa/YisoABTGrgsE=
|
||||
SHA256 (cargo/foreign-types-0.3.2.tar.gz) = 9vM564rcBSzSyniRD9qGmu+jjSLVy2SOZIXk0/wG87E=
|
||||
SHA256 (cargo/foreign-types-shared-0.1.1.tar.gz) = ALAihBGQjKhoXbp/ws3XDsmZCm51Pom2rJGoTED7r0s=
|
||||
SHA256 (cargo/form_urlencoded-1.0.1.tar.gz) = X8Jah/pP0glL/7BpJYUgNNkKF/DR4FGX1JVtNVV1IZE=
|
||||
SHA256 (cargo/fuchsia-cprng-0.1.1.tar.gz) = oG931SbBpgG3xM3Zj1S16qv/wU1fLwKW/r3H81fG07o=
|
||||
SHA256 (cargo/fuchsia-zircon-0.3.3.tar.gz) = Lpdjxp66rmMLo190iI20ZeSeJZuhvA7afQb0oGdhXYI=
|
||||
SHA256 (cargo/fuchsia-zircon-sys-0.3.3.tar.gz) = Pcqprncl0SzbhbOtmaQ023C0aMCd7RfgEthrXBAQ96c=
|
||||
SHA256 (cargo/futf-0.1.4.tar.gz) = fJwc4/qTNjAa+TWrhSxDeBfRTNM2kERlaTkuZRcKrDs=
|
||||
SHA256 (cargo/futures-0.3.19.tar.gz) = KFYHV/4rs055+Qd5S7ayKuiw5cZptjihEy8lkrGQNbQ=
|
||||
SHA256 (cargo/futures-channel-0.3.19.tar.gz) = uj3aC2WIM182CvxnXQVkwXp3or2oHKF4pLYIG9hsfws=
|
||||
SHA256 (cargo/futures-core-0.3.19.tar.gz) = 0Mj/BGG4JVmBDNzP3jIVw/NzgH9eUjK3FHm/97slg9c=
|
||||
SHA256 (cargo/futures-executor-0.3.19.tar.gz) = KdbS/1uxD7lchbjORlOKLl9ef9x1ViOn1FKauKTtnSo=
|
||||
SHA256 (cargo/futures-io-0.3.19.tar.gz) = sfnTSvWhqsb7OA9zX+UQdGw4Bnxb8Wx/0lAoBQPJcbI=
|
||||
SHA256 (cargo/futures-macro-0.3.19.tar.gz) = bb2Uet//sO/HBZmz3c97VZe7X6niReuZ9is6X3u4vTw=
|
||||
SHA256 (cargo/futures-sink-0.3.19.tar.gz) = 4wVbrMto10/2SANQ+Nbrj8+jqhG9waGuOv3QUUYX1Qg=
|
||||
SHA256 (cargo/futures-task-0.3.19.tar.gz) = bufGSFwwFnzk37g6xWioSf5TJ0yDEIFHbuE+Dc4arXI=
|
||||
SHA256 (cargo/futures-timer-3.0.2.tar.gz) = 5ksDkJ34gDTCbcFUfolwuR+YvbZRZdak6RENlCY9uyw=
|
||||
SHA256 (cargo/futures-util-0.3.19.tar.gz) = 2bXPQLR6Jx93qLG+wDygkETZnSNywN4kTmZDB2EScWQ=
|
||||
SHA256 (cargo/generator-0.7.0.tar.gz) = wdknnKgiiRwaTa4G0YVhLPj8as/l3/N3gbQSl4EbEu4=
|
||||
SHA256 (cargo/generic-array-0.12.4.tar.gz) = /9+fNPFEdEPTc5PMbCuDE6693NlpBsrzTlTGjY5X170=
|
||||
SHA256 (cargo/generic-array-0.14.5.tar.gz) = /UjTPsfwX7+hUjAP2tdkdXy97TQ8GqHP8vuvQTSFGAM=
|
||||
SHA256 (cargo/getrandom-0.1.16.tar.gz) = j8PLTZH1O1AVW9z9I/akw5rhlpwq6FmCsTV1DMyvX84=
|
||||
SHA256 (cargo/getrandom-0.2.4.tar.gz) = QY03yLHUJVPJNki+Upy3D5INO6+O9Gm3S5Y430JuC0w=
|
||||
SHA256 (cargo/gimli-0.26.1.tar.gz) = eMw3LQWNz21ezZhRDn+8nlrsTSHecPZf6o/s682IG9Q=
|
||||
SHA256 (cargo/glob-0.3.0.tar.gz) = m5GZM6OXt5w34zt3uyqj3I624WWtgJ5Y/3W8fbLjRXQ=
|
||||
SHA256 (cargo/governor-0.4.1.tar.gz) = ffDuSyN6+3Hpn34vvYQP/sLWxLtWn2myrxiqH2MHfTg=
|
||||
SHA256 (cargo/h2-0.3.11.tar.gz) = 2fH3F93Hsro2336HH9iNt5MmVR09bx/EBvv9KLWC/44=
|
||||
SHA256 (cargo/half-1.8.2.tar.gz) = 6rtKREUNoCyQREz3RVjakE7d6PtOkDWppqThVEWvC9c=
|
||||
SHA256 (cargo/handlebars-4.2.1.tar.gz) = JVRqZeXPH0cfNDh5b8Y0ZQsx1/zeAdREwwmusouS46g=
|
||||
SHA256 (cargo/hashbrown-0.11.2.tar.gz) = q17w1JCe83JMyMzmzMhXLFyBdZLpKF9UZPjob4vTcm4=
|
||||
SHA256 (cargo/heck-0.3.3.tar.gz) = bWIe+yaGPw6ZJMasV36CdeXmt3RV22T/psZckE6eEyw=
|
||||
SHA256 (cargo/hermit-abi-0.1.19.tar.gz) = YrRnNDuUukdtyyUA0kLa27OVV9+IkxCsd8XZkQCqrDM=
|
||||
SHA256 (cargo/hmac-0.10.1.tar.gz) = wUQcax6TDigXQEtQRvH5iYmRQ6Er+S3mA7afTgruHhU=
|
||||
SHA256 (cargo/hmac-0.11.0.tar.gz) = KiojIOt+wOvo2o90TXgS2fxMtNCTRKwBiY28tqIK5ps=
|
||||
SHA256 (cargo/hostname-0.3.1.tar.gz) = PHMcPhBQTMjtNc/i8dtMknTD01+khuOzHfRvBo7z6Gc=
|
||||
SHA256 (cargo/html5ever-0.25.1.tar.gz) = qvzziho2EYJC0puS4bCO+E5n5KXtBuCoC+IOajK/7Ws=
|
||||
SHA256 (cargo/http-0.2.6.tar.gz) = MfTGdGWEhm8P6rzGmJPFtRvu84MWVqlo7XriVM3E/QM=
|
||||
SHA256 (cargo/http-body-0.4.4.tar.gz) = H/T4SRlncwPaXxR2RdvqaxiB82jQOshOHcCQMevXssY=
|
||||
SHA256 (cargo/httparse-1.5.1.tar.gz) = rNlP2+HU/2iLZ7BO7i4XvVCZVTSmFTnkWt/vtF5eVQM=
|
||||
SHA256 (cargo/httpdate-1.0.2.tar.gz) = xKHjbIIdvgRXT2AoSKGfdC9Ps8mNQESfEbytGNaxdCE=
|
||||
SHA256 (cargo/hyper-0.14.16.tar.gz) = t+w+Yr3Jii8Dk6UEjkww72WUQOpuDlcpZRA+cr2Db1U=
|
||||
SHA256 (cargo/hyper-tls-0.5.0.tar.gz) = 1hg936mbhdphoUC+oO/JP99WzqoEGzfVU1GAMIJ/mQU=
|
||||
SHA256 (cargo/idna-0.1.5.tar.gz) = OPCeDwsftV/e4fF0cK2ADad69RhqGnbAJrZ5NYt+hE4=
|
||||
SHA256 (cargo/idna-0.2.3.tar.gz) = QYoKb6uCFHX2NO/jzMRcAT90Lv4D2FPo0zVdXLhQ7Pg=
|
||||
SHA256 (cargo/indexmap-1.8.0.tar.gz) = KCpiR3Isq6QEwGUBa7+lIoBuUXFMNPXfw+SjpG/LQiM=
|
||||
SHA256 (cargo/inlinable_string-0.1.15.tar.gz) = yPrlR4b2L7KRjc+uPVaFlOUOubXCW/BDca9v51FkUvs=
|
||||
SHA256 (cargo/instant-0.1.12.tar.gz) = elu+gkxQfF2llWNV6Gp0bYLg4UZPZdhizF5x2nDpSyw=
|
||||
SHA256 (cargo/iovec-0.1.4.tar.gz) = srPqb/leF1Rz+P/mp+t8ANBUJAMhuExXBRF1/jweB14=
|
||||
SHA256 (cargo/ipconfig-0.2.2.tar.gz) = 9+LxiuzpcJCUVzqfJPSDxPZcqkKY4veuG3HMZdhT+tc=
|
||||
SHA256 (cargo/ipnet-2.3.1.tar.gz) = aPLWTy7evsTOhK0QgUjmfhBkeJvuQ17cW2CtOYcUo6k=
|
||||
SHA256 (cargo/itoa-0.4.8.tar.gz) = txmR/1YpSqkitFATnuCLO/xwmCxrLHVidxN1z3NULdQ=
|
||||
SHA256 (cargo/itoa-1.0.1.tar.gz) = GquPw2dYi4nc7oOrD9ZrcrULcvoZBNcJUEWs4rDIHDU=
|
||||
SHA256 (cargo/js-sys-0.3.56.tar.gz) = o4/CTjD9VkzpdMAr8dM3yt3/Zb5sxHNaH36rIqdEDwQ=
|
||||
SHA256 (cargo/jsonwebtoken-7.2.0.tar.gz) = r6vMFeQ3pkhPxPEtD9YwaP5Fe/k/HBSNPZZJxgsQPzI=
|
||||
SHA256 (cargo/kernel32-sys-0.2.2.tar.gz) = dQdiSylINDHAui2Crs6Mps26k4K/9N3Q90kFYMBWCY0=
|
||||
SHA256 (cargo/lazy_static-1.4.0.tar.gz) = 4qutI/vEKzcA8vJ5hE3IMq2ysusGmy35GPRVxOGMxkY=
|
||||
SHA256 (cargo/lazycell-1.3.0.tar.gz) = gw0Izh0dlB5rMGRfGg61ZDAT2DXON3ml/CCCYdvhD1U=
|
||||
SHA256 (cargo/lettre-0.10.0-rc.4.tar.gz) = cdjajzTQhrCBycw7V9O7O1HRb8BrXISKGI4vFNWKwqU=
|
||||
SHA256 (cargo/libc-0.2.116.tar.gz) = Vl29iIctvkzIpG5SfyZIPB0fevpriEo71s2JPU+Y2nQ=
|
||||
SHA256 (cargo/libsqlite3-sys-0.22.2.tar.gz) = KQtkkX+LDLiF2d4PmVn+H3ddf6EvHaLbkAHByKtg+J0=
|
||||
SHA256 (cargo/linked-hash-map-0.5.4.tar.gz) = f7mzivkmCBQLhraTYEuf/MWCQkCkhNHs1HlbrLL+iPM=
|
||||
SHA256 (cargo/lock_api-0.4.6.tar.gz) = iJQ91+9KLlpL+idTqqswE+NM4lM9GZb7GO9ZHjFeKzs=
|
||||
SHA256 (cargo/log-0.4.14.tar.gz) = Ubm75sR9Ufw+GpuUWWWUa0xEFCq4eSxQg1qYDTYsJxA=
|
||||
SHA256 (cargo/loom-0.5.4.tar.gz) = 7cXH0yjjLMSVTo4BGT1/DvWrJXtQkLcKlk4JmjYDQwk=
|
||||
SHA256 (cargo/lru-cache-0.1.2.tar.gz) = MeJPGtgyHKDooeCsE/I8tmjm9UZsLFcxn2pc8cyOOxw=
|
||||
SHA256 (cargo/mac-0.1.1.tar.gz) = xB4MT++GlhrG1vioJgn1XzGwXk/OFJrFcQ5Dnfdhm6Q=
|
||||
SHA256 (cargo/mach-0.3.2.tar.gz) = uCPoOyr/2PQKnujCnbxWQEweNM0nEJIfKAHizylSevo=
|
||||
SHA256 (cargo/maplit-1.0.2.tar.gz) = Pi5loaLkPPy0eolcTIsQ0fSmEJf58lTxg67mDK2cZR0=
|
||||
SHA256 (cargo/markup5ever-0.10.1.tar.gz) = ok9A+wOFLRzdhDMM3cr5jp7Aint3aOlS+tO0zwSOyP0=
|
||||
SHA256 (cargo/markup5ever_rcdom-0.1.0.tar.gz) = 8BXaQ7zY1PFEVZo0I/RZHWm4zgZSyQU3TacgXfM2ris=
|
||||
SHA256 (cargo/match_cfg-0.1.0.tar.gz) = /77oY04NRdJYrLRI5+qrP856CkZzldTZ8ijjwfAfsuQ=
|
||||
SHA256 (cargo/matchers-0.1.0.tar.gz) = gmMHW7hsWhsUJ7Wuhi6IiWVvEm6fd8SESW6LR89cVVg=
|
||||
SHA256 (cargo/matches-0.1.9.tar.gz) = o+N4tmoGDUiUe1kHN7MKG+dnBsjde4ug8v45icaKhT8=
|
||||
SHA256 (cargo/maybe-uninit-2.0.0.tar.gz) = YDAuTbOmHacMDLeZGXYkg2LzAxnoiFDEh7m5W78FngA=
|
||||
SHA256 (cargo/memchr-2.4.1.tar.gz) = MIzDm+Abc9DRj4Kg57Kj34UkX4Svlv3dxdIC0n5HuGo=
|
||||
SHA256 (cargo/memoffset-0.6.5.tar.gz) = WqNh1Prqk2AwZKAnQV8HvY4dXIjJ+/aL9WooVCj9ec4=
|
||||
SHA256 (cargo/migrations_internals-1.4.1.tar.gz) = K0/ITkrwILg3Ap4BeWb4ahwtXoPmS1iZY9UEdSWZWGA=
|
||||
SHA256 (cargo/migrations_macros-1.4.2.tar.gz) = l1PxKQn9jZI/da5cMljK4e08jsBS4bOMk8IabRV/eJw=
|
||||
SHA256 (cargo/mime-0.3.16.tar.gz) = KmDHzlAcceA6nJwNNbhhQTrpJb2XnMek4w0GAGmqrI0=
|
||||
SHA256 (cargo/minimal-lexical-0.2.1.tar.gz) = aDVMXGvTbXP/P+zrBe+lm2rLdiZhf0livjIqgl5h95o=
|
||||
SHA256 (cargo/miniz_oxide-0.4.4.tar.gz) = qSUY6YwHhYa8bJNAKK3MpMkqU9apWBlt6DUXCgHYTks=
|
||||
SHA256 (cargo/mio-0.6.23.tar.gz) = Sv1m9bkb8qO8E/rQ4hyu2sFoykxwdQTnVYVkiugOTMQ=
|
||||
SHA256 (cargo/mio-0.7.14.tar.gz) = gGe0BP6Xxwgp8ILeyLz09xIl1+rqHYZFNJy3b6BiBcw=
|
||||
SHA256 (cargo/mio-extras-2.0.6.tar.gz) = UkA/4pABLOd3xGJnkMiVEySiueMxazFDd5xysCl0Lxk=
|
||||
SHA256 (cargo/miow-0.2.2.tar.gz) = 69gIQkFmMi1KONqHCDv93TrEwTEzTtVYVhEusG1GlE0=
|
||||
SHA256 (cargo/miow-0.3.7.tar.gz) = ufHFsCXNqHb2bvQ6ET+R68n0zO80hDAA4K3267q4TiE=
|
||||
SHA256 (cargo/multer-2.0.2.tar.gz) = X4815odWHVwWZ1kJEeZpioy3FKE0p1BXGKGC57ydODY=
|
||||
SHA256 (cargo/mysqlclient-sys-0.2.5.tar.gz) = 9hs4FSi6KTAFxCpAndc9A0UI4nO/kEgfF+wulkpulps=
|
||||
SHA256 (cargo/native-tls-0.2.8.tar.gz) = SLqfdxm1oPQvM4kHYUKF+1/XDlOFgUH2mJih+3IDsk0=
|
||||
SHA256 (cargo/net2-0.2.37.tar.gz) = ORYw0StoACrh4l6Pl0MGR0lmVQrYLaxohvuJEMGVaK4=
|
||||
SHA256 (cargo/new_debug_unreachable-1.0.4.tar.gz) = 5KJHNiFuwxYEeh/EJS4n2rsEIYqko/N8bn3b8fl4K1Q=
|
||||
SHA256 (cargo/nix-0.23.1.tar.gz) = n4ZjF6y9OiQHEMY/Bl/7Hk/UZiWQRcy1BBMLf2aPNcY=
|
||||
SHA256 (cargo/no-std-compat-0.4.1.tar.gz) = uThT2m2EwuPH1zDWRz6IF2kt2Jvjh+sBuU1/EI7LW4w=
|
||||
SHA256 (cargo/nom-4.1.1.tar.gz) = nDSfaPJfWWufRM8OfGl1KlxjOwVQw/+ElRi/ugIzd0o=
|
||||
SHA256 (cargo/nom-7.1.0.tar.gz) = Gx0R4e84nHb+W4G8ry6jLPiLYrxJThn0k9CzDnqTAQk=
|
||||
SHA256 (cargo/nonzero_ext-0.3.0.tar.gz) = OL+WRcixRWmLsLGKRjfcrLxCHqSb7yMX5P2AZaOHzyE=
|
||||
SHA256 (cargo/ntapi-0.3.6.tar.gz) = P2u5AuQ3tthuA8zhCn4q9mIpLF3+8jtliZ6jrJNUrUQ=
|
||||
SHA256 (cargo/num-bigint-0.2.6.tar.gz) = CQx/mZjuD/Zapbcj5ACfeyF3B/H7XqVRMpzE1iMfswQ=
|
||||
SHA256 (cargo/num-derive-0.3.3.tar.gz) = h2pT//mOA6k2pnSylWiw5gXwayk3LCSJ/03iPxlJdD0=
|
||||
SHA256 (cargo/num-integer-0.1.44.tar.gz) = 0sxpimO1SacLwEcHPSlJzOJ80cewpKhi0IqAMbwoAds=
|
||||
SHA256 (cargo/num-traits-0.2.14.tar.gz) = mmSx7FzaJYbihHIkhtgCrPH329xiPiv8V+Zcoc0JkpA=
|
||||
SHA256 (cargo/num_cpus-1.13.1.tar.gz) = GeZFJuve4YI0FXLlDprQOWWqUQzZRCekVJRI8oXpV6E=
|
||||
SHA256 (cargo/num_threads-0.1.3.tar.gz) = l7qZumOT4sNzR5FAG2aQLZgcsDvxkK9nTKaZSbbV+xU=
|
||||
SHA256 (cargo/object-0.27.1.tar.gz) = Z6wdP5odNhb9mmDI10KW8iQGoji2py9cwebzFN9P+/k=
|
||||
SHA256 (cargo/once_cell-1.9.0.tar.gz) = 2jJRXZ9ubkide8nYTHGwYNtyR9wDW75E6siM+HSG2NU=
|
||||
SHA256 (cargo/opaque-debug-0.2.3.tar.gz) = KDnnlmXxMb21eC5R8sbJWZwTPGCYmCpUx5Q1i/QyUpw=
|
||||
SHA256 (cargo/opaque-debug-0.3.0.tar.gz) = YkqDQMOMG4D9VJCHhi2kukPgiFivAlsjblCbZkn8E9U=
|
||||
SHA256 (cargo/openssl-0.10.38.tar.gz) = DHriIiNMMN8UEVTxWQZsUJP/c7YyBNzacSHrCC/FapU=
|
||||
SHA256 (cargo/openssl-probe-0.1.5.tar.gz) = /wEaMCw5alGXaSQx/BlIAZFUr8F4uvfY43NnRCpGAc8=
|
||||
SHA256 (cargo/openssl-src-111.17.0+1.1.1m.tar.gz) = BdajNqvRCBQZj2biqRzNczZhHzAzQRnKjOMAU2Zm/PQ=
|
||||
SHA256 (cargo/openssl-sys-0.9.72.tar.gz) = fkYQnDg2AnNfoKLkjdK3yJKwSOG/aeXDsdgEt9nCA8s=
|
||||
SHA256 (cargo/owning_ref-0.3.3.tar.gz) = zfhPQWOeA3tIT5NDOqOJeGO1Ye1lxuWccHPXxWFxDzc=
|
||||
SHA256 (cargo/parity-ws-0.11.1.tar.gz) = WYPTkprVDxLD65pnQ/GdaRhm7NRNp0wKMwjD+KVt8MY=
|
||||
SHA256 (cargo/parking_lot-0.11.2.tar.gz) = fRe3gDamBmO3l63q7kb1yd/ruGlI0SVQB6HWvgJx/5k=
|
||||
SHA256 (cargo/parking_lot-0.4.8.tar.gz) = FJ2PW5fzwRM+PPzYiGRJlZ6Fa1V/8oHikrcz18aeAF4=
|
||||
SHA256 (cargo/parking_lot_core-0.2.14.tar.gz) = TbGozPc0p7znlMwZs98G7YerLzkHA2tpPGj1a01FN/o=
|
||||
SHA256 (cargo/parking_lot_core-0.8.5.tar.gz) = 126OFJO8rA0nZsQnN/NEWPHIxQwNI7yyTqlTr/snMhY=
|
||||
SHA256 (cargo/parse-zoneinfo-0.3.0.tar.gz) = xwXyVkScYNpl4R/2Ym4MFqCguWqqNI3mE3aySbw0D0E=
|
||||
SHA256 (cargo/paste-1.0.6.tar.gz) = B0QSav4abdfzlMtQpxbb4IbLBuJV5T2NAYXYKCg1j7U=
|
||||
SHA256 (cargo/pear-0.2.3.tar.gz) = FeRCQcXkyGjj6qeLfBhIyt1jRO1PVNApgy0ytBWlhwI=
|
||||
SHA256 (cargo/pear_codegen-0.2.3.tar.gz) = gqXKZDwjA+y3QNUGU53roYnhbydUBApCkBzYEF0CgtA=
|
||||
SHA256 (cargo/pem-0.8.3.tar.gz) = /VbL0h/qSNDEQLQc1pxYn6rK3gjJktmlTkcbedD9E+s=
|
||||
SHA256 (cargo/percent-encoding-1.0.1.tar.gz) = MQEN0uGsM9W0altBNJUjmIKBPgNp+O2KXiZvFzYC+DE=
|
||||
SHA256 (cargo/percent-encoding-2.1.0.tar.gz) = 1P1WQdAcjxiiPae2/ikpj/S1WvzM33iXOyTPMXX+4y4=
|
||||
SHA256 (cargo/pest-2.1.3.tar.gz) = EPSHKulNe5CuSHVN8i/UKtUs50C483CwPaSDVBdAPlM=
|
||||
SHA256 (cargo/pest_derive-2.1.0.tar.gz) = gz0a5VjcYB6aYDZkIRlqjZS8CsmAR20LZ+HQmI1ystA=
|
||||
SHA256 (cargo/pest_generator-2.1.3.tar.gz) = mbjbYm4x5bgXh7l4NCV2loGzRwEcxZRx4z6kbS6gz1U=
|
||||
SHA256 (cargo/pest_meta-2.1.3.tar.gz) = VL5uQE9TFweYEvyPn1J53jdtiFaSniHBhOz2u9aSoR0=
|
||||
SHA256 (cargo/phf-0.10.1.tar.gz) = +rvx6tilvLwg9fi5Oe4/Ww9vKBtq00aLhGVrZYtFUlk=
|
||||
SHA256 (cargo/phf-0.8.0.tar.gz) = PfthIy40/LYz9D0SxY+Dwd+Cli3N+lZaToZv/Bfa/hI=
|
||||
SHA256 (cargo/phf_codegen-0.10.0.tar.gz) = T7HDqLxN1OXPzim0T/wUvt0u4pRVmilOKk1MnppqE80=
|
||||
SHA256 (cargo/phf_codegen-0.8.0.tar.gz) = y//uYVhbBBGEDT7Ok1zOnLYyHwHEVHfTAGZJjNXhqBU=
|
||||
SHA256 (cargo/phf_generator-0.10.0.tar.gz) = XVKFiTu164LmqvXVnukJoGoWc3qJcJhN13RrqSg0mNY=
|
||||
SHA256 (cargo/phf_generator-0.8.0.tar.gz) = FzZ/DMhvLSWAKywm7linsj+uzPeKOWCUwT3O0NAYJSY=
|
||||
SHA256 (cargo/phf_shared-0.10.0.tar.gz) = tnlq13Gs3AEj0qiNxCi1447yRFZ0PdsXRO1ij5gVwJY=
|
||||
SHA256 (cargo/phf_shared-0.8.0.tar.gz) = wAz4uer+aN3l6eqizvjuhKkzakfVZuxVyhZYljO2Wvc=
|
||||
SHA256 (cargo/pico-args-0.4.2.tar.gz) = 24vNlst0DQMUnLrVUY25/YcSahCrUZwBGJOxdUE0xGg=
|
||||
SHA256 (cargo/pin-project-lite-0.2.8.tar.gz) = 4oD753zGLJFSclnpRCFT9GiHNnSNJGYBJihjKXQrTGw=
|
||||
SHA256 (cargo/pin-utils-0.1.0.tar.gz) = i4cNjBUbby+5PoShMUYTjwXQLtEcfnxU+IJqqvfJ8YQ=
|
||||
SHA256 (cargo/pkg-config-0.3.24.tar.gz) = WIk/dRybBBKHGgmr1i7NKgApjGyDvvoiPvmMUq70DL4=
|
||||
SHA256 (cargo/ppv-lite86-0.2.16.tar.gz) = 65+ebiM+XEo1VZphe/QKTsRH2y6EwgtVpvgxZ7fleHI=
|
||||
SHA256 (cargo/pq-sys-0.4.6.tar.gz) = asJe7loFgvRaZ+g341DXhOcAO9KaX0YHlncgYcpJ/9o=
|
||||
SHA256 (cargo/precomputed-hash-0.1.1.tar.gz) = klOD76NGcwR4+0g42+kTfSpHZ1rXicVG0VCm4d1Ksxw=
|
||||
SHA256 (cargo/proc-macro-hack-0.5.19.tar.gz) = 2/DEi8HZE3WuXDzYHjci3/Grz4GjCWAkBkDSI/Wf4OU=
|
||||
SHA256 (cargo/proc-macro2-1.0.36.tar.gz) = xzQtWIP7zK4cw3ojU7Cch8mw86/XP1+5u6aHofczsCk=
|
||||
SHA256 (cargo/proc-macro2-diagnostics-0.9.1.tar.gz) = S/KXJtZ0ZNSfpiJKHQeTaowIuz+6cnx0k/bPFhb9qto=
|
||||
SHA256 (cargo/psl-types-2.0.10.tar.gz) = 6O2nxi2eyq/fi2I3TABt4K32Fmaulqlrp0o3E0qk5HA=
|
||||
SHA256 (cargo/publicsuffix-2.1.1.tar.gz) = KSly7a1rvswTerhMXjZCGkpsl56jHTzHNUDdBDFbM+E=
|
||||
SHA256 (cargo/quanta-0.9.3.tar.gz) = IK/nFCktXoedixJ0CqIjxqiPEYr0GHDothluOaAiOKg=
|
||||
SHA256 (cargo/quick-error-1.2.3.tar.gz) = odAZQdgvoqtQvh555nFCid183njrpMB0vFpDdPZQ3+A=
|
||||
SHA256 (cargo/quick-error-2.0.1.tar.gz) = qZNVXzHlpgn2F8EttiUN7crBsKhQdpEsQ25vybLI5qM=
|
||||
SHA256 (cargo/quote-1.0.15.tar.gz) = hk0+lqiZhjE2/G6Z89fK4ona/kO/LFrBm3DfchDAoUU=
|
||||
SHA256 (cargo/quoted_printable-0.4.5.tar.gz) = P+4tzln3pDQY4zgsdmVUxhTgalUtU6jwfvSZ6kszLA8=
|
||||
SHA256 (cargo/r2d2-0.8.9.tar.gz) = VFxbwriAlzycEOQGdBhAegzKowkXgdFnHUbrNRB8sm8=
|
||||
SHA256 (cargo/rand-0.4.6.tar.gz) = VShAuXATsaJpksEerDS913jkZGAaTCBUtfC/98Z2EpM=
|
||||
SHA256 (cargo/rand-0.7.3.tar.gz) = amsWedSbJLv+DIA0KaoYdEcvUNmzYxMfDon8NWtUTQM=
|
||||
SHA256 (cargo/rand-0.8.4.tar.gz) = LnVzYy5kVM9rmdeqxMzKVL4G2gWsou90I9ItJ9TUvNg=
|
||||
SHA256 (cargo/rand_chacha-0.2.2.tar.gz) = 9MjthWJ5yXNyBr9yW/NpNdhmbq16pptSvlWvNp0ZNAI=
|
||||
SHA256 (cargo/rand_chacha-0.3.1.tar.gz) = 5sEKY6D6MiUr5J0h53CdTUuvjSMcLbzh6qgUG5sSfYg=
|
||||
SHA256 (cargo/rand_core-0.3.1.tar.gz) = em/euDsHXoJm3Mh2LCJ3b2h3pjEREh9fjHQR5b5+7Us=
|
||||
SHA256 (cargo/rand_core-0.4.2.tar.gz) = nDOjxEygX6bxgH2OZ0Pzgk6FCb7KYlZpYzvgrL31Cdw=
|
||||
SHA256 (cargo/rand_core-0.5.1.tar.gz) = kL3lKW/IkbDO8SptA93MwWLOeyr/VBYK+TOPjUDfbRk=
|
||||
SHA256 (cargo/rand_core-0.6.3.tar.gz) = 008UCPVSlEU3kMSLLx67scW0t1Y+sfQYvPz9uwbrtOc=
|
||||
SHA256 (cargo/rand_hc-0.2.0.tar.gz) = yjEpr3uSoXES1ZrUmMb4Hq9GMlN2a5A5bTnqejnWYTw=
|
||||
SHA256 (cargo/rand_hc-0.3.1.tar.gz) = 1R6fWW3iJ/2i6myEYH9VWOGW7q9DyYa3JLpPuP30l+c=
|
||||
SHA256 (cargo/rand_pcg-0.2.1.tar.gz) = FqvQwbY56etNfFDAuBALDQ+Em+I0mCnHQP6ObrSBZCk=
|
||||
SHA256 (cargo/raw-cpuid-10.2.0.tar.gz) = kp9U4paR1OapzFWEed5w23qj2YzW/nq4bXUHqiiGudI=
|
||||
SHA256 (cargo/rdrand-0.4.0.tar.gz) = Z4BU63coa1FYG6Q2IMyRGr8CdYyR+T9Hl2eu0PkEWLI=
|
||||
SHA256 (cargo/redox_syscall-0.2.10.tar.gz) = g4PzljkmnN6X0lWjK9towEczcpVBSUDGi90wwuEyA/8=
|
||||
SHA256 (cargo/ref-cast-1.0.6.tar.gz) = MA8qg12AhzTuKV1FAHray567Kd064kJKz6F5MMrlQdo=
|
||||
SHA256 (cargo/ref-cast-impl-1.0.6.tar.gz) = TDjjrs0rIcs5WWN7iDuzcUvH5D8CaLminTdD7j5VzdI=
|
||||
SHA256 (cargo/regex-1.5.4.tar.gz) = 0HqGKTWetW8eL7FlK7BCEsByqHumhUagQGXVJWc6xGE=
|
||||
SHA256 (cargo/regex-automata-0.1.10.tar.gz) = bCMNc/uNjBucCzE1xRQqis7joFWPuNtc8ctl+NeGITI=
|
||||
SHA256 (cargo/regex-syntax-0.6.25.tar.gz) = 9JcoWITz/P9CT/yTPlbXy8pRHe8MmDGn+bX2FT48yJs=
|
||||
SHA256 (cargo/remove_dir_all-0.5.3.tar.gz) = Os0SVmVCKXOjOsnT3S34XtrQ9K6bANr7GgXkOp9e+Oc=
|
||||
SHA256 (cargo/reqwest-0.11.9.tar.gz) = h/JC8UiKU5p5usbb58hgmuQ7eRS3c2IQ8jmjfMyzJSU=
|
||||
SHA256 (cargo/resolv-conf-0.7.0.tar.gz) = UuRDlNIIbQEFUbFLU7HyTjFkdXDNHesDeeLCGzKaugA=
|
||||
SHA256 (cargo/ring-0.16.20.tar.gz) = MFPPUuI2o+10bfx0WqnKzxt5HYRr2vQS9gqNfW4XyPw=
|
||||
SHA256 (cargo/rmp-0.8.10.tar.gz) = T1Xl+hRGxNXdH12u7SpP4ZMHF3GiY2J00NejsIKqetY=
|
||||
SHA256 (cargo/rmpv-1.0.0.tar.gz) = 3ogTs6L5XFE4/lklv7h4QXXYjWv/BZuozgkKqJExl1Q=
|
||||
SHA256 (cargo/rustc-demangle-0.1.21.tar.gz) = fvA+CisVDHqQ0B+vYlTJxIpB6V+yqMKsHG8NK5rvw0I=
|
||||
SHA256 (cargo/rustc_version-0.2.3.tar.gz) = E44+Cstsn7JYsZtny4q9Y8AGedKFGAXqFRRlRk/pAwo=
|
||||
SHA256 (cargo/rustls-0.19.1.tar.gz) = Ne22df7uOa7JyZ+l/5hQgZlaBtWUEUrhTL55ete3ptc=
|
||||
SHA256 (cargo/rustversion-1.0.6.tar.gz) = 8sw46Ppmbi3jxKun7etf/FJGwcLtDj0X5WCu66c2sj8=
|
||||
SHA256 (cargo/ryu-1.0.9.tar.gz) = c7S3UMeCllwhG0LwIvWa8fvOq90CZiNxTxBBUvHsFJ8=
|
||||
SHA256 (cargo/same-file-1.0.6.tar.gz) = k/wdw6qpv+2V4C5urau0uvfjB4sL0bTXtrC2g3iQBQI=
|
||||
SHA256 (cargo/schannel-0.1.19.tar.gz) = jwW6YJwjTmC+4NVH/pSkx+nacz0cliz25Z76TNnIvHU=
|
||||
SHA256 (cargo/scheduled-thread-pool-0.2.5.tar.gz) = 3G90/RIEBz+gLV1daL7IAhvkw4aQthJksv20gIPQ59c=
|
||||
SHA256 (cargo/scoped-tls-1.0.0.tar.gz) = 6mqSkOPJzw8YFF73/6YtaO4L9fzWUQF+WG3H/V2kSMI=
|
||||
SHA256 (cargo/scopeguard-1.1.0.tar.gz) = 0pqwxtP8Dukv5m4tmfcA6rF6jVfRwdO3SDgPsguqeM0=
|
||||
SHA256 (cargo/sct-0.6.1.tar.gz) = s2K4OJjg5p84UVuC7hWqgGNr7+R8O209iakR54/CKM4=
|
||||
SHA256 (cargo/security-framework-2.6.0.tar.gz) = P+15SLbGisu24gwzT1WtY13A91UGlj3kRkKJ+9OwUaw=
|
||||
SHA256 (cargo/security-framework-sys-2.6.0.tar.gz) = pXMhv4vCNiCBslmZEtKWH+iZwO+t8bSy+NSLPiU7uWw=
|
||||
SHA256 (cargo/semver-0.9.0.tar.gz) = HX657ywYZhkCzEflNfm8UbeKzSVNpx03XC9nINmkBAM=
|
||||
SHA256 (cargo/semver-parser-0.7.0.tar.gz) = OIod8lPsoIVQvvbHI5LP58MJFL9B31Jptoy9b/j1cKM=
|
||||
SHA256 (cargo/serde-1.0.136.tar.gz) = zjHiSwHh5STflvHC/dBUQF+Nc3YkmlEQiG+0tlhIR4k=
|
||||
SHA256 (cargo/serde_cbor-0.11.2.tar.gz) = K+8uv95Fb7drvPn1kxUzPezE/aCytEtCAkPBHg9ewfU=
|
||||
SHA256 (cargo/serde_derive-1.0.136.tar.gz) = CFl+cVL80wb0GDjtPje+nq7tK2HELiEXJmpVT6tGYvk=
|
||||
SHA256 (cargo/serde_json-1.0.78.tar.gz) = 0jwbpM8O/US+MgF3CSgLMtHOpcPxJ1w7bZ6LxU91gIU=
|
||||
SHA256 (cargo/serde_urlencoded-0.7.1.tar.gz) = 00kcFHFcoilMTWqI8V6Ec5eIwdAw7tjBEENqr9qi8/0=
|
||||
SHA256 (cargo/sha-1-0.8.2.tar.gz) = 99lNC+3pI7POph8/H/V/+M39d7QA+4+ZmJSeDPBBY98=
|
||||
SHA256 (cargo/sha-1-0.9.8.tar.gz) = mc1nE9s88WtshOBjIeBJqbn2mYJuFgltI7vMRNFdUaY=
|
||||
SHA256 (cargo/sha1-0.6.1.tar.gz) = wdoFyXRFyqEtBehIxKT8u+op50isKPfoDpsBA5IGN3A=
|
||||
SHA256 (cargo/sha1_smol-1.0.0.tar.gz) = rhpHGGwDoyF3BC5V28X9Wu6QC44AaajXD7qWqTdc0BI=
|
||||
SHA256 (cargo/sha2-0.9.9.tar.gz) = TVih4b85dJgH2Jzy2YrC36D/HLP6o4+7ZN2IrIAT2AA=
|
||||
SHA256 (cargo/sharded-slab-0.1.4.tar.gz) = kA+6gG9wxjCwo4LQ2CXheg8Z/NBZoq3h/yN7zd9EazE=
|
||||
SHA256 (cargo/signal-hook-registry-1.4.0.tar.gz) = 5R5zMo3ErAx8y9o6SU36A98d4vRgGBJ/YMaT8mSEVbA=
|
||||
SHA256 (cargo/simple_asn1-0.4.1.tar.gz) = aSyhPeV84GE6NjyMLx3pJa3ryBsEySOsYMVIi7RKvks=
|
||||
SHA256 (cargo/siphasher-0.3.9.tar.gz) = qGIyq2D6cSh9fy3a5KcHP2t6rDNjHDAVq7VW8IxtCj4=
|
||||
SHA256 (cargo/slab-0.4.5.tar.gz) = ne+R/R4Bj+AHAieR+GXQzMmzoNUAHgGqu4tA5GAAr7U=
|
||||
SHA256 (cargo/smallvec-0.6.14.tar.gz) = uX/K66ie26MPBEoQxqPMOd+cPxfXzYKd0URsqzX4kOA=
|
||||
SHA256 (cargo/smallvec-1.8.0.tar.gz) = 8t1XRiaDkQbDIKMjMIYp3LGs/JbjKoy6Nk3cYawj7oM=
|
||||
SHA256 (cargo/socket2-0.3.19.tar.gz) = Ei5XARPSjXcwZ/qyQma2Z1P26pFXWGUWlrbjXkn4jW4=
|
||||
SHA256 (cargo/socket2-0.4.4.tar.gz) = ZtcrdZQ2rjKJiirwoUIY2/Ve/eP+6xcOtiNjfbhe4eA=
|
||||
SHA256 (cargo/spin-0.5.2.tar.gz) = bmPP8yCuLFeQRnm6fLYygKPcRhOIW+r7FI7nv5qpBC0=
|
||||
SHA256 (cargo/spin-0.9.2.tar.gz) = URJUvgxbzwYrAZpsicAaZkqjWd7WL3iqcsb8E3wFkOU=
|
||||
SHA256 (cargo/stable-pattern-0.1.0.tar.gz) = RWQWjABjX4jq7UENXvqBMa+o2GmaYSyAxFWgugXCEEU=
|
||||
SHA256 (cargo/stable_deref_trait-1.2.0.tar.gz) = qPEScpUS+ORC2B+VqKfd8rfGuKGm9QmpWGQUKzDKstM=
|
||||
SHA256 (cargo/standback-0.2.17.tar.gz) = 4RP7bz3geiQ9Q0pW7G8Ybf1RywhEgjn+e8rnP4f/KP8=
|
||||
SHA256 (cargo/state-0.5.2.tar.gz) = h89PU2nm0wRLXjZclpD0UVFqyPCVQIRiK0nqP94vbeU=
|
||||
SHA256 (cargo/stdweb-0.4.20.tar.gz) = 0CJJaxYoE0i1LQ4wrpngGnPXN7L0XTj+1O33n5MlodU=
|
||||
SHA256 (cargo/stdweb-derive-0.5.3.tar.gz) = yHpgpA/MyEvvBlI0W7u74gpgW/XQzoFxn8R29cA7UO8=
|
||||
SHA256 (cargo/stdweb-internal-macros-0.2.9.tar.gz) = WPpf9q0NmNH/qMsRWJK25p1neZ9nY+FiocnbQh3CLhE=
|
||||
SHA256 (cargo/stdweb-internal-runtime-0.1.5.tar.gz) = ITcBujNwdE3NGhKWDKpIQ7PWi00cCl1XXg1lsu6dFsA=
|
||||
SHA256 (cargo/string_cache-0.8.2.tar.gz) = kj8PObYmfTfSPOca5yNWAhNLJQrOcV3SyQQhmY3awMY=
|
||||
SHA256 (cargo/string_cache_codegen-0.5.1.tar.gz) = 8kyOXhnSKnJmJvGl4W/hWxMtzyHRAXf6WkXOeWKZa5c=
|
||||
SHA256 (cargo/subtle-2.4.1.tar.gz) = a97zLoFQwqCBEQtCdy/+fXyQMrYGvCJsgmD9l+CXZgE=
|
||||
SHA256 (cargo/syn-1.0.86.tar.gz) = imWz9P+gCS6Yh2adsOrgeUHwI5katY6kTaj+ji1RHGs=
|
||||
SHA256 (cargo/syslog-4.0.1.tar.gz) = oGQRQrQIHT1Evv+k7v1zRqIozfke1wGG2yyizvdi0yc=
|
||||
SHA256 (cargo/tempfile-3.3.0.tar.gz) = XNse9OrurdyPvTceUBcFcGSvCRGQLvNrOYAfZ8xteeQ=
|
||||
SHA256 (cargo/tendril-0.4.2.tar.gz) = qe9VfLOXpPClo6Yo8GUV94Vj8iCeZNRwVdncYFK/XjM=
|
||||
SHA256 (cargo/thiserror-1.0.30.tar.gz) = hUur5S5N8WU3BrmPz8BYQwEAObQGh1kwpw5NlkTlxBc=
|
||||
SHA256 (cargo/thiserror-impl-1.0.30.tar.gz) = qjL9P2J/Nn/hb4k+JZeuPAUCD4u6Jmak5upz03flcUs=
|
||||
SHA256 (cargo/thread_local-1.1.4.tar.gz) = VRbCe3gxHFC/QsBxQlxWCseZsRwwsx+H4wgZZf5eAYA=
|
||||
SHA256 (cargo/threadpool-1.8.1.tar.gz) = 0FDmCzPUHBkQizLOoyFkAzqQE/47RsvURXVZv793r6o=
|
||||
SHA256 (cargo/time-0.1.44.tar.gz) = bbnmkUq4sa4cJgpK56SbbFYRtAMopzWyGGJWdoXnMlU=
|
||||
SHA256 (cargo/time-0.2.27.tar.gz) = R1Kpf47r1oVP+R8cGCTNYWBiasS9RCh/f06iA1oCokI=
|
||||
SHA256 (cargo/time-0.3.7.tar.gz) = AEy8mPMPojPGGji8d+lqkQbmXIjy077xgq6VICfldT0=
|
||||
SHA256 (cargo/time-macros-0.1.1.tar.gz) = lX6cbibxLLbQ3X/HdrtnpwYxLnKZrtdMjdWxfrsn4vE=
|
||||
SHA256 (cargo/time-macros-0.2.3.tar.gz) = JesMo0aPwKzBGCh4Z5f275qhVV5KIRpg1kzI5NG+R9Y=
|
||||
SHA256 (cargo/time-macros-impl-0.1.2.tar.gz) = /TwUGhtDGU8/VqFBEiXfhkbFV4HV8m24JbPZhQfrSC8=
|
||||
SHA256 (cargo/tinyvec-1.5.1.tar.gz) = LBwdWkK2JFUgwklUnsJnGAvq/8wGFUAayOMYU9S22NI=
|
||||
SHA256 (cargo/tinyvec_macros-0.1.0.tar.gz) = zadNp+GmZPeVux+Kh+xAb7iaAlIs9uUGINAWrdbbv1w=
|
||||
SHA256 (cargo/tokio-1.16.1.tar.gz) = DCemS2Jd5tMJ6MV3FrqTAh3M8bO1yX7dbT3S0hNa/Ao=
|
||||
SHA256 (cargo/tokio-macros-1.7.0.tar.gz) = tVf3L0SMURqXniVk5V105sRDL8lv9PYkG8a97TQmQ7c=
|
||||
SHA256 (cargo/tokio-native-tls-0.3.0.tar.gz) = 99mVZgvSt/jBVoQUwRJgdsE/u3JcQBEtwBILeOubcXs=
|
||||
SHA256 (cargo/tokio-rustls-0.22.0.tar.gz) = vGhE3nLlffGYAFSzi+Op9HAqukhYvmTdcAGBqKbQ4bY=
|
||||
SHA256 (cargo/tokio-socks-0.5.1.tar.gz) = URZd+gKdKmWWlBOmzJbzVLhrRkSYcC8XSk76E2CP2MA=
|
||||
SHA256 (cargo/tokio-stream-0.1.8.tar.gz) = UBRUhO//iBi1zNJWaX82hj9Yfags+LQJxTrfHoQHmOM=
|
||||
SHA256 (cargo/tokio-util-0.6.9.tar.gz) = npnhmD5dN2zY60tmYE0umeefW9mIwwVYkdzYyeJgTMA=
|
||||
SHA256 (cargo/toml-0.5.8.tar.gz) = oxFClwgmcz34JB7zXcBA75jGeasU18PlTYJwmbOs7Ko=
|
||||
SHA256 (cargo/totp-lite-1.0.3.tar.gz) = sYAJ6L50v7LizFmmPQeNlcBChYocoRKKKU4fnOIlFIs=
|
||||
SHA256 (cargo/tower-service-0.3.1.tar.gz) = Ng39HW0w4F/aMqziyMcOnAqdpxMnV3f1pNu4oYk5MMY=
|
||||
SHA256 (cargo/tracing-0.1.29.tar.gz) = N1pjkjLK8w7fx46NibLUw3VRU5Pnr34W8BzZaRf7IQU=
|
||||
SHA256 (cargo/tracing-attributes-0.1.18.tar.gz) = 9PSAuPgVEugl8zetUelMHrXTu98rNj3NAeKxmp/+P44=
|
||||
SHA256 (cargo/tracing-core-0.1.21.tar.gz) = H07WVje4OQdwgUCD0gdW+Hv6LCG/LxELq9xUODUXRuQ=
|
||||
SHA256 (cargo/tracing-log-0.1.2.tar.gz) = ppI0d6SOQcGVHxmZ74u1owI+tyPOra/nj/tl3DZnYeM=
|
||||
SHA256 (cargo/tracing-subscriber-0.3.7.tar.gz) = UxLzJf41iOJ3QV9abMofTMrQ8kjEzVpL0zAy1yhqvCI=
|
||||
SHA256 (cargo/trust-dns-proto-0.20.3.tar.gz) = rQ1/XbQ4GZpuJgnevj9p+AjQdOCiiI7gvMtF/iNNA/Q=
|
||||
SHA256 (cargo/trust-dns-resolver-0.20.3.tar.gz) = 9q0XtgimS9BzXme94WsGNviqhZH4MaJdGEQ+0Appl3A=
|
||||
SHA256 (cargo/try-lock-0.2.3.tar.gz) = WVR7znHZw4uD2cDpK2BmxCUzcfFQBd7www2WV/UMdkI=
|
||||
SHA256 (cargo/typenum-1.15.0.tar.gz) = 3PgaxZ7cF8yGl/8xHo9e8tmfy9mBezTOxm+QtsPf2Yc=
|
||||
SHA256 (cargo/u2f-0.2.0.tar.gz) = 4vKFOSNmGQxNRoI0WPRUOsDzUXR1nHjoDFuqOeH3qk8=
|
||||
SHA256 (cargo/ubyte-0.10.1.tar.gz) = QnVruecIhV3i+KmBlWQ9/zGpfwSF2Q2EZ7Odwkvp6P4=
|
||||
SHA256 (cargo/ucd-trie-0.1.3.tar.gz) = Vt7hhTCbUNHxG/7e8P5tA2hC4/t3QTq+8p+PjRxdTBw=
|
||||
SHA256 (cargo/uncased-0.9.6.tar.gz) = W67tcyfiUFSIm5vU+XXzLl9MXUNAQtWats1BQsCnbtA=
|
||||
SHA256 (cargo/unicode-bidi-0.3.7.tar.gz) = GgFARmPj20Nu0nRtn+/vZA2GjtrjzOuBw7jVcy/aZ48=
|
||||
SHA256 (cargo/unicode-normalization-0.1.19.tar.gz) = 1UWQkylBqekmbwgy3u2E6+G/LkyeSjVU05PRj16FS/k=
|
||||
SHA256 (cargo/unicode-segmentation-1.8.0.tar.gz) = iJWEmpSeeEXga9bcGqUXMaEDxCcHAQpbWRwAOPtzOFs=
|
||||
SHA256 (cargo/unicode-xid-0.2.2.tar.gz) = jMuC1h+ApmPv4feHpRsWtaUeMxTWrDZbCGOfUjh7M/M=
|
||||
SHA256 (cargo/untrusted-0.7.1.tar.gz) = oVbGhMkep9YmJlCbzjy04dntXE2Xj3tDUmWPlqTCa0o=
|
||||
SHA256 (cargo/url-1.7.2.tar.gz) = 3U58DVMSZjaVGaSqTzmddIvTcEOwC94eT/H2ChILNVo=
|
||||
SHA256 (cargo/url-2.2.2.tar.gz) = pQfDg7LTO1/DXRhh535rOD0Viy2l4U/lG4Pf7fb9V4w=
|
||||
SHA256 (cargo/utf-8-0.7.6.tar.gz) = CcyO5y0qm+zy8v6+AgW77Y/GYVt8tCmtBi3Ht93QNqk=
|
||||
SHA256 (cargo/uuid-0.8.2.tar.gz) = vFz5jYGGJEQUyEgBfw4mdrP8tGgH9maKl9/mc1mjxLc=
|
||||
SHA256 (cargo/vcpkg-0.2.15.tar.gz) = rM1Opi97t6gv4jBm+wlX1I72d/buuCFfNy9S5IuzJCY=
|
||||
SHA256 (cargo/version_check-0.9.4.tar.gz) = SYdLUWe2XXGTuKuhVn9cfZPQAcr8NGAM7gA+2nh+SD8=
|
||||
SHA256 (cargo/walkdir-2.3.2.tar.gz) = gIzyc1zUtoZhE/ZIt5HGrcVxRTe8Ii2TR7sgM4b/2lY=
|
||||
SHA256 (cargo/want-0.3.0.tar.gz) = HOipaMsc0RDRNv+LgZpVbW+22Rk2PGFTT2hgx+sXK6A=
|
||||
SHA256 (cargo/wasi-0.10.0+wasi-snapshot-preview1.tar.gz) = GhQ1l8p8d5Pv95Te81LUF5KpPEgesQQkI/9/9yuiwx8=
|
||||
SHA256 (cargo/wasi-0.9.0+wasi-snapshot-preview1.tar.gz) = zM3fMlVP7MastYX4KjKnLii0j4xMGIPd/u6qlvfY5Rk=
|
||||
SHA256 (cargo/wasm-bindgen-0.2.79.tar.gz) = JfGvdCPYWIo9hAaBEi5y5qJN28s/DsOFysDRLSQlbAY=
|
||||
SHA256 (cargo/wasm-bindgen-backend-0.2.79.tar.gz) = iyHA3wMPWhd/PLoi6bxDImlexD5yV9hlMCkAKQvN7co=
|
||||
SHA256 (cargo/wasm-bindgen-futures-0.4.29.tar.gz) = LrbsJwoxsdPH4ma5mXORCavOi2yH5LMfz814i2Umc5U=
|
||||
SHA256 (cargo/wasm-bindgen-macro-0.2.79.tar.gz) = L0ID1p5ApS7lI7JSmnc9X/wdwAcYAch7PScLRxuA7QE=
|
||||
SHA256 (cargo/wasm-bindgen-macro-support-0.2.79.tar.gz) = v6ijDUYgjbIEhUytu11Lr1/PgHG6W/SBkMPlmTeWLrw=
|
||||
SHA256 (cargo/wasm-bindgen-shared-0.2.79.tar.gz) = PZWNA1xEOOKMcOQyGikRMC8QE1znipx4NMDKtBI9BqI=
|
||||
SHA256 (cargo/web-sys-0.3.56.tar.gz) = wGCzGfKd0lck8JoroUGPFC9Tmyvpn79NLVqPczCvuOs=
|
||||
SHA256 (cargo/webauthn-rs-0.3.2.tar.gz) = kLJm7MtLMllYdvXHPqRDsFFtoLHfcsoHvAjtm6f5bsE=
|
||||
SHA256 (cargo/webpki-0.21.4.tar.gz) = uOOMBggmLEbUpWIC66vesJTO9+VgynoibGvwVRiKpOo=
|
||||
SHA256 (cargo/widestring-0.4.3.tar.gz) = wWiUAUTdIf2ARph8FqRqM9X8hO7Cnvnc3cKsnjFSa3w=
|
||||
SHA256 (cargo/winapi-0.2.8.tar.gz) = Fn3J1pSam4V/NFEnXpEcP0QlWELB96dvM8VRA6kJCHo=
|
||||
SHA256 (cargo/winapi-0.3.9.tar.gz) = XIOaZ0/NepiVLlkyQupACr6TmSdGdh44ZBQF0osA9Bk=
|
||||
SHA256 (cargo/winapi-build-0.1.1.tar.gz) = LTFe7js0rKR5ey2msT7Ygmbm1hJWKgxGOQr4KZ/Gmbw=
|
||||
SHA256 (cargo/winapi-i686-pc-windows-gnu-0.4.0.tar.gz) = rDuHxjYgQm3ZuZHlzgMp7/VFvMu7NPO+Cf9vtqtRt7Y=
|
||||
SHA256 (cargo/winapi-util-0.1.5.tar.gz) = cOxs6FuxWBUcrl5ch/lajpfSwMSwASI/M6M0485d4Xg=
|
||||
SHA256 (cargo/winapi-x86_64-pc-windows-gnu-0.4.0.tar.gz) = cS4ieEHQV8HuHNL7Ivp+WlRhro5I+iynnsQs/BkxGD8=
|
||||
SHA256 (cargo/winreg-0.6.2.tar.gz) = spht61gcT+EbYhmYpeUzYe/mtIoVEXjQzZ7v+k3GrMk=
|
||||
SHA256 (cargo/winreg-0.7.0.tar.gz) = ASDbguih4Ln7M0WlOcR4dnwASNhChgmU2WET1bZnvWk=
|
||||
SHA256 (cargo/ws2_32-sys-0.2.1.tar.gz) = 1Zzv69DIkvot1t5YHpNzAdhVLLREic3/A1xhh8tj+l4=
|
||||
SHA256 (cargo/xml5ever-0.16.2.tar.gz) = kjQWOBj9jiQY/N4zBlXnV5ANQjas2Mxw/vNF75H22GU=
|
||||
SHA256 (cargo/yansi-0.5.0.tar.gz) = n8efSh45hX/ADD9mLL8mUcdx8A6cFf4qvDQYBr1GvXE=
|
||||
SHA256 (cargo/yubico-0.10.0.tar.gz) = TTw/WEc5BZ9HnKTeEUy/4DIxV1Krs75gr7MNtAqAIWk=
|
||||
SHA256 (vaultwarden-1.24.0.tar.gz) = h80ICFcXZo7sLGAuC/cJw0K9zjnQP7N7aE8yduryXFg=
|
||||
SHA256 (vaultwarden-1.24.0.vendor.tgz) = vOyDecYO22PdHy2CX7G4FnLLwWt5/F9uRuTbb8jD/tA=
|
||||
SIZE (cargo/addr2line-0.17.0.tar.gz) = 32260
|
||||
SIZE (cargo/adler-1.0.2.tar.gz) = 12778
|
||||
SIZE (cargo/aho-corasick-0.7.18.tar.gz) = 112923
|
||||
SIZE (cargo/alloc-no-stdlib-2.0.3.tar.gz) = 10199
|
||||
SIZE (cargo/alloc-stdlib-0.2.1.tar.gz) = 6304
|
||||
SIZE (cargo/ansi_term-0.12.1.tar.gz) = 24838
|
||||
SIZE (cargo/async-compression-0.3.12.tar.gz) = 57646
|
||||
SIZE (cargo/async-stream-0.3.2.tar.gz) = 11869
|
||||
SIZE (cargo/async-stream-impl-0.3.2.tar.gz) = 4100
|
||||
SIZE (cargo/async-trait-0.1.52.tar.gz) = 25913
|
||||
SIZE (cargo/atomic-0.5.1.tar.gz) = 12817
|
||||
SIZE (cargo/atty-0.2.14.tar.gz) = 5470
|
||||
SIZE (cargo/autocfg-1.0.1.tar.gz) = 12908
|
||||
SIZE (cargo/backtrace-0.3.64.tar.gz) = 74311
|
||||
SIZE (cargo/base-x-0.2.8.tar.gz) = 10614
|
||||
SIZE (cargo/base64-0.11.0.tar.gz) = 48362
|
||||
SIZE (cargo/base64-0.12.3.tar.gz) = 57545
|
||||
SIZE (cargo/base64-0.13.0.tar.gz) = 62070
|
||||
SIZE (cargo/binascii-0.1.4.tar.gz) = 6076
|
||||
SIZE (cargo/bitflags-1.3.2.tar.gz) = 23021
|
||||
SIZE (cargo/block-buffer-0.7.3.tar.gz) = 7179
|
||||
SIZE (cargo/block-buffer-0.9.0.tar.gz) = 7108
|
||||
SIZE (cargo/block-padding-0.1.5.tar.gz) = 7342
|
||||
SIZE (cargo/brotli-3.3.3.tar.gz) = 1369025
|
||||
SIZE (cargo/brotli-decompressor-2.3.2.tar.gz) = 191197
|
||||
SIZE (cargo/bumpalo-3.9.1.tar.gz) = 77507
|
||||
SIZE (cargo/byte-tools-0.3.1.tar.gz) = 5526
|
||||
SIZE (cargo/byteorder-1.4.3.tar.gz) = 22512
|
||||
SIZE (cargo/bytes-0.4.12.tar.gz) = 46361
|
||||
SIZE (cargo/bytes-1.1.0.tar.gz) = 49640
|
||||
SIZE (cargo/cc-1.0.72.tar.gz) = 57495
|
||||
SIZE (cargo/cfg-if-0.1.10.tar.gz) = 7933
|
||||
SIZE (cargo/cfg-if-1.0.0.tar.gz) = 7934
|
||||
SIZE (cargo/chashmap-2.2.2.tar.gz) = 14824
|
||||
SIZE (cargo/chrono-0.4.19.tar.gz) = 155663
|
||||
SIZE (cargo/chrono-tz-0.6.1.tar.gz) = 585749
|
||||
SIZE (cargo/chrono-tz-build-0.0.2.tar.gz) = 5840
|
||||
SIZE (cargo/const_fn-0.4.9.tar.gz) = 12624
|
||||
SIZE (cargo/cookie-0.15.1.tar.gz) = 33649
|
||||
SIZE (cargo/cookie-0.16.0.tar.gz) = 33950
|
||||
SIZE (cargo/cookie_store-0.15.1.tar.gz) = 28265
|
||||
SIZE (cargo/core-foundation-0.9.2.tar.gz) = 26857
|
||||
SIZE (cargo/core-foundation-sys-0.8.3.tar.gz) = 17519
|
||||
SIZE (cargo/cpufeatures-0.2.1.tar.gz) = 10500
|
||||
SIZE (cargo/crc32fast-1.3.1.tar.gz) = 38655
|
||||
SIZE (cargo/cron-0.9.0.tar.gz) = 18383
|
||||
SIZE (cargo/crossbeam-utils-0.8.6.tar.gz) = 38841
|
||||
SIZE (cargo/crypto-mac-0.10.1.tar.gz) = 9531
|
||||
SIZE (cargo/crypto-mac-0.11.1.tar.gz) = 9551
|
||||
SIZE (cargo/ctrlc-3.2.1.tar.gz) = 12893
|
||||
SIZE (cargo/dashmap-4.0.2.tar.gz) = 21066
|
||||
SIZE (cargo/data-encoding-2.3.2.tar.gz) = 19159
|
||||
SIZE (cargo/data-url-0.1.1.tar.gz) = 20039
|
||||
SIZE (cargo/devise-0.3.1.tar.gz) = 902
|
||||
SIZE (cargo/devise_codegen-0.3.1.tar.gz) = 2222
|
||||
SIZE (cargo/devise_core-0.3.1.tar.gz) = 12907
|
||||
SIZE (cargo/diesel-1.4.8.tar.gz) = 191351
|
||||
SIZE (cargo/diesel_derives-1.4.1.tar.gz) = 17646
|
||||
SIZE (cargo/diesel_migrations-1.4.0.tar.gz) = 3063
|
||||
SIZE (cargo/digest-0.8.1.tar.gz) = 9449
|
||||
SIZE (cargo/digest-0.9.0.tar.gz) = 13247
|
||||
SIZE (cargo/discard-1.0.4.tar.gz) = 4700
|
||||
SIZE (cargo/dotenv-0.15.0.tar.gz) = 11668
|
||||
SIZE (cargo/either-1.6.1.tar.gz) = 13641
|
||||
SIZE (cargo/encoding_rs-0.8.30.tar.gz) = 1370089
|
||||
SIZE (cargo/enum-as-inner-0.3.3.tar.gz) = 11450
|
||||
SIZE (cargo/error-chain-0.11.0.tar.gz) = 27207
|
||||
SIZE (cargo/fake-simd-0.1.2.tar.gz) = 5398
|
||||
SIZE (cargo/fastrand-1.7.0.tar.gz) = 11265
|
||||
SIZE (cargo/fern-0.6.0.tar.gz) = 299856
|
||||
SIZE (cargo/figment-0.10.6.tar.gz) = 60523
|
||||
SIZE (cargo/flate2-1.0.22.tar.gz) = 76026
|
||||
SIZE (cargo/fnv-1.0.7.tar.gz) = 11266
|
||||
SIZE (cargo/foreign-types-0.3.2.tar.gz) = 7504
|
||||
SIZE (cargo/foreign-types-shared-0.1.1.tar.gz) = 5672
|
||||
SIZE (cargo/form_urlencoded-1.0.1.tar.gz) = 8773
|
||||
SIZE (cargo/fuchsia-cprng-0.1.1.tar.gz) = 2950
|
||||
SIZE (cargo/fuchsia-zircon-0.3.3.tar.gz) = 22565
|
||||
SIZE (cargo/fuchsia-zircon-sys-0.3.3.tar.gz) = 7191
|
||||
SIZE (cargo/futf-0.1.4.tar.gz) = 11341
|
||||
SIZE (cargo/futures-0.3.19.tar.gz) = 47605
|
||||
SIZE (cargo/futures-channel-0.3.19.tar.gz) = 31940
|
||||
SIZE (cargo/futures-core-0.3.19.tar.gz) = 14666
|
||||
SIZE (cargo/futures-executor-0.3.19.tar.gz) = 17286
|
||||
SIZE (cargo/futures-io-0.3.19.tar.gz) = 8901
|
||||
SIZE (cargo/futures-macro-0.3.19.tar.gz) = 11253
|
||||
SIZE (cargo/futures-sink-0.3.19.tar.gz) = 7849
|
||||
SIZE (cargo/futures-task-0.3.19.tar.gz) = 11894
|
||||
SIZE (cargo/futures-timer-3.0.2.tar.gz) = 19879
|
||||
SIZE (cargo/futures-util-0.3.19.tar.gz) = 149240
|
||||
SIZE (cargo/generator-0.7.0.tar.gz) = 28814
|
||||
SIZE (cargo/generic-array-0.12.4.tar.gz) = 18212
|
||||
SIZE (cargo/generic-array-0.14.5.tar.gz) = 28915
|
||||
SIZE (cargo/getrandom-0.1.16.tar.gz) = 25077
|
||||
SIZE (cargo/getrandom-0.2.4.tar.gz) = 26800
|
||||
SIZE (cargo/gimli-0.26.1.tar.gz) = 716168
|
||||
SIZE (cargo/glob-0.3.0.tar.gz) = 18724
|
||||
SIZE (cargo/governor-0.4.1.tar.gz) = 132786
|
||||
SIZE (cargo/h2-0.3.11.tar.gz) = 161592
|
||||
SIZE (cargo/half-1.8.2.tar.gz) = 41874
|
||||
SIZE (cargo/handlebars-4.2.1.tar.gz) = 91920
|
||||
SIZE (cargo/hashbrown-0.11.2.tar.gz) = 85713
|
||||
SIZE (cargo/heck-0.3.3.tar.gz) = 10260
|
||||
SIZE (cargo/hermit-abi-0.1.19.tar.gz) = 9979
|
||||
SIZE (cargo/hmac-0.10.1.tar.gz) = 11120
|
||||
SIZE (cargo/hmac-0.11.0.tar.gz) = 11385
|
||||
SIZE (cargo/hostname-0.3.1.tar.gz) = 9272
|
||||
SIZE (cargo/html5ever-0.25.1.tar.gz) = 73165
|
||||
SIZE (cargo/http-0.2.6.tar.gz) = 106384
|
||||
SIZE (cargo/http-body-0.4.4.tar.gz) = 7836
|
||||
SIZE (cargo/httparse-1.5.1.tar.gz) = 26758
|
||||
SIZE (cargo/httpdate-1.0.2.tar.gz) = 10673
|
||||
SIZE (cargo/hyper-0.14.16.tar.gz) = 177577
|
||||
SIZE (cargo/hyper-tls-0.5.0.tar.gz) = 13257
|
||||
SIZE (cargo/idna-0.1.5.tar.gz) = 258735
|
||||
SIZE (cargo/idna-0.2.3.tar.gz) = 271023
|
||||
SIZE (cargo/indexmap-1.8.0.tar.gz) = 52583
|
||||
SIZE (cargo/inlinable_string-0.1.15.tar.gz) = 19290
|
||||
SIZE (cargo/instant-0.1.12.tar.gz) = 6128
|
||||
SIZE (cargo/iovec-0.1.4.tar.gz) = 8720
|
||||
SIZE (cargo/ipconfig-0.2.2.tar.gz) = 23017
|
||||
SIZE (cargo/ipnet-2.3.1.tar.gz) = 24932
|
||||
SIZE (cargo/itoa-0.4.8.tar.gz) = 11926
|
||||
SIZE (cargo/itoa-1.0.1.tar.gz) = 11059
|
||||
SIZE (cargo/js-sys-0.3.56.tar.gz) = 70520
|
||||
SIZE (cargo/jsonwebtoken-7.2.0.tar.gz) = 20176
|
||||
SIZE (cargo/kernel32-sys-0.2.2.tar.gz) = 24537
|
||||
SIZE (cargo/lazy_static-1.4.0.tar.gz) = 10443
|
||||
SIZE (cargo/lazycell-1.3.0.tar.gz) = 12502
|
||||
SIZE (cargo/lettre-0.10.0-rc.4.tar.gz) = 112201
|
||||
SIZE (cargo/libc-0.2.116.tar.gz) = 566648
|
||||
SIZE (cargo/libsqlite3-sys-0.22.2.tar.gz) = 2345859
|
||||
SIZE (cargo/linked-hash-map-0.5.4.tar.gz) = 16166
|
||||
SIZE (cargo/lock_api-0.4.6.tar.gz) = 25215
|
||||
SIZE (cargo/log-0.4.14.tar.gz) = 34582
|
||||
SIZE (cargo/loom-0.5.4.tar.gz) = 68124
|
||||
SIZE (cargo/lru-cache-0.1.2.tar.gz) = 9307
|
||||
SIZE (cargo/mac-0.1.1.tar.gz) = 4838
|
||||
SIZE (cargo/mach-0.3.2.tar.gz) = 19611
|
||||
SIZE (cargo/maplit-1.0.2.tar.gz) = 8871
|
||||
SIZE (cargo/markup5ever-0.10.1.tar.gz) = 34668
|
||||
SIZE (cargo/markup5ever_rcdom-0.1.0.tar.gz) = 25165
|
||||
SIZE (cargo/match_cfg-0.1.0.tar.gz) = 7153
|
||||
SIZE (cargo/matchers-0.1.0.tar.gz) = 6948
|
||||
SIZE (cargo/matches-0.1.9.tar.gz) = 2246
|
||||
SIZE (cargo/maybe-uninit-2.0.0.tar.gz) = 11809
|
||||
SIZE (cargo/memchr-2.4.1.tar.gz) = 64977
|
||||
SIZE (cargo/memoffset-0.6.5.tar.gz) = 7686
|
||||
SIZE (cargo/migrations_internals-1.4.1.tar.gz) = 6914
|
||||
SIZE (cargo/migrations_macros-1.4.2.tar.gz) = 3701
|
||||
SIZE (cargo/mime-0.3.16.tar.gz) = 15206
|
||||
SIZE (cargo/minimal-lexical-0.2.1.tar.gz) = 94841
|
||||
SIZE (cargo/miniz_oxide-0.4.4.tar.gz) = 49938
|
||||
SIZE (cargo/mio-0.6.23.tar.gz) = 103554
|
||||
SIZE (cargo/mio-0.7.14.tar.gz) = 87429
|
||||
SIZE (cargo/mio-extras-2.0.6.tar.gz) = 16292
|
||||
SIZE (cargo/miow-0.2.2.tar.gz) = 22044
|
||||
SIZE (cargo/miow-0.3.7.tar.gz) = 24563
|
||||
SIZE (cargo/multer-2.0.2.tar.gz) = 23220
|
||||
SIZE (cargo/mysqlclient-sys-0.2.5.tar.gz) = 27493
|
||||
SIZE (cargo/native-tls-0.2.8.tar.gz) = 24956
|
||||
SIZE (cargo/net2-0.2.37.tar.gz) = 21311
|
||||
SIZE (cargo/new_debug_unreachable-1.0.4.tar.gz) = 2561
|
||||
SIZE (cargo/nix-0.23.1.tar.gz) = 240531
|
||||
SIZE (cargo/no-std-compat-0.4.1.tar.gz) = 7600
|
||||
SIZE (cargo/nom-4.1.1.tar.gz) = 113255
|
||||
SIZE (cargo/nom-7.1.0.tar.gz) = 115647
|
||||
SIZE (cargo/nonzero_ext-0.3.0.tar.gz) = 15855
|
||||
SIZE (cargo/ntapi-0.3.6.tar.gz) = 127221
|
||||
SIZE (cargo/num-bigint-0.2.6.tar.gz) = 87275
|
||||
SIZE (cargo/num-derive-0.3.3.tar.gz) = 14545
|
||||
SIZE (cargo/num-integer-0.1.44.tar.gz) = 22216
|
||||
SIZE (cargo/num-traits-0.2.14.tar.gz) = 45476
|
||||
SIZE (cargo/num_cpus-1.13.1.tar.gz) = 14752
|
||||
SIZE (cargo/num_threads-0.1.3.tar.gz) = 6374
|
||||
SIZE (cargo/object-0.27.1.tar.gz) = 228030
|
||||
SIZE (cargo/once_cell-1.9.0.tar.gz) = 30702
|
||||
SIZE (cargo/opaque-debug-0.2.3.tar.gz) = 5643
|
||||
SIZE (cargo/opaque-debug-0.3.0.tar.gz) = 5767
|
||||
SIZE (cargo/openssl-0.10.38.tar.gz) = 207436
|
||||
SIZE (cargo/openssl-probe-0.1.5.tar.gz) = 7227
|
||||
SIZE (cargo/openssl-src-111.17.0+1.1.1m.tar.gz) = 5097946
|
||||
SIZE (cargo/openssl-sys-0.9.72.tar.gz) = 56510
|
||||
SIZE (cargo/owning_ref-0.3.3.tar.gz) = 11710
|
||||
SIZE (cargo/parity-ws-0.11.1.tar.gz) = 68268
|
||||
SIZE (cargo/parking_lot-0.11.2.tar.gz) = 39869
|
||||
SIZE (cargo/parking_lot-0.4.8.tar.gz) = 33640
|
||||
SIZE (cargo/parking_lot_core-0.2.14.tar.gz) = 22140
|
||||
SIZE (cargo/parking_lot_core-0.8.5.tar.gz) = 32466
|
||||
SIZE (cargo/parse-zoneinfo-0.3.0.tar.gz) = 76590
|
||||
SIZE (cargo/paste-1.0.6.tar.gz) = 17808
|
||||
SIZE (cargo/pear-0.2.3.tar.gz) = 19110
|
||||
SIZE (cargo/pear_codegen-0.2.3.tar.gz) = 7185
|
||||
SIZE (cargo/pem-0.8.3.tar.gz) = 9395
|
||||
SIZE (cargo/percent-encoding-1.0.1.tar.gz) = 10057
|
||||
SIZE (cargo/percent-encoding-2.1.0.tar.gz) = 9748
|
||||
SIZE (cargo/pest-2.1.3.tar.gz) = 77986
|
||||
SIZE (cargo/pest_derive-2.1.0.tar.gz) = 14049
|
||||
SIZE (cargo/pest_generator-2.1.3.tar.gz) = 14227
|
||||
SIZE (cargo/pest_meta-2.1.3.tar.gz) = 27818
|
||||
SIZE (cargo/phf-0.10.1.tar.gz) = 5406
|
||||
SIZE (cargo/phf-0.8.0.tar.gz) = 3902
|
||||
SIZE (cargo/phf_codegen-0.10.0.tar.gz) = 3402
|
||||
SIZE (cargo/phf_codegen-0.8.0.tar.gz) = 3192
|
||||
SIZE (cargo/phf_generator-0.10.0.tar.gz) = 7525
|
||||
SIZE (cargo/phf_generator-0.8.0.tar.gz) = 7604
|
||||
SIZE (cargo/phf_shared-0.10.0.tar.gz) = 4095
|
||||
SIZE (cargo/phf_shared-0.8.0.tar.gz) = 2860
|
||||
SIZE (cargo/pico-args-0.4.2.tar.gz) = 11565
|
||||
SIZE (cargo/pin-project-lite-0.2.8.tar.gz) = 27847
|
||||
SIZE (cargo/pin-utils-0.1.0.tar.gz) = 7580
|
||||
SIZE (cargo/pkg-config-0.3.24.tar.gz) = 16489
|
||||
SIZE (cargo/ppv-lite86-0.2.16.tar.gz) = 22245
|
||||
SIZE (cargo/pq-sys-0.4.6.tar.gz) = 13642
|
||||
SIZE (cargo/precomputed-hash-0.1.1.tar.gz) = 1640
|
||||
SIZE (cargo/proc-macro-hack-0.5.19.tar.gz) = 15556
|
||||
SIZE (cargo/proc-macro2-1.0.36.tar.gz) = 41411
|
||||
SIZE (cargo/proc-macro2-diagnostics-0.9.1.tar.gz) = 12305
|
||||
SIZE (cargo/psl-types-2.0.10.tar.gz) = 7929
|
||||
SIZE (cargo/publicsuffix-2.1.1.tar.gz) = 89303
|
||||
SIZE (cargo/quanta-0.9.3.tar.gz) = 23749
|
||||
SIZE (cargo/quick-error-1.2.3.tar.gz) = 15066
|
||||
SIZE (cargo/quick-error-2.0.1.tar.gz) = 14265
|
||||
SIZE (cargo/quote-1.0.15.tar.gz) = 27281
|
||||
SIZE (cargo/quoted_printable-0.4.5.tar.gz) = 6237
|
||||
SIZE (cargo/r2d2-0.8.9.tar.gz) = 17711
|
||||
SIZE (cargo/rand-0.4.6.tar.gz) = 76401
|
||||
SIZE (cargo/rand-0.7.3.tar.gz) = 112246
|
||||
SIZE (cargo/rand-0.8.4.tar.gz) = 87406
|
||||
SIZE (cargo/rand_chacha-0.2.2.tar.gz) = 13267
|
||||
SIZE (cargo/rand_chacha-0.3.1.tar.gz) = 15251
|
||||
SIZE (cargo/rand_core-0.3.1.tar.gz) = 15483
|
||||
SIZE (cargo/rand_core-0.4.2.tar.gz) = 20243
|
||||
SIZE (cargo/rand_core-0.5.1.tar.gz) = 21116
|
||||
SIZE (cargo/rand_core-0.6.3.tar.gz) = 21938
|
||||
SIZE (cargo/rand_hc-0.2.0.tar.gz) = 11670
|
||||
SIZE (cargo/rand_hc-0.3.1.tar.gz) = 11891
|
||||
SIZE (cargo/rand_pcg-0.2.1.tar.gz) = 11291
|
||||
SIZE (cargo/raw-cpuid-10.2.0.tar.gz) = 90945
|
||||
SIZE (cargo/rdrand-0.4.0.tar.gz) = 6456
|
||||
SIZE (cargo/redox_syscall-0.2.10.tar.gz) = 23582
|
||||
SIZE (cargo/ref-cast-1.0.6.tar.gz) = 10710
|
||||
SIZE (cargo/ref-cast-impl-1.0.6.tar.gz) = 7252
|
||||
SIZE (cargo/regex-1.5.4.tar.gz) = 236581
|
||||
SIZE (cargo/regex-automata-0.1.10.tar.gz) = 114533
|
||||
SIZE (cargo/regex-syntax-0.6.25.tar.gz) = 293293
|
||||
SIZE (cargo/remove_dir_all-0.5.3.tar.gz) = 9184
|
||||
SIZE (cargo/reqwest-0.11.9.tar.gz) = 139175
|
||||
SIZE (cargo/resolv-conf-0.7.0.tar.gz) = 17352
|
||||
SIZE (cargo/ring-0.16.20.tar.gz) = 5082615
|
||||
SIZE (cargo/rmp-0.8.10.tar.gz) = 23541
|
||||
SIZE (cargo/rmpv-1.0.0.tar.gz) = 27352
|
||||
SIZE (cargo/rustc-demangle-0.1.21.tar.gz) = 27920
|
||||
SIZE (cargo/rustc_version-0.2.3.tar.gz) = 10210
|
||||
SIZE (cargo/rustls-0.19.1.tar.gz) = 208143
|
||||
SIZE (cargo/rustversion-1.0.6.tar.gz) = 18380
|
||||
SIZE (cargo/ryu-1.0.9.tar.gz) = 48391
|
||||
SIZE (cargo/same-file-1.0.6.tar.gz) = 10183
|
||||
SIZE (cargo/schannel-0.1.19.tar.gz) = 42755
|
||||
SIZE (cargo/scheduled-thread-pool-0.2.5.tar.gz) = 9366
|
||||
SIZE (cargo/scoped-tls-1.0.0.tar.gz) = 9146
|
||||
SIZE (cargo/scopeguard-1.1.0.tar.gz) = 11470
|
||||
SIZE (cargo/sct-0.6.1.tar.gz) = 26825
|
||||
SIZE (cargo/security-framework-2.6.0.tar.gz) = 71481
|
||||
SIZE (cargo/security-framework-sys-2.6.0.tar.gz) = 17709
|
||||
SIZE (cargo/semver-0.9.0.tar.gz) = 17344
|
||||
SIZE (cargo/semver-parser-0.7.0.tar.gz) = 10268
|
||||
SIZE (cargo/serde-1.0.136.tar.gz) = 76158
|
||||
SIZE (cargo/serde_cbor-0.11.2.tar.gz) = 44570
|
||||
SIZE (cargo/serde_derive-1.0.136.tar.gz) = 54776
|
||||
SIZE (cargo/serde_json-1.0.78.tar.gz) = 144364
|
||||
SIZE (cargo/serde_urlencoded-0.7.1.tar.gz) = 12822
|
||||
SIZE (cargo/sha-1-0.8.2.tar.gz) = 12338
|
||||
SIZE (cargo/sha-1-0.9.8.tar.gz) = 14029
|
||||
SIZE (cargo/sha1-0.6.1.tar.gz) = 2931
|
||||
SIZE (cargo/sha1_smol-1.0.0.tar.gz) = 9782
|
||||
SIZE (cargo/sha2-0.9.9.tar.gz) = 22247
|
||||
SIZE (cargo/sharded-slab-0.1.4.tar.gz) = 52479
|
||||
SIZE (cargo/signal-hook-registry-1.4.0.tar.gz) = 17912
|
||||
SIZE (cargo/simple_asn1-0.4.1.tar.gz) = 15752
|
||||
SIZE (cargo/siphasher-0.3.9.tar.gz) = 10108
|
||||
SIZE (cargo/slab-0.4.5.tar.gz) = 15888
|
||||
SIZE (cargo/smallvec-0.6.14.tar.gz) = 22855
|
||||
SIZE (cargo/smallvec-1.8.0.tar.gz) = 27992
|
||||
SIZE (cargo/socket2-0.3.19.tar.gz) = 33782
|
||||
SIZE (cargo/socket2-0.4.4.tar.gz) = 44048
|
||||
SIZE (cargo/spin-0.5.2.tar.gz) = 12004
|
||||
SIZE (cargo/spin-0.9.2.tar.gz) = 28755
|
||||
SIZE (cargo/stable-pattern-0.1.0.tar.gz) = 16533
|
||||
SIZE (cargo/stable_deref_trait-1.2.0.tar.gz) = 8054
|
||||
SIZE (cargo/standback-0.2.17.tar.gz) = 29011
|
||||
SIZE (cargo/state-0.5.2.tar.gz) = 30371
|
||||
SIZE (cargo/stdweb-0.4.20.tar.gz) = 194102
|
||||
SIZE (cargo/stdweb-derive-0.5.3.tar.gz) = 3894
|
||||
SIZE (cargo/stdweb-internal-macros-0.2.9.tar.gz) = 11828
|
||||
SIZE (cargo/stdweb-internal-runtime-0.1.5.tar.gz) = 5445
|
||||
SIZE (cargo/string_cache-0.8.2.tar.gz) = 15770
|
||||
SIZE (cargo/string_cache_codegen-0.5.1.tar.gz) = 8243
|
||||
SIZE (cargo/subtle-2.4.1.tar.gz) = 12630
|
||||
SIZE (cargo/syn-1.0.86.tar.gz) = 235126
|
||||
SIZE (cargo/syslog-4.0.1.tar.gz) = 7131
|
||||
SIZE (cargo/tempfile-3.3.0.tar.gz) = 27578
|
||||
SIZE (cargo/tendril-0.4.2.tar.gz) = 37138
|
||||
SIZE (cargo/thiserror-1.0.30.tar.gz) = 17748
|
||||
SIZE (cargo/thiserror-impl-1.0.30.tar.gz) = 15230
|
||||
SIZE (cargo/thread_local-1.1.4.tar.gz) = 13106
|
||||
SIZE (cargo/threadpool-1.8.1.tar.gz) = 14408
|
||||
SIZE (cargo/time-0.1.44.tar.gz) = 28885
|
||||
SIZE (cargo/time-0.2.27.tar.gz) = 65167
|
||||
SIZE (cargo/time-0.3.7.tar.gz) = 76358
|
||||
SIZE (cargo/time-macros-0.1.1.tar.gz) = 5447
|
||||
SIZE (cargo/time-macros-0.2.3.tar.gz) = 16838
|
||||
SIZE (cargo/time-macros-impl-0.1.2.tar.gz) = 10096
|
||||
SIZE (cargo/tinyvec-1.5.1.tar.gz) = 44942
|
||||
SIZE (cargo/tinyvec_macros-0.1.0.tar.gz) = 1817
|
||||
SIZE (cargo/tokio-1.16.1.tar.gz) = 552194
|
||||
SIZE (cargo/tokio-macros-1.7.0.tar.gz) = 9261
|
||||
SIZE (cargo/tokio-native-tls-0.3.0.tar.gz) = 20759
|
||||
SIZE (cargo/tokio-rustls-0.22.0.tar.gz) = 22706
|
||||
SIZE (cargo/tokio-socks-0.5.1.tar.gz) = 16137
|
||||
SIZE (cargo/tokio-stream-0.1.8.tar.gz) = 30537
|
||||
SIZE (cargo/tokio-util-0.6.9.tar.gz) = 76480
|
||||
SIZE (cargo/toml-0.5.8.tar.gz) = 54219
|
||||
SIZE (cargo/totp-lite-1.0.3.tar.gz) = 4387
|
||||
SIZE (cargo/tower-service-0.3.1.tar.gz) = 6299
|
||||
SIZE (cargo/tracing-0.1.29.tar.gz) = 72444
|
||||
SIZE (cargo/tracing-attributes-0.1.18.tar.gz) = 22779
|
||||
SIZE (cargo/tracing-core-0.1.21.tar.gz) = 50683
|
||||
SIZE (cargo/tracing-log-0.1.2.tar.gz) = 14915
|
||||
SIZE (cargo/tracing-subscriber-0.3.7.tar.gz) = 165664
|
||||
SIZE (cargo/trust-dns-proto-0.20.3.tar.gz) = 245383
|
||||
SIZE (cargo/trust-dns-resolver-0.20.3.tar.gz) = 77051
|
||||
SIZE (cargo/try-lock-0.2.3.tar.gz) = 4158
|
||||
SIZE (cargo/typenum-1.15.0.tar.gz) = 40741
|
||||
SIZE (cargo/u2f-0.2.0.tar.gz) = 7846
|
||||
SIZE (cargo/ubyte-0.10.1.tar.gz) = 13520
|
||||
SIZE (cargo/ucd-trie-0.1.3.tar.gz) = 44615
|
||||
SIZE (cargo/uncased-0.9.6.tar.gz) = 10413
|
||||
SIZE (cargo/unicode-bidi-0.3.7.tar.gz) = 33759
|
||||
SIZE (cargo/unicode-normalization-0.1.19.tar.gz) = 107353
|
||||
SIZE (cargo/unicode-segmentation-1.8.0.tar.gz) = 94011
|
||||
SIZE (cargo/unicode-xid-0.2.2.tar.gz) = 14955
|
||||
SIZE (cargo/untrusted-0.7.1.tar.gz) = 7924
|
||||
SIZE (cargo/url-1.7.2.tar.gz) = 68597
|
||||
SIZE (cargo/url-2.2.2.tar.gz) = 68555
|
||||
SIZE (cargo/utf-8-0.7.6.tar.gz) = 10422
|
||||
SIZE (cargo/uuid-0.8.2.tar.gz) = 37909
|
||||
SIZE (cargo/vcpkg-0.2.15.tar.gz) = 228735
|
||||
SIZE (cargo/version_check-0.9.4.tar.gz) = 14895
|
||||
SIZE (cargo/walkdir-2.3.2.tar.gz) = 23516
|
||||
SIZE (cargo/want-0.3.0.tar.gz) = 6550
|
||||
SIZE (cargo/wasi-0.10.0+wasi-snapshot-preview1.tar.gz) = 26964
|
||||
SIZE (cargo/wasi-0.9.0+wasi-snapshot-preview1.tar.gz) = 31521
|
||||
SIZE (cargo/wasm-bindgen-0.2.79.tar.gz) = 164276
|
||||
SIZE (cargo/wasm-bindgen-backend-0.2.79.tar.gz) = 25776
|
||||
SIZE (cargo/wasm-bindgen-futures-0.4.29.tar.gz) = 14730
|
||||
SIZE (cargo/wasm-bindgen-macro-0.2.79.tar.gz) = 11806
|
||||
SIZE (cargo/wasm-bindgen-macro-support-0.2.79.tar.gz) = 17861
|
||||
SIZE (cargo/wasm-bindgen-shared-0.2.79.tar.gz) = 7204
|
||||
SIZE (cargo/web-sys-0.3.56.tar.gz) = 666465
|
||||
SIZE (cargo/webauthn-rs-0.3.2.tar.gz) = 246188
|
||||
SIZE (cargo/webpki-0.21.4.tar.gz) = 58505
|
||||
SIZE (cargo/widestring-0.4.3.tar.gz) = 26215
|
||||
SIZE (cargo/winapi-0.2.8.tar.gz) = 455145
|
||||
SIZE (cargo/winapi-0.3.9.tar.gz) = 1200382
|
||||
SIZE (cargo/winapi-build-0.1.1.tar.gz) = 669
|
||||
SIZE (cargo/winapi-i686-pc-windows-gnu-0.4.0.tar.gz) = 2918815
|
||||
SIZE (cargo/winapi-util-0.1.5.tar.gz) = 10164
|
||||
SIZE (cargo/winapi-x86_64-pc-windows-gnu-0.4.0.tar.gz) = 2947998
|
||||
SIZE (cargo/winreg-0.6.2.tar.gz) = 19338
|
||||
SIZE (cargo/winreg-0.7.0.tar.gz) = 21225
|
||||
SIZE (cargo/ws2_32-sys-0.2.1.tar.gz) = 4697
|
||||
SIZE (cargo/xml5ever-0.16.2.tar.gz) = 40971
|
||||
SIZE (cargo/yansi-0.5.0.tar.gz) = 17261
|
||||
SIZE (cargo/yubico-0.10.0.tar.gz) = 17439
|
||||
SIZE (vaultwarden-1.24.0.tar.gz) = 490087
|
||||
SIZE (vaultwarden-1.24.0.vendor.tgz) = 487710
|
12
security/vaultwarden/files/config.vendor
Normal file
12
security/vaultwarden/files/config.vendor
Normal file
@ -0,0 +1,12 @@
|
||||
[source."https://github.com/SergioBenitez/Rocket"]
|
||||
git = "https://github.com/SergioBenitez/Rocket"
|
||||
rev = "8cae077ba1d54b92cdef3e171a730b819d5eeb8e"
|
||||
replace-with = "vendored-sources"
|
||||
|
||||
[source."https://github.com/jjlin/job_scheduler"]
|
||||
git = "https://github.com/jjlin/job_scheduler"
|
||||
rev = "ee023418dbba2bfe1e30a5fd7d937f9e33739806"
|
||||
replace-with = "vendored-sources"
|
||||
|
||||
[source.vendored-sources]
|
||||
directory = "${WRKSRC}/myvendordir"
|
2337
security/vaultwarden/patches/patch-Cargo_lock
Normal file
2337
security/vaultwarden/patches/patch-Cargo_lock
Normal file
File diff suppressed because it is too large
Load Diff
103
security/vaultwarden/patches/patch-Cargo_toml
Normal file
103
security/vaultwarden/patches/patch-Cargo_toml
Normal file
@ -0,0 +1,103 @@
|
||||
Index: Cargo.toml
|
||||
--- Cargo.toml.orig
|
||||
+++ Cargo.toml
|
||||
@@ -3,7 +3,7 @@ name = "vaultwarden"
|
||||
version = "1.0.0"
|
||||
authors = ["Daniel García <dani-garcia@users.noreply.github.com>"]
|
||||
edition = "2021"
|
||||
-rust-version = "1.60"
|
||||
+rust-version = "1.56"
|
||||
resolver = "2"
|
||||
|
||||
repository = "https://github.com/dani-garcia/vaultwarden"
|
||||
@@ -13,6 +13,7 @@ publish = false
|
||||
build = "build.rs"
|
||||
|
||||
[features]
|
||||
+# default = ["sqlite"]
|
||||
# Empty to keep compatibility, prefer to set USE_SYSLOG=true
|
||||
enable_syslog = []
|
||||
mysql = ["diesel/mysql", "diesel_migrations/mysql"]
|
||||
@@ -29,22 +30,22 @@ unstable = []
|
||||
syslog = "4.0.1"
|
||||
|
||||
[dependencies]
|
||||
-# Web framework for nightly with a focus on ease-of-use, expressibility, and speed.
|
||||
-rocket = { version = "=0.5.0-dev", features = ["tls"], default-features = false }
|
||||
-rocket_contrib = "=0.5.0-dev"
|
||||
+# Web framework
|
||||
+rocket = { version = "0.5.0-rc.1", features = ["tls", "json"], default-features = false }
|
||||
|
||||
-# HTTP client
|
||||
-reqwest = { version = "0.11.8", features = ["blocking", "json", "gzip", "brotli", "socks", "cookies", "trust-dns"] }
|
||||
+# Async futures
|
||||
+futures = "0.3.19"
|
||||
+tokio = { version = "1.16.1", features = ["rt-multi-thread", "fs", "io-util", "parking_lot"] }
|
||||
+
|
||||
+ # HTTP client
|
||||
+reqwest = { version = "0.11.9", features = ["stream", "json", "gzip", "brotli", "socks", "cookies", "trust-dns"] }
|
||||
+bytes = "1.1.0"
|
||||
|
||||
# Used for custom short lived cookie jar
|
||||
cookie = "0.15.1"
|
||||
cookie_store = "0.15.1"
|
||||
-bytes = "1.1.0"
|
||||
url = "2.2.2"
|
||||
|
||||
-# multipart/form-data support
|
||||
-multipart = { version = "0.18.0", features = ["server"], default-features = false }
|
||||
-
|
||||
# WebSockets library
|
||||
ws = { version = "0.11.1", package = "parity-ws" }
|
||||
|
||||
@@ -55,8 +56,8 @@ rmpv = "1.0.0"
|
||||
chashmap = "2.2.2"
|
||||
|
||||
# A generic serialization/deserialization framework
|
||||
-serde = { version = "1.0.132", features = ["derive"] }
|
||||
-serde_json = "1.0.73"
|
||||
+serde = { version = "1.0.136", features = ["derive"] }
|
||||
+serde_json = "1.0.78"
|
||||
|
||||
# Logging
|
||||
log = "0.4.14"
|
||||
@@ -95,7 +96,7 @@ jsonwebtoken = "7.2.0"
|
||||
|
||||
# U2F library
|
||||
u2f = "0.2.0"
|
||||
-webauthn-rs = "0.3.1"
|
||||
+webauthn-rs = "0.3.2"
|
||||
|
||||
# Yubico Library
|
||||
yubico = { version = "0.10.0", features = ["online-tokio"], default-features = false }
|
||||
@@ -115,7 +116,7 @@ tracing = { version = "0.1.29", features = ["log"] } #
|
||||
lettre = { version = "0.10.0-rc.4", features = ["smtp-transport", "builder", "serde", "native-tls", "hostname", "tracing"], default-features = false }
|
||||
|
||||
# Template library
|
||||
-handlebars = { version = "4.1.6", features = ["dir_source"] }
|
||||
+handlebars = { version = "4.2.1", features = ["dir_source"] }
|
||||
|
||||
# For favicon extraction from main website
|
||||
html5ever = "0.25.1"
|
||||
@@ -135,16 +136,16 @@ idna = "0.2.3"
|
||||
pico-args = "0.4.2"
|
||||
|
||||
# Logging panics to logfile instead stderr only
|
||||
-backtrace = "0.3.63"
|
||||
+backtrace = "0.3.64"
|
||||
|
||||
# Macro ident concatenation
|
||||
paste = "1.0.6"
|
||||
-governor = "0.3.2"
|
||||
+governor = "0.4.1"
|
||||
|
||||
+ctrlc = { version = "3.2.1", features = ["termination"] }
|
||||
+
|
||||
[patch.crates-io]
|
||||
-# Use newest ring
|
||||
-rocket = { git = 'https://github.com/SergioBenitez/Rocket', rev = '263e39b5b429de1913ce7e3036575a7b4d88b6d7' }
|
||||
-rocket_contrib = { git = 'https://github.com/SergioBenitez/Rocket', rev = '263e39b5b429de1913ce7e3036575a7b4d88b6d7' }
|
||||
+rocket = { git = 'https://github.com/SergioBenitez/Rocket', rev = '8cae077ba1d54b92cdef3e171a730b819d5eeb8e' }
|
||||
|
||||
# The maintainer of the `job_scheduler` crate doesn't seem to have responded
|
||||
# to any issues or PRs for almost a year (as of April 2021). This hopefully
|
6
security/vaultwarden/patches/patch-Rocket_toml
Normal file
6
security/vaultwarden/patches/patch-Rocket_toml
Normal file
@ -0,0 +1,6 @@
|
||||
Index: Rocket.toml
|
||||
--- Rocket.toml.orig
|
||||
+++ Rocket.toml
|
||||
@@ -1,2 +0,0 @@
|
||||
-[global.limits]
|
||||
-json = 10485760 # 10 MiB
|
21
security/vaultwarden/patches/patch-_env_template
Normal file
21
security/vaultwarden/patches/patch-_env_template
Normal file
@ -0,0 +1,21 @@
|
||||
Index: .env.template
|
||||
--- .env.template.orig
|
||||
+++ .env.template
|
||||
@@ -53,7 +53,7 @@
|
||||
# WEBSOCKET_ENABLED=false
|
||||
|
||||
## Controls the WebSocket server address and port
|
||||
-# WEBSOCKET_ADDRESS=0.0.0.0
|
||||
+WEBSOCKET_ADDRESS=127.0.0.1
|
||||
# WEBSOCKET_PORT=3012
|
||||
|
||||
## Controls whether users are allowed to create Bitwarden Sends.
|
||||
@@ -320,7 +320,7 @@
|
||||
|
||||
## Rocket specific settings
|
||||
## See https://rocket.rs/v0.4/guide/configuration/ for more details.
|
||||
-# ROCKET_ADDRESS=0.0.0.0
|
||||
+ROCKET_ADDRESS=127.0.0.1
|
||||
# ROCKET_PORT=80 # Defaults to 80 in the Docker images, or 8000 otherwise.
|
||||
# ROCKET_WORKERS=10
|
||||
# ROCKET_TLS={certs="/path/to/certs.pem",key="/path/to/key.pem"}
|
6
security/vaultwarden/patches/patch-rust-toolchain
Normal file
6
security/vaultwarden/patches/patch-rust-toolchain
Normal file
@ -0,0 +1,6 @@
|
||||
Index: rust-toolchain
|
||||
--- rust-toolchain.orig
|
||||
+++ rust-toolchain
|
||||
@@ -1 +1 @@
|
||||
-nightly-2022-01-23
|
||||
+stable
|
200
security/vaultwarden/patches/patch-src_api_admin_rs
Normal file
200
security/vaultwarden/patches/patch-src_api_admin_rs
Normal file
@ -0,0 +1,200 @@
|
||||
Index: src/api/admin.rs
|
||||
--- src/api/admin.rs.orig
|
||||
+++ src/api/admin.rs
|
||||
@@ -3,13 +3,14 @@ use serde::de::DeserializeOwned;
|
||||
use serde_json::Value;
|
||||
use std::env;
|
||||
|
||||
+use rocket::serde::json::Json;
|
||||
use rocket::{
|
||||
- http::{Cookie, Cookies, SameSite, Status},
|
||||
- request::{self, FlashMessage, Form, FromRequest, Outcome, Request},
|
||||
- response::{content::Html, Flash, Redirect},
|
||||
+ form::Form,
|
||||
+ http::{Cookie, CookieJar, SameSite, Status},
|
||||
+ request::{self, FlashMessage, FromRequest, Outcome, Request},
|
||||
+ response::{content::RawHtml as Html, Flash, Redirect},
|
||||
Route,
|
||||
};
|
||||
-use rocket_contrib::json::Json;
|
||||
|
||||
use crate::{
|
||||
api::{ApiResult, EmptyResult, JsonResult, NumberOrString},
|
||||
@@ -85,10 +86,11 @@ fn admin_path() -> String {
|
||||
|
||||
struct Referer(Option<String>);
|
||||
|
||||
-impl<'a, 'r> FromRequest<'a, 'r> for Referer {
|
||||
+#[rocket::async_trait]
|
||||
+impl<'r> FromRequest<'r> for Referer {
|
||||
type Error = ();
|
||||
|
||||
- fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
|
||||
+ async fn from_request(request: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
|
||||
Outcome::Success(Referer(request.headers().get_one("Referer").map(str::to_string)))
|
||||
}
|
||||
}
|
||||
@@ -96,10 +98,11 @@ impl<'a, 'r> FromRequest<'a, 'r> for Referer {
|
||||
#[derive(Debug)]
|
||||
struct IpHeader(Option<String>);
|
||||
|
||||
-impl<'a, 'r> FromRequest<'a, 'r> for IpHeader {
|
||||
+#[rocket::async_trait]
|
||||
+impl<'r> FromRequest<'r> for IpHeader {
|
||||
type Error = ();
|
||||
|
||||
- fn from_request(req: &'a Request<'r>) -> Outcome<Self, Self::Error> {
|
||||
+ async fn from_request(req: &'r Request<'_>) -> Outcome<Self, Self::Error> {
|
||||
if req.headers().get_one(&CONFIG.ip_header()).is_some() {
|
||||
Outcome::Success(IpHeader(Some(CONFIG.ip_header())))
|
||||
} else if req.headers().get_one("X-Client-IP").is_some() {
|
||||
@@ -138,7 +141,7 @@ fn admin_url(referer: Referer) -> String {
|
||||
#[get("/", rank = 2)]
|
||||
fn admin_login(flash: Option<FlashMessage>) -> ApiResult<Html<String>> {
|
||||
// If there is an error, show it
|
||||
- let msg = flash.map(|msg| format!("{}: {}", msg.name(), msg.msg()));
|
||||
+ let msg = flash.map(|msg| format!("{}: {}", msg.kind(), msg.message()));
|
||||
let json = json!({
|
||||
"page_content": "admin/login",
|
||||
"version": VERSION,
|
||||
@@ -159,7 +162,7 @@ struct LoginForm {
|
||||
#[post("/", data = "<data>")]
|
||||
fn post_admin_login(
|
||||
data: Form<LoginForm>,
|
||||
- mut cookies: Cookies,
|
||||
+ cookies: &CookieJar,
|
||||
ip: ClientIp,
|
||||
referer: Referer,
|
||||
) -> Result<Redirect, Flash<Redirect>> {
|
||||
@@ -180,7 +183,7 @@ fn post_admin_login(
|
||||
|
||||
let cookie = Cookie::build(COOKIE_NAME, jwt)
|
||||
.path(admin_path())
|
||||
- .max_age(time::Duration::minutes(20))
|
||||
+ .max_age(rocket::time::Duration::minutes(20))
|
||||
.same_site(SameSite::Strict)
|
||||
.http_only(true)
|
||||
.finish();
|
||||
@@ -297,7 +300,7 @@ fn test_smtp(data: Json<InviteData>, _token: AdminToke
|
||||
}
|
||||
|
||||
#[get("/logout")]
|
||||
-fn logout(mut cookies: Cookies, referer: Referer) -> Redirect {
|
||||
+fn logout(cookies: &CookieJar, referer: Referer) -> Redirect {
|
||||
cookies.remove(Cookie::named(COOKIE_NAME));
|
||||
Redirect::to(admin_url(referer))
|
||||
}
|
||||
@@ -462,23 +465,23 @@ struct GitCommit {
|
||||
sha: String,
|
||||
}
|
||||
|
||||
-fn get_github_api<T: DeserializeOwned>(url: &str) -> Result<T, Error> {
|
||||
+async fn get_github_api<T: DeserializeOwned>(url: &str) -> Result<T, Error> {
|
||||
let github_api = get_reqwest_client();
|
||||
|
||||
- Ok(github_api.get(url).send()?.error_for_status()?.json::<T>()?)
|
||||
+ Ok(github_api.get(url).send().await?.error_for_status()?.json::<T>().await?)
|
||||
}
|
||||
|
||||
-fn has_http_access() -> bool {
|
||||
+async fn has_http_access() -> bool {
|
||||
let http_access = get_reqwest_client();
|
||||
|
||||
- match http_access.head("https://github.com/dani-garcia/vaultwarden").send() {
|
||||
+ match http_access.head("https://github.com/dani-garcia/vaultwarden").send().await {
|
||||
Ok(r) => r.status().is_success(),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[get("/diagnostics")]
|
||||
-fn diagnostics(_token: AdminToken, ip_header: IpHeader, conn: DbConn) -> ApiResult<Html<String>> {
|
||||
+async fn diagnostics(_token: AdminToken, ip_header: IpHeader, conn: DbConn) -> ApiResult<Html<String>> {
|
||||
use crate::util::read_file_string;
|
||||
use chrono::prelude::*;
|
||||
use std::net::ToSocketAddrs;
|
||||
@@ -497,7 +500,7 @@ fn diagnostics(_token: AdminToken, ip_header: IpHeader
|
||||
|
||||
// Execute some environment checks
|
||||
let running_within_docker = is_running_in_docker();
|
||||
- let has_http_access = has_http_access();
|
||||
+ let has_http_access = has_http_access().await;
|
||||
let uses_proxy = env::var_os("HTTP_PROXY").is_some()
|
||||
|| env::var_os("http_proxy").is_some()
|
||||
|| env::var_os("HTTPS_PROXY").is_some()
|
||||
@@ -513,11 +516,14 @@ fn diagnostics(_token: AdminToken, ip_header: IpHeader
|
||||
// TODO: Maybe we need to cache this using a LazyStatic or something. Github only allows 60 requests per hour, and we use 3 here already.
|
||||
let (latest_release, latest_commit, latest_web_build) = if has_http_access {
|
||||
(
|
||||
- match get_github_api::<GitRelease>("https://api.github.com/repos/dani-garcia/vaultwarden/releases/latest") {
|
||||
+ match get_github_api::<GitRelease>("https://api.github.com/repos/dani-garcia/vaultwarden/releases/latest")
|
||||
+ .await
|
||||
+ {
|
||||
Ok(r) => r.tag_name,
|
||||
_ => "-".to_string(),
|
||||
},
|
||||
- match get_github_api::<GitCommit>("https://api.github.com/repos/dani-garcia/vaultwarden/commits/main") {
|
||||
+ match get_github_api::<GitCommit>("https://api.github.com/repos/dani-garcia/vaultwarden/commits/main").await
|
||||
+ {
|
||||
Ok(mut c) => {
|
||||
c.sha.truncate(8);
|
||||
c.sha
|
||||
@@ -531,7 +537,9 @@ fn diagnostics(_token: AdminToken, ip_header: IpHeader
|
||||
} else {
|
||||
match get_github_api::<GitRelease>(
|
||||
"https://api.github.com/repos/dani-garcia/bw_web_builds/releases/latest",
|
||||
- ) {
|
||||
+ )
|
||||
+ .await
|
||||
+ {
|
||||
Ok(r) => r.tag_name.trim_start_matches('v').to_string(),
|
||||
_ => "-".to_string(),
|
||||
}
|
||||
@@ -562,7 +570,7 @@ fn diagnostics(_token: AdminToken, ip_header: IpHeader
|
||||
"ip_header_config": &CONFIG.ip_header(),
|
||||
"uses_proxy": uses_proxy,
|
||||
"db_type": *DB_TYPE,
|
||||
- "db_version": get_sql_server_version(&conn),
|
||||
+ "db_version": get_sql_server_version(&conn).await,
|
||||
"admin_url": format!("{}/diagnostics", admin_url(Referer(None))),
|
||||
"overrides": &CONFIG.get_overrides().join(", "),
|
||||
"server_time_local": Local::now().format("%Y-%m-%d %H:%M:%S %Z").to_string(),
|
||||
@@ -591,9 +599,9 @@ fn delete_config(_token: AdminToken) -> EmptyResult {
|
||||
}
|
||||
|
||||
#[post("/config/backup_db")]
|
||||
-fn backup_db(_token: AdminToken, conn: DbConn) -> EmptyResult {
|
||||
+async fn backup_db(_token: AdminToken, conn: DbConn) -> EmptyResult {
|
||||
if *CAN_BACKUP {
|
||||
- backup_database(&conn)
|
||||
+ backup_database(&conn).await
|
||||
} else {
|
||||
err!("Can't back up current DB (Only SQLite supports this feature)");
|
||||
}
|
||||
@@ -601,21 +609,22 @@ fn backup_db(_token: AdminToken, conn: DbConn) -> Empt
|
||||
|
||||
pub struct AdminToken {}
|
||||
|
||||
-impl<'a, 'r> FromRequest<'a, 'r> for AdminToken {
|
||||
+#[rocket::async_trait]
|
||||
+impl<'r> FromRequest<'r> for AdminToken {
|
||||
type Error = &'static str;
|
||||
|
||||
- fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
|
||||
+ async fn from_request(request: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
|
||||
if CONFIG.disable_admin_token() {
|
||||
Outcome::Success(AdminToken {})
|
||||
} else {
|
||||
- let mut cookies = request.cookies();
|
||||
+ let cookies = request.cookies();
|
||||
|
||||
let access_token = match cookies.get(COOKIE_NAME) {
|
||||
Some(cookie) => cookie.value(),
|
||||
None => return Outcome::Forward(()), // If there is no cookie, redirect to login
|
||||
};
|
||||
|
||||
- let ip = match request.guard::<ClientIp>() {
|
||||
+ let ip = match ClientIp::from_request(request).await {
|
||||
Outcome::Success(ip) => ip.ip,
|
||||
_ => err_handler!("Error getting Client IP"),
|
||||
};
|
10
security/vaultwarden/patches/patch-src_api_core_accounts_rs
Normal file
10
security/vaultwarden/patches/patch-src_api_core_accounts_rs
Normal file
@ -0,0 +1,10 @@
|
||||
Index: src/api/core/accounts.rs
|
||||
--- src/api/core/accounts.rs.orig
|
||||
+++ src/api/core/accounts.rs
|
||||
@@ -1,5 +1,5 @@
|
||||
use chrono::Utc;
|
||||
-use rocket_contrib::json::Json;
|
||||
+use rocket::serde::json::Json;
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{
|
394
security/vaultwarden/patches/patch-src_api_core_ciphers_rs
Normal file
394
security/vaultwarden/patches/patch-src_api_core_ciphers_rs
Normal file
@ -0,0 +1,394 @@
|
||||
Index: src/api/core/ciphers.rs
|
||||
--- src/api/core/ciphers.rs.orig
|
||||
+++ src/api/core/ciphers.rs
|
||||
@@ -1,13 +1,14 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
-use std::path::{Path, PathBuf};
|
||||
|
||||
use chrono::{NaiveDateTime, Utc};
|
||||
-use rocket::{http::ContentType, request::Form, Data, Route};
|
||||
-use rocket_contrib::json::Json;
|
||||
+use rocket::fs::TempFile;
|
||||
+use rocket::serde::json::Json;
|
||||
+use rocket::{
|
||||
+ form::{Form, FromForm},
|
||||
+ Route,
|
||||
+};
|
||||
use serde_json::Value;
|
||||
|
||||
-use multipart::server::{save::SavedData, Multipart, SaveResult};
|
||||
-
|
||||
use crate::{
|
||||
api::{self, EmptyResult, JsonResult, JsonUpcase, Notify, PasswordData, UpdateType},
|
||||
auth::Headers,
|
||||
@@ -79,9 +80,9 @@ pub fn routes() -> Vec<Route> {
|
||||
]
|
||||
}
|
||||
|
||||
-pub fn purge_trashed_ciphers(pool: DbPool) {
|
||||
+pub async fn purge_trashed_ciphers(pool: DbPool) {
|
||||
debug!("Purging trashed ciphers");
|
||||
- if let Ok(conn) = pool.get() {
|
||||
+ if let Ok(conn) = pool.get().await {
|
||||
Cipher::purge_trash(&conn);
|
||||
} else {
|
||||
error!("Failed to get DB connection while purging trashed ciphers")
|
||||
@@ -90,12 +91,12 @@ pub fn purge_trashed_ciphers(pool: DbPool) {
|
||||
|
||||
#[derive(FromForm, Default)]
|
||||
struct SyncData {
|
||||
- #[form(field = "excludeDomains")]
|
||||
+ #[field(name = "excludeDomains")]
|
||||
exclude_domains: bool, // Default: 'false'
|
||||
}
|
||||
|
||||
#[get("/sync?<data..>")]
|
||||
-fn sync(data: Form<SyncData>, headers: Headers, conn: DbConn) -> Json<Value> {
|
||||
+fn sync(data: SyncData, headers: Headers, conn: DbConn) -> Json<Value> {
|
||||
let user_json = headers.user.to_json(&conn);
|
||||
|
||||
let folders = Folder::find_by_user(&headers.user.uuid, &conn);
|
||||
@@ -828,6 +829,12 @@ fn post_attachment_v2(
|
||||
})))
|
||||
}
|
||||
|
||||
+#[derive(FromForm)]
|
||||
+struct UploadData<'f> {
|
||||
+ key: Option<String>,
|
||||
+ data: TempFile<'f>,
|
||||
+}
|
||||
+
|
||||
/// Saves the data content of an attachment to a file. This is common code
|
||||
/// shared between the v2 and legacy attachment APIs.
|
||||
///
|
||||
@@ -836,22 +843,21 @@ fn post_attachment_v2(
|
||||
///
|
||||
/// When used with the v2 API, post_attachment_v2() has already created the
|
||||
/// database record, which is passed in as `attachment`.
|
||||
-fn save_attachment(
|
||||
+async fn save_attachment(
|
||||
mut attachment: Option<Attachment>,
|
||||
cipher_uuid: String,
|
||||
- data: Data,
|
||||
- content_type: &ContentType,
|
||||
+ data: Form<UploadData<'_>>,
|
||||
headers: &Headers,
|
||||
- conn: &DbConn,
|
||||
- nt: Notify,
|
||||
-) -> Result<Cipher, crate::error::Error> {
|
||||
- let cipher = match Cipher::find_by_uuid(&cipher_uuid, conn) {
|
||||
+ conn: DbConn,
|
||||
+ nt: Notify<'_>,
|
||||
+) -> Result<(Cipher, DbConn), crate::error::Error> {
|
||||
+ let cipher = match Cipher::find_by_uuid(&cipher_uuid, &conn) {
|
||||
Some(cipher) => cipher,
|
||||
- None => err_discard!("Cipher doesn't exist", data),
|
||||
+ None => err!("Cipher doesn't exist"),
|
||||
};
|
||||
|
||||
- if !cipher.is_write_accessible_to_user(&headers.user.uuid, conn) {
|
||||
- err_discard!("Cipher is not write accessible", data)
|
||||
+ if !cipher.is_write_accessible_to_user(&headers.user.uuid, &conn) {
|
||||
+ err!("Cipher is not write accessible")
|
||||
}
|
||||
|
||||
// In the v2 API, the attachment record has already been created,
|
||||
@@ -863,11 +869,11 @@ fn save_attachment(
|
||||
|
||||
let size_limit = if let Some(ref user_uuid) = cipher.user_uuid {
|
||||
match CONFIG.user_attachment_limit() {
|
||||
- Some(0) => err_discard!("Attachments are disabled", data),
|
||||
+ Some(0) => err!("Attachments are disabled"),
|
||||
Some(limit_kb) => {
|
||||
- let left = (limit_kb * 1024) - Attachment::size_by_user(user_uuid, conn) + size_adjust;
|
||||
+ let left = (limit_kb * 1024) - Attachment::size_by_user(user_uuid, &conn) + size_adjust;
|
||||
if left <= 0 {
|
||||
- err_discard!("Attachment storage limit reached! Delete some attachments to free up space", data)
|
||||
+ err!("Attachment storage limit reached! Delete some attachments to free up space")
|
||||
}
|
||||
Some(left as u64)
|
||||
}
|
||||
@@ -875,130 +881,78 @@ fn save_attachment(
|
||||
}
|
||||
} else if let Some(ref org_uuid) = cipher.organization_uuid {
|
||||
match CONFIG.org_attachment_limit() {
|
||||
- Some(0) => err_discard!("Attachments are disabled", data),
|
||||
+ Some(0) => err!("Attachments are disabled"),
|
||||
Some(limit_kb) => {
|
||||
- let left = (limit_kb * 1024) - Attachment::size_by_org(org_uuid, conn) + size_adjust;
|
||||
+ let left = (limit_kb * 1024) - Attachment::size_by_org(org_uuid, &conn) + size_adjust;
|
||||
if left <= 0 {
|
||||
- err_discard!("Attachment storage limit reached! Delete some attachments to free up space", data)
|
||||
+ err!("Attachment storage limit reached! Delete some attachments to free up space")
|
||||
}
|
||||
Some(left as u64)
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
} else {
|
||||
- err_discard!("Cipher is neither owned by a user nor an organization", data);
|
||||
+ err!("Cipher is neither owned by a user nor an organization");
|
||||
};
|
||||
|
||||
- let mut params = content_type.params();
|
||||
- let boundary_pair = params.next().expect("No boundary provided");
|
||||
- let boundary = boundary_pair.1;
|
||||
+ let mut data = data.into_inner();
|
||||
|
||||
- let base_path = Path::new(&CONFIG.attachments_folder()).join(&cipher_uuid);
|
||||
- let mut path = PathBuf::new();
|
||||
+ if let Some(size_limit) = size_limit {
|
||||
+ if data.data.len() > size_limit {
|
||||
+ err!("Attachment storage limit exceeded with this file");
|
||||
+ }
|
||||
+ }
|
||||
|
||||
- let mut attachment_key = None;
|
||||
- let mut error = None;
|
||||
+ let file_id = match &attachment {
|
||||
+ Some(attachment) => attachment.id.clone(), // v2 API
|
||||
+ None => crypto::generate_attachment_id(), // Legacy API
|
||||
+ };
|
||||
|
||||
- Multipart::with_body(data.open(), boundary)
|
||||
- .foreach_entry(|mut field| {
|
||||
- match &*field.headers.name {
|
||||
- "key" => {
|
||||
- use std::io::Read;
|
||||
- let mut key_buffer = String::new();
|
||||
- if field.data.read_to_string(&mut key_buffer).is_ok() {
|
||||
- attachment_key = Some(key_buffer);
|
||||
- }
|
||||
- }
|
||||
- "data" => {
|
||||
- // In the legacy API, this is the encrypted filename
|
||||
- // provided by the client, stored to the database as-is.
|
||||
- // In the v2 API, this value doesn't matter, as it was
|
||||
- // already provided and stored via an earlier API call.
|
||||
- let encrypted_filename = field.headers.filename;
|
||||
+ let folder_path = tokio::fs::canonicalize(&CONFIG.attachments_folder()).await?.join(&cipher_uuid);
|
||||
+ let file_path = folder_path.join(&file_id);
|
||||
+ tokio::fs::create_dir_all(&folder_path).await?;
|
||||
|
||||
- // This random ID is used as the name of the file on disk.
|
||||
- // In the legacy API, we need to generate this value here.
|
||||
- // In the v2 API, we use the value from post_attachment_v2().
|
||||
- let file_id = match &attachment {
|
||||
- Some(attachment) => attachment.id.clone(), // v2 API
|
||||
- None => crypto::generate_attachment_id(), // Legacy API
|
||||
- };
|
||||
- path = base_path.join(&file_id);
|
||||
+ let size = data.data.len() as i32;
|
||||
+ if let Some(attachment) = &mut attachment {
|
||||
+ // v2 API
|
||||
|
||||
- let size =
|
||||
- match field.data.save().memory_threshold(0).size_limit(size_limit).with_path(path.clone()) {
|
||||
- SaveResult::Full(SavedData::File(_, size)) => size as i32,
|
||||
- SaveResult::Full(other) => {
|
||||
- error = Some(format!("Attachment is not a file: {:?}", other));
|
||||
- return;
|
||||
- }
|
||||
- SaveResult::Partial(_, reason) => {
|
||||
- error = Some(format!("Attachment storage limit exceeded with this file: {:?}", reason));
|
||||
- return;
|
||||
- }
|
||||
- SaveResult::Error(e) => {
|
||||
- error = Some(format!("Error: {:?}", e));
|
||||
- return;
|
||||
- }
|
||||
- };
|
||||
+ // Check the actual size against the size initially provided by
|
||||
+ // the client. Upstream allows +/- 1 MiB deviation from this
|
||||
+ // size, but it's not clear when or why this is needed.
|
||||
+ const LEEWAY: i32 = 1024 * 1024; // 1 MiB
|
||||
+ let min_size = attachment.file_size - LEEWAY;
|
||||
+ let max_size = attachment.file_size + LEEWAY;
|
||||
|
||||
- if let Some(attachment) = &mut attachment {
|
||||
- // v2 API
|
||||
-
|
||||
- // Check the actual size against the size initially provided by
|
||||
- // the client. Upstream allows +/- 1 MiB deviation from this
|
||||
- // size, but it's not clear when or why this is needed.
|
||||
- const LEEWAY: i32 = 1024 * 1024; // 1 MiB
|
||||
- let min_size = attachment.file_size - LEEWAY;
|
||||
- let max_size = attachment.file_size + LEEWAY;
|
||||
-
|
||||
- if min_size <= size && size <= max_size {
|
||||
- if size != attachment.file_size {
|
||||
- // Update the attachment with the actual file size.
|
||||
- attachment.file_size = size;
|
||||
- attachment.save(conn).expect("Error updating attachment");
|
||||
- }
|
||||
- } else {
|
||||
- attachment.delete(conn).ok();
|
||||
-
|
||||
- let err_msg = "Attachment size mismatch".to_string();
|
||||
- error!("{} (expected within [{}, {}], got {})", err_msg, min_size, max_size, size);
|
||||
- error = Some(err_msg);
|
||||
- }
|
||||
- } else {
|
||||
- // Legacy API
|
||||
-
|
||||
- if encrypted_filename.is_none() {
|
||||
- error = Some("No filename provided".to_string());
|
||||
- return;
|
||||
- }
|
||||
- if attachment_key.is_none() {
|
||||
- error = Some("No attachment key provided".to_string());
|
||||
- return;
|
||||
- }
|
||||
- let attachment = Attachment::new(
|
||||
- file_id,
|
||||
- cipher_uuid.clone(),
|
||||
- encrypted_filename.unwrap(),
|
||||
- size,
|
||||
- attachment_key.clone(),
|
||||
- );
|
||||
- attachment.save(conn).expect("Error saving attachment");
|
||||
- }
|
||||
- }
|
||||
- _ => error!("Invalid multipart name"),
|
||||
+ if min_size <= size && size <= max_size {
|
||||
+ if size != attachment.file_size {
|
||||
+ // Update the attachment with the actual file size.
|
||||
+ attachment.file_size = size;
|
||||
+ attachment.save(&conn).expect("Error updating attachment");
|
||||
}
|
||||
- })
|
||||
- .expect("Error processing multipart data");
|
||||
+ } else {
|
||||
+ attachment.delete(&conn).ok();
|
||||
|
||||
- if let Some(ref e) = error {
|
||||
- std::fs::remove_file(path).ok();
|
||||
- err!(e);
|
||||
+ err!(format!("Attachment size mismatch (expected within [{}, {}], got {})", min_size, max_size, size));
|
||||
+ }
|
||||
+ } else {
|
||||
+ // Legacy API
|
||||
+ let encrypted_filename = data.data.raw_name().map(|s| s.dangerous_unsafe_unsanitized_raw().to_string());
|
||||
+
|
||||
+ if encrypted_filename.is_none() {
|
||||
+ err!("No filename provided")
|
||||
+ }
|
||||
+ if data.key.is_none() {
|
||||
+ err!("No attachment key provided")
|
||||
+ }
|
||||
+ let attachment = Attachment::new(file_id, cipher_uuid.clone(), encrypted_filename.unwrap(), size, data.key);
|
||||
+ attachment.save(&conn).expect("Error saving attachment");
|
||||
}
|
||||
|
||||
- nt.send_cipher_update(UpdateType::CipherUpdate, &cipher, &cipher.update_users_revision(conn));
|
||||
+ data.data.persist_to(file_path).await?;
|
||||
|
||||
- Ok(cipher)
|
||||
+ nt.send_cipher_update(UpdateType::CipherUpdate, &cipher, &cipher.update_users_revision(&conn));
|
||||
+
|
||||
+ Ok((cipher, conn))
|
||||
}
|
||||
|
||||
/// v2 API for uploading the actual data content of an attachment.
|
||||
@@ -1006,14 +960,13 @@ fn save_attachment(
|
||||
/// /ciphers/<uuid>/attachment/v2 route, which would otherwise conflict
|
||||
/// with this one.
|
||||
#[post("/ciphers/<uuid>/attachment/<attachment_id>", format = "multipart/form-data", data = "<data>", rank = 1)]
|
||||
-fn post_attachment_v2_data(
|
||||
+async fn post_attachment_v2_data(
|
||||
uuid: String,
|
||||
attachment_id: String,
|
||||
- data: Data,
|
||||
- content_type: &ContentType,
|
||||
+ data: Form<UploadData<'_>>,
|
||||
headers: Headers,
|
||||
conn: DbConn,
|
||||
- nt: Notify,
|
||||
+ nt: Notify<'_>,
|
||||
) -> EmptyResult {
|
||||
let attachment = match Attachment::find_by_id(&attachment_id, &conn) {
|
||||
Some(attachment) if uuid == attachment.cipher_uuid => Some(attachment),
|
||||
@@ -1021,54 +974,51 @@ fn post_attachment_v2_data(
|
||||
None => err!("Attachment doesn't exist"),
|
||||
};
|
||||
|
||||
- save_attachment(attachment, uuid, data, content_type, &headers, &conn, nt)?;
|
||||
+ save_attachment(attachment, uuid, data, &headers, conn, nt).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Legacy API for creating an attachment associated with a cipher.
|
||||
#[post("/ciphers/<uuid>/attachment", format = "multipart/form-data", data = "<data>")]
|
||||
-fn post_attachment(
|
||||
+async fn post_attachment(
|
||||
uuid: String,
|
||||
- data: Data,
|
||||
- content_type: &ContentType,
|
||||
+ data: Form<UploadData<'_>>,
|
||||
headers: Headers,
|
||||
conn: DbConn,
|
||||
- nt: Notify,
|
||||
+ nt: Notify<'_>,
|
||||
) -> JsonResult {
|
||||
// Setting this as None signifies to save_attachment() that it should create
|
||||
// the attachment database record as well as saving the data to disk.
|
||||
let attachment = None;
|
||||
|
||||
- let cipher = save_attachment(attachment, uuid, data, content_type, &headers, &conn, nt)?;
|
||||
+ let (cipher, conn) = save_attachment(attachment, uuid, data, &headers, conn, nt).await?;
|
||||
|
||||
Ok(Json(cipher.to_json(&headers.host, &headers.user.uuid, &conn)))
|
||||
}
|
||||
|
||||
#[post("/ciphers/<uuid>/attachment-admin", format = "multipart/form-data", data = "<data>")]
|
||||
-fn post_attachment_admin(
|
||||
+async fn post_attachment_admin(
|
||||
uuid: String,
|
||||
- data: Data,
|
||||
- content_type: &ContentType,
|
||||
+ data: Form<UploadData<'_>>,
|
||||
headers: Headers,
|
||||
conn: DbConn,
|
||||
- nt: Notify,
|
||||
+ nt: Notify<'_>,
|
||||
) -> JsonResult {
|
||||
- post_attachment(uuid, data, content_type, headers, conn, nt)
|
||||
+ post_attachment(uuid, data, headers, conn, nt).await
|
||||
}
|
||||
|
||||
#[post("/ciphers/<uuid>/attachment/<attachment_id>/share", format = "multipart/form-data", data = "<data>")]
|
||||
-fn post_attachment_share(
|
||||
+async fn post_attachment_share(
|
||||
uuid: String,
|
||||
attachment_id: String,
|
||||
- data: Data,
|
||||
- content_type: &ContentType,
|
||||
+ data: Form<UploadData<'_>>,
|
||||
headers: Headers,
|
||||
conn: DbConn,
|
||||
- nt: Notify,
|
||||
+ nt: Notify<'_>,
|
||||
) -> JsonResult {
|
||||
_delete_cipher_attachment_by_id(&uuid, &attachment_id, &headers, &conn, &nt)?;
|
||||
- post_attachment(uuid, data, content_type, headers, conn, nt)
|
||||
+ post_attachment(uuid, data, headers, conn, nt).await
|
||||
}
|
||||
|
||||
#[post("/ciphers/<uuid>/attachment/<attachment_id>/delete-admin")]
|
||||
@@ -1248,13 +1198,13 @@ fn move_cipher_selected_put(
|
||||
|
||||
#[derive(FromForm)]
|
||||
struct OrganizationId {
|
||||
- #[form(field = "organizationId")]
|
||||
+ #[field(name = "organizationId")]
|
||||
org_id: String,
|
||||
}
|
||||
|
||||
#[post("/ciphers/purge?<organization..>", data = "<data>")]
|
||||
fn delete_all(
|
||||
- organization: Option<Form<OrganizationId>>,
|
||||
+ organization: Option<OrganizationId>,
|
||||
data: JsonUpcase<PasswordData>,
|
||||
headers: Headers,
|
||||
conn: DbConn,
|
@ -0,0 +1,43 @@
|
||||
Index: src/api/core/emergency_access.rs
|
||||
--- src/api/core/emergency_access.rs.orig
|
||||
+++ src/api/core/emergency_access.rs
|
||||
@@ -1,6 +1,6 @@
|
||||
use chrono::{Duration, Utc};
|
||||
+use rocket::serde::json::Json;
|
||||
use rocket::Route;
|
||||
-use rocket_contrib::json::Json;
|
||||
use serde_json::Value;
|
||||
use std::borrow::Borrow;
|
||||
|
||||
@@ -709,13 +709,13 @@ fn check_emergency_access_allowed() -> EmptyResult {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
-pub fn emergency_request_timeout_job(pool: DbPool) {
|
||||
+pub async fn emergency_request_timeout_job(pool: DbPool) {
|
||||
debug!("Start emergency_request_timeout_job");
|
||||
if !CONFIG.emergency_access_allowed() {
|
||||
return;
|
||||
}
|
||||
|
||||
- if let Ok(conn) = pool.get() {
|
||||
+ if let Ok(conn) = pool.get().await {
|
||||
let emergency_access_list = EmergencyAccess::find_all_recoveries(&conn);
|
||||
|
||||
if emergency_access_list.is_empty() {
|
||||
@@ -756,13 +756,13 @@ pub fn emergency_request_timeout_job(pool: DbPool) {
|
||||
}
|
||||
}
|
||||
|
||||
-pub fn emergency_notification_reminder_job(pool: DbPool) {
|
||||
+pub async fn emergency_notification_reminder_job(pool: DbPool) {
|
||||
debug!("Start emergency_notification_reminder_job");
|
||||
if !CONFIG.emergency_access_allowed() {
|
||||
return;
|
||||
}
|
||||
|
||||
- if let Ok(conn) = pool.get() {
|
||||
+ if let Ok(conn) = pool.get().await {
|
||||
let emergency_access_list = EmergencyAccess::find_all_recoveries(&conn);
|
||||
|
||||
if emergency_access_list.is_empty() {
|
@ -0,0 +1,9 @@
|
||||
Index: src/api/core/folders.rs
|
||||
--- src/api/core/folders.rs.orig
|
||||
+++ src/api/core/folders.rs
|
||||
@@ -1,4 +1,4 @@
|
||||
-use rocket_contrib::json::Json;
|
||||
+use rocket::serde::json::Json;
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{
|
39
security/vaultwarden/patches/patch-src_api_core_mod_rs
Normal file
39
security/vaultwarden/patches/patch-src_api_core_mod_rs
Normal file
@ -0,0 +1,39 @@
|
||||
Index: src/api/core/mod.rs
|
||||
--- src/api/core/mod.rs.orig
|
||||
+++ src/api/core/mod.rs
|
||||
@@ -31,8 +31,8 @@ pub fn routes() -> Vec<Route> {
|
||||
//
|
||||
// Move this somewhere else
|
||||
//
|
||||
+use rocket::serde::json::Json;
|
||||
use rocket::Route;
|
||||
-use rocket_contrib::json::Json;
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{
|
||||
@@ -144,7 +144,7 @@ fn put_eq_domains(data: JsonUpcase<EquivDomainData>, h
|
||||
}
|
||||
|
||||
#[get("/hibp/breach?<username>")]
|
||||
-fn hibp_breach(username: String) -> JsonResult {
|
||||
+async fn hibp_breach(username: String) -> JsonResult {
|
||||
let url = format!(
|
||||
"https://haveibeenpwned.com/api/v3/breachedaccount/{}?truncateResponse=false&includeUnverified=false",
|
||||
username
|
||||
@@ -153,14 +153,14 @@ fn hibp_breach(username: String) -> JsonResult {
|
||||
if let Some(api_key) = crate::CONFIG.hibp_api_key() {
|
||||
let hibp_client = get_reqwest_client();
|
||||
|
||||
- let res = hibp_client.get(&url).header("hibp-api-key", api_key).send()?;
|
||||
+ let res = hibp_client.get(&url).header("hibp-api-key", api_key).send().await?;
|
||||
|
||||
// If we get a 404, return a 404, it means no breached accounts
|
||||
if res.status() == 404 {
|
||||
return Err(Error::empty().with_code(404));
|
||||
}
|
||||
|
||||
- let value: Value = res.error_for_status()?.json()?;
|
||||
+ let value: Value = res.error_for_status()?.json().await?;
|
||||
Ok(Json(value))
|
||||
} else {
|
||||
Ok(Json(json!([{
|
@ -0,0 +1,44 @@
|
||||
Index: src/api/core/organizations.rs
|
||||
--- src/api/core/organizations.rs.orig
|
||||
+++ src/api/core/organizations.rs
|
||||
@@ -1,6 +1,6 @@
|
||||
use num_traits::FromPrimitive;
|
||||
-use rocket::{request::Form, Route};
|
||||
-use rocket_contrib::json::Json;
|
||||
+use rocket::serde::json::Json;
|
||||
+use rocket::Route;
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{
|
||||
@@ -469,12 +469,12 @@ fn put_collection_users(
|
||||
|
||||
#[derive(FromForm)]
|
||||
struct OrgIdData {
|
||||
- #[form(field = "organizationId")]
|
||||
+ #[field(name = "organizationId")]
|
||||
organization_id: String,
|
||||
}
|
||||
|
||||
#[get("/ciphers/organization-details?<data..>")]
|
||||
-fn get_org_details(data: Form<OrgIdData>, headers: Headers, conn: DbConn) -> Json<Value> {
|
||||
+fn get_org_details(data: OrgIdData, headers: Headers, conn: DbConn) -> Json<Value> {
|
||||
let ciphers = Cipher::find_by_org(&data.organization_id, &conn);
|
||||
let ciphers_json: Vec<Value> =
|
||||
ciphers.iter().map(|c| c.to_json(&headers.host, &headers.user.uuid, &conn)).collect();
|
||||
@@ -1097,14 +1097,14 @@ struct RelationsData {
|
||||
|
||||
#[post("/ciphers/import-organization?<query..>", data = "<data>")]
|
||||
fn post_org_import(
|
||||
- query: Form<OrgIdData>,
|
||||
+ query: OrgIdData,
|
||||
data: JsonUpcase<ImportData>,
|
||||
headers: AdminHeaders,
|
||||
conn: DbConn,
|
||||
nt: Notify,
|
||||
) -> EmptyResult {
|
||||
let data: ImportData = data.into_inner().data;
|
||||
- let org_id = query.into_inner().organization_id;
|
||||
+ let org_id = query.organization_id;
|
||||
|
||||
// Read and create the collections
|
||||
let collections: Vec<_> = data
|
140
security/vaultwarden/patches/patch-src_api_core_sends_rs
Normal file
140
security/vaultwarden/patches/patch-src_api_core_sends_rs
Normal file
@ -0,0 +1,140 @@
|
||||
Index: src/api/core/sends.rs
|
||||
--- src/api/core/sends.rs.orig
|
||||
+++ src/api/core/sends.rs
|
||||
@@ -1,9 +1,10 @@
|
||||
-use std::{io::Read, path::Path};
|
||||
+use std::path::Path;
|
||||
|
||||
use chrono::{DateTime, Duration, Utc};
|
||||
-use multipart::server::{save::SavedData, Multipart, SaveResult};
|
||||
-use rocket::{http::ContentType, response::NamedFile, Data};
|
||||
-use rocket_contrib::json::Json;
|
||||
+use rocket::form::Form;
|
||||
+use rocket::fs::NamedFile;
|
||||
+use rocket::fs::TempFile;
|
||||
+use rocket::serde::json::Json;
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{
|
||||
@@ -31,9 +32,9 @@ pub fn routes() -> Vec<rocket::Route> {
|
||||
]
|
||||
}
|
||||
|
||||
-pub fn purge_sends(pool: DbPool) {
|
||||
+pub async fn purge_sends(pool: DbPool) {
|
||||
debug!("Purging sends");
|
||||
- if let Ok(conn) = pool.get() {
|
||||
+ if let Ok(conn) = pool.get().await {
|
||||
Send::purge(&conn);
|
||||
} else {
|
||||
error!("Failed to get DB connection while purging sends")
|
||||
@@ -177,26 +178,24 @@ fn post_send(data: JsonUpcase<SendData>, headers: Head
|
||||
Ok(Json(send.to_json()))
|
||||
}
|
||||
|
||||
+#[derive(FromForm)]
|
||||
+struct UploadData<'f> {
|
||||
+ model: Json<crate::util::UpCase<SendData>>,
|
||||
+ data: TempFile<'f>,
|
||||
+}
|
||||
+
|
||||
#[post("/sends/file", format = "multipart/form-data", data = "<data>")]
|
||||
-fn post_send_file(data: Data, content_type: &ContentType, headers: Headers, conn: DbConn, nt: Notify) -> JsonResult {
|
||||
+async fn post_send_file(data: Form<UploadData<'_>>, headers: Headers, conn: DbConn, nt: Notify<'_>) -> JsonResult {
|
||||
enforce_disable_send_policy(&headers, &conn)?;
|
||||
|
||||
- let boundary = content_type.params().next().expect("No boundary provided").1;
|
||||
+ let UploadData {
|
||||
+ model,
|
||||
+ mut data,
|
||||
+ } = data.into_inner();
|
||||
+ let model = model.into_inner().data;
|
||||
|
||||
- let mut mpart = Multipart::with_body(data.open(), boundary);
|
||||
+ enforce_disable_hide_email_policy(&model, &headers, &conn)?;
|
||||
|
||||
- // First entry is the SendData JSON
|
||||
- let mut model_entry = match mpart.read_entry()? {
|
||||
- Some(e) if &*e.headers.name == "model" => e,
|
||||
- Some(_) => err!("Invalid entry name"),
|
||||
- None => err!("No model entry present"),
|
||||
- };
|
||||
-
|
||||
- let mut buf = String::new();
|
||||
- model_entry.data.read_to_string(&mut buf)?;
|
||||
- let data = serde_json::from_str::<crate::util::UpCase<SendData>>(&buf)?;
|
||||
- enforce_disable_hide_email_policy(&data.data, &headers, &conn)?;
|
||||
-
|
||||
// Get the file length and add an extra 5% to avoid issues
|
||||
const SIZE_525_MB: u64 = 550_502_400;
|
||||
|
||||
@@ -212,45 +211,27 @@ fn post_send_file(data: Data, content_type: &ContentTy
|
||||
None => SIZE_525_MB,
|
||||
};
|
||||
|
||||
- // Create the Send
|
||||
- let mut send = create_send(data.data, headers.user.uuid)?;
|
||||
- let file_id = crate::crypto::generate_send_id();
|
||||
-
|
||||
+ let mut send = create_send(model, headers.user.uuid)?;
|
||||
if send.atype != SendType::File as i32 {
|
||||
err!("Send content is not a file");
|
||||
}
|
||||
|
||||
- let file_path = Path::new(&CONFIG.sends_folder()).join(&send.uuid).join(&file_id);
|
||||
+ let size = data.len();
|
||||
+ if size > size_limit {
|
||||
+ err!("Attachment storage limit exceeded with this file");
|
||||
+ }
|
||||
|
||||
- // Read the data entry and save the file
|
||||
- let mut data_entry = match mpart.read_entry()? {
|
||||
- Some(e) if &*e.headers.name == "data" => e,
|
||||
- Some(_) => err!("Invalid entry name"),
|
||||
- None => err!("No model entry present"),
|
||||
- };
|
||||
+ let file_id = crate::crypto::generate_send_id();
|
||||
+ let folder_path = tokio::fs::canonicalize(&CONFIG.sends_folder()).await?.join(&send.uuid);
|
||||
+ let file_path = folder_path.join(&file_id);
|
||||
+ tokio::fs::create_dir_all(&folder_path).await?;
|
||||
+ data.persist_to(&file_path).await?;
|
||||
|
||||
- let size = match data_entry.data.save().memory_threshold(0).size_limit(size_limit).with_path(&file_path) {
|
||||
- SaveResult::Full(SavedData::File(_, size)) => size as i32,
|
||||
- SaveResult::Full(other) => {
|
||||
- std::fs::remove_file(&file_path).ok();
|
||||
- err!(format!("Attachment is not a file: {:?}", other));
|
||||
- }
|
||||
- SaveResult::Partial(_, reason) => {
|
||||
- std::fs::remove_file(&file_path).ok();
|
||||
- err!(format!("Attachment storage limit exceeded with this file: {:?}", reason));
|
||||
- }
|
||||
- SaveResult::Error(e) => {
|
||||
- std::fs::remove_file(&file_path).ok();
|
||||
- err!(format!("Error: {:?}", e));
|
||||
- }
|
||||
- };
|
||||
-
|
||||
- // Set ID and sizes
|
||||
let mut data_value: Value = serde_json::from_str(&send.data)?;
|
||||
if let Some(o) = data_value.as_object_mut() {
|
||||
o.insert(String::from("Id"), Value::String(file_id));
|
||||
o.insert(String::from("Size"), Value::Number(size.into()));
|
||||
- o.insert(String::from("SizeName"), Value::String(crate::util::get_display_size(size)));
|
||||
+ o.insert(String::from("SizeName"), Value::String(crate::util::get_display_size(size as i32)));
|
||||
}
|
||||
send.data = serde_json::to_string(&data_value)?;
|
||||
|
||||
@@ -367,10 +348,10 @@ fn post_access_file(
|
||||
}
|
||||
|
||||
#[get("/sends/<send_id>/<file_id>?<t>")]
|
||||
-fn download_send(send_id: SafeString, file_id: SafeString, t: String) -> Option<NamedFile> {
|
||||
+async fn download_send(send_id: SafeString, file_id: SafeString, t: String) -> Option<NamedFile> {
|
||||
if let Ok(claims) = crate::auth::decode_send(&t) {
|
||||
if claims.sub == format!("{}/{}", send_id, file_id) {
|
||||
- return NamedFile::open(Path::new(&CONFIG.sends_folder()).join(send_id).join(file_id)).ok();
|
||||
+ return NamedFile::open(Path::new(&CONFIG.sends_folder()).join(send_id).join(file_id)).await.ok();
|
||||
}
|
||||
}
|
||||
None
|
@ -0,0 +1,11 @@
|
||||
Index: src/api/core/two_factor/authenticator.rs
|
||||
--- src/api/core/two_factor/authenticator.rs.orig
|
||||
+++ src/api/core/two_factor/authenticator.rs
|
||||
@@ -1,6 +1,6 @@
|
||||
use data_encoding::BASE32;
|
||||
+use rocket::serde::json::Json;
|
||||
use rocket::Route;
|
||||
-use rocket_contrib::json::Json;
|
||||
|
||||
use crate::{
|
||||
api::{
|
@ -0,0 +1,55 @@
|
||||
Index: src/api/core/two_factor/duo.rs
|
||||
--- src/api/core/two_factor/duo.rs.orig
|
||||
+++ src/api/core/two_factor/duo.rs
|
||||
@@ -1,7 +1,7 @@
|
||||
use chrono::Utc;
|
||||
use data_encoding::BASE64;
|
||||
+use rocket::serde::json::Json;
|
||||
use rocket::Route;
|
||||
-use rocket_contrib::json::Json;
|
||||
|
||||
use crate::{
|
||||
api::{core::two_factor::_generate_recover_code, ApiResult, EmptyResult, JsonResult, JsonUpcase, PasswordData},
|
||||
@@ -152,7 +152,7 @@ fn check_duo_fields_custom(data: &EnableDuoData) -> bo
|
||||
}
|
||||
|
||||
#[post("/two-factor/duo", data = "<data>")]
|
||||
-fn activate_duo(data: JsonUpcase<EnableDuoData>, headers: Headers, conn: DbConn) -> JsonResult {
|
||||
+async fn activate_duo(data: JsonUpcase<EnableDuoData>, headers: Headers, conn: DbConn) -> JsonResult {
|
||||
let data: EnableDuoData = data.into_inner().data;
|
||||
let mut user = headers.user;
|
||||
|
||||
@@ -163,7 +163,7 @@ fn activate_duo(data: JsonUpcase<EnableDuoData>, heade
|
||||
let (data, data_str) = if check_duo_fields_custom(&data) {
|
||||
let data_req: DuoData = data.into();
|
||||
let data_str = serde_json::to_string(&data_req)?;
|
||||
- duo_api_request("GET", "/auth/v2/check", "", &data_req).map_res("Failed to validate Duo credentials")?;
|
||||
+ duo_api_request("GET", "/auth/v2/check", "", &data_req).await.map_res("Failed to validate Duo credentials")?;
|
||||
(data_req.obscure(), data_str)
|
||||
} else {
|
||||
(DuoData::secret(), String::new())
|
||||
@@ -185,11 +185,11 @@ fn activate_duo(data: JsonUpcase<EnableDuoData>, heade
|
||||
}
|
||||
|
||||
#[put("/two-factor/duo", data = "<data>")]
|
||||
-fn activate_duo_put(data: JsonUpcase<EnableDuoData>, headers: Headers, conn: DbConn) -> JsonResult {
|
||||
- activate_duo(data, headers, conn)
|
||||
+async fn activate_duo_put(data: JsonUpcase<EnableDuoData>, headers: Headers, conn: DbConn) -> JsonResult {
|
||||
+ activate_duo(data, headers, conn).await
|
||||
}
|
||||
|
||||
-fn duo_api_request(method: &str, path: &str, params: &str, data: &DuoData) -> EmptyResult {
|
||||
+async fn duo_api_request(method: &str, path: &str, params: &str, data: &DuoData) -> EmptyResult {
|
||||
use reqwest::{header, Method};
|
||||
use std::str::FromStr;
|
||||
|
||||
@@ -209,7 +209,8 @@ fn duo_api_request(method: &str, path: &str, params: &
|
||||
.basic_auth(username, Some(password))
|
||||
.header(header::USER_AGENT, "vaultwarden:Duo/1.0 (Rust)")
|
||||
.header(header::DATE, date)
|
||||
- .send()?
|
||||
+ .send()
|
||||
+ .await?
|
||||
.error_for_status()?;
|
||||
|
||||
Ok(())
|
@ -0,0 +1,11 @@
|
||||
Index: src/api/core/two_factor/email.rs
|
||||
--- src/api/core/two_factor/email.rs.orig
|
||||
+++ src/api/core/two_factor/email.rs
|
||||
@@ -1,6 +1,6 @@
|
||||
use chrono::{Duration, NaiveDateTime, Utc};
|
||||
+use rocket::serde::json::Json;
|
||||
use rocket::Route;
|
||||
-use rocket_contrib::json::Json;
|
||||
|
||||
use crate::{
|
||||
api::{core::two_factor::_generate_recover_code, EmptyResult, JsonResult, JsonUpcase, PasswordData},
|
@ -0,0 +1,29 @@
|
||||
Index: src/api/core/two_factor/mod.rs
|
||||
--- src/api/core/two_factor/mod.rs.orig
|
||||
+++ src/api/core/two_factor/mod.rs
|
||||
@@ -1,7 +1,7 @@
|
||||
use chrono::{Duration, Utc};
|
||||
use data_encoding::BASE32;
|
||||
+use rocket::serde::json::Json;
|
||||
use rocket::Route;
|
||||
-use rocket_contrib::json::Json;
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{
|
||||
@@ -158,14 +158,14 @@ fn disable_twofactor_put(data: JsonUpcase<DisableTwoFa
|
||||
disable_twofactor(data, headers, conn)
|
||||
}
|
||||
|
||||
-pub fn send_incomplete_2fa_notifications(pool: DbPool) {
|
||||
+pub async fn send_incomplete_2fa_notifications(pool: DbPool) {
|
||||
debug!("Sending notifications for incomplete 2FA logins");
|
||||
|
||||
if CONFIG.incomplete_2fa_time_limit() <= 0 || !CONFIG.mail_enabled() {
|
||||
return;
|
||||
}
|
||||
|
||||
- let conn = match pool.get() {
|
||||
+ let conn = match pool.get().await {
|
||||
Ok(conn) => conn,
|
||||
_ => {
|
||||
error!("Failed to get DB connection in send_incomplete_2fa_notifications()");
|
@ -0,0 +1,11 @@
|
||||
Index: src/api/core/two_factor/u2f.rs
|
||||
--- src/api/core/two_factor/u2f.rs.orig
|
||||
+++ src/api/core/two_factor/u2f.rs
|
||||
@@ -1,6 +1,6 @@
|
||||
use once_cell::sync::Lazy;
|
||||
+use rocket::serde::json::Json;
|
||||
use rocket::Route;
|
||||
-use rocket_contrib::json::Json;
|
||||
use serde_json::Value;
|
||||
use u2f::{
|
||||
messages::{RegisterResponse, SignResponse, U2fSignRequest},
|
@ -0,0 +1,10 @@
|
||||
Index: src/api/core/two_factor/webauthn.rs
|
||||
--- src/api/core/two_factor/webauthn.rs.orig
|
||||
+++ src/api/core/two_factor/webauthn.rs
|
||||
@@ -1,5 +1,5 @@
|
||||
+use rocket::serde::json::Json;
|
||||
use rocket::Route;
|
||||
-use rocket_contrib::json::Json;
|
||||
use serde_json::Value;
|
||||
use url::Url;
|
||||
use webauthn_rs::{base64_data::Base64UrlSafeData, proto::*, AuthenticationState, RegistrationState, Webauthn};
|
@ -0,0 +1,10 @@
|
||||
Index: src/api/core/two_factor/yubikey.rs
|
||||
--- src/api/core/two_factor/yubikey.rs.orig
|
||||
+++ src/api/core/two_factor/yubikey.rs
|
||||
@@ -1,5 +1,5 @@
|
||||
+use rocket::serde::json::Json;
|
||||
use rocket::Route;
|
||||
-use rocket_contrib::json::Json;
|
||||
use serde_json::Value;
|
||||
use yubico::{config::Config, verify};
|
||||
|
325
security/vaultwarden/patches/patch-src_api_icons_rs
Normal file
325
security/vaultwarden/patches/patch-src_api_icons_rs
Normal file
@ -0,0 +1,325 @@
|
||||
Index: src/api/icons.rs
|
||||
--- src/api/icons.rs.orig
|
||||
+++ src/api/icons.rs
|
||||
@@ -1,19 +1,19 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
- fs::{create_dir_all, remove_file, symlink_metadata, File},
|
||||
- io::prelude::*,
|
||||
net::{IpAddr, ToSocketAddrs},
|
||||
sync::{Arc, RwLock},
|
||||
time::{Duration, SystemTime},
|
||||
};
|
||||
|
||||
+use bytes::{Buf, Bytes, BytesMut};
|
||||
+use futures::{stream::StreamExt, TryFutureExt};
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
-use reqwest::{blocking::Client, blocking::Response, header};
|
||||
-use rocket::{
|
||||
- http::ContentType,
|
||||
- response::{Content, Redirect},
|
||||
- Route,
|
||||
+use reqwest::{header, Client, Response};
|
||||
+use rocket::{http::ContentType, response::Redirect, Route};
|
||||
+use tokio::{
|
||||
+ fs::{create_dir_all, remove_file, symlink_metadata, File},
|
||||
+ io::{AsyncReadExt, AsyncWriteExt},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
@@ -104,27 +104,23 @@ fn icon_google(domain: String) -> Option<Redirect> {
|
||||
}
|
||||
|
||||
#[get("/<domain>/icon.png")]
|
||||
-fn icon_internal(domain: String) -> Cached<Content<Vec<u8>>> {
|
||||
+async fn icon_internal(domain: String) -> Cached<(ContentType, Vec<u8>)> {
|
||||
const FALLBACK_ICON: &[u8] = include_bytes!("../static/images/fallback-icon.png");
|
||||
|
||||
if !is_valid_domain(&domain) {
|
||||
warn!("Invalid domain: {}", domain);
|
||||
return Cached::ttl(
|
||||
- Content(ContentType::new("image", "png"), FALLBACK_ICON.to_vec()),
|
||||
+ (ContentType::new("image", "png"), FALLBACK_ICON.to_vec()),
|
||||
CONFIG.icon_cache_negttl(),
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
- match get_icon(&domain) {
|
||||
+ match get_icon(&domain).await {
|
||||
Some((icon, icon_type)) => {
|
||||
- Cached::ttl(Content(ContentType::new("image", icon_type), icon), CONFIG.icon_cache_ttl(), true)
|
||||
+ Cached::ttl((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(),
|
||||
- true,
|
||||
- ),
|
||||
+ _ => Cached::ttl((ContentType::new("image", "png"), FALLBACK_ICON.to_vec()), CONFIG.icon_cache_negttl(), true),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,15 +313,15 @@ fn is_domain_blacklisted(domain: &str) -> bool {
|
||||
is_blacklisted
|
||||
}
|
||||
|
||||
-fn get_icon(domain: &str) -> Option<(Vec<u8>, String)> {
|
||||
+async fn get_icon(domain: &str) -> Option<(Vec<u8>, String)> {
|
||||
let path = format!("{}/{}.png", CONFIG.icon_cache_folder(), domain);
|
||||
|
||||
// Check for expiration of negatively cached copy
|
||||
- if icon_is_negcached(&path) {
|
||||
+ if icon_is_negcached(&path).await {
|
||||
return None;
|
||||
}
|
||||
|
||||
- if let Some(icon) = get_cached_icon(&path) {
|
||||
+ if let Some(icon) = get_cached_icon(&path).await {
|
||||
let icon_type = match get_icon_type(&icon) {
|
||||
Some(x) => x,
|
||||
_ => "x-icon",
|
||||
@@ -338,31 +334,31 @@ fn get_icon(domain: &str) -> Option<(Vec<u8>, String)>
|
||||
}
|
||||
|
||||
// Get the icon, or None in case of error
|
||||
- match download_icon(domain) {
|
||||
+ match download_icon(domain).await {
|
||||
Ok((icon, icon_type)) => {
|
||||
- save_icon(&path, &icon);
|
||||
- Some((icon, icon_type.unwrap_or("x-icon").to_string()))
|
||||
+ save_icon(&path, &icon).await;
|
||||
+ Some((icon.to_vec(), icon_type.unwrap_or("x-icon").to_string()))
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("Unable to download icon: {:?}", e);
|
||||
let miss_indicator = path + ".miss";
|
||||
- save_icon(&miss_indicator, &[]);
|
||||
+ save_icon(&miss_indicator, &[]).await;
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-fn get_cached_icon(path: &str) -> Option<Vec<u8>> {
|
||||
+async fn get_cached_icon(path: &str) -> Option<Vec<u8>> {
|
||||
// Check for expiration of successfully cached copy
|
||||
- if icon_is_expired(path) {
|
||||
+ if icon_is_expired(path).await {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Try to read the cached icon, and return it if it exists
|
||||
- if let Ok(mut f) = File::open(path) {
|
||||
+ if let Ok(mut f) = File::open(path).await {
|
||||
let mut buffer = Vec::new();
|
||||
|
||||
- if f.read_to_end(&mut buffer).is_ok() {
|
||||
+ if f.read_to_end(&mut buffer).await.is_ok() {
|
||||
return Some(buffer);
|
||||
}
|
||||
}
|
||||
@@ -370,22 +366,22 @@ fn get_cached_icon(path: &str) -> Option<Vec<u8>> {
|
||||
None
|
||||
}
|
||||
|
||||
-fn file_is_expired(path: &str, ttl: u64) -> Result<bool, Error> {
|
||||
- let meta = symlink_metadata(path)?;
|
||||
+async fn file_is_expired(path: &str, ttl: u64) -> Result<bool, Error> {
|
||||
+ let meta = symlink_metadata(path).await?;
|
||||
let modified = meta.modified()?;
|
||||
let age = SystemTime::now().duration_since(modified)?;
|
||||
|
||||
Ok(ttl > 0 && ttl <= age.as_secs())
|
||||
}
|
||||
|
||||
-fn icon_is_negcached(path: &str) -> bool {
|
||||
+async fn icon_is_negcached(path: &str) -> bool {
|
||||
let miss_indicator = path.to_owned() + ".miss";
|
||||
- let expired = file_is_expired(&miss_indicator, CONFIG.icon_cache_negttl());
|
||||
+ let expired = file_is_expired(&miss_indicator, CONFIG.icon_cache_negttl()).await;
|
||||
|
||||
match expired {
|
||||
// No longer negatively cached, drop the marker
|
||||
Ok(true) => {
|
||||
- if let Err(e) = remove_file(&miss_indicator) {
|
||||
+ if let Err(e) = remove_file(&miss_indicator).await {
|
||||
error!("Could not remove negative cache indicator for icon {:?}: {:?}", path, e);
|
||||
}
|
||||
false
|
||||
@@ -397,8 +393,8 @@ fn icon_is_negcached(path: &str) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
-fn icon_is_expired(path: &str) -> bool {
|
||||
- let expired = file_is_expired(path, CONFIG.icon_cache_ttl());
|
||||
+async fn icon_is_expired(path: &str) -> bool {
|
||||
+ let expired = file_is_expired(path, CONFIG.icon_cache_ttl()).await;
|
||||
expired.unwrap_or(true)
|
||||
}
|
||||
|
||||
@@ -521,13 +517,13 @@ struct IconUrlResult {
|
||||
/// let icon_result = get_icon_url("github.com")?;
|
||||
/// let icon_result = get_icon_url("vaultwarden.discourse.group")?;
|
||||
/// ```
|
||||
-fn get_icon_url(domain: &str) -> Result<IconUrlResult, Error> {
|
||||
+async fn get_icon_url(domain: &str) -> Result<IconUrlResult, Error> {
|
||||
// Default URL with secure and insecure schemes
|
||||
let ssldomain = format!("https://{}", domain);
|
||||
let httpdomain = format!("http://{}", domain);
|
||||
|
||||
// First check the domain as given during the request for both HTTPS and HTTP.
|
||||
- let resp = match get_page(&ssldomain).or_else(|_| get_page(&httpdomain)) {
|
||||
+ let resp = match get_page(&ssldomain).or_else(|_| get_page(&httpdomain)).await {
|
||||
Ok(c) => Ok(c),
|
||||
Err(e) => {
|
||||
let mut sub_resp = Err(e);
|
||||
@@ -546,7 +542,7 @@ fn get_icon_url(domain: &str) -> Result<IconUrlResult,
|
||||
let httpbase = format!("http://{}", base_domain);
|
||||
debug!("[get_icon_url]: Trying without subdomains '{}'", base_domain);
|
||||
|
||||
- sub_resp = get_page(&sslbase).or_else(|_| get_page(&httpbase));
|
||||
+ sub_resp = get_page(&sslbase).or_else(|_| get_page(&httpbase)).await;
|
||||
}
|
||||
|
||||
// When the domain is not an IP, and has less then 2 dots, try to add www. infront of it.
|
||||
@@ -557,7 +553,7 @@ fn get_icon_url(domain: &str) -> Result<IconUrlResult,
|
||||
let httpwww = format!("http://{}", www_domain);
|
||||
debug!("[get_icon_url]: Trying with www. prefix '{}'", www_domain);
|
||||
|
||||
- sub_resp = get_page(&sslwww).or_else(|_| get_page(&httpwww));
|
||||
+ sub_resp = get_page(&sslwww).or_else(|_| get_page(&httpwww)).await;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -581,7 +577,7 @@ fn get_icon_url(domain: &str) -> Result<IconUrlResult,
|
||||
iconlist.push(Icon::new(35, String::from(url.join("/favicon.ico").unwrap())));
|
||||
|
||||
// 384KB should be more than enough for the HTML, though as we only really need the HTML header.
|
||||
- let mut limited_reader = content.take(384 * 1024);
|
||||
+ let mut limited_reader = stream_to_bytes_limit(content, 384 * 1024).await?.reader();
|
||||
|
||||
use html5ever::tendril::TendrilSink;
|
||||
let dom = html5ever::parse_document(markup5ever_rcdom::RcDom::default(), Default::default())
|
||||
@@ -607,11 +603,11 @@ fn get_icon_url(domain: &str) -> Result<IconUrlResult,
|
||||
})
|
||||
}
|
||||
|
||||
-fn get_page(url: &str) -> Result<Response, Error> {
|
||||
- get_page_with_referer(url, "")
|
||||
+async fn get_page(url: &str) -> Result<Response, Error> {
|
||||
+ get_page_with_referer(url, "").await
|
||||
}
|
||||
|
||||
-fn get_page_with_referer(url: &str, referer: &str) -> Result<Response, Error> {
|
||||
+async 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()) {
|
||||
warn!("Favicon '{}' resolves to a blacklisted domain or IP!", url);
|
||||
}
|
||||
@@ -621,7 +617,7 @@ fn get_page_with_referer(url: &str, referer: &str) ->
|
||||
client = client.header("Referer", referer)
|
||||
}
|
||||
|
||||
- match client.send() {
|
||||
+ match client.send().await {
|
||||
Ok(c) => c.error_for_status().map_err(Into::into),
|
||||
Err(e) => err_silent!(format!("{}", e)),
|
||||
}
|
||||
@@ -706,14 +702,14 @@ fn parse_sizes(sizes: Option<&str>) -> (u16, u16) {
|
||||
(width, height)
|
||||
}
|
||||
|
||||
-fn download_icon(domain: &str) -> Result<(Vec<u8>, Option<&str>), Error> {
|
||||
+async fn download_icon(domain: &str) -> Result<(Bytes, Option<&str>), Error> {
|
||||
if is_domain_blacklisted(domain) {
|
||||
err_silent!("Domain is blacklisted", domain)
|
||||
}
|
||||
|
||||
- let icon_result = get_icon_url(domain)?;
|
||||
+ let icon_result = get_icon_url(domain).await?;
|
||||
|
||||
- let mut buffer = Vec::new();
|
||||
+ let mut buffer = Bytes::new();
|
||||
let mut icon_type: Option<&str> = None;
|
||||
|
||||
use data_url::DataUrl;
|
||||
@@ -722,8 +718,12 @@ fn download_icon(domain: &str) -> Result<(Vec<u8>, Opt
|
||||
if icon.href.starts_with("data:image") {
|
||||
let datauri = DataUrl::process(&icon.href).unwrap();
|
||||
// Check if we are able to decode the data uri
|
||||
- match datauri.decode_to_vec() {
|
||||
- Ok((body, _fragment)) => {
|
||||
+ let mut body = BytesMut::new();
|
||||
+ match datauri.decode::<_, ()>(|bytes| {
|
||||
+ body.extend_from_slice(bytes);
|
||||
+ Ok(())
|
||||
+ }) {
|
||||
+ Ok(_) => {
|
||||
// Also check if the size is atleast 67 bytes, which seems to be the smallest png i could create
|
||||
if body.len() >= 67 {
|
||||
// Check if the icon type is allowed, else try an icon from the list.
|
||||
@@ -733,17 +733,17 @@ fn download_icon(domain: &str) -> Result<(Vec<u8>, Opt
|
||||
continue;
|
||||
}
|
||||
info!("Extracted icon from data:image uri for {}", domain);
|
||||
- buffer = body;
|
||||
+ buffer = body.freeze();
|
||||
break;
|
||||
}
|
||||
}
|
||||
_ => debug!("Extracted icon from data:image uri is invalid"),
|
||||
};
|
||||
} else {
|
||||
- match get_page_with_referer(&icon.href, &icon_result.referer) {
|
||||
- Ok(mut res) => {
|
||||
- res.copy_to(&mut buffer)?;
|
||||
- // Check if the icon type is allowed, else try an icon from the list.
|
||||
+ match get_page_with_referer(&icon.href, &icon_result.referer).await {
|
||||
+ Ok(res) => {
|
||||
+ buffer = stream_to_bytes_limit(res, 512 * 1024).await?; // 512 KB for each icon max
|
||||
+ // Check if the icon type is allowed, else try an icon from the list.
|
||||
icon_type = get_icon_type(&buffer);
|
||||
if icon_type.is_none() {
|
||||
buffer.clear();
|
||||
@@ -765,13 +765,13 @@ fn download_icon(domain: &str) -> Result<(Vec<u8>, Opt
|
||||
Ok((buffer, icon_type))
|
||||
}
|
||||
|
||||
-fn save_icon(path: &str, icon: &[u8]) {
|
||||
- match File::create(path) {
|
||||
+async fn save_icon(path: &str, icon: &[u8]) {
|
||||
+ match File::create(path).await {
|
||||
Ok(mut f) => {
|
||||
- f.write_all(icon).expect("Error writing icon file");
|
||||
+ f.write_all(icon).await.expect("Error writing icon file");
|
||||
}
|
||||
Err(ref e) if e.kind() == std::io::ErrorKind::NotFound => {
|
||||
- create_dir_all(&CONFIG.icon_cache_folder()).expect("Error creating icon cache folder");
|
||||
+ create_dir_all(&CONFIG.icon_cache_folder()).await.expect("Error creating icon cache folder");
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("Unable to save icon: {:?}", e);
|
||||
@@ -820,8 +820,6 @@ impl reqwest::cookie::CookieStore for Jar {
|
||||
}
|
||||
|
||||
fn cookies(&self, url: &url::Url) -> Option<header::HeaderValue> {
|
||||
- use bytes::Bytes;
|
||||
-
|
||||
let cookie_store = self.0.read().unwrap();
|
||||
let s = cookie_store
|
||||
.get_request_values(url)
|
||||
@@ -835,4 +833,13 @@ impl reqwest::cookie::CookieStore for Jar {
|
||||
|
||||
header::HeaderValue::from_maybe_shared(Bytes::from(s)).ok()
|
||||
}
|
||||
+}
|
||||
+
|
||||
+async fn stream_to_bytes_limit(res: Response, max_size: usize) -> Result<Bytes, reqwest::Error> {
|
||||
+ let mut stream = res.bytes_stream().take(max_size);
|
||||
+ let mut buf = BytesMut::new();
|
||||
+ while let Some(chunk) = stream.next().await {
|
||||
+ buf.extend(chunk?);
|
||||
+ }
|
||||
+ Ok(buf.freeze())
|
||||
}
|
110
security/vaultwarden/patches/patch-src_api_identity_rs
Normal file
110
security/vaultwarden/patches/patch-src_api_identity_rs
Normal file
@ -0,0 +1,110 @@
|
||||
Index: src/api/identity.rs
|
||||
--- src/api/identity.rs.orig
|
||||
+++ src/api/identity.rs
|
||||
@@ -1,10 +1,10 @@
|
||||
use chrono::Utc;
|
||||
use num_traits::FromPrimitive;
|
||||
+use rocket::serde::json::Json;
|
||||
use rocket::{
|
||||
- request::{Form, FormItems, FromForm},
|
||||
+ form::{Form, FromForm},
|
||||
Route,
|
||||
};
|
||||
-use rocket_contrib::json::Json;
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{
|
||||
@@ -455,64 +455,55 @@ fn _json_err_twofactor(providers: &[i32], user_uuid: &
|
||||
|
||||
// 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
|
||||
-#[derive(Debug, Clone, Default)]
|
||||
+#[derive(Debug, Clone, Default, FromForm)]
|
||||
#[allow(non_snake_case)]
|
||||
struct ConnectData {
|
||||
- // refresh_token, password, client_credentials (API key)
|
||||
- grant_type: String,
|
||||
+ #[field(name = uncased("grant_type"))]
|
||||
+ #[field(name = uncased("granttype"))]
|
||||
+ grant_type: String, // refresh_token, password, client_credentials (API key)
|
||||
|
||||
// Needed for grant_type="refresh_token"
|
||||
+ #[field(name = uncased("refresh_token"))]
|
||||
+ #[field(name = uncased("refreshtoken"))]
|
||||
refresh_token: Option<String>,
|
||||
|
||||
// Needed for grant_type = "password" | "client_credentials"
|
||||
- client_id: Option<String>, // web, cli, desktop, browser, mobile
|
||||
- client_secret: Option<String>, // API key login (cli only)
|
||||
+ #[field(name = uncased("client_id"))]
|
||||
+ #[field(name = uncased("clientid"))]
|
||||
+ client_id: Option<String>, // web, cli, desktop, browser, mobile
|
||||
+ #[field(name = uncased("client_secret"))]
|
||||
+ #[field(name = uncased("clientsecret"))]
|
||||
+ client_secret: Option<String>,
|
||||
+ #[field(name = uncased("password"))]
|
||||
password: Option<String>,
|
||||
+ #[field(name = uncased("scope"))]
|
||||
scope: Option<String>,
|
||||
+ #[field(name = uncased("username"))]
|
||||
username: Option<String>,
|
||||
|
||||
+ #[field(name = uncased("device_identifier"))]
|
||||
+ #[field(name = uncased("deviceidentifier"))]
|
||||
device_identifier: Option<String>,
|
||||
+ #[field(name = uncased("device_name"))]
|
||||
+ #[field(name = uncased("devicename"))]
|
||||
device_name: Option<String>,
|
||||
+ #[field(name = uncased("device_type"))]
|
||||
+ #[field(name = uncased("devicetype"))]
|
||||
device_type: Option<String>,
|
||||
+ #[field(name = uncased("device_push_token"))]
|
||||
+ #[field(name = uncased("devicepushtoken"))]
|
||||
device_push_token: Option<String>, // Unused; mobile device push not yet supported.
|
||||
|
||||
// Needed for two-factor auth
|
||||
+ #[field(name = uncased("two_factor_provider"))]
|
||||
+ #[field(name = uncased("twofactorprovider"))]
|
||||
two_factor_provider: Option<i32>,
|
||||
+ #[field(name = uncased("two_factor_token"))]
|
||||
+ #[field(name = uncased("twofactortoken"))]
|
||||
two_factor_token: Option<String>,
|
||||
+ #[field(name = uncased("two_factor_remember"))]
|
||||
+ #[field(name = uncased("twofactorremember"))]
|
||||
two_factor_remember: Option<i32>,
|
||||
-}
|
||||
-
|
||||
-impl<'f> FromForm<'f> for ConnectData {
|
||||
- type Error = String;
|
||||
-
|
||||
- fn from_form(items: &mut FormItems<'f>, _strict: bool) -> Result<Self, Self::Error> {
|
||||
- let mut form = Self::default();
|
||||
- for item in items {
|
||||
- let (key, value) = item.key_value_decoded();
|
||||
- let mut normalized_key = key.to_lowercase();
|
||||
- normalized_key.retain(|c| c != '_'); // Remove '_'
|
||||
-
|
||||
- match normalized_key.as_ref() {
|
||||
- "granttype" => form.grant_type = value,
|
||||
- "refreshtoken" => form.refresh_token = Some(value),
|
||||
- "clientid" => form.client_id = Some(value),
|
||||
- "clientsecret" => form.client_secret = Some(value),
|
||||
- "password" => form.password = Some(value),
|
||||
- "scope" => form.scope = Some(value),
|
||||
- "username" => form.username = Some(value),
|
||||
- "deviceidentifier" => form.device_identifier = Some(value),
|
||||
- "devicename" => form.device_name = Some(value),
|
||||
- "devicetype" => form.device_type = Some(value),
|
||||
- "devicepushtoken" => form.device_push_token = Some(value),
|
||||
- "twofactorprovider" => form.two_factor_provider = value.parse().ok(),
|
||||
- "twofactortoken" => form.two_factor_token = Some(value),
|
||||
- "twofactorremember" => form.two_factor_remember = value.parse().ok(),
|
||||
- key => warn!("Detected unexpected parameter during login: {}", key),
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- Ok(form)
|
||||
- }
|
||||
}
|
||||
|
||||
fn _check_is_some<T>(value: &Option<T>, msg: &str) -> EmptyResult {
|
12
security/vaultwarden/patches/patch-src_api_mod_rs
Normal file
12
security/vaultwarden/patches/patch-src_api_mod_rs
Normal file
@ -0,0 +1,12 @@
|
||||
Index: src/api/mod.rs
|
||||
--- src/api/mod.rs.orig
|
||||
+++ src/api/mod.rs
|
||||
@@ -5,7 +5,7 @@ mod identity;
|
||||
mod notifications;
|
||||
mod web;
|
||||
|
||||
-use rocket_contrib::json::Json;
|
||||
+use rocket::serde::json::Json;
|
||||
use serde_json::Value;
|
||||
|
||||
pub use crate::api::{
|
39
security/vaultwarden/patches/patch-src_api_notifications_rs
Normal file
39
security/vaultwarden/patches/patch-src_api_notifications_rs
Normal file
@ -0,0 +1,39 @@
|
||||
Index: src/api/notifications.rs
|
||||
--- src/api/notifications.rs.orig
|
||||
+++ src/api/notifications.rs
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
+use rocket::serde::json::Json;
|
||||
use rocket::Route;
|
||||
-use rocket_contrib::json::Json;
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
use crate::{api::EmptyResult, auth::Headers, Error, CONFIG};
|
||||
@@ -417,7 +417,7 @@ pub enum UpdateType {
|
||||
}
|
||||
|
||||
use rocket::State;
|
||||
-pub type Notify<'a> = State<'a, WebSocketUsers>;
|
||||
+pub type Notify<'a> = &'a State<WebSocketUsers>;
|
||||
|
||||
pub fn start_notification_server() -> WebSocketUsers {
|
||||
let factory = WsFactory::init();
|
||||
@@ -430,12 +430,11 @@ pub fn start_notification_server() -> WebSocketUsers {
|
||||
settings.queue_size = 2;
|
||||
settings.panic_on_internal = false;
|
||||
|
||||
- ws::Builder::new()
|
||||
- .with_settings(settings)
|
||||
- .build(factory)
|
||||
- .unwrap()
|
||||
- .listen((CONFIG.websocket_address().as_str(), CONFIG.websocket_port()))
|
||||
- .unwrap();
|
||||
+ let ws = ws::Builder::new().with_settings(settings).build(factory).unwrap();
|
||||
+ CONFIG.set_ws_shutdown_handle(ws.broadcaster());
|
||||
+ ws.listen((CONFIG.websocket_address().as_str(), CONFIG.websocket_port())).unwrap();
|
||||
+
|
||||
+ warn!("WS Server stopped!");
|
||||
});
|
||||
}
|
||||
|
90
security/vaultwarden/patches/patch-src_api_web_rs
Normal file
90
security/vaultwarden/patches/patch-src_api_web_rs
Normal file
@ -0,0 +1,90 @@
|
||||
Index: src/api/web.rs
|
||||
--- src/api/web.rs.orig
|
||||
+++ src/api/web.rs
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
-use rocket::{http::ContentType, response::content::Content, response::NamedFile, Route};
|
||||
-use rocket_contrib::json::Json;
|
||||
+use rocket::serde::json::Json;
|
||||
+use rocket::{fs::NamedFile, http::ContentType, Route};
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{
|
||||
@@ -21,16 +21,16 @@ pub fn routes() -> Vec<Route> {
|
||||
}
|
||||
|
||||
#[get("/")]
|
||||
-fn web_index() -> Cached<Option<NamedFile>> {
|
||||
- Cached::short(NamedFile::open(Path::new(&CONFIG.web_vault_folder()).join("index.html")).ok(), false)
|
||||
+async fn web_index() -> Cached<Option<NamedFile>> {
|
||||
+ Cached::short(NamedFile::open(Path::new(&CONFIG.web_vault_folder()).join("index.html")).await.ok(), false)
|
||||
}
|
||||
|
||||
#[get("/app-id.json")]
|
||||
-fn app_id() -> Cached<Content<Json<Value>>> {
|
||||
+fn app_id() -> Cached<(ContentType, Json<Value>)> {
|
||||
let content_type = ContentType::new("application", "fido.trusted-apps+json");
|
||||
|
||||
Cached::long(
|
||||
- Content(
|
||||
+ (
|
||||
content_type,
|
||||
Json(json!({
|
||||
"trustedFacets": [
|
||||
@@ -58,13 +58,13 @@ fn app_id() -> Cached<Content<Json<Value>>> {
|
||||
}
|
||||
|
||||
#[get("/<p..>", rank = 10)] // Only match this if the other routes don't match
|
||||
-fn web_files(p: PathBuf) -> Cached<Option<NamedFile>> {
|
||||
- Cached::long(NamedFile::open(Path::new(&CONFIG.web_vault_folder()).join(p)).ok(), true)
|
||||
+async fn web_files(p: PathBuf) -> Cached<Option<NamedFile>> {
|
||||
+ Cached::long(NamedFile::open(Path::new(&CONFIG.web_vault_folder()).join(p)).await.ok(), true)
|
||||
}
|
||||
|
||||
#[get("/attachments/<uuid>/<file_id>")]
|
||||
-fn attachments(uuid: SafeString, file_id: SafeString) -> Option<NamedFile> {
|
||||
- NamedFile::open(Path::new(&CONFIG.attachments_folder()).join(uuid).join(file_id)).ok()
|
||||
+async fn attachments(uuid: SafeString, file_id: SafeString) -> Option<NamedFile> {
|
||||
+ NamedFile::open(Path::new(&CONFIG.attachments_folder()).join(uuid).join(file_id)).await.ok()
|
||||
}
|
||||
|
||||
// We use DbConn here to let the alive healthcheck also verify the database connection.
|
||||
@@ -78,25 +78,20 @@ fn alive(_conn: DbConn) -> Json<String> {
|
||||
}
|
||||
|
||||
#[get("/vw_static/<filename>")]
|
||||
-fn static_files(filename: String) -> Result<Content<&'static [u8]>, Error> {
|
||||
+fn static_files(filename: String) -> Result<(ContentType, &'static [u8]), Error> {
|
||||
match filename.as_ref() {
|
||||
- "mail-github.png" => Ok(Content(ContentType::PNG, include_bytes!("../static/images/mail-github.png"))),
|
||||
- "logo-gray.png" => Ok(Content(ContentType::PNG, include_bytes!("../static/images/logo-gray.png"))),
|
||||
- "error-x.svg" => Ok(Content(ContentType::SVG, include_bytes!("../static/images/error-x.svg"))),
|
||||
- "hibp.png" => Ok(Content(ContentType::PNG, include_bytes!("../static/images/hibp.png"))),
|
||||
- "vaultwarden-icon.png" => {
|
||||
- Ok(Content(ContentType::PNG, include_bytes!("../static/images/vaultwarden-icon.png")))
|
||||
- }
|
||||
-
|
||||
- "bootstrap.css" => Ok(Content(ContentType::CSS, include_bytes!("../static/scripts/bootstrap.css"))),
|
||||
- "bootstrap-native.js" => {
|
||||
- Ok(Content(ContentType::JavaScript, include_bytes!("../static/scripts/bootstrap-native.js")))
|
||||
- }
|
||||
- "identicon.js" => Ok(Content(ContentType::JavaScript, include_bytes!("../static/scripts/identicon.js"))),
|
||||
- "datatables.js" => Ok(Content(ContentType::JavaScript, include_bytes!("../static/scripts/datatables.js"))),
|
||||
- "datatables.css" => Ok(Content(ContentType::CSS, include_bytes!("../static/scripts/datatables.css"))),
|
||||
+ "mail-github.png" => Ok((ContentType::PNG, include_bytes!("../static/images/mail-github.png"))),
|
||||
+ "logo-gray.png" => Ok((ContentType::PNG, include_bytes!("../static/images/logo-gray.png"))),
|
||||
+ "error-x.svg" => Ok((ContentType::SVG, include_bytes!("../static/images/error-x.svg"))),
|
||||
+ "hibp.png" => Ok((ContentType::PNG, include_bytes!("../static/images/hibp.png"))),
|
||||
+ "vaultwarden-icon.png" => Ok((ContentType::PNG, include_bytes!("../static/images/vaultwarden-icon.png"))),
|
||||
+ "bootstrap.css" => Ok((ContentType::CSS, include_bytes!("../static/scripts/bootstrap.css"))),
|
||||
+ "bootstrap-native.js" => Ok((ContentType::JavaScript, include_bytes!("../static/scripts/bootstrap-native.js"))),
|
||||
+ "identicon.js" => Ok((ContentType::JavaScript, include_bytes!("../static/scripts/identicon.js"))),
|
||||
+ "datatables.js" => Ok((ContentType::JavaScript, include_bytes!("../static/scripts/datatables.js"))),
|
||||
+ "datatables.css" => Ok((ContentType::CSS, include_bytes!("../static/scripts/datatables.css"))),
|
||||
"jquery-3.6.0.slim.js" => {
|
||||
- Ok(Content(ContentType::JavaScript, include_bytes!("../static/scripts/jquery-3.6.0.slim.js")))
|
||||
+ Ok((ContentType::JavaScript, include_bytes!("../static/scripts/jquery-3.6.0.slim.js")))
|
||||
}
|
||||
_ => err!(format!("Static file not found: {}", filename)),
|
||||
}
|
392
security/vaultwarden/patches/patch-src_auth_rs
Normal file
392
security/vaultwarden/patches/patch-src_auth_rs
Normal file
@ -0,0 +1,392 @@
|
||||
Index: src/auth.rs
|
||||
--- src/auth.rs.orig
|
||||
+++ src/auth.rs
|
||||
@@ -257,7 +257,10 @@ pub fn generate_send_claims(send_id: &str, file_id: &s
|
||||
//
|
||||
// Bearer token authentication
|
||||
//
|
||||
-use rocket::request::{FromRequest, Outcome, Request};
|
||||
+use rocket::{
|
||||
+ outcome::try_outcome,
|
||||
+ request::{FromRequest, Outcome, Request},
|
||||
+};
|
||||
|
||||
use crate::db::{
|
||||
models::{CollectionUser, Device, User, UserOrgStatus, UserOrgType, UserOrganization, UserStampException},
|
||||
@@ -268,10 +271,11 @@ pub struct Host {
|
||||
pub host: String,
|
||||
}
|
||||
|
||||
-impl<'a, 'r> FromRequest<'a, 'r> for Host {
|
||||
+#[rocket::async_trait]
|
||||
+impl<'r> FromRequest<'r> for Host {
|
||||
type Error = &'static str;
|
||||
|
||||
- fn from_request(request: &'a Request<'r>) -> Outcome<Self, Self::Error> {
|
||||
+ async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> {
|
||||
let headers = request.headers();
|
||||
|
||||
// Get host
|
||||
@@ -314,17 +318,14 @@ pub struct Headers {
|
||||
pub user: User,
|
||||
}
|
||||
|
||||
-impl<'a, 'r> FromRequest<'a, 'r> for Headers {
|
||||
+#[rocket::async_trait]
|
||||
+impl<'r> FromRequest<'r> for Headers {
|
||||
type Error = &'static str;
|
||||
|
||||
- fn from_request(request: &'a Request<'r>) -> Outcome<Self, Self::Error> {
|
||||
+ async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> {
|
||||
let headers = request.headers();
|
||||
|
||||
- let host = match Host::from_request(request) {
|
||||
- Outcome::Forward(_) => return Outcome::Forward(()),
|
||||
- Outcome::Failure(f) => return Outcome::Failure(f),
|
||||
- Outcome::Success(host) => host.host,
|
||||
- };
|
||||
+ let host = try_outcome!(Host::from_request(request).await).host;
|
||||
|
||||
// Get access_token
|
||||
let access_token: &str = match headers.get_one("Authorization") {
|
||||
@@ -344,7 +345,7 @@ impl<'a, 'r> FromRequest<'a, 'r> for Headers {
|
||||
let device_uuid = claims.device;
|
||||
let user_uuid = claims.sub;
|
||||
|
||||
- let conn = match request.guard::<DbConn>() {
|
||||
+ let conn = match DbConn::from_request(request).await {
|
||||
Outcome::Success(conn) => conn,
|
||||
_ => err_handler!("Error getting DB"),
|
||||
};
|
||||
@@ -363,7 +364,7 @@ impl<'a, 'r> FromRequest<'a, 'r> for Headers {
|
||||
if let Some(stamp_exception) =
|
||||
user.stamp_exception.as_deref().and_then(|s| serde_json::from_str::<UserStampException>(s).ok())
|
||||
{
|
||||
- let current_route = match request.route().and_then(|r| r.name) {
|
||||
+ let current_route = match request.route().and_then(|r| r.name.as_deref()) {
|
||||
Some(name) => name,
|
||||
_ => err_handler!("Error getting current route for stamp exception"),
|
||||
};
|
||||
@@ -411,13 +412,13 @@ pub struct OrgHeaders {
|
||||
// but there are cases where it is a query value.
|
||||
// First check the path, if this is not a valid uuid, try the query values.
|
||||
fn get_org_id(request: &Request) -> Option<String> {
|
||||
- if let Some(Ok(org_id)) = request.get_param::<String>(1) {
|
||||
+ if let Some(Ok(org_id)) = request.param::<String>(1) {
|
||||
if uuid::Uuid::parse_str(&org_id).is_ok() {
|
||||
return Some(org_id);
|
||||
}
|
||||
}
|
||||
|
||||
- if let Some(Ok(org_id)) = request.get_query_value::<String>("organizationId") {
|
||||
+ if let Some(Ok(org_id)) = request.query_value::<String>("organizationId") {
|
||||
if uuid::Uuid::parse_str(&org_id).is_ok() {
|
||||
return Some(org_id);
|
||||
}
|
||||
@@ -426,52 +427,48 @@ fn get_org_id(request: &Request) -> Option<String> {
|
||||
None
|
||||
}
|
||||
|
||||
-impl<'a, 'r> FromRequest<'a, 'r> for OrgHeaders {
|
||||
+#[rocket::async_trait]
|
||||
+impl<'r> FromRequest<'r> for OrgHeaders {
|
||||
type Error = &'static str;
|
||||
|
||||
- fn from_request(request: &'a Request<'r>) -> Outcome<Self, Self::Error> {
|
||||
- match request.guard::<Headers>() {
|
||||
- Outcome::Forward(_) => Outcome::Forward(()),
|
||||
- Outcome::Failure(f) => Outcome::Failure(f),
|
||||
- Outcome::Success(headers) => {
|
||||
- match get_org_id(request) {
|
||||
- Some(org_id) => {
|
||||
- let conn = match request.guard::<DbConn>() {
|
||||
- Outcome::Success(conn) => conn,
|
||||
- _ => err_handler!("Error getting DB"),
|
||||
- };
|
||||
+ async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> {
|
||||
+ let headers = try_outcome!(Headers::from_request(request).await);
|
||||
+ match get_org_id(request) {
|
||||
+ Some(org_id) => {
|
||||
+ let conn = match DbConn::from_request(request).await {
|
||||
+ Outcome::Success(conn) => conn,
|
||||
+ _ => err_handler!("Error getting DB"),
|
||||
+ };
|
||||
|
||||
- let user = headers.user;
|
||||
- let org_user = match UserOrganization::find_by_user_and_org(&user.uuid, &org_id, &conn) {
|
||||
- Some(user) => {
|
||||
- if user.status == UserOrgStatus::Confirmed as i32 {
|
||||
- user
|
||||
- } else {
|
||||
- err_handler!("The current user isn't confirmed member of the organization")
|
||||
- }
|
||||
- }
|
||||
- None => err_handler!("The current user isn't member of the organization"),
|
||||
- };
|
||||
-
|
||||
- Outcome::Success(Self {
|
||||
- host: headers.host,
|
||||
- device: headers.device,
|
||||
- user,
|
||||
- org_user_type: {
|
||||
- if let Some(org_usr_type) = UserOrgType::from_i32(org_user.atype) {
|
||||
- org_usr_type
|
||||
- } else {
|
||||
- // This should only happen if the DB is corrupted
|
||||
- err_handler!("Unknown user type in the database")
|
||||
- }
|
||||
- },
|
||||
- org_user,
|
||||
- org_id,
|
||||
- })
|
||||
+ let user = headers.user;
|
||||
+ let org_user = match UserOrganization::find_by_user_and_org(&user.uuid, &org_id, &conn) {
|
||||
+ Some(user) => {
|
||||
+ if user.status == UserOrgStatus::Confirmed as i32 {
|
||||
+ user
|
||||
+ } else {
|
||||
+ err_handler!("The current user isn't confirmed member of the organization")
|
||||
+ }
|
||||
}
|
||||
- _ => err_handler!("Error getting the organization id"),
|
||||
- }
|
||||
+ None => err_handler!("The current user isn't member of the organization"),
|
||||
+ };
|
||||
+
|
||||
+ Outcome::Success(Self {
|
||||
+ host: headers.host,
|
||||
+ device: headers.device,
|
||||
+ user,
|
||||
+ org_user_type: {
|
||||
+ if let Some(org_usr_type) = UserOrgType::from_i32(org_user.atype) {
|
||||
+ org_usr_type
|
||||
+ } else {
|
||||
+ // This should only happen if the DB is corrupted
|
||||
+ err_handler!("Unknown user type in the database")
|
||||
+ }
|
||||
+ },
|
||||
+ org_user,
|
||||
+ org_id,
|
||||
+ })
|
||||
}
|
||||
+ _ => err_handler!("Error getting the organization id"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -483,25 +480,21 @@ pub struct AdminHeaders {
|
||||
pub org_user_type: UserOrgType,
|
||||
}
|
||||
|
||||
-impl<'a, 'r> FromRequest<'a, 'r> for AdminHeaders {
|
||||
+#[rocket::async_trait]
|
||||
+impl<'r> FromRequest<'r> for AdminHeaders {
|
||||
type Error = &'static str;
|
||||
|
||||
- fn from_request(request: &'a Request<'r>) -> Outcome<Self, Self::Error> {
|
||||
- match request.guard::<OrgHeaders>() {
|
||||
- Outcome::Forward(_) => Outcome::Forward(()),
|
||||
- Outcome::Failure(f) => Outcome::Failure(f),
|
||||
- Outcome::Success(headers) => {
|
||||
- if headers.org_user_type >= UserOrgType::Admin {
|
||||
- Outcome::Success(Self {
|
||||
- host: headers.host,
|
||||
- device: headers.device,
|
||||
- user: headers.user,
|
||||
- org_user_type: headers.org_user_type,
|
||||
- })
|
||||
- } else {
|
||||
- err_handler!("You need to be Admin or Owner to call this endpoint")
|
||||
- }
|
||||
- }
|
||||
+ async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> {
|
||||
+ let headers = try_outcome!(OrgHeaders::from_request(request).await);
|
||||
+ if headers.org_user_type >= UserOrgType::Admin {
|
||||
+ Outcome::Success(Self {
|
||||
+ host: headers.host,
|
||||
+ device: headers.device,
|
||||
+ user: headers.user,
|
||||
+ org_user_type: headers.org_user_type,
|
||||
+ })
|
||||
+ } else {
|
||||
+ err_handler!("You need to be Admin or Owner to call this endpoint")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -520,13 +513,13 @@ impl From<AdminHeaders> for Headers {
|
||||
// but there could be cases where it is a query value.
|
||||
// First check the path, if this is not a valid uuid, try the query values.
|
||||
fn get_col_id(request: &Request) -> Option<String> {
|
||||
- if let Some(Ok(col_id)) = request.get_param::<String>(3) {
|
||||
+ if let Some(Ok(col_id)) = request.param::<String>(3) {
|
||||
if uuid::Uuid::parse_str(&col_id).is_ok() {
|
||||
return Some(col_id);
|
||||
}
|
||||
}
|
||||
|
||||
- if let Some(Ok(col_id)) = request.get_query_value::<String>("collectionId") {
|
||||
+ if let Some(Ok(col_id)) = request.query_value::<String>("collectionId") {
|
||||
if uuid::Uuid::parse_str(&col_id).is_ok() {
|
||||
return Some(col_id);
|
||||
}
|
||||
@@ -545,46 +538,38 @@ pub struct ManagerHeaders {
|
||||
pub org_user_type: UserOrgType,
|
||||
}
|
||||
|
||||
-impl<'a, 'r> FromRequest<'a, 'r> for ManagerHeaders {
|
||||
+#[rocket::async_trait]
|
||||
+impl<'r> FromRequest<'r> for ManagerHeaders {
|
||||
type Error = &'static str;
|
||||
|
||||
- fn from_request(request: &'a Request<'r>) -> Outcome<Self, Self::Error> {
|
||||
- match request.guard::<OrgHeaders>() {
|
||||
- Outcome::Forward(_) => Outcome::Forward(()),
|
||||
- Outcome::Failure(f) => Outcome::Failure(f),
|
||||
- Outcome::Success(headers) => {
|
||||
- if headers.org_user_type >= UserOrgType::Manager {
|
||||
- match get_col_id(request) {
|
||||
- Some(col_id) => {
|
||||
- let conn = match request.guard::<DbConn>() {
|
||||
- Outcome::Success(conn) => conn,
|
||||
- _ => err_handler!("Error getting DB"),
|
||||
- };
|
||||
+ async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> {
|
||||
+ let headers = try_outcome!(OrgHeaders::from_request(request).await);
|
||||
+ if headers.org_user_type >= UserOrgType::Manager {
|
||||
+ match get_col_id(request) {
|
||||
+ Some(col_id) => {
|
||||
+ let conn = match DbConn::from_request(request).await {
|
||||
+ Outcome::Success(conn) => conn,
|
||||
+ _ => err_handler!("Error getting DB"),
|
||||
+ };
|
||||
|
||||
- if !headers.org_user.has_full_access() {
|
||||
- match CollectionUser::find_by_collection_and_user(
|
||||
- &col_id,
|
||||
- &headers.org_user.user_uuid,
|
||||
- &conn,
|
||||
- ) {
|
||||
- Some(_) => (),
|
||||
- None => err_handler!("The current user isn't a manager for this collection"),
|
||||
- }
|
||||
- }
|
||||
+ if !headers.org_user.has_full_access() {
|
||||
+ match CollectionUser::find_by_collection_and_user(&col_id, &headers.org_user.user_uuid, &conn) {
|
||||
+ Some(_) => (),
|
||||
+ None => err_handler!("The current user isn't a manager for this collection"),
|
||||
}
|
||||
- _ => err_handler!("Error getting the collection id"),
|
||||
}
|
||||
-
|
||||
- Outcome::Success(Self {
|
||||
- host: headers.host,
|
||||
- device: headers.device,
|
||||
- user: headers.user,
|
||||
- org_user_type: headers.org_user_type,
|
||||
- })
|
||||
- } else {
|
||||
- err_handler!("You need to be a Manager, Admin or Owner to call this endpoint")
|
||||
}
|
||||
+ _ => err_handler!("Error getting the collection id"),
|
||||
}
|
||||
+
|
||||
+ Outcome::Success(Self {
|
||||
+ host: headers.host,
|
||||
+ device: headers.device,
|
||||
+ user: headers.user,
|
||||
+ org_user_type: headers.org_user_type,
|
||||
+ })
|
||||
+ } else {
|
||||
+ err_handler!("You need to be a Manager, Admin or Owner to call this endpoint")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -608,25 +593,21 @@ pub struct ManagerHeadersLoose {
|
||||
pub org_user_type: UserOrgType,
|
||||
}
|
||||
|
||||
-impl<'a, 'r> FromRequest<'a, 'r> for ManagerHeadersLoose {
|
||||
+#[rocket::async_trait]
|
||||
+impl<'r> FromRequest<'r> for ManagerHeadersLoose {
|
||||
type Error = &'static str;
|
||||
|
||||
- fn from_request(request: &'a Request<'r>) -> Outcome<Self, Self::Error> {
|
||||
- match request.guard::<OrgHeaders>() {
|
||||
- Outcome::Forward(_) => Outcome::Forward(()),
|
||||
- Outcome::Failure(f) => Outcome::Failure(f),
|
||||
- Outcome::Success(headers) => {
|
||||
- if headers.org_user_type >= UserOrgType::Manager {
|
||||
- Outcome::Success(Self {
|
||||
- host: headers.host,
|
||||
- device: headers.device,
|
||||
- user: headers.user,
|
||||
- org_user_type: headers.org_user_type,
|
||||
- })
|
||||
- } else {
|
||||
- err_handler!("You need to be a Manager, Admin or Owner to call this endpoint")
|
||||
- }
|
||||
- }
|
||||
+ async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> {
|
||||
+ let headers = try_outcome!(OrgHeaders::from_request(request).await);
|
||||
+ if headers.org_user_type >= UserOrgType::Manager {
|
||||
+ Outcome::Success(Self {
|
||||
+ host: headers.host,
|
||||
+ device: headers.device,
|
||||
+ user: headers.user,
|
||||
+ org_user_type: headers.org_user_type,
|
||||
+ })
|
||||
+ } else {
|
||||
+ err_handler!("You need to be a Manager, Admin or Owner to call this endpoint")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -647,24 +628,20 @@ pub struct OwnerHeaders {
|
||||
pub user: User,
|
||||
}
|
||||
|
||||
-impl<'a, 'r> FromRequest<'a, 'r> for OwnerHeaders {
|
||||
+#[rocket::async_trait]
|
||||
+impl<'r> FromRequest<'r> for OwnerHeaders {
|
||||
type Error = &'static str;
|
||||
|
||||
- fn from_request(request: &'a Request<'r>) -> Outcome<Self, Self::Error> {
|
||||
- match request.guard::<OrgHeaders>() {
|
||||
- Outcome::Forward(_) => Outcome::Forward(()),
|
||||
- Outcome::Failure(f) => Outcome::Failure(f),
|
||||
- Outcome::Success(headers) => {
|
||||
- if headers.org_user_type == UserOrgType::Owner {
|
||||
- Outcome::Success(Self {
|
||||
- host: headers.host,
|
||||
- device: headers.device,
|
||||
- user: headers.user,
|
||||
- })
|
||||
- } else {
|
||||
- err_handler!("You need to be Owner to call this endpoint")
|
||||
- }
|
||||
- }
|
||||
+ async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> {
|
||||
+ let headers = try_outcome!(OrgHeaders::from_request(request).await);
|
||||
+ if headers.org_user_type == UserOrgType::Owner {
|
||||
+ Outcome::Success(Self {
|
||||
+ host: headers.host,
|
||||
+ device: headers.device,
|
||||
+ user: headers.user,
|
||||
+ })
|
||||
+ } else {
|
||||
+ err_handler!("You need to be Owner to call this endpoint")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -678,10 +655,11 @@ pub struct ClientIp {
|
||||
pub ip: IpAddr,
|
||||
}
|
||||
|
||||
-impl<'a, 'r> FromRequest<'a, 'r> for ClientIp {
|
||||
+#[rocket::async_trait]
|
||||
+impl<'r> FromRequest<'r> for ClientIp {
|
||||
type Error = ();
|
||||
|
||||
- fn from_request(req: &'a Request<'r>) -> Outcome<Self, Self::Error> {
|
||||
+ async fn from_request(req: &'r Request<'_>) -> Outcome<Self, Self::Error> {
|
||||
let ip = if CONFIG._ip_header_enabled() {
|
||||
req.headers().get_one(&CONFIG.ip_header()).and_then(|ip| {
|
||||
match ip.find(',') {
|
69
security/vaultwarden/patches/patch-src_config_rs
Normal file
69
security/vaultwarden/patches/patch-src_config_rs
Normal file
@ -0,0 +1,69 @@
|
||||
Index: src/config.rs
|
||||
--- src/config.rs.orig
|
||||
+++ src/config.rs
|
||||
@@ -36,6 +36,9 @@ macro_rules! make_config {
|
||||
pub struct Config { inner: RwLock<Inner> }
|
||||
|
||||
struct Inner {
|
||||
+ rocket_shutdown_handle: Option<rocket::Shutdown>,
|
||||
+ ws_shutdown_handle: Option<ws::Sender>,
|
||||
+
|
||||
templates: Handlebars<'static>,
|
||||
config: ConfigItems,
|
||||
|
||||
@@ -332,6 +335,8 @@ make_config! {
|
||||
attachments_folder: String, false, auto, |c| format!("{}/{}", c.data_folder, "attachments");
|
||||
/// Sends folder
|
||||
sends_folder: String, false, auto, |c| format!("{}/{}", c.data_folder, "sends");
|
||||
+ /// Temp folder |> Used for storing temporary file uploads
|
||||
+ tmp_folder: String, false, auto, |c| format!("{}/{}", c.data_folder, "tmp");
|
||||
/// Templates folder
|
||||
templates_folder: String, false, auto, |c| format!("{}/{}", c.data_folder, "templates");
|
||||
/// Session JWT key
|
||||
@@ -509,6 +514,9 @@ make_config! {
|
||||
/// Max database connection retries |> Number of times to retry the database connection during startup, with 1 second between each retry, set to 0 to retry indefinitely
|
||||
db_connection_retries: u32, false, def, 15;
|
||||
|
||||
+ /// Timeout when aquiring database connection
|
||||
+ database_timeout: u64, false, def, 30;
|
||||
+
|
||||
/// Database connection pool size
|
||||
database_max_conns: u32, false, def, 10;
|
||||
|
||||
@@ -743,6 +751,8 @@ impl Config {
|
||||
|
||||
Ok(Config {
|
||||
inner: RwLock::new(Inner {
|
||||
+ rocket_shutdown_handle: None,
|
||||
+ ws_shutdown_handle: None,
|
||||
templates: load_templates(&config.templates_folder),
|
||||
config,
|
||||
_env,
|
||||
@@ -905,6 +915,27 @@ impl Config {
|
||||
} else {
|
||||
let hb = &CONFIG.inner.read().unwrap().templates;
|
||||
hb.render(name, data).map_err(Into::into)
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ pub fn set_rocket_shutdown_handle(&self, handle: rocket::Shutdown) {
|
||||
+ self.inner.write().unwrap().rocket_shutdown_handle = Some(handle);
|
||||
+ }
|
||||
+
|
||||
+ pub fn set_ws_shutdown_handle(&self, handle: ws::Sender) {
|
||||
+ self.inner.write().unwrap().ws_shutdown_handle = Some(handle);
|
||||
+ }
|
||||
+
|
||||
+ pub fn shutdown(&self) {
|
||||
+ if let Ok(c) = self.inner.read() {
|
||||
+ if let Some(handle) = c.ws_shutdown_handle.clone() {
|
||||
+ handle.shutdown().ok();
|
||||
+ }
|
||||
+ // Wait a bit before stopping the web server
|
||||
+ std::thread::sleep(std::time::Duration::from_secs(1));
|
||||
+ if let Some(handle) = c.rocket_shutdown_handle.clone() {
|
||||
+ handle.notify();
|
||||
+ }
|
||||
}
|
||||
}
|
||||
}
|
318
security/vaultwarden/patches/patch-src_db_mod_rs
Normal file
318
security/vaultwarden/patches/patch-src_db_mod_rs
Normal file
@ -0,0 +1,318 @@
|
||||
Index: src/db/mod.rs
|
||||
--- src/db/mod.rs.orig
|
||||
+++ src/db/mod.rs
|
||||
@@ -1,10 +1,18 @@
|
||||
+use std::{sync::Arc, time::Duration};
|
||||
+
|
||||
use diesel::r2d2::{ConnectionManager, Pool, PooledConnection};
|
||||
use rocket::{
|
||||
http::Status,
|
||||
+ outcome::IntoOutcome,
|
||||
request::{FromRequest, Outcome},
|
||||
- Request, State,
|
||||
+ Request,
|
||||
};
|
||||
|
||||
+use tokio::{
|
||||
+ sync::{Mutex, OwnedSemaphorePermit, Semaphore},
|
||||
+ time::timeout,
|
||||
+};
|
||||
+
|
||||
use crate::{
|
||||
error::{Error, MapResult},
|
||||
CONFIG,
|
||||
@@ -22,6 +30,23 @@ pub mod __mysql_schema;
|
||||
#[path = "schemas/postgresql/schema.rs"]
|
||||
pub mod __postgresql_schema;
|
||||
|
||||
+// There changes are based on Rocket 0.5-rc wrapper of Diesel: https://github.com/SergioBenitez/Rocket/blob/v0.5-rc/contrib/sync_db_pools
|
||||
+
|
||||
+// A wrapper around spawn_blocking that propagates panics to the calling code.
|
||||
+pub async fn run_blocking<F, R>(job: F) -> R
|
||||
+where
|
||||
+ F: FnOnce() -> R + Send + 'static,
|
||||
+ R: Send + 'static,
|
||||
+{
|
||||
+ match tokio::task::spawn_blocking(job).await {
|
||||
+ Ok(ret) => ret,
|
||||
+ Err(e) => match e.try_into_panic() {
|
||||
+ Ok(panic) => std::panic::resume_unwind(panic),
|
||||
+ Err(_) => unreachable!("spawn_blocking tasks are never cancelled"),
|
||||
+ },
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
// This is used to generate the main DbConn and DbPool enums, which contain one variant for each database supported
|
||||
macro_rules! generate_connections {
|
||||
( $( $name:ident: $ty:ty ),+ ) => {
|
||||
@@ -29,13 +54,54 @@ macro_rules! generate_connections {
|
||||
#[derive(Eq, PartialEq)]
|
||||
pub enum DbConnType { $( $name, )+ }
|
||||
|
||||
+ pub struct DbConn {
|
||||
+ conn: Arc<Mutex<Option<DbConnInner>>>,
|
||||
+ permit: Option<OwnedSemaphorePermit>,
|
||||
+ }
|
||||
+
|
||||
#[allow(non_camel_case_types)]
|
||||
- pub enum DbConn { $( #[cfg($name)] $name(PooledConnection<ConnectionManager< $ty >>), )+ }
|
||||
+ pub enum DbConnInner { $( #[cfg($name)] $name(PooledConnection<ConnectionManager< $ty >>), )+ }
|
||||
|
||||
+
|
||||
+ #[derive(Clone)]
|
||||
+ pub struct DbPool {
|
||||
+ // This is an 'Option' so that we can drop the pool in a 'spawn_blocking'.
|
||||
+ pool: Option<DbPoolInner>,
|
||||
+ semaphore: Arc<Semaphore>
|
||||
+ }
|
||||
+
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Clone)]
|
||||
- pub enum DbPool { $( #[cfg($name)] $name(Pool<ConnectionManager< $ty >>), )+ }
|
||||
+ pub enum DbPoolInner { $( #[cfg($name)] $name(Pool<ConnectionManager< $ty >>), )+ }
|
||||
|
||||
+ impl Drop for DbConn {
|
||||
+ fn drop(&mut self) {
|
||||
+ let conn = self.conn.clone();
|
||||
+ let permit = self.permit.take();
|
||||
+
|
||||
+ // Since connection can't be on the stack in an async fn during an
|
||||
+ // await, we have to spawn a new blocking-safe thread...
|
||||
+ tokio::task::spawn_blocking(move || {
|
||||
+ // And then re-enter the runtime to wait on the async mutex, but in a blocking fashion.
|
||||
+ let mut conn = tokio::runtime::Handle::current().block_on(conn.lock_owned());
|
||||
+
|
||||
+ if let Some(conn) = conn.take() {
|
||||
+ drop(conn);
|
||||
+ }
|
||||
+
|
||||
+ // Drop permit after the connection is dropped
|
||||
+ drop(permit);
|
||||
+ });
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ impl Drop for DbPool {
|
||||
+ fn drop(&mut self) {
|
||||
+ let pool = self.pool.take();
|
||||
+ tokio::task::spawn_blocking(move || drop(pool));
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
impl DbPool {
|
||||
// For the given database URL, guess it's type, run migrations create pool and return it
|
||||
pub fn from_config() -> Result<Self, Error> {
|
||||
@@ -50,9 +116,13 @@ macro_rules! generate_connections {
|
||||
let manager = ConnectionManager::new(&url);
|
||||
let pool = Pool::builder()
|
||||
.max_size(CONFIG.database_max_conns())
|
||||
+ .connection_timeout(Duration::from_secs(CONFIG.database_timeout()))
|
||||
.build(manager)
|
||||
.map_res("Failed to create pool")?;
|
||||
- return Ok(Self::$name(pool));
|
||||
+ return Ok(DbPool {
|
||||
+ pool: Some(DbPoolInner::$name(pool)),
|
||||
+ semaphore: Arc::new(Semaphore::new(CONFIG.database_max_conns() as usize)),
|
||||
+ });
|
||||
}
|
||||
#[cfg(not($name))]
|
||||
#[allow(unreachable_code)]
|
||||
@@ -61,10 +131,26 @@ macro_rules! generate_connections {
|
||||
)+ }
|
||||
}
|
||||
// Get a connection from the pool
|
||||
- pub fn get(&self) -> Result<DbConn, Error> {
|
||||
- match self { $(
|
||||
+ pub async fn get(&self) -> Result<DbConn, Error> {
|
||||
+ let duration = Duration::from_secs(CONFIG.database_timeout());
|
||||
+ let permit = match timeout(duration, self.semaphore.clone().acquire_owned()).await {
|
||||
+ Ok(p) => p.expect("Semaphore should be open"),
|
||||
+ Err(_) => {
|
||||
+ err!("Timeout waiting for database connection");
|
||||
+ }
|
||||
+ };
|
||||
+
|
||||
+ match self.pool.as_ref().expect("DbPool.pool should always be Some()") { $(
|
||||
#[cfg($name)]
|
||||
- Self::$name(p) => Ok(DbConn::$name(p.get().map_res("Error retrieving connection from pool")?)),
|
||||
+ DbPoolInner::$name(p) => {
|
||||
+ let pool = p.clone();
|
||||
+ let c = run_blocking(move || pool.get_timeout(duration)).await.map_res("Error retrieving connection from pool")?;
|
||||
+
|
||||
+ return Ok(DbConn {
|
||||
+ conn: Arc::new(Mutex::new(Some(DbConnInner::$name(c)))),
|
||||
+ permit: Some(permit)
|
||||
+ });
|
||||
+ },
|
||||
)+ }
|
||||
}
|
||||
}
|
||||
@@ -113,42 +199,95 @@ macro_rules! db_run {
|
||||
db_run! { $conn: sqlite, mysql, postgresql $body }
|
||||
};
|
||||
|
||||
- // Different code for each db
|
||||
- ( $conn:ident: $( $($db:ident),+ $body:block )+ ) => {{
|
||||
- #[allow(unused)] use diesel::prelude::*;
|
||||
- match $conn {
|
||||
- $($(
|
||||
- #[cfg($db)]
|
||||
- crate::db::DbConn::$db(ref $conn) => {
|
||||
- paste::paste! {
|
||||
- #[allow(unused)] use crate::db::[<__ $db _schema>]::{self as schema, *};
|
||||
- #[allow(unused)] use [<__ $db _model>]::*;
|
||||
- #[allow(unused)] use crate::db::FromDb;
|
||||
- }
|
||||
- $body
|
||||
- },
|
||||
- )+)+
|
||||
- }}
|
||||
- };
|
||||
-
|
||||
- // Same for all dbs
|
||||
( @raw $conn:ident: $body:block ) => {
|
||||
db_run! { @raw $conn: sqlite, mysql, postgresql $body }
|
||||
};
|
||||
|
||||
// Different code for each db
|
||||
- ( @raw $conn:ident: $( $($db:ident),+ $body:block )+ ) => {
|
||||
+ ( $conn:ident: $( $($db:ident),+ $body:block )+ ) => {{
|
||||
#[allow(unused)] use diesel::prelude::*;
|
||||
- #[allow(unused_variables)]
|
||||
- match $conn {
|
||||
- $($(
|
||||
- #[cfg($db)]
|
||||
- crate::db::DbConn::$db(ref $conn) => {
|
||||
- $body
|
||||
- },
|
||||
- )+)+
|
||||
- }
|
||||
- };
|
||||
+
|
||||
+ // It is important that this inner Arc<Mutex<>> (or the OwnedMutexGuard
|
||||
+ // derived from it) never be a variable on the stack at an await point,
|
||||
+ // where Drop might be called at any time. This causes (synchronous)
|
||||
+ // Drop to be called from asynchronous code, which some database
|
||||
+ // wrappers do not or can not handle.
|
||||
+ let conn = $conn.conn.clone();
|
||||
+
|
||||
+ // Since connection can't be on the stack in an async fn during an
|
||||
+ // await, we have to spawn a new blocking-safe thread...
|
||||
+ /*
|
||||
+ run_blocking(move || {
|
||||
+ // And then re-enter the runtime to wait on the async mutex, but in
|
||||
+ // a blocking fashion.
|
||||
+ let mut conn = tokio::runtime::Handle::current().block_on(conn.lock_owned());
|
||||
+ let conn = conn.as_mut().expect("internal invariant broken: self.connection is Some");
|
||||
+ */
|
||||
+ let mut __conn_mutex = conn.try_lock_owned().unwrap();
|
||||
+ let conn = __conn_mutex.as_mut().unwrap();
|
||||
+ match conn {
|
||||
+ $($(
|
||||
+ #[cfg($db)]
|
||||
+ crate::db::DbConnInner::$db($conn) => {
|
||||
+ paste::paste! {
|
||||
+ #[allow(unused)] use crate::db::[<__ $db _schema>]::{self as schema, *};
|
||||
+ #[allow(unused)] use [<__ $db _model>]::*;
|
||||
+ #[allow(unused)] use crate::db::FromDb;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ // Since connection can't be on the stack in an async fn during an
|
||||
+ // await, we have to spawn a new blocking-safe thread...
|
||||
+ run_blocking(move || {
|
||||
+ // And then re-enter the runtime to wait on the async mutex, but in
|
||||
+ // a blocking fashion.
|
||||
+ let mut conn = tokio::runtime::Handle::current().block_on(async {
|
||||
+ conn.lock_owned().await
|
||||
+ });
|
||||
+
|
||||
+ let conn = conn.as_mut().expect("internal invariant broken: self.connection is Some");
|
||||
+ f(conn)
|
||||
+ }).await;*/
|
||||
+
|
||||
+ $body
|
||||
+ },
|
||||
+ )+)+
|
||||
+ }
|
||||
+ // }).await
|
||||
+ }};
|
||||
+
|
||||
+ ( @raw $conn:ident: $( $($db:ident),+ $body:block )+ ) => {{
|
||||
+ #[allow(unused)] use diesel::prelude::*;
|
||||
+
|
||||
+ // It is important that this inner Arc<Mutex<>> (or the OwnedMutexGuard
|
||||
+ // derived from it) never be a variable on the stack at an await point,
|
||||
+ // where Drop might be called at any time. This causes (synchronous)
|
||||
+ // Drop to be called from asynchronous code, which some database
|
||||
+ // wrappers do not or can not handle.
|
||||
+ let conn = $conn.conn.clone();
|
||||
+
|
||||
+ // Since connection can't be on the stack in an async fn during an
|
||||
+ // await, we have to spawn a new blocking-safe thread...
|
||||
+ run_blocking(move || {
|
||||
+ // And then re-enter the runtime to wait on the async mutex, but in
|
||||
+ // a blocking fashion.
|
||||
+ let mut conn = tokio::runtime::Handle::current().block_on(conn.lock_owned());
|
||||
+ match conn.as_mut().expect("internal invariant broken: self.connection is Some") {
|
||||
+ $($(
|
||||
+ #[cfg($db)]
|
||||
+ crate::db::DbConnInner::$db($conn) => {
|
||||
+ paste::paste! {
|
||||
+ #[allow(unused)] use crate::db::[<__ $db _schema>]::{self as schema, *};
|
||||
+ // @RAW: #[allow(unused)] use [<__ $db _model>]::*;
|
||||
+ #[allow(unused)] use crate::db::FromDb;
|
||||
+ }
|
||||
+
|
||||
+ $body
|
||||
+ },
|
||||
+ )+)+
|
||||
+ }
|
||||
+ }).await
|
||||
+ }};
|
||||
}
|
||||
|
||||
pub trait FromDb {
|
||||
@@ -227,9 +366,10 @@ pub mod models;
|
||||
|
||||
/// Creates a back-up of the sqlite database
|
||||
/// MySQL/MariaDB and PostgreSQL are not supported.
|
||||
-pub fn backup_database(conn: &DbConn) -> Result<(), Error> {
|
||||
+pub async fn backup_database(conn: &DbConn) -> Result<(), Error> {
|
||||
db_run! {@raw conn:
|
||||
postgresql, mysql {
|
||||
+ let _ = conn;
|
||||
err!("PostgreSQL and MySQL/MariaDB do not support this backup feature");
|
||||
}
|
||||
sqlite {
|
||||
@@ -244,7 +384,7 @@ pub fn backup_database(conn: &DbConn) -> Result<(), Er
|
||||
}
|
||||
|
||||
/// Get the SQL Server version
|
||||
-pub fn get_sql_server_version(conn: &DbConn) -> String {
|
||||
+pub async fn get_sql_server_version(conn: &DbConn) -> String {
|
||||
db_run! {@raw conn:
|
||||
postgresql, mysql {
|
||||
no_arg_sql_function!(version, diesel::sql_types::Text);
|
||||
@@ -260,15 +400,14 @@ pub fn get_sql_server_version(conn: &DbConn) -> String
|
||||
/// Attempts to retrieve a single connection from the managed database pool. If
|
||||
/// no pool is currently managed, fails with an `InternalServerError` status. If
|
||||
/// no connections are available, fails with a `ServiceUnavailable` status.
|
||||
-impl<'a, 'r> FromRequest<'a, 'r> for DbConn {
|
||||
+#[rocket::async_trait]
|
||||
+impl<'r> FromRequest<'r> for DbConn {
|
||||
type Error = ();
|
||||
|
||||
- fn from_request(request: &'a Request<'r>) -> Outcome<DbConn, ()> {
|
||||
- // https://github.com/SergioBenitez/Rocket/commit/e3c1a4ad3ab9b840482ec6de4200d30df43e357c
|
||||
- let pool = try_outcome!(request.guard::<State<DbPool>>());
|
||||
- match pool.get() {
|
||||
- Ok(conn) => Outcome::Success(conn),
|
||||
- Err(_) => Outcome::Failure((Status::ServiceUnavailable, ())),
|
||||
+ async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> {
|
||||
+ match request.rocket().state::<DbPool>() {
|
||||
+ Some(p) => p.get().await.map_err(|_| ()).into_outcome(Status::ServiceUnavailable),
|
||||
+ None => Outcome::Failure((Status::InternalServerError, ())),
|
||||
}
|
||||
}
|
||||
}
|
41
security/vaultwarden/patches/patch-src_error_rs
Normal file
41
security/vaultwarden/patches/patch-src_error_rs
Normal file
@ -0,0 +1,41 @@
|
||||
Index: src/error.rs
|
||||
--- src/error.rs.orig
|
||||
+++ src/error.rs
|
||||
@@ -45,6 +45,7 @@ use lettre::transport::smtp::Error as SmtpErr;
|
||||
use openssl::error::ErrorStack as SSLErr;
|
||||
use regex::Error as RegexErr;
|
||||
use reqwest::Error as ReqErr;
|
||||
+use rocket::error::Error as RocketErr;
|
||||
use serde_json::{Error as SerdeErr, Value};
|
||||
use std::io::Error as IoErr;
|
||||
use std::time::SystemTimeError as TimeErr;
|
||||
@@ -84,6 +85,7 @@ make_error! {
|
||||
Address(AddrErr): _has_source, _api_error,
|
||||
Smtp(SmtpErr): _has_source, _api_error,
|
||||
OpenSSL(SSLErr): _has_source, _api_error,
|
||||
+ Rocket(RocketErr): _has_source, _api_error,
|
||||
|
||||
DieselCon(DieselConErr): _has_source, _api_error,
|
||||
DieselMig(DieselMigErr): _has_source, _api_error,
|
||||
@@ -193,8 +195,8 @@ use rocket::http::{ContentType, Status};
|
||||
use rocket::request::Request;
|
||||
use rocket::response::{self, Responder, Response};
|
||||
|
||||
-impl<'r> Responder<'r> for Error {
|
||||
- fn respond_to(self, _: &Request) -> response::Result<'r> {
|
||||
+impl<'r> Responder<'r, 'static> for Error {
|
||||
+ fn respond_to(self, _: &Request) -> response::Result<'static> {
|
||||
match self.error {
|
||||
ErrorKind::Empty(_) => {} // Don't print the error in this situation
|
||||
ErrorKind::Simple(_) => {} // Don't print the error in this situation
|
||||
@@ -202,8 +204,8 @@ impl<'r> Responder<'r> for Error {
|
||||
};
|
||||
|
||||
let code = Status::from_code(self.error_code).unwrap_or(Status::BadRequest);
|
||||
-
|
||||
- Response::build().status(code).header(ContentType::JSON).sized_body(Cursor::new(format!("{}", self))).ok()
|
||||
+ let body = self.to_string();
|
||||
+ Response::build().status(code).header(ContentType::JSON).sized_body(Some(body.len()), Cursor::new(body)).ok()
|
||||
}
|
||||
}
|
||||
|
199
security/vaultwarden/patches/patch-src_main_rs
Normal file
199
security/vaultwarden/patches/patch-src_main_rs
Normal file
@ -0,0 +1,199 @@
|
||||
Index: src/main.rs
|
||||
--- src/main.rs.orig
|
||||
+++ src/main.rs
|
||||
@@ -20,8 +20,15 @@ extern crate diesel;
|
||||
#[macro_use]
|
||||
extern crate diesel_migrations;
|
||||
|
||||
-use job_scheduler::{Job, JobScheduler};
|
||||
-use std::{fs::create_dir_all, panic, path::Path, process::exit, str::FromStr, thread, time::Duration};
|
||||
+use std::{
|
||||
+ fs::{canonicalize, create_dir_all},
|
||||
+ panic,
|
||||
+ path::Path,
|
||||
+ process::exit,
|
||||
+ str::FromStr,
|
||||
+ thread,
|
||||
+ time::Duration,
|
||||
+};
|
||||
|
||||
#[macro_use]
|
||||
mod error;
|
||||
@@ -37,9 +44,11 @@ mod util;
|
||||
|
||||
pub use config::CONFIG;
|
||||
pub use error::{Error, MapResult};
|
||||
+use rocket::data::{Limits, ToByteUnit};
|
||||
pub use util::is_running_in_docker;
|
||||
|
||||
-fn main() {
|
||||
+#[rocket::main]
|
||||
+async fn main() -> Result<(), Error> {
|
||||
parse_args();
|
||||
launch_info();
|
||||
|
||||
@@ -56,13 +65,16 @@ fn main() {
|
||||
});
|
||||
check_web_vault();
|
||||
|
||||
- create_icon_cache_folder();
|
||||
+ create_dir(&CONFIG.icon_cache_folder(), "icon cache");
|
||||
+ create_dir(&CONFIG.tmp_folder(), "tmp folder");
|
||||
+ create_dir(&CONFIG.sends_folder(), "sends folder");
|
||||
+ create_dir(&CONFIG.attachments_folder(), "attachments folder");
|
||||
|
||||
let pool = create_db_pool();
|
||||
- schedule_jobs(pool.clone());
|
||||
- crate::db::models::TwoFactor::migrate_u2f_to_webauthn(&pool.get().unwrap()).unwrap();
|
||||
+ schedule_jobs(pool.clone()).await;
|
||||
+ crate::db::models::TwoFactor::migrate_u2f_to_webauthn(&pool.get().await.unwrap()).unwrap();
|
||||
|
||||
- launch_rocket(pool, extra_debug); // Blocks until program termination.
|
||||
+ launch_rocket(pool, extra_debug).await // Blocks until program termination.
|
||||
}
|
||||
|
||||
const HELP: &str = "\
|
||||
@@ -127,10 +139,12 @@ fn init_logging(level: log::LevelFilter) -> Result<(),
|
||||
.level_for("hyper::server", log::LevelFilter::Warn)
|
||||
// Silence rocket logs
|
||||
.level_for("_", log::LevelFilter::Off)
|
||||
- .level_for("launch", log::LevelFilter::Off)
|
||||
- .level_for("launch_", log::LevelFilter::Off)
|
||||
- .level_for("rocket::rocket", log::LevelFilter::Off)
|
||||
- .level_for("rocket::fairing", log::LevelFilter::Off)
|
||||
+ .level_for("rocket::launch", log::LevelFilter::Error)
|
||||
+ .level_for("rocket::launch_", log::LevelFilter::Error)
|
||||
+ .level_for("rocket::rocket", log::LevelFilter::Warn)
|
||||
+ .level_for("rocket::server", log::LevelFilter::Warn)
|
||||
+ .level_for("rocket::fairing::fairings", log::LevelFilter::Warn)
|
||||
+ .level_for("rocket::shield::shield", log::LevelFilter::Warn)
|
||||
// Never show html5ever and hyper::proto logs, too noisy
|
||||
.level_for("html5ever", log::LevelFilter::Off)
|
||||
.level_for("hyper::proto", log::LevelFilter::Off)
|
||||
@@ -243,10 +257,6 @@ fn create_dir(path: &str, description: &str) {
|
||||
create_dir_all(path).expect(&err_msg);
|
||||
}
|
||||
|
||||
-fn create_icon_cache_folder() {
|
||||
- create_dir(&CONFIG.icon_cache_folder(), "icon cache");
|
||||
-}
|
||||
-
|
||||
fn check_data_folder() {
|
||||
let data_folder = &CONFIG.data_folder();
|
||||
let path = Path::new(data_folder);
|
||||
@@ -314,51 +324,73 @@ fn create_db_pool() -> db::DbPool {
|
||||
}
|
||||
}
|
||||
|
||||
-fn launch_rocket(pool: db::DbPool, extra_debug: bool) {
|
||||
+async fn launch_rocket(pool: db::DbPool, extra_debug: bool) -> Result<(), Error> {
|
||||
let basepath = &CONFIG.domain_path();
|
||||
|
||||
+ let mut config = rocket::Config::from(rocket::Config::figment());
|
||||
+ config.address = std::net::IpAddr::V4(std::net::Ipv4Addr::UNSPECIFIED); // TODO: Allow this to be changed, keep ROCKET_ADDRESS for compat
|
||||
+ config.temp_dir = canonicalize(CONFIG.tmp_folder()).unwrap().into();
|
||||
+ config.limits = Limits::new() //
|
||||
+ .limit("json", 10.megabytes())
|
||||
+ .limit("data-form", 150.megabytes())
|
||||
+ .limit("file", 150.megabytes());
|
||||
+
|
||||
// If adding more paths here, consider also adding them to
|
||||
// crate::utils::LOGGED_ROUTES to make sure they appear in the log
|
||||
- let result = rocket::ignite()
|
||||
- .mount(&[basepath, "/"].concat(), api::web_routes())
|
||||
- .mount(&[basepath, "/api"].concat(), api::core_routes())
|
||||
- .mount(&[basepath, "/admin"].concat(), api::admin_routes())
|
||||
- .mount(&[basepath, "/identity"].concat(), api::identity_routes())
|
||||
- .mount(&[basepath, "/icons"].concat(), api::icons_routes())
|
||||
- .mount(&[basepath, "/notifications"].concat(), api::notifications_routes())
|
||||
+ let instance = rocket::custom(config)
|
||||
+ .mount([basepath, "/"].concat(), api::web_routes())
|
||||
+ .mount([basepath, "/api"].concat(), api::core_routes())
|
||||
+ .mount([basepath, "/admin"].concat(), api::admin_routes())
|
||||
+ .mount([basepath, "/identity"].concat(), api::identity_routes())
|
||||
+ .mount([basepath, "/icons"].concat(), api::icons_routes())
|
||||
+ .mount([basepath, "/notifications"].concat(), api::notifications_routes())
|
||||
.manage(pool)
|
||||
.manage(api::start_notification_server())
|
||||
.attach(util::AppHeaders())
|
||||
.attach(util::Cors())
|
||||
.attach(util::BetterLogging(extra_debug))
|
||||
- .launch();
|
||||
+ .ignite()
|
||||
+ .await?;
|
||||
|
||||
- // Launch and print error if there is one
|
||||
- // The launch will restore the original logging level
|
||||
- error!("Launch error {:#?}", result);
|
||||
+ CONFIG.set_rocket_shutdown_handle(instance.shutdown());
|
||||
+ ctrlc::set_handler(move || {
|
||||
+ info!("Exiting vaultwarden!");
|
||||
+ CONFIG.shutdown();
|
||||
+ })
|
||||
+ .expect("Error setting Ctrl-C handler");
|
||||
+
|
||||
+ instance.launch().await?;
|
||||
+
|
||||
+ info!("Vaultwarden process exited!");
|
||||
+ Ok(())
|
||||
}
|
||||
|
||||
-fn schedule_jobs(pool: db::DbPool) {
|
||||
+async fn schedule_jobs(pool: db::DbPool) {
|
||||
if CONFIG.job_poll_interval_ms() == 0 {
|
||||
info!("Job scheduler disabled.");
|
||||
return;
|
||||
}
|
||||
+
|
||||
+ let runtime = tokio::runtime::Handle::current();
|
||||
+
|
||||
thread::Builder::new()
|
||||
.name("job-scheduler".to_string())
|
||||
.spawn(move || {
|
||||
+ use job_scheduler::{Job, JobScheduler};
|
||||
+
|
||||
let mut sched = JobScheduler::new();
|
||||
|
||||
// Purge sends that are past their deletion date.
|
||||
if !CONFIG.send_purge_schedule().is_empty() {
|
||||
sched.add(Job::new(CONFIG.send_purge_schedule().parse().unwrap(), || {
|
||||
- api::purge_sends(pool.clone());
|
||||
+ runtime.spawn(api::purge_sends(pool.clone()));
|
||||
}));
|
||||
}
|
||||
|
||||
// Purge trashed items that are old enough to be auto-deleted.
|
||||
if !CONFIG.trash_purge_schedule().is_empty() {
|
||||
sched.add(Job::new(CONFIG.trash_purge_schedule().parse().unwrap(), || {
|
||||
- api::purge_trashed_ciphers(pool.clone());
|
||||
+ runtime.spawn(api::purge_trashed_ciphers(pool.clone()));
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -366,7 +398,7 @@ fn schedule_jobs(pool: db::DbPool) {
|
||||
// indicates that a user's master password has been compromised.
|
||||
if !CONFIG.incomplete_2fa_schedule().is_empty() {
|
||||
sched.add(Job::new(CONFIG.incomplete_2fa_schedule().parse().unwrap(), || {
|
||||
- api::send_incomplete_2fa_notifications(pool.clone());
|
||||
+ runtime.spawn(api::send_incomplete_2fa_notifications(pool.clone()));
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -375,7 +407,7 @@ fn schedule_jobs(pool: db::DbPool) {
|
||||
// sending reminders for requests that are about to be granted anyway.
|
||||
if !CONFIG.emergency_request_timeout_schedule().is_empty() {
|
||||
sched.add(Job::new(CONFIG.emergency_request_timeout_schedule().parse().unwrap(), || {
|
||||
- api::emergency_request_timeout_job(pool.clone());
|
||||
+ runtime.spawn(api::emergency_request_timeout_job(pool.clone()));
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -383,7 +415,7 @@ fn schedule_jobs(pool: db::DbPool) {
|
||||
// emergency access requests.
|
||||
if !CONFIG.emergency_notification_reminder_schedule().is_empty() {
|
||||
sched.add(Job::new(CONFIG.emergency_notification_reminder_schedule().parse().unwrap(), || {
|
||||
- api::emergency_notification_reminder_job(pool.clone());
|
||||
+ runtime.spawn(api::emergency_notification_reminder_job(pool.clone()));
|
||||
}));
|
||||
}
|
||||
|
185
security/vaultwarden/patches/patch-src_util_rs
Normal file
185
security/vaultwarden/patches/patch-src_util_rs
Normal file
@ -0,0 +1,185 @@
|
||||
Index: src/util.rs
|
||||
--- src/util.rs.orig
|
||||
+++ src/util.rs
|
||||
@@ -5,10 +5,10 @@ use std::io::Cursor;
|
||||
|
||||
use rocket::{
|
||||
fairing::{Fairing, Info, Kind},
|
||||
- http::{ContentType, Header, HeaderMap, Method, RawStr, Status},
|
||||
+ http::{ContentType, Header, HeaderMap, Method, Status},
|
||||
request::FromParam,
|
||||
response::{self, Responder},
|
||||
- Data, Request, Response, Rocket,
|
||||
+ Data, Orbit, Request, Response, Rocket,
|
||||
};
|
||||
|
||||
use std::thread::sleep;
|
||||
@@ -18,6 +18,7 @@ use crate::CONFIG;
|
||||
|
||||
pub struct AppHeaders();
|
||||
|
||||
+#[rocket::async_trait]
|
||||
impl Fairing for AppHeaders {
|
||||
fn info(&self) -> Info {
|
||||
Info {
|
||||
@@ -26,7 +27,7 @@ impl Fairing for AppHeaders {
|
||||
}
|
||||
}
|
||||
|
||||
- fn on_response(&self, _req: &Request, res: &mut Response) {
|
||||
+ async fn on_response<'r>(&self, _req: &'r Request<'_>, res: &mut Response<'r>) {
|
||||
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("X-Frame-Options", "SAMEORIGIN");
|
||||
@@ -72,6 +73,7 @@ impl Cors {
|
||||
}
|
||||
}
|
||||
|
||||
+#[rocket::async_trait]
|
||||
impl Fairing for Cors {
|
||||
fn info(&self) -> Info {
|
||||
Info {
|
||||
@@ -80,7 +82,7 @@ impl Fairing for Cors {
|
||||
}
|
||||
}
|
||||
|
||||
- fn on_response(&self, request: &Request, response: &mut Response) {
|
||||
+ async fn on_response<'r>(&self, request: &'r Request<'_>, response: &mut Response<'r>) {
|
||||
let req_headers = request.headers();
|
||||
|
||||
if let Some(origin) = Cors::get_allowed_origin(req_headers) {
|
||||
@@ -97,7 +99,7 @@ impl Fairing for Cors {
|
||||
response.set_header(Header::new("Access-Control-Allow-Credentials", "true"));
|
||||
response.set_status(Status::Ok);
|
||||
response.set_header(ContentType::Plain);
|
||||
- response.set_sized_body(Cursor::new(""));
|
||||
+ response.set_sized_body(Some(0), Cursor::new(""));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -134,25 +136,21 @@ impl<R> Cached<R> {
|
||||
}
|
||||
}
|
||||
|
||||
-impl<'r, R: Responder<'r>> Responder<'r> for Cached<R> {
|
||||
- fn respond_to(self, req: &Request) -> response::Result<'r> {
|
||||
+impl<'r, R: 'r + Responder<'r, 'static> + Send> Responder<'r, 'static> for Cached<R> {
|
||||
+ fn respond_to(self, request: &'r Request<'_>) -> response::Result<'static> {
|
||||
+ let mut res = self.response.respond_to(request)?;
|
||||
+
|
||||
let cache_control_header = if self.is_immutable {
|
||||
format!("public, immutable, max-age={}", self.ttl)
|
||||
} else {
|
||||
format!("public, max-age={}", self.ttl)
|
||||
};
|
||||
+ res.set_raw_header("Cache-Control", cache_control_header);
|
||||
|
||||
let time_now = chrono::Local::now();
|
||||
-
|
||||
- match self.response.respond_to(req) {
|
||||
- Ok(mut res) => {
|
||||
- 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)
|
||||
- }
|
||||
- e @ Err(_) => e,
|
||||
- }
|
||||
+ 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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,11 +173,9 @@ impl<'r> FromParam<'r> for SafeString {
|
||||
type Error = ();
|
||||
|
||||
#[inline(always)]
|
||||
- fn from_param(param: &'r RawStr) -> Result<Self, Self::Error> {
|
||||
- let s = param.percent_decode().map(|cow| cow.into_owned()).map_err(|_| ())?;
|
||||
-
|
||||
- if s.chars().all(|c| matches!(c, 'a'..='z' | 'A'..='Z' |'0'..='9' | '-')) {
|
||||
- Ok(SafeString(s))
|
||||
+ fn from_param(param: &'r str) -> Result<Self, Self::Error> {
|
||||
+ if param.chars().all(|c| matches!(c, 'a'..='z' | 'A'..='Z' |'0'..='9' | '-')) {
|
||||
+ Ok(SafeString(param.to_string()))
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
@@ -193,15 +189,16 @@ const LOGGED_ROUTES: [&str; 6] =
|
||||
|
||||
// Boolean is extra debug, when true, we ignore the whitelist above and also print the mounts
|
||||
pub struct BetterLogging(pub bool);
|
||||
+#[rocket::async_trait]
|
||||
impl Fairing for BetterLogging {
|
||||
fn info(&self) -> Info {
|
||||
Info {
|
||||
name: "Better Logging",
|
||||
- kind: Kind::Launch | Kind::Request | Kind::Response,
|
||||
+ kind: Kind::Liftoff | Kind::Request | Kind::Response,
|
||||
}
|
||||
}
|
||||
|
||||
- fn on_launch(&self, rocket: &Rocket) {
|
||||
+ async fn on_liftoff(&self, rocket: &Rocket<Orbit>) {
|
||||
if self.0 {
|
||||
info!(target: "routes", "Routes loaded:");
|
||||
let mut routes: Vec<_> = rocket.routes().collect();
|
||||
@@ -225,34 +222,36 @@ impl Fairing for BetterLogging {
|
||||
info!(target: "start", "Rocket has launched from {}", addr);
|
||||
}
|
||||
|
||||
- fn on_request(&self, request: &mut Request<'_>, _data: &Data) {
|
||||
+ async fn on_request(&self, request: &mut Request<'_>, _data: &mut Data<'_>) {
|
||||
let method = request.method();
|
||||
if !self.0 && method == Method::Options {
|
||||
return;
|
||||
}
|
||||
let uri = request.uri();
|
||||
let uri_path = uri.path();
|
||||
- let uri_subpath = uri_path.strip_prefix(&CONFIG.domain_path()).unwrap_or(uri_path);
|
||||
+ let uri_path_str = uri_path.url_decode_lossy();
|
||||
+ let uri_subpath = uri_path_str.strip_prefix(&CONFIG.domain_path()).unwrap_or(&uri_path_str);
|
||||
if self.0 || LOGGED_ROUTES.iter().any(|r| uri_subpath.starts_with(r)) {
|
||||
match uri.query() {
|
||||
- Some(q) => info!(target: "request", "{} {}?{}", method, uri_path, &q[..q.len().min(30)]),
|
||||
- None => info!(target: "request", "{} {}", method, uri_path),
|
||||
+ Some(q) => info!(target: "request", "{} {}?{}", method, uri_path_str, &q[..q.len().min(30)]),
|
||||
+ None => info!(target: "request", "{} {}", method, uri_path_str),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
- fn on_response(&self, request: &Request, response: &mut Response) {
|
||||
+ async fn on_response<'r>(&self, request: &'r Request<'_>, response: &mut Response<'r>) {
|
||||
if !self.0 && request.method() == Method::Options {
|
||||
return;
|
||||
}
|
||||
let uri_path = request.uri().path();
|
||||
- let uri_subpath = uri_path.strip_prefix(&CONFIG.domain_path()).unwrap_or(uri_path);
|
||||
+ let uri_path_str = uri_path.url_decode_lossy();
|
||||
+ let uri_subpath = uri_path_str.strip_prefix(&CONFIG.domain_path()).unwrap_or(&uri_path_str);
|
||||
if self.0 || LOGGED_ROUTES.iter().any(|r| uri_subpath.starts_with(r)) {
|
||||
let status = response.status();
|
||||
- if let Some(route) = request.route() {
|
||||
- info!(target: "response", "{} => {} {}", route, status.code, status.reason)
|
||||
+ if let Some(ref route) = request.route() {
|
||||
+ info!(target: "response", "{} => {}", route, status)
|
||||
} else {
|
||||
- info!(target: "response", "{} {}", status.code, status.reason)
|
||||
+ info!(target: "response", "{}", status)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -614,10 +613,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
-use reqwest::{
|
||||
- blocking::{Client, ClientBuilder},
|
||||
- header,
|
||||
-};
|
||||
+use reqwest::{header, Client, ClientBuilder};
|
||||
|
||||
pub fn get_reqwest_client() -> Client {
|
||||
get_reqwest_client_builder().build().expect("Failed to build client")
|
10
security/vaultwarden/pkg/DESCR
Normal file
10
security/vaultwarden/pkg/DESCR
Normal file
@ -0,0 +1,10 @@
|
||||
Unofficial Bitwarden compatible server written in Rust and compatible
|
||||
with upstream Bitwarden clients.
|
||||
Full implementation of Bitwarden API is provided including:
|
||||
- Organizations support
|
||||
- Attachments
|
||||
- Vault API support
|
||||
- Serving the static files for Vault interface
|
||||
- Website icons API
|
||||
- Authenticator and U2F support
|
||||
- YubiKey and Duo support
|
12
security/vaultwarden/pkg/PLIST
Normal file
12
security/vaultwarden/pkg/PLIST
Normal file
@ -0,0 +1,12 @@
|
||||
@newgroup _vaultwarden:878
|
||||
@newuser _vaultwarden:878:878:default:Vaultwarden Daemon:/nonexistent:/sbin/nologin
|
||||
@rcscript ${RCDIR}/vaultwarden
|
||||
@bin bin/vaultwarden
|
||||
share/doc/vaultwarden/
|
||||
share/doc/vaultwarden/.env.template
|
||||
@owner _vaultwarden
|
||||
@group _vaultwarden
|
||||
@mode 640
|
||||
@sample /var/vaultwarden/.env
|
||||
@mode 750
|
||||
@sample /var/vaultwarden/data/
|
15
security/vaultwarden/pkg/vaultwarden.rc
Normal file
15
security/vaultwarden/pkg/vaultwarden.rc
Normal file
@ -0,0 +1,15 @@
|
||||
#!/bin/ksh
|
||||
|
||||
daemon="${PREFIX}/bin/vaultwarden"
|
||||
daemon_user="_vaultwarden"
|
||||
|
||||
. /etc/rc.d/rc.subr
|
||||
|
||||
rc_start() {
|
||||
${rcexec} "cd ${VARBASE}/vaultwarden; ${daemon} ${daemon_flags}"
|
||||
}
|
||||
|
||||
rc_bg=YES
|
||||
rc_reload=NO
|
||||
|
||||
rc_cmd $1
|
Loading…
Reference in New Issue
Block a user