From 4a76b8589af958956822faa12ee7315742b6699a Mon Sep 17 00:00:00 2001 From: Chris Tam Date: Tue, 18 Feb 2025 16:26:30 +0800 Subject: [PATCH] init --- .env.sample | 3 + .gitignore | 3 + Cargo.lock | 1764 ++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 17 + README.md | 419 ++++++++++++ Screenshot.png | Bin 0 -> 22462 bytes src/main.rs | 228 +++++++ 7 files changed, 2434 insertions(+) create mode 100644 .env.sample create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 README.md create mode 100644 Screenshot.png create mode 100644 src/main.rs diff --git a/.env.sample b/.env.sample new file mode 100644 index 0000000..511d48c --- /dev/null +++ b/.env.sample @@ -0,0 +1,3 @@ +SECURITYHUB_ID=1 +PORT=8081 +GENERATE_RANDOM_BITS_NUM=1000 \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f570b1e --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/target +database*.json +.env \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..5458ea7 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1764 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "actix-codec" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617a8268e3537fe1d8c9ead925fca49ef6400927ee7bc26750e90ecee14ce4b8" +dependencies = [ + "bitflags", + "bytes", + "futures-core", + "futures-sink", + "memchr", + "pin-project-lite", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "actix-cors" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0346d8c1f762b41b458ed3145eea914966bb9ad20b9be0d6d463b20d45586370" +dependencies = [ + "actix-utils", + "actix-web", + "derive_more", + "futures-util", + "log", + "once_cell", + "smallvec", +] + +[[package]] +name = "actix-http" +version = "3.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2079246596c18b4a33e274ae10c0e50613f4d32a4198e09c7b93771013fed74" +dependencies = [ + "actix-codec", + "actix-rt", + "actix-service", + "actix-utils", + "ahash 0.8.3", + "base64", + "bitflags", + "brotli", + "bytes", + "bytestring", + "derive_more", + "encoding_rs", + "flate2", + "futures-core", + "h2", + "http", + "httparse", + "httpdate", + "itoa", + "language-tags", + "local-channel", + "mime", + "percent-encoding", + "pin-project-lite", + "rand", + "sha1", + "smallvec", + "tokio", + "tokio-util", + "tracing", + "zstd", +] + +[[package]] +name = "actix-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "465a6172cf69b960917811022d8f29bc0b7fa1398bc4f78b3c466673db1213b6" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "actix-router" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66ff4d247d2b160861fa2866457e85706833527840e4133f8f49aa423a38799" +dependencies = [ + "bytestring", + "http", + "regex", + "serde", + "tracing", +] + +[[package]] +name = "actix-rt" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15265b6b8e2347670eb363c47fc8c75208b4a4994b27192f345fcbe707804f3e" +dependencies = [ + "futures-core", + "tokio", +] + +[[package]] +name = "actix-server" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e8613a75dd50cc45f473cee3c34d59ed677c0f7b44480ce3b8247d7dc519327" +dependencies = [ + "actix-rt", + "actix-service", + "actix-utils", + "futures-core", + "futures-util", + "mio", + "num_cpus", + "socket2", + "tokio", + "tracing", +] + +[[package]] +name = "actix-service" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b894941f818cfdc7ccc4b9e60fa7e53b5042a2e8567270f9147d5591893373a" +dependencies = [ + "futures-core", + "paste", + "pin-project-lite", +] + +[[package]] +name = "actix-utils" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a1dcdff1466e3c2488e1cb5c36a71822750ad43839937f85d2f4d9f8b705d8" +dependencies = [ + "local-waker", + "pin-project-lite", +] + +[[package]] +name = "actix-web" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd3cb42f9566ab176e1ef0b8b3a896529062b4efc6be0123046095914c4c1c96" +dependencies = [ + "actix-codec", + "actix-http", + "actix-macros", + "actix-router", + "actix-rt", + "actix-server", + "actix-service", + "actix-utils", + "actix-web-codegen", + "ahash 0.7.6", + "bytes", + "bytestring", + "cfg-if", + "cookie", + "derive_more", + "encoding_rs", + "futures-core", + "futures-util", + "http", + "itoa", + "language-tags", + "log", + "mime", + "once_cell", + "pin-project-lite", + "regex", + "serde", + "serde_json", + "serde_urlencoded", + "smallvec", + "socket2", + "time", + "url", +] + +[[package]] +name = "actix-web-codegen" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2262160a7ae29e3415554a3f1fc04c764b1540c116aa524683208078b7a75bc9" +dependencies = [ + "actix-router", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "async-trait" +version = "0.1.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.18", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base64" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "brotli" +version = "3.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "2.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b6561fd3f895a11e8f72af2cb7d22e08366bebc2b6b57f7744c4bda27034744" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bumpalo" +version = "3.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" + +[[package]] +name = "bytes" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" + +[[package]] +name = "bytestring" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "238e4886760d98c4f899360c834fa93e62cf7f721ac3c2da375cbdf4b8679aae" +dependencies = [ + "bytes", +] + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +dependencies = [ + "jobserver", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "cookie" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" +dependencies = [ + "percent-encoding", + "time", + "version_check", +] + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" + +[[package]] +name = "cpufeatures" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "dotenv" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" + +[[package]] +name = "dske_poc_server" +version = "0.1.0" +dependencies = [ + "actix-cors", + "actix-web", + "async-trait", + "dotenv", + "rand", + "reqwest", + "serde", + "serde_json", + "tokio", +] + +[[package]] +name = "encoding_rs" +version = "0.8.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "errno" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + +[[package]] +name = "flate2" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" + +[[package]] +name = "futures-sink" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" + +[[package]] +name = "futures-task" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" + +[[package]] +name = "futures-util" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "h2" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d357c7ae988e7d2182f7d7871d0b963962420b0678b0997ce7de72001aeab782" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + +[[package]] +name = "http" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "hyper" +version = "0.14.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi 0.3.1", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "ipnet" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" + +[[package]] +name = "itoa" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" + +[[package]] +name = "jobserver" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "language-tags" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.146" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" + +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "local-channel" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f303ec0e94c6c54447f84f3b0ef7af769858a9c4ef56ef2a986d3dcd4c3fc9c" +dependencies = [ + "futures-core", + "futures-sink", + "futures-util", + "local-waker", +] + +[[package]] +name = "local-waker" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e34f76eb3611940e0e7d53a9aaa4e6a3151f69541a282fd0dad5571420c53ff1" + +[[package]] +name = "lock_api" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "num_cpus" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +dependencies = [ + "hermit-abi 0.2.6", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "openssl" +version = "0.10.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69b3f656a17a6cbc115b5c7a40c616947d213ba182135b014d6051b73ab6f019" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.18", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2ce0f250f34a308dcfdbb351f511359857d4ed2134ba715a4eadd46e1ffd617" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + +[[package]] +name = "paste" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" + +[[package]] +name = "percent-encoding" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" + +[[package]] +name = "reqwest" +version = "0.11.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.37.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys 0.48.0", +] + +[[package]] +name = "ryu" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" + +[[package]] +name = "schannel" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" +dependencies = [ + "windows-sys 0.42.0", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "security-framework" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" + +[[package]] +name = "serde" +version = "1.0.163" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.163" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.18", +] + +[[package]] +name = "serde_json" +version = "1.0.96" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha1" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] +name = "slab" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + +[[package]] +name = "socket2" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" +dependencies = [ + "autocfg", + "cfg-if", + "fastrand", + "redox_syscall", + "rustix", + "windows-sys 0.48.0", +] + +[[package]] +name = "time" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f3403384eaacbca9923fa06940178ac13e4edb725486d70e8e15881d0c836cc" +dependencies = [ + "itoa", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" + +[[package]] +name = "time-macros" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" +dependencies = [ + "time-core", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.28.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" +dependencies = [ + "autocfg", + "bytes", + "libc", + "mio", + "num_cpus", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-macros" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.18", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +dependencies = [ + "cfg-if", + "log", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + +[[package]] +name = "unicode-ident" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "url" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.18", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d1985d03709c53167ce907ff394f5316aa22cb4e12761295c5dc57dacb6297e" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.18", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" + +[[package]] +name = "web-sys" +version = "0.3.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + +[[package]] +name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] + +[[package]] +name = "zstd" +version = "0.12.3+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76eea132fb024e0e13fd9c2f5d5d595d8a967aa72382ac2f9d39fcc95afd0806" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "6.0.5+zstd.1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56d9e60b4b1758206c238a10165fbcae3ca37b01744e394c463463f6529d23b" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.8+zstd.1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5556e6ee25d32df2586c098bbfa278803692a20d0ab9565e049480d52707ec8c" +dependencies = [ + "cc", + "libc", + "pkg-config", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..1c91553 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "dske_poc_server" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +actix-web = "4.3.1" +dotenv = "0.15.0" +reqwest = { version = "0.11.17", features = ["json"] } +serde = { version = "1.0.160", features = ["derive"] } +serde_json = "1.0.96" +tokio = { version = "1.28.0", features = ["full"] } +async-trait = "0.1.68" +actix-cors = "0.6.4" +rand = "0.8.5" diff --git a/README.md b/README.md new file mode 100644 index 0000000..c4ff4d5 --- /dev/null +++ b/README.md @@ -0,0 +1,419 @@ +# DSKE POC (Security Hub Server) + +## Introduction + +This is a proof of concept for the DSKE system. The main goal is to demonstrate the algorithm in DSKE. There are a few assumptions and limitations in this proof-of-concept project: + +1. This is not a working protocol, this project is just to prove the algorithm concept. +2. This project is demonstrating a simple DSKE protocol, which means n = k. It is a (n, n) secret sharing scheme. +3. The code assumes that the final key sender chooses all common security hubs with the receiver that they both register. + +This project is separated into two parts: the client and the security hub server. + +- [client](https://gitea.devchristam.com/devchristam/dske_poc_client) +- [server](https://gitea.devchristam.com/devchristam/dske_poc_server) + +You need to host multiple clients and servers to make this proof-of-concept DSKE system work. + +## DSKE Main Phases + +1. PSKM Generation and Distribution + + The security hub's `POST /register_client` endpoint will generate random bits and record the client on the server side. This endpoint will return the generated random bits. The client's `POST /register_securityhub` endpoint will store these random bits so that both the security hub and the client have a copy. Note that the distribution process needs to be done manually because real PSKM distribution is done physically. + +2. Peer Identity Establishment + + When a client wants to share a key with another client using `POST /make_connection`, the sender client will send a request to the receiver client's `POST /agree_connection` endpoint with a list of security hubs to use in the key exchange. The receiver client will check if both the sender and receiver are registered in those security hubs using the security hub's `POST /user_list` endpoint. This endpoint will display every client ID registered in the security hub, allowing the client to identify common security hubs. + +3. Key Agreement + + The sender will use the `POST /make_connection` endpoint to exchange keys with the receiver. + + 1. Share Generation + + The proof-of-concept project will use an (n, n) secret sharing scheme in a simple DSKE protocol. For simplicity, the sender will choose all the common security hubs with the receiver. + + 2. Share Distribution + + The sender will send a request to the security hub's `POST /generate_key_instruction` endpoint to generate a key instruction A (sender's random bits) XOR B (receiver's random bits). + + 3. Key Reconstruction + + After the security hub sends a request to the client's `POST /receive_key_instruction` endpoint, the client will calculate A ^ B ^ B to retrieve A in each request and store the calculated A in a key-value pair using the final key hash as the key. The receiver can reconstruct the final key S by executing XOR on every share in the simple DSKE protocol (n, n) secret sharing scheme. + +4. Key Validation + + The receiver will only reconstruct the final key if the number of received shares equals the total number of shares. The exchange process will abort if the numbers do not match. + +## Step-by-Step Setup Guide + +This guide will walk you through the steps to set up and run the DSKE POC server and client. + +### Steps + +#### 1. Clone the Repository + +Clone the repository to your local machine using the following commands: + +```bash +# Clone the DSKE POC server +git clone https://gitea.devchristam.com/devchristam/dske_poc_server.git + +# Clone the DSKE POC client +git clone https://gitea.devchristam.com/devchristam/dske_poc_client.git +``` + +#### 2. Build the Project + +Navigate to the project directory and build the project using Cargo: + +```sh +cargo build +``` + +#### 3. Run the Server and Client + +Run the server and client using the following commands. You need to use Tmux or open multiple terminal applications to host multiple servers and clients on the same machine. + +For server: + +```sh +# The code supports .env for port and security hub ID settings. +# Even if not using the .env file, please copy the .env because missing variables will show a runtime error. +cp .env.sample .env +# set the environment variables in .env if needed +# cargo run -- +# e.g. +cargo run -- 8081 1 +cargo run -- 8082 2 +cargo run -- 8083 3 +``` + +For client: + +```sh +# The code supports .env for port and security hub ID settings. +# Even if not using the .env file, please copy the .env because missing variables will show a runtime error. +cp .env.sample .env +# set the environment variables in .env if needed +# cargo run -- +# e.g. +cargo run -- 8001 1 +cargo run -- 8002 2 +``` + +## 4. Exchange Key + +### Steps + +All API calls use `content-type: "application/json"`. + +#### 1. Register Client in Security Hub + +Use the security hub endpoint `POST /register_client` to record the client. + +- Example (record a client running on `cargo run -- 8001 1`): +```json +{ + "id": 1, + "username": "alice", + "url": "http://localhost:8001" +} +``` + +- This request will return a payload. You need to copy the `random_bits` array for step 2: + +```json +{ + "id": 1, + "username": "alice", + "url": "http://localhost:8001", + "random_bits": [ + false, + false, + true, + true, + true, + ... + ] +} +``` + +#### 2. Register Security Hub in the Client + +Copy the `random_bits` array and input the same content into the client endpoint `POST /register_securityhub`. + +- Example (record a security hub running on `cargo run -- 8081 1`): + +```json +{ + "securityhub_id": 1, + "securityhub_url": "http://localhost:8081", + "random_bits": [ + false, + false, + true, + true, + true, + ... + ] +} +``` + +After repeating steps 1 and 2, you can create a proof-of-concept DSKE system network. Then the client can exchange keys within the network. + +#### 3. Exchange Key + +In the client endpoint `POST /make_connection`, you can exchange the final key with another client. + +- Example (from client `cargo run -- 8001 1` exchanging key with `cargo run -- 8002 2`): +```json +{ + "client_id": 2, + "client_url": "http://localhost:8002", + "keysize": 5 +} +``` + +![screenshot](./Screenshot.png) + +## API Documentation + +### Server + +#### `POST /register_client` + +Registers a client in the security hub. + +- **Input:** + + `content-type: "application/json"` + + ```json + { + "id": Integer, + "username": String, + "url": String + } + ``` + + Example: + + ```json + { + "id": 999, + "username": "test", + "url": "http://localhost:8888" + } + ``` + +- **Output:** + + ```json + { + "id": Integer, + "username": String, + "url": String, + "random_bits": Boolean[] + } + ``` + + Example: + + ```json + { + "id": 999, + "username": "test", + "url": "http://localhost:8888", + "random_bits": [true, false, true, ...] + } + ``` + +#### `POST /user_list` + +Retrieves the list of registered user IDs from the security hub. + +- **Input:** + + No input required. + +- **Output:** + + ```json + Integer[] + ``` + + Example: + + ```json + [1, 2, 3, ...] + ``` + +#### `POST /generate_key_instruction` + +Generates a key instruction for the key exchange process. + +- **Input:** + + `content-type: "application/json"` + + ```json + { + "sender_id": Integer, + "receiver_id": Integer, + "hash": Integer, + "keysize": Integer + } + ``` + + Example: + + ```json + { + "sender_id": 1, + "receiver_id": 2, + "hash": 12345, + "keysize": 5 + } + ``` + +- **Output:** + + ```json + Boolean[] + ``` + + Example: + + ```json + [true, false, true, ...] + ``` + +### Client + +#### `POST /register_securityhub` + +Registers a security hub in the client. + +- **Input:** + + `content-type: "application/json"` + + ```json + { + "securityhub_id": Integer, + "securityhub_url": String, + "random_bits": Boolean[] + } + ``` + + Example: + + ```json + { + "securityhub_id": 1, + "securityhub_url": "http://localhost:8081", + "random_bits": [true, false, true, ...] + } + ``` + +- **Output:** + + Null + +#### `POST /make_connection` + +Initiates a key exchange with another client. + +- **Input:** + + `content-type: "application/json"` + + ```json + { + "client_id": Integer, + "client_url": String, + "keysize": Integer + } + ``` + + Example: + + ```json + { + "client_id": 2, + "client_url": "http://localhost:8002", + "keysize": 5 + } + ``` + +- **Output:** + + Null + +#### `POST /agree_connection` + +Agrees to a key exchange initiated by another client. Check the `securityhub_list` are both registered or not. + +- **Input:** + + `content-type: "application/json"` + + ```json + { + "client_id": Integer, + "securityhub_list": Integer[], + "keysize": Integer + } + ``` + + Example: + + ```json + { + "client_id": 1, + "securityhub_list": [1, 2], + "keysize": 5 + } + ``` + +- **Output:** + + Null + +If the exchange cannot process, the API will not return `200 OK`. + + +#### `POST /receive_key_instruction` + +Receives a key instruction from the security hub. + +- **Input:** + + `content-type: "application/json"` + + ```json + { + "sender_id": Integer, + "hash": Integer, + "key_instruction": Boolean[], + "total": Integer, + "securityhub_id": Integer + } + ``` + + Example: + + ```json + { + "sender_id": 1, + "hash": 1234, + "key_instruction": [true, false, ...], + "total": 2, + "securityhub_id": 1 + } + ``` + +- **Output:** + + Null \ No newline at end of file diff --git a/Screenshot.png b/Screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..17d9e3db28d924b64864bd4a1c59b5720573da31 GIT binary patch literal 22462 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 MzMm|L_PSpFCu>rxC;$Ke literal 0 HcmV?d00001 diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..8c6e93e --- /dev/null +++ b/src/main.rs @@ -0,0 +1,228 @@ +use actix_cors::Cors; +use actix_web::{ http::header, web, App, HttpServer, Responder, HttpResponse }; +use serde::{ Deserialize, Serialize }; +use reqwest::Client as HttpClient; +use std::sync::Mutex; +use std::collections::HashMap; +use std::fs; +use std::env; +use std::io::Write; +use dotenv::dotenv; +use rand::Rng; + +#[derive(Serialize, Deserialize, Debug, Clone)] +struct User { + id: u64, + username: String, + url: String, + random_bits: Vec +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +struct RegisterUser { + id: u64, + username: String, + url: String +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +struct GenerateKeyInstruction { + sender_id: u64, + receiver_id: u64, + hash: u64, + total: u64, + keysize: u64 +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +struct Database { + users: HashMap +} + +impl Database { + fn new() -> Self { + Self { + users: HashMap::new() + } + } + + fn get_user(&self, id: &u64) -> Option<&User> { + self.users.get(id) + } + + fn update_user(&mut self, user: User) { + self.users.insert(user.id, user); + } + + fn insert_user(&mut self, user: User) { + self.users.insert(user.id, user); + } + + fn save_to_file(&self) -> std::io::Result<()> { + let data: String = serde_json::to_string(&self)?; + let args: Vec = env::args().collect(); + let file_name = format!("database-{}.json", args.get(2).unwrap_or(&env::var("SECURITYHUB_ID").unwrap())); + let mut file: fs::File = fs::File::create(file_name)?; + file.write_all(data.as_bytes())?; + Ok(()) + } + + fn load_from_file() -> std::io::Result { + let args: Vec = env::args().collect(); + let file_name = format!("database-{}.json", args.get(2).unwrap_or(&env::var("SECURITYHUB_ID").unwrap())); + let file_content: String = fs::read_to_string(file_name)?; + let db: Database = serde_json::from_str(&file_content)?; + Ok(db) + } +} + +struct AppState { + db: Mutex +} + +async fn user_list(app_state: web::Data) -> impl Responder { + let db: std::sync::MutexGuard = app_state.db.lock().unwrap(); + let user_ids: Vec = db.users.keys().cloned().collect(); + HttpResponse::Ok().json(user_ids) +} + +async fn register_client(app_state: web::Data, user: web::Json) -> impl Responder { + let mut db: std::sync::MutexGuard = app_state.db.lock().unwrap(); + let mut random_bits: Vec = Vec::new(); + + let mut rng = rand::thread_rng(); + + // number of random bits to generate + let num_bits = env::var("GENERATE_RANDOM_BITS_NUM").unwrap().parse::().unwrap(); + for _ in 0..num_bits { + let random_bit: u8 = rng.gen_range(0..=1); + random_bits.push(random_bit == 1); + } + + let create_user = User { + id: user.id, + username: user.username.clone(), + url: user.url.clone(), + random_bits + }; + + db.insert_user(create_user.clone()); + let _ = db.save_to_file(); + HttpResponse::Ok().json(create_user) +} + +async fn generate_key_instruction(app_state: web::Data, generate_key_instruction: web::Json) -> impl Responder { + let mut db: std::sync::MutexGuard = app_state.db.lock().unwrap(); + + let sender = db.get_user(&generate_key_instruction.sender_id); + match sender { + Some(_) => (), + None => return HttpResponse::NotFound().finish() + } + let mut sender = sender.unwrap().clone(); + + let receiver = db.get_user(&generate_key_instruction.receiver_id); + match receiver { + Some(_) => (), + None => return HttpResponse::NotFound().finish() + } + let mut receiver = receiver.unwrap().clone(); + + // check remaining random bits + if sender.random_bits.len() < generate_key_instruction.keysize as usize || receiver.random_bits.len() < generate_key_instruction.keysize as usize{ + return HttpResponse::BadRequest().finish() + } + + // calculate key instruction A ^ B + let key_instruction: Vec = (0..generate_key_instruction.keysize) + .map(|i| sender.random_bits[i as usize] ^ receiver.random_bits[i as usize]) + .collect(); + + // reduce the sender random bits by keysize + sender.random_bits = sender.random_bits.iter().skip(generate_key_instruction.keysize as usize).cloned().collect(); + db.update_user(sender.clone()); + + let client = HttpClient::new(); + let args: Vec = env::args().collect(); + let securityhub_id_env = env::var("SECURITYHUB_ID").unwrap(); + let securityhub_id: u64 = args.get(2).unwrap_or(&securityhub_id_env).parse().unwrap(); + let res = client.post(&format!("{}/receive_key_instruction", receiver.url)) + .json(&serde_json::json!({ + "sender_id": sender.id, + "securityhub_id": securityhub_id, + "hash": generate_key_instruction.hash, + "total": generate_key_instruction.total, + "key_instruction": key_instruction.clone() + })) + .send() + .await; + + let mut flag = false; + match res { + Ok(_) => { + println!("Key instruction sent to client {}", receiver.id); + receiver.random_bits = receiver.random_bits.iter().skip(generate_key_instruction.keysize as usize).cloned().collect(); + db.update_user(receiver.clone()); + flag = true; + }, + Err(err) => { + println!("Error connecting to client {}: {:?}", receiver.id, err); + } + } + let _ = db.save_to_file(); + if flag { + HttpResponse::Ok().json(key_instruction) + } else { + HttpResponse::NotFound().finish() + } + +} + +#[actix_web::main] +async fn main() -> std::io::Result<()> { + dotenv().ok(); + let args: Vec = env::args().collect(); + let db: Database = match Database::load_from_file() { + Ok(db) => db, + Err(_) => Database::new() + }; + + let data: web::Data = web::Data::new(AppState { + db: Mutex::new(db) + }); + + // if args[1] is set, use the port from the args + // else use the port from the .env + let port_env = env::var("PORT").unwrap(); + let port = args.get(1).unwrap_or(&port_env); + println!("Starting server on port {}", port); + + // if args[2] is set, use the securityhub id from the args + // else use the securityhub id from the .env + let securityhub_id_env = env::var("SECURITYHUB_ID").unwrap(); + let securityhub_id = args.get(2).unwrap_or(&securityhub_id_env); + println!("Security Hub ID: {}", securityhub_id); + + HttpServer::new(move || { + App::new() + .wrap( + Cors::permissive() + .allowed_origin_fn(|origin, _req_head| { + origin.as_bytes().starts_with(b"http://localhost") || origin == "null" + }) + .allowed_methods(vec!["GET", "POST", "PUT", "DELETE"]) + .allowed_headers(vec![header::AUTHORIZATION, header::ACCEPT]) + .allowed_header(header::CONTENT_TYPE) + .supports_credentials() + .max_age(3600) + ) + .app_data(data.clone()) + .route("/register_client", web::post().to(register_client)) + .route("/generate_key_instruction", web::post().to(generate_key_instruction)) + .route("/user_list", web::post().to(user_list)) + }) + + .bind(format!("127.0.0.1:{}", port))? + .run() + .await +}