aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock731
-rw-r--r--Cargo.toml7
-rw-r--r--src/client.rs115
-rw-r--r--src/cmd/stream.rs36
-rw-r--r--src/cmd/watch.rs49
-rw-r--r--src/error.rs41
-rw-r--r--src/main.rs1
-rw-r--r--src/oauth.rs82
-rw-r--r--src/oauth/recurse_center.rs85
-rw-r--r--src/protocol.rs100
-rw-r--r--src/server.rs116
11 files changed, 1308 insertions, 55 deletions
diff --git a/Cargo.lock b/Cargo.lock
index edf89c4..1288de6 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,6 +1,11 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
+name = "adler32"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "aho-corasick"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -22,6 +27,11 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "arrayref"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "arrayvec"
version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -64,11 +74,42 @@ dependencies = [
]
[[package]]
+name = "base64"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "safemem 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "base64"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "bitflags"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "block-buffer"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "byte-tools"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "byteorder"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -79,6 +120,7 @@ version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -124,6 +166,32 @@ dependencies = [
]
[[package]]
+name = "cookie"
+version = "0.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "cookie_store"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "publicsuffix 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
+ "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
+ "try_from 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "core-foundation"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -138,6 +206,14 @@ version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "crc32fast"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "crossbeam-deque"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -261,11 +337,65 @@ dependencies = [
]
[[package]]
+name = "curl"
+version = "0.4.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "curl-sys 0.4.23 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-sys 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)",
+ "schannel 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "socket2 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "curl-sys"
+version = "0.4.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-sys 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "vcpkg 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "digest"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "doc-comment"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "dtoa"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "either"
+version = "1.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "encoding_rs"
+version = "0.8.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "env_logger"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -278,6 +408,15 @@ dependencies = [
]
[[package]]
+name = "error-chain"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "backtrace 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)",
+ "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "evmap"
version = "6.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -287,6 +426,42 @@ dependencies = [
]
[[package]]
+name = "failure"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "backtrace 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "failure_derive"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "fake-simd"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "flate2"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
+ "miniz_oxide 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "fnv"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -329,6 +504,15 @@ version = "0.1.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "futures-cpupool"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "futures01"
version = "0.1.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -337,6 +521,14 @@ dependencies = [
]
[[package]]
+name = "generic-array"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "getrandom"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -347,11 +539,54 @@ dependencies = [
]
[[package]]
+name = "h2"
+version = "0.1.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
+ "http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "indexmap 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "hashbrown"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "http"
+version = "0.1.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "http-body"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
+ "http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "httparse"
+version = "1.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "humantime"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -360,6 +595,72 @@ dependencies = [
]
[[package]]
+name = "hyper"
+version = "0.12.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "h2 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)",
+ "http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "http-body 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-reactor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-threadpool 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "want 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "hyper-tls"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
+ "hyper 0.12.35 (registry+https://github.com/rust-lang/crates.io-index)",
+ "native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "idna"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "idna"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "indexmap"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "iovec"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -369,6 +670,11 @@ dependencies = [
]
[[package]]
+name = "itoa"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "kernel32-sys"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -388,6 +694,17 @@ version = "0.2.62"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "libz-sys"
+version = "1.0.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "vcpkg 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "lock_api"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -404,6 +721,11 @@ dependencies = [
]
[[package]]
+name = "matches"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "memchr"
version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -417,6 +739,28 @@ dependencies = [
]
[[package]]
+name = "mime"
+version = "0.3.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "mime_guess"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "mime 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicase 2.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "miniz_oxide"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "mio"
version = "0.6.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -500,6 +844,35 @@ dependencies = [
]
[[package]]
+name = "oauth2"
+version = "3.0.0-alpha.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "curl 0.4.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
+ "http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "reqwest 0.9.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
+ "sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "open"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "openssl"
version = "0.10.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -554,6 +927,16 @@ dependencies = [
]
[[package]]
+name = "percent-encoding"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "percent-encoding"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "pkg-config"
version = "0.3.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -572,6 +955,26 @@ dependencies = [
]
[[package]]
+name = "proc-macro2"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "publicsuffix"
+version = "1.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "quick-error"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -585,6 +988,14 @@ dependencies = [
]
[[package]]
+name = "quote"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "rand"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -765,6 +1176,39 @@ dependencies = [
]
[[package]]
+name = "reqwest"
+version = "0.9.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cookie_store 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "encoding_rs 0.8.20 (registry+https://github.com/rust-lang/crates.io-index)",
+ "flate2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
+ "http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "hyper 0.12.35 (registry+https://github.com/rust-lang/crates.io-index)",
+ "hyper-tls 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mime 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mime_guess 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_urlencoded 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-threadpool 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winreg 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "rustc-demangle"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -778,6 +1222,16 @@ dependencies = [
]
[[package]]
+name = "ryu"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "safemem"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "schannel"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -824,6 +1278,56 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "serde"
+version = "1.0.101"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.101"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.41"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "serde_urlencoded"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "sha2"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "signal-hook"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -873,6 +1377,25 @@ dependencies = [
]
[[package]]
+name = "socket2"
+version = "0.3.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
+ "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "string"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "strsim"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -888,6 +1411,27 @@ dependencies = [
]
[[package]]
+name = "syn"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "synstructure"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "teleterm"
version = "0.1.0"
dependencies = [
@@ -896,17 +1440,24 @@ dependencies = [
"crossterm 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)",
"native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "oauth2 3.0.0-alpha.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "open 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"ratelimit_meter 5.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "reqwest 0.9.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
"snafu 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-pty-process 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-signal 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-tls 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"twoway 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -948,6 +1499,16 @@ dependencies = [
]
[[package]]
+name = "time"
+version = "0.1.42"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
+ "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "tokio"
version = "0.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -971,6 +1532,16 @@ dependencies = [
]
[[package]]
+name = "tokio-buf"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "tokio-codec"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1157,6 +1728,19 @@ dependencies = [
]
[[package]]
+name = "try-lock"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "try_from"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "twoway"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1166,11 +1750,40 @@ dependencies = [
]
[[package]]
+name = "typenum"
+version = "1.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "unchecked-index"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "unicase"
+version = "2.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "unicode-bidi"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "unicode-normalization"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "unicode-width"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1181,6 +1794,31 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "unicode-xid"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "url"
+version = "1.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "url"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "uuid"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1199,6 +1837,21 @@ version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "version_check"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "want"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "wasi"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1250,6 +1903,14 @@ dependencies = [
]
[[package]]
+name = "winreg"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "ws2_32-sys"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1259,15 +1920,21 @@ dependencies = [
]
[metadata]
+"checksum adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2"
"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum arc-swap 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f1a1eca3195b729bbd64e292ef2f5fff6b1c28504fed762ce2b1013dde4d8e92"
+"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee"
"checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba"
"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90"
"checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875"
"checksum backtrace 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)" = "690a62be8920ccf773ee00ef0968649b0e724cda8bd5b12286302b4ae955fdf5"
"checksum backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "82a830b4ef2d1124a711c71d263c5abdc710ef8e907bd508c88be475cebc422b"
+"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
+"checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643"
"checksum bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8a606a02debe2813760609f57a64a2ffd27d9fdf5b2f133eaca0b248dd92cdd2"
+"checksum block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab"
+"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40"
"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
"checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c"
"checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101"
@@ -1275,8 +1942,11 @@ dependencies = [
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
+"checksum cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "888604f00b3db336d2af898ec3c1d5d0ddf5e6d462220f2ededc33a87ac4bbd5"
+"checksum cookie_store 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46750b3f362965f197996c4448e4a0935e791bf7d6631bfce9ee0af3d24c919c"
"checksum core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "25b9e03f145fd4f2bf705e07b900cd41fc636598fe5dc452fd0db1441c3f496d"
"checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b"
+"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
"checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71"
"checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9"
"checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b"
@@ -1289,9 +1959,20 @@ dependencies = [
"checksum crossterm_terminal 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1882bfcef878a2ef66c36d988f8c2f1ec487a62c929a66e5f9ca75c03d0c4058"
"checksum crossterm_utils 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f1b46df236ff59f418afe87b2f19941e050ac205f1f1aa0bdba114b820201477"
"checksum crossterm_winapi 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1521f4476da2d62ec558221bf3136d834cc08c585b1bcb2c072f89e47b27f138"
+"checksum curl 0.4.25 (registry+https://github.com/rust-lang/crates.io-index)" = "06aa71e9208a54def20792d877bc663d6aae0732b9852e612c4a933177c31283"
+"checksum curl-sys 0.4.23 (registry+https://github.com/rust-lang/crates.io-index)" = "f71cd2dbddb49c744c1c9e0b96106f50a634e8759ec51bcd5399a578700a3ab3"
+"checksum digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90"
"checksum doc-comment 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "923dea538cea0aa3025e8685b20d6ee21ef99c4f77e954a30febbaac5ec73a97"
+"checksum dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ea57b42383d091c85abcc2706240b94ab2a8fa1fc81c10ff23c4de06e2a90b5e"
+"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
+"checksum encoding_rs 0.8.20 (registry+https://github.com/rust-lang/crates.io-index)" = "87240518927716f79692c2ed85bfe6e98196d18c6401ec75355760233a7e12e9"
"checksum env_logger 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "39ecdb7dd54465526f0a56d666e3b2dd5f3a218665a030b6e4ad9e70fa95d8fa"
+"checksum error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ab49e9dcb602294bc42f9a7dfc9bc6e936fca4418ea300dbfb84fe16de0b7d9"
"checksum evmap 6.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6fdb60074c9b82c91f8702fa5351b85d22b668dae7f73bf06b44a09bc372380f"
+"checksum failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9"
+"checksum failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08"
+"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
+"checksum flate2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ad3c5233c9a940c8719031b423d7e6c16af66e031cb0420b0896f5245bf181d3"
"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
"checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
@@ -1299,18 +1980,35 @@ dependencies = [
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
"checksum futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1b980f2816d6ee8673b6517b52cb0e808a180efc92e5c19d02cdda79066703ef"
+"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4"
"checksum futures01 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "7ef8cbbf52909170053540c6c05a62433ddb60662dabee714e2a882caa864f22"
+"checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d"
"checksum getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571"
+"checksum h2 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b34c246847f938a410a03c5458c7fee2274436675e76d8b903c08efc29c462"
"checksum hashbrown 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e1de41fb8dba9714efd92241565cdff73f78508c95697dd56787d3cba27e2353"
+"checksum http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "372bcb56f939e449117fb0869c2e8fd8753a8223d92a172c6e808cf123a5b6e4"
+"checksum http-body 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6741c859c1b2463a423a1dbce98d418e6c3c3fc720fb0d45528657320920292d"
+"checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9"
"checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
+"checksum hyper 0.12.35 (registry+https://github.com/rust-lang/crates.io-index)" = "9dbe6ed1438e1f8ad955a4701e9a944938e9519f6888d12d8558b645e247d5f6"
+"checksum hyper-tls 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3a800d6aa50af4b5850b2b0f659625ce9504df908e9733b635720483be26174f"
+"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e"
+"checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9"
+"checksum indexmap 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a61202fbe46c4a951e9404a720a0180bcf3212c750d735cb5c4ba4dc551299f3"
"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
+"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba"
+"checksum libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "2eb5e43362e38e2bca2fd5f5134c4d4564a23a5c28e9b95411652021a8675ebe"
"checksum lock_api 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8912e782533a93a167888781b836336a6ca5da6175c05944c86cf28c31104dc"
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
+"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e"
"checksum memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f"
+"checksum mime 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "dd1d63acd1b78403cc0c325605908475dd9b9a3acbf65ed8bcab97e27014afcf"
+"checksum mime_guess 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1a0ed03949aef72dbdf3116a383d7b38b4768e6f960528cd6a6044aa9ed68599"
+"checksum miniz_oxide 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "304f66c19be2afa56530fa7c39796192eef38618da8d19df725ad7c6d6b2aaae"
"checksum mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)" = "83f51996a3ed004ef184e16818edc51fadffe8e7ca68be67f9dee67d84d0ff23"
"checksum mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125"
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
@@ -1319,16 +2017,23 @@ dependencies = [
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
"checksum nonzero_ext 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "db1b4163932b207be6e3a06412aed4d84cca40dc087419f231b3a38cba2ca8e9"
"checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273"
+"checksum oauth2 3.0.0-alpha.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d69f226653e3db15acb32fdd1017733923f92aa77c1d6ccacce66d623fa8d720"
+"checksum open 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "94b424e1086328b0df10235c6ff47be63708071881bead9e76997d9291c0134b"
"checksum openssl 0.10.25 (registry+https://github.com/rust-lang/crates.io-index)" = "2f372b2b53ce10fb823a337aaa674e3a7d072b957c6264d0f4ff0bd86e657449"
"checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
"checksum openssl-sys 0.9.51 (registry+https://github.com/rust-lang/crates.io-index)" = "ba24190c8f0805d3bd2ce028f439fe5af1d55882bbe6261bed1dbc93b50dd6b1"
"checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252"
"checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b"
+"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
+"checksum percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
"checksum pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "72d5370d90f49f70bd033c3d75e87fc529fbfff9d6f7cccef07d6170079d91ea"
"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b"
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
+"checksum proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "90cf5f418035b98e655e9cdb225047638296b862b42411c4e45bb88d700f7fc0"
+"checksum publicsuffix 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9bf259a81de2b2eb9850ec990ec78e6a25319715584fd7652b9b26f96fcb1510"
"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
+"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
"checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412"
"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
@@ -1349,27 +2054,41 @@ dependencies = [
"checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd"
"checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716"
"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
+"checksum reqwest 0.9.22 (registry+https://github.com/rust-lang/crates.io-index)" = "2c2064233e442ce85c77231ebd67d9eca395207dec2127fe0bbedde4bd29a650"
"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
+"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8"
+"checksum safemem 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d2b08423011dae9a5ca23f07cf57dac3857f5c885d352b76f6d95f4aea9434d0"
"checksum schannel 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "87f550b06b6cba9c8b8be3ee73f391990116bf527450d2556e9b9ce263b9a021"
"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d"
"checksum security-framework 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eee63d0f4a9ec776eeb30e220f0bc1e092c3ad744b2a379e3993070364d3adc2"
"checksum security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9636f8989cbf61385ae4824b98c1aaa54c994d7d8b41f11c601ed799f0549a56"
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
+"checksum serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd"
+"checksum serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "4b133a43a1ecd55d4086bd5b4dc6c1751c68b1bfbeba7a5040442022c7e7c02e"
+"checksum serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2"
+"checksum serde_urlencoded 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "642dd69105886af2efd227f75a520ec9b44a820d65bc133a9131f7d229fd165a"
+"checksum sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9eb6be24e4c23a84d7184280d2722f7f2731fcdd4a9d886efbfe4413e4847ea0"
"checksum signal-hook 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4f61c4d59f3aaa9f61bba6450a9b80ba48362fd7d651689e7a10c453b1f6dc68"
"checksum signal-hook-registry 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1797d48f38f91643908bb14e35e79928f9f4b3cefb2420a564dde0991b4358dc"
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7"
"checksum snafu 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d0bf93d08d6a44363b47d737f1f5bebbf5e6a1eaaa3d4c128ceeaca6b718292"
"checksum snafu-derive 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "624e94bd38e471f67883b467711e7a7ad7dbe284f5fb7e661dc8a671fc5b26a0"
+"checksum socket2 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "e8b74de517221a2cb01a53349cf54182acdc31a074727d3079068448c0676d85"
+"checksum string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d"
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5"
+"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf"
+"checksum synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f085a5855930c0441ca1288cf044ea4aecf4f43a91668abdb870b4ba546a203"
"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
"checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e"
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
+"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
"checksum tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6"
+"checksum tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8fb220f46c53859a4b7ec083e41dec9778ff0b1851c0942b211edb89e0ccdc46"
"checksum tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c501eceaf96f0e1793cf26beb63da3d11c738c4a943fdf3746d81d64684c39f"
"checksum tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d16217cad7f1b840c5a97dfb3c43b0c871fef423a6e8d2118c604e843662a443"
"checksum tokio-executor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0f27ee0e6db01c5f0b2973824547ce7e637b2ed79b891a9677b0de9bd532b6ac"
@@ -1385,13 +2104,24 @@ dependencies = [
"checksum tokio-tls 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "354b8cd83825b3c20217a9dc174d6a0c67441a2fae5c41bcb1ea6679f6ae0f7c"
"checksum tokio-udp 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f02298505547f73e60f568359ef0d016d5acd6e830ab9bc7c4a5b3403440121b"
"checksum tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "037ffc3ba0e12a0ab4aca92e5234e0dedeb48fddf6ccd260f1f150a36a9f2445"
+"checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382"
+"checksum try_from 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "283d3b89e1368717881a9d51dad843cc435380d8109c9e47d38780a324698d8b"
"checksum twoway 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "766345ed3891b291d01af307cd3ad2992a4261cb6c0c7e665cd3e01cf379dd24"
+"checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9"
"checksum unchecked-index 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eeba86d422ce181a719445e51872fa30f1f7413b62becb52e95ec91aa262d85c"
+"checksum unicase 2.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2e2e6bd1e59e56598518beb94fd6db628ded570326f0a98c679a304bd9f00150"
+"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
+"checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426"
"checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
+"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
+"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a"
+"checksum url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75b414f6c464c879d7f9babf951f23bc3743fb7313c081b2e6ca719067ea9d61"
"checksum uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a"
"checksum vcpkg 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "33dd455d0f96e90a75803cfeb7f948768c08d70a6de9a8d2362461935698bf95"
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
+"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
+"checksum want 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6395efa4784b027708f7451087e647ec73cc74f5d9bc2e418404248d679a230"
"checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
@@ -1400,4 +2130,5 @@ dependencies = [
"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
"checksum wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96f5016b18804d24db43cebf3c77269e7569b8954a8464501c216cc5e070eaa9"
+"checksum winreg 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9"
"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
diff --git a/Cargo.toml b/Cargo.toml
index 499bef9..f8f8f0f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -10,17 +10,24 @@ clap = "2"
crossterm = "0.11"
env_logger = "0.7"
futures = "0.1"
+lazy_static = "1"
log = "0.4"
mio = "0.6"
native-tls = "0.2"
+oauth2 = "3.0.0-alpha.3"
+open = "1"
rand = "0.7"
ratelimit_meter = "5"
+regex = "1"
+reqwest = "0.9"
+serde = "1"
snafu = { version = "0.5", features = ["futures-01"] }
tokio = "0.1"
tokio-pty-process = "0.4"
tokio-signal = "0.2"
tokio-tls = "0.2"
twoway = "0.2"
+url = "1"
uuid = { version = "0.7", features = ["v4"] }
[[bin]]
diff --git a/src/client.rs b/src/client.rs
index 7ecd211..7e5a388 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -71,7 +71,7 @@ pub struct Client<
S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static,
> {
connect: Connector<S>,
- username: String,
+ auth: crate::protocol::Auth,
buffer_size: usize,
term_type: String,
@@ -97,12 +97,12 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static>
{
pub fn stream(
connect: Connector<S>,
- username: &str,
+ auth: &crate::protocol::Auth,
buffer_size: usize,
) -> Self {
Self::new(
connect,
- username,
+ auth,
buffer_size,
&[crate::protocol::Message::start_streaming()],
true,
@@ -111,13 +111,13 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static>
pub fn watch(
connect: Connector<S>,
- username: &str,
+ auth: &crate::protocol::Auth,
buffer_size: usize,
id: &str,
) -> Self {
Self::new(
connect,
- username,
+ auth,
buffer_size,
&[crate::protocol::Message::start_watching(id)],
false,
@@ -126,15 +126,15 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static>
pub fn list(
connect: Connector<S>,
- username: &str,
+ auth: &crate::protocol::Auth,
buffer_size: usize,
) -> Self {
- Self::new(connect, username, buffer_size, &[], true)
+ Self::new(connect, auth, buffer_size, &[], true)
}
fn new(
connect: Connector<S>,
- username: &str,
+ auth: &crate::protocol::Auth,
buffer_size: usize,
on_login: &[crate::protocol::Message],
handle_sigwinch: bool,
@@ -159,7 +159,7 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static>
Self {
connect,
- username: username.to_string(),
+ auth: auth.clone(),
buffer_size,
term_type,
@@ -243,8 +243,8 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static>
);
self.to_send.clear();
- self.send_message(crate::protocol::Message::login_plain(
- &self.username,
+ self.send_message(crate::protocol::Message::login(
+ &self.auth,
&self.term_type,
&crate::term::Size::get()?,
));
@@ -259,6 +259,23 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static>
msg.log("recv");
match msg {
+ // XXX store the id and use it on future requests
+ crate::protocol::Message::OauthRequest { url, id: _id } => {
+ let mut state = None;
+ let parsed_url = url::Url::parse(&url).unwrap();
+ for (k, v) in parsed_url.query_pairs() {
+ if k == "state" {
+ state = Some(v);
+ }
+ }
+ open::that(url).context(crate::error::OpenLink)?;
+ let code = self
+ .wait_for_oauth_response(state.map(|s| s.to_string()))?;
+ self.send_message(crate::protocol::Message::OauthResponse {
+ code,
+ });
+ Ok(crate::component_future::Poll::DidWork)
+ }
crate::protocol::Message::LoggedIn { .. } => {
self.reset_reconnect_timer();
for msg in &self.on_login {
@@ -274,6 +291,82 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static>
)),
}
}
+
+ fn wait_for_oauth_response(
+ &self,
+ state: Option<String>,
+ ) -> Result<String> {
+ lazy_static::lazy_static! {
+ static ref RE: regex::Regex = regex::Regex::new(
+ r"GET (/[^ ]*) HTTP/1\.1"
+ ).unwrap();
+ }
+
+ let addr =
+ "127.0.0.1:44141".parse().context(crate::error::ParseAddr)?;
+ let listener = tokio::net::TcpListener::bind(&addr)
+ .context(crate::error::Bind)?;
+ let (wcode, rcode) = tokio::sync::mpsc::channel(1);
+ let wcode2 = wcode.clone();
+ let fut = listener
+ .incoming()
+ .into_future()
+ .map_err(|(e, _)| e)
+ .context(crate::error::Acceptor)
+ .and_then(|(sock, _)| {
+ let sock = sock.unwrap();
+ tokio::io::lines(std::io::BufReader::new(sock))
+ .into_future()
+ .map_err(|(e, _)| e)
+ .context(crate::error::ReadSocket)
+ })
+ .and_then(move |(buf, lines)| {
+ let buf = buf.unwrap();
+ let path = &RE.captures(&buf).unwrap()[1];
+ let base = url::Url::parse("http://localhost:44141").unwrap();
+ let url = base.join(path).unwrap();
+ let mut req_code = None;
+ let mut req_state = None;
+ for (k, v) in url.query_pairs() {
+ if k == "code" {
+ req_code = Some(v.to_string());
+ }
+ if k == "state" {
+ req_state = Some(v.to_string());
+ }
+ }
+ let res = if let Some(auth_state) = state {
+ if req_state.is_none() || req_state.unwrap() != auth_state
+ {
+ unimplemented!()
+ } else {
+ Ok(req_code.unwrap())
+ }
+ } else {
+ Ok(req_code.unwrap())
+ };
+ wcode
+ .send(res)
+ .context(crate::error::SendResultChannel)
+ .map(|_| lines.into_inner().into_inner())
+ })
+ .and_then(|sock| {
+ let response = r"HTTP/1.1 200 OK
+
+authenticated successfully! now close this page and return to your terminal.
+";
+ tokio::io::write_all(sock, response)
+ .context(crate::error::WriteSocket)
+ })
+ .map(|_| ())
+ .map_err(|e| {
+ wcode2.wait().send(Err(e)).unwrap();
+ });
+ tokio::spawn(fut);
+ // XXX we don't actually want to block the main thread here - move
+ // this to a background thing that we poll instead
+ rcode.wait().next().unwrap().unwrap()
+ }
}
impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static>
diff --git a/src/cmd/stream.rs b/src/cmd/stream.rs
index 695f54b..4a68fb9 100644
--- a/src/cmd/stream.rs
+++ b/src/cmd/stream.rs
@@ -4,11 +4,16 @@ use tokio::io::AsyncWrite as _;
pub fn cmd<'a, 'b>(app: clap::App<'a, 'b>) -> clap::App<'a, 'b> {
app.about("Stream your terminal")
.arg(
- clap::Arg::with_name("username")
- .long("username")
+ clap::Arg::with_name("login-plain")
+ .long("login-plain")
.takes_value(true),
)
.arg(
+ clap::Arg::with_name("login-recurse-center")
+ .long("login-recurse-center")
+ .conflicts_with("login-plain"),
+ )
+ .arg(
clap::Arg::with_name("address")
.long("address")
.takes_value(true),
@@ -24,11 +29,16 @@ pub fn cmd<'a, 'b>(app: clap::App<'a, 'b>) -> clap::App<'a, 'b> {
}
pub fn run<'a>(matches: &clap::ArgMatches<'a>) -> super::Result<()> {
- let username = matches
- .value_of("username")
- .map(std::string::ToString::to_string)
- .or_else(|| std::env::var("USER").ok())
- .context(crate::error::CouldntFindUsername)?;
+ let auth = if matches.is_present("login-recurse-center") {
+ crate::protocol::Auth::RecurseCenter { id: None }
+ } else {
+ let username = matches
+ .value_of("login-plain")
+ .map(std::string::ToString::to_string)
+ .or_else(|| std::env::var("USER").ok())
+ .context(crate::error::CouldntFindUsername)?;
+ crate::protocol::Auth::Plain { username }
+ };
let (host, address) =
crate::util::resolve_address(matches.value_of("address"))?;
let tls = matches.is_present("tls");
@@ -48,11 +58,11 @@ pub fn run<'a>(matches: &clap::ArgMatches<'a>) -> super::Result<()> {
} else {
vec![]
};
- run_impl(&username, &host, address, tls, buffer_size, &command, &args)
+ run_impl(&auth, &host, address, tls, buffer_size, &command, &args)
}
fn run_impl(
- username: &str,
+ auth: &crate::protocol::Auth,
host: &str,
address: std::net::SocketAddr,
tls: bool,
@@ -84,7 +94,7 @@ fn run_impl(
args,
connect,
buffer_size,
- username,
+ auth,
))
} else {
let connect: crate::client::Connector<_> = Box::new(move || {
@@ -98,7 +108,7 @@ fn run_impl(
args,
connect,
buffer_size,
- username,
+ auth,
))
};
tokio::run(fut.map_err(|e| {
@@ -131,10 +141,10 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static>
args: &[String],
connect: crate::client::Connector<S>,
buffer_size: usize,
- username: &str,
+ auth: &crate::protocol::Auth,
) -> Self {
let client =
- crate::client::Client::stream(connect, username, buffer_size);
+ crate::client::Client::stream(connect, auth, buffer_size);
// TODO: tokio::io::stdin is broken (it's blocking)
// see https://github.com/tokio-rs/tokio/issues/589
diff --git a/src/cmd/watch.rs b/src/cmd/watch.rs
index 43d14a0..ae8d31b 100644
--- a/src/cmd/watch.rs
+++ b/src/cmd/watch.rs
@@ -4,11 +4,16 @@ use std::io::Write as _;
pub fn cmd<'a, 'b>(app: clap::App<'a, 'b>) -> clap::App<'a, 'b> {
app.about("Watch teleterm streams")
.arg(
- clap::Arg::with_name("username")
- .long("username")
+ clap::Arg::with_name("login-plain")
+ .long("login-plain")
.takes_value(true),
)
.arg(
+ clap::Arg::with_name("login-recurse-center")
+ .long("login-recurse-center")
+ .conflicts_with("login-plain"),
+ )
+ .arg(
clap::Arg::with_name("address")
.long("address")
.takes_value(true),
@@ -17,25 +22,30 @@ pub fn cmd<'a, 'b>(app: clap::App<'a, 'b>) -> clap::App<'a, 'b> {
}
pub fn run<'a>(matches: &clap::ArgMatches<'a>) -> super::Result<()> {
- let username = matches
- .value_of("username")
- .map(std::string::ToString::to_string)
- .or_else(|| std::env::var("USER").ok())
- .context(crate::error::CouldntFindUsername)?;
+ let auth = if matches.is_present("login-recurse-center") {
+ crate::protocol::Auth::RecurseCenter { id: None }
+ } else {
+ let username = matches
+ .value_of("login-plain")
+ .map(std::string::ToString::to_string)
+ .or_else(|| std::env::var("USER").ok())
+ .context(crate::error::CouldntFindUsername)?;
+ crate::protocol::Auth::Plain { username }
+ };
let (host, address) =
crate::util::resolve_address(matches.value_of("address"))?;
let tls = matches.is_present("tls");
- run_impl(&username, &host, address, tls)
+ run_impl(&auth, &host, address, tls)
}
fn run_impl(
- username: &str,
+ auth: &crate::protocol::Auth,
host: &str,
address: std::net::SocketAddr,
tls: bool,
) -> Result<()> {
let host = host.to_string();
- let username = username.to_string();
+ let auth = auth.clone();
let fut: Box<
dyn futures::future::Future<Item = (), Error = Error> + Send,
> = if tls {
@@ -60,7 +70,7 @@ fn run_impl(
))
})
});
- Box::new(WatchSession::new(make_connector, &username))
+ Box::new(WatchSession::new(make_connector, &auth))
} else {
let make_connector: Box<
dyn Fn() -> crate::client::Connector<_> + Send,
@@ -72,7 +82,7 @@ fn run_impl(
)
})
});
- Box::new(WatchSession::new(make_connector, &username))
+ Box::new(WatchSession::new(make_connector, &auth))
};
tokio::run(fut.map_err(|e| {
eprintln!("{}", e);
@@ -160,7 +170,7 @@ struct WatchSession<
S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static,
> {
make_connector: Box<dyn Fn() -> crate::client::Connector<S> + Send>,
- username: String,
+ auth: crate::protocol::Auth,
key_reader: crate::key_reader::KeyReader,
list_client: crate::client::Client<S>,
@@ -174,17 +184,14 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static>
{
fn new(
make_connector: Box<dyn Fn() -> crate::client::Connector<S> + Send>,
- username: &str,
+ auth: &crate::protocol::Auth,
) -> Self {
- let list_client = crate::client::Client::list(
- make_connector(),
- username,
- 4_194_304,
- );
+ let list_client =
+ crate::client::Client::list(make_connector(), auth, 4_194_304);
Self {
make_connector,
- username: username.to_string(),
+ auth: auth.clone(),
key_reader: crate::key_reader::KeyReader::new(),
list_client,
@@ -286,7 +293,7 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static>
if let Some(id) = sessions.id_for(*c) {
let client = crate::client::Client::watch(
(self.make_connector)(),
- &self.username,
+ &self.auth,
4_194_304,
id,
);
diff --git a/src/error.rs b/src/error.rs
index 42135d8..2836f32 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -25,6 +25,18 @@ pub enum Error {
#[snafu(display("eof"))]
EOF,
+ #[snafu(display("failed to retrieve access token: {:?}", msg))]
+ ExchangeCode {
+ msg: String,
+ // XXX RequestTokenError doesn't implement the right traits
+ // source: oauth2::RequestTokenError<
+ // oauth2::reqwest::Error,
+ // oauth2::StandardErrorResponse<
+ // oauth2::basic::BasicErrorResponseType,
+ // >,
+ // >
+ },
+
#[snafu(display("failed to parse string: {:?}", data))]
ExtraMessageData { data: Vec<u8> },
@@ -34,6 +46,12 @@ pub enum Error {
#[snafu(display("failed to flush writes to terminal: {}", source))]
FlushTerminalSync { source: std::io::Error },
+ #[snafu(display(
+ "failed to get recurse center profile data: {}",
+ source
+ ))]
+ GetProfile { source: reqwest::Error },
+
#[snafu(display("failed to get terminal size: {}", source))]
GetTerminalSize { source: crossterm::ErrorKind },
@@ -78,6 +96,9 @@ pub enum Error {
#[snafu(display("failed to open identity file: {}", source))]
OpenIdentityFile { source: std::io::Error },
+ #[snafu(display("failed to open link in browser: {}", source))]
+ OpenLink { source: std::io::Error },
+
#[snafu(display("failed to open a pty: {}", source))]
OpenPty { source: std::io::Error },
@@ -104,6 +125,9 @@ pub enum Error {
source: std::array::TryFromSliceError,
},
+ #[snafu(display("failed to parse response json: {}", source))]
+ ParseJson { source: reqwest::Error },
+
#[snafu(display("failed to parse address: {}", source))]
ParsePort { source: std::num::ParseIntError },
@@ -120,6 +144,9 @@ pub enum Error {
#[snafu(display("failed to parse string: {}", source))]
ParseString { source: std::string::FromUtf8Error },
+ #[snafu(display("failed to parse url: {}", source))]
+ ParseUrl { source: url::ParseError },
+
#[snafu(display("failed to poll for process exit: {}", source))]
ProcessExitPoll { source: std::io::Error },
@@ -152,6 +179,9 @@ pub enum Error {
#[snafu(display("failed to read from pty: {}", source))]
ReadPty { source: std::io::Error },
+ #[snafu(display("failed to read from socket: {}", source))]
+ ReadSocket { source: tokio::io::Error },
+
#[snafu(display("failed to read from terminal: {}", source))]
ReadTerminal { source: std::io::Error },
@@ -162,6 +192,14 @@ pub enum Error {
ResolveAddress { source: std::io::Error },
#[snafu(display(
+ "failed to send oauth result back to main thread: {}",
+ source
+ ))]
+ SendResultChannel {
+ source: tokio::sync::mpsc::error::SendError,
+ },
+
+ #[snafu(display(
"failed to send accepted socket to server thread: {}",
source
))]
@@ -262,6 +300,9 @@ pub enum Error {
#[snafu(display("failed to write to pty: {}", source))]
WritePty { source: std::io::Error },
+ #[snafu(display("failed to write to socket: {}", source))]
+ WriteSocket { source: tokio::io::Error },
+
#[snafu(display("failed to write to stdout: {}", source))]
WriteTerminal { source: tokio::io::Error },
diff --git a/src/main.rs b/src/main.rs
index 5d528bf..89124d9 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -15,6 +15,7 @@ mod cmd;
mod component_future;
mod error;
mod key_reader;
+mod oauth;
mod process;
mod protocol;
mod server;
diff --git a/src/oauth.rs b/src/oauth.rs
new file mode 100644
index 0000000..8d1944a
--- /dev/null
+++ b/src/oauth.rs
@@ -0,0 +1,82 @@
+use crate::prelude::*;
+
+pub mod recurse_center;
+
+pub trait Oauth {
+ fn client(&self) -> &oauth2::basic::BasicClient;
+
+ fn generate_authorize_url(&self) -> String {
+ let (auth_url, _) = self
+ .client()
+ .authorize_url(oauth2::CsrfToken::new_random)
+ .url();
+ auth_url.to_string()
+ }
+
+ fn get_token(
+ &self,
+ code: &str,
+ ) -> Box<
+ dyn futures::future::Future<
+ Item = oauth2::basic::BasicTokenResponse,
+ Error = Error,
+ > + Send,
+ > {
+ let fut = self
+ .client()
+ .exchange_code(oauth2::AuthorizationCode::new(code.to_string()))
+ .request_async(oauth2::reqwest::async_http_client)
+ .map_err(|e| {
+ let msg = stringify_oauth2_http_error(&e);
+ Error::ExchangeCode { msg }
+ });
+ Box::new(fut)
+ }
+
+ fn get_username(
+ &self,
+ code: &str,
+ ) -> Box<dyn futures::future::Future<Item = String, Error = Error> + Send>;
+}
+
+pub struct Config {
+ client_id: String,
+ client_secret: String,
+ auth_url: url::Url,
+ token_url: url::Url,
+ redirect_url: url::Url,
+}
+
+impl Config {
+ fn into_basic_client(self) -> oauth2::basic::BasicClient {
+ oauth2::basic::BasicClient::new(
+ oauth2::ClientId::new(self.client_id),
+ Some(oauth2::ClientSecret::new(self.client_secret)),
+ oauth2::AuthUrl::new(self.auth_url),
+ Some(oauth2::TokenUrl::new(self.token_url)),
+ )
+ .set_redirect_url(oauth2::RedirectUrl::new(self.redirect_url))
+ }
+}
+
+// make this actually give useful information, because the default
+// stringification is pretty useless
+fn stringify_oauth2_http_error(
+ e: &oauth2::RequestTokenError<
+ oauth2::reqwest::Error,
+ oauth2::StandardErrorResponse<oauth2::basic::BasicErrorResponseType>,
+ >,
+) -> String {
+ match e {
+ oauth2::RequestTokenError::ServerResponse(t) => {
+ format!("ServerResponse({})", t)
+ }
+ oauth2::RequestTokenError::Request(re) => format!("Request({})", re),
+ oauth2::RequestTokenError::Parse(se, b) => format!(
+ "Parse({}, {})",
+ se,
+ std::string::String::from_utf8_lossy(b)
+ ),
+ oauth2::RequestTokenError::Other(s) => format!("Other({})", s),
+ }
+}
diff --git a/src/oauth/recurse_center.rs b/src/oauth/recurse_center.rs
new file mode 100644
index 0000000..26aa306
--- /dev/null
+++ b/src/oauth/recurse_center.rs
@@ -0,0 +1,85 @@
+use crate::prelude::*;
+use oauth2::TokenResponse as _;
+
+pub struct Oauth {
+ client: oauth2::basic::BasicClient,
+}
+
+impl Oauth {
+ pub fn new(config: super::Config) -> Self {
+ Self {
+ client: config.into_basic_client(),
+ }
+ }
+}
+
+impl super::Oauth for Oauth {
+ fn client(&self) -> &oauth2::basic::BasicClient {
+ &self.client
+ }
+
+ fn get_username(
+ &self,
+ code: &str,
+ ) -> Box<dyn futures::future::Future<Item = String, Error = Error> + Send>
+ {
+ let fut = self
+ .get_token(code)
+ .and_then(|token| {
+ let access_token = token.access_token();
+ reqwest::r#async::Client::new()
+ .get("https://www.recurse.com/api/v1/profiles/me")
+ .bearer_auth(access_token.secret())
+ .send()
+ .context(crate::error::GetProfile)
+ })
+ .and_then(|mut res| res.json().context(crate::error::ParseJson))
+ .map(|user: User| user.name());
+ Box::new(fut)
+ }
+}
+
+pub fn config(
+ client_id: &str,
+ client_secret: &str,
+ redirect_url: url::Url,
+) -> super::Config {
+ super::Config {
+ client_id: client_id.to_string(),
+ client_secret: client_secret.to_string(),
+ auth_url: url::Url::parse("https://www.recurse.com/oauth/authorize")
+ .unwrap(),
+ token_url: url::Url::parse("https://www.recurse.com/oauth/token")
+ .unwrap(),
+ redirect_url,
+ }
+}
+
+#[derive(serde::Deserialize)]
+struct User {
+ name: String,
+ stints: Vec<Stint>,
+}
+
+#[derive(serde::Deserialize)]
+struct Stint {
+ batch: Option<Batch>,
+ start_date: String,
+}
+
+#[derive(serde::Deserialize)]
+struct Batch {
+ short_name: String,
+}
+
+impl User {
+ fn name(&self) -> String {
+ let latest_stint =
+ self.stints.iter().max_by_key(|s| &s.start_date).unwrap();
+ if let Some(batch) = &latest_stint.batch {
+ format!("{} ({})", self.name, batch.short_name)
+ } else {
+ self.name.to_string()
+ }
+ }
+}
diff --git a/src/protocol.rs b/src/protocol.rs
index 37fe793..5aa6c3c 100644
--- a/src/protocol.rs
+++ b/src/protocol.rs
@@ -55,9 +55,11 @@ pub const PROTO_VERSION: u32 = 1;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Auth {
Plain { username: String },
+ RecurseCenter { id: Option<String> },
}
const AUTH_PLAIN: u32 = 0;
+const AUTH_RECURSE_CENTER: u32 = 1;
// XXX https://github.com/rust-lang/rust/issues/64362
#[allow(dead_code)]
@@ -91,6 +93,13 @@ pub enum Message {
LoggedIn {
username: String,
},
+ OauthRequest {
+ url: String,
+ id: String,
+ },
+ OauthResponse {
+ code: String,
+ },
}
const MSG_LOGIN: u32 = 0;
@@ -104,18 +113,18 @@ const MSG_DISCONNECTED: u32 = 7;
const MSG_ERROR: u32 = 8;
const MSG_RESIZE: u32 = 9;
const MSG_LOGGED_IN: u32 = 10;
+const MSG_OAUTH_REQUEST: u32 = 11;
+const MSG_OAUTH_RESPONSE: u32 = 12;
impl Message {
- pub fn login_plain(
- username: &str,
+ pub fn login(
+ auth: &Auth,
term_type: &str,
size: &crate::term::Size,
) -> Self {
Self::Login {
proto_version: PROTO_VERSION,
- auth: Auth::Plain {
- username: username.to_string(),
- },
+ auth: auth.clone(),
term_type: term_type.to_string(),
size: size.clone(),
}
@@ -169,6 +178,19 @@ impl Message {
}
}
+ pub fn oauth_request(url: &str, id: &str) -> Self {
+ Self::OauthRequest {
+ url: url.to_string(),
+ id: id.to_string(),
+ }
+ }
+
+ pub fn oauth_response(code: &str) -> Self {
+ Self::OauthResponse {
+ code: code.to_string(),
+ }
+ }
+
#[allow(dead_code)]
pub fn read<R: std::io::Read>(r: R) -> Result<Self> {
Packet::read(r).and_then(Self::try_from)
@@ -208,6 +230,13 @@ impl Message {
data.len()
);
}
+ // these are security-sensitive, keep them out of logs
+ Self::OauthRequest { .. } => {
+ log::debug!("{}: message(OauthRequest {{ .. }})", id);
+ }
+ Self::OauthResponse { .. } => {
+ log::debug!("{}: message(OauthResponse {{ .. }})", id);
+ }
message => {
log::debug!("{}: message({:?})", id, message);
}
@@ -340,6 +369,11 @@ impl From<&Message> for Packet {
write_u32(AUTH_PLAIN, data);
write_str(username, data);
}
+ Auth::RecurseCenter { id } => {
+ let id = id.as_ref().map_or("", |s| s.as_str());
+ write_u32(AUTH_RECURSE_CENTER, data);
+ write_str(id, data);
+ }
}
}
@@ -438,6 +472,27 @@ impl From<&Message> for Packet {
data,
}
}
+ Message::OauthRequest { url, id } => {
+ let mut data = vec![];
+
+ write_str(url, &mut data);
+ write_str(id, &mut data);
+
+ Self {
+ ty: MSG_OAUTH_REQUEST,
+ data,
+ }
+ }
+ Message::OauthResponse { code } => {
+ let mut data = vec![];
+
+ write_str(code, &mut data);
+
+ Self {
+ ty: MSG_OAUTH_RESPONSE,
+ data,
+ }
+ }
}
}
}
@@ -532,6 +587,12 @@ impl std::convert::TryFrom<Packet> for Message {
let auth = Auth::Plain { username };
(auth, data)
}
+ AUTH_RECURSE_CENTER => {
+ let (id, data) = read_str(data)?;
+ let id = if id == "" { None } else { Some(id) };
+ let auth = Auth::RecurseCenter { id };
+ (auth, data)
+ }
_ => return Err(Error::InvalidAuthType { ty }),
};
Ok((auth, data))
@@ -588,6 +649,17 @@ impl std::convert::TryFrom<Packet> for Message {
(Self::LoggedIn { username }, data)
}
+ MSG_OAUTH_REQUEST => {
+ let (url, data) = read_str(data)?;
+ let (id, data) = read_str(data)?;
+
+ (Self::OauthRequest { url, id }, data)
+ }
+ MSG_OAUTH_RESPONSE => {
+ let (code, data) = read_str(data)?;
+
+ (Self::OauthResponse { code }, data)
+ }
_ => return Err(Error::InvalidMessageType { ty: packet.ty }),
};
@@ -685,8 +757,22 @@ mod test {
fn valid_messages() -> Vec<Message> {
vec![
- Message::login_plain(
- "doy",
+ Message::login(
+ &Auth::Plain {
+ username: "doy".to_string(),
+ },
+ "screen",
+ &crate::term::Size { rows: 24, cols: 80 },
+ ),
+ Message::login(
+ &Auth::RecurseCenter {
+ id: Some("some-random-id".to_string()),
+ },
+ "screen",
+ &crate::term::Size { rows: 24, cols: 80 },
+ ),
+ Message::login(
+ &Auth::RecurseCenter { id: None },
"screen",
&crate::term::Size { rows: 24, cols: 80 },
),
diff --git a/src/server.rs b/src/server.rs
index 7f04813..6a85d74 100644
--- a/src/server.rs
+++ b/src/server.rs
@@ -147,6 +147,34 @@ impl ConnectionState {
}
}
+ fn login_oauth_start(
+ &mut self,
+ term_type: &str,
+ size: &crate::term::Size,
+ ) {
+ if let Self::Accepted = self {
+ *self = Self::LoggingIn {
+ term_info: TerminalInfo {
+ term: term_type.to_string(),
+ size: size.clone(),
+ },
+ };
+ } else {
+ unreachable!()
+ }
+ }
+
+ fn login_oauth_finish(&mut self, username: &str) {
+ if let Self::LoggingIn { term_info } = self {
+ *self = Self::LoggedIn {
+ username: username.to_string(),
+ term_info: term_info.clone(),
+ };
+ } else {
+ unreachable!()
+ }
+ }
+
fn stream(&mut self, buffer_size: usize) {
if let Self::LoggedIn {
username,
@@ -190,6 +218,7 @@ struct Connection<
closed: bool,
state: ConnectionState,
last_activity: std::time::Instant,
+ oauth_client: Option<Box<dyn crate::oauth::Oauth + Send>>,
}
impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static>
@@ -212,6 +241,7 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static>
closed: false,
state: ConnectionState::new(),
last_activity: std::time::Instant::now(),
+ oauth_client: None,
}
}
@@ -323,6 +353,54 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static>
&username,
));
}
+ crate::protocol::Auth::RecurseCenter { id } => {
+ // XXX this needs some kind of real configuration system
+ let client_id =
+ std::env::var("TT_RECURSE_CENTER_CLIENT_ID").unwrap();
+ let client_secret =
+ std::env::var("TT_RECURSE_CENTER_CLIENT_SECRET").unwrap();
+ let redirect_url =
+ std::env::var("TT_RECURSE_CENTER_REDIRECT_URL").unwrap();
+ let redirect_url = url::Url::parse(&redirect_url).unwrap();
+
+ conn.oauth_client =
+ Some(Box::new(crate::oauth::recurse_center::Oauth::new(
+ crate::oauth::recurse_center::config(
+ &client_id,
+ &client_secret,
+ redirect_url,
+ ),
+ )));
+
+ if let Some(id) = id {
+ log::info!(
+ "{}: login(recurse_center, {:?})",
+ conn.id,
+ id
+ );
+ // refresh
+ unimplemented!()
+ } else {
+ let id = format!("{}", uuid::Uuid::new_v4());
+ log::info!(
+ "{}: login(recurse_center, {:?})",
+ conn.id,
+ id
+ );
+
+ conn.state.login_oauth_start(term_type, &size);
+ conn.send_message(
+ crate::protocol::Message::oauth_request(
+ &conn
+ .oauth_client
+ .as_ref()
+ .unwrap()
+ .generate_authorize_url(),
+ &id,
+ ),
+ );
+ }
+ }
}
Ok(())
@@ -422,6 +500,35 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static>
Ok(())
}
+ fn handle_message_oauth_response(
+ &mut self,
+ conn: &mut Connection<S>,
+ code: &str,
+ ) -> Result<
+ Option<
+ Box<
+ dyn futures::future::Future<
+ Item = (ConnectionState, crate::protocol::Message),
+ Error = Error,
+ > + Send,
+ >,
+ >,
+ > {
+ let client = conn.oauth_client.as_ref().ok_or_else(|| {
+ Error::UnexpectedMessage {
+ message: crate::protocol::Message::oauth_response(code),
+ }
+ })?;
+
+ let mut new_state = conn.state.clone();
+ let fut = client.get_username(code).map(|username| {
+ new_state.login_oauth_finish(&username);
+ (new_state, crate::protocol::Message::logged_in(&username))
+ });
+
+ Ok(Some(Box::new(fut)))
+ }
+
fn handle_accepted_message(
&mut self,
conn: &mut Connection<S>,
@@ -440,7 +547,7 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static>
fn handle_logging_in_message(
&mut self,
- _conn: &mut Connection<S>,
+ conn: &mut Connection<S>,
message: crate::protocol::Message,
) -> Result<
Option<
@@ -452,8 +559,11 @@ impl<S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Send + 'static>
>,
>,
> {
- match &message {
- _ => Err(Error::UnauthenticatedMessage { message }),
+ match message {
+ crate::protocol::Message::OauthResponse { code } => {
+ self.handle_message_oauth_response(conn, &code)
+ }
+ m => Err(Error::UnauthenticatedMessage { message: m }),
}
}