vw_small

Hardened fork of Vaultwarden (https://github.com/dani-garcia/vaultwarden) with fewer features.
git clone https://git.philomathiclife.com/repos/vw_small
Log | Files | Refs | README

commit a1272c71901016cb4ec617547e600377423277ec
parent 0a6b4e9961872963888a95ae2b06b5a14770f941
Author: Daniel GarcĂ­a <dani-garcia@users.noreply.github.com>
Date:   Thu, 13 Dec 2018 17:49:55 +0100

Merge branch 'rocket-0.4'

Diffstat:
M.env | 11+++++++++++
M.travis.yml | 2++
MCargo.lock | 843++++++++++++++++++++++++++++++++++++++++++-------------------------------------
MCargo.toml | 43++++++++++++++++++++++++++-----------------
MDockerfile | 9++++++---
MDockerfile.aarch64 | 8++++----
MDockerfile.alpine | 7++++---
MDockerfile.armv7 | 5+++--
Dlibs/jsonwebtoken/Cargo.toml | 20--------------------
Dlibs/jsonwebtoken/LICENSE | 21---------------------
Dlibs/jsonwebtoken/src/crypto.rs | 120-------------------------------------------------------------------------------
Dlibs/jsonwebtoken/src/errors.rs | 68--------------------------------------------------------------------
Dlibs/jsonwebtoken/src/header.rs | 64----------------------------------------------------------------
Dlibs/jsonwebtoken/src/lib.rs | 142-------------------------------------------------------------------------------
Dlibs/jsonwebtoken/src/serialization.rs | 42------------------------------------------
Dlibs/jsonwebtoken/src/validation.rs | 377-------------------------------------------------------------------------------
Amigrations/2018-11-27-152651_add_att_key_columns/down.sql | 0
Amigrations/2018-11-27-152651_add_att_key_columns/up.sql | 4++++
Mrust-toolchain | 2+-
Msrc/api/core/accounts.rs | 159+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
Msrc/api/core/ciphers.rs | 210++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Msrc/api/core/folders.rs | 29++++++++++++++++++++++-------
Msrc/api/core/mod.rs | 193++++++++++++++++---------------------------------------------------------------
Msrc/api/core/organizations.rs | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
Msrc/api/core/two_factor.rs | 55+++++++++++++++++++++++++++++++++++++++----------------
Msrc/api/icons.rs | 8++++----
Msrc/api/identity.rs | 253+++++++++++++++++++++++++++++++------------------------------------------------
Msrc/api/mod.rs | 9+++++----
Msrc/api/notifications.rs | 30+++++++++++++++---------------
Msrc/api/web.rs | 7++++---
Msrc/auth.rs | 86++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Msrc/db/mod.rs | 2+-
Msrc/db/models/attachment.rs | 55++++++++++++++++++++-----------------------------------
Msrc/db/models/cipher.rs | 40++++++++++++++++------------------------
Msrc/db/models/collection.rs | 19+++++++------------
Msrc/db/models/device.rs | 25++++++++++++++++---------
Msrc/db/models/folder.rs | 14++++++--------
Msrc/db/models/organization.rs | 31+++++++++++++++----------------
Msrc/db/models/two_factor.rs | 14++++++--------
Msrc/db/models/user.rs | 25+++++++++++--------------
Msrc/db/schema.rs | 1+
Msrc/mail.rs | 2+-
Msrc/main.rs | 133++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Msrc/util.rs | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
44 files changed, 1361 insertions(+), 1974 deletions(-)

diff --git a/.env b/.env @@ -18,6 +18,17 @@ # WEBSOCKET_ADDRESS=0.0.0.0 # WEBSOCKET_PORT=3012 +## Enable extended logging +## This shows timestamps and allows logging to file and to syslog +### To enable logging to file, use the LOG_FILE env variable +### To enable syslog, you need to compile with `cargo build --features=enable_syslog' +# EXTENDED_LOGGING=true + +## Logging to file +## This requires extended logging +## It's recommended to also set 'ROCKET_CLI_COLORS=off' +# LOG_FILE=/path/to/log + ## Controls if new users can register # SIGNUPS_ALLOWED=true diff --git a/.travis.yml b/.travis.yml @@ -5,3 +5,5 @@ dist: trusty # so we get a VM with higher specs cache: cargo rust: - nightly +script: +- cargo build --verbose --all-features diff --git a/Cargo.lock b/Cargo.lock @@ -8,7 +8,7 @@ name = "aho-corasick" version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -18,7 +18,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "arrayvec" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", @@ -41,7 +41,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -52,24 +52,7 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "base64" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "base64" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -91,6 +74,11 @@ dependencies = [ [[package]] name = "bitflags" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bitflags" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -105,26 +93,28 @@ dependencies = [ "diesel 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "diesel_migrations 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonwebtoken 4.0.1", + "fern 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonwebtoken 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "lettre 0.9.0 (git+https://github.com/lettre/lettre?rev=c988b1760ad81)", "lettre_email 0.9.0 (git+https://github.com/lettre/lettre?rev=c988b1760ad81)", "libsqlite3-sys 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", - "multipart 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "multipart 0.15.4 (registry+https://github.com/rust-lang/crates.io-index)", "native-tls 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "oath 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "reqwest 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)", "rmpv 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rocket 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", - "rocket_codegen 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", - "rocket_contrib 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", + "rocket 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rocket_contrib 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", - "u2f 0.1.2 (git+https://github.com/wisespace-io/u2f-rs?rev=193de35093a44)", + "syslog 4.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "u2f 0.1.2 (git+https://github.com/wisespace-io/u2f-rs?rev=75b9fa5afb4c5)", "uuid 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "ws 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", "yubico 0.4.0 (git+https://github.com/dani-garcia/yubico-rs)", @@ -132,12 +122,11 @@ dependencies = [ [[package]] name = "buf_redux" -version = "0.7.1" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slice-deque 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -146,11 +135,6 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "build_const" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] name = "byte-tools" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -218,11 +202,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cookie" -version = "0.9.2" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -233,7 +217,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -241,24 +225,15 @@ name = "core-foundation-sys" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crc" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "crossbeam-deque" -version = "0.2.0" +name = "crc32fast" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -267,70 +242,72 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-epoch 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crossbeam-epoch" -version = "0.3.1" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "crossbeam-epoch" -version = "0.6.1" +name = "crossbeam-utils" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "crossbeam-utils" -version = "0.2.2" +name = "crypto-mac" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "generic-array 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "crossbeam-utils" -version = "0.5.0" +name = "data-encoding" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "crossbeam-utils" -version = "0.6.1" +name = "devise" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "devise_codegen 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "devise_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "crypto-mac" -version = "0.3.0" +name = "devise_codegen" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "generic-array 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "devise_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "data-encoding" -version = "2.1.1" +name = "devise_core" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "diesel" @@ -387,7 +364,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -468,7 +445,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "encoding_rs" -version = "0.8.12" +version = "0.8.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -478,6 +455,9 @@ dependencies = [ name = "error-chain" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "failure" @@ -495,7 +475,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.21 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -513,6 +493,25 @@ dependencies = [ ] [[package]] +name = "fern" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "syslog 4.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "filetime" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "fnv" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -531,6 +530,24 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] +name = "fsevent" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "fsevent-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fsevent-sys" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "fuchsia-zircon" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -579,18 +596,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "h2" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "string 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "string 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -609,13 +626,13 @@ name = "hostname" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", "winutil 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "http" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -648,38 +665,39 @@ dependencies = [ [[package]] name = "hyper" -version = "0.12.14" +version = "0.12.17" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "h2 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "h2 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-tcp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "want 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "hyper-sync-rustls" -version = "0.1.0" +version = "0.3.0-rc.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "hyper 0.10.15 (registry+https://github.com/rust-lang/crates.io-index)", - "rustls 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "webpki-roots 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustls 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)", + "webpki-roots 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -689,7 +707,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.12.14 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.17 (registry+https://github.com/rust-lang/crates.io-index)", "native-tls 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -710,11 +728,33 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] +name = "inotify" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "inotify-sys" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "iovec" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -739,8 +779,8 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -751,16 +791,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "jsonwebtoken" -version = "4.0.1" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -779,17 +819,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "lazy_static" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "lazy_static" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "lazycell" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -806,8 +841,8 @@ dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "native-tls 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "nom 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -828,17 +863,17 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.43" +version = "0.2.45" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libflate" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crc32fast 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -877,25 +912,17 @@ dependencies = [ ] [[package]] -name = "mach" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] name = "matches" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "memchr" -version = "2.1.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -969,8 +996,8 @@ dependencies = [ "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazycell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", @@ -983,7 +1010,7 @@ name = "mio-extras" version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazycell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -995,7 +1022,7 @@ version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1017,17 +1044,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "multipart" -version = "0.15.3" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "buf_redux 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "buf_redux 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.10.15 (registry+https://github.com/rust-lang/crates.io-index)", "iron 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "mime_guess 1.8.6 (registry+https://github.com/rust-lang/crates.io-index)", - "nickel 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "nickel 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1051,7 +1078,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "openssl 0.10.15 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1059,7 +1086,7 @@ dependencies = [ "schannel 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "security-framework 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "security-framework-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1068,13 +1095,13 @@ version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "nickel" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "groupable 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1084,7 +1111,7 @@ dependencies = [ "modifier 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "mustache 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "plugin 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "typemap 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1101,7 +1128,25 @@ name = "nom" version = "4.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "notify" +version = "4.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "fsevent 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", + "fsevent-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", + "mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1112,7 +1157,7 @@ dependencies = [ "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.21 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1141,7 +1186,7 @@ name = "num_cpus" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1165,7 +1210,7 @@ dependencies = [ "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-sys 0.9.39 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1180,17 +1225,12 @@ version = "0.9.39" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "ordermap" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] name = "owning_ref" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1227,9 +1267,9 @@ name = "parking_lot_core" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1238,23 +1278,29 @@ name = "parking_lot_core" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "pear" -version = "0.0.20" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "pear_codegen 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "pear_codegen" -version = "0.0.20" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "yansi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1370,7 +1416,7 @@ version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1380,7 +1426,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1391,23 +1437,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_isaac 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1446,7 +1492,7 @@ dependencies = [ [[package]] name = "rand_isaac" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1470,64 +1516,25 @@ dependencies = [ ] [[package]] -name = "rayon" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rayon-core" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] name = "redox_syscall" -version = "0.1.42" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "regex" -version = "0.2.11" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "regex" -version = "1.0.6" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "regex-syntax" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "regex-syntax" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1548,20 +1555,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "encoding_rs 0.8.12 (registry+https://github.com/rust-lang/crates.io-index)", + "encoding_rs 0.8.13 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.12.14 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.17 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-tls 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libflate 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", + "libflate 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "mime 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", "mime_guess 2.0.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", "native-tls 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", "serde_urlencoded 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "uuid 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1569,14 +1576,13 @@ dependencies = [ [[package]] name = "ring" -version = "0.11.0" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1599,59 +1605,74 @@ dependencies = [ [[package]] name = "rocket" -version = "0.3.17" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", - "cookie 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.10.15 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper-sync-rustls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "isatty 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ordermap 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "pear 0.0.20 (registry+https://github.com/rust-lang/crates.io-index)", - "pear_codegen 0.0.20 (registry+https://github.com/rust-lang/crates.io-index)", - "rustls 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "pear 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rocket_codegen 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rocket_http 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "state 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "yansi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "yansi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rocket_codegen" -version = "0.3.17" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "rocket 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", + "devise 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "rocket_http 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "yansi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "yansi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rocket_contrib" -version = "0.3.17" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "rocket 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "notify 4.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rocket 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] +name = "rocket_http" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cookie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.10.15 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper-sync-rustls 0.3.0-rc.4 (registry+https://github.com/rust-lang/crates.io-index)", + "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "pear 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustls 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "state 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "rust-crypto" version = "0.2.36" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1682,15 +1703,15 @@ dependencies = [ [[package]] name = "rustls" -version = "0.9.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "webpki 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)", + "sct 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1709,6 +1730,14 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] +name = "same-file" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "schannel" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1731,13 +1760,22 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] +name = "sct" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)", + "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "security-framework" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "core-foundation 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", "security-framework-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1747,7 +1785,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1765,17 +1803,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.80" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_derive" -version = "1.0.80" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.21 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1785,7 +1823,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1795,7 +1833,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1839,18 +1877,8 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "slice-deque" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "mach 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] name = "smallvec" -version = "0.6.6" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1868,7 +1896,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "string" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1893,7 +1921,7 @@ dependencies = [ [[package]] name = "syn" -version = "0.15.21" +version = "0.15.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1916,11 +1944,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.21 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] +name = "syslog" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "tempdir" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1931,13 +1970,13 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.0.4" +version = "3.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1947,8 +1986,8 @@ name = "thread-id" version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1973,8 +2012,8 @@ name = "time" version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1993,23 +2032,24 @@ dependencies = [ [[package]] name = "tokio" -version = "0.1.11" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-current-thread 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-current-thread 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-fs 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-tcp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-udp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-uds 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-uds 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2024,7 +2064,7 @@ dependencies = [ [[package]] name = "tokio-current-thread" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2046,7 +2086,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2061,10 +2101,10 @@ dependencies = [ [[package]] name = "tokio-reactor" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2086,29 +2126,29 @@ dependencies = [ "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-threadpool" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-deque 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-timer" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2116,7 +2156,7 @@ dependencies = [ [[package]] name = "tokio-udp" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2125,31 +2165,32 @@ dependencies = [ "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-uds" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "toml" -version = "0.4.8" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2167,7 +2208,7 @@ name = "twoway" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2191,19 +2232,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "u2f" version = "0.1.2" -source = "git+https://github.com/wisespace-io/u2f-rs?rev=193de35093a44#193de35093a44576edba6cc94d9b54f2a1cbdcd1" +source = "git+https://github.com/wisespace-io/u2f-rs?rev=75b9fa5afb4c5#75b9fa5afb4c5230255136b6689df2a359f41472" dependencies = [ - "base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "webpki 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", + "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2268,7 +2309,7 @@ dependencies = [ [[package]] name = "untrusted" -version = "0.5.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2310,41 +2351,41 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "want" -version = "0.0.6" +name = "walkdir" +version = "2.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "webpki" -version = "0.14.0" +name = "want" +version = "0.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "webpki" -version = "0.16.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)", + "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "webpki-roots" -version = "0.11.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "webpki 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2372,6 +2413,14 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] +name = "winapi-util" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2416,13 +2465,18 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] +name = "yansi" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "yubico" version = "0.4.0" source = "git+https://github.com/dani-garcia/yubico-rs#a3a8143611f651d1ff6ec9a2d12599d0aaaea0c6" dependencies = [ "base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "reqwest 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)", "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2433,19 +2487,17 @@ dependencies = [ "checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c" "checksum aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9a933f4e58658d7b12defcf96dc5c720f20832deebe3e0a19efd3b6aaeeb9e" "checksum antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34fde25430d87a9388dadbe6e34d7f72a462c8b43ac8d309b42b0a8505d7e2a5" -"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" +"checksum arrayvec 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "f405cc4c21cd8b784f6c8fc2adf9bc00f59558f0049b5ec21517f875963040cc" "checksum ascii 0.8.7 (registry+https://github.com/rust-lang/crates.io-index)" = "97be891acc47ca214468e09425d02cef3af2c94d0d82081cd02061f996802f14" "checksum ascii_utils 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "71938f30533e4d95a6d17aa530939da3842c2ab6f4f84b9dae68447e4129f74a" "checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a" "checksum backtrace-sys 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "c66d56ac8dabd07f6aacdaf633f4b8262f5b3601a810a0dcddffd5c22c69daa0" "checksum base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "621fc7ecb8008f86d7fb9b95356cd692ce9514b80a86d85b397f32a22da7b9e2" -"checksum base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "30e93c03064e7590d0466209155251b90c22e37fab1daf2771582598b5827557" -"checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9" "checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" +"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" -"checksum buf_redux 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20c6687a26c9ce967594b78038c06139a0d3a5b3005d16572284d543924a01aa" +"checksum buf_redux 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72f25c67abbf523ff8457771622fb731ac4a2391439de33bc60febcdee1749c9" "checksum bufstream 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "40e38929add23cdf8a366df9b0e088953150724bcbe5fc330b0d8eb3b328eec8" -"checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" "checksum byte-tools 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0919189ba800c7ffe8778278116b7e0de3905ab81c72abb69c85cbfef7991279" "checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d" "checksum bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa" @@ -2456,19 +2508,18 @@ dependencies = [ "checksum chunked_transfer 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "498d20a7aaf62625b9bf26e637cf7736417cde1d0c99f1d04d1170229a85cf87" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" -"checksum cookie 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "477eb650753e319be2ae77ec368a58c638f9f0c4d941c39bad95e950fb1d1d0d" +"checksum cookie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1465f8134efa296b4c19db34d909637cb2bf0f7aaf21299e23e18fa29ac557cf" "checksum core-foundation 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "286e0b41c3a20da26536c6000a280585d519fd07b3956b43aed8a79e9edce980" "checksum core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "716c271e8613ace48344f723b60b900a93150271e5be206212d052bbc0883efa" -"checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" -"checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" +"checksum crc32fast 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e91d5240c6975ef33aeb5f148f35275c25eda8e8a5f95abe421978b05b8bf192" "checksum crossbeam-deque 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4fe1b6f945f824c7a25afe44f62e25d714c0cc523f8e99d8db5cd1026e1269d3" -"checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" "checksum crossbeam-epoch 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2449aaa4ec7ef96e5fb24db16024b935df718e9ae1cec0a1e68feeca2efca7b8" -"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" -"checksum crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "677d453a17e8bd2b913fa38e8b9cf04bcdbb5be790aa294f2389661d72036015" -"checksum crossbeam-utils 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c55913cc2799171a550e307918c0a360e8c16004820291bf3b638969b4a01816" +"checksum crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e07fc155212827475223f0bcfae57e945e694fc90950ddf3f6695bbfd5555c72" "checksum crypto-mac 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dba62c86c26dcba13c278afcaac0c7452486fe604a2668a0dfa4e0edc98d8a9e" "checksum data-encoding 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "67df0571a74bf0d97fb8b2ed22abdd9a48475c96bd327db968b7d9cace99655e" +"checksum devise 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "74e04ba2d03c5fa0d954c061fc8c9c288badadffc272ebb87679a89846de3ed3" +"checksum devise_codegen 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "066ceb7928ca93a9bedc6d0e612a8a0424048b0ab1f75971b203d01420c055d7" +"checksum devise_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cf41c59b22b5e3ec0ea55c7847e5f358d340f3a8d6d53a5cf4f1564967f96487" "checksum diesel 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "164080ac16a4d1d80a50f0a623e4ddef41cb2779eee85bcc76907d340dfc98cc" "checksum diesel_derives 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "03bcaf77491f53e400d5ee3bdd57142ea4e1c47fe9217b3361ff9a76ca0e3d37" "checksum diesel_migrations 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b42c35d1ce9e8d57a3e7001b4127f2bc1b073a89708bb7019f5be27c991c28" @@ -2484,15 +2535,19 @@ dependencies = [ "checksum encoding-index-singlebyte 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3351d5acffb224af9ca265f435b859c7c01537c0849754d3db3fdf2bfe2ae84a" "checksum encoding-index-tradchinese 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fd0e20d5688ce3cab59eb3ef3a2083a5c77bf496cb798dc6fcdb75f323890c18" "checksum encoding_index_tests 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569" -"checksum encoding_rs 0.8.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ca20350a7cb5aab5b9034731123d6d412caf3e92d4985e739e411ba0955fd0eb" +"checksum encoding_rs 0.8.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1a8fa54e6689eb2549c4efed8d00d7f3b2b994a064555b0e8df4ae3764bcc4be" "checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3" "checksum failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6dd377bcc1b1b7ce911967e3ec24fa19c3224394ec05b54aa7b083d498341ac7" "checksum failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "64c2d913fe8ed3b6c6518eedf4538255b989945c14c2a7d5cbff62a5e2120596" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" "checksum fast_chemail 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)" = "115e1df89e36c3300a0f88b8b81c41ad24f7bf2b291912e405824d98a553704b" +"checksum fern 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b48af88aaf938b11baef948a5599e66e709cf92854aa2b87c71f1bcf20f80a01" +"checksum filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a2df5c1a8c4be27e7707789dc42ae65976e60b394afd293d1419ab915833e646" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" "checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +"checksum fsevent 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "c4bbbf71584aeed076100b5665ac14e3d85eeb31fdbb45fbd41ef9a682b5ec05" +"checksum fsevent-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1a772d36c338d07a032d5375a36f15f9a7043bf0cb8ce7cee658e037c6032874" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "49e7653e374fe0d0c12de4250f0bdb60680b8c80eed558c5c7538eec9c89e21b" @@ -2500,37 +2555,38 @@ dependencies = [ "checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" "checksum generic-array 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe043cf9b85297937897087de81f590361686e1ac2d4d471b45435de5dfb6a6" "checksum groupable 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "32619942b8be646939eaf3db0602b39f5229b74575b67efc897811ded1db4e57" -"checksum h2 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "7dd33bafe2e6370e6c8eb0cf1b8c5f93390b90acde7e9b03723f166b28b648ed" +"checksum h2 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "1ac030ae20dee464c5d0f36544d8b914a6bc606da44a57e052d2b0f5dae129e0" "checksum hmac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bdb5aa9647ba4711e9d6968dc1c810cd23989ed435443ca962e1bf6d8b8b83ff" "checksum hostname 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "21ceb46a83a85e824ef93669c8b390009623863b5c195d1ba747292c0c72f94e" -"checksum http 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "24f58e8c2d8e886055c3ead7b28793e1455270b5fb39650984c224bc538ba581" +"checksum http 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "02096a6d2c55e63f7fcb800690e4f889a25f6ec342e3adb4594e293b625215ab" "checksum httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e8734b0cfd3bc3e101ec59100e101c2eecd19282202e87808b3037b442777a83" "checksum hyper 0.10.15 (registry+https://github.com/rust-lang/crates.io-index)" = "df0caae6b71d266b91b4a83111a61d2b94ed2e2bea024c532b933dcff867e58c" -"checksum hyper 0.12.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2f60ae467ef4fc5eba9a34d31648c9c8ed902faf45a217f6734ce9ea64779ac7" -"checksum hyper-sync-rustls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c6df6f419a9f116cc93b5f39a5ded1161e088a2c8424c8fcd1d4049193424a4" +"checksum hyper 0.12.17 (registry+https://github.com/rust-lang/crates.io-index)" = "c49a75385d35ff5e9202755f09beb0b878a05c4c363fcc52b23eeb5dcb6782cc" +"checksum hyper-sync-rustls 0.3.0-rc.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6d1a443a90413a118ac6739e024f6a5180aa3b3f43f7de65f9d388a961cff19b" "checksum hyper-tls 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "32cd73f14ad370d3b4d4b7dce08f69b81536c82e39fcc89731930fe5788cd661" "checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" "checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d" +"checksum inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40b54539f3910d6f84fbf9a643efd6e3aa6e4f001426c0329576128255994718" +"checksum inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e74a1aa87c59aeff6ef2cc2fa62d41bc43f54952f55652656b18a02fd5e356c0" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" "checksum iron 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d8e17268922834707e1c29e8badbf9c712c9c43378e1b6a3388946baff10be2" "checksum isatty 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e31a8281fc93ec9693494da65fbf28c0c2aa60a2eaec25dc58e2f31952e95edc" "checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b" +"checksum jsonwebtoken 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8d438ea707d465c230305963b67f8357a1d56fcfad9434797d7cb1c46c2e41df" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" -"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" "checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" -"checksum lazycell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ddba4c30a78328befecec92fc94970e53b3ae385827d28620f0f5bb2493081e0" +"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" "checksum lettre 0.9.0 (git+https://github.com/lettre/lettre?rev=c988b1760ad81)" = "<none>" "checksum lettre_email 0.9.0 (git+https://github.com/lettre/lettre?rev=c988b1760ad81)" = "<none>" -"checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d" -"checksum libflate 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "21138fc6669f438ed7ae3559d5789a5f0ba32f28c1f0608d1e452b0bb06ee936" +"checksum libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "2d2857ec59fadc0773853c664d2d18e7198e83883e7060b63c924cb077bd5c74" +"checksum libflate 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)" = "bff3ac7d6f23730d3b533c35ed75eef638167634476a499feef16c428d74b57b" "checksum libsqlite3-sys 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d3711dfd91a1081d2458ad2d06ea30a8755256e74038be2ad927d94e1c955ca8" "checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" -"checksum mach 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "86dd2487cdfea56def77b88438a2c915fb45113c5319bfe7e14306ca4cd0b0e1" "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" -"checksum memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0a3eb002f0535929f1199681417029ebea04aadc0c7a4224b46be99c7f5d6a16" +"checksum memchr 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "db4c41318937f6e76648f42826b1d9ade5c09cafb5aef7e351240a70f39206e9" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" "checksum migrations_internals 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8cf7c8c4f83fa9f47440c0b4af99973502de55e6e7b875f693bd263e03f93e7e" "checksum migrations_macros 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "79f12499ef7353bdeca2d081bc61edd8351dac09a33af845952009b5a3d68c1a" @@ -2543,13 +2599,14 @@ dependencies = [ "checksum mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" "checksum modifier 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "41f5c9112cb662acd3b204077e0de5bc66305fa8df65c8019d5adb10e9ab6e58" -"checksum multipart 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b3bd50d71866514b14d2ca09823d81390d92daa40bc835f83a908c52ab0a802e" +"checksum multipart 0.15.4 (registry+https://github.com/rust-lang/crates.io-index)" = "adba94490a79baf2d6a23eac897157047008272fa3eecb3373ae6377b91eca28" "checksum mustache 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ddb004e419334fc9172d0a5ff91c0770bdd6239091b0b343eb5926101f0a7d13" "checksum native-tls 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ff8e08de0070bbf4c31f452ea2a70db092f36f6f2e4d897adf5674477d488fb2" "checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" -"checksum nickel 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "22b40e35b9f46a076dcbd8193125cea0e4130b1c015f68655038010f3e826e04" +"checksum nickel 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "da8f6d24c912e56ae0b595fed54326dc49e8d7c8a13f303861fd0c2c3021e746" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" "checksum nom 4.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9c349f68f25f596b9f44cf0e7c69752a5c633b0550c3ff849518bfba0233774a" +"checksum notify 4.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "873ecfd8c174964ae30f401329d140142312c8e5590719cf1199d5f1717d8078" "checksum num-derive 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8af1847c907c2f04d7bfd572fb25bbb4385c637fe5be163cf2f8c5d778fe1e7d" "checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" "checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" @@ -2559,15 +2616,14 @@ dependencies = [ "checksum openssl 0.10.15 (registry+https://github.com/rust-lang/crates.io-index)" = "5e1309181cdcbdb51bc3b6bedb33dfac2a83b3d585033d3f6d9e22e8c1928613" "checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" "checksum openssl-sys 0.9.39 (registry+https://github.com/rust-lang/crates.io-index)" = "278c1ad40a89aa1e741a1eed089a2f60b18fab8089c3139b542140fc7d674106" -"checksum ordermap 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "b81cf3b8cb96aa0e73bbedfcdc9708d09fec2854ba8d474be4e6f666d7379e8b" "checksum owning_ref 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9d52571ddcb42e9c900c901a18d8d67e393df723fcd51dd59c5b1a85d0acb6cc" "checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" "checksum parking_lot 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "fa12d706797d42551663426a45e2db2e0364bd1dbf6aeada87e89c5f981f43e9" "checksum parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0802bff09003b291ba756dc7e79313e51cc31667e94afbe847def490424cde5" "checksum parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4db1a8ccf734a7bce794cc19b3df06ed87ab2f3907036b693c68f56b4d4537fa" "checksum parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad7f7e6ebdc79edff6fdcb87a55b620174f7a989e3eb31b65231f4af57f00b8c" -"checksum pear 0.0.20 (registry+https://github.com/rust-lang/crates.io-index)" = "353fe88ff7a430c0f39ca4ec19e1f8fa0062f696370e8df3080ac40139a63301" -"checksum pear_codegen 0.0.20 (registry+https://github.com/rust-lang/crates.io-index)" = "fd0f3ef1db2d855e0c00fad8e5a8216a70df6d9c1c7f7a7ac9f1cf50675142b7" +"checksum pear 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c26d2b92e47063ffce70d3e3b1bd097af121a9e0db07ca38a6cc1cf0cc85ff25" +"checksum pear_codegen 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "336db4a192cc7f54efeb0c4e11a9245394824cc3bcbd37ba3ff51240c35d7a6e" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum phf 0.7.23 (registry+https://github.com/rust-lang/crates.io-index)" = "cec29da322b242f4c3098852c77a0ca261c9c01b806cae85a5572a1eb94db9a6" "checksum phf_codegen 0.7.23 (registry+https://github.com/rust-lang/crates.io-index)" = "7d187f00cd98d5afbcd8898f6cf181743a449162aeb329dcd2f3849009e605ad" @@ -2585,47 +2641,46 @@ dependencies = [ "checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1" "checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd" "checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c" -"checksum rand 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de3f08319b5395bd19b70e73c4c465329495db02dafeb8ca711a20f1c2bd058c" +"checksum rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae9d223d52ae411a33cf7e54ec6034ec165df296ccd23533d671a28252b6f66a" "checksum rand_chacha 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "771b009e3a508cb67e8823dda454aaa5368c7bc1c16829fb77d3e980440dd34a" "checksum rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1961a422c4d189dfb50ffa9320bf1f2a9bd54ecb92792fb9477f99a1045f3372" "checksum rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0905b6b7079ec73b314d4c748701f6931eb79fd97c668caa3f1899b22b32c6db" "checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" -"checksum rand_isaac 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d6ecfe9ebf36acd47a49d150990b047a5f7db0a7236ee2414b7ff5cc1097c7b" +"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" "checksum rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "086bd09a33c7044e56bb44d5bdde5a60e7f119a9e95b0775f545de759a32fe05" "checksum rand_xorshift 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "effa3fcaa47e18db002bdde6060944b6d2f9cfd8db471c30e873448ad9187be3" -"checksum rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a77c51c07654ddd93f6cb543c7a849863b03abc7e82591afda6dc8ad4ac3ac4a" -"checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356" -"checksum redox_syscall 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "cf8fb82a4d1c9b28f1c26c574a5b541f5ffb4315f6c9a791fa47b6a04438fe93" -"checksum regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9329abc99e39129fcceabd24cf5d85b4671ef7c29c50e972bc5afe32438ec384" -"checksum regex 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ee84f70c8c08744ea9641a731c7fadb475bf2ecc52d7f627feb833e0b3990467" -"checksum regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7" -"checksum regex-syntax 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fbc557aac2b708fe84121caf261346cc2eed71978024337e42eb46b8a252ac6e" +"checksum redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "679da7508e9a6390aeaf7fbd02a800fdc64b73fe2204dd2c8ae66d22d9d5ad5d" +"checksum regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37e7cbbd370869ce2e8dff25c7018702d10b21a20ef7135316f8daecd6c25b7f" +"checksum regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4e47a2ed29da7a9e1960e1639e7a982e6edc6d49be308a3b02daf511504a16d1" "checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" "checksum reqwest 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ab52e462d1e15891441aeefadff68bdea005174328ce3da0a314f2ad313ec837" -"checksum ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2a6dc7fc06a05e6de183c5b97058582e9da2de0c136eafe49609769c507724" +"checksum ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2c4db68a2e35f3497146b7e4563df7d4773a2433230c5e4b448328e31740458a" "checksum rmp 0.8.7 (git+https://github.com/dani-garcia/msgpack-rust)" = "<none>" "checksum rmpv 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29af0205707de955a396a1d3c657677c65f791ebabb63c0596c0b2fec0bf6325" -"checksum rocket 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "a61d746c68f1d357f6e011985570474c4af368aa81900320074098d34ed0c64e" -"checksum rocket_codegen 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "7873d65adfa3e440ac373a28240341853da170913aad7e4207c0198389e5d0e9" -"checksum rocket_contrib 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "4b2348e3b2458e173203f1e51f3b2e00495a092b70bd9506d2ce2ac64e129d14" +"checksum rocket 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "242154377a85c2a9e036fc31ffc8c200b9e1f22a196e47baa3b57716606ca89d" +"checksum rocket_codegen 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d907d6d458c859651c1cf4c8fa99b77685082bde0561db6a4600b365058f710" +"checksum rocket_contrib 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f73e161dad5730435f51c815a5c6831d2e57b6b4299b1bf609d31b09aa9a2fa7" +"checksum rocket_http 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba9d4f2ce5bba6e1b6d3100493bbad63879e99bbf6b4365d61e6f781daab324d" "checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" "checksum rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "bcfe5b13211b4d78e5c2cadfebd7769197d95c639c35a50057eb4c05de811395" "checksum rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0ceb8ce7a5e520de349e1fa172baeba4a9e8d5ef06c47471863530bc4972ee1e" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum rustls 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17727f4b991294da2c84d75a43c003151ff58072212768800f66c56ee46dca43" +"checksum rustls 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8b7891791343c75b73ed9a18cadcafd8c8563d11a88ebe2d87f5b8a3182654d9" "checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7" "checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" "checksum safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dca453248a96cb0749e36ccdfe2b0b4e54a61bfef89fb97ec621eb8e0a93dd9" +"checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267" "checksum schannel 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "0e1a231dc10abf6749cfa5d7767f25888d484201accbd919b66ab5413c502d56" "checksum scheduled-thread-pool 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a2ff3fc5223829be817806c6441279c676e454cc7da608faf03b0ccc09d3889" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" +"checksum sct 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb8f61f9e6eadd062a71c380043d28036304a4706b3c4dd001ff3387ed00745a" "checksum security-framework 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "697d3f3c23a618272ead9e1fb259c1411102b31c6af8b93f1d64cca9c3b0e8e0" "checksum security-framework-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab01dfbe5756785b5b4d46e0289e5a18071dfa9a7c2b24213ea00b9ef9b665bf" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)" = "15c141fc7027dd265a47c090bf864cf62b42c4d228bbcf4e51a0c9e2b0d3f7ef" -"checksum serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)" = "225de307c6302bec3898c51ca302fc94a7a1697ef0845fcee6448f33c032249c" +"checksum serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)" = "6fa52f19aee12441d5ad11c9a00459122bd8f98707cadf9778c540674f1935b6" +"checksum serde_derive 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)" = "96a7f9496ac65a2db5929afa087b54f8fc5008dcfbe48a8874ed20049b0d6154" "checksum serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)" = "c37ccd6be3ed1fdf419ee848f7c758eb31b054d7cd3ae3600e3bae0adf569811" "checksum serde_urlencoded 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d48f9f99cd749a2de71d29da5f948de7f2764cc5a9d7f3c97e3514d4ee6eabf2" "checksum sha-1 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8347606816471548cd60f0abd5ef0d513a81f5202dbdab9c09f17a15b5248484" @@ -2633,43 +2688,43 @@ dependencies = [ "checksum sha2 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "84920f9ac881e94e33ec89e1b3dcd36040523a308a92548e01217ce35d8cf6a8" "checksum siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" "checksum slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5f9776d6b986f77b35c6cf846c11ad986ff128fe0b2b63a3628e3755e8d3102d" -"checksum slice-deque 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "bf9114aa87a7c0ce55425e175d553fa0bef683c7bb2add185a878a2ff8643529" -"checksum smallvec 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "622df2d454c29a4d89b30dc3b27b42d7d90d6b9e587dbf8f67652eb7514da484" +"checksum smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b73ea3738b47563803ef814925e69be00799a8c07420be8b996f8e98fb2336db" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum state 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7345c971d1ef21ffdbd103a75990a15eb03604fc8b8852ca8cb418ee1a099028" -"checksum string 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00caf261d6f90f588f8450b8e1230fa0d5be49ee6140fdfbcb55335aff350970" +"checksum string 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "98998cced76115b1da46f63388b909d118a37ae0be0f82ad35773d4a4bc9d18d" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum syn 0.13.11 (registry+https://github.com/rust-lang/crates.io-index)" = "14f9bf6292f3a61d2c716723fdb789a41bbe104168e6f496dc6497e531ea1b9b" -"checksum syn 0.15.21 (registry+https://github.com/rust-lang/crates.io-index)" = "816b7af21405b011a23554ea2dc3f6576dc86ca557047c34098c1d741f10f823" +"checksum syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)" = "ae8b29eb5210bc5cf63ed6149cbf9adfc82ac0be023d8735c176ee74a2db4da7" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" "checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015" +"checksum syslog 4.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a0641142b4081d3d44beffa4eefd7346a228cdf91ed70186db2ca2cef762d327" "checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" -"checksum tempfile 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "55c1195ef8513f3273d55ff59fe5da6940287a0d7a98331254397f464833675b" +"checksum tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7e91405c14320e5c79b3d148e1c86f40749a36e490642202a31689cb1a3452b2" "checksum thread-id 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c7fbf4c9d56b320106cd64fd024dadfa0be7cb4706725fc44a7d7ce952d820c1" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865" "checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" "checksum tiny_http 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a442681f9f72e440be192700eeb2861e4174b9983f16f4877c93a134cb5e5f63" -"checksum tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "6e93c78d23cc61aa245a8acd2c4a79c4d7fa7fb5c3ca90d5737029f043a84895" +"checksum tokio 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "a7817d4c98cc5be21360b3b37d6036fe9b7aefa5b7a201b7b16ff33423822f7d" "checksum tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c501eceaf96f0e1793cf26beb63da3d11c738c4a943fdf3746d81d64684c39f" -"checksum tokio-current-thread 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f90fcd90952f0a496d438a976afba8e5c205fb12123f813d8ab3aa1c8436638c" +"checksum tokio-current-thread 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "331c8acc267855ec06eb0c94618dcbbfea45bed2d20b77252940095273fb58f6" "checksum tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c117b6cf86bb730aab4834f10df96e4dd586eff2c3c27d3781348da49e255bde" "checksum tokio-fs 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "60ae25f6b17d25116d2cba342083abe5255d3c2c79cb21ea11aa049c53bf7c75" "checksum tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "7392fe0a70d5ce0c882c4778116c519bd5dbaa8a7c3ae3d04578b3afafdcda21" -"checksum tokio-reactor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4b26fd37f1125738b2170c80b551f69ff6fecb277e6e5ca885e53eec2b005018" +"checksum tokio-reactor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "502b625acb4ee13cbb3b90b8ca80e0addd263ddacf6931666ef751e610b07fb5" "checksum tokio-tcp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7ad235e9dadd126b2d47f6736f65aa1fdcd6420e66ca63f44177bc78df89f912" -"checksum tokio-threadpool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3929aee321c9220ed838ed6c3928be7f9b69986b0e3c22c972a66dbf8a298c68" -"checksum tokio-timer 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3a52f00c97fedb6d535d27f65cccb7181c8dd4c6edc3eda9ea93f6d45d05168e" -"checksum tokio-udp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "da941144b816d0dcda4db3a1ba87596e4df5e860a72b70783fe435891f80601c" -"checksum tokio-uds 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "df195376b43508f01570bacc73e13a1de0854dc59e79d1ec09913e8db6dd2a70" -"checksum toml 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "4a2ecc31b0351ea18b3fe11274b8db6e4d82bce861bbb22e6dbed40417902c65" +"checksum tokio-threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "56c5556262383032878afad66943926a1d1f0967f17e94bd7764ceceb3b70e7f" +"checksum tokio-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "4f37f0111d76cc5da132fe9bc0590b9b9cfd079bc7e75ac3846278430a299ff8" +"checksum tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "66268575b80f4a4a710ef83d087fdfeeabdce9b74c797535fbac18a2cb906e92" +"checksum tokio-uds 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "99ce87382f6c1a24b513a72c048b2c8efe66cb5161c9061d00bee510f08dc168" +"checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" "checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" "checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" "checksum twoway 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "59b11b2b5241ba34be09c3cc85a36e56e48f9888862e19cedf23336d35316ed1" "checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" "checksum typemap 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "653be63c80a3296da5551e1bfd2cca35227e13cdd08c6668903ae2f4f77aa1f6" "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" -"checksum u2f 0.1.2 (git+https://github.com/wisespace-io/u2f-rs?rev=193de35093a44)" = "<none>" +"checksum u2f 0.1.2 (git+https://github.com/wisespace-io/u2f-rs?rev=75b9fa5afb4c5)" = "<none>" "checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" "checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" "checksum unicase 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d3218ea14b4edcaccfa0df0a64a3792a2c32cc706f1b336e48867f9d3147f90" @@ -2679,24 +2734,26 @@ dependencies = [ "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" "checksum unsafe-any 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f30360d7979f5e9c6e6cea48af192ea8fab4afb3cf72597154b8f08935bc9c7f" -"checksum untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f392d7819dbe58833e26872f5f6f0d68b7bbbe90fc3667e98731c4a15ad9a7ae" +"checksum untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "55cd1f4b4e96b46aeb8d4855db4a7a9bd96eeeb5c6a1ab54593328761642ce2f" "checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" "checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737" "checksum uuid 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dab5c5526c5caa3d106653401a267fed923e7046f35895ffcb5ca42db64942e6" "checksum vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "def296d3eb3b12371b2c7d0e83bfe1403e4db2d7a0bba324a12b21c4ee13143d" "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +"checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1" "checksum want 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "797464475f30ddb8830cc529aaaae648d581f99e2036a928877dfde027ddf6b3" -"checksum webpki 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e499345fc4c6b7c79a5b8756d4592c4305510a13512e79efafe00dfbd67bbac6" -"checksum webpki 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "493012e46177f3f4ee9cd58fd0c81ecb77e6d6cc6ebce55989b9c33376fbe5ee" -"checksum webpki-roots 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5bfb3f50499f21ad2317f442845e3b5805b007f1e728f59885c99e61b8c181a7" +"checksum webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)" = "17d7967316d8411ca3b01821ee6c332bde138ba4363becdb492f12e514daa17f" +"checksum webpki-roots 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "85d1f408918fd590908a70d36b7ac388db2edc221470333e4d6e5b598e44cabf" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "afc5508759c5bf4285e61feb862b6083c8480aec864fa17a81fdec6f69b461ab" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum winutil 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7daf138b6b14196e3830a588acf1e86966c694d3e8fb026fb105b8b5dca07e6e" "checksum ws 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)" = "329d3e6dd450a9c5c73024e1047f0be7e24121a68484eb0b5368977bee3cf8c3" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" "checksum yansi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d60c3b48c9cdec42fb06b3b84b5b087405e1fa1c644a1af3930e4dfafe93de48" +"checksum yansi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9fc79f4a1e39857fc00c3f662cbf2651c771f00e9c15fe2abc341806bd46bd71" "checksum yubico 0.4.0 (git+https://github.com/dani-garcia/yubico-rs)" = "<none>" diff --git a/Cargo.toml b/Cargo.toml @@ -2,21 +2,24 @@ name = "bitwarden_rs" version = "1.0.0" authors = ["Daniel García <dani-garcia@users.noreply.github.com>"] +edition = "2018" + +[features] +enable_syslog = ["syslog", "fern/syslog-4"] [dependencies] # Web framework for nightly with a focus on ease-of-use, expressibility, and speed. -rocket = { version = "0.3.17", features = ["tls"] } -rocket_codegen = "0.3.17" -rocket_contrib = "0.3.17" +rocket = { version = "0.4.0", features = ["tls"], default-features = false } +rocket_contrib = "0.4.0" # HTTP client -reqwest = "0.9.2" +reqwest = "0.9.5" # multipart/form-data support -multipart = "0.15.3" +multipart = "0.15.4" # WebSockets library -ws = "0.7.8" +ws = "0.7.9" # MessagePack library rmpv = "0.4.0" @@ -25,9 +28,14 @@ rmpv = "0.4.0" chashmap = "2.2.0" # A generic serialization/deserialization framework -serde = "1.0.79" -serde_derive = "1.0.79" -serde_json = "1.0.31" +serde = "1.0.82" +serde_derive = "1.0.82" +serde_json = "1.0.33" + +# Logging +log = "0.4.6" +fern = "0.5.7" +syslog = { version = "4.0.1", optional = true } # A safe, extensible ORM and Query builder diesel = { version = "1.3.3", features = ["sqlite", "chrono", "r2d2"] } @@ -37,7 +45,7 @@ diesel_migrations = { version = "1.3.0", features = ["sqlite"] } libsqlite3-sys = { version = "0.9.3", features = ["bundled"] } # Crypto library -ring = { version = "= 0.11.0", features = ["rsa_signing"] } +ring = { version = "0.13.5", features = ["rsa_signing"] } # UUID generation uuid = { version = "0.7.1", features = ["v4"] } @@ -52,7 +60,7 @@ oath = "0.10.2" data-encoding = "2.1.1" # JWT library -jsonwebtoken = "= 4.0.1" +jsonwebtoken = "5.0.1" # U2F library u2f = "0.1.2" @@ -64,7 +72,7 @@ yubico = { version = "=0.4.0", features = ["online"], default-features = false } dotenv = { version = "0.13.0", default-features = false } # Lazy static macro -lazy_static = "1.1.0" +lazy_static = { version = "1.2.0", features = ["nightly"] } # Numerical libraries num-traits = "0.2.6" @@ -73,20 +81,21 @@ num-derive = "0.2.3" # Email libraries lettre = "0.9.0" lettre_email = "0.9.0" -native-tls = "0.2.1" +native-tls = "0.2.2" # Number encoding library -byteorder = "1.2.6" +byteorder = "1.2.7" [patch.crates-io] - # Make jwt use ring 0.11, to match rocket -jsonwebtoken = { path = "libs/jsonwebtoken" } +# Add support for Timestamp type rmp = { git = 'https://github.com/dani-garcia/msgpack-rust' } + +# Use new native_tls version 0.2 lettre = { git = 'https://github.com/lettre/lettre', rev = 'c988b1760ad81' } lettre_email = { git = 'https://github.com/lettre/lettre', rev = 'c988b1760ad81' } # Version 0.1.2 from crates.io lacks a commit that fixes a certificate error -u2f = { git = 'https://github.com/wisespace-io/u2f-rs', rev = '193de35093a44' } +u2f = { git = 'https://github.com/wisespace-io/u2f-rs', rev = '75b9fa5afb4c5' } # Allows optional libusb support yubico = { git = 'https://github.com/dani-garcia/yubico-rs' } diff --git a/Dockerfile b/Dockerfile @@ -2,9 +2,9 @@ # https://docs.docker.com/develop/develop-images/multistage-build/ # https://whitfin.io/speeding-up-rust-docker-builds/ ####################### VAULT BUILD IMAGE ####################### -FROM node:8-alpine as vault +FROM node:10-alpine as vault -ENV VAULT_VERSION "v2.5.0" +ENV VAULT_VERSION "v2.6.1" ENV URL "https://github.com/bitwarden/web.git" @@ -41,7 +41,6 @@ WORKDIR /app # Copies over *only* your manifests and vendored dependencies COPY ./Cargo.* ./ -COPY ./libs ./libs COPY ./rust-toolchain ./rust-toolchain # Builds your dependencies and removes the @@ -54,6 +53,9 @@ RUN find . -not -path "./target*" -delete # To avoid copying unneeded files, use .dockerignore COPY . . +# Make sure that we actually build the project +RUN touch src/main.rs + # Builds again, this time it'll just be # your actual source files being built RUN cargo build --release @@ -64,6 +66,7 @@ RUN cargo build --release FROM debian:stretch-slim ENV ROCKET_ENV "staging" +ENV ROCKET_PORT=80 ENV ROCKET_WORKERS=10 # Install needed libraries diff --git a/Dockerfile.aarch64 b/Dockerfile.aarch64 @@ -2,9 +2,9 @@ # https://docs.docker.com/develop/develop-images/multistage-build/ # https://whitfin.io/speeding-up-rust-docker-builds/ ####################### VAULT BUILD IMAGE ####################### -FROM node:8-alpine as vault +FROM node:10-alpine as vault -ENV VAULT_VERSION "v2.5.0" +ENV VAULT_VERSION "v2.6.1" ENV URL "https://github.com/bitwarden/web.git" @@ -69,6 +69,7 @@ RUN cargo build --release --target=aarch64-unknown-linux-gnu -v FROM balenalib/aarch64-debian:stretch ENV ROCKET_ENV "staging" +ENV ROCKET_PORT=80 ENV ROCKET_WORKERS=10 RUN [ "cross-build-start" ] @@ -95,4 +96,4 @@ COPY --from=vault /web-vault ./web-vault COPY --from=build /app/target/aarch64-unknown-linux-gnu/release/bitwarden_rs . # Configures the startup! -CMD ./bitwarden_rs -\ No newline at end of file +CMD ./bitwarden_rs diff --git a/Dockerfile.alpine b/Dockerfile.alpine @@ -2,9 +2,9 @@ # https://docs.docker.com/develop/develop-images/multistage-build/ # https://whitfin.io/speeding-up-rust-docker-builds/ ####################### VAULT BUILD IMAGE ####################### -FROM node:8-alpine as vault +FROM node:10-alpine as vault -ENV VAULT_VERSION "v2.5.0" +ENV VAULT_VERSION "v2.6.1" ENV URL "https://github.com/bitwarden/web.git" @@ -26,7 +26,7 @@ RUN npm run dist \ ########################## BUILD IMAGE ########################## # Musl build image for statically compiled binary -FROM clux/muslrust:nightly-2018-10-03 as build +FROM clux/muslrust:nightly-2018-11-30 as build ENV USER "root" @@ -45,6 +45,7 @@ RUN cargo build --release FROM alpine:3.8 ENV ROCKET_ENV "staging" +ENV ROCKET_PORT=80 ENV ROCKET_WORKERS=10 ENV SSL_CERT_DIR=/etc/ssl/certs diff --git a/Dockerfile.armv7 b/Dockerfile.armv7 @@ -2,9 +2,9 @@ # https://docs.docker.com/develop/develop-images/multistage-build/ # https://whitfin.io/speeding-up-rust-docker-builds/ ####################### VAULT BUILD IMAGE ####################### -FROM node:8-alpine as vault +FROM node:10-alpine as vault -ENV VAULT_VERSION "v2.5.0" +ENV VAULT_VERSION "v2.6.1" ENV URL "https://github.com/bitwarden/web.git" @@ -69,6 +69,7 @@ RUN cargo build --release --target=armv7-unknown-linux-gnueabihf -v FROM balenalib/armv7hf-debian:stretch ENV ROCKET_ENV "staging" +ENV ROCKET_PORT=80 ENV ROCKET_WORKERS=10 RUN [ "cross-build-start" ] diff --git a/libs/jsonwebtoken/Cargo.toml b/libs/jsonwebtoken/Cargo.toml @@ -1,20 +0,0 @@ -[package] -name = "jsonwebtoken" -version = "4.0.1" -authors = ["Vincent Prouillet <prouillet.vincent@gmail.com>"] -license = "MIT" -readme = "README.md" -description = "Create and parse JWT in a strongly typed way." -homepage = "https://github.com/Keats/rust-jwt" -repository = "https://github.com/Keats/rust-jwt" -keywords = ["jwt", "web", "api", "token", "json"] - -[dependencies] -error-chain = { version = "0.11", default-features = false } -serde_json = "1.0" -serde_derive = "1.0" -serde = "1.0" -ring = { version = "0.11.0", features = ["rsa_signing", "dev_urandom_fallback"] } -base64 = "0.9" -untrusted = "0.5" -chrono = "0.4" diff --git a/libs/jsonwebtoken/LICENSE b/libs/jsonwebtoken/LICENSE @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Vincent Prouillet - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/libs/jsonwebtoken/src/crypto.rs b/libs/jsonwebtoken/src/crypto.rs @@ -1,120 +0,0 @@ -use std::sync::Arc; - -use base64; -use ring::{rand, digest, hmac, signature}; -use ring::constant_time::verify_slices_are_equal; -use untrusted; - -use errors::{Result, ErrorKind}; - - -/// The algorithms supported for signing/verifying -#[derive(Debug, PartialEq, Copy, Clone, Serialize, Deserialize)] -pub enum Algorithm { - /// HMAC using SHA-256 - HS256, - /// HMAC using SHA-384 - HS384, - /// HMAC using SHA-512 - HS512, - - /// RSASSA-PKCS1-v1_5 using SHA-256 - RS256, - /// RSASSA-PKCS1-v1_5 using SHA-384 - RS384, - /// RSASSA-PKCS1-v1_5 using SHA-512 - RS512, -} - -/// The actual HS signing + encoding -fn sign_hmac(alg: &'static digest::Algorithm, key: &[u8], signing_input: &str) -> Result<String> { - let signing_key = hmac::SigningKey::new(alg, key); - let digest = hmac::sign(&signing_key, signing_input.as_bytes()); - - Ok( - base64::encode_config::<hmac::Signature>(&digest, base64::URL_SAFE_NO_PAD) - ) -} - -/// The actual RSA signing + encoding -/// Taken from Ring doc https://briansmith.org/rustdoc/ring/signature/index.html -fn sign_rsa(alg: Algorithm, key: &[u8], signing_input: &str) -> Result<String> { - let ring_alg = match alg { - Algorithm::RS256 => &signature::RSA_PKCS1_SHA256, - Algorithm::RS384 => &signature::RSA_PKCS1_SHA384, - Algorithm::RS512 => &signature::RSA_PKCS1_SHA512, - _ => unreachable!(), - }; - - let key_pair = Arc::new( - signature::RSAKeyPair::from_der(untrusted::Input::from(key)) - .map_err(|_| ErrorKind::InvalidKey)? - ); - let mut signing_state = signature::RSASigningState::new(key_pair) - .map_err(|_| ErrorKind::InvalidKey)?; - let mut signature = vec![0; signing_state.key_pair().public_modulus_len()]; - let rng = rand::SystemRandom::new(); - signing_state.sign(ring_alg, &rng, signing_input.as_bytes(), &mut signature) - .map_err(|_| ErrorKind::InvalidKey)?; - - Ok( - base64::encode_config::<[u8]>(&signature, base64::URL_SAFE_NO_PAD) - ) -} - -/// Take the payload of a JWT, sign it using the algorithm given and return -/// the base64 url safe encoded of the result. -/// -/// Only use this function if you want to do something other than JWT. -pub fn sign(signing_input: &str, key: &[u8], algorithm: Algorithm) -> Result<String> { - match algorithm { - Algorithm::HS256 => sign_hmac(&digest::SHA256, key, signing_input), - Algorithm::HS384 => sign_hmac(&digest::SHA384, key, signing_input), - Algorithm::HS512 => sign_hmac(&digest::SHA512, key, signing_input), - - Algorithm::RS256 | Algorithm::RS384 | Algorithm::RS512 => sign_rsa(algorithm, key, signing_input), -// TODO: if PKCS1 is made prublic, remove the line above and uncomment below -// Algorithm::RS256 => sign_rsa(&signature::RSA_PKCS1_SHA256, key, signing_input), -// Algorithm::RS384 => sign_rsa(&signature::RSA_PKCS1_SHA384, key, signing_input), -// Algorithm::RS512 => sign_rsa(&signature::RSA_PKCS1_SHA512, key, signing_input), - } -} - -/// See Ring RSA docs for more details -fn verify_rsa(alg: &signature::RSAParameters, signature: &str, signing_input: &str, key: &[u8]) -> Result<bool> { - let signature_bytes = base64::decode_config(signature, base64::URL_SAFE_NO_PAD)?; - let public_key_der = untrusted::Input::from(key); - let message = untrusted::Input::from(signing_input.as_bytes()); - let expected_signature = untrusted::Input::from(signature_bytes.as_slice()); - - let res = signature::verify(alg, public_key_der, message, expected_signature); - - Ok(res.is_ok()) -} - -/// Compares the signature given with a re-computed signature for HMAC or using the public key -/// for RSA. -/// -/// Only use this function if you want to do something other than JWT. -/// -/// `signature` is the signature part of a jwt (text after the second '.') -/// -/// `signing_input` is base64(header) + "." + base64(claims) -pub fn verify(signature: &str, signing_input: &str, key: &[u8], algorithm: Algorithm) -> Result<bool> { - match algorithm { - Algorithm::HS256 | Algorithm::HS384 | Algorithm::HS512 => { - // we just re-sign the data with the key and compare if they are equal - let signed = sign(signing_input, key, algorithm)?; - Ok(verify_slices_are_equal(signature.as_ref(), signed.as_ref()).is_ok()) - }, - Algorithm::RS256 => verify_rsa(&signature::RSA_PKCS1_2048_8192_SHA256, signature, signing_input, key), - Algorithm::RS384 => verify_rsa(&signature::RSA_PKCS1_2048_8192_SHA384, signature, signing_input, key), - Algorithm::RS512 => verify_rsa(&signature::RSA_PKCS1_2048_8192_SHA512, signature, signing_input, key), - } -} - -impl Default for Algorithm { - fn default() -> Self { - Algorithm::HS256 - } -} diff --git a/libs/jsonwebtoken/src/errors.rs b/libs/jsonwebtoken/src/errors.rs @@ -1,68 +0,0 @@ -use base64; -use serde_json; -use ring; - -error_chain! { - errors { - /// When a token doesn't have a valid JWT shape - InvalidToken { - description("invalid token") - display("Invalid token") - } - /// When the signature doesn't match - InvalidSignature { - description("invalid signature") - display("Invalid signature") - } - /// When the secret given is not a valid RSA key - InvalidKey { - description("invalid key") - display("Invalid Key") - } - - // Validation error - - /// When a token’s `exp` claim indicates that it has expired - ExpiredSignature { - description("expired signature") - display("Expired Signature") - } - /// When a token’s `iss` claim does not match the expected issuer - InvalidIssuer { - description("invalid issuer") - display("Invalid Issuer") - } - /// When a token’s `aud` claim does not match one of the expected audience values - InvalidAudience { - description("invalid audience") - display("Invalid Audience") - } - /// When a token’s `aud` claim does not match one of the expected audience values - InvalidSubject { - description("invalid subject") - display("Invalid Subject") - } - /// When a token’s `iat` claim is in the future - InvalidIssuedAt { - description("invalid issued at") - display("Invalid Issued At") - } - /// When a token’s nbf claim represents a time in the future - ImmatureSignature { - description("immature signature") - display("Immature Signature") - } - /// When the algorithm in the header doesn't match the one passed to `decode` - InvalidAlgorithm { - description("Invalid algorithm") - display("Invalid Algorithm") - } - } - - foreign_links { - Unspecified(ring::error::Unspecified) #[doc = "An error happened while signing/verifying a token with RSA"]; - Base64(base64::DecodeError) #[doc = "An error happened while decoding some base64 text"]; - Json(serde_json::Error) #[doc = "An error happened while serializing/deserializing JSON"]; - Utf8(::std::string::FromUtf8Error) #[doc = "An error happened while trying to convert the result of base64 decoding to a String"]; - } -} diff --git a/libs/jsonwebtoken/src/header.rs b/libs/jsonwebtoken/src/header.rs @@ -1,64 +0,0 @@ -use crypto::Algorithm; - - -/// A basic JWT header, the alg defaults to HS256 and typ is automatically -/// set to `JWT`. All the other fields are optional. -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct Header { - /// The type of JWS: it can only be "JWT" here - /// - /// Defined in [RFC7515#4.1.9](https://tools.ietf.org/html/rfc7515#section-4.1.9). - #[serde(skip_serializing_if = "Option::is_none")] - pub typ: Option<String>, - /// The algorithm used - /// - /// Defined in [RFC7515#4.1.1](https://tools.ietf.org/html/rfc7515#section-4.1.1). - pub alg: Algorithm, - /// Content type - /// - /// Defined in [RFC7519#5.2](https://tools.ietf.org/html/rfc7519#section-5.2). - #[serde(skip_serializing_if = "Option::is_none")] - pub cty: Option<String>, - /// JSON Key URL - /// - /// Defined in [RFC7515#4.1.2](https://tools.ietf.org/html/rfc7515#section-4.1.2). - #[serde(skip_serializing_if = "Option::is_none")] - pub jku: Option<String>, - /// Key ID - /// - /// Defined in [RFC7515#4.1.4](https://tools.ietf.org/html/rfc7515#section-4.1.4). - #[serde(skip_serializing_if = "Option::is_none")] - pub kid: Option<String>, - /// X.509 URL - /// - /// Defined in [RFC7515#4.1.5](https://tools.ietf.org/html/rfc7515#section-4.1.5). - #[serde(skip_serializing_if = "Option::is_none")] - pub x5u: Option<String>, - /// X.509 certificate thumbprint - /// - /// Defined in [RFC7515#4.1.7](https://tools.ietf.org/html/rfc7515#section-4.1.7). - #[serde(skip_serializing_if = "Option::is_none")] - pub x5t: Option<String>, -} - -impl Header { - /// Returns a JWT header with the algorithm given - pub fn new(algorithm: Algorithm) -> Header { - Header { - typ: Some("JWT".to_string()), - alg: algorithm, - cty: None, - jku: None, - kid: None, - x5u: None, - x5t: None, - } - } -} - -impl Default for Header { - /// Returns a JWT header using the default Algorithm, HS256 - fn default() -> Self { - Header::new(Algorithm::default()) - } -} diff --git a/libs/jsonwebtoken/src/lib.rs b/libs/jsonwebtoken/src/lib.rs @@ -1,142 +0,0 @@ -//! Create and parses JWT (JSON Web Tokens) -//! -//! Documentation: [stable](https://docs.rs/jsonwebtoken/) -#![recursion_limit = "300"] -#![deny(missing_docs)] -#![allow(unused_doc_comments)] -#![allow(renamed_and_removed_lints)] - -#[macro_use] -extern crate error_chain; -#[macro_use] -extern crate serde_derive; -extern crate serde_json; -extern crate serde; -extern crate base64; -extern crate ring; -extern crate untrusted; -extern crate chrono; - -/// All the errors, generated using error-chain -pub mod errors; -mod header; -mod crypto; -mod serialization; -mod validation; - -pub use header::Header; -pub use crypto::{ - Algorithm, - sign, - verify, -}; -pub use validation::Validation; -pub use serialization::TokenData; - - -use serde::de::DeserializeOwned; -use serde::ser::Serialize; - -use errors::{Result, ErrorKind}; -use serialization::{from_jwt_part, from_jwt_part_claims, to_jwt_part}; -use validation::{validate}; - - -/// Encode the header and claims given and sign the payload using the algorithm from the header and the key -/// -/// ```rust,ignore -/// #[macro_use] -/// extern crate serde_derive; -/// use jsonwebtoken::{encode, Algorithm, Header}; -/// -/// /// #[derive(Debug, Serialize, Deserialize)] -/// struct Claims { -/// sub: String, -/// company: String -/// } -/// -/// let my_claims = Claims { -/// sub: "b@b.com".to_owned(), -/// company: "ACME".to_owned() -/// }; -/// -/// // my_claims is a struct that implements Serialize -/// // This will create a JWT using HS256 as algorithm -/// let token = encode(&Header::default(), &my_claims, "secret".as_ref()).unwrap(); -/// ``` -pub fn encode<T: Serialize>(header: &Header, claims: &T, key: &[u8]) -> Result<String> { - let encoded_header = to_jwt_part(&header)?; - let encoded_claims = to_jwt_part(&claims)?; - let signing_input = [encoded_header.as_ref(), encoded_claims.as_ref()].join("."); - let signature = sign(&*signing_input, key.as_ref(), header.alg)?; - - Ok([signing_input, signature].join(".")) -} - -/// Used in decode: takes the result of a rsplit and ensure we only get 2 parts -/// Errors if we don't -macro_rules! expect_two { - ($iter:expr) => {{ - let mut i = $iter; - match (i.next(), i.next(), i.next()) { - (Some(first), Some(second), None) => (first, second), - _ => return Err(ErrorKind::InvalidToken.into()) - } - }} -} - -/// Decode a token into a struct containing 2 fields: `claims` and `header`. -/// -/// If the token or its signature is invalid or the claims fail validation, it will return an error. -/// -/// ```rust,ignore -/// #[macro_use] -/// extern crate serde_derive; -/// use jsonwebtoken::{decode, Validation, Algorithm}; -/// -/// #[derive(Debug, Serialize, Deserialize)] -/// struct Claims { -/// sub: String, -/// company: String -/// } -/// -/// let token = "a.jwt.token".to_string(); -/// // Claims is a struct that implements Deserialize -/// let token_data = decode::<Claims>(&token, "secret", &Validation::new(Algorithm::HS256)); -/// ``` -pub fn decode<T: DeserializeOwned>(token: &str, key: &[u8], validation: &Validation) -> Result<TokenData<T>> { - let (signature, signing_input) = expect_two!(token.rsplitn(2, '.')); - let (claims, header) = expect_two!(signing_input.rsplitn(2, '.')); - let header: Header = from_jwt_part(header)?; - - if !verify(signature, signing_input, key, header.alg)? { - return Err(ErrorKind::InvalidSignature.into()); - } - - if !validation.algorithms.contains(&header.alg) { - return Err(ErrorKind::InvalidAlgorithm.into()); - } - - let (decoded_claims, claims_map): (T, _) = from_jwt_part_claims(claims)?; - - validate(&claims_map, validation)?; - - Ok(TokenData { header: header, claims: decoded_claims }) -} - -/// Decode a token and return the Header. This is not doing any kind of validation: it is meant to be -/// used when you don't know which `alg` the token is using and want to find out. -/// -/// If the token has an invalid format, it will return an error. -/// -/// ```rust,ignore -/// use jsonwebtoken::decode_header; -/// -/// let token = "a.jwt.token".to_string(); -/// let header = decode_header(&token); -/// ``` -pub fn decode_header(token: &str) -> Result<Header> { - let (_, signing_input) = expect_two!(token.rsplitn(2, '.')); - let (_, header) = expect_two!(signing_input.rsplitn(2, '.')); - from_jwt_part(header) -} diff --git a/libs/jsonwebtoken/src/serialization.rs b/libs/jsonwebtoken/src/serialization.rs @@ -1,42 +0,0 @@ -use base64; -use serde::de::DeserializeOwned; -use serde::ser::Serialize; -use serde_json::{from_str, to_string, Value}; -use serde_json::map::Map; - -use errors::{Result}; -use header::Header; - - -/// The return type of a successful call to decode -#[derive(Debug)] -pub struct TokenData<T> { - /// The decoded JWT header - pub header: Header, - /// The decoded JWT claims - pub claims: T -} - -/// Serializes to JSON and encodes to base64 -pub fn to_jwt_part<T: Serialize>(input: &T) -> Result<String> { - let encoded = to_string(input)?; - Ok(base64::encode_config(encoded.as_bytes(), base64::URL_SAFE_NO_PAD)) -} - -/// Decodes from base64 and deserializes from JSON to a struct -pub fn from_jwt_part<B: AsRef<str>, T: DeserializeOwned>(encoded: B) -> Result<T> { - let decoded = base64::decode_config(encoded.as_ref(), base64::URL_SAFE_NO_PAD)?; - let s = String::from_utf8(decoded)?; - - Ok(from_str(&s)?) -} - -/// Decodes from base64 and deserializes from JSON to a struct AND a hashmap -pub fn from_jwt_part_claims<B: AsRef<str>, T: DeserializeOwned>(encoded: B) -> Result<(T, Map<String, Value>)> { - let decoded = base64::decode_config(encoded.as_ref(), base64::URL_SAFE_NO_PAD)?; - let s = String::from_utf8(decoded)?; - - let claims: T = from_str(&s)?; - let map: Map<_,_> = from_str(&s)?; - Ok((claims, map)) -} diff --git a/libs/jsonwebtoken/src/validation.rs b/libs/jsonwebtoken/src/validation.rs @@ -1,377 +0,0 @@ -use chrono::Utc; -use serde::ser::Serialize; -use serde_json::{Value, from_value, to_value}; -use serde_json::map::Map; - -use errors::{Result, ErrorKind}; -use crypto::Algorithm; - - -/// Contains the various validations that are applied after decoding a token. -/// -/// All time validation happen on UTC timestamps. -/// -/// ```rust -/// use jsonwebtoken::Validation; -/// -/// // Default value -/// let validation = Validation::default(); -/// -/// // Changing one parameter -/// let mut validation = Validation {leeway: 60, ..Default::default()}; -/// -/// // Setting audience -/// let mut validation = Validation::default(); -/// validation.set_audience(&"Me"); // string -/// validation.set_audience(&["Me", "You"]); // array of strings -/// ``` -#[derive(Debug, Clone, PartialEq)] -pub struct Validation { - /// Add some leeway (in seconds) to the `exp`, `iat` and `nbf` validation to - /// account for clock skew. - /// - /// Defaults to `0`. - pub leeway: i64, - /// Whether to validate the `exp` field. - /// - /// It will return an error if the time in the `exp` field is past. - /// - /// Defaults to `true`. - pub validate_exp: bool, - /// Whether to validate the `iat` field. - /// - /// It will return an error if the time in the `iat` field is in the future. - /// - /// Defaults to `true`. - pub validate_iat: bool, - /// Whether to validate the `nbf` field. - /// - /// It will return an error if the current timestamp is before the time in the `nbf` field. - /// - /// Defaults to `true`. - pub validate_nbf: bool, - /// If it contains a value, the validation will check that the `aud` field is the same as the - /// one provided and will error otherwise. - /// Since `aud` can be either a String or a Vec<String> in the JWT spec, you will need to use - /// the [set_audience](struct.Validation.html#method.set_audience) method to set it. - /// - /// Defaults to `None`. - pub aud: Option<Value>, - /// If it contains a value, the validation will check that the `iss` field is the same as the - /// one provided and will error otherwise. - /// - /// Defaults to `None`. - pub iss: Option<String>, - /// If it contains a value, the validation will check that the `sub` field is the same as the - /// one provided and will error otherwise. - /// - /// Defaults to `None`. - pub sub: Option<String>, - /// If it contains a value, the validation will check that the `alg` of the header is contained - /// in the ones provided and will error otherwise. - /// - /// Defaults to `vec![Algorithm::HS256]`. - pub algorithms: Vec<Algorithm>, -} - -impl Validation { - /// Create a default validation setup allowing the given alg - pub fn new(alg: Algorithm) -> Validation { - let mut validation = Validation::default(); - validation.algorithms = vec![alg]; - validation - } - - /// Since `aud` can be either a String or an array of String in the JWT spec, this method will take - /// care of serializing the value. - pub fn set_audience<T: Serialize>(&mut self, audience: &T) { - self.aud = Some(to_value(audience).unwrap()); - } -} - -impl Default for Validation { - fn default() -> Validation { - Validation { - leeway: 0, - - validate_exp: true, - validate_iat: true, - validate_nbf: true, - - iss: None, - sub: None, - aud: None, - - algorithms: vec![Algorithm::HS256], - } - } -} - - - -pub fn validate(claims: &Map<String, Value>, options: &Validation) -> Result<()> { - let now = Utc::now().timestamp(); - - if let Some(iat) = claims.get("iat") { - if options.validate_iat && from_value::<i64>(iat.clone())? > now + options.leeway { - return Err(ErrorKind::InvalidIssuedAt.into()); - } - } - - if let Some(exp) = claims.get("exp") { - if options.validate_exp && from_value::<i64>(exp.clone())? < now - options.leeway { - return Err(ErrorKind::ExpiredSignature.into()); - } - } - - if let Some(nbf) = claims.get("nbf") { - if options.validate_nbf && from_value::<i64>(nbf.clone())? > now + options.leeway { - return Err(ErrorKind::ImmatureSignature.into()); - } - } - - if let Some(iss) = claims.get("iss") { - if let Some(ref correct_iss) = options.iss { - if from_value::<String>(iss.clone())? != *correct_iss { - return Err(ErrorKind::InvalidIssuer.into()); - } - } - } - - if let Some(sub) = claims.get("sub") { - if let Some(ref correct_sub) = options.sub { - if from_value::<String>(sub.clone())? != *correct_sub { - return Err(ErrorKind::InvalidSubject.into()); - } - } - } - - if let Some(aud) = claims.get("aud") { - if let Some(ref correct_aud) = options.aud { - if aud != correct_aud { - return Err(ErrorKind::InvalidAudience.into()); - } - } - } - - Ok(()) -} - - -#[cfg(test)] -mod tests { - use serde_json::{to_value}; - use serde_json::map::Map; - use chrono::Utc; - - use super::{validate, Validation}; - - use errors::ErrorKind; - - #[test] - fn iat_in_past_ok() { - let mut claims = Map::new(); - claims.insert("iat".to_string(), to_value(Utc::now().timestamp() - 10000).unwrap()); - let res = validate(&claims, &Validation::default()); - assert!(res.is_ok()); - } - - #[test] - fn iat_in_future_fails() { - let mut claims = Map::new(); - claims.insert("iat".to_string(), to_value(Utc::now().timestamp() + 100000).unwrap()); - let res = validate(&claims, &Validation::default()); - assert!(res.is_err()); - - match res.unwrap_err().kind() { - &ErrorKind::InvalidIssuedAt => (), - _ => assert!(false), - }; - } - - #[test] - fn iat_in_future_but_in_leeway_ok() { - let mut claims = Map::new(); - claims.insert("iat".to_string(), to_value(Utc::now().timestamp() + 50).unwrap()); - let validation = Validation { - leeway: 1000 * 60, - ..Default::default() - }; - let res = validate(&claims, &validation); - assert!(res.is_ok()); - } - - #[test] - fn exp_in_future_ok() { - let mut claims = Map::new(); - claims.insert("exp".to_string(), to_value(Utc::now().timestamp() + 10000).unwrap()); - let res = validate(&claims, &Validation::default()); - assert!(res.is_ok()); - } - - #[test] - fn exp_in_past_fails() { - let mut claims = Map::new(); - claims.insert("exp".to_string(), to_value(Utc::now().timestamp() - 100000).unwrap()); - let res = validate(&claims, &Validation::default()); - assert!(res.is_err()); - - match res.unwrap_err().kind() { - &ErrorKind::ExpiredSignature => (), - _ => assert!(false), - }; - } - - #[test] - fn exp_in_past_but_in_leeway_ok() { - let mut claims = Map::new(); - claims.insert("exp".to_string(), to_value(Utc::now().timestamp() - 500).unwrap()); - let validation = Validation { - leeway: 1000 * 60, - ..Default::default() - }; - let res = validate(&claims, &validation); - assert!(res.is_ok()); - } - - #[test] - fn nbf_in_past_ok() { - let mut claims = Map::new(); - claims.insert("nbf".to_string(), to_value(Utc::now().timestamp() - 10000).unwrap()); - let res = validate(&claims, &Validation::default()); - assert!(res.is_ok()); - } - - #[test] - fn nbf_in_future_fails() { - let mut claims = Map::new(); - claims.insert("nbf".to_string(), to_value(Utc::now().timestamp() + 100000).unwrap()); - let res = validate(&claims, &Validation::default()); - assert!(res.is_err()); - - match res.unwrap_err().kind() { - &ErrorKind::ImmatureSignature => (), - _ => assert!(false), - }; - } - - #[test] - fn nbf_in_future_but_in_leeway_ok() { - let mut claims = Map::new(); - claims.insert("nbf".to_string(), to_value(Utc::now().timestamp() + 500).unwrap()); - let validation = Validation { - leeway: 1000 * 60, - ..Default::default() - }; - let res = validate(&claims, &validation); - assert!(res.is_ok()); - } - - #[test] - fn iss_ok() { - let mut claims = Map::new(); - claims.insert("iss".to_string(), to_value("Keats").unwrap()); - let validation = Validation { - iss: Some("Keats".to_string()), - ..Default::default() - }; - let res = validate(&claims, &validation); - assert!(res.is_ok()); - } - - #[test] - fn iss_not_matching_fails() { - let mut claims = Map::new(); - claims.insert("iss".to_string(), to_value("Hacked").unwrap()); - let validation = Validation { - iss: Some("Keats".to_string()), - ..Default::default() - }; - let res = validate(&claims, &validation); - assert!(res.is_err()); - - match res.unwrap_err().kind() { - &ErrorKind::InvalidIssuer => (), - _ => assert!(false), - }; - } - - #[test] - fn sub_ok() { - let mut claims = Map::new(); - claims.insert("sub".to_string(), to_value("Keats").unwrap()); - let validation = Validation { - sub: Some("Keats".to_string()), - ..Default::default() - }; - let res = validate(&claims, &validation); - assert!(res.is_ok()); - } - - #[test] - fn sub_not_matching_fails() { - let mut claims = Map::new(); - claims.insert("sub".to_string(), to_value("Hacked").unwrap()); - let validation = Validation { - sub: Some("Keats".to_string()), - ..Default::default() - }; - let res = validate(&claims, &validation); - assert!(res.is_err()); - - match res.unwrap_err().kind() { - &ErrorKind::InvalidSubject => (), - _ => assert!(false), - }; - } - - #[test] - fn aud_string_ok() { - let mut claims = Map::new(); - claims.insert("aud".to_string(), to_value("Everyone").unwrap()); - let mut validation = Validation::default(); - validation.set_audience(&"Everyone"); - let res = validate(&claims, &validation); - assert!(res.is_ok()); - } - - #[test] - fn aud_array_of_string_ok() { - let mut claims = Map::new(); - claims.insert("aud".to_string(), to_value(["UserA", "UserB"]).unwrap()); - let mut validation = Validation::default(); - validation.set_audience(&["UserA", "UserB"]); - let res = validate(&claims, &validation); - assert!(res.is_ok()); - } - - #[test] - fn aud_type_mismatch_fails() { - let mut claims = Map::new(); - claims.insert("aud".to_string(), to_value("Everyone").unwrap()); - let mut validation = Validation::default(); - validation.set_audience(&["UserA", "UserB"]); - let res = validate(&claims, &validation); - assert!(res.is_err()); - - match res.unwrap_err().kind() { - &ErrorKind::InvalidAudience => (), - _ => assert!(false), - }; - } - - #[test] - fn aud_correct_type_not_matching_fails() { - let mut claims = Map::new(); - claims.insert("aud".to_string(), to_value("Everyone").unwrap()); - let mut validation = Validation::default(); - validation.set_audience(&"None"); - let res = validate(&claims, &validation); - assert!(res.is_err()); - - match res.unwrap_err().kind() { - &ErrorKind::InvalidAudience => (), - _ => assert!(false), - }; - } -} diff --git a/migrations/2018-11-27-152651_add_att_key_columns/down.sql b/migrations/2018-11-27-152651_add_att_key_columns/down.sql diff --git a/migrations/2018-11-27-152651_add_att_key_columns/up.sql b/migrations/2018-11-27-152651_add_att_key_columns/up.sql @@ -0,0 +1,3 @@ +ALTER TABLE attachments + ADD COLUMN + key TEXT; +\ No newline at end of file diff --git a/rust-toolchain b/rust-toolchain @@ -1 +1 @@ -nightly-2018-10-03 +nightly-2018-12-01 diff --git a/src/api/core/accounts.rs b/src/api/core/accounts.rs @@ -1,13 +1,37 @@ -use rocket_contrib::Json; - -use db::DbConn; -use db::models::*; - -use api::{PasswordData, JsonResult, EmptyResult, JsonUpcase, NumberOrString}; -use auth::Headers; -use mail; - -use CONFIG; +use rocket_contrib::json::Json; + +use crate::db::models::*; +use crate::db::DbConn; + +use crate::api::{EmptyResult, JsonResult, JsonUpcase, NumberOrString, PasswordData, UpdateType, WebSocketUsers}; +use crate::auth::Headers; +use crate::mail; + +use crate::CONFIG; + +use rocket::{Route, State}; + +pub fn routes() -> Vec<Route> { + routes![ + register, + profile, + put_profile, + post_profile, + get_public_keys, + post_keys, + post_password, + post_kdf, + post_rotatekey, + post_sstamp, + post_email_token, + post_email, + delete_account, + post_delete_account, + revision_date, + password_hint, + prelogin, + ] +} #[derive(Deserialize, Debug)] #[allow(non_snake_case)] @@ -33,23 +57,22 @@ struct KeysData { fn register(data: JsonUpcase<RegisterData>, conn: DbConn) -> EmptyResult { let data: RegisterData = data.into_inner().data; - let mut user = match User::find_by_mail(&data.Email, &conn) { - Some(mut user) => { + Some(user) => { if Invitation::take(&data.Email, &conn) { for mut user_org in UserOrganization::find_invited_by_user(&user.uuid, &conn).iter_mut() { user_org.status = UserOrgStatus::Accepted as i32; if user_org.save(&conn).is_err() { err!("Failed to accept user to organization") } - }; + } user } else if CONFIG.signups_allowed { - err!("Account with this email already exists") + err!("Account with this email already exists") } else { - err!("Registration not allowed") + err!("Registration not allowed") } - }, + } None => { if CONFIG.signups_allowed || Invitation::take(&data.Email, &conn) { User::new(data.Email) @@ -86,7 +109,7 @@ fn register(data: JsonUpcase<RegisterData>, conn: DbConn) -> EmptyResult { match user.save(&conn) { Ok(()) => Ok(()), - Err(_) => err!("Failed to save user") + Err(_) => err!("Failed to save user"), } } @@ -99,7 +122,7 @@ fn profile(headers: Headers, conn: DbConn) -> JsonResult { #[allow(non_snake_case)] struct ProfileData { #[serde(rename = "Culture")] - _Culture: String, // Ignored, always use en-US + _Culture: String, // Ignored, always use en-US MasterPasswordHint: Option<String>, Name: String, } @@ -122,7 +145,7 @@ fn post_profile(data: JsonUpcase<ProfileData>, headers: Headers, conn: DbConn) - }; match user.save(&conn) { Ok(()) => Ok(Json(user.to_json(&conn))), - Err(_) => err!("Failed to save user profile") + Err(_) => err!("Failed to save user profile"), } } @@ -130,7 +153,7 @@ fn post_profile(data: JsonUpcase<ProfileData>, headers: Headers, conn: DbConn) - fn get_public_keys(uuid: String, _headers: Headers, conn: DbConn) -> JsonResult { let user = match User::find_by_uuid(&uuid, &conn) { Some(user) => user, - None => err!("User doesn't exist") + None => err!("User doesn't exist"), }; Ok(Json(json!({ @@ -151,12 +174,10 @@ fn post_keys(data: JsonUpcase<KeysData>, headers: Headers, conn: DbConn) -> Json match user.save(&conn) { Ok(()) => Ok(Json(user.to_json(&conn))), - Err(_) => err!("Failed to save the user's keys") + Err(_) => err!("Failed to save the user's keys"), } } - - #[derive(Deserialize)] #[allow(non_snake_case)] struct ChangePassData { @@ -178,7 +199,7 @@ fn post_password(data: JsonUpcase<ChangePassData>, headers: Headers, conn: DbCon user.key = data.Key; match user.save(&conn) { Ok(()) => Ok(()), - Err(_) => err!("Failed to save password") + Err(_) => err!("Failed to save password"), } } @@ -208,10 +229,86 @@ fn post_kdf(data: JsonUpcase<ChangeKdfData>, headers: Headers, conn: DbConn) -> user.key = data.Key; match user.save(&conn) { Ok(()) => Ok(()), - Err(_) => err!("Failed to save password settings") + Err(_) => err!("Failed to save password settings"), } } +#[derive(Deserialize)] +#[allow(non_snake_case)] +struct UpdateFolderData { + Id: String, + Name: String, +} + +use super::ciphers::CipherData; + +#[derive(Deserialize)] +#[allow(non_snake_case)] +struct KeyData { + Ciphers: Vec<CipherData>, + Folders: Vec<UpdateFolderData>, + Key: String, + PrivateKey: String, + MasterPasswordHash: String, +} + +#[post("/accounts/key", data = "<data>")] +fn post_rotatekey(data: JsonUpcase<KeyData>, headers: Headers, conn: DbConn, ws: State<WebSocketUsers>) -> EmptyResult { + let data: KeyData = data.into_inner().data; + + if !headers.user.check_valid_password(&data.MasterPasswordHash) { + err!("Invalid password") + } + + let user_uuid = &headers.user.uuid; + + // Update folder data + for folder_data in data.Folders { + let mut saved_folder = match Folder::find_by_uuid(&folder_data.Id, &conn) { + Some(folder) => folder, + None => err!("Folder doesn't exist"), + }; + + if &saved_folder.user_uuid != user_uuid { + err!("The folder is not owned by the user") + } + + saved_folder.name = folder_data.Name; + if saved_folder.save(&conn).is_err() { + err!("Failed to save folder") + } + } + + // Update cipher data + use super::ciphers::update_cipher_from_data; + + for cipher_data in data.Ciphers { + let mut saved_cipher = match Cipher::find_by_uuid(cipher_data.Id.as_ref().unwrap(), &conn) { + Some(cipher) => cipher, + None => err!("Cipher doesn't exist"), + }; + + if saved_cipher.user_uuid.as_ref().unwrap() != user_uuid { + err!("The cipher is not owned by the user") + } + + update_cipher_from_data(&mut saved_cipher, cipher_data, &headers, false, &conn, &ws, UpdateType::SyncCipherUpdate)? + } + + // Update user data + let mut user = headers.user; + + user.key = data.Key; + user.private_key = Some(data.PrivateKey); + user.reset_security_stamp(); + + if user.save(&conn).is_err() { + err!("Failed modify user key"); + } + + Ok(()) +} + #[post("/accounts/security-stamp", data = "<data>")] fn post_sstamp(data: JsonUpcase<PasswordData>, headers: Headers, conn: DbConn) -> EmptyResult { let data: PasswordData = data.into_inner().data; @@ -224,7 +321,7 @@ fn post_sstamp(data: JsonUpcase<PasswordData>, headers: Headers, conn: DbConn) - user.reset_security_stamp(); match user.save(&conn) { Ok(()) => Ok(()), - Err(_) => err!("Failed to reset security stamp") + Err(_) => err!("Failed to reset security stamp"), } } @@ -255,7 +352,7 @@ fn post_email_token(data: JsonUpcase<EmailTokenData>, headers: Headers, conn: Db struct ChangeEmailData { MasterPasswordHash: String, NewEmail: String, - + Key: String, NewMasterPasswordHash: String, #[serde(rename = "Token")] @@ -276,13 +373,13 @@ fn post_email(data: JsonUpcase<ChangeEmailData>, headers: Headers, conn: DbConn) } user.email = data.NewEmail; - + user.set_password(&data.NewMasterPasswordHash); user.key = data.Key; match user.save(&conn) { Ok(()) => Ok(()), - Err(_) => err!("Failed to save email address") + Err(_) => err!("Failed to save email address"), } } @@ -299,10 +396,10 @@ fn delete_account(data: JsonUpcase<PasswordData>, headers: Headers, conn: DbConn if !user.check_valid_password(&data.MasterPasswordHash) { err!("Invalid password") } - + match user.delete(&conn) { Ok(()) => Ok(()), - Err(_) => err!("Failed deleting user account, are you the only owner of some organization?") + Err(_) => err!("Failed deleting user account, are you the only owner of some organization?"), } } diff --git a/src/api/core/ciphers.rs b/src/api/core/ciphers.rs @@ -1,35 +1,76 @@ +use std::collections::{HashSet, HashMap}; use std::path::Path; -use std::collections::HashSet; -use rocket::State; -use rocket::Data; use rocket::http::ContentType; +use rocket::{request::Form, Data, Route, State}; -use rocket_contrib::{Json, Value}; +use rocket_contrib::json::Json; +use serde_json::Value; -use multipart::server::{Multipart, SaveResult}; use multipart::server::save::SavedData; +use multipart::server::{Multipart, SaveResult}; use data_encoding::HEXLOWER; -use db::DbConn; -use db::models::*; - -use crypto; - -use api::{self, PasswordData, JsonResult, EmptyResult, JsonUpcase, WebSocketUsers, UpdateType}; -use auth::Headers; - -use CONFIG; - -#[derive(FromForm)] -#[allow(non_snake_case)] +use crate::db::models::*; +use crate::db::DbConn; + +use crate::crypto; + +use crate::api::{self, EmptyResult, JsonResult, JsonUpcase, PasswordData, UpdateType, WebSocketUsers}; +use crate::auth::Headers; + +use crate::CONFIG; + +pub fn routes() -> Vec<Route> { + routes![ + sync, + get_ciphers, + get_cipher, + get_cipher_admin, + get_cipher_details, + post_ciphers, + put_cipher_admin, + post_ciphers_admin, + post_ciphers_create, + post_ciphers_import, + post_attachment, + post_attachment_admin, + post_attachment_share, + delete_attachment_post, + delete_attachment_post_admin, + delete_attachment, + delete_attachment_admin, + post_cipher_admin, + post_cipher_share, + put_cipher_share, + put_cipher_share_seleted, + post_cipher, + put_cipher, + delete_cipher_post, + delete_cipher_post_admin, + delete_cipher, + delete_cipher_admin, + delete_cipher_selected, + delete_cipher_selected_post, + delete_all, + move_cipher_selected, + move_cipher_selected_put, + + post_collections_update, + post_collections_admin, + put_collections_admin, + ] +} + +#[derive(FromForm, Default)] struct SyncData { - excludeDomains: bool, + #[form(field = "excludeDomains")] + exclude_domains: bool, // Default: 'false' } -#[get("/sync?<data>")] -fn sync(data: SyncData, headers: Headers, conn: DbConn) -> JsonResult { +#[get("/sync?<data..>")] +fn sync(data: Form<SyncData>, headers: Headers, conn: DbConn) -> JsonResult { let user_json = headers.user.to_json(&conn); let folders = Folder::find_by_user(&headers.user.uuid, &conn); @@ -41,7 +82,7 @@ fn sync(data: SyncData, headers: Headers, conn: DbConn) -> JsonResult { let ciphers = Cipher::find_by_user(&headers.user.uuid, &conn); let ciphers_json: Vec<Value> = ciphers.iter().map(|c| c.to_json(&headers.host, &headers.user.uuid, &conn)).collect(); - let domains_json = if data.excludeDomains { Value::Null } else { api::core::get_eq_domains(headers).unwrap().into_inner() }; + let domains_json = if data.exclude_domains { Value::Null } else { api::core::get_eq_domains(headers).unwrap().into_inner() }; Ok(Json(json!({ "Profile": user_json, @@ -53,14 +94,6 @@ fn sync(data: SyncData, headers: Headers, conn: DbConn) -> JsonResult { }))) } -#[get("/sync")] -fn sync_no_query(headers: Headers, conn: DbConn) -> JsonResult { - let sync_data = SyncData { - excludeDomains: false, - }; - sync(sync_data, headers, conn) -} - #[get("/ciphers")] fn get_ciphers(headers: Headers, conn: DbConn) -> JsonResult { let ciphers = Cipher::find_by_user(&headers.user.uuid, &conn); @@ -103,7 +136,7 @@ fn get_cipher_details(uuid: String, headers: Headers, conn: DbConn) -> JsonResul #[allow(non_snake_case)] pub struct CipherData { // Id is optional as it is included only in bulk share - Id: Option<String>, + pub Id: Option<String>, // Folder id is not included in import FolderId: Option<String>, // TODO: Some of these might appear all the time, no need for Option @@ -129,13 +162,25 @@ pub struct CipherData { Favorite: Option<bool>, PasswordHistory: Option<Value>, + + // These are used during key rotation + #[serde(rename = "Attachments")] + _Attachments: Option<Value>, // Unused, contains map of {id: filename} + Attachments2: Option<HashMap<String, Attachments2Data>> +} + +#[derive(Deserialize, Debug)] +#[allow(non_snake_case)] +pub struct Attachments2Data { + FileName: String, + Key: String, } #[post("/ciphers/admin", data = "<data>")] fn post_ciphers_admin(data: JsonUpcase<ShareCipherData>, headers: Headers, conn: DbConn, ws: State<WebSocketUsers>) -> JsonResult { let data: ShareCipherData = data.into_inner().data; - let mut cipher = Cipher::new(data.Cipher.Type.clone(), data.Cipher.Name.clone()); + let mut cipher = Cipher::new(data.Cipher.Type, data.Cipher.Name.clone()); cipher.user_uuid = Some(headers.user.uuid.clone()); match cipher.save(&conn) { Ok(()) => (), @@ -188,6 +233,28 @@ pub fn update_cipher_from_data(cipher: &mut Cipher, data: CipherData, headers: & } } + // Modify attachments name and keys when rotating + if let Some(attachments) = data.Attachments2 { + for (id, attachment) in attachments { + let mut saved_att = match Attachment::find_by_id(&id, &conn) { + Some(att) => att, + None => err!("Attachment doesn't exist") + }; + + if saved_att.cipher_uuid != cipher.uuid { + err!("Attachment is not owned by the cipher") + } + + saved_att.key = Some(attachment.Key); + saved_att.file_name = attachment.FileName; + + match saved_att.save(&conn) { + Ok(()) => (), + Err(_) => err!("Failed to save attachment") + }; + } + } + let type_data_opt = match data.Type { 1 => data.Login, 2 => data.SecureNote, @@ -219,7 +286,7 @@ pub fn update_cipher_from_data(cipher: &mut Cipher, data: CipherData, headers: & match cipher.save(&conn) { Ok(()) => (), - Err(_) => println!("Error: Failed to save cipher") + Err(_) => err!("Failed to save cipher") }; ws.send_cipher_update(ut, &cipher, &cipher.update_users_revision(&conn)); @@ -266,7 +333,6 @@ fn post_ciphers_import(data: JsonUpcase<ImportData>, headers: Headers, conn: DbC } // Read the relations between folders and ciphers - use std::collections::HashMap; let mut relations_map = HashMap::new(); for relation in data.FolderRelationships { @@ -509,37 +575,52 @@ fn post_attachment(uuid: String, data: Data, content_type: &ContentType, headers let base_path = Path::new(&CONFIG.attachments_folder).join(&cipher.uuid); + let mut attachment_key = None; + Multipart::with_body(data.open(), boundary).foreach_entry(|mut field| { - // This is provided by the client, don't trust it - let name = field.headers.filename.expect("No filename provided"); - - let file_name = HEXLOWER.encode(&crypto::get_random(vec![0; 10])); - let path = base_path.join(&file_name); - - let size = match field.data.save() - .memory_threshold(0) - .size_limit(None) - .with_path(path) { - SaveResult::Full(SavedData::File(_, size)) => size as i32, - SaveResult::Full(other) => { - println!("Attachment is not a file: {:?}", other); - return; + match field.headers.name.as_str() { + "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); + } }, - SaveResult::Partial(_, reason) => { - println!("Partial result: {:?}", reason); - return; + "data" => { + // This is provided by the client, don't trust it + let name = field.headers.filename.expect("No filename provided"); + + let file_name = HEXLOWER.encode(&crypto::get_random(vec![0; 10])); + let path = base_path.join(&file_name); + + let size = match field.data.save() + .memory_threshold(0) + .size_limit(None) + .with_path(path) { + SaveResult::Full(SavedData::File(_, size)) => size as i32, + SaveResult::Full(other) => { + error!("Attachment is not a file: {:?}", other); + return; + }, + SaveResult::Partial(_, reason) => { + error!("Partial result: {:?}", reason); + return; + }, + SaveResult::Error(e) => { + error!("Error: {:?}", e); + return; + } + }; + + let mut attachment = Attachment::new(file_name, cipher.uuid.clone(), name, size); + attachment.key = attachment_key.clone(); + match attachment.save(&conn) { + Ok(()) => (), + Err(_) => error!("Failed to save attachment") + }; }, - SaveResult::Error(e) => { - println!("Error: {:?}", e); - return; - } - }; - - let attachment = Attachment::new(file_name, cipher.uuid.clone(), name, size); - match attachment.save(&conn) { - Ok(()) => (), - Err(_) => println!("Error: failed to save attachment") - }; + _ => error!("Invalid multipart name") + } }).expect("Error processing multipart data"); Ok(Json(cipher.to_json(&headers.host, &headers.user.uuid, &conn))) @@ -670,7 +751,7 @@ fn move_cipher_selected(data: JsonUpcase<Value>, headers: Headers, conn: DbConn, } match cipher.save(&conn) { Ok(()) => (), - Err(_) => println!("Error: Failed to save cipher") + Err(_) => err!("Failed to save cipher") }; ws.send_cipher_update(UpdateType::SyncCipherUpdate, &cipher, &cipher.update_users_revision(&conn)); } @@ -708,8 +789,7 @@ fn delete_all(data: JsonUpcase<PasswordData>, headers: Headers, conn: DbConn, ws for f in Folder::find_by_user(&user.uuid, &conn) { if f.delete(&conn).is_err() { err!("Failed deleting folder") - } - else { + } else { ws.send_folder_update(UpdateType::SyncFolderCreate, &f); } } @@ -761,6 +841,6 @@ fn _delete_cipher_attachment_by_id(uuid: &str, attachment_id: &str, headers: &He ws.send_cipher_update(UpdateType::SyncCipherDelete, &cipher, &cipher.update_users_revision(&conn)); Ok(()) } - Err(_) => err!("Deleting attachement failed") + Err(_) => err!("Deleting attachment failed") } } diff --git a/src/api/core/folders.rs b/src/api/core/folders.rs @@ -1,11 +1,26 @@ use rocket::State; -use rocket_contrib::{Json, Value}; - -use db::DbConn; -use db::models::*; - -use api::{JsonResult, EmptyResult, JsonUpcase, WebSocketUsers, UpdateType}; -use auth::Headers; +use rocket_contrib::json::Json; +use serde_json::Value; + +use crate::db::DbConn; +use crate::db::models::*; + +use crate::api::{JsonResult, EmptyResult, JsonUpcase, WebSocketUsers, UpdateType}; +use crate::auth::Headers; + +use rocket::Route; + +pub fn routes() -> Vec<Route> { + routes![ + get_folders, + get_folder, + post_folders, + post_folder, + put_folder, + delete_folder_post, + delete_folder, + ] +} #[get("/folders")] fn get_folders(headers: Headers, conn: DbConn) -> JsonResult { diff --git a/src/api/core/mod.rs b/src/api/core/mod.rs @@ -4,182 +4,69 @@ mod folders; mod organizations; pub(crate) mod two_factor; -use self::accounts::*; -use self::ciphers::*; -use self::folders::*; -use self::organizations::*; -use self::two_factor::*; - pub fn routes() -> Vec<Route> { - routes![ - register, - profile, - put_profile, - post_profile, - get_public_keys, - post_keys, - post_password, - post_kdf, - post_sstamp, - post_email_token, - post_email, - delete_account, - post_delete_account, - revision_date, - password_hint, - prelogin, - - sync, - sync_no_query, - - get_ciphers, - get_cipher, - get_cipher_admin, - get_cipher_details, - post_ciphers, - put_cipher_admin, - post_ciphers_admin, - post_ciphers_create, - post_ciphers_import, - post_attachment, - post_attachment_admin, - post_attachment_share, - delete_attachment_post, - delete_attachment_post_admin, - delete_attachment, - delete_attachment_admin, - post_cipher_admin, - post_cipher_share, - put_cipher_share, - put_cipher_share_seleted, - post_cipher, - put_cipher, - delete_cipher_post, - delete_cipher_post_admin, - delete_cipher, - delete_cipher_admin, - delete_cipher_selected, - delete_cipher_selected_post, - delete_all, - move_cipher_selected, - move_cipher_selected_put, - - get_folders, - get_folder, - post_folders, - post_folder, - put_folder, - delete_folder_post, - delete_folder, - - get_twofactor, - get_recover, - recover, - disable_twofactor, - disable_twofactor_put, - generate_authenticator, - activate_authenticator, - activate_authenticator_put, - generate_u2f, - generate_u2f_challenge, - activate_u2f, - activate_u2f_put, - generate_yubikey, - activate_yubikey, - activate_yubikey_put, - - get_organization, - create_organization, - delete_organization, - post_delete_organization, - leave_organization, - get_user_collections, - get_org_collections, - get_org_collection_detail, - get_collection_users, - put_organization, - post_organization, - post_organization_collections, - delete_organization_collection_user, - post_organization_collection_delete_user, - post_organization_collection_update, - put_organization_collection_update, - delete_organization_collection, - post_organization_collection_delete, - post_collections_update, - post_collections_admin, - put_collections_admin, - get_org_details, - get_org_users, - send_invite, - confirm_invite, - get_user, - edit_user, - put_organization_user, - delete_user, - post_delete_user, - post_reinvite_user, - post_org_import, - + let mut mod_routes = routes![ clear_device_token, put_device_token, get_eq_domains, post_eq_domains, put_eq_domains, + ]; + + let mut routes = Vec::new(); + routes.append(&mut accounts::routes()); + routes.append(&mut ciphers::routes()); + routes.append(&mut folders::routes()); + routes.append(&mut organizations::routes()); + routes.append(&mut two_factor::routes()); + routes.append(&mut mod_routes); - ] + routes } /// /// Move this somewhere else /// - use rocket::Route; -use rocket_contrib::{Json, Value}; +use rocket_contrib::json::Json; +use serde_json::Value; -use db::DbConn; -use db::models::*; +use crate::db::DbConn; -use api::{JsonResult, EmptyResult, JsonUpcase}; -use auth::Headers; +use crate::api::{EmptyResult, JsonResult, JsonUpcase}; +use crate::auth::Headers; -#[put("/devices/identifier/<uuid>/clear-token", data = "<data>")] -fn clear_device_token(uuid: String, data: Json<Value>, headers: Headers, conn: DbConn) -> EmptyResult { - let _data: Value = data.into_inner(); - - let device = match Device::find_by_uuid(&uuid, &conn) { - Some(device) => device, - None => err!("Device not found") - }; +#[put("/devices/identifier/<uuid>/clear-token")] +fn clear_device_token(uuid: String) -> EmptyResult { + // This endpoint doesn't have auth header - if device.user_uuid != headers.user.uuid { - err!("Device not owned by user") - } + let _ = uuid; + // uuid is not related to deviceId - match device.delete(&conn) { - Ok(()) => Ok(()), - Err(_) => err!("Failed deleting device") - } + // This only clears push token + // https://github.com/bitwarden/core/blob/master/src/Api/Controllers/DevicesController.cs#L109 + // https://github.com/bitwarden/core/blob/master/src/Core/Services/Implementations/DeviceService.cs#L37 + Ok(()) } #[put("/devices/identifier/<uuid>/token", data = "<data>")] -fn put_device_token(uuid: String, data: Json<Value>, headers: Headers, conn: DbConn) -> JsonResult { - let _data: Value = data.into_inner(); - - let device = match Device::find_by_uuid(&uuid, &conn) { - Some(device) => device, - None => err!("Device not found") - }; - - if device.user_uuid != headers.user.uuid { - err!("Device not owned by user") - } +fn put_device_token(uuid: String, data: JsonUpcase<Value>, headers: Headers) -> JsonResult { + let _data: Value = data.into_inner().data; + // Data has a single string value "PushToken" + let _ = uuid; + // uuid is not related to deviceId - // TODO: What does this do? + // TODO: This should save the push token, but we don't have push functionality - err!("Not implemented") + Ok(Json(json!({ + "Id": headers.device.uuid, + "Name": headers.device.name, + "Type": headers.device.type_, + "Identifier": headers.device.uuid, + "CreationDate": crate::util::format_date(&headers.device.created_at), + }))) } #[derive(Serialize, Deserialize, Debug)] @@ -213,7 +100,6 @@ fn get_eq_domains(headers: Headers) -> JsonResult { }))) } - #[derive(Deserialize, Debug)] #[allow(non_snake_case)] struct EquivDomainData { @@ -236,9 +122,8 @@ fn post_eq_domains(data: JsonUpcase<EquivDomainData>, headers: Headers, conn: Db match user.save(&conn) { Ok(()) => Ok(Json(json!({}))), - Err(_) => err!("Failed to save user") + Err(_) => err!("Failed to save user"), } - } #[put("/settings/domains", data = "<data>")] diff --git a/src/api/core/organizations.rs b/src/api/core/organizations.rs @@ -1,14 +1,53 @@ use rocket::State; -use rocket_contrib::{Json, Value}; -use CONFIG; -use db::DbConn; -use db::models::*; +use rocket::request::Form; +use rocket_contrib::json::Json; +use serde_json::Value; -use api::{PasswordData, JsonResult, EmptyResult, NumberOrString, JsonUpcase, WebSocketUsers, UpdateType}; -use auth::{Headers, AdminHeaders, OwnerHeaders}; +use crate::CONFIG; +use crate::db::DbConn; +use crate::db::models::*; + +use crate::api::{PasswordData, JsonResult, EmptyResult, NumberOrString, JsonUpcase, WebSocketUsers, UpdateType}; +use crate::auth::{Headers, AdminHeaders, OwnerHeaders}; use serde::{Deserialize, Deserializer}; +use rocket::Route; + +pub fn routes() -> Vec<Route> { + routes![ + get_organization, + create_organization, + delete_organization, + post_delete_organization, + leave_organization, + get_user_collections, + get_org_collections, + get_org_collection_detail, + get_collection_users, + put_organization, + post_organization, + post_organization_collections, + delete_organization_collection_user, + post_organization_collection_delete_user, + post_organization_collection_update, + put_organization_collection_update, + delete_organization_collection, + post_organization_collection_delete, + get_org_details, + get_org_users, + send_invite, + confirm_invite, + get_user, + edit_user, + put_organization_user, + delete_user, + post_delete_user, + post_reinvite_user, + post_org_import, + ] +} + #[derive(Deserialize)] #[allow(non_snake_case)] @@ -315,14 +354,14 @@ fn get_collection_users(org_id: String, coll_id: String, _headers: AdminHeaders, } #[derive(FromForm)] -#[allow(non_snake_case)] struct OrgIdData { - organizationId: String + #[form(field = "organizationId")] + organization_id: String } -#[get("/ciphers/organization-details?<data>")] -fn get_org_details(data: OrgIdData, headers: Headers, conn: DbConn) -> JsonResult { - let ciphers = Cipher::find_by_org(&data.organizationId, &conn); +#[get("/ciphers/organization-details?<data..>")] +fn get_org_details(data: Form<OrgIdData>, headers: Headers, conn: DbConn) -> JsonResult { + 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(); Ok(Json(json!({ @@ -643,10 +682,10 @@ struct RelationsData { Value: usize, } -#[post("/ciphers/import-organization?<query>", data = "<data>")] -fn post_org_import(query: OrgIdData, data: JsonUpcase<ImportData>, headers: Headers, conn: DbConn, ws: State<WebSocketUsers>) -> EmptyResult { +#[post("/ciphers/import-organization?<query..>", data = "<data>")] +fn post_org_import(query: Form<OrgIdData>, data: JsonUpcase<ImportData>, headers: Headers, conn: DbConn, ws: State<WebSocketUsers>) -> EmptyResult { let data: ImportData = data.into_inner().data; - let org_id = query.organizationId; + let org_id = query.into_inner().organization_id; let org_user = match UserOrganization::find_by_user_and_org(&headers.user.uuid, &org_id, &conn) { Some(user) => user, @@ -700,4 +739,4 @@ fn post_org_import(query: OrgIdData, data: JsonUpcase<ImportData>, headers: Head Ok(()) => Ok(()), Err(_) => err!("Failed to update the revision, please log out and log back in to finish import.") } -} -\ No newline at end of file +} diff --git a/src/api/core/two_factor.rs b/src/api/core/two_factor.rs @@ -1,16 +1,40 @@ use data_encoding::BASE32; -use rocket_contrib::{Json, Value}; +use rocket_contrib::json::Json; use serde_json; +use serde_json::Value; -use db::{ + +use crate::db::{ models::{TwoFactor, TwoFactorType, User}, DbConn, }; -use crypto; - -use api::{ApiResult, JsonResult, JsonUpcase, NumberOrString, PasswordData}; -use auth::Headers; +use crate::crypto; + +use crate::api::{ApiResult, JsonResult, JsonUpcase, NumberOrString, PasswordData}; +use crate::auth::Headers; + +use rocket::Route; + +pub fn routes() -> Vec<Route> { + routes![ + get_twofactor, + get_recover, + recover, + disable_twofactor, + disable_twofactor_put, + generate_authenticator, + activate_authenticator, + activate_authenticator_put, + generate_u2f, + generate_u2f_challenge, + activate_u2f, + activate_u2f_put, + generate_yubikey, + activate_yubikey, + activate_yubikey_put, + ] +} #[get("/two-factor")] fn get_twofactor(headers: Headers, conn: DbConn) -> JsonResult { @@ -50,7 +74,7 @@ struct RecoverTwoFactor { fn recover(data: JsonUpcase<RecoverTwoFactor>, conn: DbConn) -> JsonResult { let data: RecoverTwoFactor = data.into_inner().data; - use db::models::User; + use crate::db::models::User; // Get the user let mut user = match User::find_by_mail(&data.Email, &conn) { @@ -219,7 +243,7 @@ fn _generate_recover_code(user: &mut User, conn: &DbConn) { let totp_recover = BASE32.encode(&crypto::get_random(vec![0u8; 20])); user.totp_recover = Some(totp_recover); if user.save(conn).is_err() { - println!("Error: Failed to save the user's two factor recovery code") + error!("Failed to save the user's two factor recovery code") } } } @@ -228,7 +252,7 @@ use u2f::messages::{RegisterResponse, SignResponse, U2fSignRequest}; use u2f::protocol::{Challenge, U2f}; use u2f::register::Registration; -use CONFIG; +use crate::CONFIG; const U2F_VERSION: &str = "U2F_V2"; @@ -376,7 +400,7 @@ fn activate_u2f(data: JsonUpcase<EnableU2FData>, headers: Headers, conn: DbConn) }))) } Err(e) => { - println!("Error: {:#?}", e); + error!("{:#?}", e); err!("Error activating u2f") } } @@ -480,11 +504,11 @@ pub fn validate_u2f_login(user_uuid: &str, response: &str, conn: &DbConn) -> Api match response { Ok(new_counter) => { _counter = new_counter; - println!("O {:#}", new_counter); + info!("O {:#}", new_counter); return Ok(()); } Err(e) => { - println!("E {:#}", e); + info!("E {:#}", e); break; } } @@ -544,9 +568,8 @@ fn parse_yubikeys(data: &EnableYubikeyData) -> Vec<String> { fn jsonify_yubikeys(yubikeys: Vec<String>) -> serde_json::Value { let mut result = json!({}); - for i in 0..yubikeys.len() { - let ref key = &yubikeys[i]; - result[format!("Key{}", i+1)] = Value::String(key.to_string()); + for (i, key) in yubikeys.into_iter().enumerate() { + result[format!("Key{}", i+1)] = Value::String(key); } result @@ -630,7 +653,7 @@ fn activate_yubikey(data: JsonUpcase<EnableYubikeyData>, headers: Headers, conn: let yubikeys = parse_yubikeys(&data); - if yubikeys.len() == 0 { + if yubikeys.is_empty() { return Ok(Json(json!({ "Enabled": false, "Object": "twoFactorU2f", diff --git a/src/api/icons.rs b/src/api/icons.rs @@ -7,7 +7,7 @@ use rocket::http::ContentType; use reqwest; -use CONFIG; +use crate::CONFIG; pub fn routes() -> Vec<Route> { routes![icon] @@ -43,7 +43,7 @@ fn get_icon (domain: &str) -> Vec<u8> { icon }, Err(e) => { - println!("Error downloading icon: {:?}", e); + error!("Error downloading icon: {:?}", e); get_fallback_icon() } } @@ -71,7 +71,7 @@ fn get_icon_url(domain: &str) -> String { } fn download_icon(url: &str) -> Result<Vec<u8>, reqwest::Error> { - println!("Downloading icon for {}...", url); + info!("Downloading icon for {}...", url); let mut res = reqwest::get(url)?; res = res.error_for_status()?; @@ -105,7 +105,7 @@ fn get_fallback_icon() -> Vec<u8> { icon }, Err(e) => { - println!("Error downloading fallback icon: {:?}", e); + error!("Error downloading fallback icon: {:?}", e); vec![] } } diff --git a/src/api/identity.rs b/src/api/identity.rs @@ -1,42 +1,43 @@ -use std::collections::HashMap; -use std::net::{IpAddr, Ipv4Addr, SocketAddr}; +use rocket::request::LenientForm; +use rocket::Route; -use rocket::request::{self, Form, FormItems, FromForm, FromRequest, Request}; -use rocket::{Outcome, Route}; - -use rocket_contrib::{Json, Value}; +use rocket_contrib::json::Json; +use serde_json::Value; use num_traits::FromPrimitive; -use db::models::*; -use db::DbConn; +use crate::db::models::*; +use crate::db::DbConn; + +use crate::util::{self, JsonMap}; -use util::{self, JsonMap}; +use crate::api::{ApiResult, EmptyResult, JsonResult}; -use api::{ApiResult, JsonResult}; +use crate::auth::ClientIp; -use CONFIG; +use crate::CONFIG; pub fn routes() -> Vec<Route> { routes![login] } -#[post("/connect/token", data = "<connect_data>")] -fn login(connect_data: Form<ConnectData>, device_type: DeviceType, conn: DbConn, socket: Option<SocketAddr>) -> JsonResult { - let data = connect_data.get(); +#[post("/connect/token", data = "<data>")] +fn login(data: LenientForm<ConnectData>, conn: DbConn, ip: ClientIp) -> JsonResult { + let data: ConnectData = data.into_inner(); + validate_data(&data)?; match data.grant_type { - GrantType::RefreshToken => _refresh_login(data, device_type, conn), - GrantType::Password => _password_login(data, device_type, conn, socket), + GrantType::refresh_token => _refresh_login(data, conn), + GrantType::password => _password_login(data, conn, ip), } } -fn _refresh_login(data: &ConnectData, _device_type: DeviceType, conn: DbConn) -> JsonResult { +fn _refresh_login(data: ConnectData, conn: DbConn) -> JsonResult { // Extract token - let token = data.get("refresh_token"); + let token = data.refresh_token.unwrap(); // Get device by refresh token - let mut device = match Device::find_by_refresh_token(token, &conn) { + let mut device = match Device::find_by_refresh_token(&token, &conn) { Some(device) => device, None => err!("Invalid refresh token"), }; @@ -47,90 +48,71 @@ fn _refresh_login(data: &ConnectData, _device_type: DeviceType, conn: DbConn) -> let (access_token, expires_in) = device.refresh_tokens(&user, orgs); match device.save(&conn) { - Ok(()) => Ok(Json(json!({ - "access_token": access_token, - "expires_in": expires_in, - "token_type": "Bearer", - "refresh_token": device.refresh_token, - "Key": user.key, - "PrivateKey": user.private_key, - }))), - Err(_) => err!("Failed to add device to user") + Ok(()) => Ok(Json(json!({ + "access_token": access_token, + "expires_in": expires_in, + "token_type": "Bearer", + "refresh_token": device.refresh_token, + "Key": user.key, + "PrivateKey": user.private_key, + }))), + Err(e) => err!("Failed to add device to user", e), } } -fn _password_login(data: &ConnectData, device_type: DeviceType, conn: DbConn, remote: Option<SocketAddr>) -> JsonResult { - // Get the ip for error reporting - let ip = match remote { - Some(ip) => ip.ip(), - None => IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), - }; - +fn _password_login(data: ConnectData, conn: DbConn, ip: ClientIp) -> JsonResult { // Validate scope - let scope = data.get("scope"); + let scope = data.scope.as_ref().unwrap(); if scope != "api offline_access" { err!("Scope not supported") } // Get the user - let username = data.get("username"); + let username = data.username.as_ref().unwrap(); let user = match User::find_by_mail(username, &conn) { Some(user) => user, None => err!(format!( "Username or password is incorrect. Try again. IP: {}. Username: {}.", - ip, username + ip.ip, username )), }; // Check password - let password = data.get("password"); + let password = data.password.as_ref().unwrap(); if !user.check_valid_password(password) { err!(format!( "Username or password is incorrect. Try again. IP: {}. Username: {}.", - ip, username + ip.ip, username )) } - // Let's only use the header and ignore the 'devicetype' parameter - let device_type_num = device_type.0; - - let (device_id, device_name) = if data.is_device { - ( - data.get("deviceidentifier").clone(), - data.get("devicename").clone(), - ) - } else { - (format!("web-{}", user.uuid), String::from("web")) - }; + let device_type = util::try_parse_string(data.device_type.as_ref()).unwrap_or(0); + let device_id = data.device_identifier.clone().unwrap_or_else(crate::util::get_uuid); + let device_name = data.device_name.clone().unwrap_or("unknown_device".into()); // Find device or create new let mut device = match Device::find_by_uuid(&device_id, &conn) { Some(device) => { - // Check if valid device + // Check if owned device, and recreate if not if device.user_uuid != user.uuid { - match device.delete(&conn) { - Ok(()) => Device::new(device_id, user.uuid.clone(), device_name, device_type_num), - Err(_) => err!("Tried to delete device not owned by user, but failed") - } + info!("Device exists but is owned by another user. The old device will be discarded"); + Device::new(device_id, user.uuid.clone(), device_name, device_type) } else { device } } - None => { - // Create new device - Device::new(device_id, user.uuid.clone(), device_name, device_type_num) - } + None => Device::new(device_id, user.uuid.clone(), device_name, device_type) }; - let twofactor_token = twofactor_auth(&user.uuid, &data, &mut device, &conn)?; + let twofactor_token = twofactor_auth(&user.uuid, &data.clone(), &mut device, &conn)?; // Common let user = User::find_by_uuid(&device.user_uuid, &conn).unwrap(); let orgs = UserOrganization::find_by_user(&user.uuid, &conn); let (access_token, expires_in) = device.refresh_tokens(&user, orgs); - if device.save(&conn).is_err() { - err!("Failed to add device to user") + if let Err(e) = device.save(&conn) { + err!("Failed to add device to user", e) } let mut result = json!({ @@ -147,6 +129,7 @@ fn _password_login(data: &ConnectData, device_type: DeviceType, conn: DbConn, re result["TwoFactorToken"] = Value::String(token); } + info!("User {} logged in successfully. IP: {}", username, ip.ip); Ok(Json(result)) } @@ -167,13 +150,10 @@ fn twofactor_auth( return Ok(None); } - let provider = match util::try_parse_string(data.get_opt("twoFactorProvider")) { - Some(provider) => provider, - None => providers[0], // If we aren't given a two factor provider, asume the first one - }; + let provider = data.two_factor_provider.unwrap_or(providers[0]); // If we aren't given a two factor provider, asume the first one - let twofactor_code = match data.get_opt("twoFactorToken") { - Some(code) => code, + let twofactor_code = match data.two_factor_token { + Some(ref code) => code, None => err_json!(_json_err_twofactor(&providers, user_uuid, conn)?), }; @@ -181,8 +161,8 @@ fn twofactor_auth( match TwoFactorType::from_i32(provider) { Some(TwoFactorType::Remember) => { - match &device.twofactor_remember { - Some(remember) if remember == twofactor_code => return Ok(None), // No twofactor token needed here + match device.twofactor_remember { + Some(ref remember) if remember == twofactor_code => return Ok(None), // No twofactor token needed here _ => err_json!(_json_err_twofactor(&providers, user_uuid, conn)?), } } @@ -204,13 +184,13 @@ fn twofactor_auth( } Some(TwoFactorType::U2f) => { - use api::core::two_factor; + use crate::api::core::two_factor; - two_factor::validate_u2f_login(user_uuid, twofactor_code, conn)?; + two_factor::validate_u2f_login(user_uuid, &twofactor_code, conn)?; } Some(TwoFactorType::YubiKey) => { - use api::core::two_factor; + use crate::api::core::two_factor; two_factor::validate_yubikey_login(user_uuid, twofactor_code, conn)?; } @@ -218,7 +198,7 @@ fn twofactor_auth( _ => err!("Invalid two factor provider"), } - if util::try_parse_string_or(data.get_opt("twoFactorRemember"), 0) == 1 { + if data.two_factor_remember.unwrap_or(0) == 1 { Ok(Some(device.refresh_twofactor_remember())) } else { device.delete_twofactor_remember(); @@ -227,7 +207,7 @@ fn twofactor_auth( } fn _json_err_twofactor(providers: &[i32], user_uuid: &str, conn: &DbConn) -> ApiResult<Value> { - use api::core::two_factor; + use crate::api::core::two_factor; let mut result = json!({ "error" : "invalid_grant", @@ -289,93 +269,60 @@ fn _json_err_twofactor(providers: &[i32], user_uuid: &str, conn: &DbConn) -> Api Ok(result) } -#[derive(Clone, Copy)] -struct DeviceType(i32); - -impl<'a, 'r> FromRequest<'a, 'r> for DeviceType { - type Error = &'static str; - - fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> { - let headers = request.headers(); - let type_opt = headers.get_one("Device-Type"); - let type_num = util::try_parse_string_or(type_opt, 0); - - Outcome::Success(DeviceType(type_num)) - } -} - -#[derive(Debug)] +#[derive(FromForm, Debug, Clone)] +#[allow(non_snake_case)] struct ConnectData { grant_type: GrantType, - is_device: bool, - data: HashMap<String, String>, -} -#[derive(Debug, Copy, Clone)] -enum GrantType { - RefreshToken, - Password, + // Needed for grant_type="refresh_token" + refresh_token: Option<String>, + + // Needed for grant_type="password" + client_id: Option<String>, // web, cli, desktop, browser, mobile + password: Option<String>, + scope: Option<String>, + username: Option<String>, + + #[form(field = "deviceIdentifier")] + device_identifier: Option<String>, + #[form(field = "deviceName")] + device_name: Option<String>, + #[form(field = "deviceType")] + device_type: Option<String>, + + // Needed for two-factor auth + #[form(field = "twoFactorProvider")] + two_factor_provider: Option<i32>, + #[form(field = "twoFactorToken")] + two_factor_token: Option<String>, + #[form(field = "twoFactorRemember")] + two_factor_remember: Option<i32>, } -impl ConnectData { - fn get(&self, key: &str) -> &String { - &self.data[&key.to_lowercase()] - } - - fn get_opt(&self, key: &str) -> Option<&String> { - self.data.get(&key.to_lowercase()) - } +#[derive(FromFormValue, Debug, Clone, Copy)] +#[allow(non_camel_case_types)] +enum GrantType { + refresh_token, + password, } -const VALUES_REFRESH: [&str; 1] = ["refresh_token"]; -const VALUES_PASSWORD: [&str; 5] = ["client_id", "grant_type", "password", "scope", "username"]; -const VALUES_DEVICE: [&str; 3] = ["deviceidentifier", "devicename", "devicetype"]; - -impl<'f> FromForm<'f> for ConnectData { - type Error = String; - - fn from_form(items: &mut FormItems<'f>, _strict: bool) -> Result<Self, Self::Error> { - let mut data = HashMap::new(); - - // Insert data into map - for (key, value) in items { - match (key.url_decode(), value.url_decode()) { - (Ok(key), Ok(value)) => data.insert(key.to_lowercase(), value), - _ => return Err("Error decoding key or value".to_string()), - }; +fn validate_data(data: &ConnectData) -> EmptyResult { + match data.grant_type { + GrantType::refresh_token => { + _check_is_some(&data.refresh_token, "refresh_token cannot be blank") + } + GrantType::password => { + _check_is_some(&data.client_id, "client_id cannot be blank")?; + _check_is_some(&data.password, "password cannot be blank")?; + _check_is_some(&data.scope, "scope cannot be blank")?; + _check_is_some(&data.username, "username cannot be blank") } - - // Validate needed values - let (grant_type, is_device) = match data.get("grant_type").map(String::as_ref) { - Some("refresh_token") => { - check_values(&data, &VALUES_REFRESH)?; - (GrantType::RefreshToken, false) // Device doesn't matter here - } - Some("password") => { - check_values(&data, &VALUES_PASSWORD)?; - - let is_device = match data["client_id"].as_ref() { - "browser" | "mobile" => check_values(&data, &VALUES_DEVICE)?, - _ => false, - }; - (GrantType::Password, is_device) - } - _ => return Err("Grant type not supported".to_string()), - }; - - Ok(ConnectData { - grant_type, - is_device, - data, - }) } } -fn check_values(map: &HashMap<String, String>, values: &[&str]) -> Result<bool, String> { - for value in values { - if !map.contains_key(*value) { - return Err(format!("{} cannot be blank", value)); - } +fn _check_is_some<T>(value: &Option<T>, msg: &str) -> EmptyResult { + if value.is_none() { + err!(msg) } - Ok(true) + Ok(()) } diff --git a/src/api/mod.rs b/src/api/mod.rs @@ -12,14 +12,15 @@ pub use self::notifications::routes as notifications_routes; pub use self::notifications::{start_notification_server, WebSocketUsers, UpdateType}; use rocket::response::status::BadRequest; -use rocket_contrib::Json; +use rocket_contrib::json::Json; +use serde_json::Value; // Type aliases for API methods results -type ApiResult<T> = Result<T, BadRequest<Json>>; -type JsonResult = ApiResult<Json>; +type ApiResult<T> = Result<T, BadRequest<Json<Value>>>; +type JsonResult = ApiResult<Json<Value>>; type EmptyResult = ApiResult<()>; -use util; +use crate::util; type JsonUpcase<T> = Json<util::UpCase<T>>; // Common structs representing JSON data received diff --git a/src/api/notifications.rs b/src/api/notifications.rs @@ -1,12 +1,12 @@ use rocket::Route; -use rocket_contrib::Json; +use rocket_contrib::json::Json; use serde_json::Value as JsonValue; -use api::JsonResult; -use auth::Headers; -use db::DbConn; +use crate::api::JsonResult; +use crate::auth::Headers; +use crate::db::DbConn; -use CONFIG; +use crate::CONFIG; pub fn routes() -> Vec<Route> { routes![negotiate, websockets_err] @@ -19,7 +19,7 @@ fn websockets_err() -> JsonResult { #[post("/hub/negotiate")] fn negotiate(_headers: Headers, _conn: DbConn) -> JsonResult { - use crypto; + use crate::crypto; use data_encoding::BASE64URL; let conn_id = BASE64URL.encode(&crypto::get_random(vec![0u8; 16])); @@ -52,7 +52,7 @@ use chashmap::CHashMap; use chrono::NaiveDateTime; use serde_json::from_str; -use db::models::{Cipher, Folder, User}; +use crate::db::models::{Cipher, Folder, User}; use rmpv::Value; @@ -139,7 +139,7 @@ impl Handler for WSHandler { let _id = &query_split[1][3..]; // Validate the user - use auth; + use crate::auth; let claims = match auth::decode_jwt(access_token) { Ok(claims) => claims, Err(_) => { @@ -169,7 +169,7 @@ impl Handler for WSHandler { } fn on_message(&mut self, msg: Message) -> ws::Result<()> { - println!("Server got message '{}'. ", msg); + info!("Server got message '{}'. ", msg); if let Message::Text(text) = msg.clone() { let json = &text[..text.len() - 1]; // Remove last char @@ -242,10 +242,10 @@ pub struct WebSocketUsers { } impl WebSocketUsers { - fn send_update(&self, user_uuid: &String, data: Vec<u8>) -> ws::Result<()> { + fn send_update(&self, user_uuid: &String, data: &[u8]) -> ws::Result<()> { if let Some(user) = self.map.get(user_uuid) { for sender in user.iter() { - sender.send(data.clone())?; + sender.send(data)?; } } Ok(()) @@ -262,7 +262,7 @@ impl WebSocketUsers { ut, ); - self.send_update(&user.uuid.clone(), data).ok(); + self.send_update(&user.uuid.clone(), &data).ok(); } pub fn send_folder_update(&self, ut: UpdateType, folder: &Folder) { @@ -275,10 +275,10 @@ impl WebSocketUsers { ut, ); - self.send_update(&folder.user_uuid, data).ok(); + self.send_update(&folder.user_uuid, &data).ok(); } - pub fn send_cipher_update(&self, ut: UpdateType, cipher: &Cipher, user_uuids: &Vec<String>) { + pub fn send_cipher_update(&self, ut: UpdateType, cipher: &Cipher, user_uuids: &[String]) { let user_uuid = convert_option(cipher.user_uuid.clone()); let org_uuid = convert_option(cipher.organization_uuid.clone()); @@ -294,7 +294,7 @@ impl WebSocketUsers { ); for uuid in user_uuids { - self.send_update(&uuid, data.clone()).ok(); + self.send_update(&uuid, &data).ok(); } } } diff --git a/src/api/web.rs b/src/api/web.rs @@ -6,9 +6,10 @@ use rocket::response::{self, NamedFile, Responder}; use rocket::response::content::Content; use rocket::http::{ContentType, Status}; use rocket::Route; -use rocket_contrib::{Json, Value}; +use rocket_contrib::json::Json; +use serde_json::Value; -use CONFIG; +use crate::CONFIG; pub fn routes() -> Vec<Route> { if CONFIG.web_vault_enabled { @@ -73,7 +74,7 @@ fn attachments(uuid: String, file: PathBuf) -> io::Result<NamedFile> { #[get("/alive")] fn alive() -> Json<String> { - use util::format_date; + use crate::util::format_date; use chrono::Utc; Json(format_date(&Utc::now().naive_utc())) diff --git a/src/auth.rs b/src/auth.rs @@ -1,22 +1,21 @@ /// /// JWT Handling /// - -use util::read_file; +use crate::util::read_file; use chrono::Duration; -use jwt; +use jsonwebtoken::{self, Algorithm, Header}; use serde::ser::Serialize; -use CONFIG; +use crate::CONFIG; -const JWT_ALGORITHM: jwt::Algorithm = jwt::Algorithm::RS256; +const JWT_ALGORITHM: Algorithm = Algorithm::RS256; lazy_static! { pub static ref DEFAULT_VALIDITY: Duration = Duration::hours(2); pub static ref JWT_ISSUER: String = CONFIG.domain.clone(); - static ref JWT_HEADER: jwt::Header = jwt::Header::new(JWT_ALGORITHM); + static ref JWT_HEADER: Header = Header::new(JWT_ALGORITHM); static ref PRIVATE_RSA_KEY: Vec<u8> = match read_file(&CONFIG.private_rsa_key) { Ok(key) => key, @@ -30,17 +29,17 @@ lazy_static! { } pub fn encode_jwt<T: Serialize>(claims: &T) -> String { - match jwt::encode(&JWT_HEADER, claims, &PRIVATE_RSA_KEY) { + match jsonwebtoken::encode(&JWT_HEADER, claims, &PRIVATE_RSA_KEY) { Ok(token) => token, Err(e) => panic!("Error encoding jwt {}", e) } } pub fn decode_jwt(token: &str) -> Result<JWTClaims, String> { - let validation = jwt::Validation { + let validation = jsonwebtoken::Validation { leeway: 30, // 30 seconds validate_exp: true, - validate_iat: true, + validate_iat: false, // IssuedAt is the same as NotBefore validate_nbf: true, aud: None, iss: Some(JWT_ISSUER.clone()), @@ -48,10 +47,10 @@ pub fn decode_jwt(token: &str) -> Result<JWTClaims, String> { algorithms: vec![JWT_ALGORITHM], }; - match jwt::decode(token, &PUBLIC_RSA_KEY, &validation) { + match jsonwebtoken::decode(token, &PUBLIC_RSA_KEY, &validation) { Ok(decoded) => Ok(decoded.claims), Err(msg) => { - println!("Error validating jwt - {:#?}", msg); + error!("Error validating jwt - {:#?}", msg); Err(msg.to_string()) } } @@ -76,6 +75,7 @@ pub struct JWTClaims { pub orgowner: Vec<String>, pub orgadmin: Vec<String>, pub orguser: Vec<String>, + pub orgmanager: Vec<String>, // user security_stamp pub sstamp: String, @@ -90,12 +90,11 @@ pub struct JWTClaims { /// /// Bearer token authentication /// - use rocket::Outcome; use rocket::request::{self, Request, FromRequest}; -use db::DbConn; -use db::models::{User, Organization, UserOrganization, UserOrgType, UserOrgStatus, Device}; +use crate::db::DbConn; +use crate::db::models::{User, Organization, UserOrganization, UserOrgType, UserOrgStatus, Device}; pub struct Headers { pub host: String, @@ -139,13 +138,11 @@ impl<'a, 'r> FromRequest<'a, 'r> for Headers { // Get access_token let access_token: &str = match request.headers().get_one("Authorization") { - Some(a) => { - match a.rsplit("Bearer ").next() { - Some(split) => split, - None => err_handler!("No access token provided") - } - } - None => err_handler!("No access token provided") + Some(a) => match a.rsplit("Bearer ").next() { + Some(split) => split, + None => err_handler!("No access token provided"), + }, + None => err_handler!("No access token provided"), }; // Check JWT token is valid and get device and user from it @@ -192,13 +189,12 @@ impl<'a, 'r> FromRequest<'a, 'r> for OrgHeaders { fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> { match request.guard::<Headers>() { - Outcome::Forward(f) => Outcome::Forward(f), + Outcome::Forward(_) => Outcome::Forward(()), Outcome::Failure(f) => Outcome::Failure(f), Outcome::Success(headers) => { - // org_id is expected to be the first dynamic param - match request.get_param::<String>(0) { - Err(_) => err_handler!("Error getting the organization id"), - Ok(org_id) => { + // org_id is expected to be the second param ("/organizations/<org_id>") + match request.get_param::<String>(1) { + Some(Ok(org_id)) => { let conn = match request.guard::<DbConn>() { Outcome::Success(conn) => conn, _ => err_handler!("Error getting DB") @@ -226,14 +222,15 @@ impl<'a, 'r> FromRequest<'a, 'r> for OrgHeaders { device: headers.device, user: headers.user, org_user_type: { - if let Some(org_usr_type) = UserOrgType::from_i32(&org_user.type_) { + if let Some(org_usr_type) = UserOrgType::from_i32(org_user.type_) { org_usr_type } else { // This should only happen if the DB is corrupted err_handler!("Unknown user type in the database") } }, }) - } + }, + _ => err_handler!("Error getting the organization id"), } } } @@ -252,11 +249,11 @@ impl<'a, 'r> FromRequest<'a, 'r> for AdminHeaders { fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> { match request.guard::<OrgHeaders>() { - Outcome::Forward(f) => Outcome::Forward(f), + Outcome::Forward(_) => Outcome::Forward(()), Outcome::Failure(f) => Outcome::Failure(f), Outcome::Success(headers) => { if headers.org_user_type >= UserOrgType::Admin { - Outcome::Success(Self{ + Outcome::Success(Self { host: headers.host, device: headers.device, user: headers.user, @@ -281,11 +278,11 @@ impl<'a, 'r> FromRequest<'a, 'r> for OwnerHeaders { fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> { match request.guard::<OrgHeaders>() { - Outcome::Forward(f) => Outcome::Forward(f), + Outcome::Forward(_) => Outcome::Forward(()), Outcome::Failure(f) => Outcome::Failure(f), Outcome::Success(headers) => { if headers.org_user_type == UserOrgType::Owner { - Outcome::Success(Self{ + Outcome::Success(Self { host: headers.host, device: headers.device, user: headers.user, @@ -296,4 +293,26 @@ impl<'a, 'r> FromRequest<'a, 'r> for OwnerHeaders { } } } -} -\ No newline at end of file +} + +/// +/// Client IP address detection +/// +use std::net::IpAddr; + +pub struct ClientIp { + pub ip: IpAddr, +} + +impl<'a, 'r> FromRequest<'a, 'r> for ClientIp { + type Error = (); + + fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> { + let ip = match request.client_ip() { + Some(addr) => addr, + None => "0.0.0.0".parse().unwrap(), + }; + + Outcome::Success(ClientIp { ip }) + } +} diff --git a/src/db/mod.rs b/src/db/mod.rs @@ -9,7 +9,7 @@ use rocket::http::Status; use rocket::request::{self, FromRequest}; use rocket::{Outcome, Request, State}; -use CONFIG; +use crate::CONFIG; /// An alias to the database connection used type Connection = SqliteConnection; diff --git a/src/db/models/attachment.rs b/src/db/models/attachment.rs @@ -1,7 +1,7 @@ -use serde_json::Value as JsonValue; +use serde_json::Value; use super::Cipher; -use CONFIG; +use crate::CONFIG; #[derive(Debug, Identifiable, Queryable, Insertable, Associations)] #[table_name = "attachments"] @@ -12,6 +12,7 @@ pub struct Attachment { pub cipher_uuid: String, pub file_name: String, pub file_size: i32, + pub key: Option<String> } /// Local methods @@ -22,6 +23,7 @@ impl Attachment { cipher_uuid, file_name, file_size, + key: None } } @@ -29,8 +31,8 @@ impl Attachment { format!("{}/{}/{}", CONFIG.attachments_folder, self.cipher_uuid, self.id) } - pub fn to_json(&self, host: &str) -> JsonValue { - use util::get_display_size; + pub fn to_json(&self, host: &str) -> Value { + use crate::util::get_display_size; let web_path = format!("{}/attachments/{}/{}", host, self.cipher_uuid, self.id); let display_size = get_display_size(self.file_size); @@ -41,6 +43,7 @@ impl Attachment { "FileName": self.file_name, "Size": self.file_size.to_string(), "SizeName": display_size, + "Key": self.key, "Object": "attachment" }) } @@ -48,8 +51,8 @@ impl Attachment { use diesel; use diesel::prelude::*; -use db::DbConn; -use db::schema::attachments; +use crate::db::DbConn; +use crate::db::schema::attachments; /// Database methods impl Attachment { @@ -61,39 +64,21 @@ impl Attachment { } pub fn delete(self, conn: &DbConn) -> QueryResult<()> { - use util; - use std::{thread, time}; - - let mut retries = 10; - - loop { - match diesel::delete( - attachments::table.filter( - attachments::id.eq(&self.id) - ) - ).execute(&**conn) { - Ok(_) => break, - Err(err) => { - if retries < 1 { - println!("ERROR: Failed with 10 retries"); - return Err(err) - } else { - retries -= 1; - println!("Had to retry! Retries left: {}", retries); - thread::sleep(time::Duration::from_millis(500)); - continue - } - } - } - } - - util::delete_file(&self.get_file_path()); + crate::util::retry( + || { + diesel::delete(attachments::table.filter(attachments::id.eq(&self.id))) + .execute(&**conn) + }, + 10, + )?; + + crate::util::delete_file(&self.get_file_path()); Ok(()) } pub fn delete_all_by_cipher(cipher_uuid: &str, conn: &DbConn) -> QueryResult<()> { - for attachement in Attachment::find_by_cipher(&cipher_uuid, &conn) { - attachement.delete(&conn)?; + for attachment in Attachment::find_by_cipher(&cipher_uuid, &conn) { + attachment.delete(&conn)?; } Ok(()) } diff --git a/src/db/models/cipher.rs b/src/db/models/cipher.rs @@ -1,7 +1,5 @@ use chrono::{NaiveDateTime, Utc}; -use serde_json::Value as JsonValue; - -use uuid::Uuid; +use serde_json::Value; use super::{User, Organization, Attachment, FolderCipher, CollectionCipher, UserOrganization, UserOrgType, UserOrgStatus}; @@ -41,7 +39,7 @@ impl Cipher { let now = Utc::now().naive_utc(); Self { - uuid: Uuid::new_v4().to_string(), + uuid: crate::util::get_uuid(), created_at: now, updated_at: now, @@ -63,28 +61,28 @@ impl Cipher { use diesel; use diesel::prelude::*; -use db::DbConn; -use db::schema::*; +use crate::db::DbConn; +use crate::db::schema::*; /// Database methods impl Cipher { - pub fn to_json(&self, host: &str, user_uuid: &str, conn: &DbConn) -> JsonValue { + pub fn to_json(&self, host: &str, user_uuid: &str, conn: &DbConn) -> Value { use serde_json; - use util::format_date; + use crate::util::format_date; use super::Attachment; let attachments = Attachment::find_by_cipher(&self.uuid, conn); - let attachments_json: Vec<JsonValue> = attachments.iter().map(|c| c.to_json(host)).collect(); + let attachments_json: Vec<Value> = attachments.iter().map(|c| c.to_json(host)).collect(); - let fields_json: JsonValue = if let Some(ref fields) = self.fields { + let fields_json: Value = if let Some(ref fields) = self.fields { serde_json::from_str(fields).unwrap() - } else { JsonValue::Null }; + } else { Value::Null }; - let password_history_json: JsonValue = if let Some(ref password_history) = self.password_history { + let password_history_json: Value = if let Some(ref password_history) = self.password_history { serde_json::from_str(password_history).unwrap() - } else { JsonValue::Null }; + } else { Value::Null }; - let mut data_json: JsonValue = serde_json::from_str(&self.data).unwrap(); + let mut data_json: Value = serde_json::from_str(&self.data).unwrap(); // TODO: ******* Backwards compat start ********** // To remove backwards compatibility, just remove this entire section @@ -234,7 +232,7 @@ impl Cipher { } pub fn is_write_accessible_to_user(&self, user_uuid: &str, conn: &DbConn) -> bool { - match ciphers::table + ciphers::table .filter(ciphers::uuid.eq(&self.uuid)) .left_join(users_organizations::table.on( ciphers::organization_uuid.eq(users_organizations::org_uuid.nullable()).and( @@ -255,14 +253,11 @@ impl Cipher { ) )) .select(ciphers::all_columns) - .first::<Self>(&**conn).ok() { - Some(_) => true, - None => false - } + .first::<Self>(&**conn).ok().is_some() } pub fn is_accessible_to_user(&self, user_uuid: &str, conn: &DbConn) -> bool { - match ciphers::table + ciphers::table .filter(ciphers::uuid.eq(&self.uuid)) .left_join(users_organizations::table.on( ciphers::organization_uuid.eq(users_organizations::org_uuid.nullable()).and( @@ -281,10 +276,7 @@ impl Cipher { ) )) .select(ciphers::all_columns) - .first::<Self>(&**conn).ok() { - Some(_) => true, - None => false - } + .first::<Self>(&**conn).ok().is_some() } pub fn get_folder_uuid(&self, user_uuid: &str, conn: &DbConn) -> Option<String> { diff --git a/src/db/models/collection.rs b/src/db/models/collection.rs @@ -1,6 +1,4 @@ -use serde_json::Value as JsonValue; - -use uuid::Uuid; +use serde_json::Value; use super::{Organization, UserOrganization, UserOrgType, UserOrgStatus}; @@ -18,14 +16,14 @@ pub struct Collection { impl Collection { pub fn new(org_uuid: String, name: String) -> Self { Self { - uuid: Uuid::new_v4().to_string(), + uuid: crate::util::get_uuid(), org_uuid, name, } } - pub fn to_json(&self) -> JsonValue { + pub fn to_json(&self) -> Value { json!({ "Id": self.uuid, "OrganizationId": self.org_uuid, @@ -37,8 +35,8 @@ impl Collection { use diesel; use diesel::prelude::*; -use db::DbConn; -use db::schema::*; +use crate::db::DbConn; +use crate::db::schema::*; /// Database methods impl Collection { @@ -150,15 +148,12 @@ impl Collection { if user_org.access_all { true } else { - match users_collections::table.inner_join(collections::table) + users_collections::table.inner_join(collections::table) .filter(users_collections::collection_uuid.eq(&self.uuid)) .filter(users_collections::user_uuid.eq(&user_uuid)) .filter(users_collections::read_only.eq(false)) .select(collections::all_columns) - .first::<Self>(&**conn).ok() { - None => false, // Read only or no access to collection - Some(_) => true, - } + .first::<Self>(&**conn).ok().is_some() // Read only or no access to collection } } } diff --git a/src/db/models/device.rs b/src/db/models/device.rs @@ -45,7 +45,7 @@ impl Device { pub fn refresh_twofactor_remember(&mut self) -> String { use data_encoding::BASE64; - use crypto; + use crate::crypto; let twofactor_remember = BASE64.encode(&crypto::get_random(vec![0u8; 180])); self.twofactor_remember = Some(twofactor_remember.clone()); @@ -62,7 +62,7 @@ impl Device { // If there is no refresh token, we create one if self.refresh_token.is_empty() { use data_encoding::BASE64URL; - use crypto; + use crate::crypto; self.refresh_token = BASE64URL.encode(&crypto::get_random_64()); } @@ -71,14 +71,14 @@ impl Device { let time_now = Utc::now().naive_utc(); self.updated_at = time_now; - let orgowner: Vec<_> = orgs.iter().filter(|o| o.type_ == 0).map(|o| o.org_uuid.clone()).collect(); let orgadmin: Vec<_> = orgs.iter().filter(|o| o.type_ == 1).map(|o| o.org_uuid.clone()).collect(); let orguser: Vec<_> = orgs.iter().filter(|o| o.type_ == 2).map(|o| o.org_uuid.clone()).collect(); + let orgmanager: Vec<_> = orgs.iter().filter(|o| o.type_ == 3).map(|o| o.org_uuid.clone()).collect(); // Create the JWT claims struct, to send to the client - use auth::{encode_jwt, JWTClaims, DEFAULT_VALIDITY, JWT_ISSUER}; + use crate::auth::{encode_jwt, JWTClaims, DEFAULT_VALIDITY, JWT_ISSUER}; let claims = JWTClaims { nbf: time_now.timestamp(), exp: (time_now + *DEFAULT_VALIDITY).timestamp(), @@ -93,6 +93,7 @@ impl Device { orgowner, orgadmin, orguser, + orgmanager, sstamp: user.security_stamp.to_string(), device: self.uuid.to_string(), @@ -100,23 +101,29 @@ impl Device { amr: vec!["Application".into()], }; - (encode_jwt(&claims), DEFAULT_VALIDITY.num_seconds()) } } use diesel; use diesel::prelude::*; -use db::DbConn; -use db::schema::devices; +use crate::db::DbConn; +use crate::db::schema::devices; /// Database methods impl Device { pub fn save(&mut self, conn: &DbConn) -> QueryResult<()> { self.updated_at = Utc::now().naive_utc(); - diesel::replace_into(devices::table) - .values(&*self).execute(&**conn).and(Ok(())) + crate::util::retry( + || { + diesel::replace_into(devices::table) + .values(&*self) + .execute(&**conn) + }, + 10, + ) + .and(Ok(())) } pub fn delete(self, conn: &DbConn) -> QueryResult<()> { diff --git a/src/db/models/folder.rs b/src/db/models/folder.rs @@ -1,7 +1,5 @@ use chrono::{NaiveDateTime, Utc}; -use serde_json::Value as JsonValue; - -use uuid::Uuid; +use serde_json::Value; use super::{User, Cipher}; @@ -33,7 +31,7 @@ impl Folder { let now = Utc::now().naive_utc(); Self { - uuid: Uuid::new_v4().to_string(), + uuid: crate::util::get_uuid(), created_at: now, updated_at: now, @@ -42,8 +40,8 @@ impl Folder { } } - pub fn to_json(&self) -> JsonValue { - use util::format_date; + pub fn to_json(&self) -> Value { + use crate::util::format_date; json!({ "Id": self.uuid, @@ -65,8 +63,8 @@ impl FolderCipher { use diesel; use diesel::prelude::*; -use db::DbConn; -use db::schema::{folders, folders_ciphers}; +use crate::db::DbConn; +use crate::db::schema::{folders, folders_ciphers}; /// Database methods impl Folder { diff --git a/src/db/models/organization.rs b/src/db/models/organization.rs @@ -1,7 +1,6 @@ use std::cmp::Ordering; -use serde_json::Value as JsonValue; +use serde_json::Value; -use uuid::Uuid; use super::{User, CollectionUser, Invitation}; #[derive(Debug, Identifiable, Queryable, Insertable)] @@ -78,10 +77,10 @@ impl PartialEq<i32> for UserOrgType { impl PartialOrd<i32> for UserOrgType { fn partial_cmp(&self, other: &i32) -> Option<Ordering> { - if let Some(other) = Self::from_i32(other) { + if let Some(other) = Self::from_i32(*other) { return Some(self.cmp(&other)) } - return None + None } fn gt(&self, other: &i32) -> bool { @@ -108,10 +107,10 @@ impl PartialEq<UserOrgType> for i32 { impl PartialOrd<UserOrgType> for i32 { fn partial_cmp(&self, other: &UserOrgType) -> Option<Ordering> { - if let Some(self_type) = UserOrgType::from_i32(self) { + if let Some(self_type) = UserOrgType::from_i32(*self) { return Some(self_type.cmp(other)) } - return None + None } fn lt(&self, other: &UserOrgType) -> bool { @@ -141,7 +140,7 @@ impl UserOrgType { } } - pub fn from_i32(i: &i32) -> Option<Self> { + pub fn from_i32(i: i32) -> Option<Self> { match i { 0 => Some(UserOrgType::Owner), 1 => Some(UserOrgType::Admin), @@ -159,7 +158,7 @@ impl Organization { pub fn new(name: String, billing_email: String) -> Self { Self { - uuid: Uuid::new_v4().to_string(), + uuid: crate::util::get_uuid(), name, billing_email, @@ -174,7 +173,7 @@ impl Organization { } } - pub fn to_json(&self) -> JsonValue { + pub fn to_json(&self) -> Value { json!({ "Id": self.uuid, "Name": self.name, @@ -206,7 +205,7 @@ impl Organization { impl UserOrganization { pub fn new(user_uuid: String, org_uuid: String) -> Self { Self { - uuid: Uuid::new_v4().to_string(), + uuid: crate::util::get_uuid(), user_uuid, org_uuid, @@ -236,8 +235,8 @@ impl UserOrganization { use diesel; use diesel::prelude::*; -use db::DbConn; -use db::schema::{organizations, users_organizations, users_collections, ciphers_collections}; +use crate::db::DbConn; +use crate::db::schema::{organizations, users_organizations, users_collections, ciphers_collections}; /// Database methods impl Organization { @@ -285,7 +284,7 @@ impl Organization { } impl UserOrganization { - pub fn to_json(&self, conn: &DbConn) -> JsonValue { + pub fn to_json(&self, conn: &DbConn) -> Value { let org = Organization::find_by_uuid(&self.org_uuid, conn).unwrap(); json!({ @@ -313,7 +312,7 @@ impl UserOrganization { }) } - pub fn to_json_user_details(&self, conn: &DbConn) -> JsonValue { + pub fn to_json_user_details(&self, conn: &DbConn) -> Value { let user = User::find_by_uuid(&self.user_uuid, conn).unwrap(); json!({ @@ -330,7 +329,7 @@ impl UserOrganization { }) } - pub fn to_json_collection_user_details(&self, read_only: bool, conn: &DbConn) -> JsonValue { + pub fn to_json_collection_user_details(&self, read_only: bool, conn: &DbConn) -> Value { let user = User::find_by_uuid(&self.user_uuid, conn).unwrap(); json!({ @@ -345,7 +344,7 @@ impl UserOrganization { }) } - pub fn to_json_details(&self, conn: &DbConn) -> JsonValue { + pub fn to_json_details(&self, conn: &DbConn) -> Value { let coll_uuids = if self.access_all { vec![] // If we have complete access, no need to fill the array } else { diff --git a/src/db/models/two_factor.rs b/src/db/models/two_factor.rs @@ -1,6 +1,4 @@ -use serde_json::Value as JsonValue; - -use uuid::Uuid; +use serde_json::Value; use super::User; @@ -36,7 +34,7 @@ pub enum TwoFactorType { impl TwoFactor { pub fn new(user_uuid: String, type_: TwoFactorType, data: String) -> Self { Self { - uuid: Uuid::new_v4().to_string(), + uuid: crate::util::get_uuid(), user_uuid, type_: type_ as i32, enabled: true, @@ -59,7 +57,7 @@ impl TwoFactor { generated == totp_code } - pub fn to_json(&self) -> JsonValue { + pub fn to_json(&self) -> Value { json!({ "Enabled": self.enabled, "Key": "", // This key and value vary @@ -67,7 +65,7 @@ impl TwoFactor { }) } - pub fn to_json_list(&self) -> JsonValue { + pub fn to_json_list(&self) -> Value { json!({ "Enabled": self.enabled, "Type": self.type_, @@ -78,8 +76,8 @@ impl TwoFactor { use diesel; use diesel::prelude::*; -use db::DbConn; -use db::schema::twofactor; +use crate::db::DbConn; +use crate::db::schema::twofactor; /// Database methods impl TwoFactor { diff --git a/src/db/models/user.rs b/src/db/models/user.rs @@ -1,10 +1,8 @@ use chrono::{NaiveDateTime, Utc}; -use serde_json::Value as JsonValue; +use serde_json::Value; -use uuid::Uuid; - -use crypto; -use CONFIG; +use crate::crypto; +use crate::CONFIG; #[derive(Debug, Identifiable, Queryable, Insertable)] @@ -50,7 +48,7 @@ impl User { let email = mail.to_lowercase(); Self { - uuid: Uuid::new_v4().to_string(), + uuid: crate::util::get_uuid(), created_at: now, updated_at: now, name: email.clone(), @@ -61,7 +59,7 @@ impl User { salt: crypto::get_random_64(), password_iterations: CONFIG.password_iterations, - security_stamp: Uuid::new_v4().to_string(), + security_stamp: crate::util::get_uuid(), password_hint: None, private_key: None, @@ -97,11 +95,10 @@ impl User { self.password_hash = crypto::hash_password(password.as_bytes(), &self.salt, self.password_iterations as u32); - self.reset_security_stamp(); } pub fn reset_security_stamp(&mut self) { - self.security_stamp = Uuid::new_v4().to_string(); + self.security_stamp = crate::util::get_uuid(); } pub fn is_server_admin(&self) -> bool { @@ -114,20 +111,20 @@ impl User { use diesel; use diesel::prelude::*; -use db::DbConn; -use db::schema::{users, invitations}; +use crate::db::DbConn; +use crate::db::schema::{users, invitations}; use super::{Cipher, Folder, Device, UserOrganization, UserOrgType}; /// Database methods impl User { - pub fn to_json(&self, conn: &DbConn) -> JsonValue { + pub fn to_json(&self, conn: &DbConn) -> Value { use super::{UserOrganization, UserOrgType, UserOrgStatus, TwoFactor}; let mut orgs = UserOrganization::find_by_user(&self.uuid, conn); if self.is_server_admin() { orgs.push(UserOrganization::new_virtual(self.uuid.clone(), UserOrgType::Owner, UserOrgStatus::Confirmed)); } - let orgs_json: Vec<JsonValue> = orgs.iter().map(|c| c.to_json(&conn)).collect(); + let orgs_json: Vec<Value> = orgs.iter().map(|c| c.to_json(&conn)).collect(); let twofactor_enabled = !TwoFactor::find_by_user(&self.uuid, conn).is_empty(); json!({ @@ -181,7 +178,7 @@ impl User { pub fn update_uuid_revision(uuid: &str, conn: &DbConn) { if let Some(mut user) = User::find_by_uuid(&uuid, conn) { if user.update_revision(conn).is_err(){ - println!("Warning: Failed to update revision for {}", user.email); + warn!("Failed to update revision for {}", user.email); }; }; } diff --git a/src/db/schema.rs b/src/db/schema.rs @@ -4,6 +4,7 @@ table! { cipher_uuid -> Text, file_name -> Text, file_size -> Integer, + key -> Nullable<Text>, } } diff --git a/src/mail.rs b/src/mail.rs @@ -4,7 +4,7 @@ use lettre::smtp::ConnectionReuseParameters; use lettre::smtp::authentication::Credentials; use lettre_email::EmailBuilder; -use MailConfig; +use crate::MailConfig; fn mailer(config: &MailConfig) -> SmtpTransport { let client_security = if config.smtp_ssl { diff --git a/src/main.rs b/src/main.rs @@ -1,41 +1,15 @@ -#![feature(plugin, custom_derive, vec_remove_item, try_trait)] -#![plugin(rocket_codegen)] -#![recursion_limit="128"] +#![feature(proc_macro_hygiene, decl_macro, vec_remove_item, try_trait)] +#![recursion_limit = "128"] #![allow(proc_macro_derive_resolution_fallback)] // TODO: Remove this when diesel update fixes warnings -extern crate rocket; -extern crate rocket_contrib; -extern crate reqwest; -extern crate multipart; -extern crate ws; -extern crate rmpv; -extern crate chashmap; -extern crate serde; -#[macro_use] -extern crate serde_derive; -#[macro_use] -extern crate serde_json; -#[macro_use] -extern crate diesel; -#[macro_use] -extern crate diesel_migrations; -extern crate ring; -extern crate uuid; -extern crate chrono; -extern crate oath; -extern crate data_encoding; -extern crate jsonwebtoken as jwt; -extern crate u2f; -extern crate yubico; -extern crate dotenv; -#[macro_use] -extern crate lazy_static; -#[macro_use] -extern crate num_derive; -extern crate num_traits; -extern crate lettre; -extern crate lettre_email; -extern crate native_tls; -extern crate byteorder; + +#[macro_use] extern crate rocket; +#[macro_use] extern crate serde_derive; +#[macro_use] extern crate serde_json; +#[macro_use] extern crate log; +#[macro_use] extern crate diesel; +#[macro_use] extern crate diesel_migrations; +#[macro_use] extern crate lazy_static; +#[macro_use] extern crate num_derive; use std::{path::Path, process::{exit, Command}}; use rocket::Rocket; @@ -50,6 +24,9 @@ mod auth; mod mail; fn init_rocket() -> Rocket { + + // TODO: TO HIDE MOUNTING LOG, call ignite, set logging to disabled, call all the mounts, and then enable it again + rocket::ignite() .mount("/", api::web_routes()) .mount("/api", api::core_routes()) @@ -69,7 +46,7 @@ mod migrations { pub fn run_migrations() { // Make sure the database is up to date (create if it doesn't exist, or run the migrations) - let connection = ::db::get_connection().expect("Can't conect to DB"); + let connection = crate::db::get_connection().expect("Can't conect to DB"); use std::io::stdout; embedded_migrations::run_with_output(&connection, &mut stdout()).expect("Can't run migrations"); @@ -77,6 +54,10 @@ mod migrations { } fn main() { + if CONFIG.extended_logging { + init_logging().ok(); + } + check_db(); check_rsa_keys(); check_web_vault(); @@ -85,13 +66,61 @@ fn main() { init_rocket().launch(); } +fn init_logging() -> Result<(), fern::InitError> { + let mut logger = fern::Dispatch::new() + .format(|out, message, record| { + out.finish(format_args!( + "{}[{}][{}] {}", + chrono::Local::now().format("[%Y-%m-%d][%H:%M:%S]"), + record.target(), + record.level(), + message + )) + }) + .level(log::LevelFilter::Debug) + .level_for("hyper", log::LevelFilter::Warn) + .level_for("ws", log::LevelFilter::Info) + .level_for("multipart", log::LevelFilter::Info) + .chain(std::io::stdout()); + + if let Some(log_file) = CONFIG.log_file.as_ref() { + logger = logger.chain(fern::log_file(log_file)?); + } + + logger = chain_syslog(logger); + logger.apply()?; + + Ok(()) +} + +#[cfg(not(feature = "enable_syslog"))] +fn chain_syslog(logger: fern::Dispatch) -> fern::Dispatch { logger } + +#[cfg(feature = "enable_syslog")] +fn chain_syslog(logger: fern::Dispatch) -> fern::Dispatch { + let syslog_fmt = syslog::Formatter3164 { + facility: syslog::Facility::LOG_USER, + hostname: None, + process: "bitwarden_rs".into(), + pid: 0, + }; + + match syslog::unix(syslog_fmt) { + Ok(sl) => logger.chain(sl), + Err(e) => { + error!("Unable to connect to syslog: {:?}", e); + logger + } + } +} + fn check_db() { let path = Path::new(&CONFIG.database_url); if let Some(parent) = path.parent() { use std::fs; if fs::create_dir_all(parent).is_err() { - println!("Error creating database directory"); + error!("Error creating database directory"); exit(1); } } @@ -106,16 +135,16 @@ fn check_rsa_keys() { // If the RSA keys don't exist, try to create them if !util::file_exists(&CONFIG.private_rsa_key) || !util::file_exists(&CONFIG.public_rsa_key) { - println!("JWT keys don't exist, checking if OpenSSL is available..."); + info!("JWT keys don't exist, checking if OpenSSL is available..."); Command::new("openssl") .arg("version") .output().unwrap_or_else(|_| { - println!("Can't create keys because OpenSSL is not available, make sure it's installed and available on the PATH"); + info!("Can't create keys because OpenSSL is not available, make sure it's installed and available on the PATH"); exit(1); }); - println!("OpenSSL detected, creating keys..."); + info!("OpenSSL detected, creating keys..."); let mut success = Command::new("openssl").arg("genrsa") .arg("-out").arg(&CONFIG.private_rsa_key_pem) @@ -139,9 +168,9 @@ fn check_rsa_keys() { .status.success(); if success { - println!("Keys created correctly."); + info!("Keys created correctly."); } else { - println!("Error creating keys, exiting..."); + error!("Error creating keys, exiting..."); exit(1); } } @@ -155,7 +184,7 @@ fn check_web_vault() { let index_path = Path::new(&CONFIG.web_vault_folder).join("index.html"); if !index_path.exists() { - println!("Web vault is not found. Please follow the steps in the README to install it"); + error!("Web vault is not found. Please follow the steps in the README to install it"); exit(1); } } @@ -177,7 +206,7 @@ pub struct MailConfig { impl MailConfig { fn load() -> Option<Self> { - use util::{get_env, get_env_or}; + use crate::util::{get_env, get_env_or}; // When SMTP_HOST is absent, we assume the user does not want to enable it. let smtp_host = match get_env("SMTP_HOST") { @@ -186,7 +215,7 @@ impl MailConfig { }; let smtp_from = get_env("SMTP_FROM").unwrap_or_else(|| { - println!("Please specify SMTP_FROM to enable SMTP support."); + error!("Please specify SMTP_FROM to enable SMTP support."); exit(1); }); @@ -202,7 +231,7 @@ impl MailConfig { let smtp_username = get_env("SMTP_USERNAME"); let smtp_password = get_env("SMTP_PASSWORD").or_else(|| { if smtp_username.as_ref().is_some() { - println!("SMTP_PASSWORD is mandatory when specifying SMTP_USERNAME."); + error!("SMTP_PASSWORD is mandatory when specifying SMTP_USERNAME."); exit(1); } else { None @@ -236,6 +265,9 @@ pub struct Config { websocket_enabled: bool, websocket_url: String, + extended_logging: bool, + log_file: Option<String>, + local_icon_extractor: bool, signups_allowed: bool, invitations_allowed: bool, @@ -256,7 +288,7 @@ pub struct Config { impl Config { fn load() -> Self { - use util::{get_env, get_env_or}; + use crate::util::{get_env, get_env_or}; dotenv::dotenv().ok(); let df = get_env_or("DATA_FOLDER", "data".to_string()); @@ -281,6 +313,9 @@ impl Config { websocket_enabled: get_env_or("WEBSOCKET_ENABLED", false), websocket_url: format!("{}:{}", get_env_or("WEBSOCKET_ADDRESS", "0.0.0.0".to_string()), get_env_or("WEBSOCKET_PORT", 3012)), + + extended_logging: get_env_or("EXTENDED_LOGGING", true), + log_file: get_env("LOG_FILE"), local_icon_extractor: get_env_or("LOCAL_ICON_EXTRACTOR", false), signups_allowed: get_env_or("SIGNUPS_ALLOWED", true), diff --git a/src/util.rs b/src/util.rs @@ -2,36 +2,46 @@ /// Macros /// #[macro_export] -macro_rules! err { - ($err:expr, $msg:expr) => {{ - println!("ERROR: {}", $msg); +macro_rules! _err_object { + ($msg:expr) => {{ err_json!(json!({ - "error": $err, - "error_description": $err, - "ErrorModel": { - "Message": $msg, - "ValidationErrors": null, - "ExceptionMessage": null, - "ExceptionStackTrace": null, - "InnerExceptionMessage": null, - "Object": "error" - }})) + "Message": "", + "error": "", + "error_description": "", + "ValidationErrors": {"": [ $msg ]}, + "ErrorModel": { + "Message": $msg, + "Object": "error" + }, + "Object": "error" + })) + }}; +} + +#[macro_export] +macro_rules! err { + ($msg:expr) => {{ + error!("{}", $msg); + _err_object!($msg) }}; - ($msg:expr) => { err!("unknown_error", $msg) } + ($usr_msg:expr, $log_value:expr) => {{ + error!("{}: {:#?}", $usr_msg, $log_value); + _err_object!($usr_msg) + }} } #[macro_export] macro_rules! err_json { ($expr:expr) => {{ - return Err($crate::rocket::response::status::BadRequest(Some($crate::rocket_contrib::Json($expr)))); + return Err(rocket::response::status::BadRequest(Some(rocket_contrib::json::Json($expr)))); }} } #[macro_export] macro_rules! err_handler { ($expr:expr) => {{ - println!("ERROR: {}", $expr); - return $crate::rocket::Outcome::Failure(($crate::rocket::http::Status::Unauthorized, $expr)); + error!("{}", $expr); + return rocket::Outcome::Failure((rocket::http::Status::Unauthorized, $expr)); }} } @@ -92,6 +102,10 @@ pub fn get_display_size(size: i32) -> String { format!("{} {}", size, UNITS[unit_counter]) } +pub fn get_uuid() -> String { + uuid::Uuid::new_v4().to_string() +} + /// /// String util methods @@ -238,6 +252,33 @@ fn upcase_value(value: &Value) -> Value { fn _process_key(key: &str) -> String { match key.to_lowercase().as_ref() { "ssn" => "SSN".into(), - _ => self::upcase_first(key) + _ => self::upcase_first(key), + } +} + +// +// Retry methods +// + +pub fn retry<F, T, E>(func: F, max_tries: i32) -> Result<T, E> +where + F: Fn() -> Result<T, E>, +{ + use std::{thread::sleep, time::Duration}; + let mut tries = 0; + + loop { + match func() { + ok @ Ok(_) => return ok, + err @ Err(_) => { + tries += 1; + + if tries >= max_tries { + return err; + } + + sleep(Duration::from_millis(500)); + } + } } }