mirror of
				https://github.com/dani-garcia/vaultwarden.git
				synced 2025-10-28 00:40:01 +02:00 
			
		
		
		
	Implemented U2F, refactored Two Factor authentication, registering U2F device and authentication should work. Works on Chrome on MacOS with a virtual device.
This commit is contained in:
		
							
								
								
									
										263
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										263
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @@ -29,6 +29,14 @@ name = "ascii" | |||||||
| version = "0.7.1" | version = "0.7.1" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | 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]] | [[package]] | ||||||
| name = "base64" | name = "base64" | ||||||
| version = "0.6.0" | version = "0.6.0" | ||||||
| @@ -70,15 +78,18 @@ dependencies = [ | |||||||
|  "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", |  "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)", |  "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)", |  "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)", |  "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)", |  "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)", |  "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 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_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)", |  "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 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", | ||||||
|  "serde_derive 1.0.68 (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)", |  "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)", |  "uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", | ||||||
| ] | ] | ||||||
|  |  | ||||||
| @@ -117,7 +128,7 @@ dependencies = [ | |||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "cc" | name = "cc" | ||||||
| version = "1.0.17" | version = "1.0.18" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| @@ -162,7 +173,7 @@ dependencies = [ | |||||||
|  "base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", |  "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)", |  "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)", |  "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]] | [[package]] | ||||||
| @@ -325,7 +336,7 @@ dependencies = [ | |||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "dtoa" | name = "dtoa" | ||||||
| version = "0.4.2" | version = "0.4.3" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| @@ -450,7 +461,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "futures" | name = "futures" | ||||||
| version = "0.1.21" | version = "0.1.22" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| @@ -458,7 +469,7 @@ name = "futures-cpupool" | |||||||
| version = "0.1.8" | version = "0.1.8" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| dependencies = [ | 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)", |  "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)", |  "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)", |  "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)", |  "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]] | [[package]] | ||||||
| @@ -521,13 +532,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||||||
| dependencies = [ | dependencies = [ | ||||||
|  "base64 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", |  "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)", |  "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)", |  "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)", |  "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)", |  "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)", |  "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)", |  "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", | ||||||
|  "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)", | ||||||
|  "net2 0.2.33 (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)", |  "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)", |  "relay 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||||
| @@ -555,7 +566,7 @@ name = "hyper-tls" | |||||||
| version = "0.1.3" | version = "0.1.3" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| dependencies = [ | 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)", |  "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)", |  "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-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", | ||||||
| @@ -566,7 +577,7 @@ dependencies = [ | |||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "idna" | name = "idna" | ||||||
| version = "0.1.4" | version = "0.1.5" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", |  "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)", |  "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)", |  "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)", |  "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]] | [[package]] | ||||||
| @@ -610,7 +621,7 @@ dependencies = [ | |||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "itoa" | name = "itoa" | ||||||
| version = "0.4.1" | version = "0.4.2" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| @@ -621,8 +632,8 @@ dependencies = [ | |||||||
|  "chrono 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", |  "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)", |  "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)", |  "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 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", | ||||||
|  "serde_derive 1.0.68 (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)", |  "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)", |  "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]] | [[package]] | ||||||
| name = "libflate" | name = "libflate" | ||||||
| version = "0.1.15" | version = "0.1.16" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", |  "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", | ||||||
| @@ -676,7 +687,7 @@ name = "libsqlite3-sys" | |||||||
| version = "0.9.1" | version = "0.9.1" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| dependencies = [ | 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)", |  "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)", |  "vcpkg 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", | ||||||
| ] | ] | ||||||
| @@ -686,12 +697,12 @@ name = "log" | |||||||
| version = "0.3.9" | version = "0.3.9" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| dependencies = [ | 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]] | [[package]] | ||||||
| name = "log" | name = "log" | ||||||
| version = "0.4.2" | version = "0.4.3" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", |  "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", | ||||||
| @@ -751,7 +762,7 @@ dependencies = [ | |||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "mime" | name = "mime" | ||||||
| version = "0.3.7" | version = "0.3.8" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", |  "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" | version = "2.0.0-alpha.5" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| dependencies = [ | 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 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)", |  "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)", |  "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||||
| @@ -781,7 +792,7 @@ dependencies = [ | |||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "mio" | name = "mio" | ||||||
| version = "0.6.14" | version = "0.6.15" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", |  "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)", |  "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)", |  "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)", |  "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)", |  "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)", |  "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)", |  "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)", |  "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)", |  "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)", |  "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)", |  "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", | ||||||
|  "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)", | ||||||
|  "mime_guess 2.0.0-alpha.5 (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)", |  "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)", |  "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)", |  "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)", |  "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)", |  "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]] | [[package]] | ||||||
| @@ -901,6 +912,17 @@ dependencies = [ | |||||||
|  "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", |  "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", | ||||||
| ] | ] | ||||||
|  |  | ||||||
|  | [[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]] | [[package]] | ||||||
| name = "num-integer" | name = "num-integer" | ||||||
| version = "0.1.39" | version = "0.1.39" | ||||||
| @@ -960,7 +982,7 @@ name = "openssl-sys" | |||||||
| version = "0.9.33" | version = "0.9.33" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| dependencies = [ | 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)", |  "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)", |  "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)", |  "vcpkg 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", | ||||||
| @@ -981,7 +1003,7 @@ name = "pear_codegen" | |||||||
| version = "0.0.18" | version = "0.0.18" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| dependencies = [ | 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)", |  "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" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", |  "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)", |  "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" | version = "0.1.1" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| dependencies = [ | 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]] | [[package]] | ||||||
| @@ -1198,20 +1220,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||||||
| dependencies = [ | dependencies = [ | ||||||
|  "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", |  "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)", |  "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 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)", |  "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)", |  "libflate 0.1.16 (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)", | ||||||
|  "mime_guess 2.0.0-alpha.5 (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)", |  "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_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)", |  "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-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-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)", |  "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)", |  "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)", |  "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)", |  "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)", |  "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)", |  "url 1.7.1 (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)", |  "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 = [ | dependencies = [ | ||||||
|  "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", |  "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)", |  "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)", |  "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 = [ | dependencies = [ | ||||||
|  "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", |  "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)", |  "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)", |  "serde_json 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)", | ||||||
| ] | ] | ||||||
|  |  | ||||||
| @@ -1352,17 +1374,17 @@ dependencies = [ | |||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "serde" | name = "serde" | ||||||
| version = "1.0.68" | version = "1.0.70" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "serde_derive" | name = "serde_derive" | ||||||
| version = "1.0.68" | version = "1.0.70" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "proc-macro2 0.4.6 (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)", |  "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]] | [[package]] | ||||||
| @@ -1370,9 +1392,9 @@ name = "serde_json" | |||||||
| version = "1.0.22" | version = "1.0.22" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "dtoa 0.4.2 (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.1 (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.68 (registry+https://github.com/rust-lang/crates.io-index)", |  "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", | ||||||
| ] | ] | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| @@ -1380,10 +1402,10 @@ name = "serde_urlencoded" | |||||||
| version = "0.5.2" | version = "0.5.2" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "dtoa 0.4.2 (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.1 (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.68 (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.0 (registry+https://github.com/rust-lang/crates.io-index)", |  "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||||
| ] | ] | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| @@ -1462,7 +1484,7 @@ dependencies = [ | |||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "syn" | name = "syn" | ||||||
| version = "0.14.2" | version = "0.14.4" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", |  "proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", | ||||||
| @@ -1538,14 +1560,14 @@ name = "tokio" | |||||||
| version = "0.1.7" | version = "0.1.7" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| dependencies = [ | 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)", | ||||||
|  "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-executor 0.1.2 (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-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-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-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-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)", |  "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" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "bytes 0.4.8 (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)", | ||||||
|  "tokio-io 0.1.7 (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" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "bytes 0.4.8 (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)", | ||||||
|  "iovec 0.1.2 (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)", |  "log 0.4.3 (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)", | ||||||
|  "scoped-tls 0.1.2 (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 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)", |  "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" | version = "0.1.2" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| dependencies = [ | 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]] | [[package]] | ||||||
| name = "tokio-fs" | name = "tokio-fs" | ||||||
| version = "0.1.1" | version = "0.1.2" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| dependencies = [ | 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-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]] | [[package]] | ||||||
| @@ -1602,8 +1624,8 @@ version = "0.1.7" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "bytes 0.4.8 (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)", | ||||||
|  "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]] | [[package]] | ||||||
| @@ -1611,7 +1633,7 @@ name = "tokio-proto" | |||||||
| version = "0.1.1" | version = "0.1.1" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| dependencies = [ | 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)", |  "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)", |  "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)", |  "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", | ||||||
| @@ -1628,9 +1650,9 @@ name = "tokio-reactor" | |||||||
| version = "0.1.2" | version = "0.1.2" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| dependencies = [ | 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.4.2 (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.14 (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)", |  "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-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)", |  "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" | version = "0.1.0" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| dependencies = [ | 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]] | [[package]] | ||||||
| @@ -1650,21 +1672,21 @@ version = "0.1.0" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "bytes 0.4.8 (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)", | ||||||
|  "iovec 0.1.2 (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-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-reactor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||||
| ] | ] | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "tokio-threadpool" | name = "tokio-threadpool" | ||||||
| version = "0.1.4" | version = "0.1.5" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "crossbeam-deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", |  "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)", |  "futures 0.1.22 (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)", | ||||||
|  "num_cpus 1.8.0 (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)", |  "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)", |  "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" | version = "0.2.4" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| dependencies = [ | 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)", |  "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" | version = "0.1.4" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| dependencies = [ | 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)", |  "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-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-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" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "bytes 0.4.8 (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)", | ||||||
|  "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)", | ||||||
|  "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-codec 0.1.0 (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-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-reactor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||||
| @@ -1709,7 +1731,7 @@ name = "toml" | |||||||
| version = "0.4.6" | version = "0.4.6" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| dependencies = [ | 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]] | [[package]] | ||||||
| @@ -1748,6 +1770,24 @@ name = "typenum" | |||||||
| version = "1.10.0" | version = "1.10.0" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | 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]] | [[package]] | ||||||
| name = "ucd-util" | name = "ucd-util" | ||||||
| version = "0.1.1" | version = "0.1.1" | ||||||
| @@ -1758,7 +1798,7 @@ name = "unicase" | |||||||
| version = "1.4.2" | version = "1.4.2" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| dependencies = [ | 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]] | [[package]] | ||||||
| @@ -1766,7 +1806,7 @@ name = "unicase" | |||||||
| version = "2.1.0" | version = "2.1.0" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| dependencies = [ | 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]] | [[package]] | ||||||
| @@ -1825,10 +1865,10 @@ dependencies = [ | |||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "url" | name = "url" | ||||||
| version = "1.7.0" | version = "1.7.1" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| dependencies = [ | 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)", |  "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)", |  "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]] | [[package]] | ||||||
| name = "version_check" | name = "version_check" | ||||||
| version = "0.1.3" | version = "0.1.4" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  |  | ||||||
| [[package]] | [[package]] | ||||||
| @@ -1876,8 +1916,8 @@ name = "want" | |||||||
| version = "0.0.4" | version = "0.0.4" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| dependencies = [ | 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.4.2 (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)", |  "try-lock 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||||
| ] | ] | ||||||
|  |  | ||||||
| @@ -1891,6 +1931,15 @@ dependencies = [ | |||||||
|  "untrusted 0.5.1 (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" | ||||||
|  | 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]] | [[package]] | ||||||
| name = "webpki-roots" | name = "webpki-roots" | ||||||
| version = "0.11.0" | version = "0.11.0" | ||||||
| @@ -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 antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34fde25430d87a9388dadbe6e34d7f72a462c8b43ac8d309b42b0a8505d7e2a5" | ||||||
| "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" | "checksum arrayvec 0.4.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 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.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 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" | "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 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 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 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 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.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" | "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 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 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 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 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-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" | "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 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 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 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 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 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" | "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 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-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 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 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 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 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 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 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 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 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 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 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 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.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 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 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" | "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_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 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.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 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 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 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 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" | "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 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 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 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-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-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" | "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 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 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 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 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)" = "0c3adf19c07af6d186d91dae8927b83b0553d07ca56cbf7f2f32560455c91920" | ||||||
| "checksum serde_derive 1.0.68 (registry+https://github.com/rust-lang/crates.io-index)" = "6a25ad0bf818ed2d180c89addbe29198d1de6c89ed08a48aa6a4d3d16a63cbfe" | "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_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 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" | "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 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.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.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 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 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" | "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-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-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-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-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-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-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-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-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-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-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" | "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 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 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 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 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 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" | "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 unsafe-any 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f30360d7979f5e9c6e6cea48af192ea8fab4afb3cf72597154b8f08935bc9c7f" | ||||||
| "checksum untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f392d7819dbe58833e26872f5f6f0d68b7bbbe90fc3667e98731c4a15ad9a7ae" | "checksum untrusted 0.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 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 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.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 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 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 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 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.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e499345fc4c6b7c79a5b8756d4592c4305510a13512e79efafe00dfbd67bbac6" | ||||||
|  | "checksum webpki 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "493012e46177f3f4ee9cd58fd0c81ecb77e6d6cc6ebce55989b9c33376fbe5ee" | ||||||
| "checksum webpki-roots 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5bfb3f50499f21ad2317f442845e3b5805b007f1e728f59885c99e61b8c181a7" | "checksum webpki-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.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" | "checksum winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "773ef9dcc5f24b7d850d0ff101e542ff24c3b090a9768e03ff889fdef41f00fd" | ||||||
|   | |||||||
							
								
								
									
										17
									
								
								Cargo.toml
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								Cargo.toml
									
									
									
									
									
								
							| @@ -16,8 +16,8 @@ reqwest = "0.8.6" | |||||||
| multipart = "0.14.2" | multipart = "0.14.2" | ||||||
|  |  | ||||||
| # A generic serialization/deserialization framework | # A generic serialization/deserialization framework | ||||||
| serde = "1.0.68" | serde = "1.0.70" | ||||||
| serde_derive = "1.0.68" | serde_derive = "1.0.70" | ||||||
| serde_json = "1.0.22" | serde_json = "1.0.22" | ||||||
|  |  | ||||||
| # A safe, extensible ORM and Query builder | # A safe, extensible ORM and Query builder | ||||||
| @@ -45,11 +45,22 @@ data-encoding = "2.1.1" | |||||||
| # JWT library | # JWT library | ||||||
| jsonwebtoken = "= 4.0.1" | jsonwebtoken = "= 4.0.1" | ||||||
|  |  | ||||||
|  | # U2F library | ||||||
|  | u2f = "0.1.2" | ||||||
|  |  | ||||||
| # A `dotenv` implementation for Rust | # A `dotenv` implementation for Rust | ||||||
| dotenv = { version = "0.13.0", default-features = false } | dotenv = { version = "0.13.0", default-features = false } | ||||||
|  |  | ||||||
| # Lazy static macro | # Lazy static macro | ||||||
| lazy_static = "1.0.1" | lazy_static = "1.0.1" | ||||||
|  |  | ||||||
|  | # Numerical libraries | ||||||
|  | num-traits = "0.2.5" | ||||||
|  | num-derive = "0.2.2" | ||||||
|  |  | ||||||
| [patch.crates-io] | [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' } | ||||||
| @@ -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; | ||||||
							
								
								
									
										15
									
								
								migrations/2018-07-11-181453_create_u2f_twofactor/up.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								migrations/2018-07-11-181453_create_u2f_twofactor/up.sql
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||||
| @@ -2,7 +2,7 @@ mod accounts; | |||||||
| mod ciphers; | mod ciphers; | ||||||
| mod folders; | mod folders; | ||||||
| mod organizations; | mod organizations; | ||||||
| mod two_factor; | pub(crate) mod two_factor; | ||||||
|  |  | ||||||
| use self::accounts::*; | use self::accounts::*; | ||||||
| use self::ciphers::*; | use self::ciphers::*; | ||||||
| @@ -58,9 +58,11 @@ pub fn routes() -> Vec<Route> { | |||||||
|         get_twofactor, |         get_twofactor, | ||||||
|         get_recover, |         get_recover, | ||||||
|         recover, |         recover, | ||||||
|  |         disable_twofactor, | ||||||
|         generate_authenticator, |         generate_authenticator, | ||||||
|         activate_authenticator, |         activate_authenticator, | ||||||
|         disable_authenticator, |         generate_u2f, | ||||||
|  |         activate_u2f, | ||||||
|  |  | ||||||
|         get_organization, |         get_organization, | ||||||
|         create_organization, |         create_organization, | ||||||
|   | |||||||
| @@ -1,28 +1,24 @@ | |||||||
| use rocket_contrib::{Json, Value}; |  | ||||||
|  |  | ||||||
| use data_encoding::BASE32; | 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 crypto; | ||||||
|  |  | ||||||
| use api::{PasswordData, JsonResult, NumberOrString, JsonUpcase}; | use api::{ApiResult, JsonResult, JsonUpcase, NumberOrString, PasswordData}; | ||||||
| use auth::Headers; | use auth::Headers; | ||||||
|  |  | ||||||
| #[get("/two-factor")] | #[get("/two-factor")] | ||||||
| fn get_twofactor(headers: Headers) -> JsonResult { | fn get_twofactor(headers: Headers, conn: DbConn) -> JsonResult { | ||||||
|     let data = if headers.user.totp_secret.is_none() { |     let twofactors = TwoFactor::find_by_user(&headers.user.uuid, &conn); | ||||||
|         Value::Null |     let twofactors_json: Vec<Value> = twofactors.iter().map(|c| c.to_json_list()).collect(); | ||||||
|     } else { |  | ||||||
|         json!([{ |  | ||||||
|             "Enabled": true, |  | ||||||
|             "Type": 0, |  | ||||||
|             "Object": "twoFactorProvider" |  | ||||||
|         }]) |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     Ok(Json(json!({ |     Ok(Json(json!({ | ||||||
|         "Data": data, |         "Data": twofactors_json, | ||||||
|         "Object": "list" |         "Object": "list" | ||||||
|     }))) |     }))) | ||||||
| } | } | ||||||
| @@ -58,7 +54,7 @@ fn recover(data: JsonUpcase<RecoverTwoFactor>, conn: DbConn) -> JsonResult { | |||||||
|     // Get the user |     // Get the user | ||||||
|     let mut user = match User::find_by_mail(&data.Email, &conn) { |     let mut user = match User::find_by_mail(&data.Email, &conn) { | ||||||
|         Some(user) => user, |         Some(user) => user, | ||||||
|         None => err!("Username or password is incorrect. Try again.") |         None => err!("Username or password is incorrect. Try again."), | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     // Check password |     // Check password | ||||||
| @@ -71,24 +67,69 @@ fn recover(data: JsonUpcase<RecoverTwoFactor>, conn: DbConn) -> JsonResult { | |||||||
|         err!("Recovery code is incorrect. Try again.") |         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.totp_recover = None; | ||||||
|     user.save(&conn); |     user.save(&conn); | ||||||
|  |  | ||||||
|     Ok(Json(json!({}))) |     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>")] | #[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; |     let data: PasswordData = data.into_inner().data; | ||||||
|  |  | ||||||
|     if !headers.user.check_valid_password(&data.MasterPasswordHash) { |     if !headers.user.check_valid_password(&data.MasterPasswordHash) { | ||||||
|         err!("Invalid password"); |         err!("Invalid password"); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     let (enabled, key) = match headers.user.totp_secret { |     let type_ = TwoFactorType::Authenticator as i32; | ||||||
|         Some(secret) => (true, secret), |     let twofactor = TwoFactor::find_by_user_and_type(&headers.user.uuid, type_, &conn); | ||||||
|         _ => (false, BASE32.encode(&crypto::get_random(vec![0u8; 20]))) |  | ||||||
|  |     let (enabled, key) = match twofactor { | ||||||
|  |         Some(tf) => (true, tf.data), | ||||||
|  |         _ => (false, BASE32.encode(&crypto::get_random(vec![0u8; 20]))), | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     Ok(Json(json!({ |     Ok(Json(json!({ | ||||||
| @@ -100,20 +141,24 @@ fn generate_authenticator(data: JsonUpcase<PasswordData>, headers: Headers) -> J | |||||||
|  |  | ||||||
| #[derive(Deserialize, Debug)] | #[derive(Deserialize, Debug)] | ||||||
| #[allow(non_snake_case)] | #[allow(non_snake_case)] | ||||||
| struct EnableTwoFactorData { | struct EnableAuthenticatorData { | ||||||
|     MasterPasswordHash: String, |     MasterPasswordHash: String, | ||||||
|     Key: String, |     Key: String, | ||||||
|     Token: NumberOrString, |     Token: NumberOrString, | ||||||
| } | } | ||||||
|  |  | ||||||
| #[post("/two-factor/authenticator", data = "<data>")] | #[post("/two-factor/authenticator", data = "<data>")] | ||||||
| fn activate_authenticator(data: JsonUpcase<EnableTwoFactorData>, headers: Headers, conn: DbConn) -> JsonResult { | fn activate_authenticator( | ||||||
|     let data: EnableTwoFactorData = data.into_inner().data; |     data: JsonUpcase<EnableAuthenticatorData>, | ||||||
|  |     headers: Headers, | ||||||
|  |     conn: DbConn, | ||||||
|  | ) -> JsonResult { | ||||||
|  |     let data: EnableAuthenticatorData = data.into_inner().data; | ||||||
|     let password_hash = data.MasterPasswordHash; |     let password_hash = data.MasterPasswordHash; | ||||||
|     let key = data.Key; |     let key = data.Key; | ||||||
|     let token = match data.Token.into_i32() { |     let token = match data.Token.into_i32() { | ||||||
|         Some(n) => n as u64, |         Some(n) => n as u64, | ||||||
|         None => err!("Malformed token") |         None => err!("Malformed token"), | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     if !headers.user.check_valid_password(&password_hash) { |     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 |     // Validate key as base32 and 20 bytes length | ||||||
|     let decoded_key: Vec<u8> = match BASE32.decode(key.as_bytes()) { |     let decoded_key: Vec<u8> = match BASE32.decode(key.as_bytes()) { | ||||||
|         Ok(decoded) => decoded, |         Ok(decoded) => decoded, | ||||||
|         _ => err!("Invalid totp secret") |         _ => err!("Invalid totp secret"), | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     if decoded_key.len() != 20 { |     if decoded_key.len() != 20 { | ||||||
|         err!("Invalid key length") |         err!("Invalid key length") | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Set key in user.totp_secret |     let type_ = TwoFactorType::Authenticator; | ||||||
|     let mut user = headers.user; |     let twofactor = TwoFactor::new(headers.user.uuid.clone(), type_, key.to_uppercase()); | ||||||
|     user.totp_secret = Some(key.to_uppercase()); |  | ||||||
|  |  | ||||||
|     // Validate the token provided with the key |     // Validate the token provided with the key | ||||||
|     if !user.check_totp_code(token) { |     if !twofactor.check_totp_code(token) { | ||||||
|         err!("Invalid totp code") |         err!("Invalid totp code") | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Generate totp_recover |     let mut user = headers.user; | ||||||
|     let totp_recover = BASE32.encode(&crypto::get_random(vec![0u8; 20])); |     _generate_recover_code(&mut user, &conn); | ||||||
|     user.totp_recover = Some(totp_recover); |     twofactor.save(&conn).expect("Error saving twofactor"); | ||||||
|  |  | ||||||
|     user.save(&conn); |  | ||||||
|  |  | ||||||
|     Ok(Json(json!({ |     Ok(Json(json!({ | ||||||
|         "Enabled": true, |         "Enabled": true, | ||||||
| @@ -152,32 +194,228 @@ fn activate_authenticator(data: JsonUpcase<EnableTwoFactorData>, headers: Header | |||||||
|     }))) |     }))) | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Deserialize)] | fn _generate_recover_code(user: &mut User, conn: &DbConn) { | ||||||
| #[allow(non_snake_case)] |     if user.totp_recover.is_none() { | ||||||
| struct DisableTwoFactorData { |         let totp_recover = BASE32.encode(&crypto::get_random(vec![0u8; 20])); | ||||||
|     MasterPasswordHash: String, |         user.totp_recover = Some(totp_recover); | ||||||
|     Type: NumberOrString, |         user.save(conn); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| #[post("/two-factor/disable", data = "<data>")] | use u2f::messages::{RegisterResponse, SignResponse, U2fSignRequest}; | ||||||
| fn disable_authenticator(data: JsonUpcase<DisableTwoFactorData>, headers: Headers, conn: DbConn) -> JsonResult { | use u2f::protocol::{Challenge, U2f}; | ||||||
|     let data: DisableTwoFactorData = data.into_inner().data; | use u2f::register::Registration; | ||||||
|     let password_hash = data.MasterPasswordHash; |  | ||||||
|     let _type = data.Type; |  | ||||||
|  |  | ||||||
|     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"); |         err!("Invalid password"); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     let mut user = headers.user; |     let user_uuid = &headers.user.uuid; | ||||||
|     user.totp_secret = None; |  | ||||||
|     user.totp_recover = None; |  | ||||||
|  |  | ||||||
|     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!({ |     Ok(Json(json!({ | ||||||
|         "Enabled": false, |         "Enabled": enabled, | ||||||
|         "Type": 0, |         "Challenge": { | ||||||
|         "Object": "twoFactorProvider" |             "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") | ||||||
|  | } | ||||||
|   | |||||||
| @@ -1,19 +1,21 @@ | |||||||
| use std::collections::HashMap; | use std::collections::HashMap; | ||||||
|  |  | ||||||
| use rocket::{Route, Outcome}; | use rocket::request::{self, Form, FormItems, FromForm, FromRequest, Request}; | ||||||
| use rocket::request::{self, Request, FromRequest, Form, FormItems, FromForm}; | use rocket::{Outcome, Route}; | ||||||
|  |  | ||||||
| use rocket_contrib::{Json, Value}; | use rocket_contrib::{Json, Value}; | ||||||
|  |  | ||||||
| use db::DbConn; | use num_traits::FromPrimitive; | ||||||
|  |  | ||||||
| use db::models::*; | use db::models::*; | ||||||
|  | use db::DbConn; | ||||||
|  |  | ||||||
| use util; | use util::{self, JsonMap}; | ||||||
|  |  | ||||||
| use api::JsonResult; | use api::{ApiResult, JsonResult}; | ||||||
|  |  | ||||||
| pub fn routes() -> Vec<Route> { | pub fn routes() -> Vec<Route> { | ||||||
|     routes![ login] |     routes![login] | ||||||
| } | } | ||||||
|  |  | ||||||
| #[post("/connect/token", data = "<connect_data>")] | #[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(); |     let data = connect_data.get(); | ||||||
|  |  | ||||||
|     match data.grant_type { |     match data.grant_type { | ||||||
|         GrantType::RefreshToken =>_refresh_login(data, device_type, conn), |         GrantType::RefreshToken => _refresh_login(data, device_type, conn), | ||||||
|         GrantType::Password => _password_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 |     // Get device by refresh token | ||||||
|     let mut device = match Device::find_by_refresh_token(token, &conn) { |     let mut device = match Device::find_by_refresh_token(token, &conn) { | ||||||
|         Some(device) => device, |         Some(device) => device, | ||||||
|         None => err!("Invalid refresh token") |         None => err!("Invalid refresh token"), | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     // COMMON |     // COMMON | ||||||
| @@ -64,7 +66,7 @@ fn _password_login(data: &ConnectData, device_type: DeviceType, conn: DbConn) -> | |||||||
|     let username = data.get("username"); |     let username = data.get("username"); | ||||||
|     let user = match User::find_by_mail(username, &conn) { |     let user = match User::find_by_mail(username, &conn) { | ||||||
|         Some(user) => user, |         Some(user) => user, | ||||||
|         None => err!("Username or password is incorrect. Try again.") |         None => err!("Username or password is incorrect. Try again."), | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     // Check password |     // Check password | ||||||
| @@ -102,42 +104,7 @@ fn _password_login(data: &ConnectData, device_type: DeviceType, conn: DbConn) -> | |||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     let twofactor_token = if user.requires_twofactor() { |     let twofactor_token = twofactor_auth(&user.uuid, &data, &mut device, &conn)?; | ||||||
|         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 |  | ||||||
|  |  | ||||||
|     // Common |     // Common | ||||||
|     let user = User::find_by_uuid(&device.user_uuid, &conn).unwrap(); |     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)) |     Ok(Json(result)) | ||||||
| } | } | ||||||
|  |  | ||||||
| fn _json_err_twofactor() -> Value { | fn twofactor_auth( | ||||||
|     json!({ |     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" : "invalid_grant", | ||||||
|         "error_description" : "Two factor required.", |         "error_description" : "Two factor required.", | ||||||
|         "TwoFactorProviders" : [ 0 ], |         "TwoFactorProviders" : providers, | ||||||
|         "TwoFactorProviders2" : { "0" : null } |         "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)] | #[derive(Clone, Copy)] | ||||||
| @@ -187,7 +265,6 @@ impl<'a, 'r> FromRequest<'a, 'r> for DeviceType { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| struct ConnectData { | struct ConnectData { | ||||||
|     grant_type: GrantType, |     grant_type: GrantType, | ||||||
| @@ -196,7 +273,10 @@ struct ConnectData { | |||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Debug, Copy, Clone)] | #[derive(Debug, Copy, Clone)] | ||||||
| enum GrantType { RefreshToken, Password } | enum GrantType { | ||||||
|  |     RefreshToken, | ||||||
|  |     Password, | ||||||
|  | } | ||||||
|  |  | ||||||
| impl ConnectData { | impl ConnectData { | ||||||
|     fn get(&self, key: &str) -> &String { |     fn get(&self, key: &str) -> &String { | ||||||
| @@ -227,8 +307,7 @@ impl<'f> FromForm<'f> for ConnectData { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         // Validate needed values |         // Validate needed values | ||||||
|         let (grant_type, is_device) = |         let (grant_type, is_device) = match data.get("grant_type").map(String::as_ref) { | ||||||
|             match data.get("grant_type").map(String::as_ref) { |  | ||||||
|             Some("refresh_token") => { |             Some("refresh_token") => { | ||||||
|                 check_values(&data, &VALUES_REFRESH)?; |                 check_values(&data, &VALUES_REFRESH)?; | ||||||
|                 (GrantType::RefreshToken, false) // Device doesn't matter here |                 (GrantType::RefreshToken, false) // Device doesn't matter here | ||||||
| @@ -238,14 +317,18 @@ impl<'f> FromForm<'f> for ConnectData { | |||||||
|  |  | ||||||
|                 let is_device = match data["client_id"].as_ref() { |                 let is_device = match data["client_id"].as_ref() { | ||||||
|                     "browser" | "mobile" => check_values(&data, &VALUES_DEVICE)?, |                     "browser" | "mobile" => check_values(&data, &VALUES_DEVICE)?, | ||||||
|                         _ => false |                     _ => false, | ||||||
|                 }; |                 }; | ||||||
|                 (GrantType::Password, is_device) |                 (GrantType::Password, is_device) | ||||||
|             } |             } | ||||||
|                 _ => return Err("Grant type not supported".to_string()) |             _ => return Err("Grant type not supported".to_string()), | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
|         Ok(ConnectData { grant_type, is_device, data }) |         Ok(ConnectData { | ||||||
|  |             grant_type, | ||||||
|  |             is_device, | ||||||
|  |             data, | ||||||
|  |         }) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| mod core; | pub(crate) mod core; | ||||||
| mod icons; | mod icons; | ||||||
| mod identity; | mod identity; | ||||||
| mod web; | mod web; | ||||||
| @@ -12,8 +12,9 @@ use rocket::response::status::BadRequest; | |||||||
| use rocket_contrib::Json; | use rocket_contrib::Json; | ||||||
|  |  | ||||||
| // Type aliases for API methods results | // Type aliases for API methods results | ||||||
| type JsonResult = Result<Json, BadRequest<Json>>; | type ApiResult<T> = Result<T, BadRequest<Json>>; | ||||||
| type EmptyResult = Result<(), BadRequest<Json>>; | type JsonResult = ApiResult<Json>; | ||||||
|  | type EmptyResult = ApiResult<()>; | ||||||
|  |  | ||||||
| use util; | use util; | ||||||
| type JsonUpcase<T> = Json<util::UpCase<T>>; | type JsonUpcase<T> = Json<util::UpCase<T>>; | ||||||
|   | |||||||
| @@ -4,13 +4,13 @@ use std::path::{Path, PathBuf}; | |||||||
| use rocket::request::Request; | use rocket::request::Request; | ||||||
| use rocket::response::{self, NamedFile, Responder}; | use rocket::response::{self, NamedFile, Responder}; | ||||||
| use rocket::Route; | use rocket::Route; | ||||||
| use rocket_contrib::Json; | use rocket_contrib::{Json, Value}; | ||||||
|  |  | ||||||
| use CONFIG; | use CONFIG; | ||||||
|  |  | ||||||
| pub fn routes() -> Vec<Route> { | pub fn routes() -> Vec<Route> { | ||||||
|     if CONFIG.web_vault_enabled { |     if CONFIG.web_vault_enabled { | ||||||
|         routes![web_index, web_files, attachments, alive] |         routes![web_index, app_id, web_files, attachments, alive] | ||||||
|     } else { |     } else { | ||||||
|         routes![attachments, alive] |         routes![attachments, alive] | ||||||
|     } |     } | ||||||
| @@ -22,6 +22,20 @@ fn web_index() -> WebHeaders<io::Result<NamedFile>> { | |||||||
|     web_files("index.html".into()) |     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 | #[get("/<p..>", rank = 1)] // Only match this if the other routes don't match | ||||||
| fn web_files(p: PathBuf) -> WebHeaders<io::Result<NamedFile>> { | fn web_files(p: PathBuf) -> WebHeaders<io::Result<NamedFile>> { | ||||||
|     WebHeaders(NamedFile::open(Path::new(&CONFIG.web_vault_folder).join(p))) |     WebHeaders(NamedFile::open(Path::new(&CONFIG.web_vault_folder).join(p))) | ||||||
|   | |||||||
| @@ -11,11 +11,11 @@ use serde::ser::Serialize; | |||||||
| use CONFIG; | use CONFIG; | ||||||
|  |  | ||||||
| const JWT_ALGORITHM: jwt::Algorithm = jwt::Algorithm::RS256; | 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! { | lazy_static! { | ||||||
|     pub static ref DEFAULT_VALIDITY: Duration = Duration::hours(2); |     pub static ref DEFAULT_VALIDITY: Duration = Duration::hours(2); | ||||||
|  |     pub static ref JWT_ISSUER: String = CONFIG.domain.clone(); | ||||||
|  |  | ||||||
|     static ref JWT_HEADER: jwt::Header = jwt::Header::new(JWT_ALGORITHM); |     static ref JWT_HEADER: jwt::Header = jwt::Header::new(JWT_ALGORITHM); | ||||||
|  |  | ||||||
|     static ref PRIVATE_RSA_KEY: Vec<u8> = match read_file(&CONFIG.private_rsa_key) { |     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_iat: true, | ||||||
|         validate_nbf: true, |         validate_nbf: true, | ||||||
|         aud: None, |         aud: None, | ||||||
|         iss: Some(JWT_ISSUER.into()), |         iss: Some(JWT_ISSUER.clone()), | ||||||
|         sub: None, |         sub: None, | ||||||
|         algorithms: vec![JWT_ALGORITHM], |         algorithms: vec![JWT_ALGORITHM], | ||||||
|     }; |     }; | ||||||
|   | |||||||
| @@ -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 data_encoding::BASE64; | ||||||
|         use crypto; |         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) { |     pub fn delete_twofactor_remember(&mut self) { | ||||||
|   | |||||||
| @@ -6,6 +6,7 @@ mod user; | |||||||
|  |  | ||||||
| mod collection; | mod collection; | ||||||
| mod organization; | mod organization; | ||||||
|  | mod two_factor; | ||||||
|  |  | ||||||
| pub use self::attachment::Attachment; | pub use self::attachment::Attachment; | ||||||
| pub use self::cipher::Cipher; | pub use self::cipher::Cipher; | ||||||
| @@ -15,3 +16,4 @@ pub use self::user::User; | |||||||
| pub use self::organization::Organization; | pub use self::organization::Organization; | ||||||
| pub use self::organization::{UserOrganization, UserOrgStatus, UserOrgType}; | pub use self::organization::{UserOrganization, UserOrgStatus, UserOrgType}; | ||||||
| pub use self::collection::{Collection, CollectionUser, CollectionCipher}; | pub use self::collection::{Collection, CollectionUser, CollectionCipher}; | ||||||
|  | pub use self::two_factor::{TwoFactor, TwoFactorType}; | ||||||
							
								
								
									
										112
									
								
								src/db/models/two_factor.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								src/db/models/two_factor.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -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() | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -27,7 +27,8 @@ pub struct User { | |||||||
|     pub private_key: Option<String>, |     pub private_key: Option<String>, | ||||||
|     pub public_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 totp_recover: Option<String>, | ||||||
|  |  | ||||||
|     pub security_stamp: String, |     pub security_stamp: String, | ||||||
| @@ -64,7 +65,7 @@ impl User { | |||||||
|             private_key: None, |             private_key: None, | ||||||
|             public_key: None, |             public_key: None, | ||||||
|              |              | ||||||
|             totp_secret: None, |             _totp_secret: None, | ||||||
|             totp_recover: None, |             totp_recover: None, | ||||||
|  |  | ||||||
|             equivalent_domains: "[]".to_string(), |             equivalent_domains: "[]".to_string(), | ||||||
| @@ -97,28 +98,6 @@ impl User { | |||||||
|     pub fn reset_security_stamp(&mut self) { |     pub fn reset_security_stamp(&mut self) { | ||||||
|         self.security_stamp = Uuid::new_v4().to_string(); |         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; | use diesel; | ||||||
| @@ -130,10 +109,13 @@ use db::schema::users; | |||||||
| impl User { | impl User { | ||||||
|     pub fn to_json(&self, conn: &DbConn) -> JsonValue { |     pub fn to_json(&self, conn: &DbConn) -> JsonValue { | ||||||
|         use super::UserOrganization; |         use super::UserOrganization; | ||||||
|  |         use super::TwoFactor; | ||||||
|  |  | ||||||
|         let orgs = UserOrganization::find_by_user(&self.uuid, conn); |         let orgs = UserOrganization::find_by_user(&self.uuid, conn); | ||||||
|         let orgs_json: Vec<JsonValue> = orgs.iter().map(|c| c.to_json(&conn)).collect(); |         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!({ |         json!({ | ||||||
|             "Id": self.uuid, |             "Id": self.uuid, | ||||||
|             "Name": self.name, |             "Name": self.name, | ||||||
| @@ -142,7 +124,7 @@ impl User { | |||||||
|             "Premium": true, |             "Premium": true, | ||||||
|             "MasterPasswordHint": self.password_hint, |             "MasterPasswordHint": self.password_hint, | ||||||
|             "Culture": "en-US", |             "Culture": "en-US", | ||||||
|             "TwoFactorEnabled": self.totp_secret.is_some(), |             "TwoFactorEnabled": twofactor_enabled, | ||||||
|             "Key": self.key, |             "Key": self.key, | ||||||
|             "PrivateKey": self.private_key, |             "PrivateKey": self.private_key, | ||||||
|             "SecurityStamp": self.security_stamp, |             "SecurityStamp": self.security_stamp, | ||||||
|   | |||||||
| @@ -79,6 +79,17 @@ table! { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | table! { | ||||||
|  |     twofactor (uuid) { | ||||||
|  |         uuid -> Text, | ||||||
|  |         user_uuid -> Text, | ||||||
|  |         #[sql_name = "type"] | ||||||
|  |         type_ -> Integer, | ||||||
|  |         enabled -> Bool, | ||||||
|  |         data -> Text, | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| table! { | table! { | ||||||
|     users (uuid) { |     users (uuid) { | ||||||
|         uuid -> Text, |         uuid -> Text, | ||||||
| @@ -132,6 +143,7 @@ joinable!(devices -> users (user_uuid)); | |||||||
| joinable!(folders -> users (user_uuid)); | joinable!(folders -> users (user_uuid)); | ||||||
| joinable!(folders_ciphers -> ciphers (cipher_uuid)); | joinable!(folders_ciphers -> ciphers (cipher_uuid)); | ||||||
| joinable!(folders_ciphers -> folders (folder_uuid)); | joinable!(folders_ciphers -> folders (folder_uuid)); | ||||||
|  | joinable!(twofactor -> users (user_uuid)); | ||||||
| joinable!(users_collections -> collections (collection_uuid)); | joinable!(users_collections -> collections (collection_uuid)); | ||||||
| joinable!(users_collections -> users (user_uuid)); | joinable!(users_collections -> users (user_uuid)); | ||||||
| joinable!(users_organizations -> organizations (org_uuid)); | joinable!(users_organizations -> organizations (org_uuid)); | ||||||
| @@ -146,6 +158,7 @@ allow_tables_to_appear_in_same_query!( | |||||||
|     folders, |     folders, | ||||||
|     folders_ciphers, |     folders_ciphers, | ||||||
|     organizations, |     organizations, | ||||||
|  |     twofactor, | ||||||
|     users, |     users, | ||||||
|     users_collections, |     users_collections, | ||||||
|     users_organizations, |     users_organizations, | ||||||
|   | |||||||
| @@ -19,9 +19,13 @@ extern crate chrono; | |||||||
| extern crate oath; | extern crate oath; | ||||||
| extern crate data_encoding; | extern crate data_encoding; | ||||||
| extern crate jsonwebtoken as jwt; | extern crate jsonwebtoken as jwt; | ||||||
|  | extern crate u2f; | ||||||
| extern crate dotenv; | extern crate dotenv; | ||||||
| #[macro_use] | #[macro_use] | ||||||
| extern crate lazy_static; | extern crate lazy_static; | ||||||
|  | #[macro_use] | ||||||
|  | extern crate num_derive; | ||||||
|  | extern crate num_traits; | ||||||
|  |  | ||||||
| use std::{env, path::Path, process::{exit, Command}}; | use std::{env, path::Path, process::{exit, Command}}; | ||||||
| use rocket::Rocket; | use rocket::Rocket; | ||||||
| @@ -160,6 +164,7 @@ pub struct Config { | |||||||
|     local_icon_extractor: bool, |     local_icon_extractor: bool, | ||||||
|     signups_allowed: bool, |     signups_allowed: bool, | ||||||
|     password_iterations: i32, |     password_iterations: i32, | ||||||
|  |     domain: String, | ||||||
| } | } | ||||||
|  |  | ||||||
| impl Config { | impl Config { | ||||||
| @@ -184,6 +189,7 @@ impl Config { | |||||||
|             local_icon_extractor: util::parse_option_string(env::var("LOCAL_ICON_EXTRACTOR").ok()).unwrap_or(false), |             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), |             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), |             password_iterations: util::parse_option_string(env::var("PASSWORD_ITERATIONS").ok()).unwrap_or(100_000), | ||||||
|  |             domain: env::var("DOMAIN").unwrap_or("https://localhost".into()), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -132,7 +132,9 @@ pub fn format_date(date: &NaiveDateTime) -> String { | |||||||
| use std::fmt; | use std::fmt; | ||||||
|  |  | ||||||
| use serde::de::{self, DeserializeOwned, Deserializer, MapAccess, SeqAccess, Visitor}; | 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)] | #[derive(PartialEq, Serialize, Deserialize)] | ||||||
| pub struct UpCase<T: DeserializeOwned> { | 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> |     fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error> | ||||||
|         where A: MapAccess<'de> |         where A: MapAccess<'de> | ||||||
|     { |     { | ||||||
|         use serde_json::Map; |         let mut result_map = JsonMap::new(); | ||||||
|         let mut result_map = Map::<String, Value>::new(); |  | ||||||
|  |  | ||||||
|         while let Some((key, value)) = map.next_entry()? { |         while let Some((key, value)) = map.next_entry()? { | ||||||
|             result_map.insert(upcase_first(key), upcase_value(&value)); |             result_map.insert(upcase_first(key), upcase_value(&value)); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user