commit dae92b9018f2870592592feb4a1e951955a44a36
parent dde7c0d99bd262cc11efad2d9e52fac37fc6a1c1
Author: Daniel GarcĂa <dani-garcia@users.noreply.github.com>
Date: Thu, 12 Jul 2018 21:46:50 +0200
Implemented U2F, refactored Two Factor authentication, registering U2F device and authentication should work. Works on Chrome on MacOS with a virtual device.
Diffstat:
17 files changed, 822 insertions(+), 273 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -31,6 +31,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "base64"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "base64"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
@@ -70,15 +78,18 @@ dependencies = [
"lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libsqlite3-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
"multipart 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-derive 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"oath 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
"reqwest 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)",
"ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rocket 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rocket_codegen 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rocket_contrib 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.68 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.68 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "u2f 0.1.2 (git+https://github.com/wisespace-io/u2f-rs?rev=193de35093a44)",
"uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -117,7 +128,7 @@ dependencies = [
[[package]]
name = "cc"
-version = "1.0.17"
+version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -162,7 +173,7 @@ dependencies = [
"base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
- "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -325,7 +336,7 @@ dependencies = [
[[package]]
name = "dtoa"
-version = "0.4.2"
+version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -450,7 +461,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "futures"
-version = "0.1.21"
+version = "0.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -458,7 +469,7 @@ name = "futures-cpupool"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -511,7 +522,7 @@ dependencies = [
"traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -521,13 +532,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"base64 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
"bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"httparse 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "mime 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mime 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
"percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"relay 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -555,7 +566,7 @@ name = "hyper-tls"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper 0.11.27 (registry+https://github.com/rust-lang/crates.io-index)",
"native-tls 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -566,7 +577,7 @@ dependencies = [
[[package]]
name = "idna"
-version = "0.1.4"
+version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -595,7 +606,7 @@ dependencies = [
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"plugin 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"typemap 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -610,7 +621,7 @@ dependencies = [
[[package]]
name = "itoa"
-version = "0.4.1"
+version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -621,8 +632,8 @@ dependencies = [
"chrono 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.68 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.68 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
"untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -663,7 +674,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libflate"
-version = "0.1.15"
+version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -676,7 +687,7 @@ name = "libsqlite3-sys"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
"vcpkg 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -686,12 +697,12 @@ name = "log"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "log"
-version = "0.4.2"
+version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -751,7 +762,7 @@ dependencies = [
[[package]]
name = "mime"
-version = "0.3.7"
+version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -773,7 +784,7 @@ name = "mime_guess"
version = "2.0.0-alpha.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "mime 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mime 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"phf 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)",
"phf_codegen 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)",
"unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -781,7 +792,7 @@ dependencies = [
[[package]]
name = "mio"
-version = "0.6.14"
+version = "0.6.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -790,7 +801,7 @@ dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -822,8 +833,8 @@ dependencies = [
"httparse 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)",
"iron 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "mime 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mime 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"mime_guess 2.0.0-alpha.5 (registry+https://github.com/rust-lang/crates.io-index)",
"nickel 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
"quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -883,7 +894,7 @@ dependencies = [
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
"typemap 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -902,6 +913,17 @@ dependencies = [
]
[[package]]
+name = "num-derive"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "num-integer"
version = "0.1.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -960,7 +982,7 @@ name = "openssl-sys"
version = "0.9.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
"vcpkg 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -981,7 +1003,7 @@ name = "pear_codegen"
version = "0.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"yansi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1086,7 +1108,7 @@ version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"scheduled-thread-pool 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1180,7 +1202,7 @@ name = "relay"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1198,20 +1220,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"encoding_rs 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper 0.11.27 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper-tls 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "libflate 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libflate 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"mime_guess 2.0.0-alpha.5 (registry+https://github.com/rust-lang/crates.io-index)",
"native-tls 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.68 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_urlencoded 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1248,8 +1270,8 @@ dependencies = [
"state 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"yansi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1260,7 +1282,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"rocket 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
- "version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"yansi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1271,7 +1293,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"rocket 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.68 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1352,17 +1374,17 @@ dependencies = [
[[package]]
name = "serde"
-version = "1.0.68"
+version = "1.0.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde_derive"
-version = "1.0.68"
+version = "1.0.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1370,9 +1392,9 @@ name = "serde_json"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.68 (registry+https://github.com/rust-lang/crates.io-index)",
+ "dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1380,10 +1402,10 @@ name = "serde_urlencoded"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.68 (registry+https://github.com/rust-lang/crates.io-index)",
- "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1462,7 +1484,7 @@ dependencies = [
[[package]]
name = "syn"
-version = "0.14.2"
+version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1538,14 +1560,14 @@ name = "tokio"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
- "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-fs 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-fs 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-reactor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-tcp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-threadpool 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-threadpool 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-timer 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-udp 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1556,7 +1578,7 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1566,10 +1588,10 @@ version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
"scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1583,17 +1605,17 @@ name = "tokio-executor"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tokio-fs"
-version = "0.1.1"
+version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "tokio-threadpool 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-threadpool 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1602,8 +1624,8 @@ version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1611,7 +1633,7 @@ name = "tokio-proto"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1628,9 +1650,9 @@ name = "tokio-reactor"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1641,7 +1663,7 @@ name = "tokio-service"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1650,21 +1672,21 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-reactor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tokio-threadpool"
-version = "0.1.4"
+version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crossbeam-deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1675,7 +1697,7 @@ name = "tokio-timer"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1684,7 +1706,7 @@ name = "tokio-tls"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
"native-tls 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1696,9 +1718,9 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-codec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-reactor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1709,7 +1731,7 @@ name = "toml"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "serde 1.0.68 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1749,6 +1771,24 @@ version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "u2f"
+version = "0.1.2"
+source = "git+https://github.com/wisespace-io/u2f-rs?rev=193de35093a44#193de35093a44576edba6cc94d9b54f2a1cbdcd1"
+dependencies = [
+ "base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "chrono 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "webpki 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "ucd-util"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1758,7 +1798,7 @@ name = "unicase"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1766,7 +1806,7 @@ name = "unicase"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1825,10 +1865,10 @@ dependencies = [
[[package]]
name = "url"
-version = "1.7.0"
+version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1863,7 +1903,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "version_check"
-version = "0.1.3"
+version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -1876,8 +1916,8 @@ name = "want"
version = "0.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"try-lock 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1892,6 +1932,15 @@ dependencies = [
]
[[package]]
+name = "webpki"
+version = "0.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "webpki-roots"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1949,6 +1998,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34fde25430d87a9388dadbe6e34d7f72a462c8b43ac8d309b42b0a8505d7e2a5"
"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef"
"checksum ascii 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae7d751998c189c1d4468cf0a39bb2eae052a9c58d50ebb3b9591ee3813ad50"
+"checksum base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "30e93c03064e7590d0466209155251b90c22e37fab1daf2771582598b5827557"
"checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9"
"checksum base64 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "85415d2594767338a74a30c1d370b2f3262ec1b4ed2d7bba5b3faf4de40467d9"
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
@@ -1958,7 +2008,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum byte-tools 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0919189ba800c7ffe8778278116b7e0de3905ab81c72abb69c85cbfef7991279"
"checksum byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74c0b906e9446b0a2e4f760cdb3fa4b2c48cdc6db8766a845c54b6ff063fd2e9"
"checksum bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7dd32989a66957d3f0cba6588f15d4281a733f4e9ffc43fcd2385f57d3bf99ff"
-"checksum cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "49ec142f5768efb5b7622aebc3fdbdbb8950a4b9ba996393cb76ef7466e8747d"
+"checksum cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "2119ea4867bd2b8ed3aecab467709720b2d55b1bcfe09f772fd68066eaf15275"
"checksum cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efe5c877e17a9c717a0bf3613b2709f723202c4e4675cc8f12926ded29bcb17e"
"checksum chrono 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)" = "9213f7cd7c27e95c2b57c49f0e69b1ea65b27138da84a170133fd21b07659c00"
"checksum chrono 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6962c635d530328acc53ac6a955e83093fedc91c5809dfac1fa60fa470830a37"
@@ -1982,7 +2032,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum digest 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7a68d759d7a66a4f63d5bd2a2b14ad7e8cf93fe8c9be227031cd4e72ab0e9ee8"
"checksum digest-buffer 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4eb92364e9f6d3da159257250532d448b218406d2acb149f724e8f48e9f5cb9a"
"checksum dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0d0a1279c96732bc6800ce6337b6a614697b0e74ae058dc03c62ebeb78b4d86"
-"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
+"checksum dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6d301140eb411af13d3115f9a562c85cc6b541ade9dfa314132244aaee7489dd"
"checksum encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "6b0d943856b990d12d3b55b359144ff341533e516d94098b1d3fc1ac666d36ec"
"checksum encoding-index-japanese 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)" = "04e8b2ff42e9a05335dbf8b5c6f7567e5591d0d916ccef4e0b1710d32a0d0c91"
"checksum encoding-index-korean 1.20141219.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4dc33fb8e6bcba213fe2f14275f0963fd16f0a02c878e3095ecfdf5bee529d81"
@@ -1999,7 +2049,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
-"checksum futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "1a70b146671de62ec8c8ed572219ca5d594d9b06c0b364d5e67b722fc559b48c"
+"checksum futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "80599c995ed197a276e27c27f94a6346446538adde3b87c1ab384f6f8cabfed4"
"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4"
"checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb"
"checksum generic-array 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe043cf9b85297937897087de81f590361686e1ac2d4d471b45435de5dfb6a6"
@@ -2010,21 +2060,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum hyper 0.11.27 (registry+https://github.com/rust-lang/crates.io-index)" = "34a590ca09d341e94cddf8e5af0bbccde205d5fbc2fa3c09dd67c7f85cea59d7"
"checksum hyper-sync-rustls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c6df6f419a9f116cc93b5f39a5ded1161e088a2c8424c8fcd1d4049193424a4"
"checksum hyper-tls 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a5aa51f6ae9842239b0fac14af5f22123b8432b4cc774a44ff059fcba0f675ca"
-"checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d"
+"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e"
"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
"checksum iron 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d8e17268922834707e1c29e8badbf9c712c9c43378e1b6a3388946baff10be2"
"checksum isatty 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6c324313540cd4d7ba008d43dc6606a32a5579f13cc17b2804c13096f0a5c522"
-"checksum itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c069bbec61e1ca5a596166e55dfe4773ff745c3d16b700013bcaff9a6df2c682"
+"checksum itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5adb58558dcd1d786b5f0bd15f3226ee23486e24b7b58304b60f64dc68e62606"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
"checksum lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e6412c5e2ad9584b0b8e979393122026cdd6d2a80b933f890dcd694ddbe73739"
"checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef"
"checksum libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" = "b685088df2b950fccadf07a7187c8ef846a959c142338a48f9dc0b94517eb5f1"
-"checksum libflate 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "f70a41040e4ed915b462ffb9c8dd20ece3700565aa5e2e163288a0f7ca00487a"
+"checksum libflate 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "7d4b4c7aff5bac19b956f693d0ea0eade8066deb092186ae954fa6ba14daab98"
"checksum libsqlite3-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0e9eb7b8e152b6a01be6a4a2917248381875758250dc3df5d46caf9250341dda"
"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
-"checksum log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6fddaa003a65722a7fb9e26b0ce95921fe4ba590542ced664d8ce2fa26f9f3ac"
+"checksum log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "61bd98ae7f7b754bc53dca7d44b604f733c6bba044ea6f41bc8d89272d8161d2"
"checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376"
"checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a"
"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d"
@@ -2032,10 +2082,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum migrations_internals 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8cf7c8c4f83fa9f47440c0b4af99973502de55e6e7b875f693bd263e03f93e7e"
"checksum migrations_macros 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "79f12499ef7353bdeca2d081bc61edd8351dac09a33af845952009b5a3d68c1a"
"checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0"
-"checksum mime 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0b28683d0b09bbc20be1c9b3f6f24854efb1356ffcffee08ea3f6e65596e85fa"
+"checksum mime 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "fe51c8699d2dc522bf8c1ebe26ea2193d151fb54bcdfd7d0318750c189994cd9"
"checksum mime_guess 1.8.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7287ba93031813826d8974566e54eb5e49d4473752f7df21c610dab289aee8cb"
"checksum mime_guess 2.0.0-alpha.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d1a78b5e2283080d5a8ba68216171b4fe34f6ccdd909bb29be16ce8a9a831341"
-"checksum mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)" = "6d771e3ef92d58a8da8df7d6976bfca9371ed1de6619d9d5a5ce5b1f29b85bfe"
+"checksum mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)" = "4fcfcb32d63961fb6f367bfd5d21e4600b92cd310f71f9dca25acae196eb1560"
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
"checksum modifier 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "41f5c9112cb662acd3b204077e0de5bc66305fa8df65c8019d5adb10e9ab6e58"
"checksum multipart 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1720cbd59d1cbcc184b66f2f74a3287caf524764eee5a8fbb3f5f0e469cd5c00"
@@ -2045,6 +2095,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum nickel 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "22b40e35b9f46a076dcbd8193125cea0e4130b1c015f68655038010f3e826e04"
"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2"
"checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e"
+"checksum num-derive 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0d2c31b75c36a993d30c7a13d70513cb93f02acafdd5b7ba250f9b0e18615de7"
"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
"checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124"
"checksum num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "630de1ef5cc79d0cdd78b7e33b81f083cbfe90de0f4b2b2f07f905867c70e9fe"
@@ -2095,8 +2146,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
"checksum security-framework 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "dfa44ee9c54ce5eecc9de7d5acbad112ee58755239381f687e564004ba4a2332"
"checksum security-framework-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "5421621e836278a0b139268f36eee0dc7e389b784dc3f79d8f11aabadf41bead"
-"checksum serde 1.0.68 (registry+https://github.com/rust-lang/crates.io-index)" = "429fcc4efa8a11341b5422c2ace724daba276c1748467e869478f53c0ba4562e"
-"checksum serde_derive 1.0.68 (registry+https://github.com/rust-lang/crates.io-index)" = "6a25ad0bf818ed2d180c89addbe29198d1de6c89ed08a48aa6a4d3d16a63cbfe"
+"checksum serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)" = "0c3adf19c07af6d186d91dae8927b83b0553d07ca56cbf7f2f32560455c91920"
+"checksum serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)" = "3525a779832b08693031b8ecfb0de81cd71cfd3812088fafe9a7496789572124"
"checksum serde_json 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)" = "84b8035cabe9b35878adec8ac5fe03d5f6bc97ff6edd7ccb96b44c1276ba390e"
"checksum serde_urlencoded 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e703cef904312097cfceab9ce131ff6bbe09e8c964a0703345a5f49238757bc1"
"checksum sha-1 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8347606816471548cd60f0abd5ef0d513a81f5202dbdab9c09f17a15b5248484"
@@ -2109,7 +2160,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum state 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7345c971d1ef21ffdbd103a75990a15eb03604fc8b8852ca8cb418ee1a099028"
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
"checksum syn 0.13.11 (registry+https://github.com/rust-lang/crates.io-index)" = "14f9bf6292f3a61d2c716723fdb789a41bbe104168e6f496dc6497e531ea1b9b"
-"checksum syn 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c67da57e61ebc7b7b6fff56bb34440ca3a83db037320b0507af4c10368deda7d"
+"checksum syn 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)" = "2beff8ebc3658f07512a413866875adddd20f4fd47b2a4e6c9da65cd281baaea"
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
"checksum synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a761d12e6d8dcb4dcf952a7a89b475e3a9d69e4a69307e01a470977642914bd"
"checksum take 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b157868d8ac1f56b64604539990685fa7611d8fa9e5476cf0c02cf34d32917c5"
@@ -2121,13 +2172,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum tokio-codec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "881e9645b81c2ce95fcb799ded2c29ffb9f25ef5bef909089a420e5961dd8ccb"
"checksum tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "aeeffbbb94209023feaef3c196a41cbcdafa06b4a6f893f68779bb5e53796f71"
"checksum tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8cac2a7883ff3567e9d66bb09100d09b33d90311feca0206c7ca034bc0c55113"
-"checksum tokio-fs 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fc42bae2f6e33865b99069d95bcddfc85c9f0849b4e7e7399eeee71956ef34d7"
+"checksum tokio-fs 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "40697ecbea5660df15b15d50a077386477d2f6a35002adf01ce76ff9dd9dce48"
"checksum tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a5c9635ee806f26d302b8baa1e145689a280d8f5aa8d0552e7344808da54cc21"
"checksum tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8fbb47ae81353c63c487030659494b295f6cb6576242f907f203473b191b0389"
"checksum tokio-reactor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e00ec63bbec2c97ce1178cb0587b2c438b2f6b09d3ee54a33c45a9cf0d530810"
"checksum tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24da22d077e0f15f55162bdbdc661228c1581892f52074fb242678d015b45162"
"checksum tokio-tcp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ec9b094851aadd2caf83ba3ad8e8c4ce65a42104f7b94d9e6550023f0407853f"
-"checksum tokio-threadpool 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c3873a6d8d0b636e024e77b9a82eaab6739578a06189ecd0e731c7308fbc5d"
+"checksum tokio-threadpool 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "24ab84f574027b0e875378f31575cf175360891919e93a3490f07e76e00e4efb"
"checksum tokio-timer 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "028b94314065b90f026a21826cffd62a4e40a92cda3e5c069cc7b02e5945f5e9"
"checksum tokio-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "772f4b04e560117fe3b0a53e490c16ddc8ba6ec437015d91fa385564996ed913"
"checksum tokio-udp 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "43eb534af6e8f37d43ab1b612660df14755c42bd003c5f8d2475ee78cc4600c0"
@@ -2138,6 +2189,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887"
"checksum typemap 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "653be63c80a3296da5551e1bfd2cca35227e13cdd08c6668903ae2f4f77aa1f6"
"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
+"checksum u2f 0.1.2 (git+https://github.com/wisespace-io/u2f-rs?rev=193de35093a44)" = "<none>"
"checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d"
"checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33"
"checksum unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284b6d3db520d67fbe88fd778c21510d1b0ba4a551e5d0fbb023d33405f6de8a"
@@ -2149,15 +2201,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum unsafe-any 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f30360d7979f5e9c6e6cea48af192ea8fab4afb3cf72597154b8f08935bc9c7f"
"checksum untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f392d7819dbe58833e26872f5f6f0d68b7bbbe90fc3667e98731c4a15ad9a7ae"
"checksum url 0.2.38 (registry+https://github.com/rust-lang/crates.io-index)" = "cbaa8377a162d88e7d15db0cf110c8523453edcbc5bc66d2b6fffccffa34a068"
-"checksum url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f808aadd8cfec6ef90e4a14eb46f24511824d1ac596b9682703c87056c8678b7"
+"checksum url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a321979c09843d272956e73700d12c4e7d3d92b2ee112b31548aef0d4efc5a6"
"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
"checksum uuid 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "78c590b5bd79ed10aad8fb75f078a59d8db445af6c743e55c4a53227fc01c13f"
"checksum uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e1436e58182935dcd9ce0add9ea0b558e8a87befe01c1a301e6020aeb0876363"
"checksum vcpkg 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cbe533e138811704c0e3cbde65a818b35d3240409b4346256c5ede403e082474"
-"checksum version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6b772017e347561807c1aa192438c5fd74242a670a6cffacc40f2defd1dc069d"
+"checksum version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7716c242968ee87e5542f8021178248f267f295a5c4803beae8b8b7fd9bc6051"
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
"checksum want 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a05d9d966753fa4b5c8db73fcab5eed4549cfe0e1e4e66911e5564a0085c35d1"
"checksum webpki 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e499345fc4c6b7c79a5b8756d4592c4305510a13512e79efafe00dfbd67bbac6"
+"checksum webpki 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "493012e46177f3f4ee9cd58fd0c81ecb77e6d6cc6ebce55989b9c33376fbe5ee"
"checksum webpki-roots 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5bfb3f50499f21ad2317f442845e3b5805b007f1e728f59885c99e61b8c181a7"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "773ef9dcc5f24b7d850d0ff101e542ff24c3b090a9768e03ff889fdef41f00fd"
diff --git a/Cargo.toml b/Cargo.toml
@@ -16,8 +16,8 @@ reqwest = "0.8.6"
multipart = "0.14.2"
# A generic serialization/deserialization framework
-serde = "1.0.68"
-serde_derive = "1.0.68"
+serde = "1.0.70"
+serde_derive = "1.0.70"
serde_json = "1.0.22"
# A safe, extensible ORM and Query builder
@@ -45,11 +45,22 @@ data-encoding = "2.1.1"
# JWT library
jsonwebtoken = "= 4.0.1"
+# U2F library
+u2f = "0.1.2"
+
# A `dotenv` implementation for Rust
dotenv = { version = "0.13.0", default-features = false }
# Lazy static macro
lazy_static = "1.0.1"
+# Numerical libraries
+num-traits = "0.2.5"
+num-derive = "0.2.2"
+
[patch.crates-io]
-jsonwebtoken = { path = "libs/jsonwebtoken" } # Make jwt use ring 0.11, to match rocket
+ # Make jwt use ring 0.11, to match rocket
+jsonwebtoken = { path = "libs/jsonwebtoken" }
+
+# Version 0.1.2 from crates.io lacks a commit that fixes a certificate error
+u2f = { git = 'https://github.com/wisespace-io/u2f-rs', rev = '193de35093a44' }
+\ No newline at end of file
diff --git a/migrations/2018-07-11-181453_create_u2f_twofactor/down.sql b/migrations/2018-07-11-181453_create_u2f_twofactor/down.sql
@@ -0,0 +1,8 @@
+UPDATE users
+SET totp_secret = (
+ SELECT twofactor.data FROM twofactor
+ WHERE twofactor.type = 0
+ AND twofactor.user_uuid = users.uuid
+);
+
+DROP TABLE twofactor;
+\ No newline at end of file
diff --git a/migrations/2018-07-11-181453_create_u2f_twofactor/up.sql b/migrations/2018-07-11-181453_create_u2f_twofactor/up.sql
@@ -0,0 +1,15 @@
+CREATE TABLE twofactor (
+ uuid TEXT NOT NULL PRIMARY KEY,
+ user_uuid TEXT NOT NULL REFERENCES users (uuid),
+ type INTEGER NOT NULL,
+ enabled BOOLEAN NOT NULL,
+ data TEXT NOT NULL,
+
+ UNIQUE (user_uuid, type)
+);
+
+
+INSERT INTO twofactor (uuid, user_uuid, type, enabled, data)
+SELECT lower(hex(randomblob(16))) , uuid, 0, 1, u.totp_secret FROM users u where u.totp_secret IS NOT NULL;
+
+UPDATE users SET totp_secret = NULL; -- Instead of recreating the table, just leave the columns empty
+\ No newline at end of file
diff --git a/src/api/core/mod.rs b/src/api/core/mod.rs
@@ -2,7 +2,7 @@ mod accounts;
mod ciphers;
mod folders;
mod organizations;
-mod two_factor;
+pub(crate) mod two_factor;
use self::accounts::*;
use self::ciphers::*;
@@ -58,9 +58,11 @@ pub fn routes() -> Vec<Route> {
get_twofactor,
get_recover,
recover,
+ disable_twofactor,
generate_authenticator,
activate_authenticator,
- disable_authenticator,
+ generate_u2f,
+ activate_u2f,
get_organization,
create_organization,
diff --git a/src/api/core/two_factor.rs b/src/api/core/two_factor.rs
@@ -1,28 +1,24 @@
-use rocket_contrib::{Json, Value};
-
use data_encoding::BASE32;
+use rocket_contrib::{Json, Value};
+use serde_json;
-use db::DbConn;
+use db::{
+ models::{TwoFactor, TwoFactorType, User},
+ DbConn,
+};
use crypto;
-use api::{PasswordData, JsonResult, NumberOrString, JsonUpcase};
+use api::{ApiResult, JsonResult, JsonUpcase, NumberOrString, PasswordData};
use auth::Headers;
#[get("/two-factor")]
-fn get_twofactor(headers: Headers) -> JsonResult {
- let data = if headers.user.totp_secret.is_none() {
- Value::Null
- } else {
- json!([{
- "Enabled": true,
- "Type": 0,
- "Object": "twoFactorProvider"
- }])
- };
+fn get_twofactor(headers: Headers, conn: DbConn) -> JsonResult {
+ let twofactors = TwoFactor::find_by_user(&headers.user.uuid, &conn);
+ let twofactors_json: Vec<Value> = twofactors.iter().map(|c| c.to_json_list()).collect();
Ok(Json(json!({
- "Data": data,
+ "Data": twofactors_json,
"Object": "list"
})))
}
@@ -58,7 +54,7 @@ fn recover(data: JsonUpcase<RecoverTwoFactor>, conn: DbConn) -> JsonResult {
// Get the user
let mut user = match User::find_by_mail(&data.Email, &conn) {
Some(user) => user,
- None => err!("Username or password is incorrect. Try again.")
+ None => err!("Username or password is incorrect. Try again."),
};
// Check password
@@ -71,24 +67,69 @@ fn recover(data: JsonUpcase<RecoverTwoFactor>, conn: DbConn) -> JsonResult {
err!("Recovery code is incorrect. Try again.")
}
- user.totp_secret = None;
+ // Remove all twofactors from the user
+ for twofactor in TwoFactor::find_by_user(&user.uuid, &conn) {
+ twofactor.delete(&conn).expect("Error deleting twofactor");
+ }
+
+ // Remove the recovery code, not needed without twofactors
user.totp_recover = None;
user.save(&conn);
Ok(Json(json!({})))
}
+#[derive(Deserialize)]
+#[allow(non_snake_case)]
+struct DisableTwoFactorData {
+ MasterPasswordHash: String,
+ Type: NumberOrString,
+}
+
+#[post("/two-factor/disable", data = "<data>")]
+fn disable_twofactor(
+ data: JsonUpcase<DisableTwoFactorData>,
+ headers: Headers,
+ conn: DbConn,
+) -> JsonResult {
+ let data: DisableTwoFactorData = data.into_inner().data;
+ let password_hash = data.MasterPasswordHash;
+
+ if !headers.user.check_valid_password(&password_hash) {
+ err!("Invalid password");
+ }
+
+ let type_ = data.Type.into_i32().expect("Invalid type");
+
+ if let Some(twofactor) = TwoFactor::find_by_user_and_type(&headers.user.uuid, type_, &conn) {
+ twofactor.delete(&conn).expect("Error deleting twofactor");
+ }
+
+ Ok(Json(json!({
+ "Enabled": false,
+ "Type": type_,
+ "Object": "twoFactorProvider"
+ })))
+}
+
#[post("/two-factor/get-authenticator", data = "<data>")]
-fn generate_authenticator(data: JsonUpcase<PasswordData>, headers: Headers) -> JsonResult {
+fn generate_authenticator(
+ data: JsonUpcase<PasswordData>,
+ headers: Headers,
+ conn: DbConn,
+) -> JsonResult {
let data: PasswordData = data.into_inner().data;
if !headers.user.check_valid_password(&data.MasterPasswordHash) {
err!("Invalid password");
}
- let (enabled, key) = match headers.user.totp_secret {
- Some(secret) => (true, secret),
- _ => (false, BASE32.encode(&crypto::get_random(vec![0u8; 20])))
+ let type_ = TwoFactorType::Authenticator as i32;
+ let twofactor = TwoFactor::find_by_user_and_type(&headers.user.uuid, type_, &conn);
+
+ let (enabled, key) = match twofactor {
+ Some(tf) => (true, tf.data),
+ _ => (false, BASE32.encode(&crypto::get_random(vec![0u8; 20]))),
};
Ok(Json(json!({
@@ -100,20 +141,24 @@ fn generate_authenticator(data: JsonUpcase<PasswordData>, headers: Headers) -> J
#[derive(Deserialize, Debug)]
#[allow(non_snake_case)]
-struct EnableTwoFactorData {
+struct EnableAuthenticatorData {
MasterPasswordHash: String,
Key: String,
Token: NumberOrString,
}
#[post("/two-factor/authenticator", data = "<data>")]
-fn activate_authenticator(data: JsonUpcase<EnableTwoFactorData>, headers: Headers, conn: DbConn) -> JsonResult {
- let data: EnableTwoFactorData = data.into_inner().data;
+fn activate_authenticator(
+ data: JsonUpcase<EnableAuthenticatorData>,
+ headers: Headers,
+ conn: DbConn,
+) -> JsonResult {
+ let data: EnableAuthenticatorData = data.into_inner().data;
let password_hash = data.MasterPasswordHash;
let key = data.Key;
let token = match data.Token.into_i32() {
Some(n) => n as u64,
- None => err!("Malformed token")
+ None => err!("Malformed token"),
};
if !headers.user.check_valid_password(&password_hash) {
@@ -123,27 +168,24 @@ fn activate_authenticator(data: JsonUpcase<EnableTwoFactorData>, headers: Header
// Validate key as base32 and 20 bytes length
let decoded_key: Vec<u8> = match BASE32.decode(key.as_bytes()) {
Ok(decoded) => decoded,
- _ => err!("Invalid totp secret")
+ _ => err!("Invalid totp secret"),
};
if decoded_key.len() != 20 {
err!("Invalid key length")
}
- // Set key in user.totp_secret
- let mut user = headers.user;
- user.totp_secret = Some(key.to_uppercase());
+ let type_ = TwoFactorType::Authenticator;
+ let twofactor = TwoFactor::new(headers.user.uuid.clone(), type_, key.to_uppercase());
// Validate the token provided with the key
- if !user.check_totp_code(token) {
+ if !twofactor.check_totp_code(token) {
err!("Invalid totp code")
}
- // Generate totp_recover
- let totp_recover = BASE32.encode(&crypto::get_random(vec![0u8; 20]));
- user.totp_recover = Some(totp_recover);
-
- user.save(&conn);
+ let mut user = headers.user;
+ _generate_recover_code(&mut user, &conn);
+ twofactor.save(&conn).expect("Error saving twofactor");
Ok(Json(json!({
"Enabled": true,
@@ -152,32 +194,228 @@ fn activate_authenticator(data: JsonUpcase<EnableTwoFactorData>, headers: Header
})))
}
-#[derive(Deserialize)]
-#[allow(non_snake_case)]
-struct DisableTwoFactorData {
- MasterPasswordHash: String,
- Type: NumberOrString,
+fn _generate_recover_code(user: &mut User, conn: &DbConn) {
+ if user.totp_recover.is_none() {
+ let totp_recover = BASE32.encode(&crypto::get_random(vec![0u8; 20]));
+ user.totp_recover = Some(totp_recover);
+ user.save(conn);
+ }
}
-#[post("/two-factor/disable", data = "<data>")]
-fn disable_authenticator(data: JsonUpcase<DisableTwoFactorData>, headers: Headers, conn: DbConn) -> JsonResult {
- let data: DisableTwoFactorData = data.into_inner().data;
- let password_hash = data.MasterPasswordHash;
- let _type = data.Type;
+use u2f::messages::{RegisterResponse, SignResponse, U2fSignRequest};
+use u2f::protocol::{Challenge, U2f};
+use u2f::register::Registration;
- if !headers.user.check_valid_password(&password_hash) {
+use CONFIG;
+
+const U2F_VERSION: &str = "U2F_V2";
+
+lazy_static! {
+ static ref APP_ID: String = format!("{}/app-id.json", &CONFIG.domain);
+ static ref U2F: U2f = U2f::new(APP_ID.clone());
+}
+
+#[post("/two-factor/get-u2f", data = "<data>")]
+fn generate_u2f(data: JsonUpcase<PasswordData>, headers: Headers, conn: DbConn) -> JsonResult {
+ let data: PasswordData = data.into_inner().data;
+
+ if !headers.user.check_valid_password(&data.MasterPasswordHash) {
err!("Invalid password");
}
- let mut user = headers.user;
- user.totp_secret = None;
- user.totp_recover = None;
+ let user_uuid = &headers.user.uuid;
- user.save(&conn);
+ let u2f_type = TwoFactorType::U2f as i32;
+ let register_type = TwoFactorType::U2fRegisterChallenge;
+ let (enabled, challenge) = match TwoFactor::find_by_user_and_type(user_uuid, u2f_type, &conn) {
+ Some(_) => (true, String::new()),
+ None => {
+ let c = _create_u2f_challenge(user_uuid, register_type, &conn);
+ (false, c.challenge)
+ }
+ };
Ok(Json(json!({
- "Enabled": false,
- "Type": 0,
- "Object": "twoFactorProvider"
+ "Enabled": enabled,
+ "Challenge": {
+ "UserId": headers.user.uuid,
+ "AppId": APP_ID.to_string(),
+ "Challenge": challenge,
+ "Version": U2F_VERSION,
+ },
+ "Object": "twoFactorU2f"
})))
}
+
+#[derive(Deserialize, Debug)]
+#[allow(non_snake_case)]
+struct EnableU2FData {
+ MasterPasswordHash: String,
+ DeviceResponse: String,
+}
+
+#[post("/two-factor/u2f", data = "<data>")]
+fn activate_u2f(data: JsonUpcase<EnableU2FData>, headers: Headers, conn: DbConn) -> JsonResult {
+ let data: EnableU2FData = data.into_inner().data;
+
+ if !headers.user.check_valid_password(&data.MasterPasswordHash) {
+ err!("Invalid password");
+ }
+
+ let tf_challenge = TwoFactor::find_by_user_and_type(
+ &headers.user.uuid,
+ TwoFactorType::U2fRegisterChallenge as i32,
+ &conn,
+ );
+
+ if let Some(tf_challenge) = tf_challenge {
+ let challenge: Challenge = serde_json::from_str(&tf_challenge.data).unwrap();
+ tf_challenge
+ .delete(&conn)
+ .expect("Error deleting U2F register challenge");
+
+ let response: RegisterResponse = serde_json::from_str(&data.DeviceResponse).unwrap();
+
+ match U2F.register_response(challenge.clone(), response) {
+ Ok(registration) => {
+ // TODO: Allow more than one U2F device
+ let mut registrations = Vec::new();
+ registrations.push(registration);
+
+ let tf_registration = TwoFactor::new(
+ headers.user.uuid.clone(),
+ TwoFactorType::U2f,
+ serde_json::to_string(®istrations).unwrap(),
+ );
+ tf_registration
+ .save(&conn)
+ .expect("Error saving U2F registration");
+
+ let mut user = headers.user;
+ _generate_recover_code(&mut user, &conn);
+
+ Ok(Json(json!({
+ "Enabled": true,
+ "Challenge": {
+ "UserId": user.uuid,
+ "AppId": APP_ID.to_string(),
+ "Challenge": challenge,
+ "Version": U2F_VERSION,
+ },
+ "Object": "twoFactorU2f"
+ })))
+ }
+ Err(e) => {
+ println!("Error: {:#?}", e);
+ err!("Error activating u2f")
+ }
+ }
+ } else {
+ err!("Can't recover challenge")
+ }
+}
+
+fn _create_u2f_challenge(user_uuid: &str, type_: TwoFactorType, conn: &DbConn) -> Challenge {
+ let challenge = U2F.generate_challenge().unwrap();
+
+ TwoFactor::new(
+ user_uuid.into(),
+ type_,
+ serde_json::to_string(&challenge).unwrap(),
+ ).save(conn)
+ .expect("Error saving challenge");
+
+ challenge
+}
+
+// This struct is copied from the U2F lib
+// because it doesn't implement Deserialize
+#[derive(Serialize, Deserialize, Clone)]
+#[serde(rename_all = "camelCase")]
+pub struct RegistrationCopy {
+ pub key_handle: Vec<u8>,
+ pub pub_key: Vec<u8>,
+ pub attestation_cert: Option<Vec<u8>>,
+}
+
+impl Into<Registration> for RegistrationCopy {
+ fn into(self) -> Registration {
+ Registration {
+ key_handle: self.key_handle,
+ pub_key: self.pub_key,
+ attestation_cert: self.attestation_cert,
+ }
+ }
+}
+
+fn _parse_registrations(registations: &str) -> Vec<Registration> {
+ let registrations_copy: Vec<RegistrationCopy> = serde_json::from_str(registations).unwrap();
+
+ registrations_copy.into_iter().map(Into::into).collect()
+}
+
+pub fn generate_u2f_login(user_uuid: &str, conn: &DbConn) -> ApiResult<U2fSignRequest> {
+ let challenge = _create_u2f_challenge(user_uuid, TwoFactorType::U2fLoginChallenge, conn);
+
+ let type_ = TwoFactorType::U2f as i32;
+ let twofactor = match TwoFactor::find_by_user_and_type(user_uuid, type_, conn) {
+ Some(tf) => tf,
+ None => err!("No U2F devices registered"),
+ };
+
+ let registrations = _parse_registrations(&twofactor.data);
+ let signed_request: U2fSignRequest = U2F.sign_request(challenge, registrations);
+
+ Ok(signed_request)
+}
+
+pub fn validate_u2f_login(user_uuid: &str, response: &str, conn: &DbConn) -> ApiResult<()> {
+ let challenge_type = TwoFactorType::U2fLoginChallenge as i32;
+ let u2f_type = TwoFactorType::U2f as i32;
+
+ let tf_challenge = TwoFactor::find_by_user_and_type(user_uuid, challenge_type, &conn);
+
+ let challenge = match tf_challenge {
+ Some(tf_challenge) => {
+ let challenge: Challenge = serde_json::from_str(&tf_challenge.data).unwrap();
+ tf_challenge
+ .delete(&conn)
+ .expect("Error deleting U2F login challenge");
+ challenge
+ }
+ None => err!("Can't recover login challenge"),
+ };
+
+ let twofactor = match TwoFactor::find_by_user_and_type(user_uuid, u2f_type, conn) {
+ Some(tf) => tf,
+ None => err!("No U2F devices registered"),
+ };
+
+ let registrations = _parse_registrations(&twofactor.data);
+
+ println!("response {:#?}", response);
+
+ let response: SignResponse = serde_json::from_str(response).unwrap();
+
+ println!("client_data {:#?}", response.client_data);
+ println!("key_handle {:#?}", response.key_handle);
+ println!("signature_data {:#?}", response.signature_data);
+
+ let mut _counter: u32 = 0;
+ for registration in registrations {
+ let response =
+ U2F.sign_response(challenge.clone(), registration, response.clone(), _counter);
+ match response {
+ Ok(new_counter) => {
+ _counter = new_counter;
+ println!("O {:#}", new_counter);
+ return Ok(());
+ }
+ Err(e) => {
+ println!("E {:#}", e);
+ break;
+ }
+ }
+ }
+ err!("error verifying response")
+}
diff --git a/src/api/identity.rs b/src/api/identity.rs
@@ -1,19 +1,21 @@
use std::collections::HashMap;
-use rocket::{Route, Outcome};
-use rocket::request::{self, Request, FromRequest, Form, FormItems, FromForm};
+use rocket::request::{self, Form, FormItems, FromForm, FromRequest, Request};
+use rocket::{Outcome, Route};
use rocket_contrib::{Json, Value};
-use db::DbConn;
+use num_traits::FromPrimitive;
+
use db::models::*;
+use db::DbConn;
-use util;
+use util::{self, JsonMap};
-use api::JsonResult;
+use api::{ApiResult, JsonResult};
pub fn routes() -> Vec<Route> {
- routes![ login]
+ routes![login]
}
#[post("/connect/token", data = "<connect_data>")]
@@ -21,8 +23,8 @@ fn login(connect_data: Form<ConnectData>, device_type: DeviceType, conn: DbConn)
let data = connect_data.get();
match data.grant_type {
- GrantType::RefreshToken =>_refresh_login(data, device_type, conn),
- GrantType::Password => _password_login(data, device_type, conn)
+ GrantType::RefreshToken => _refresh_login(data, device_type, conn),
+ GrantType::Password => _password_login(data, device_type, conn),
}
}
@@ -33,7 +35,7 @@ fn _refresh_login(data: &ConnectData, _device_type: DeviceType, conn: DbConn) ->
// Get device by refresh token
let mut device = match Device::find_by_refresh_token(token, &conn) {
Some(device) => device,
- None => err!("Invalid refresh token")
+ None => err!("Invalid refresh token"),
};
// COMMON
@@ -64,7 +66,7 @@ fn _password_login(data: &ConnectData, device_type: DeviceType, conn: DbConn) ->
let username = data.get("username");
let user = match User::find_by_mail(username, &conn) {
Some(user) => user,
- None => err!("Username or password is incorrect. Try again.")
+ None => err!("Username or password is incorrect. Try again."),
};
// Check password
@@ -72,7 +74,7 @@ fn _password_login(data: &ConnectData, device_type: DeviceType, conn: DbConn) ->
if !user.check_valid_password(password) {
err!("Username or password is incorrect. Try again.")
}
-
+
// Let's only use the header and ignore the 'devicetype' parameter
let device_type_num = device_type.0;
@@ -102,42 +104,7 @@ fn _password_login(data: &ConnectData, device_type: DeviceType, conn: DbConn) ->
}
};
- let twofactor_token = if user.requires_twofactor() {
- let twofactor_provider = util::parse_option_string(data.get_opt("twoFactorProvider")).unwrap_or(0);
- let twofactor_code = match data.get_opt("twoFactorToken") {
- Some(code) => code,
- None => err_json!(_json_err_twofactor())
- };
-
- match twofactor_provider {
- 0 /* TOTP */ => {
- let totp_code: u64 = match twofactor_code.parse() {
- Ok(code) => code,
- Err(_) => err!("Invalid Totp code")
- };
-
- if !user.check_totp_code(totp_code) {
- err_json!(_json_err_twofactor())
- }
-
- if util::parse_option_string(data.get_opt("twoFactorRemember")).unwrap_or(0) == 1 {
- device.refresh_twofactor_remember();
- device.twofactor_remember.clone()
- } else {
- device.delete_twofactor_remember();
- None
- }
- },
- 5 /* Remember */ => {
- match device.twofactor_remember {
- Some(ref remember) if remember == twofactor_code => (),
- _ => err_json!(_json_err_twofactor())
- };
- None // No twofactor token needed here
- },
- _ => err!("Invalid two factor provider"),
- }
- } else { None }; // No twofactor token if twofactor is disabled
+ let twofactor_token = twofactor_auth(&user.uuid, &data, &mut device, &conn)?;
// Common
let user = User::find_by_uuid(&device.user_uuid, &conn).unwrap();
@@ -163,13 +130,124 @@ fn _password_login(data: &ConnectData, device_type: DeviceType, conn: DbConn) ->
Ok(Json(result))
}
-fn _json_err_twofactor() -> Value {
- json!({
+fn twofactor_auth(
+ user_uuid: &str,
+ data: &ConnectData,
+ device: &mut Device,
+ conn: &DbConn,
+) -> ApiResult<Option<String>> {
+ let twofactors_raw = TwoFactor::find_by_user(user_uuid, conn);
+ // Remove u2f challenge twofactors (impl detail)
+ let twofactors: Vec<_> = twofactors_raw.iter().filter(|tf| tf.type_ < 1000).collect();
+
+ let providers: Vec<_> = twofactors.iter().map(|tf| tf.type_).collect();
+
+ // No twofactor token if twofactor is disabled
+ if twofactors.len() == 0 {
+ return Ok(None);
+ }
+
+ let provider = match util::parse_option_string(data.get_opt("twoFactorProvider")) {
+ Some(provider) => provider,
+ None => providers[0], // If we aren't given a two factor provider, asume the first one
+ };
+
+ let twofactor_code = match data.get_opt("twoFactorToken") {
+ Some(code) => code,
+ None => err_json!(_json_err_twofactor(&providers, user_uuid, conn)?),
+ };
+
+ let twofactor = twofactors.iter().filter(|tf| tf.type_ == provider).nth(0);
+
+ match TwoFactorType::from_i32(provider) {
+ Some(TwoFactorType::Remember) => {
+ match &device.twofactor_remember {
+ Some(remember) if remember == twofactor_code => return Ok(None), // No twofactor token needed here
+ _ => err_json!(_json_err_twofactor(&providers, user_uuid, conn)?),
+ }
+ }
+
+ Some(TwoFactorType::Authenticator) => {
+ let twofactor = match twofactor {
+ Some(tf) => tf,
+ None => err!("TOTP not enabled"),
+ };
+
+ let totp_code: u64 = match twofactor_code.parse() {
+ Ok(code) => code,
+ _ => err!("Invalid TOTP code"),
+ };
+
+ if !twofactor.check_totp_code(totp_code) {
+ err_json!(_json_err_twofactor(&providers, user_uuid, conn)?)
+ }
+ }
+
+ Some(TwoFactorType::U2f) => {
+ use api::core::two_factor;
+
+ two_factor::validate_u2f_login(user_uuid, twofactor_code, conn)?;
+ }
+
+ _ => err!("Invalid two factor provider"),
+ }
+
+ if util::parse_option_string(data.get_opt("twoFactorRemember")).unwrap_or(0) == 1 {
+ Ok(Some(device.refresh_twofactor_remember()))
+ } else {
+ device.delete_twofactor_remember();
+ Ok(None)
+ }
+}
+
+fn _json_err_twofactor(providers: &[i32], user_uuid: &str, conn: &DbConn) -> ApiResult<Value> {
+ use api::core::two_factor;
+
+ let mut result = json!({
"error" : "invalid_grant",
"error_description" : "Two factor required.",
- "TwoFactorProviders" : [ 0 ],
- "TwoFactorProviders2" : { "0" : null }
- })
+ "TwoFactorProviders" : providers,
+ "TwoFactorProviders2" : {} // { "0" : null }
+ });
+
+ for provider in providers {
+ result["TwoFactorProviders2"][provider.to_string()] = Value::Null;
+
+ match TwoFactorType::from_i32(*provider) {
+ Some(TwoFactorType::Authenticator) => { /* Nothing to do for TOTP */ }
+
+ Some(TwoFactorType::U2f) => {
+ let request = two_factor::generate_u2f_login(user_uuid, conn)?;
+ 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));
+ }
+
+ 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);
+ }
+
+ _ => {}
+ }
+ }
+
+ Ok(result)
}
#[derive(Clone, Copy)]
@@ -187,7 +265,6 @@ impl<'a, 'r> FromRequest<'a, 'r> for DeviceType {
}
}
-
#[derive(Debug)]
struct ConnectData {
grant_type: GrantType,
@@ -196,7 +273,10 @@ struct ConnectData {
}
#[derive(Debug, Copy, Clone)]
-enum GrantType { RefreshToken, Password }
+enum GrantType {
+ RefreshToken,
+ Password,
+}
impl ConnectData {
fn get(&self, key: &str) -> &String {
@@ -227,25 +307,28 @@ impl<'f> FromForm<'f> for ConnectData {
}
// Validate needed values
- let (grant_type, is_device) =
- match data.get("grant_type").map(String::as_ref) {
- Some("refresh_token") => {
- check_values(&data, &VALUES_REFRESH)?;
- (GrantType::RefreshToken, false) // Device doesn't matter here
- }
- Some("password") => {
- check_values(&data, &VALUES_PASSWORD)?;
-
- let is_device = match data["client_id"].as_ref() {
- "browser" | "mobile" => check_values(&data, &VALUES_DEVICE)?,
- _ => false
- };
- (GrantType::Password, is_device)
- }
- _ => return Err("Grant type not supported".to_string())
- };
+ let (grant_type, is_device) = match data.get("grant_type").map(String::as_ref) {
+ Some("refresh_token") => {
+ check_values(&data, &VALUES_REFRESH)?;
+ (GrantType::RefreshToken, false) // Device doesn't matter here
+ }
+ Some("password") => {
+ check_values(&data, &VALUES_PASSWORD)?;
+
+ let is_device = match data["client_id"].as_ref() {
+ "browser" | "mobile" => check_values(&data, &VALUES_DEVICE)?,
+ _ => false,
+ };
+ (GrantType::Password, is_device)
+ }
+ _ => return Err("Grant type not supported".to_string()),
+ };
- Ok(ConnectData { grant_type, is_device, data })
+ Ok(ConnectData {
+ grant_type,
+ is_device,
+ data,
+ })
}
}
diff --git a/src/api/mod.rs b/src/api/mod.rs
@@ -1,4 +1,4 @@
-mod core;
+pub(crate) mod core;
mod icons;
mod identity;
mod web;
@@ -12,8 +12,9 @@ use rocket::response::status::BadRequest;
use rocket_contrib::Json;
// Type aliases for API methods results
-type JsonResult = Result<Json, BadRequest<Json>>;
-type EmptyResult = Result<(), BadRequest<Json>>;
+type ApiResult<T> = Result<T, BadRequest<Json>>;
+type JsonResult = ApiResult<Json>;
+type EmptyResult = ApiResult<()>;
use util;
type JsonUpcase<T> = Json<util::UpCase<T>>;
diff --git a/src/api/web.rs b/src/api/web.rs
@@ -4,13 +4,13 @@ use std::path::{Path, PathBuf};
use rocket::request::Request;
use rocket::response::{self, NamedFile, Responder};
use rocket::Route;
-use rocket_contrib::Json;
+use rocket_contrib::{Json, Value};
use CONFIG;
pub fn routes() -> Vec<Route> {
if CONFIG.web_vault_enabled {
- routes![web_index, web_files, attachments, alive]
+ routes![web_index, app_id, web_files, attachments, alive]
} else {
routes![attachments, alive]
}
@@ -22,6 +22,20 @@ fn web_index() -> WebHeaders<io::Result<NamedFile>> {
web_files("index.html".into())
}
+#[get("/app-id.json")]
+fn app_id() -> WebHeaders<Json<Value>> {
+ WebHeaders(Json(json!({
+ "trustedFacets": [
+ {
+ "version": { "major": 1, "minor": 0 },
+ "ids": [
+ &CONFIG.domain,
+ "ios:bundle-id:com.8bit.bitwarden",
+ "android:apk-key-hash:dUGFzUzf3lmHSLBDBIv+WaFyZMI" ]
+ }]
+ })))
+}
+
#[get("/<p..>", rank = 1)] // Only match this if the other routes don't match
fn web_files(p: PathBuf) -> WebHeaders<io::Result<NamedFile>> {
WebHeaders(NamedFile::open(Path::new(&CONFIG.web_vault_folder).join(p)))
diff --git a/src/auth.rs b/src/auth.rs
@@ -11,11 +11,11 @@ use serde::ser::Serialize;
use CONFIG;
const JWT_ALGORITHM: jwt::Algorithm = jwt::Algorithm::RS256;
- // TODO: This isn't used, but we should make sure it represents the correct address
-pub const JWT_ISSUER: &str = "localhost:8000/identity";
lazy_static! {
pub static ref DEFAULT_VALIDITY: Duration = Duration::hours(2);
+ pub static ref JWT_ISSUER: String = CONFIG.domain.clone();
+
static ref JWT_HEADER: jwt::Header = jwt::Header::new(JWT_ALGORITHM);
static ref PRIVATE_RSA_KEY: Vec<u8> = match read_file(&CONFIG.private_rsa_key) {
@@ -43,7 +43,7 @@ pub fn decode_jwt(token: &str) -> Result<JWTClaims, String> {
validate_iat: true,
validate_nbf: true,
aud: None,
- iss: Some(JWT_ISSUER.into()),
+ iss: Some(JWT_ISSUER.clone()),
sub: None,
algorithms: vec![JWT_ALGORITHM],
};
diff --git a/src/db/models/device.rs b/src/db/models/device.rs
@@ -43,11 +43,14 @@ impl Device {
}
}
- pub fn refresh_twofactor_remember(&mut self) {
+ pub fn refresh_twofactor_remember(&mut self) -> String {
use data_encoding::BASE64;
use crypto;
- self.twofactor_remember = Some(BASE64.encode(&crypto::get_random(vec![0u8; 180])));
+ let twofactor_remember = BASE64.encode(&crypto::get_random(vec![0u8; 180]));
+ self.twofactor_remember = Some(twofactor_remember.clone());
+
+ twofactor_remember
}
pub fn delete_twofactor_remember(&mut self) {
diff --git a/src/db/models/mod.rs b/src/db/models/mod.rs
@@ -6,6 +6,7 @@ mod user;
mod collection;
mod organization;
+mod two_factor;
pub use self::attachment::Attachment;
pub use self::cipher::Cipher;
@@ -15,3 +16,4 @@ pub use self::user::User;
pub use self::organization::Organization;
pub use self::organization::{UserOrganization, UserOrgStatus, UserOrgType};
pub use self::collection::{Collection, CollectionUser, CollectionCipher};
+pub use self::two_factor::{TwoFactor, TwoFactorType};
+\ No newline at end of file
diff --git a/src/db/models/two_factor.rs b/src/db/models/two_factor.rs
@@ -0,0 +1,112 @@
+use serde_json::Value as JsonValue;
+
+use uuid::Uuid;
+
+use super::User;
+
+#[derive(Debug, Identifiable, Queryable, Insertable, Associations)]
+#[table_name = "twofactor"]
+#[belongs_to(User, foreign_key = "user_uuid")]
+#[primary_key(uuid)]
+pub struct TwoFactor {
+ pub uuid: String,
+ pub user_uuid: String,
+ pub type_: i32,
+ pub enabled: bool,
+ pub data: String,
+}
+
+#[allow(dead_code)]
+#[derive(FromPrimitive, ToPrimitive)]
+pub enum TwoFactorType {
+ Authenticator = 0,
+ Email = 1,
+ Duo = 2,
+ YubiKey = 3,
+ U2f = 4,
+ Remember = 5,
+ OrganizationDuo = 6,
+
+ // These are implementation details
+ U2fRegisterChallenge = 1000,
+ U2fLoginChallenge = 1001,
+}
+
+/// Local methods
+impl TwoFactor {
+ pub fn new(user_uuid: String, type_: TwoFactorType, data: String) -> Self {
+ Self {
+ uuid: Uuid::new_v4().to_string(),
+ user_uuid,
+ type_: type_ as i32,
+ enabled: true,
+ data,
+ }
+ }
+
+ pub fn check_totp_code(&self, totp_code: u64) -> bool {
+ let totp_secret = self.data.as_bytes();
+
+ use data_encoding::BASE32;
+ use oath::{totp_raw_now, HashType};
+
+ let decoded_secret = match BASE32.decode(totp_secret) {
+ Ok(s) => s,
+ Err(_) => return false
+ };
+
+ let generated = totp_raw_now(&decoded_secret, 6, 0, 30, &HashType::SHA1);
+ generated == totp_code
+ }
+
+ pub fn to_json(&self) -> JsonValue {
+ json!({
+ "Enabled": self.enabled,
+ "Key": "", // This key and value vary
+ "Object": "twoFactorAuthenticator" // This value varies
+ })
+ }
+
+ pub fn to_json_list(&self) -> JsonValue {
+ json!({
+ "Enabled": self.enabled,
+ "Type": self.type_,
+ "Object": "twoFactorProvider"
+ })
+ }
+}
+
+use diesel;
+use diesel::prelude::*;
+use db::DbConn;
+use db::schema::twofactor;
+
+/// Database methods
+impl TwoFactor {
+ pub fn save(&self, conn: &DbConn) -> QueryResult<usize> {
+ diesel::replace_into(twofactor::table)
+ .values(self)
+ .execute(&**conn)
+ }
+
+ pub fn delete(self, conn: &DbConn) -> QueryResult<usize> {
+ diesel::delete(
+ twofactor::table.filter(
+ twofactor::uuid.eq(self.uuid)
+ )
+ ).execute(&**conn)
+ }
+
+ pub fn find_by_user(user_uuid: &str, conn: &DbConn) -> Vec<Self> {
+ twofactor::table
+ .filter(twofactor::user_uuid.eq(user_uuid))
+ .load::<Self>(&**conn).expect("Error loading twofactor")
+ }
+
+ pub fn find_by_user_and_type(user_uuid: &str, type_: i32, conn: &DbConn) -> Option<Self> {
+ twofactor::table
+ .filter(twofactor::user_uuid.eq(user_uuid))
+ .filter(twofactor::type_.eq(type_))
+ .first::<Self>(&**conn).ok()
+ }
+}
+\ No newline at end of file
diff --git a/src/db/models/user.rs b/src/db/models/user.rs
@@ -27,7 +27,8 @@ pub struct User {
pub private_key: Option<String>,
pub public_key: Option<String>,
- pub totp_secret: Option<String>,
+ #[column_name = "totp_secret"]
+ _totp_secret: Option<String>,
pub totp_recover: Option<String>,
pub security_stamp: String,
@@ -64,7 +65,7 @@ impl User {
private_key: None,
public_key: None,
- totp_secret: None,
+ _totp_secret: None,
totp_recover: None,
equivalent_domains: "[]".to_string(),
@@ -97,28 +98,6 @@ impl User {
pub fn reset_security_stamp(&mut self) {
self.security_stamp = Uuid::new_v4().to_string();
}
-
- pub fn requires_twofactor(&self) -> bool {
- self.totp_secret.is_some()
- }
-
- pub fn check_totp_code(&self, totp_code: u64) -> bool {
- if let Some(ref totp_secret) = self.totp_secret {
- // Validate totp
- use data_encoding::BASE32;
- use oath::{totp_raw_now, HashType};
-
- let decoded_secret = match BASE32.decode(totp_secret.as_bytes()) {
- Ok(s) => s,
- Err(_) => return false
- };
-
- let generated = totp_raw_now(&decoded_secret, 6, 0, 30, &HashType::SHA1);
- generated == totp_code
- } else {
- true
- }
- }
}
use diesel;
@@ -130,10 +109,13 @@ use db::schema::users;
impl User {
pub fn to_json(&self, conn: &DbConn) -> JsonValue {
use super::UserOrganization;
+ use super::TwoFactor;
let orgs = UserOrganization::find_by_user(&self.uuid, conn);
let orgs_json: Vec<JsonValue> = orgs.iter().map(|c| c.to_json(&conn)).collect();
+ let twofactor_enabled = TwoFactor::find_by_user(&self.uuid, conn).len() > 0;
+
json!({
"Id": self.uuid,
"Name": self.name,
@@ -142,7 +124,7 @@ impl User {
"Premium": true,
"MasterPasswordHint": self.password_hint,
"Culture": "en-US",
- "TwoFactorEnabled": self.totp_secret.is_some(),
+ "TwoFactorEnabled": twofactor_enabled,
"Key": self.key,
"PrivateKey": self.private_key,
"SecurityStamp": self.security_stamp,
diff --git a/src/db/schema.rs b/src/db/schema.rs
@@ -80,6 +80,17 @@ table! {
}
table! {
+ twofactor (uuid) {
+ uuid -> Text,
+ user_uuid -> Text,
+ #[sql_name = "type"]
+ type_ -> Integer,
+ enabled -> Bool,
+ data -> Text,
+ }
+}
+
+table! {
users (uuid) {
uuid -> Text,
created_at -> Timestamp,
@@ -132,6 +143,7 @@ joinable!(devices -> users (user_uuid));
joinable!(folders -> users (user_uuid));
joinable!(folders_ciphers -> ciphers (cipher_uuid));
joinable!(folders_ciphers -> folders (folder_uuid));
+joinable!(twofactor -> users (user_uuid));
joinable!(users_collections -> collections (collection_uuid));
joinable!(users_collections -> users (user_uuid));
joinable!(users_organizations -> organizations (org_uuid));
@@ -146,6 +158,7 @@ allow_tables_to_appear_in_same_query!(
folders,
folders_ciphers,
organizations,
+ twofactor,
users,
users_collections,
users_organizations,
diff --git a/src/main.rs b/src/main.rs
@@ -19,9 +19,13 @@ extern crate chrono;
extern crate oath;
extern crate data_encoding;
extern crate jsonwebtoken as jwt;
+extern crate u2f;
extern crate dotenv;
#[macro_use]
extern crate lazy_static;
+#[macro_use]
+extern crate num_derive;
+extern crate num_traits;
use std::{env, path::Path, process::{exit, Command}};
use rocket::Rocket;
@@ -160,6 +164,7 @@ pub struct Config {
local_icon_extractor: bool,
signups_allowed: bool,
password_iterations: i32,
+ domain: String,
}
impl Config {
@@ -184,6 +189,7 @@ impl Config {
local_icon_extractor: util::parse_option_string(env::var("LOCAL_ICON_EXTRACTOR").ok()).unwrap_or(false),
signups_allowed: util::parse_option_string(env::var("SIGNUPS_ALLOWED").ok()).unwrap_or(true),
password_iterations: util::parse_option_string(env::var("PASSWORD_ITERATIONS").ok()).unwrap_or(100_000),
+ domain: env::var("DOMAIN").unwrap_or("https://localhost".into()),
}
}
}
diff --git a/src/util.rs b/src/util.rs
@@ -132,7 +132,9 @@ pub fn format_date(date: &NaiveDateTime) -> String {
use std::fmt;
use serde::de::{self, DeserializeOwned, Deserializer, MapAccess, SeqAccess, Visitor};
-use serde_json::Value;
+use serde_json::{self, Value};
+
+pub type JsonMap = serde_json::Map<String, Value>;
#[derive(PartialEq, Serialize, Deserialize)]
pub struct UpCase<T: DeserializeOwned> {
@@ -162,8 +164,7 @@ impl<'de> Visitor<'de> for UpCaseVisitor {
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where A: MapAccess<'de>
{
- use serde_json::Map;
- let mut result_map = Map::<String, Value>::new();
+ let mut result_map = JsonMap::new();
while let Some((key, value)) = map.next_entry()? {
result_map.insert(upcase_first(key), upcase_value(&value));