Merge pull request #25 from warp-tech/otp

This commit is contained in:
Eugeny 2022-04-16 22:57:59 +02:00 committed by GitHub
commit 1840cc25cf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 386 additions and 303 deletions

317
Cargo.lock generated
View file

@ -33,7 +33,7 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877"
dependencies = [ dependencies = [
"generic-array 0.14.5", "generic-array",
] ]
[[package]] [[package]]
@ -46,7 +46,7 @@ dependencies = [
"cipher", "cipher",
"cpufeatures", "cpufeatures",
"ctr", "ctr",
"opaque-debug 0.3.0", "opaque-debug",
] ]
[[package]] [[package]]
@ -63,12 +63,6 @@ dependencies = [
"subtle", "subtle",
] ]
[[package]]
name = "ahash"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e"
[[package]] [[package]]
name = "ahash" name = "ahash"
version = "0.7.6" version = "0.7.6"
@ -354,6 +348,12 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "base32"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23ce669cd6c8588f79e15cf450314f9638f967fc5770ff1c7c1deb0925ea7cfa"
[[package]] [[package]]
name = "base64" name = "base64"
version = "0.13.0" version = "0.13.0"
@ -406,25 +406,13 @@ dependencies = [
"digest 0.10.3", "digest 0.10.3",
] ]
[[package]]
name = "block-buffer"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
dependencies = [
"block-padding 0.1.5",
"byte-tools",
"byteorder",
"generic-array 0.12.4",
]
[[package]] [[package]]
name = "block-buffer" name = "block-buffer"
version = "0.9.0" version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
dependencies = [ dependencies = [
"generic-array 0.14.5", "generic-array",
] ]
[[package]] [[package]]
@ -433,7 +421,7 @@ version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324"
dependencies = [ dependencies = [
"generic-array 0.14.5", "generic-array",
] ]
[[package]] [[package]]
@ -442,19 +430,10 @@ version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2cb03d1bed155d89dce0f845b7899b18a9a163e148fd004e1c28421a783e2d8e" checksum = "2cb03d1bed155d89dce0f845b7899b18a9a163e148fd004e1c28421a783e2d8e"
dependencies = [ dependencies = [
"block-padding 0.2.1", "block-padding",
"cipher", "cipher",
] ]
[[package]]
name = "block-padding"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5"
dependencies = [
"byte-tools",
]
[[package]] [[package]]
name = "block-padding" name = "block-padding"
version = "0.2.1" version = "0.2.1"
@ -483,7 +462,7 @@ checksum = "fe3ff3fc1de48c1ac2e3341c4df38b0d1bfb8fdf04632a187c8b75aaa319a7ab"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"cipher", "cipher",
"opaque-debug 0.3.0", "opaque-debug",
] ]
[[package]] [[package]]
@ -493,10 +472,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899"
[[package]] [[package]]
name = "byte-tools" name = "bytemuck"
version = "0.3.1" version = "1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" checksum = "cdead85bdec19c194affaeeb670c0e41fe23de31459efd1c174d049269cf02cc"
[[package]] [[package]]
name = "byteorder" name = "byteorder"
@ -534,6 +513,12 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "checked_int_cast"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17cc5e6b5ab06331c33589842070416baa137e8b0eb912b008cfd4a78ada7919"
[[package]] [[package]]
name = "chrono" name = "chrono"
version = "0.4.19" version = "0.4.19"
@ -554,7 +539,7 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7"
dependencies = [ dependencies = [
"generic-array 0.14.5", "generic-array",
] ]
[[package]] [[package]]
@ -623,6 +608,12 @@ dependencies = [
"winapi 0.3.9", "winapi 0.3.9",
] ]
[[package]]
name = "color_quant"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
[[package]] [[package]]
name = "concurrent-queue" name = "concurrent-queue"
version = "1.2.2" version = "1.2.2"
@ -639,15 +630,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54ad70579325f1a38ea4c13412b82241c5900700a69785d73e2736bd65a33f86" checksum = "54ad70579325f1a38ea4c13412b82241c5900700a69785d73e2736bd65a33f86"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"json5",
"lazy_static 1.4.0", "lazy_static 1.4.0",
"nom", "nom",
"pathdiff", "pathdiff",
"ron",
"rust-ini",
"serde", "serde",
"serde_json",
"toml",
"yaml-rust", "yaml-rust",
] ]
@ -828,7 +814,7 @@ version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8"
dependencies = [ dependencies = [
"generic-array 0.14.5", "generic-array",
"typenum", "typenum",
] ]
@ -838,7 +824,7 @@ version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714"
dependencies = [ dependencies = [
"generic-array 0.14.5", "generic-array",
"subtle", "subtle",
] ]
@ -941,22 +927,13 @@ dependencies = [
"zeroize", "zeroize",
] ]
[[package]]
name = "digest"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
dependencies = [
"generic-array 0.12.4",
]
[[package]] [[package]]
name = "digest" name = "digest"
version = "0.9.0" version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
dependencies = [ dependencies = [
"generic-array 0.14.5", "generic-array",
] ]
[[package]] [[package]]
@ -990,15 +967,6 @@ dependencies = [
"winapi 0.3.9", "winapi 0.3.9",
] ]
[[package]]
name = "dlv-list"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68df3f2b690c1b86e65ef7830956aededf3cb0a16f898f79b9a6f421a7b6211b"
dependencies = [
"rand",
]
[[package]] [[package]]
name = "dotenv" name = "dotenv"
version = "0.15.0" version = "0.15.0"
@ -1032,12 +1000,6 @@ version = "2.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77f3309417938f28bf8228fcff79a4a37103981e3e186d2ccd19c74b38f4eb71" checksum = "77f3309417938f28bf8228fcff79a4a37103981e3e186d2ccd19c74b38f4eb71"
[[package]]
name = "fake-simd"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
[[package]] [[package]]
name = "fastrand" name = "fastrand"
version = "1.7.0" version = "1.7.0"
@ -1244,15 +1206,6 @@ dependencies = [
"slab", "slab",
] ]
[[package]]
name = "generic-array"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd"
dependencies = [
"typenum",
]
[[package]] [[package]]
name = "generic-array" name = "generic-array"
version = "0.14.5" version = "0.14.5"
@ -1280,7 +1233,7 @@ version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99" checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99"
dependencies = [ dependencies = [
"opaque-debug 0.3.0", "opaque-debug",
"polyval", "polyval",
] ]
@ -1321,22 +1274,13 @@ dependencies = [
"tracing", "tracing",
] ]
[[package]]
name = "hashbrown"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
dependencies = [
"ahash 0.4.7",
]
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.11.2" version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
dependencies = [ dependencies = [
"ahash 0.7.6", "ahash",
] ]
[[package]] [[package]]
@ -1345,7 +1289,7 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf" checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf"
dependencies = [ dependencies = [
"hashbrown 0.11.2", "hashbrown",
] ]
[[package]] [[package]]
@ -1374,7 +1318,7 @@ dependencies = [
"http", "http",
"httpdate", "httpdate",
"mime", "mime",
"sha-1 0.10.0", "sha-1",
] ]
[[package]] [[package]]
@ -1556,6 +1500,20 @@ dependencies = [
"unicode-normalization", "unicode-normalization",
] ]
[[package]]
name = "image"
version = "0.23.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24ffcb7e7244a9bf19d35bf2883b9c080c4ced3c07a9895572178cdb8f13f6a1"
dependencies = [
"bytemuck",
"byteorder",
"color_quant",
"num-iter",
"num-rational",
"num-traits",
]
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "1.8.0" version = "1.8.0"
@ -1563,7 +1521,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"hashbrown 0.11.2", "hashbrown",
] ]
[[package]] [[package]]
@ -1631,17 +1589,6 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
[[package]]
name = "json5"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96b0db21af676c1ce64250b5f40f3ce2cf27e4e47cb91ed91eb6fe9350b430c1"
dependencies = [
"pest",
"pest_derive",
"serde",
]
[[package]] [[package]]
name = "kernel32-sys" name = "kernel32-sys"
version = "0.2.2" version = "0.2.2"
@ -1747,12 +1694,6 @@ dependencies = [
"value-bag", "value-bag",
] ]
[[package]]
name = "maplit"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
[[package]] [[package]]
name = "matchers" name = "matchers"
version = "0.1.0" version = "0.1.0"
@ -1947,6 +1888,28 @@ dependencies = [
"num-traits", "num-traits",
] ]
[[package]]
name = "num-iter"
version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-rational"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]] [[package]]
name = "num-traits" name = "num-traits"
version = "0.2.14" version = "0.2.14"
@ -1990,12 +1953,6 @@ version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
[[package]]
name = "opaque-debug"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
[[package]] [[package]]
name = "opaque-debug" name = "opaque-debug"
version = "0.3.0" version = "0.3.0"
@ -2045,16 +2002,6 @@ dependencies = [
"vcpkg", "vcpkg",
] ]
[[package]]
name = "ordered-multimap"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c672c7ad9ec066e428c00eb917124a06f08db19e2584de982cc34b1f4c12485"
dependencies = [
"dlv-list",
"hashbrown 0.9.1",
]
[[package]] [[package]]
name = "os_str_bytes" name = "os_str_bytes"
version = "6.0.0" version = "6.0.0"
@ -2216,49 +2163,6 @@ version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
[[package]]
name = "pest"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53"
dependencies = [
"ucd-trie",
]
[[package]]
name = "pest_derive"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0"
dependencies = [
"pest",
"pest_generator",
]
[[package]]
name = "pest_generator"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55"
dependencies = [
"pest",
"pest_meta",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "pest_meta"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d"
dependencies = [
"maplit",
"pest",
"sha-1 0.8.2",
]
[[package]] [[package]]
name = "petgraph" name = "petgraph"
version = "0.6.0" version = "0.6.0"
@ -2442,7 +2346,7 @@ checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"cpufeatures", "cpufeatures",
"opaque-debug 0.3.0", "opaque-debug",
"universal-hash", "universal-hash",
] ]
@ -2558,6 +2462,16 @@ dependencies = [
"prost", "prost",
] ]
[[package]]
name = "qrcode"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16d2f1455f3630c6e5107b4f2b94e74d76dea80736de0981fd27644216cff57f"
dependencies = [
"checked_int_cast",
"image",
]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.15" version = "1.0.15"
@ -2707,17 +2621,6 @@ dependencies = [
"winapi 0.3.9", "winapi 0.3.9",
] ]
[[package]]
name = "ron"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b861ecaade43ac97886a512b360d01d66be9f41f3c61088b42cedf92e03d678"
dependencies = [
"base64",
"bitflags",
"serde",
]
[[package]] [[package]]
name = "russh" name = "russh"
version = "0.34.0-beta.2" version = "0.34.0-beta.2"
@ -2729,7 +2632,7 @@ dependencies = [
"digest 0.9.0", "digest 0.9.0",
"flate2", "flate2",
"futures", "futures",
"generic-array 0.14.5", "generic-array",
"log", "log",
"openssl", "openssl",
"rand", "rand",
@ -2831,16 +2734,6 @@ dependencies = [
"walkdir", "walkdir",
] ]
[[package]]
name = "rust-ini"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63471c4aa97a1cf8332a5f97709a79a4234698de6a1f5087faf66f2dae810e22"
dependencies = [
"cfg-if 1.0.0",
"ordered-multimap",
]
[[package]] [[package]]
name = "rust_decimal" name = "rust_decimal"
version = "1.22.0" version = "1.22.0"
@ -3147,18 +3040,6 @@ dependencies = [
"yaml-rust", "yaml-rust",
] ]
[[package]]
name = "sha-1"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df"
dependencies = [
"block-buffer 0.7.3",
"digest 0.8.1",
"fake-simd",
"opaque-debug 0.2.3",
]
[[package]] [[package]]
name = "sha-1" name = "sha-1"
version = "0.10.0" version = "0.10.0"
@ -3180,7 +3061,7 @@ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"cpufeatures", "cpufeatures",
"digest 0.9.0", "digest 0.9.0",
"opaque-debug 0.3.0", "opaque-debug",
] ]
[[package]] [[package]]
@ -3282,7 +3163,7 @@ version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "195183bf6ff8328bb82c0511a83faf60aacf75840103388851db61d7a9854ae3" checksum = "195183bf6ff8328bb82c0511a83faf60aacf75840103388851db61d7a9854ae3"
dependencies = [ dependencies = [
"ahash 0.7.6", "ahash",
"atoi", "atoi",
"bitflags", "bitflags",
"byteorder", "byteorder",
@ -3688,6 +3569,18 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "totp-rs"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8707de57599ceb299004ba63de6733d7eb393116e07d4492dcf11191297e373"
dependencies = [
"base32",
"hmac 0.12.1",
"sha-1",
"sha2 0.10.2",
]
[[package]] [[package]]
name = "tower" name = "tower"
version = "0.4.12" version = "0.4.12"
@ -3806,12 +3699,6 @@ version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
[[package]]
name = "ucd-trie"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
[[package]] [[package]]
name = "ucd-util" name = "ucd-util"
version = "0.1.8" version = "0.1.8"
@ -3872,7 +3759,7 @@ version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05"
dependencies = [ dependencies = [
"generic-array 0.14.5", "generic-array",
"subtle", "subtle",
] ]
@ -3975,6 +3862,7 @@ dependencies = [
name = "warpgate" name = "warpgate"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"ansi_term",
"anyhow", "anyhow",
"async-trait", "async-trait",
"bytes", "bytes",
@ -3982,12 +3870,14 @@ dependencies = [
"config", "config",
"console 0.1.0", "console 0.1.0",
"console-subscriber", "console-subscriber",
"data-encoding",
"dhat", "dhat",
"dialoguer", "dialoguer",
"futures", "futures",
"isatty", "isatty",
"notify", "notify",
"openssl", "openssl",
"qrcode",
"rcgen", "rcgen",
"sd-notify", "sd-notify",
"serde_yaml", "serde_yaml",
@ -4038,16 +3928,19 @@ dependencies = [
"chrono", "chrono",
"data-encoding", "data-encoding",
"humantime-serde", "humantime-serde",
"lazy_static 1.4.0",
"packet", "packet",
"password-hash 0.3.2", "password-hash 0.3.2",
"poem-openapi", "poem-openapi",
"rand", "rand",
"rand_chacha",
"rand_core", "rand_core",
"sea-orm", "sea-orm",
"serde", "serde",
"serde_json", "serde_json",
"thiserror", "thiserror",
"tokio", "tokio",
"totp-rs",
"tracing", "tracing",
"url", "url",
"uuid", "uuid",

View file

@ -11,7 +11,7 @@ bytes = "1.1"
chrono = "0.4" chrono = "0.4"
futures = "0.3" futures = "0.3"
hex = "0.4" hex = "0.4"
mime_guess = "2.0" mime_guess = {version = "2.0", default_features = false}
poem = {version = "^1.3.24", features = ["cookie", "session", "anyhow", "rustls"]} poem = {version = "^1.3.24", features = ["cookie", "session", "anyhow", "rustls"]}
poem-openapi = {version = "^1.3.24", features = ["swagger-ui", "chrono", "uuid", "static-files"]} poem-openapi = {version = "^1.3.24", features = ["swagger-ui", "chrono", "uuid", "static-files"]}
russh-keys = {version = "0.22.0-beta.1", features = ["openssl"]} russh-keys = {version = "0.22.0-beta.1", features = ["openssl"]}

View file

@ -63,6 +63,7 @@ impl Api {
Ok(LoginResponse::Failure) Ok(LoginResponse::Failure)
} }
AuthResult::Rejected => Ok(LoginResponse::Failure), AuthResult::Rejected => Ok(LoginResponse::Failure),
AuthResult::OTPNeeded => Ok(LoginResponse::Failure), // TODO
} }
} }

View file

@ -9,7 +9,7 @@ use sea_orm::{ActiveModelTrait, DatabaseConnection, EntityTrait};
use std::sync::Arc; use std::sync::Arc;
use tokio::sync::Mutex; use tokio::sync::Mutex;
use uuid::Uuid; use uuid::Uuid;
use warpgate_common::hash::generate_ticket_secret; use warpgate_common::helpers::hash::generate_ticket_secret;
use warpgate_db_entities::Ticket; use warpgate_db_entities::Ticket;
pub struct Api; pub struct Api;

View file

@ -12,16 +12,19 @@ bytes = "1.1"
chrono = {version = "0.4", features = ["serde"]} chrono = {version = "0.4", features = ["serde"]}
data-encoding = "2.3" data-encoding = "2.3"
humantime-serde = "1.1" humantime-serde = "1.1"
lazy_static = "1.4"
packet = "0.1" packet = "0.1"
password-hash = "0.3" password-hash = "0.3"
poem-openapi = {version = "^1.3.24", features = ["swagger-ui", "chrono", "uuid", "static-files"]} poem-openapi = {version = "^1.3.24", features = ["swagger-ui", "chrono", "uuid", "static-files"]}
rand = "0.8" rand = "0.8"
rand_chacha = "0.3"
rand_core = {version = "0.6", features = ["std"]} rand_core = {version = "0.6", features = ["std"]}
sea-orm = {version = "^0.6", features = ["sqlx-sqlite", "runtime-tokio-native-tls", "macros"], default-features = false} sea-orm = {version = "^0.6", features = ["sqlx-sqlite", "runtime-tokio-native-tls", "macros"], default-features = false}
serde = "1.0" serde = "1.0"
serde_json = "1.0" serde_json = "1.0"
thiserror = "1.0" thiserror = "1.0"
tokio = {version = "1.17", features = ["tracing"]} tokio = {version = "1.17", features = ["tracing"]}
totp-rs = "1.0"
tracing = "0.1" tracing = "0.1"
url = "2.2" url = "2.2"
uuid = {version = "0.8", features = ["v4", "serde"]} uuid = {version = "0.8", features = ["v4", "serde"]}

View file

@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize};
use std::path::PathBuf; use std::path::PathBuf;
use std::time::Duration; use std::time::Duration;
use crate::helpers::otp::OtpSecretKey;
use crate::Secret; use crate::Secret;
const fn _default_true() -> bool { const fn _default_true() -> bool {
@ -89,6 +90,11 @@ pub enum UserAuthCredential {
Password { hash: Secret<String> }, Password { hash: Secret<String> },
#[serde(rename = "publickey")] #[serde(rename = "publickey")]
PublicKey { key: Secret<String> }, PublicKey { key: Secret<String> },
#[serde(rename = "otp")]
TOTP {
#[serde(with = "crate::helpers::serde_base64_secret")]
key: OtpSecretKey,
},
} }
#[derive(Debug, Deserialize, Serialize, Clone)] #[derive(Debug, Deserialize, Serialize, Clone)]

View file

@ -1,5 +1,6 @@
use super::ConfigProvider; use super::ConfigProvider;
use crate::hash::verify_password_hash; use crate::helpers::hash::verify_password_hash;
use crate::helpers::otp::verify_totp;
use crate::{ use crate::{
AuthCredential, AuthResult, Target, User, UserAuthCredential, UserSnapshot, WarpgateConfig, AuthCredential, AuthResult, Target, User, UserAuthCredential, UserSnapshot, WarpgateConfig,
}; };
@ -36,6 +37,7 @@ fn credential_is_type(c: &UserAuthCredential, k: &str) -> bool {
match c { match c {
UserAuthCredential::Password { .. } => k == "password", UserAuthCredential::Password { .. } => k == "password",
UserAuthCredential::PublicKey { .. } => k == "publickey", UserAuthCredential::PublicKey { .. } => k == "publickey",
UserAuthCredential::TOTP { .. } => k == "otp",
} }
} }
@ -92,48 +94,59 @@ impl ConfigProvider for FileConfigProvider {
let mut valid_credentials = vec![]; let mut valid_credentials = vec![];
for client_credential in credentials { for client_credential in credentials {
if let AuthCredential::PublicKey { match client_credential {
kind, AuthCredential::PublicKey {
public_key_bytes, kind,
} = client_credential public_key_bytes,
{ } => {
let mut base64_bytes = BASE64_MIME.encode(public_key_bytes); let mut base64_bytes = BASE64_MIME.encode(public_key_bytes);
base64_bytes.pop(); base64_bytes.pop();
base64_bytes.pop(); base64_bytes.pop();
let client_key = format!("{} {}", kind, base64_bytes); let client_key = format!("{} {}", kind, base64_bytes);
debug!(username=%user.username, "Client key: {}", client_key); debug!(username=%user.username, "Client key: {}", client_key);
for credential in user.credentials.iter() { for credential in user.credentials.iter() {
if let UserAuthCredential::PublicKey { key: ref user_key } = credential { if let UserAuthCredential::PublicKey { key: ref user_key } = credential {
if &client_key == user_key.expose_secret() { if &client_key == user_key.expose_secret() {
valid_credentials.push(credential);
break;
}
}
}
}
}
for client_credential in credentials {
if let AuthCredential::Password(client_password) = client_credential {
for credential in user.credentials.iter() {
if let UserAuthCredential::Password {
hash: ref user_password_hash,
} = credential
{
match verify_password_hash(
client_password.expose_secret(),
user_password_hash.expose_secret(),
) {
Ok(true) => {
valid_credentials.push(credential); valid_credentials.push(credential);
break; break;
} }
Ok(false) => continue, }
Err(e) => { }
error!(username=%user.username, "Error verifying password hash: {}", e); }
continue; AuthCredential::Password(client_password) => {
for credential in user.credentials.iter() {
if let UserAuthCredential::Password {
hash: ref user_password_hash,
} = credential
{
match verify_password_hash(
client_password.expose_secret(),
user_password_hash.expose_secret(),
) {
Ok(true) => {
valid_credentials.push(credential);
break;
}
Ok(false) => continue,
Err(e) => {
error!(username=%user.username, "Error verifying password hash: {}", e);
continue;
}
}
}
}
}
AuthCredential::OTP(client_otp) => {
for credential in user.credentials.iter() {
if let UserAuthCredential::TOTP {
key: ref user_otp_key,
} = credential
{
if verify_totp(client_otp.expose_secret(), user_otp_key) {
valid_credentials.push(credential);
break;
} }
} }
} }
@ -141,31 +154,38 @@ impl ConfigProvider for FileConfigProvider {
} }
} }
if !valid_credentials.is_empty() { if valid_credentials.is_empty() {
match user.require { warn!(username=%user.username, "Client credentials did not match");
Some(ref required_kinds) => { }
for kind in required_kinds {
if !valid_credentials match user.require {
.iter() Some(ref required_kinds) => {
.any(|x| credential_is_type(x, kind)) let mut remaining_required_kinds = HashSet::new();
{ remaining_required_kinds.extend(required_kinds);
return Ok(AuthResult::Rejected); for kind in required_kinds {
} if valid_credentials
.iter()
.any(|x| credential_is_type(x, kind))
{
remaining_required_kinds.remove(kind);
} }
}
if remaining_required_kinds.is_empty() {
return Ok(AuthResult::Accepted { return Ok(AuthResult::Accepted {
username: user.username.clone(), username: user.username.clone(),
}); });
} } else if remaining_required_kinds.contains(&"otp".to_string()) {
None => { return Ok(AuthResult::OTPNeeded);
return Ok(AuthResult::Accepted { } else {
username: user.username.clone(), return Ok(AuthResult::Rejected);
})
} }
} }
None => {
return Ok(AuthResult::Accepted {
username: user.username.clone(),
})
}
} }
warn!(username=%user.username, "Client credentials did not match");
Ok(AuthResult::Rejected)
} }
async fn authorize_target(&mut self, username: &str, target_name: &str) -> Result<bool> { async fn authorize_target(&mut self, username: &str, target_name: &str) -> Result<bool> {

View file

@ -13,10 +13,12 @@ use warpgate_db_entities::Ticket;
pub enum AuthResult { pub enum AuthResult {
Accepted { username: String }, Accepted { username: String },
OTPNeeded,
Rejected, Rejected,
} }
pub enum AuthCredential { pub enum AuthCredential {
OTP(Secret<String>),
Password(Secret<String>), Password(Secret<String>),
PublicKey { PublicKey {
kind: String, kind: String,

View file

@ -1,2 +1,6 @@
pub mod fs; pub mod fs;
pub mod hash;
pub mod otp;
pub mod rng;
pub mod serde_base64; pub mod serde_base64;
pub mod serde_base64_secret;

View file

@ -0,0 +1,31 @@
use std::time::SystemTime;
use super::rng::get_crypto_rng;
use crate::types::Secret;
use bytes::Bytes;
use rand::Rng;
use totp_rs::{Algorithm, TOTP};
pub type OtpExposedSecretKey = Bytes;
pub type OtpSecretKey = Secret<OtpExposedSecretKey>;
pub fn generate_key() -> OtpSecretKey {
Secret::new(Bytes::from_iter(get_crypto_rng().gen::<[u8; 32]>()))
}
pub fn generate_setup_url(key: &OtpSecretKey, label: &str) -> Secret<String> {
let totp = get_totp(key);
Secret::new(totp.get_url(label, "Warpgate"))
}
fn get_totp(key: &OtpSecretKey) -> TOTP<OtpExposedSecretKey> {
TOTP::new(Algorithm::SHA1, 6, 1, 30, key.expose_secret().clone())
}
pub fn verify_totp(code: &str, key: &OtpSecretKey) -> bool {
let time = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.as_secs();
get_totp(key).check(code, time)
}

View file

@ -0,0 +1,6 @@
use rand::SeedableRng;
use rand_chacha::ChaCha20Rng;
pub fn get_crypto_rng() -> ChaCha20Rng {
ChaCha20Rng::from_entropy()
}

View file

@ -1,18 +1,16 @@
use bytes::Bytes;
use data_encoding::BASE64; use data_encoding::BASE64;
use serde::{Deserialize, Serializer}; use serde::{Deserialize, Serializer};
pub fn serialize<S>(bytes: &Bytes, serializer: S) -> Result<S::Ok, S::Error> pub fn serialize<S: Serializer, B: AsRef<[u8]>>(
where bytes: B,
S: Serializer, serializer: S,
{ ) -> Result<S::Ok, S::Error> {
serializer.serialize_str(&BASE64.encode(bytes)) serializer.serialize_str(&BASE64.encode(bytes.as_ref()))
} }
pub fn deserialize<'de, D>(deserializer: D) -> Result<Bytes, D::Error> pub fn deserialize<'de, D: serde::Deserializer<'de>, B: From<Vec<u8>>>(
where deserializer: D,
D: serde::Deserializer<'de>, ) -> Result<B, D::Error> {
{
let s = String::deserialize(deserializer)?; let s = String::deserialize(deserializer)?;
Ok(BASE64 Ok(BASE64
.decode(s.as_bytes()) .decode(s.as_bytes())

View file

@ -0,0 +1,15 @@
use super::serde_base64;
use crate::Secret;
use bytes::Bytes;
use serde::Serializer;
pub fn serialize<S: Serializer>(secret: &Secret<Bytes>, serializer: S) -> Result<S::Ok, S::Error> {
serde_base64::serialize(secret.expose_secret().as_ref(), serializer)
}
pub fn deserialize<'de, D: serde::Deserializer<'de>>(
deserializer: D,
) -> Result<Secret<Bytes>, D::Error> {
let inner = serde_base64::deserialize(deserializer)?;
Ok(Secret::new(inner))
}

View file

@ -6,7 +6,6 @@ pub mod consts;
mod data; mod data;
pub mod db; pub mod db;
pub mod eventhub; pub mod eventhub;
pub mod hash;
pub mod helpers; pub mod helpers;
mod protocols; mod protocols;
pub mod recordings; pub mod recordings;

View file

@ -1,14 +1,14 @@
[package] [package]
name = "warpgate-db-migrations"
version = "0.1.0"
edition = "2021" edition = "2021"
publish = false
license = "Apache-2.0" license = "Apache-2.0"
name = "warpgate-db-migrations"
publish = false
version = "0.1.0"
[lib] [lib]
[dependencies] [dependencies]
sea-schema = { version = "0.5", default-features = false, features = [ "migration", "debug-print" ] }
uuid = {version = "0.8", features = ["v4", "serde"]}
chrono = "0.4" chrono = "0.4"
sea-orm = {version = "^0.6", features = ["sqlx-sqlite", "runtime-tokio-native-tls", "macros"], default-features = false} sea-orm = {version = "^0.6", features = ["sqlx-sqlite", "runtime-tokio-native-tls", "macros"], default-features = false}
sea-schema = {version = "0.5", default-features = false, features = ["migration", "debug-print"]}
uuid = {version = "0.8", features = ["v4", "serde"]}

View file

@ -8,11 +8,12 @@ version = "0.1.0"
ansi_term = "0.12" ansi_term = "0.12"
anyhow = "1.0" anyhow = "1.0"
async-trait = "0.1" async-trait = "0.1"
bimap = "0.6"
bytes = "1.1" bytes = "1.1"
dialoguer = "0.10" dialoguer = "0.10"
futures = "0.3" futures = "0.3"
russh = {version = "0.34.0-beta.2", features = ["openssl"] } russh = {version = "0.34.0-beta.2", features = ["openssl"]}
russh-keys = {version = "0.22.0-beta.1", features = ["openssl"] } russh-keys = {version = "0.22.0-beta.1", features = ["openssl"]}
sea-orm = {version = "^0.6", features = ["runtime-tokio-native-tls"], default-features = false} sea-orm = {version = "^0.6", features = ["runtime-tokio-native-tls"], default-features = false}
thiserror = "1.0" thiserror = "1.0"
time = "0.3" time = "0.3"
@ -21,4 +22,3 @@ tracing = "0.1"
uuid = {version = "0.8", features = ["v4"]} uuid = {version = "0.8", features = ["v4"]}
warpgate-common = {version = "*", path = "../warpgate-common"} warpgate-common = {version = "*", path = "../warpgate-common"}
warpgate-db-entities = {version = "*", path = "../warpgate-db-entities"} warpgate-db-entities = {version = "*", path = "../warpgate-db-entities"}
bimap = "0.6"

View file

@ -22,7 +22,7 @@ pub async fn run_server(services: Services, address: SocketAddr) -> Result<()> {
let config = services.config.lock().await; let config = services.config.lock().await;
russh::server::Config { russh::server::Config {
auth_rejection_time: std::time::Duration::from_secs(1), auth_rejection_time: std::time::Duration::from_secs(1),
methods: MethodSet::PUBLICKEY | MethodSet::PASSWORD, methods: MethodSet::PUBLICKEY | MethodSet::PASSWORD | MethodSet::KEYBOARD_INTERACTIVE,
keys: load_host_keys(&config)?, keys: load_host_keys(&config)?,
..Default::default() ..Default::default()
} }

View file

@ -141,6 +141,28 @@ impl russh::server::Handler for ServerHandler {
.boxed() .boxed()
} }
fn auth_keyboard_interactive(
self,
user: &str,
_submethods: &str,
response: Option<russh::server::Response>,
) -> Self::FutureAuth {
let user = user.to_string();
let response = response
.and_then(|mut r| r.next())
.and_then(|b| String::from_utf8(b.to_vec()).ok());
async move {
let result = self
.session
.lock()
.await
._auth_keyboard_interactive(Secret::new(user), response.map(Secret::new))
.await;
Ok((self, result))
}
.boxed()
}
fn data(self, channel: ChannelId, data: &[u8], session: Session) -> Self::FutureUnit { fn data(self, channel: ChannelId, data: &[u8], session: Session) -> Self::FutureUnit {
let data = BytesMut::from(data).freeze(); let data = BytesMut::from(data).freeze();
async move { async move {
@ -344,15 +366,6 @@ impl russh::server::Handler for ServerHandler {
// self.finished_auth(Auth::Reject) // self.finished_auth(Auth::Reject)
// } // }
// fn auth_keyboard_interactive(
// self,
// user: &str,
// submethods: &str,
// response: Option<russh::server::Response>,
// ) -> Self::FutureAuth {
// self.finished_auth(Auth::Reject)
// }
// fn tcpip_forward(self, address: &str, port: u32, session: Session) -> Self::FutureBool { // fn tcpip_forward(self, address: &str, port: u32, session: Session) -> Self::FutureBool {
// self.finished_bool(false, session) // self.finished_bool(false, session)
// } // }

View file

@ -14,6 +14,7 @@ use russh::server::Session;
use russh::{CryptoVec, Sig}; use russh::{CryptoVec, Sig};
use russh_keys::key::PublicKey; use russh_keys::key::PublicKey;
use russh_keys::PublicKeyBase64; use russh_keys::PublicKeyBase64;
use std::borrow::Cow;
use std::collections::hash_map::Entry::Vacant; use std::collections::hash_map::Entry::Vacant;
use std::collections::HashMap; use std::collections::HashMap;
use std::net::{Ipv4Addr, SocketAddr}; use std::net::{Ipv4Addr, SocketAddr};
@ -850,6 +851,7 @@ impl ServerSession {
match self.try_auth(&selector).await { match self.try_auth(&selector).await {
Ok(AuthResult::Accepted { .. }) => russh::server::Auth::Accept, Ok(AuthResult::Accepted { .. }) => russh::server::Auth::Accept,
Ok(AuthResult::Rejected) => russh::server::Auth::Reject, Ok(AuthResult::Rejected) => russh::server::Auth::Reject,
Ok(AuthResult::OTPNeeded) => russh::server::Auth::Reject,
Err(error) => { Err(error) => {
error!(session=?self, ?error, "Failed to verify credentials"); error!(session=?self, ?error, "Failed to verify credentials");
russh::server::Auth::Reject russh::server::Auth::Reject
@ -870,6 +872,34 @@ impl ServerSession {
match self.try_auth(&selector).await { match self.try_auth(&selector).await {
Ok(AuthResult::Accepted { .. }) => russh::server::Auth::Accept, Ok(AuthResult::Accepted { .. }) => russh::server::Auth::Accept,
Ok(AuthResult::Rejected) => russh::server::Auth::Reject, Ok(AuthResult::Rejected) => russh::server::Auth::Reject,
Ok(AuthResult::OTPNeeded) => russh::server::Auth::Reject,
Err(error) => {
error!(session=?self, ?error, "Failed to verify credentials");
russh::server::Auth::Reject
}
}
}
pub async fn _auth_keyboard_interactive(
&mut self,
ssh_username: Secret<String>,
response: Option<Secret<String>>,
) -> russh::server::Auth {
let selector: AuthSelector = ssh_username.expose_secret().into();
info!(session=?self, "Keyboard-interactive auth as {:?}", selector);
if let Some(otp) = response {
self.credentials.push(AuthCredential::OTP(otp));
}
match self.try_auth(&selector).await {
Ok(AuthResult::Accepted { .. }) => russh::server::Auth::Accept,
Ok(AuthResult::Rejected) => russh::server::Auth::Reject,
Ok(AuthResult::OTPNeeded) => russh::server::Auth::Partial {
name: Cow::Borrowed("OTP"),
instructions: Cow::Borrowed(""),
prompts: Cow::Owned(vec![(Cow::Borrowed("One-time password: "), true)]),
},
Err(error) => { Err(error) => {
error!(session=?self, ?error, "Failed to verify credentials"); error!(session=?self, ?error, "Failed to verify credentials");
russh::server::Auth::Reject russh::server::Auth::Reject
@ -913,6 +943,7 @@ impl ServerSession {
Ok(AuthResult::Accepted { username }) Ok(AuthResult::Accepted { username })
} }
AuthResult::Rejected => Ok(AuthResult::Rejected), AuthResult::Rejected => Ok(AuthResult::Rejected),
AuthResult::OTPNeeded => Ok(AuthResult::OTPNeeded),
} }
} }
AuthSelector::Ticket { secret } => { AuthSelector::Ticket { secret } => {

View file

@ -5,19 +5,22 @@ name = "warpgate"
version = "0.1.1" version = "0.1.1"
[dependencies] [dependencies]
ansi_term = "0.12"
anyhow = {version = "1.0", features = ["backtrace"]} anyhow = {version = "1.0", features = ["backtrace"]}
async-trait = "0.1" async-trait = "0.1"
bytes = "1.1" bytes = "1.1"
clap = {version = "3.1", features = ["derive"]} clap = {version = "3.1", features = ["derive"]}
config = "0.12" config = {version = "0.12", features = ["yaml"], default_features = false}
console = "0.1" console = {version = "0.1", default_features = false}
console-subscriber = {version = "0.1", optional = true} console-subscriber = {version = "0.1", optional = true}
data-encoding = "2.3"
dhat = {version = "0.3", optional = true} dhat = {version = "0.3", optional = true}
dialoguer = "0.10" dialoguer = "0.10"
futures = "0.3" futures = "0.3"
isatty = "0.1" isatty = "0.1"
notify = "^5.0.0-beta.1" notify = "^5.0.0-beta.1"
openssl = {version = "0.10", features = ["vendored"]}# Embed OpenSSL openssl = {version = "0.10", features = ["vendored"]}# Embed OpenSSL
qrcode = "0.12"
rcgen = {version = "0.9", features = ["zeroize"]} rcgen = {version = "0.9", features = ["zeroize"]}
serde_yaml = "0.8.23" serde_yaml = "0.8.23"
time = "0.3" time = "0.3"

View file

@ -2,7 +2,7 @@ use anyhow::Result;
use dialoguer::theme::ColorfulTheme; use dialoguer::theme::ColorfulTheme;
use isatty::stdin_isatty; use isatty::stdin_isatty;
use std::io::stdin; use std::io::stdin;
use warpgate_common::hash::hash_password; use warpgate_common::helpers::hash::hash_password;
pub(crate) async fn command() -> Result<()> { pub(crate) async fn command() -> Result<()> {
let mut input = String::new(); let mut input = String::new();

View file

@ -1,6 +1,7 @@
pub mod check; pub mod check;
pub mod client_keys; pub mod client_keys;
pub mod hash; pub mod hash;
pub mod otp;
pub mod run; pub mod run;
pub mod setup; pub mod setup;
pub mod test_target; pub mod test_target;

View file

@ -0,0 +1,54 @@
use ansi_term::Color::{Black, White};
use ansi_term::Style;
use anyhow::Result;
use data_encoding::BASE64;
use qrcode::{Color, QrCode};
use tracing::*;
use warpgate_common::helpers::otp::{generate_key, generate_setup_url};
pub(crate) async fn command() -> Result<()> {
let key = generate_key();
let url = generate_setup_url(&key, "test");
let code = QrCode::new(url.expose_secret().as_bytes())?;
let width = code.width();
let pixels = code.into_colors();
for _ in 0..width + 4 {
print!("{}", Style::new().on(White).paint(" "));
}
println!();
for hy in 0..(pixels.len() + width - 1) / width / 2 + 1 {
print!("{}", Style::new().on(White).paint(" "));
for x in 0..width {
let top = pixels
.get(hy * 2 * width + x)
.map(|x| *x == Color::Dark)
.unwrap_or(false);
let bottom = pixels
.get((hy * 2 + 1) * width + x)
.map(|x| *x == Color::Dark)
.unwrap_or(false);
print!(
"{}",
match (top, bottom) {
(true, true) => Style::new().fg(Black).paint(""),
(true, false) => Style::new().fg(Black).on(White).paint(""),
(false, true) => Style::new().fg(Black).on(White).paint(""),
(false, false) => Style::new().on(White).paint(" "),
}
);
}
println!("{}", Style::new().on(White).paint(" "));
}
println!();
info!("Setup URL: {}", url.expose_secret());
info!("Config file snippet:");
println!();
println!(" - type: otp");
println!(" key: {}", BASE64.encode(key.expose_secret()));
Ok(())
}

View file

@ -6,7 +6,7 @@ use std::fs::{create_dir_all, File};
use std::io::Write; use std::io::Write;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use tracing::*; use tracing::*;
use warpgate_common::hash::hash_password; use warpgate_common::helpers::hash::hash_password;
use warpgate_common::helpers::fs::{secure_directory, secure_file}; use warpgate_common::helpers::fs::{secure_directory, secure_file};
use warpgate_common::{ use warpgate_common::{
Role, SSHConfig, Secret, Services, Target, TargetWebAdminOptions, User, UserAuthCredential, Role, SSHConfig, Secret, Services, Target, TargetWebAdminOptions, User, UserAuthCredential,

View file

@ -37,6 +37,8 @@ enum Commands {
Check, Check,
/// Test the connection to a target host /// Test the connection to a target host
TestTarget { target_name: String }, TestTarget { target_name: String },
/// Generate a new 2FA (TOTP) enrollment key
GenerateOtp,
} }
async fn _main() -> Result<()> { async fn _main() -> Result<()> {
@ -51,6 +53,7 @@ async fn _main() -> Result<()> {
} }
Commands::Setup => crate::commands::setup::command(&cli).await, Commands::Setup => crate::commands::setup::command(&cli).await,
Commands::ClientKeys => crate::commands::client_keys::command(&cli).await, Commands::ClientKeys => crate::commands::client_keys::command(&cli).await,
Commands::GenerateOtp => crate::commands::otp::command().await,
} }
} }