From cfbeb563719d8aa0bc686d832c746cccdcf71883 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa?= Date: Fri, 5 Apr 2019 22:09:53 +0200 Subject: [PATCH 1/7] Implement user duo, initial version TODO: - At the moment each user needs to configure a DUO application and input the API keys, we need to check if multiple users can register with the same keys correctly and if so we could implement a global setting. - Sometimes the Duo frame doesn't load correctly, but canceling, reloading the page and logging in again seems to fix it for me. --- Cargo.lock | 112 +++++++++---------- Cargo.toml | 4 +- src/api/core/two_factor.rs | 220 ++++++++++++++++++++++++++++++++++++- src/api/identity.rs | 25 ++++- src/crypto.rs | 13 +++ 5 files changed, 312 insertions(+), 62 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d6e357ab..b746a06a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -61,7 +61,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "backtrace" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -69,7 +69,7 @@ dependencies = [ "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -77,7 +77,7 @@ name = "backtrace-sys" version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -139,8 +139,8 @@ dependencies = [ "rmpv 0.4.0 (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.89 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "soup 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "syslog 4.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -245,7 +245,7 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.32" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -594,7 +594,7 @@ name = "error-chain" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -602,7 +602,7 @@ name = "failure" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -771,7 +771,7 @@ dependencies = [ "bytes 0.4.12 (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.26 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.17 (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.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -790,7 +790,7 @@ dependencies = [ "pest_derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -838,7 +838,7 @@ dependencies = [ [[package]] name = "http" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -878,7 +878,7 @@ dependencies = [ "futures 0.1.26 (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.17 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.17 (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)", @@ -969,7 +969,7 @@ dependencies = [ "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.52 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -985,8 +985,8 @@ 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)", "ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1029,8 +1029,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.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1059,7 +1059,7 @@ name = "libsqlite3-sys" version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.34 (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)", ] @@ -1106,8 +1106,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "phf 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", "phf_codegen 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache_codegen 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1198,7 +1198,7 @@ name = "miniz_oxide_c_api" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)", "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "miniz_oxide 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1285,7 +1285,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1322,7 +1322,7 @@ dependencies = [ "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)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1404,7 +1404,7 @@ name = "openssl-sys" version = "0.9.43" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1453,7 +1453,7 @@ dependencies = [ "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1465,7 +1465,7 @@ dependencies = [ "rand 0.6.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.9 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1627,7 +1627,7 @@ dependencies = [ "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1645,7 +1645,7 @@ dependencies = [ "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1693,7 +1693,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1706,7 +1706,7 @@ dependencies = [ "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1764,7 +1764,7 @@ name = "remove_dir_all" version = "0.5.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)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1777,14 +1777,14 @@ dependencies = [ "encoding_rs 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.12.25 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-tls 0.3.2 (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.13 (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.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (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.18 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1801,7 +1801,7 @@ name = "ring" version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1866,7 +1866,7 @@ dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "notify 4.0.10 (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.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1948,7 +1948,7 @@ version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2009,12 +2009,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.89" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_derive" -version = "1.0.89" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2029,7 +2029,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.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2039,7 +2039,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.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2142,7 +2142,7 @@ dependencies = [ "new_debug_unreachable 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", "precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache_codegen 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2234,7 +2234,7 @@ dependencies = [ "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.52 (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)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2270,7 +2270,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.52 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2399,7 +2399,7 @@ name = "toml" version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2440,8 +2440,8 @@ dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 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)", - "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2549,7 +2549,7 @@ version = "2.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "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 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2588,7 +2588,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2610,7 +2610,7 @@ name = "winapi-util" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2623,7 +2623,7 @@ name = "winutil" 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)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2691,7 +2691,7 @@ dependencies = [ "checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" "checksum ascii_utils 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "71938f30533e4d95a6d17aa530939da3842c2ab6f4f84b9dae68447e4129f74a" "checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" -"checksum backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "cd5a90e2b463010cd0e0ce9a11d4a9d5d58d9f41d4a6ba3dcaf9e68b466e88b4" +"checksum backtrace 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "f106c02a3604afcdc0df5d36cc47b44b55917dbaf3d808f71c163a0ddba64637" "checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6" "checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" @@ -2710,7 +2710,7 @@ dependencies = [ "checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" "checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" "checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" -"checksum cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)" = "ad0daef304fa0b4238f5f7ed7178774b43b06f6a9b6509f6642bef4ff1f7b9b2" +"checksum cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)" = "30f813bf45048a18eda9190fd3c6b78644146056740c43172a5a3699118588fd" "checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4" "checksum chashmap 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ff41a3c2c1e39921b9003de14bf0439c7b63a9039637c291e1a64925d8ddfa45" "checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878" @@ -2778,7 +2778,7 @@ dependencies = [ "checksum hmac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f127a908633569f208325f86f71255d3363c79721d7f9fe31cd5569908819771" "checksum hostname 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "21ceb46a83a85e824ef93669c8b390009623863b5c195d1ba747292c0c72f94e" "checksum html5ever 0.22.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c213fa6a618dc1da552f54f85cba74b05d8e883c92ec4e89067736938084c26e" -"checksum http 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "fe67e3678f2827030e89cc4b9e7ecd16d52f132c0b940ab5005f88e821500f6a" +"checksum http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "eed324f0f0daf6ec10c474f150505af2c143f251722bf9dbd1261bd1f2ee2c1a" "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.25 (registry+https://github.com/rust-lang/crates.io-index)" = "7d5b6658b016965ae301fa995306db965c93677880ea70765a84235a96eae896" @@ -2902,8 +2902,8 @@ dependencies = [ "checksum security-framework-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3d6696852716b589dff9e886ff83778bb635150168e83afa8ac6b8a78cb82abc" "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.89 (registry+https://github.com/rust-lang/crates.io-index)" = "92514fb95f900c9b5126e32d020f5c6d40564c27a5ea6d1d7d9f157a96623560" -"checksum serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6eabf4b5914e88e24eea240bb7c9f9a2cbc1bbbe8d961d381975ec3c6b806c" +"checksum serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)" = "aa5f7c20820475babd2c077c3ab5f8c77a31c15e16ea38687b4c02d3e48680f4" +"checksum serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)" = "58fc82bec244f168b23d1963b45c8bf5726e9a15a9d146a067f9081aeed2de79" "checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d" "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" @@ -2970,7 +2970,7 @@ dependencies = [ "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 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" "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.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" diff --git a/Cargo.toml b/Cargo.toml index 506f5f62..1e844fa8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,8 +38,8 @@ rmpv = "0.4.0" chashmap = "2.2.2" # A generic serialization/deserialization framework -serde = "1.0.89" -serde_derive = "1.0.89" +serde = "1.0.90" +serde_derive = "1.0.90" serde_json = "1.0.39" # Logging diff --git a/src/api/core/two_factor.rs b/src/api/core/two_factor.rs index c097c78b..31cca499 100644 --- a/src/api/core/two_factor.rs +++ b/src/api/core/two_factor.rs @@ -1,4 +1,4 @@ -use data_encoding::BASE32; +use data_encoding::{BASE32, BASE64}; use rocket_contrib::json::Json; use serde_json; use serde_json::Value; @@ -31,6 +31,9 @@ pub fn routes() -> Vec { generate_yubikey, activate_yubikey, activate_yubikey_put, + get_duo, + activate_duo, + activate_duo_put, ] } @@ -231,7 +234,6 @@ pub fn validate_totp_code_str(totp_code: &str, secret: &str) -> EmptyResult { } pub fn validate_totp_code(totp_code: u64, secret: &str) -> EmptyResult { - use data_encoding::BASE32; use oath::{totp_raw_now, HashType}; let decoded_secret = match BASE32.decode(secret.as_bytes()) { @@ -714,3 +716,217 @@ pub fn validate_yubikey_login(response: &str, twofactor_data: &str) -> EmptyResu Err(_e) => err!("Failed to verify Yubikey against OTP server"), } } + +#[derive(Serialize, Deserialize, Default)] +pub struct DuoData { + pub host: String, + sk: String, + ik: String, + ak: String, +} + +#[post("/two-factor/get-duo", data = "")] +fn get_duo(data: JsonUpcase, headers: Headers, conn: DbConn) -> JsonResult { + let data: PasswordData = data.into_inner().data; + + if !headers.user.check_valid_password(&data.MasterPasswordHash) { + err!("Invalid password"); + } + + let type_ = TwoFactorType::Duo as i32; + let twofactor = TwoFactor::find_by_user_and_type(&headers.user.uuid, type_, &conn); + + let (enabled, data) = match twofactor { + Some(tf) => (true, serde_json::from_str(&tf.data)?), + _ => (false, DuoData::default()), + }; + + // TODO: It's probably not the best idea to return the keys here + + Ok(Json(json!({ + "Enabled": enabled, + "Host": data.host, + "SecretKey": data.sk, + "IntegrationKey": data.ik, + "Object": "twoFactorDuo" + }))) +} + +#[derive(Deserialize)] +#[allow(non_snake_case)] +struct EnableDuoData { + MasterPasswordHash: String, + Host: String, + SecretKey: String, + IntegrationKey: String, +} + +#[post("/two-factor/duo", data = "")] +fn activate_duo(data: JsonUpcase, headers: Headers, conn: DbConn) -> JsonResult { + let data: EnableDuoData = data.into_inner().data; + + if !headers.user.check_valid_password(&data.MasterPasswordHash) { + err!("Invalid password"); + } + + let data = DuoData { + host: data.Host, + sk: data.SecretKey, + ik: data.IntegrationKey, + ak: BASE64.encode(&crypto::get_random_64()), + }; + + // Validate parameters with the server + duo_api_request("GET", "/auth/v2/check", "", &data)?; + + let data_json = serde_json::to_string(&data)?; + let type_ = TwoFactorType::Duo; + let twofactor = TwoFactor::new(headers.user.uuid.clone(), type_, data_json); + twofactor.save(&conn)?; + + // TODO: It's probably not the best idea to return the keys here + Ok(Json(json!({ + "Enabled": true, + "Host": data.host, + "SecretKey": data.sk, + "IntegrationKey": data.ik, + "Object": "twoFactorDuo" + }))) +} + +#[put("/two-factor/duo", data = "")] +fn activate_duo_put(data: JsonUpcase, headers: Headers, conn: DbConn) -> JsonResult { + activate_duo(data, headers, conn) +} + +fn duo_api_request(method: &str, path: &str, params: &str, data: &DuoData) -> EmptyResult { + const AGENT: &str = "bitwarden_rs:Duo/1.0 (Rust)"; + + use std::str::FromStr; + + use chrono::Utc; + use reqwest::{header::*, Client, Method}; + + let url = format!("https://{}{}", data.host, path); + + let date = Utc::now().to_rfc2822(); + + let username = &data.ik; + let fields = [&date, method, &data.host, path, params]; + let password = crypto::hmac_sign(&data.sk, &fields.join("\n")); + + let m = Method::from_str(method).unwrap_or_default(); + + Client::new() + .request(m, &url) + .basic_auth(username, Some(password)) + .header(USER_AGENT, AGENT) + .header(DATE, date) + .send()? + .error_for_status()?; + + Ok(()) +} + +const DUO_EXPIRE: i64 = 300; +const APP_EXPIRE: i64 = 3600; + +const AUTH_PREFIX: &str = "AUTH"; +const DUO_PREFIX: &str = "TX"; +const APP_PREFIX: &str = "APP"; + +use chrono::Utc; + +pub fn generate_duo_signature(data: &DuoData, email: &str) -> String { + let now = Utc::now().timestamp(); + + let duo_sign = sign_duo_values(&data.sk, email, &data.ik, DUO_PREFIX, now + DUO_EXPIRE); + let app_sign = sign_duo_values(&data.ak, email, &data.ik, APP_PREFIX, now + APP_EXPIRE); + + format!("{}:{}", duo_sign, app_sign) +} + +fn sign_duo_values(key: &str, email: &str, ikey: &str, prefix: &str, expire: i64) -> String { + let val = format!("{}|{}|{}", email, ikey, expire); + let cookie = format!("{}|{}", prefix, BASE64.encode(val.as_bytes())); + + format!("{}|{}", cookie, crypto::hmac_sign(key, &cookie)) +} + +pub fn validate_duo_login(response: &str, twofactor_data: &str) -> EmptyResult { + let data: DuoData = serde_json::from_str(twofactor_data)?; + + let split: Vec<&str> = response.split(":").collect(); + if split.len() != 2 { + err!("Invalid response length"); + } + + let auth_sig = split[0]; + let app_sig = split[1]; + + let now = Utc::now().timestamp(); + + let auth_user = parse_duo_values(&data.sk, auth_sig, &data.ik, AUTH_PREFIX, now)?; + let app_user = parse_duo_values(&data.ak, app_sig, &data.ik, APP_PREFIX, now)?; + + if !crypto::ct_eq(auth_user, app_user) { + err!("Error validating duo authentication") + } + + Ok(()) +} + +fn parse_duo_values(key: &str, val: &str, ikey: &str, prefix: &str, time: i64) -> ApiResult { + let split: Vec<&str> = val.split("|").collect(); + if split.len() != 3 { + err!("Invalid value length") + } + + let u_prefix = split[0]; + let u_b64 = split[1]; + let u_sig = split[2]; + + let sig = crypto::hmac_sign(key, &format!("{}|{}", u_prefix, u_b64)); + + if !crypto::ct_eq(crypto::hmac_sign(key, &sig), crypto::hmac_sign(key, u_sig)) { + err!("Duo signatures don't match") + } + + if u_prefix != prefix { + err!("Prefixes don't match") + } + + let cookie_vec = match BASE64.decode(u_b64.as_bytes()) { + Ok(c) => c, + Err(_) => err!("Invalid Duo cookie encoding"), + }; + + let cookie = match String::from_utf8(cookie_vec) { + Ok(c) => c, + Err(_) => err!("Invalid Duo cookie encoding"), + }; + + let cookie_split: Vec<&str> = cookie.split("|").collect(); + if cookie_split.len() != 3 { + err!("Invalid cookie length") + } + + let username = cookie_split[0]; + let u_ikey = cookie_split[1]; + let expire = cookie_split[2]; + + if !crypto::ct_eq(ikey, u_ikey) { + err!("Invalid ikey") + } + + let expire = match expire.parse() { + Ok(e) => e, + Err(_) => err!("Invalid expire time"), + }; + + if time >= expire { + err!("Expired authorization") + } + + Ok(username.into()) +} diff --git a/src/api/identity.rs b/src/api/identity.rs index 309613f2..b881cbe9 100644 --- a/src/api/identity.rs +++ b/src/api/identity.rs @@ -178,6 +178,7 @@ fn twofactor_auth( Some(TwoFactorType::Authenticator) => _tf::validate_totp_code_str(twofactor_code, &selected_data?)?, Some(TwoFactorType::U2f) => _tf::validate_u2f_login(user_uuid, twofactor_code, conn)?, Some(TwoFactorType::YubiKey) => _tf::validate_yubikey_login(twofactor_code, &selected_data?)?, + Some(TwoFactorType::Duo) => _tf::validate_duo_login(twofactor_code, &selected_data?)?, Some(TwoFactorType::Remember) => { match device.twofactor_remember { @@ -237,13 +238,33 @@ fn _json_err_twofactor(providers: &[i32], user_uuid: &str, conn: &DbConn) -> Api } let mut map = JsonMap::new(); - use serde_json; let challenge_list_str = serde_json::to_string(&challenge_list).unwrap(); map.insert("Challenges".into(), Value::String(challenge_list_str)); result["TwoFactorProviders2"][provider.to_string()] = Value::Object(map); } + Some(tf_type @ TwoFactorType::Duo) => { + let twofactor = match TwoFactor::find_by_user_and_type(user_uuid, tf_type as i32, &conn) { + Some(tf) => tf, + None => err!("No Duo devices registered"), + }; + + let duo_data: two_factor::DuoData = serde_json::from_str(&twofactor.data)?; + + let email = match User::find_by_uuid(user_uuid, &conn) { + Some(u) => u.email, + None => err!("User does not exist") + }; + + let signature = two_factor::generate_duo_signature(&duo_data, &email); + + let mut map = JsonMap::new(); + map.insert("Host".into(), Value::String(duo_data.host)); + map.insert("Signature".into(), Value::String(signature)); + result["TwoFactorProviders2"][provider.to_string()] = Value::Object(map); + } + Some(tf_type @ TwoFactorType::YubiKey) => { let twofactor = match TwoFactor::find_by_user_and_type(user_uuid, tf_type as i32, &conn) { Some(tf) => tf, @@ -251,7 +272,7 @@ fn _json_err_twofactor(providers: &[i32], user_uuid: &str, conn: &DbConn) -> Api }; let yubikey_metadata: two_factor::YubikeyMetadata = - serde_json::from_str(&twofactor.data).expect("Can't parse Yubikey Metadata"); + serde_json::from_str(&twofactor.data)?; let mut map = JsonMap::new(); map.insert("Nfc".into(), Value::Bool(yubikey_metadata.Nfc)); diff --git a/src/crypto.rs b/src/crypto.rs index 628afcd0..4cb46c41 100644 --- a/src/crypto.rs +++ b/src/crypto.rs @@ -19,6 +19,19 @@ pub fn verify_password_hash(secret: &[u8], salt: &[u8], previous: &[u8], iterati pbkdf2::verify(DIGEST_ALG, iterations, salt, secret, previous).is_ok() } +// +// HMAC +// +pub fn hmac_sign(key: &str, data:&str) -> String { + use data_encoding::HEXLOWER; + use ring::{digest, hmac}; + + let key = hmac::SigningKey::new(&digest::SHA1, key.as_bytes()); + let signature = hmac::sign(&key, data.as_bytes()); + + HEXLOWER.encode(signature.as_ref()) +} + // // Random values // From 754087b990807535d4635fb0b7e7a7bad8323b79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa?= Date: Sun, 7 Apr 2019 18:58:15 +0200 Subject: [PATCH 2/7] Add global duo config and document options in .env template --- .env.template | 15 ++++++ src/api/core/two_factor.rs | 93 +++++++++++++++++--------------------- src/api/identity.rs | 54 +++++++++------------- src/config.rs | 20 ++++++++ 4 files changed, 99 insertions(+), 83 deletions(-) diff --git a/.env.template b/.env.template index 578d1e93..7892652e 100644 --- a/.env.template +++ b/.env.template @@ -112,6 +112,21 @@ # YUBICO_SECRET_KEY=AAAAAAAAAAAAAAAAAAAAAAAA # YUBICO_SERVER=http://yourdomain.com/wsapi/2.0/verify +## Duo Settings +## You need to configure all options to enable Duo support +## Create an account and protect an application as mentioned in this link (only the first step, not the rest): +## https://help.bitwarden.com/article/setup-two-step-login-duo/#create-a-duo-security-account +## Then set the following options, based on the values obtained from the last step: +# DUO_IKEY= +# DUO_SKEY= +# DUO_HOST= +## The Aplication Key needs to be randomly generated. Recommended at least 40 characters in base64. +## Example command to generate it: 'openssl rand -base64 48' +## Note that this shouldn't change between runs. +# DUO_AKEY= +## After that, you should be able to follow the rest of the guide linked above, +## ignoring the fields that ask for the values that you already configured beforehand. + ## Rocket specific settings, check Rocket documentation to learn more # ROCKET_ENV=staging # ROCKET_ADDRESS=0.0.0.0 # Enable this to test mobile app diff --git a/src/api/core/two_factor.rs b/src/api/core/two_factor.rs index 31cca499..45258302 100644 --- a/src/api/core/two_factor.rs +++ b/src/api/core/two_factor.rs @@ -717,16 +717,12 @@ pub fn validate_yubikey_login(response: &str, twofactor_data: &str) -> EmptyResu } } -#[derive(Serialize, Deserialize, Default)] -pub struct DuoData { - pub host: String, - sk: String, - ik: String, - ak: String, -} - #[post("/two-factor/get-duo", data = "")] fn get_duo(data: JsonUpcase, headers: Headers, conn: DbConn) -> JsonResult { + if CONFIG.duo_host().is_none() { + err!("Duo is disabled. Refer to the Wiki for instructions in how to enable it") + } + let data: PasswordData = data.into_inner().data; if !headers.user.check_valid_password(&data.MasterPasswordHash) { @@ -736,24 +732,22 @@ fn get_duo(data: JsonUpcase, headers: Headers, conn: DbConn) -> Js let type_ = TwoFactorType::Duo as i32; let twofactor = TwoFactor::find_by_user_and_type(&headers.user.uuid, type_, &conn); - let (enabled, data) = match twofactor { - Some(tf) => (true, serde_json::from_str(&tf.data)?), - _ => (false, DuoData::default()), + let (enabled, msg) = match twofactor { + Some(_) => (true, ""), + _ => (false, ""), }; - // TODO: It's probably not the best idea to return the keys here - Ok(Json(json!({ "Enabled": enabled, - "Host": data.host, - "SecretKey": data.sk, - "IntegrationKey": data.ik, + "Host": msg, + "SecretKey": msg, + "IntegrationKey": msg, "Object": "twoFactorDuo" }))) } #[derive(Deserialize)] -#[allow(non_snake_case)] +#[allow(non_snake_case, dead_code)] struct EnableDuoData { MasterPasswordHash: String, Host: String, @@ -769,27 +763,15 @@ fn activate_duo(data: JsonUpcase, headers: Headers, conn: DbConn) err!("Invalid password"); } - let data = DuoData { - host: data.Host, - sk: data.SecretKey, - ik: data.IntegrationKey, - ak: BASE64.encode(&crypto::get_random_64()), - }; - - // Validate parameters with the server - duo_api_request("GET", "/auth/v2/check", "", &data)?; - - let data_json = serde_json::to_string(&data)?; let type_ = TwoFactorType::Duo; - let twofactor = TwoFactor::new(headers.user.uuid.clone(), type_, data_json); + let twofactor = TwoFactor::new(headers.user.uuid.clone(), type_, String::new()); twofactor.save(&conn)?; - // TODO: It's probably not the best idea to return the keys here Ok(Json(json!({ "Enabled": true, - "Host": data.host, - "SecretKey": data.sk, - "IntegrationKey": data.ik, + "Host": "", + "SecretKey": "", + "IntegrationKey": "", "Object": "twoFactorDuo" }))) } @@ -799,7 +781,8 @@ fn activate_duo_put(data: JsonUpcase, headers: Headers, conn: DbC activate_duo(data, headers, conn) } -fn duo_api_request(method: &str, path: &str, params: &str, data: &DuoData) -> EmptyResult { +// duo_api_request("GET", "/auth/v2/check", "", &data)?; +fn _duo_api_request(method: &str, path: &str, params: &str) -> EmptyResult { const AGENT: &str = "bitwarden_rs:Duo/1.0 (Rust)"; use std::str::FromStr; @@ -807,13 +790,15 @@ fn duo_api_request(method: &str, path: &str, params: &str, data: &DuoData) -> Em use chrono::Utc; use reqwest::{header::*, Client, Method}; - let url = format!("https://{}{}", data.host, path); + let ik = CONFIG.duo_ikey().unwrap(); + let sk = CONFIG.duo_skey().unwrap(); + let host = CONFIG.duo_host().unwrap(); + let url = format!("https://{}{}", host, path); let date = Utc::now().to_rfc2822(); - - let username = &data.ik; - let fields = [&date, method, &data.host, path, params]; - let password = crypto::hmac_sign(&data.sk, &fields.join("\n")); + let username = &ik; + let fields = [&date, method, &host, path, params]; + let password = crypto::hmac_sign(&sk, &fields.join("\n")); let m = Method::from_str(method).unwrap_or_default(); @@ -837,11 +822,15 @@ const APP_PREFIX: &str = "APP"; use chrono::Utc; -pub fn generate_duo_signature(data: &DuoData, email: &str) -> String { +pub fn generate_duo_signature(email: &str) -> String { let now = Utc::now().timestamp(); - let duo_sign = sign_duo_values(&data.sk, email, &data.ik, DUO_PREFIX, now + DUO_EXPIRE); - let app_sign = sign_duo_values(&data.ak, email, &data.ik, APP_PREFIX, now + APP_EXPIRE); + let ik = CONFIG.duo_ikey().unwrap(); + let sk = CONFIG.duo_skey().unwrap(); + let ak = CONFIG.duo_akey().unwrap(); + + let duo_sign = sign_duo_values(&sk, email, &ik, DUO_PREFIX, now + DUO_EXPIRE); + let app_sign = sign_duo_values(&ak, email, &ik, APP_PREFIX, now + APP_EXPIRE); format!("{}:{}", duo_sign, app_sign) } @@ -853,10 +842,8 @@ fn sign_duo_values(key: &str, email: &str, ikey: &str, prefix: &str, expire: i64 format!("{}|{}", cookie, crypto::hmac_sign(key, &cookie)) } -pub fn validate_duo_login(response: &str, twofactor_data: &str) -> EmptyResult { - let data: DuoData = serde_json::from_str(twofactor_data)?; - - let split: Vec<&str> = response.split(":").collect(); +pub fn validate_duo_login(email: &str, response: &str) -> EmptyResult { + let split: Vec<&str> = response.split(':').collect(); if split.len() != 2 { err!("Invalid response length"); } @@ -866,10 +853,14 @@ pub fn validate_duo_login(response: &str, twofactor_data: &str) -> EmptyResult { let now = Utc::now().timestamp(); - let auth_user = parse_duo_values(&data.sk, auth_sig, &data.ik, AUTH_PREFIX, now)?; - let app_user = parse_duo_values(&data.ak, app_sig, &data.ik, APP_PREFIX, now)?; + let ik = CONFIG.duo_ikey().unwrap(); + let sk = CONFIG.duo_skey().unwrap(); + let ak = CONFIG.duo_akey().unwrap(); - if !crypto::ct_eq(auth_user, app_user) { + let auth_user = parse_duo_values(&sk, auth_sig, &ik, AUTH_PREFIX, now)?; + let app_user = parse_duo_values(&ak, app_sig, &ik, APP_PREFIX, now)?; + + if !crypto::ct_eq(&auth_user, app_user) || !crypto::ct_eq(&auth_user, email) { err!("Error validating duo authentication") } @@ -877,7 +868,7 @@ pub fn validate_duo_login(response: &str, twofactor_data: &str) -> EmptyResult { } fn parse_duo_values(key: &str, val: &str, ikey: &str, prefix: &str, time: i64) -> ApiResult { - let split: Vec<&str> = val.split("|").collect(); + let split: Vec<&str> = val.split('|').collect(); if split.len() != 3 { err!("Invalid value length") } @@ -906,7 +897,7 @@ fn parse_duo_values(key: &str, val: &str, ikey: &str, prefix: &str, time: i64) - Err(_) => err!("Invalid Duo cookie encoding"), }; - let cookie_split: Vec<&str> = cookie.split("|").collect(); + let cookie_split: Vec<&str> = cookie.split('|').collect(); if cookie_split.len() != 3 { err!("Invalid cookie length") } diff --git a/src/api/identity.rs b/src/api/identity.rs index b881cbe9..d3535ab7 100644 --- a/src/api/identity.rs +++ b/src/api/identity.rs @@ -9,7 +9,7 @@ use num_traits::FromPrimitive; use crate::db::models::*; use crate::db::DbConn; -use crate::util::{self, JsonMap}; +use crate::util; use crate::api::{ApiResult, EmptyResult, JsonResult}; @@ -178,7 +178,7 @@ fn twofactor_auth( Some(TwoFactorType::Authenticator) => _tf::validate_totp_code_str(twofactor_code, &selected_data?)?, Some(TwoFactorType::U2f) => _tf::validate_u2f_login(user_uuid, twofactor_code, conn)?, Some(TwoFactorType::YubiKey) => _tf::validate_yubikey_login(twofactor_code, &selected_data?)?, - Some(TwoFactorType::Duo) => _tf::validate_duo_login(twofactor_code, &selected_data?)?, + Some(TwoFactorType::Duo) => _tf::validate_duo_login(data.username.as_ref().unwrap(), twofactor_code)?, Some(TwoFactorType::Remember) => { match device.twofactor_remember { @@ -227,42 +227,33 @@ fn _json_err_twofactor(providers: &[i32], user_uuid: &str, conn: &DbConn) -> Api let mut challenge_list = Vec::new(); for key in request.registered_keys { - let mut challenge_map = JsonMap::new(); - - challenge_map.insert("appId".into(), Value::String(request.app_id.clone())); - challenge_map.insert("challenge".into(), Value::String(request.challenge.clone())); - challenge_map.insert("version".into(), Value::String(key.version)); - challenge_map.insert("keyHandle".into(), Value::String(key.key_handle.unwrap_or_default())); - - challenge_list.push(Value::Object(challenge_map)); + challenge_list.push(json!({ + "appId": request.app_id, + "challenge": request.challenge, + "version": key.version, + "keyHandle": key.key_handle, + })); } - let mut map = JsonMap::new(); let challenge_list_str = serde_json::to_string(&challenge_list).unwrap(); - map.insert("Challenges".into(), Value::String(challenge_list_str)); - result["TwoFactorProviders2"][provider.to_string()] = Value::Object(map); + result["TwoFactorProviders2"][provider.to_string()] = json!({ + "Challenges": challenge_list_str, + }); } - Some(tf_type @ TwoFactorType::Duo) => { - let twofactor = match TwoFactor::find_by_user_and_type(user_uuid, tf_type as i32, &conn) { - Some(tf) => tf, - None => err!("No Duo devices registered"), - }; - - let duo_data: two_factor::DuoData = serde_json::from_str(&twofactor.data)?; - + Some(TwoFactorType::Duo) => { let email = match User::find_by_uuid(user_uuid, &conn) { Some(u) => u.email, - None => err!("User does not exist") + None => err!("User does not exist"), }; - let signature = two_factor::generate_duo_signature(&duo_data, &email); + let signature = two_factor::generate_duo_signature(&email); - let mut map = JsonMap::new(); - map.insert("Host".into(), Value::String(duo_data.host)); - map.insert("Signature".into(), Value::String(signature)); - result["TwoFactorProviders2"][provider.to_string()] = Value::Object(map); + result["TwoFactorProviders2"][provider.to_string()] = json!({ + "Host": CONFIG.duo_host(), + "Signature": signature, + }); } Some(tf_type @ TwoFactorType::YubiKey) => { @@ -271,12 +262,11 @@ fn _json_err_twofactor(providers: &[i32], user_uuid: &str, conn: &DbConn) -> Api None => err!("No YubiKey devices registered"), }; - let yubikey_metadata: two_factor::YubikeyMetadata = - serde_json::from_str(&twofactor.data)?; + let yubikey_metadata: two_factor::YubikeyMetadata = serde_json::from_str(&twofactor.data)?; - let mut map = JsonMap::new(); - map.insert("Nfc".into(), Value::Bool(yubikey_metadata.Nfc)); - result["TwoFactorProviders2"][provider.to_string()] = Value::Object(map); + result["TwoFactorProviders2"][provider.to_string()] = json!({ + "Nfc": yubikey_metadata.Nfc, + }) } _ => {} diff --git a/src/config.rs b/src/config.rs index f27afaed..3a7a85f1 100644 --- a/src/config.rs +++ b/src/config.rs @@ -302,6 +302,20 @@ make_config! { yubico_server: String, true, option; }, + /// Duo settings + duo: _enable_duo { + /// Enabled + _enable_duo: bool, true, def, true; + /// Integration Key + duo_ikey: String, true, option; + /// Secret Key + duo_skey: Pass, true, option; + /// Host + duo_host: String, true, option; + /// Application Key + duo_akey: Pass, true, option; + }, + /// SMTP Email Settings smtp: _enable_smtp { /// Enabled @@ -332,6 +346,12 @@ fn validate_config(cfg: &ConfigItems) -> Result<(), Error> { } } + if (cfg.duo_host.is_some() || cfg.duo_ikey.is_some() || cfg.duo_skey.is_some() || cfg.duo_akey.is_some()) + && !(cfg.duo_host.is_some() && cfg.duo_ikey.is_some() && cfg.duo_skey.is_some() && cfg.duo_akey.is_some()) + { + err!("All Duo options need to be set for Duo support") + } + if cfg.yubico_client_id.is_some() != cfg.yubico_secret_key.is_some() { err!("Both `YUBICO_CLIENT_ID` and `YUBICO_SECRET_KEY` need to be set for Yubikey OTP support") } From d89bd707a89f236a3192dba66cf5b6474e4317f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa?= Date: Sun, 7 Apr 2019 18:58:32 +0200 Subject: [PATCH 3/7] Update vault release to show duo button --- Dockerfile | 2 +- Dockerfile.aarch64 | 2 +- Dockerfile.alpine | 2 +- Dockerfile.armv6 | 2 +- Dockerfile.armv7 | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index 7f1adbde..80c43d39 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ ####################### VAULT BUILD IMAGE ####################### FROM alpine as vault -ENV VAULT_VERSION "v2.10.0" +ENV VAULT_VERSION "v2.10.0b" ENV URL "https://github.com/dani-garcia/bw_web_builds/releases/download/$VAULT_VERSION/bw_web_$VAULT_VERSION.tar.gz" diff --git a/Dockerfile.aarch64 b/Dockerfile.aarch64 index 3f42c82d..fa84ce7b 100644 --- a/Dockerfile.aarch64 +++ b/Dockerfile.aarch64 @@ -4,7 +4,7 @@ ####################### VAULT BUILD IMAGE ####################### FROM alpine as vault -ENV VAULT_VERSION "v2.10.0" +ENV VAULT_VERSION "v2.10.0b" ENV URL "https://github.com/dani-garcia/bw_web_builds/releases/download/$VAULT_VERSION/bw_web_$VAULT_VERSION.tar.gz" diff --git a/Dockerfile.alpine b/Dockerfile.alpine index 9c899b8e..06739e73 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -4,7 +4,7 @@ ####################### VAULT BUILD IMAGE ####################### FROM alpine as vault -ENV VAULT_VERSION "v2.10.0" +ENV VAULT_VERSION "v2.10.0b" ENV URL "https://github.com/dani-garcia/bw_web_builds/releases/download/$VAULT_VERSION/bw_web_$VAULT_VERSION.tar.gz" diff --git a/Dockerfile.armv6 b/Dockerfile.armv6 index 4afc4208..a8860c79 100644 --- a/Dockerfile.armv6 +++ b/Dockerfile.armv6 @@ -4,7 +4,7 @@ ####################### VAULT BUILD IMAGE ####################### FROM alpine as vault -ENV VAULT_VERSION "v2.10.0" +ENV VAULT_VERSION "v2.10.0b" ENV URL "https://github.com/dani-garcia/bw_web_builds/releases/download/$VAULT_VERSION/bw_web_$VAULT_VERSION.tar.gz" diff --git a/Dockerfile.armv7 b/Dockerfile.armv7 index 9752b6c0..60c651a3 100644 --- a/Dockerfile.armv7 +++ b/Dockerfile.armv7 @@ -4,7 +4,7 @@ ####################### VAULT BUILD IMAGE ####################### FROM alpine as vault -ENV VAULT_VERSION "v2.10.0" +ENV VAULT_VERSION "v2.10.0b" ENV URL "https://github.com/dani-garcia/bw_web_builds/releases/download/$VAULT_VERSION/bw_web_$VAULT_VERSION.tar.gz" From 621f60729749592ecd734c0bc42ff4437ca70a5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa?= Date: Thu, 11 Apr 2019 15:32:38 +0200 Subject: [PATCH 4/7] Update dependencies and fix some warnings --- Cargo.lock | 135 ++++++++++++++++++++++++++----------- Cargo.toml | 2 +- rust-toolchain | 2 +- src/api/core/two_factor.rs | 1 - src/crypto.rs | 3 +- src/db/models/cipher.rs | 2 - src/db/models/user.rs | 2 - 7 files changed, 98 insertions(+), 49 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b746a06a..1da06f21 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -77,7 +77,7 @@ name = "backtrace-sys" version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -134,7 +134,7 @@ dependencies = [ "oath 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "quoted_printable 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "reqwest 0.9.13 (registry+https://github.com/rust-lang/crates.io-index)", + "reqwest 0.9.14 (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.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -245,7 +245,7 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.34" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -296,6 +296,25 @@ dependencies = [ "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "cookie_store" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cookie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "publicsuffix 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "try_from 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "core-foundation" version = "0.5.1" @@ -397,7 +416,7 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -417,7 +436,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "devise_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -427,7 +446,7 @@ 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.27 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -449,7 +468,7 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -597,6 +616,14 @@ dependencies = [ "backtrace 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "error-chain" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "failure" version = "0.1.5" @@ -612,7 +639,7 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)", "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -646,7 +673,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.52 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -764,7 +791,7 @@ dependencies = [ [[package]] name = "h2" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -832,7 +859,7 @@ dependencies = [ "mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "markup5ever 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -871,13 +898,13 @@ dependencies = [ [[package]] name = "hyper" -version = "0.12.25" +version = "0.12.27" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.26 (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.17 (registry+https://github.com/rust-lang/crates.io-index)", + "h2 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", "http 0.1.17 (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)", @@ -914,7 +941,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.12.25 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.27 (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.12 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -968,7 +995,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.52 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1059,7 +1086,7 @@ name = "libsqlite3-sys" version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (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)", ] @@ -1198,7 +1225,7 @@ name = "miniz_oxide_c_api" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "miniz_oxide 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1331,7 +1358,7 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1404,7 +1431,7 @@ name = "openssl-sys" version = "0.9.43" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1482,7 +1509,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.15.30 (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)", @@ -1518,7 +1545,7 @@ dependencies = [ "pest 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "pest_meta 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1585,6 +1612,18 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "publicsuffix" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "quick-error" version = "1.2.2" @@ -1597,7 +1636,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "quote" -version = "0.6.11" +version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1736,7 +1775,7 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.1.52" +version = "0.1.54" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1769,16 +1808,18 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.9.13" +version = "0.9.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "cookie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cookie_store 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "encoding_rs 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", "http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.12.25 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.27 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-tls 0.3.2 (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.13 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1787,6 +1828,7 @@ dependencies = [ "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "serde_urlencoded 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1801,7 +1843,7 @@ name = "ring" version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1852,7 +1894,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "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.11 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (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.5.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2018,7 +2060,7 @@ version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2155,7 +2197,7 @@ dependencies = [ "phf_generator 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", "phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2190,7 +2232,7 @@ version = "0.15.30" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2208,7 +2250,7 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2232,7 +2274,7 @@ dependencies = [ "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.52 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (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.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2269,7 +2311,7 @@ version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.52 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2286,6 +2328,7 @@ dependencies = [ "tokio-executor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-reactor 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-threadpool 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-trace-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2412,6 +2455,14 @@ name = "try-lock" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "try_from" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "twoway" version = "0.1.8" @@ -2674,7 +2725,7 @@ dependencies = [ "crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "hmac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "reqwest 0.9.13 (registry+https://github.com/rust-lang/crates.io-index)", + "reqwest 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)", "sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "subtle 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2710,13 +2761,14 @@ dependencies = [ "checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" "checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" "checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" -"checksum cc 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)" = "30f813bf45048a18eda9190fd3c6b78644146056740c43172a5a3699118588fd" +"checksum cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)" = "5e5f3fee5eeb60324c2781f1e41286bdee933850fff9b3c672587fed5ec58c83" "checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4" "checksum chashmap 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ff41a3c2c1e39921b9003de14bf0439c7b63a9039637c291e1a64925d8ddfa45" "checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878" "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.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1465f8134efa296b4c19db34d909637cb2bf0f7aaf21299e23e18fa29ac557cf" +"checksum cookie_store 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b0d2f2ecb21dce00e2453268370312978af9b8024020c7a37ae2cc6dbbe64685" "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" @@ -2751,6 +2803,7 @@ dependencies = [ "checksum encoding_index_tests 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569" "checksum encoding_rs 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)" = "4155785c79f2f6701f185eb2e6b4caf0555ec03477cb4c70db67b465311620ed" "checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3" +"checksum error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07e791d3be96241c77c43846b665ef1384606da2cd2a48730abe606a12906e02" "checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" "checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" @@ -2772,7 +2825,7 @@ dependencies = [ "checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592" "checksum generic-array 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe043cf9b85297937897087de81f590361686e1ac2d4d471b45435de5dfb6a6" "checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" -"checksum h2 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "910a5e7be6283a9c91b3982fa5188368c8719cce2a3cf3b86048673bf9d9c36b" +"checksum h2 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "85ab6286db06040ddefb71641b50017c06874614001a134b423783e2db2920bd" "checksum handlebars 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d82e5750d8027a97b9640e3fefa66bbaf852a35228e1c90790efd13c4b09c166" "checksum hmac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bdb5aa9647ba4711e9d6968dc1c810cd23989ed435443ca962e1bf6d8b8b83ff" "checksum hmac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f127a908633569f208325f86f71255d3363c79721d7f9fe31cd5569908819771" @@ -2781,7 +2834,7 @@ dependencies = [ "checksum http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "eed324f0f0daf6ec10c474f150505af2c143f251722bf9dbd1261bd1f2ee2c1a" "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.25 (registry+https://github.com/rust-lang/crates.io-index)" = "7d5b6658b016965ae301fa995306db965c93677880ea70765a84235a96eae896" +"checksum hyper 0.12.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4f2777434f26af6e4ce4fdcdccd3bed9d861d11e87bcbe72c0f51ddaca8ff848" "checksum hyper-sync-rustls 0.3.0-rc.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6d1a443a90413a118ac6739e024f6a5180aa3b3f43f7de65f9d388a961cff19b" "checksum hyper-tls 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3a800d6aa50af4b5850b2b0f659625ce9504df908e9733b635720483be26174f" "checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" @@ -2857,9 +2910,10 @@ dependencies = [ "checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c" "checksum precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" "checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915" +"checksum publicsuffix 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5afecba86dcf1e4fd610246f89899d1924fe12e1e89f555eb7c7f710f3c5ad1d" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" -"checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1" +"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db" "checksum quoted_printable 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4126fa98c6d7b166e6a29a24ab96721d618759d803df6a8cb35d6140da475b5a" "checksum r2d2 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9dd8a293251281a4d02848925fcdbbc9f466ddb4965981bb06680359b3d12091" "checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" @@ -2874,11 +2928,11 @@ dependencies = [ "checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -"checksum redox_syscall 0.1.52 (registry+https://github.com/rust-lang/crates.io-index)" = "d32b3053e5ced86e4bc0411fec997389532bf56b000e66cb4884eeeb41413d69" +"checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252" "checksum regex 1.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "559008764a17de49a3146b234641644ed37d118d1ef641a0bb573d146edc6ce0" "checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96" "checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" -"checksum reqwest 0.9.13 (registry+https://github.com/rust-lang/crates.io-index)" = "3c4ef83e0beb14bfe38b9f01330a5bc8e965a9f9628690aa28383746dac1e925" +"checksum reqwest 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)" = "19c4c4990514fbd7a80380b826d81368ba6f6af61007ea142519ce47d72f6b0f" "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)" = "" "checksum rmpv 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29af0205707de955a396a1d3c657677c65f791ebabb63c0596c0b2fec0bf6325" @@ -2946,6 +3000,7 @@ dependencies = [ "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 try_from 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "283d3b89e1368717881a9d51dad843cc435380d8109c9e47d38780a324698d8b" "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 typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" diff --git a/Cargo.toml b/Cargo.toml index 1e844fa8..3e2cff37 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ rocket = { version = "0.4.0", features = ["tls"], default-features = false } rocket_contrib = "0.4.0" # HTTP client -reqwest = "0.9.13" +reqwest = "0.9.14" # multipart/form-data support multipart = { version = "0.16.1", features = ["server"], default-features = false } diff --git a/rust-toolchain b/rust-toolchain index 66f6c4e6..ec48b525 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2019-03-14 +nightly-2019-04-11 diff --git a/src/api/core/two_factor.rs b/src/api/core/two_factor.rs index 45258302..94cbc1e7 100644 --- a/src/api/core/two_factor.rs +++ b/src/api/core/two_factor.rs @@ -787,7 +787,6 @@ fn _duo_api_request(method: &str, path: &str, params: &str) -> EmptyResult { use std::str::FromStr; - use chrono::Utc; use reqwest::{header::*, Client, Method}; let ik = CONFIG.duo_ikey().unwrap(); diff --git a/src/crypto.rs b/src/crypto.rs index 4cb46c41..e55e461b 100644 --- a/src/crypto.rs +++ b/src/crypto.rs @@ -2,7 +2,7 @@ // PBKDF2 derivation // -use ring::{digest, pbkdf2}; +use ring::{digest, pbkdf2, hmac}; static DIGEST_ALG: &digest::Algorithm = &digest::SHA256; const OUTPUT_LEN: usize = digest::SHA256_OUTPUT_LEN; @@ -24,7 +24,6 @@ pub fn verify_password_hash(secret: &[u8], salt: &[u8], previous: &[u8], iterati // pub fn hmac_sign(key: &str, data:&str) -> String { use data_encoding::HEXLOWER; - use ring::{digest, hmac}; let key = hmac::SigningKey::new(&digest::SHA1, key.as_bytes()); let signature = hmac::sign(&key, data.as_bytes()); diff --git a/src/db/models/cipher.rs b/src/db/models/cipher.rs index 47d2784a..21cabb90 100644 --- a/src/db/models/cipher.rs +++ b/src/db/models/cipher.rs @@ -72,9 +72,7 @@ use crate::error::MapResult; /// Database methods impl Cipher { pub fn to_json(&self, host: &str, user_uuid: &str, conn: &DbConn) -> Value { - use super::Attachment; use crate::util::format_date; - use serde_json; let attachments = Attachment::find_by_cipher(&self.uuid, conn); let attachments_json: Vec = attachments.iter().map(|c| c.to_json(host)).collect(); diff --git a/src/db/models/user.rs b/src/db/models/user.rs index 91d018d7..cde12afa 100644 --- a/src/db/models/user.rs +++ b/src/db/models/user.rs @@ -113,8 +113,6 @@ use crate::error::MapResult; /// Database methods impl User { pub fn to_json(&self, conn: &DbConn) -> Value { - use super::{TwoFactor, UserOrganization}; - let orgs = UserOrganization::find_by_user(&self.uuid, conn); let orgs_json: Vec = orgs.iter().map(|c| c.to_json(&conn)).collect(); let twofactor_enabled = !TwoFactor::find_by_user(&self.uuid, conn).is_empty(); From bf446f44f97a5f9df7c7c274e5d78981b6b2287c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa?= Date: Thu, 11 Apr 2019 15:41:13 +0200 Subject: [PATCH 5/7] Enable DATA_FOLDER to affect default CONFIG_FILE path --- src/config.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/config.rs b/src/config.rs index 3a7a85f1..309b65ae 100644 --- a/src/config.rs +++ b/src/config.rs @@ -9,7 +9,10 @@ lazy_static! { println!("Error loading config:\n\t{:?}\n", e); exit(12) }); - pub static ref CONFIG_FILE: String = get_env("CONFIG_FILE").unwrap_or_else(|| "data/config.json".into()); + pub static ref CONFIG_FILE: String = { + let data_folder = get_env("DATA_FOLDER").unwrap_or_else(|| String::from("data")); + get_env("CONFIG_FILE").unwrap_or_else(|| format!("{}/config.json", data_folder)) + }; } pub type Pass = String; From cad63f97616ac4f003a65543860c49e75b32a08c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa?= Date: Thu, 11 Apr 2019 16:08:26 +0200 Subject: [PATCH 6/7] Auto generate akey --- src/api/core/two_factor.rs | 17 +++++++++----- src/config.rs | 46 +++++++++++++++++++++++++++----------- 2 files changed, 44 insertions(+), 19 deletions(-) diff --git a/src/api/core/two_factor.rs b/src/api/core/two_factor.rs index 94cbc1e7..1849f035 100644 --- a/src/api/core/two_factor.rs +++ b/src/api/core/two_factor.rs @@ -821,12 +821,19 @@ const APP_PREFIX: &str = "APP"; use chrono::Utc; +// let (ik, sk, ak) = get_duo_keys(); +fn get_duo_keys() -> (String, String, String) { + ( + CONFIG.duo_ikey().unwrap(), + CONFIG.duo_skey().unwrap(), + CONFIG.get_duo_akey(), + ) +} + pub fn generate_duo_signature(email: &str) -> String { let now = Utc::now().timestamp(); - let ik = CONFIG.duo_ikey().unwrap(); - let sk = CONFIG.duo_skey().unwrap(); - let ak = CONFIG.duo_akey().unwrap(); + let (ik, sk, ak) = get_duo_keys(); let duo_sign = sign_duo_values(&sk, email, &ik, DUO_PREFIX, now + DUO_EXPIRE); let app_sign = sign_duo_values(&ak, email, &ik, APP_PREFIX, now + APP_EXPIRE); @@ -852,9 +859,7 @@ pub fn validate_duo_login(email: &str, response: &str) -> EmptyResult { let now = Utc::now().timestamp(); - let ik = CONFIG.duo_ikey().unwrap(); - let sk = CONFIG.duo_skey().unwrap(); - let ak = CONFIG.duo_akey().unwrap(); + let (ik, sk, ak) = get_duo_keys(); let auth_user = parse_duo_values(&sk, auth_sig, &ik, AUTH_PREFIX, now)?; let app_user = parse_duo_values(&ak, app_sig, &ik, APP_PREFIX, now)?; diff --git a/src/config.rs b/src/config.rs index 309b65ae..d40eecae 100644 --- a/src/config.rs +++ b/src/config.rs @@ -9,7 +9,7 @@ lazy_static! { println!("Error loading config:\n\t{:?}\n", e); exit(12) }); - pub static ref CONFIG_FILE: String = { + pub static ref CONFIG_FILE: String = { let data_folder = get_env("DATA_FOLDER").unwrap_or_else(|| String::from("data")); get_env("CONFIG_FILE").unwrap_or_else(|| format!("{}/config.json", data_folder)) }; @@ -64,7 +64,7 @@ macro_rules! make_config { /// Merges the values of both builders into a new builder. /// If both have the same element, `other` wins. - fn merge(&self, other: &Self) -> Self { + fn merge(&self, other: &Self, show_overrides: bool) -> Self { let mut overrides = Vec::new(); let mut builder = self.clone(); $($( @@ -77,7 +77,7 @@ macro_rules! make_config { } )+)+ - if !overrides.is_empty() { + if show_overrides && !overrides.is_empty() { // We can't use warn! here because logging isn't setup yet. println!("[WARNING] The following environment variables are being overriden by the config file,"); println!("[WARNING] please use the admin panel to make changes to them:"); @@ -315,8 +315,8 @@ make_config! { duo_skey: Pass, true, option; /// Host duo_host: String, true, option; - /// Application Key - duo_akey: Pass, true, option; + /// Application Key (generated automatically) + _duo_akey: Pass, false, option; }, /// SMTP Email Settings @@ -349,10 +349,10 @@ fn validate_config(cfg: &ConfigItems) -> Result<(), Error> { } } - if (cfg.duo_host.is_some() || cfg.duo_ikey.is_some() || cfg.duo_skey.is_some() || cfg.duo_akey.is_some()) - && !(cfg.duo_host.is_some() && cfg.duo_ikey.is_some() && cfg.duo_skey.is_some() && cfg.duo_akey.is_some()) + if (cfg.duo_host.is_some() || cfg.duo_ikey.is_some() || cfg.duo_skey.is_some()) + && !(cfg.duo_host.is_some() && cfg.duo_ikey.is_some() && cfg.duo_skey.is_some()) { - err!("All Duo options need to be set for Duo support") + err!("All Duo options need to be set for global Duo support") } if cfg.yubico_client_id.is_some() != cfg.yubico_secret_key.is_some() { @@ -377,7 +377,7 @@ impl Config { let _usr = ConfigBuilder::from_file(&CONFIG_FILE).unwrap_or_default(); // Create merged config, config file overwrites env - let builder = _env.merge(&_usr); + let builder = _env.merge(&_usr, true); // Fill any missing with defaults let config = builder.build(); @@ -406,7 +406,7 @@ impl Config { // Prepare the combined config let config = { let env = &self.inner.read().unwrap()._env; - env.merge(&builder).build() + env.merge(&builder, false).build() }; validate_config(&config)?; @@ -425,6 +425,14 @@ impl Config { Ok(()) } + pub fn update_config_partial(&self, other: ConfigBuilder) -> Result<(), Error> { + let builder = { + let usr = &self.inner.read().unwrap()._usr; + usr.merge(&other, false) + }; + self.update_config(builder) + } + pub fn delete_user_config(&self) -> Result<(), Error> { crate::util::delete_file(&CONFIG_FILE)?; @@ -460,9 +468,21 @@ impl Config { let inner = &self.inner.read().unwrap().config; inner._enable_smtp && inner.smtp_host.is_some() } - pub fn yubico_enabled(&self) -> bool { - let inner = &self.inner.read().unwrap().config; - inner._enable_yubico && inner.yubico_client_id.is_some() && inner.yubico_secret_key.is_some() + + pub fn get_duo_akey(&self) -> String { + if let Some(akey) = self._duo_akey() { + akey + } else { + let akey = crate::crypto::get_random_64(); + let akey_s = data_encoding::BASE64.encode(&akey); + + // Save the new value + let mut builder = ConfigBuilder::default(); + builder._duo_akey = Some(akey_s.clone()); + self.update_config_partial(builder).ok(); + + akey_s + } } pub fn render_template( From 8d9827c55f28372598360a7607a8b9b5ccd2cd18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa?= Date: Thu, 11 Apr 2019 18:40:03 +0200 Subject: [PATCH 7/7] Implement selection between global config and user settings for duo keys. --- src/api/core/two_factor.rs | 204 +++++++++++++++++++++++++++++-------- src/api/identity.rs | 4 +- src/config.rs | 4 +- src/error.rs | 15 +++ 4 files changed, 179 insertions(+), 48 deletions(-) diff --git a/src/api/core/two_factor.rs b/src/api/core/two_factor.rs index 1849f035..f5ab09d3 100644 --- a/src/api/core/two_factor.rs +++ b/src/api/core/two_factor.rs @@ -717,33 +717,102 @@ pub fn validate_yubikey_login(response: &str, twofactor_data: &str) -> EmptyResu } } +#[derive(Serialize, Deserialize)] +struct DuoData { + host: String, + ik: String, + sk: String, +} + +impl DuoData { + fn global() -> Option { + match CONFIG.duo_host() { + Some(host) => Some(Self { + host, + ik: CONFIG.duo_ikey().unwrap(), + sk: CONFIG.duo_skey().unwrap(), + }), + None => None, + } + + } + fn msg(s: &str) -> Self { + Self { + host: s.into(), + ik: s.into(), + sk: s.into(), + } + } + fn secret() -> Self { + Self::msg("") + } + fn obscure(self) -> Self { + let mut host = self.host; + let mut ik = self.ik; + let mut sk = self.sk; + + let digits = 4; + let replaced = "************"; + + host.replace_range(digits.., replaced); + ik.replace_range(digits.., replaced); + sk.replace_range(digits.., replaced); + + Self { host, ik, sk } + } +} + + +enum DuoStatus { + Global(DuoData), // Using the global duo config + User(DuoData), // Using the user's config + Disabled(bool), // True if there is a global setting +} + +impl DuoStatus { + fn data(self) -> Option { + match self { + DuoStatus::Global(data) => Some(data), + DuoStatus::User(data) => Some(data), + DuoStatus::Disabled(_) => None, + } + } +} +const DISABLED_MESSAGE_DEFAULT: &str = ""; + #[post("/two-factor/get-duo", data = "")] fn get_duo(data: JsonUpcase, headers: Headers, conn: DbConn) -> JsonResult { - if CONFIG.duo_host().is_none() { - err!("Duo is disabled. Refer to the Wiki for instructions in how to enable it") - } - let data: PasswordData = data.into_inner().data; if !headers.user.check_valid_password(&data.MasterPasswordHash) { err!("Invalid password"); } - let type_ = TwoFactorType::Duo as i32; - let twofactor = TwoFactor::find_by_user_and_type(&headers.user.uuid, type_, &conn); + let data = get_user_duo_data(&headers.user.uuid, &conn); - let (enabled, msg) = match twofactor { - Some(_) => (true, ""), - _ => (false, ""), + let (enabled, data) = match data { + DuoStatus::Global(_) => (true, Some(DuoData::secret())), + DuoStatus::User(data) => (true, Some(data.obscure())), + DuoStatus::Disabled(true) => (false, Some(DuoData::msg(DISABLED_MESSAGE_DEFAULT))), + DuoStatus::Disabled(false) => (false, None), }; - Ok(Json(json!({ - "Enabled": enabled, - "Host": msg, - "SecretKey": msg, - "IntegrationKey": msg, - "Object": "twoFactorDuo" - }))) + let json = if let Some(data) = data { + json!({ + "Enabled": enabled, + "Host": data.host, + "SecretKey": data.sk, + "IntegrationKey": data.ik, + "Object": "twoFactorDuo" + }) + } else { + json!({ + "Enabled": enabled, + "Object": "twoFactorDuo" + }) + }; + + Ok(Json(json)) } #[derive(Deserialize)] @@ -755,6 +824,25 @@ struct EnableDuoData { IntegrationKey: String, } +impl From for DuoData { + fn from(d: EnableDuoData) -> Self { + Self { + host: d.Host, + ik: d.IntegrationKey, + sk: d.SecretKey, + } + } +} + +fn check_duo_fields_custom(data: &EnableDuoData) -> bool { + fn empty_or_default(s: &str) -> bool { + let st = s.trim(); + st.is_empty() || s == DISABLED_MESSAGE_DEFAULT + } + + !empty_or_default(&data.Host) && !empty_or_default(&data.SecretKey) && !empty_or_default(&data.IntegrationKey) +} + #[post("/two-factor/duo", data = "")] fn activate_duo(data: JsonUpcase, headers: Headers, conn: DbConn) -> JsonResult { let data: EnableDuoData = data.into_inner().data; @@ -763,15 +851,24 @@ fn activate_duo(data: JsonUpcase, headers: Headers, conn: DbConn) err!("Invalid password"); } + let (data, data_str) = if check_duo_fields_custom(&data) { + let data_req: DuoData = data.into(); + let data_str = serde_json::to_string(&data_req)?; + //duo_api_request("GET", "/auth/v2/check", "", &data_req).map_res("Failed to validate Duo credentials")?; + (data_req.obscure(), data_str) + } else { + (DuoData::secret(), String::new()) + }; + let type_ = TwoFactorType::Duo; - let twofactor = TwoFactor::new(headers.user.uuid.clone(), type_, String::new()); + let twofactor = TwoFactor::new(headers.user.uuid.clone(), type_, data_str); twofactor.save(&conn)?; Ok(Json(json!({ "Enabled": true, - "Host": "", - "SecretKey": "", - "IntegrationKey": "", + "Host": data.host, + "SecretKey": data.sk, + "IntegrationKey": data.ik, "Object": "twoFactorDuo" }))) } @@ -781,23 +878,17 @@ fn activate_duo_put(data: JsonUpcase, headers: Headers, conn: DbC activate_duo(data, headers, conn) } -// duo_api_request("GET", "/auth/v2/check", "", &data)?; -fn _duo_api_request(method: &str, path: &str, params: &str) -> EmptyResult { +fn duo_api_request(method: &str, path: &str, params: &str, data: &DuoData) -> EmptyResult { const AGENT: &str = "bitwarden_rs:Duo/1.0 (Rust)"; + use reqwest::{header::*, Client, Method}; use std::str::FromStr; - use reqwest::{header::*, Client, Method}; - - let ik = CONFIG.duo_ikey().unwrap(); - let sk = CONFIG.duo_skey().unwrap(); - let host = CONFIG.duo_host().unwrap(); - - let url = format!("https://{}{}", host, path); + let url = format!("https://{}{}", &data.host, path); let date = Utc::now().to_rfc2822(); - let username = &ik; - let fields = [&date, method, &host, path, params]; - let password = crypto::hmac_sign(&sk, &fields.join("\n")); + let username = &data.ik; + let fields = [&date, method, &data.host, path, params]; + let password = crypto::hmac_sign(&data.sk, &fields.join("\n")); let m = Method::from_str(method).unwrap_or_default(); @@ -821,24 +912,49 @@ const APP_PREFIX: &str = "APP"; use chrono::Utc; -// let (ik, sk, ak) = get_duo_keys(); -fn get_duo_keys() -> (String, String, String) { - ( - CONFIG.duo_ikey().unwrap(), - CONFIG.duo_skey().unwrap(), - CONFIG.get_duo_akey(), - ) + +fn get_user_duo_data(uuid: &str, conn: &DbConn) -> DuoStatus { + let type_ = TwoFactorType::Duo as i32; + + // If the user doesn't have an entry, disabled + let twofactor = match TwoFactor::find_by_user_and_type(uuid, type_, &conn) { + Some(t) => t, + None => return DuoStatus::Disabled(DuoData::global().is_some()), + }; + + // If the user has the required values, we use those + if let Ok(data) = serde_json::from_str(&twofactor.data) { + return DuoStatus::User(data); + } + + // Otherwise, we try to use the globals + if let Some(global) = DuoData::global() { + return DuoStatus::Global(global); + } + + // If there are no globals configured, just disable it + DuoStatus::Disabled(false) } -pub fn generate_duo_signature(email: &str) -> String { +// let (ik, sk, ak) = get_duo_keys(); +fn get_duo_keys_email(email: &str, conn: &DbConn) -> ApiResult<(String, String, String)> { + let data = User::find_by_mail(email, &conn) + .and_then(|u| get_user_duo_data(&u.uuid, &conn).data()) + .or_else(|| DuoData::global()) + .map_res("Can't fetch Duo keys")?; + + Ok((data.ik, data.sk, CONFIG.get_duo_akey())) +} + +pub fn generate_duo_signature(email: &str, conn: &DbConn) -> ApiResult { let now = Utc::now().timestamp(); - let (ik, sk, ak) = get_duo_keys(); + let (ik, sk, ak) = get_duo_keys_email(email, conn)?; let duo_sign = sign_duo_values(&sk, email, &ik, DUO_PREFIX, now + DUO_EXPIRE); let app_sign = sign_duo_values(&ak, email, &ik, APP_PREFIX, now + APP_EXPIRE); - format!("{}:{}", duo_sign, app_sign) + Ok(format!("{}:{}", duo_sign, app_sign)) } fn sign_duo_values(key: &str, email: &str, ikey: &str, prefix: &str, expire: i64) -> String { @@ -848,7 +964,7 @@ fn sign_duo_values(key: &str, email: &str, ikey: &str, prefix: &str, expire: i64 format!("{}|{}", cookie, crypto::hmac_sign(key, &cookie)) } -pub fn validate_duo_login(email: &str, response: &str) -> EmptyResult { +pub fn validate_duo_login(email: &str, response: &str, conn: &DbConn) -> EmptyResult { let split: Vec<&str> = response.split(':').collect(); if split.len() != 2 { err!("Invalid response length"); @@ -859,7 +975,7 @@ pub fn validate_duo_login(email: &str, response: &str) -> EmptyResult { let now = Utc::now().timestamp(); - let (ik, sk, ak) = get_duo_keys(); + let (ik, sk, ak) = get_duo_keys_email(email, conn)?; let auth_user = parse_duo_values(&sk, auth_sig, &ik, AUTH_PREFIX, now)?; let app_user = parse_duo_values(&ak, app_sig, &ik, APP_PREFIX, now)?; diff --git a/src/api/identity.rs b/src/api/identity.rs index d3535ab7..3e7b526b 100644 --- a/src/api/identity.rs +++ b/src/api/identity.rs @@ -178,7 +178,7 @@ fn twofactor_auth( Some(TwoFactorType::Authenticator) => _tf::validate_totp_code_str(twofactor_code, &selected_data?)?, Some(TwoFactorType::U2f) => _tf::validate_u2f_login(user_uuid, twofactor_code, conn)?, Some(TwoFactorType::YubiKey) => _tf::validate_yubikey_login(twofactor_code, &selected_data?)?, - Some(TwoFactorType::Duo) => _tf::validate_duo_login(data.username.as_ref().unwrap(), twofactor_code)?, + Some(TwoFactorType::Duo) => _tf::validate_duo_login(data.username.as_ref().unwrap(), twofactor_code, conn)?, Some(TwoFactorType::Remember) => { match device.twofactor_remember { @@ -248,7 +248,7 @@ fn _json_err_twofactor(providers: &[i32], user_uuid: &str, conn: &DbConn) -> Api None => err!("User does not exist"), }; - let signature = two_factor::generate_duo_signature(&email); + let signature = two_factor::generate_duo_signature(&email, conn)?; result["TwoFactorProviders2"][provider.to_string()] = json!({ "Host": CONFIG.duo_host(), diff --git a/src/config.rs b/src/config.rs index d40eecae..6fb3c92f 100644 --- a/src/config.rs +++ b/src/config.rs @@ -305,10 +305,10 @@ make_config! { yubico_server: String, true, option; }, - /// Duo settings + /// Global Duo settings (Note that users can override them) duo: _enable_duo { /// Enabled - _enable_duo: bool, true, def, true; + _enable_duo: bool, true, def, false; /// Integration Key duo_ikey: String, true, option; /// Secret Key diff --git a/src/error.rs b/src/error.rs index be8907e0..5f99db4e 100644 --- a/src/error.rs +++ b/src/error.rs @@ -41,6 +41,8 @@ use regex::Error as RegexErr; use reqwest::Error as ReqErr; use serde_json::{Error as SerdeErr, Value}; use std::io::Error as IOErr; + +use std::option::NoneError as NoneErr; use std::time::SystemTimeError as TimeErr; use u2f::u2ferror::U2fError as U2fErr; use yubico::yubicoerror::YubicoError as YubiErr; @@ -73,6 +75,13 @@ make_error! { YubiError(YubiErr): _has_source, _api_error, } +// This is implemented by hand because NoneError doesn't implement neither Display nor Error +impl From for Error { + fn from(_: NoneErr) -> Self { + Error::from(("NoneError", String::new())) + } +} + impl std::fmt::Debug for Error { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self.source() { @@ -118,6 +127,12 @@ impl> MapResult<()> for Result { } } +impl MapResult for Option { + fn map_res(self, msg: &str) -> Result { + self.ok_or_else(|| Error::new(msg, "")) + } +} + fn _has_source(e: T) -> Option { Some(e) }