commit b10773b7dd3e366d80b5ea40ebcc7c005244db89 Author: ny0c Date: Thu Dec 22 18:54:55 2022 +0800 first commit diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..6833819 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1919 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "actix-codec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57a7559404a7f3573127aab53c08ce37a6c6a315c374a31070f3c91cd1b4a7fe" +dependencies = [ + "bitflags", + "bytes", + "futures-core", + "futures-sink", + "log", + "memchr", + "pin-project-lite", + "tokio", + "tokio-util", +] + +[[package]] +name = "actix-http" +version = "3.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c83abf9903e1f0ad9973cc4f7b9767fd5a03a583f51a5b7a339e07987cd2724" +dependencies = [ + "actix-codec", + "actix-rt", + "actix-service", + "actix-tls", + "actix-utils", + "ahash", + "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", + "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", +] + +[[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.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ea16c295198e958ef31930a6ef37d0fb64e9ca3b6116e6b93a8bdae96ee1000" +dependencies = [ + "futures-core", + "tokio", +] + +[[package]] +name = "actix-server" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0da34f8e659ea1b077bb4637948b815cd3768ad5a188fdcd74ff4d84240cd824" +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-tls" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fde0cf292f7cdc7f070803cb9a0d45c018441321a78b1042ffbbb81ec333297" +dependencies = [ + "actix-codec", + "actix-rt", + "actix-service", + "actix-utils", + "futures-core", + "log", + "pin-project-lite", + "tokio-rustls", + "tokio-util", + "webpki-roots", +] + +[[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.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d48f7b6534e06c7bfc72ee91db7917d4af6afe23e7d223b51e68fffbb21e96b9" +dependencies = [ + "actix-codec", + "actix-http", + "actix-macros", + "actix-router", + "actix-rt", + "actix-server", + "actix-service", + "actix-tls", + "actix-utils", + "actix-web-codegen", + "ahash", + "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.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa9362663c8643d67b2d5eafba49e4cb2c8a053a29ed00a0bea121f17c76b13" +dependencies = [ + "actix-router", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "actix-web-httpauth" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dda62cf04bc3a9ad2ea8f314f721951cfdb4cdacec4e984d20e77c7bb170991" +dependencies = [ + "actix-utils", + "actix-web", + "base64", + "futures-core", + "futures-util", + "log", + "pin-project-lite", +] + +[[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 = "aho-corasick" +version = "0.7.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +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.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6e93155431f3931513b243d371981bb2770112b370c82745a1d19d2f99364" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64ct" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf" + +[[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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +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.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ad2d4653bf5ca36ae797b1f4bb4dbddb60ce49ca4aed8a2ce4829f60425b80" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bumpalo" +version = "3.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" + +[[package]] +name = "bytestring" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7f83e57d9154148e355404702e2694463241880b939570d7c97c014da7a69a1" +dependencies = [ + "bytes", +] + +[[package]] +name = "cc" +version = "1.0.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a284da2e6fe2092f2353e51713435363112dfd60030e22add80be333fb928f" +dependencies = [ + "jobserver", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "combine" +version = "4.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" +dependencies = [ + "bytes", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", + "tokio-util", +] + +[[package]] +name = "const-oid" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cec318a675afcb6a1ea1d4340e2d377e56e47c266f28043ceccbf4412ddfdd3b" + +[[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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "344adc371239ef32293cb1c4fe519592fcf21206c79c02854320afcdf3ab4917" +dependencies = [ + "percent-encoding", + "time", + "version_check", +] + +[[package]] +name = "cpufeatures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +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 = "der" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dd2ae565c0a381dde7fade45fce95984c568bdcb4700a4fdbe3175e0380b2f" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[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", +] + +[[package]] +name = "digest" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", +] + +[[package]] +name = "encoding_rs" +version = "0.8.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "env_logger" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "errno" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +dependencies = [ + "errno-dragonfly", + "libc", + "winapi", +] + +[[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 = "flate2" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" +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 = "form_urlencoded" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" + +[[package]] +name = "futures-executor" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" + +[[package]] +name = "futures-macro" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" + +[[package]] +name = "futures-task" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" + +[[package]] +name = "futures-util" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "h2" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4" +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.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + +[[package]] +name = "http" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[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 = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "is-terminal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "927609f78c2913a6f6ac3c27a4fe87f43e2a35367c0c4b0f8265e8f49a104330" +dependencies = [ + "hermit-abi 0.2.6", + "io-lifetimes", + "rustix", + "windows-sys", +] + +[[package]] +name = "itoa" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" + +[[package]] +name = "jobserver" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "jsonwebtoken" +version = "8.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa4b4af834c6cfd35d8763d359661b90f2e45d8f750a0849156c7f4671af09c" +dependencies = [ + "base64", + "pem", + "ring", + "serde", + "serde_json", + "simple_asn1", +] + +[[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" +dependencies = [ + "spin", +] + +[[package]] +name = "libc" +version = "0.2.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" + +[[package]] +name = "libm" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" + +[[package]] +name = "linux-raw-sys" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f9f08d8963a6c613f4b1a78f4f4a4dbfadf8e6545b2d72861731e4858b8b47f" + +[[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.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[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.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + +[[package]] +name = "miniz_oxide" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys", +] + +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-bigint-dig" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2399c9463abc5f909349d8aa9ba080e0b88b3ce2885389b60b993f39b1a56905" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" +dependencies = [ + "hermit-abi 0.1.19", + "libc", +] + +[[package]] +name = "nv_ls" +version = "0.1.0" +dependencies = [ + "actix-web", + "actix-web-httpauth", + "base64", + "derive_more", + "env_logger", + "futures", + "jsonwebtoken", + "log", + "num-bigint-dig", + "num-traits", + "obfstr", + "pem", + "rand", + "rcgen", + "redis", + "ring", + "rsa", + "rustls", + "rustls-pemfile", + "serde", + "serde_json", + "sha2", + "time", + "tokio", + "uuid", +] + +[[package]] +name = "obfstr" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a32982fced7de6834f4583fde19da2db188afbb4ba57bea6f024f7bf40c542" + +[[package]] +name = "once_cell" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" + +[[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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + +[[package]] +name = "paste" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1" + +[[package]] +name = "pem" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c64931a1a212348ec4f3b4362585eca7159d0d09cbdf4a7f74f02173596fd4" +dependencies = [ + "base64", +] + +[[package]] +name = "pem-rfc7468" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d159833a9105500e0398934e205e0773f0b27529557134ecfc51c27646adac" +dependencies = [ + "base64ct", +] + +[[package]] +name = "percent-encoding" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" + +[[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 = "pkcs1" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eff33bdbdfc54cc98a2eca766ebdec3e1b8fb7387523d5c9c9a2891da856f719" +dependencies = [ + "der", + "pkcs8", + "spki", + "zeroize", +] + +[[package]] +name = "pkcs8" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" +dependencies = [ + "der", + "spki", +] + +[[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.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +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 = "rcgen" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbe84efe2f38dea12e9bfc1f65377fdf03e53a18cb3b995faedf7934c7e785b" +dependencies = [ + "pem", + "ring", + "time", + "yasna", +] + +[[package]] +name = "redis" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "513b3649f1a111c17954296e4a3b9eecb108b766c803e2b99f179ebe27005985" +dependencies = [ + "async-trait", + "bytes", + "combine", + "futures-util", + "itoa", + "percent-encoding", + "pin-project-lite", + "ryu", + "sha1_smol", + "tokio", + "tokio-util", + "url", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi", +] + +[[package]] +name = "rsa" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "094052d5470cbcef561cb848a7209968c9f12dfa6d668f4bca048ac5de51099c" +dependencies = [ + "byteorder", + "digest", + "num-bigint-dig", + "num-integer", + "num-iter", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core", + "signature", + "smallvec", + "subtle", + "zeroize", +] + +[[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.36.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb93e85278e08bb5788653183213d3a60fc242b10cb9be96586f5a73dcb67c23" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "rustls" +version = "0.20.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "539a2bfe908f471bfa933876bd1eb6a19cf2176d375f82ef7f99530a40e48c2c" +dependencies = [ + "log", + "ring", + "sct", + "webpki", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0864aeff53f8c05aa08d86e5ef839d3dfcf07aeba2db32f12db0ef716e87bd55" +dependencies = [ + "base64", +] + +[[package]] +name = "ryu" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "sct" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "semver" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4" + +[[package]] +name = "serde" +version = "1.0.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db" +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 = "sha1_smol" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" + +[[package]] +name = "sha2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +dependencies = [ + "digest", + "rand_core", +] + +[[package]] +name = "simple_asn1" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror", + "time", +] + +[[package]] +name = "slab" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +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.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spki" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" +dependencies = [ + "itoa", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" + +[[package]] +name = "time-macros" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2" +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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "tokio" +version = "1.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76ce4a75fb488c605c54bf610f221cea8b0dafb53333c1a67e8ee199dcd2ae3" +dependencies = [ + "autocfg", + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "winapi", +] + +[[package]] +name = "tokio-macros" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-rustls" +version = "0.23.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" +dependencies = [ + "rustls", + "tokio", + "webpki", +] + +[[package]] +name = "tokio-util" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[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.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "unicode-bidi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" + +[[package]] +name = "unicode-ident" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "url" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "uuid" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "422ee0de9031b5b948b97a8fc04e3aa35230001a722ddd27943e0be31564ce4c" +dependencies = [ + "getrandom", + "rand", + "serde", + "uuid-macro-internal", +] + +[[package]] +name = "uuid-macro-internal" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73bc89f2894593e665241e0052c3791999e6787b7c4831daa0a5c2e637e276d8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[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.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" + +[[package]] +name = "web-sys" +version = "0.3.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "webpki-roots" +version = "0.22.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368bfe657969fb01238bb756d351dcade285e0f6fcbd36dcb23359a5169975be" +dependencies = [ + "webpki", +] + +[[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-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[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", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" + +[[package]] +name = "yasna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346d34a236c9d3e5f3b9b74563f238f955bbd05fa0b8b4efa53c130c43982f4c" +dependencies = [ + "time", +] + +[[package]] +name = "zeroize" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.4+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fa202f2ef00074143e219d15b62ffc317d17cc33909feac471c044087cad7b0" +dependencies = [ + "cc", + "libc", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..1378cc0 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,50 @@ +[package] +name = "nv_ls" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +rsa = "0.7.2" +ring = "0.16.20" +rand = "0.8.5" +pem = { version = "1.0" } +rcgen = { version = "0.10.0", features = ["pem"] } +num-traits = { version = "0.2", default-features = false } +num-bigint-dig = { version = "0.8", default-features = false } +sha2 = "0.10.6" +base64 = "0.13.1" +uuid = { version = "1.2.2", features = ["v4", "fast-rng", "macro-diagnostics", "serde"] } + + +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +jsonwebtoken = "8" +time = { version = "0.3.17", features = ["macros", "serde", "formatting", "parsing"] } + + +tokio = { version = "1.13.1", features = ["full"] } +actix-web = { version = "4", features = ["rustls"] } +actix-web-httpauth = "0.8.0" +rustls = "0.20" +rustls-pemfile = "1" +env_logger = "0.10" +log = "0.4" +futures = "0.3.25" + +redis = { version = "0.22", features = ["tokio-comp"] } +obfstr = "0.4.1" +derive_more = "0.99.17" + + +[profile.dev.package.num-bigint-dig] +opt-level = 3 + + +[profile.release] +strip = true +opt-level = 3 +lto = true +codegen-units = 1 +panic = "abort" \ No newline at end of file diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..d6de1c6 --- /dev/null +++ b/readme.md @@ -0,0 +1,73 @@ +## config.json + +### server_addr + +The service listener addr. + +### server_port + +The service listener port. + +### domain + +Automatic generation of ssl certificates for domain names. + +If you have a certificate, you do not need to change anything. + +### req_host + +The host filled in the client's token, it is also the address of the client request + +### req_port + +The port filled in the client's token, it is also the port of the client request + +### redis_url + +Same as the name + +### redis_task_interval + +How often to automatically clean up the client release inside redis. + +### scope_ref_list + +Whatever, just let it as is, or ur can random some uuid v4, but keep in mind it only takes two + +### nls_service_instance_ref + +Whatever, just let it as is, or ur can random a new uuid v4 + +### lease_time + +Client lease time, In second + +### lease_renewal_factor + +The interval factor between client vm requests to the server, expressed as a percentage. + +*lease_time* * *lease_renewal_factor* + +e.g: + +lease_time: 600s, lease_renewal_factor: 20, time now: 2022/12/03 10:00:00 + +It means, The time of the next client request time is: 2022/12/03 10:02:00, and next time is 2022/12/03 10:04:00 till the client lease renew + +### cert_https + +Same as the name + +### rsa_client_token + +For vm client token encryption and vm-side verification of signatures, can delete the corresponding file and generate it again randomly + + + + + + + +## Get vm client token + +just access `https://ur-ip-addr:server_port/genClientToken` diff --git a/src/api.rs b/src/api.rs new file mode 100644 index 0000000..e18dae4 --- /dev/null +++ b/src/api.rs @@ -0,0 +1,440 @@ +use actix_web::{get, post, put, delete, web, Result, Responder, HttpResponse, http::header::ContentType, Either}; +use std::str::FromStr; + +use num_traits::cast::ToPrimitive; +use sha2::{Sha256, Digest}; +use uuid::{Uuid, uuid}; +use time::OffsetDateTime; +use time::macros::format_description; +use rsa::{PublicKeyParts, RsaPublicKey}; +use rsa::pkcs8::{DecodePublicKey, EncodePublicKey, LineEnding}; + + +use crate::core_struct::{AppConfigState, NodeUrl, PortMap, PortSet, JwtAuthToken}; +use crate::core_struct::origin::{OriginRequest, OriginResponse}; +use crate::core_struct::code::{CodeRequest, CodeResponse, AcData}; +use crate::core_struct::client_token::{ClientTokenRequest, ServiceInstanceConfiguration, ServiceInstancePublicKeyConfiguration, ServiceInstancePublicKeyMe}; +use crate::core_struct::token::{AuthCode, TokenRequest, TokenResponse}; +use crate::core_struct::leases::{ClientLeasesResponse, AddLessorResponse, CreateLeaseResult, LeaseCreateDetail, UpdateLeasesResponse, UpdateLeasesErrorResponse, DeleteLeasesResponse}; + + +#[derive(Debug, derive_more::Display, derive_more::Error)] +pub enum ApiError { + #[display(fmt = "Api Error: {}", detail)] + InternalError { detail: String }, +} + +impl actix_web::error::ResponseError for ApiError { + fn status_code(&self) -> actix_web::http::StatusCode { + match *self { + ApiError::InternalError { .. } => actix_web::http::StatusCode::INTERNAL_SERVER_ERROR, + } + } + + fn error_response(&self) -> HttpResponse { + HttpResponse::build(self.status_code()) + .insert_header(ContentType::html()) + .body(self.to_string()) + } +} + + +#[get("/genClientToken")] +pub async fn gen_client_token(config_state: web::Data) -> HttpResponse { + let req_port = &config_state.req_port; + let req_host = &config_state.req_host; + let token_public_key_str = &config_state.rsa_client_token.public_key.clone(); + let token_public_key = RsaPublicKey::from_public_key_pem(std::str::from_utf8(token_public_key_str).expect("error read key")).expect("Error get public key"); + let key_modulus = token_public_key.n().clone(); + let key_exponent = token_public_key.e().clone(); + + let current_time = OffsetDateTime::now_utc(); + let exp_time = current_time.clone() + std::time::Duration::from_secs(60 * 60 * 24 * 30); + let client_token_obj = ClientTokenRequest { + jti: Uuid::new_v4(), + iss: "NLS Service Instance".to_string(), + aud: "NLS Licensed Client".to_string(), + iat: current_time.clone(), + nbf: current_time.clone(), + exp: exp_time, + update_mode: "ABSOLUTE".to_string(), + scope_ref_list: config_state.scope_ref_list.clone(), + fulfillment_class_ref_list: None, + service_instance_configuration: ServiceInstanceConfiguration { + nls_service_instance_ref: config_state.nls_service_instance_ref.clone(), + svc_port_set_list: vec![PortSet { + idx: 0, + d_name: "DLS".to_string(), + svc_port_map: vec![ + PortMap { + service: "auth".to_string(), + port: req_port.clone(), + }, PortMap { + service: "lease".to_string(), + port: req_port.clone(), + }, + ], + }], + node_url_list: vec![ + NodeUrl { + idx: 0, + url: req_host.clone(), + url_qr: req_host.clone(), + svc_port_set_idx: 0, + } + ], + }, + service_instance_public_key_configuration: ServiceInstancePublicKeyConfiguration { + service_instance_public_key_me: ServiceInstancePublicKeyMe { type_mod: format!("{:x}", key_modulus), exp: key_exponent.to_u32().unwrap() }, + service_instance_public_key_pem: token_public_key.to_public_key_pem(LineEnding::LF).unwrap(), + key_retention_mode: "LATEST_ONLY".to_string(), + }, + }; + + let jwt_header = jsonwebtoken::Header::new(jsonwebtoken::Algorithm::RS256); + + let client_token_str = jsonwebtoken::encode( + &jwt_header, + &client_token_obj, + &jsonwebtoken::EncodingKey::from_rsa_pem(&config_state.rsa_client_token.private_key).expect("Error read jwt encode key!"), + ).expect("Failed to encode jwt data!"); + + let tok_format = format_description!("[day]-[month]-[year]-[hour]:[minute]:[second]"); + let tok_time = OffsetDateTime::now_utc().format(&tok_format).unwrap(); + HttpResponse::Ok() + .content_type(ContentType::octet_stream()) + .append_header(("Content-Disposition", format!("attachment; filename=\"client_configuration_token_{}.tok\"", &tok_time))) + .body(client_token_str.into_bytes()) +} + + +#[post("/auth/v1/origin")] +pub async fn origin_req(origin_request: web::Json) -> Result { + let origin_response = OriginResponse { + origin_ref: origin_request.candidate_origin_ref, + environment: origin_request.environment.clone(), + svc_port_set_list: None, + node_url_list: None, + node_query_order: None, + prompts: None, + sync_timestamp: OffsetDateTime::now_utc(), + }; + Ok(web::Json(origin_response)) +} + + +// todo error catch +#[post("/auth/v1/code")] +pub async fn code_req(code_request: web::Json, config_state: web::Data) -> Either, Result> { + let time_now = OffsetDateTime::now_utc(); + let exp_time = time_now.clone() + std::time::Duration::from_secs(600); + let code_challenge = code_request.code_challenge.clone(); + + let ac_data = AcData { + iat: time_now, + exp: exp_time, + challenge: code_challenge, + origin_ref: code_request.origin_ref, + key_ref: uuid!("00000000-0000-0000-0000-000000000000"), + kid: uuid!("00000000-0000-0000-0000-000000000000"), + }; + + let mut jwt_header = jsonwebtoken::Header::new(jsonwebtoken::Algorithm::RS256); + jwt_header.kid = Option::from("00000000-0000-0000-0000-000000000000".to_string()); + + let auth_code = jsonwebtoken::encode( + &jwt_header, + &ac_data, + &jsonwebtoken::EncodingKey::from_rsa_pem(&config_state.rsa_server_jwt.private_key).expect("Error read jwt encode key!"), + ).expect("Failed to encode jwt data!"); + + let code_resp = CodeResponse { + auth_code, + sync_timestamp: OffsetDateTime::now_utc(), + prompts: None, + }; + Either::Left(web::Json(code_resp)) +} + + +#[post("/auth/v1/token")] +pub async fn auth_token(token_request: web::Json, config_state: web::Data) -> Either, Result> { + // decode jwt + let client_auth_code = match jsonwebtoken::decode::( + &token_request.auth_code, + &jsonwebtoken::DecodingKey::from_rsa_pem(&config_state.rsa_server_jwt.public_key).expect("Error read jwt decode key"), + &jsonwebtoken::Validation::new(jsonwebtoken::Algorithm::RS256), + ) { + Ok(data) => data, + Err(decode_error) => { + log::info!("jwt decode error!"); + return Either::Right(Err(ApiError::InternalError { detail: decode_error.to_string() })); + } + }; + + // check challenge + let code_verifier = token_request.code_verifier.clone(); + let mut hasher = Sha256::new(); + hasher.update(&code_verifier); + let result = hasher.finalize(); + let b64_result = base64::encode(result).rsplit("=").collect::(); + if b64_result != client_auth_code.claims.challenge { + log::info!("Challenge failed!"); + return Either::Right(Err(ApiError::InternalError { detail: "Challenge Failed!".to_string() })); + } + + + let time_now = OffsetDateTime::now_utc(); + let exp_time = time_now.clone() + std::time::Duration::from_secs(60 * 60); // 1hr + + let auth_token = JwtAuthToken { + iat: time_now.clone(), + nbf: time_now.clone(), + iss: "https://cls.nvidia.org".to_string(), + aud: "https://cls.nvidia.org".to_string(), + exp: exp_time.clone(), + origin_ref: client_auth_code.claims.origin_ref, + key_ref: client_auth_code.claims.key_ref, + kid: client_auth_code.claims.kid, + }; + + + let mut jwt_header = jsonwebtoken::Header::new(jsonwebtoken::Algorithm::RS256); + jwt_header.kid = Option::from("00000000-0000-0000-0000-000000000000".to_string()); + + let auth_token = jsonwebtoken::encode( + &jwt_header, + &auth_token, + &jsonwebtoken::EncodingKey::from_rsa_pem(&config_state.rsa_server_jwt.private_key).expect("Error read jwt encode key!"), + ).expect("Failed to encode jwt data!"); + + let token_resp = TokenResponse { + auth_token, + expires: exp_time, + prompts: None, + sync_timestamp: time_now, + }; + Either::Left(web::Json(token_resp)) +} + + +// todo error catch +#[get("/v1/lessor/leases")] +pub async fn get_all_leases(jwt_auth_token: Option>, redis_client: web::Data) -> Result { + let time_now = OffsetDateTime::now_utc(); + + let mut client_leases = ClientLeasesResponse { + active_lease_list: vec![], + prompts: None, + sync_timestamp: time_now, + }; + + let origin_ref: Uuid = match jwt_auth_token { + Some(data) => data.origin_ref, + None => { + return Ok(web::Json(client_leases)); + } + }; + + let mut redis_conn = redis_client.get_async_connection().await.expect("failed to get redis connection!"); + + let lease_data: Vec = redis::cmd("ZRANGEBYSCORE") + .arg(&[ + origin_ref.to_string().as_str(), + format!("({}", time_now.unix_timestamp()).as_str(), + "+inf" + ]) + .query_async(&mut redis_conn) + .await.expect("unable to get redis"); + + if lease_data.len() == 0 { + return Ok(web::Json(client_leases)); + } else { + for lease in lease_data { + client_leases.active_lease_list.push(Uuid::from_str(lease.as_str()).unwrap()); + } + } + + Ok(web::Json(client_leases)) +} + +#[post("/v1/lessor")] +pub async fn add_lessor( + jwt_auth_token: Option>, + config_state: web::Data, + redis_client: web::Data, +) -> Either, Result> { + let origin_ref: Uuid = match jwt_auth_token { + Some(data) => data.origin_ref, + None => { + return Either::Right(Ok(HttpResponse::Ok().content_type("application/json").body("none"))); + } + }; + + + let time_now = OffsetDateTime::now_utc(); + let exp_time = time_now + time::Duration::minutes(i64::from(config_state.lease_time)); + + let new_ref = Uuid::new_v4(); + + let mut redis_conn = redis_client.get_async_connection().await.expect("failed to get redis connection!"); + let redis_status: i32 = redis::cmd("ZADD") + .arg(&[ + origin_ref.to_string().as_str(), + exp_time.unix_timestamp().to_string().as_str(), + new_ref.to_string().as_str() + ]) + .query_async(&mut redis_conn) + .await.expect("unable to get redis"); + + if !(redis_status == 1 || redis_status == 0) { + return Either::Right(Ok(HttpResponse::Ok().content_type("application/json").body("none"))); + } + let add_resp = AddLessorResponse { + lease_result_list: vec![ + CreateLeaseResult { + error: None, + lease: LeaseCreateDetail { + type_ref: new_ref, + created: time_now, + expires: exp_time, + recommended_lease_renewal: config_state.lease_renewal_factor.clone(), + offline_lease: false, + license_type: "CONCURRENT_COUNTED_SINGLE".to_string(), + }, + ordinal: None, + } + ], + prompts: None, + result_code: None, + sync_timestamp: time_now, + }; + Either::Left(web::Json(add_resp)) +} + +#[put("/v1/lease/{lease_ref}")] +pub async fn update_lessor( + req_path: web::Path, + jwt_auth_token: Option>, + config_state: web::Data, + redis_client: web::Data, +) -> Either, Result> { + // env setup + let time_now = OffsetDateTime::now_utc(); + let exp_time = time_now + time::Duration::minutes(i64::from(config_state.lease_time)); + let lease_ref = req_path.into_inner(); + let mut redis_conn = redis_client.get_async_connection().await.expect("failed to get redis connection!"); + + let mut error_resp = UpdateLeasesErrorResponse { + code: 404, + message: "".to_string(), + prompts: None, + sync_timestamp: time_now, + }; + + // get ref from jwt + let origin_ref: Uuid = match jwt_auth_token { + Some(data) => data.origin_ref, + None => { + error_resp.code = 500; + error_resp.message = format!("Unable to get origin_ref!"); + return Either::Right(Ok(HttpResponse::BadRequest().content_type("application/json").body(serde_json::to_string(&error_resp).unwrap()))); + } + }; + + // get all lease by ref from redis + let lease_data: Vec = redis::cmd("ZRANGEBYSCORE") + .arg(&[ + origin_ref.to_string().as_str(), + format!("({}", time_now.unix_timestamp()).as_str(), + "+inf" + ]) + .query_async(&mut redis_conn) + .await.expect("unable to get redis"); + + // check lease_ref in db or not + if !lease_data.contains(&lease_ref.to_string()) { + error_resp.message = format!("no current lease found for: {}", lease_ref); + return Either::Right(Ok(HttpResponse::NotFound().content_type("application/json").body(serde_json::to_string(&error_resp).unwrap()))); + } else { + // update the lease + let redis_status: i32 = redis::cmd("ZADD") + .arg(&[ + origin_ref.to_string().as_str(), + exp_time.unix_timestamp().to_string().as_str(), + lease_ref.to_string().as_str() + ]) + .query_async(&mut redis_conn) + .await.expect("unable to get redis"); + + if !(redis_status == 1 || redis_status == 0) { + error_resp.code = 500; + error_resp.message = format!("Failed to update lease: {}", lease_ref); + return Either::Right(Ok(HttpResponse::InternalServerError().content_type("application/json").body(serde_json::to_string(&error_resp).unwrap()))); + } + } + + let update_resp = UpdateLeasesResponse { + expires: exp_time, + lease_ref: lease_ref, + offline_lease: false, + prompts: None, + recommended_lease_renewal: config_state.lease_renewal_factor.clone(), + sync_timestamp: time_now, + }; + Either::Left(web::Json(update_resp)) +} + +#[delete("/v1/lessor/leases")] +pub async fn delete_all_leases( + jwt_auth_token: Option>, + redis_client: web::Data, +) -> Either, Result> { + // env setup + let time_now = OffsetDateTime::now_utc(); + let mut redis_conn = redis_client.get_async_connection().await.expect("failed to get redis connection!"); + + // get ref from jwt + let origin_ref: Uuid = match jwt_auth_token { + Some(data) => data.origin_ref, + None => { + return Either::Right(Ok(HttpResponse::BadRequest().content_type("text/html").body("None"))); + } + }; + + let mut del_resp = DeleteLeasesResponse { + release_failure_list: None, + released_lease_list: vec![], + prompts: None, + sync_timestamp: time_now, + }; + + // get all lease by ref from redis + let lease_data: Vec = redis::cmd("ZRANGEBYSCORE") + .arg(&[ + origin_ref.to_string().as_str(), + format!("({}", time_now.unix_timestamp()).as_str(), + "+inf" + ]) + .query_async(&mut redis_conn) + .await.expect("unable to get redis"); + + if !lease_data.is_empty() { + // delete the lease by ref + let redis_status: i32 = redis::cmd("DEL") + .arg(&[ + origin_ref.to_string().as_str(), + ]) + .query_async(&mut redis_conn) + .await.expect("unable to get redis"); + if redis_status != 1 { + del_resp.release_failure_list = Some(lease_data.iter().map(|x| Uuid::from_str(x.as_str()).unwrap()).collect()); + } + + for lease in lease_data { + del_resp.released_lease_list.push(Uuid::from_str(lease.as_str()).unwrap()); + } + } + + Either::Left(web::Json(del_resp)) +} \ No newline at end of file diff --git a/src/cert_tools.rs b/src/cert_tools.rs new file mode 100644 index 0000000..789eb5b --- /dev/null +++ b/src/cert_tools.rs @@ -0,0 +1,58 @@ +#![allow(clippy::complexity, clippy::style, clippy::pedantic)] + +use rsa::{RsaPrivateKey, RsaPublicKey}; +use rsa::pkcs8::{EncodePrivateKey, EncodePublicKey, LineEnding}; +use rand::rngs::OsRng; + +use rcgen::{Certificate, CertificateParams, DistinguishedName, date_time_ymd, DnType}; +use std::convert::TryFrom; +use crate::utils::MyRsaKeyPair; + + +pub fn gen_rsa2048() -> MyRsaKeyPair { + let mut rng = rand::thread_rng(); + let bits = 2048; + let priv_key = RsaPrivateKey::new(&mut rng, bits).expect("failed to generate a key"); + let pub_key = RsaPublicKey::from(&priv_key); + + let pub_key_str = pub_key.to_public_key_pem(LineEnding::LF).unwrap(); + let priv_key_str = priv_key.to_pkcs8_pem(LineEnding::LF).unwrap().as_str().to_owned(); + + MyRsaKeyPair { + public_key: pub_key_str.into_bytes(), + private_key: priv_key_str.into_bytes(), + } +} + + +pub fn gen_cert_rsa2048(common_name: String) -> MyRsaKeyPair { + let mut params: CertificateParams = Default::default(); + params.not_before = date_time_ymd(2021, 01, 01); + params.not_after = date_time_ymd(2030, 12, 30); + params.distinguished_name = DistinguishedName::new(); + params.distinguished_name.push(DnType::CommonName, common_name); + params.distinguished_name.push(DnType::OrganizationalUnitName, "Server Cert"); + params.distinguished_name.push(DnType::OrganizationName, "ORG"); + params.distinguished_name.push(DnType::CountryName, "RS"); + + params.alg = &rcgen::PKCS_RSA_SHA256; + + + let mut rng = OsRng; + let bits = 2048; + let private_key = RsaPrivateKey::new(&mut rng, bits).expect("Failed to gen private key!"); + let private_key_der = private_key.to_pkcs8_der().unwrap(); + let key_pair = rcgen::KeyPair::try_from(private_key_der.as_bytes()).unwrap(); + params.key_pair = Some(key_pair); + + let cert = Certificate::from_params(params).expect("Failed to gen cert!"); + let pem_serialized = cert.serialize_pem().unwrap(); + + let cert_str = pem_serialized; + let cert_key = cert.serialize_private_key_pem(); + + MyRsaKeyPair { + public_key: cert_str.into_bytes(), + private_key: cert_key.into_bytes(), + } +} \ No newline at end of file diff --git a/src/core_struct/client_token.rs b/src/core_struct/client_token.rs new file mode 100644 index 0000000..403cffc --- /dev/null +++ b/src/core_struct/client_token.rs @@ -0,0 +1,50 @@ +use uuid::Uuid; +use serde::{Serialize, Deserialize}; +use time::OffsetDateTime; +use time::serde as time_serde; +use crate::core_struct::{NodeUrl, PortSet}; + +time_serde::format_description!(rfc3339_ms_z, OffsetDateTime, "[year]-[month]-[day]T[hour]:[minute]:[second].[subsecond digits:6]Z"); + + +#[derive(Serialize, Deserialize, Debug)] +pub struct ClientTokenRequest { + pub jti: Uuid, + pub iss: String, + pub aud: String, + #[serde(with = "time::serde::timestamp")] + pub iat: OffsetDateTime, + #[serde(with = "time::serde::timestamp")] + pub nbf: OffsetDateTime, + #[serde(with = "time::serde::timestamp")] + pub exp: OffsetDateTime, + // TODO should come from UI as param + pub update_mode: String, + pub scope_ref_list: Vec, + pub fulfillment_class_ref_list: Option>, + pub service_instance_configuration: ServiceInstanceConfiguration, + pub service_instance_public_key_configuration: ServiceInstancePublicKeyConfiguration, + +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct ServiceInstanceConfiguration { + pub nls_service_instance_ref: Uuid, + pub svc_port_set_list: Vec, + pub node_url_list: Vec, +} + + +#[derive(Serialize, Deserialize, Debug)] +pub struct ServiceInstancePublicKeyConfiguration { + pub service_instance_public_key_me: ServiceInstancePublicKeyMe, + pub service_instance_public_key_pem: String, + pub key_retention_mode: String, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct ServiceInstancePublicKeyMe { + #[serde(rename = "mod")] + pub type_mod: String, + pub exp: u32, +} \ No newline at end of file diff --git a/src/core_struct/code.rs b/src/core_struct/code.rs new file mode 100644 index 0000000..1505e62 --- /dev/null +++ b/src/core_struct/code.rs @@ -0,0 +1,37 @@ +use uuid::Uuid; +use serde::{Serialize, Deserialize}; +use time::OffsetDateTime; +use time::serde as time_serde; + +use crate::core_struct::LicenseProviderPrompt; + + +time_serde::format_description!(rfc3339_ms_z, OffsetDateTime, "[year]-[month]-[day]T[hour]:[minute]:[second].[subsecond digits:6]Z"); + + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct CodeRequest { + pub code_challenge: String, + pub origin_ref: Uuid, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct CodeResponse { + // jwt + pub auth_code: String, + #[serde(with = "rfc3339_ms_z")] + pub sync_timestamp: OffsetDateTime, + pub prompts: Option>, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct AcData { + #[serde(with = "time::serde::timestamp")] + pub iat: OffsetDateTime, + #[serde(with = "time::serde::timestamp")] + pub exp: OffsetDateTime, + pub challenge: String, + pub origin_ref: Uuid, + pub key_ref: Uuid, + pub kid: Uuid, +} diff --git a/src/core_struct/leases.rs b/src/core_struct/leases.rs new file mode 100644 index 0000000..d585f64 --- /dev/null +++ b/src/core_struct/leases.rs @@ -0,0 +1,93 @@ +use uuid::Uuid; +use serde::{Serialize, Deserialize}; +use time::OffsetDateTime; +use time::serde as time_serde; + +use crate::core_struct::LicenseProviderPrompt; + + +time_serde::format_description!(rfc3339_ms_z, OffsetDateTime, "[year]-[month]-[day]T[hour]:[minute]:[second].[subsecond digits:6]Z"); +time_serde::format_description!(rfc3339_ms, OffsetDateTime, "[year]-[month]-[day]T[hour]:[minute]:[second].[subsecond digits:6]"); + + +#[derive(Serialize, Deserialize, Debug)] +pub struct ClientLeasesResponse { + pub active_lease_list: Vec, + pub prompts: Option>, + #[serde(with = "rfc3339_ms_z")] + pub sync_timestamp: OffsetDateTime, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct ClientLeasesErrorResponse { + pub detail: String, + pub status: u32, + pub title: String, + #[serde(rename = "type")] + pub error_type: String, +} + + +#[derive(Serialize, Deserialize, Debug)] +pub struct AddLessorResponse { + pub lease_result_list: Vec, + pub prompts: Option>, + // one of "SUCCESS", "FULFILLMENT_FAILURE", "INVALID_LEASE_PROPOSAL", "UNKNOWN_ACCESS_GROUP", "INFRASTRUCTURE_FAILURE", or None -> SUCCESS + pub result_code: Option, + #[serde(with = "rfc3339_ms_z")] + pub sync_timestamp: OffsetDateTime, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct CreateLeaseResult { + pub error: Option, + pub lease: LeaseCreateDetail, + pub ordinal: Option, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct LeaseCreateDetail { + #[serde(rename = "ref")] + pub type_ref: Uuid, + #[serde(with = "rfc3339_ms")] + pub created: OffsetDateTime, + #[serde(with = "rfc3339_ms")] + pub expires: OffsetDateTime, + pub recommended_lease_renewal: f32, + pub offline_lease: bool, + // default to CONCURRENT_COUNTED_SINGLE now, seem apply for all req + pub license_type: String, +} + + +#[derive(Serialize, Deserialize, Debug)] +pub struct UpdateLeasesResponse { + #[serde(with = "rfc3339_ms_z")] + pub expires: OffsetDateTime, + pub lease_ref: Uuid, + pub offline_lease: bool, + pub prompts: Option>, + pub recommended_lease_renewal: f32, + #[serde(with = "rfc3339_ms_z")] + pub sync_timestamp: OffsetDateTime, +} + + +#[derive(Serialize, Deserialize, Debug)] +pub struct UpdateLeasesErrorResponse { + pub message: String, + pub code: u16, + pub prompts: Option>, + #[serde(with = "rfc3339_ms_z")] + pub sync_timestamp: OffsetDateTime, +} + + +#[derive(Serialize, Deserialize, Debug)] +pub struct DeleteLeasesResponse { + pub release_failure_list: Option>, + pub released_lease_list: Vec, + pub prompts: Option>, + #[serde(with = "rfc3339_ms_z")] + pub sync_timestamp: OffsetDateTime, +} diff --git a/src/core_struct/mod.rs b/src/core_struct/mod.rs new file mode 100644 index 0000000..24d38f0 --- /dev/null +++ b/src/core_struct/mod.rs @@ -0,0 +1,76 @@ +pub mod origin; +pub mod code; +pub mod client_token; +pub mod token; +pub mod leases; + +use uuid::Uuid; +use serde::{Serialize, Deserialize}; +use time::OffsetDateTime; +use crate::utils::MyRsaKeyPair; + + +#[derive(Clone)] +pub struct AppConfigState { + pub req_port: u16, + pub req_host: String, + pub scope_ref_list: Vec, + pub nls_service_instance_ref: Uuid, + pub lease_time: u16, + pub lease_renewal_factor: f32, + pub rsa_client_token: MyRsaKeyPair, + pub rsa_server_jwt: MyRsaKeyPair, +} + +#[derive(Clone)] +pub struct RedisTaskConfig { + pub redis_url: String, + pub task_interval: u16, +} + + +#[derive(Serialize, Deserialize, Debug)] +pub struct PortSet { + pub idx: u8, + pub d_name: String, + pub svc_port_map: Vec, +} + + +#[derive(Serialize, Deserialize, Debug)] +pub struct PortMap { + pub service: String, + pub port: u16, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct NodeUrl { + pub idx: u8, + pub url: String, + pub url_qr: String, + pub svc_port_set_idx: u8, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct LicenseProviderPrompt { + // datetime + pub ts: String, + pub prompt_ref: String, + pub operation_type: String, +} + + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct JwtAuthToken { + #[serde(with = "time::serde::timestamp")] + pub iat: OffsetDateTime, + #[serde(with = "time::serde::timestamp")] + pub nbf: OffsetDateTime, + pub iss: String, + pub aud: String, + #[serde(with = "time::serde::timestamp")] + pub exp: OffsetDateTime, + pub origin_ref: Uuid, + pub key_ref: Uuid, + pub kid: Uuid, +} \ No newline at end of file diff --git a/src/core_struct/origin.rs b/src/core_struct/origin.rs new file mode 100644 index 0000000..be0a654 --- /dev/null +++ b/src/core_struct/origin.rs @@ -0,0 +1,43 @@ +use uuid::Uuid; +use serde::{Serialize, Deserialize}; +use time::OffsetDateTime; +use time::serde as time_serde; +use crate::core_struct::{LicenseProviderPrompt, NodeUrl, PortSet}; + +time_serde::format_description!(rfc3339_ms_z, OffsetDateTime, "[year]-[month]-[day]T[hour]:[minute]:[second].[subsecond digits:6]Z"); + +#[derive(Serialize, Deserialize, Debug)] +pub struct OriginRequest { + pub environment: EnvironmentData, + pub candidate_origin_ref: Uuid, + pub registration_pending: bool, + pub update_pending: bool, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct EnvironmentData { + pub fingerprint: FingerprintData, + pub guest_driver_version: String, + pub hostname: String, + pub os_platform: String, + pub os_version: String, + pub ip_address_list: Vec, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct FingerprintData { + pub mac_address_list: Vec, +} + + +#[derive(Serialize, Debug)] +pub struct OriginResponse { + pub origin_ref: Uuid, + pub environment: EnvironmentData, + pub svc_port_set_list: Option>, + pub node_url_list: Option>, + pub node_query_order: Option>, + pub prompts: Option>, + #[serde(with = "rfc3339_ms_z")] + pub sync_timestamp: OffsetDateTime, +} diff --git a/src/core_struct/token.rs b/src/core_struct/token.rs new file mode 100644 index 0000000..c635321 --- /dev/null +++ b/src/core_struct/token.rs @@ -0,0 +1,47 @@ +use serde::{Deserialize, Serialize}; +use time::OffsetDateTime; +use time::serde as time_serde; +use uuid::Uuid; +use crate::core_struct::LicenseProviderPrompt; + +time_serde::format_description!(rfc3339_ms_z, OffsetDateTime, "[year]-[month]-[day]T[hour]:[minute]:[second].[subsecond digits:6]Z"); + +#[derive(Serialize, Deserialize, Debug)] +pub struct TokenRequest { + pub auth_code: String, + pub code_verifier: String, +} + + +#[derive(Serialize, Deserialize, Debug)] +pub struct AuthCode { + #[serde(with = "time::serde::timestamp")] + pub iat: OffsetDateTime, + #[serde(with = "time::serde::timestamp")] + pub exp: OffsetDateTime, + pub challenge: String, + pub origin_ref: Uuid, + pub key_ref: Uuid, + pub kid: Uuid, +} + + +#[derive(Serialize, Deserialize, Debug)] +pub struct TokenResponse { + pub auth_token: String, + #[serde(with = "rfc3339_ms_z")] + pub expires: OffsetDateTime, + pub prompts: Option>, + #[serde(with = "rfc3339_ms_z")] + pub sync_timestamp: OffsetDateTime, +} + + +#[derive(Serialize, Deserialize, Debug)] +pub struct TokenErrorResponse { + pub code: u16, + pub message: String, + pub prompts: Option>, + #[serde(with = "rfc3339_ms_z")] + pub sync_timestamp: OffsetDateTime, +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..905caae --- /dev/null +++ b/src/main.rs @@ -0,0 +1,220 @@ +mod utils; +mod cert_tools; +mod core_struct; +mod api; + +use std::net::SocketAddr; +use std::sync::{ + atomic::{AtomicBool, Ordering}, + Arc, +}; +use actix_web::{get, web, App, Error, HttpServer, Responder, HttpResponse, middleware, dev::ServiceRequest, HttpMessage}; + +use actix_web_httpauth::{ + extractors::bearer::BearerAuth, + middleware::HttpAuthentication, +}; + +use rustls::{Certificate, PrivateKey, ServerConfig}; +use time::OffsetDateTime; + +use crate::utils::{load_config, prepare_redis}; +use crate::core_struct::{AppConfigState, JwtAuthToken, RedisTaskConfig}; +use crate::api::{add_lessor, auth_token, code_req, delete_all_leases, gen_client_token, get_all_leases, origin_req, update_lessor}; +use crate::core_struct::leases::ClientLeasesErrorResponse; + + +#[get("/")] +async fn hello() -> impl Responder { + HttpResponse::Ok().body("Hello world!") +} + + +// todo impl new type for json error +async fn leases_validator(req: ServiceRequest, credentials: BearerAuth) -> Result { + let config_state = req.app_data::>().cloned().expect("Server Error"); + + // decode jwt + let client_auth_token = match jsonwebtoken::decode::( + &credentials.token(), + &jsonwebtoken::DecodingKey::from_rsa_pem(&config_state.rsa_server_jwt.public_key).expect("Error read jwt decode key"), + &jsonwebtoken::Validation::new(jsonwebtoken::Algorithm::RS256), + ) { + Ok(token_data) => token_data, + Err(jwt_error) => { + let error_resp = ClientLeasesErrorResponse { + detail: jwt_error.to_string(), + status: 401, + title: "Unauthorized".to_string(), + error_type: "about:blank".to_string(), + }; + let new_error = actix_web::error::ErrorUnauthorized(serde_json::to_string_pretty(&error_resp).unwrap()); + return Err((new_error, req)); + } + }; + req.extensions_mut().insert(client_auth_token.claims); + Ok(req) +} + + +async fn async_clean_lease(task_config: RedisTaskConfig, shutdown_marker: Arc) -> std::io::Result<()> { + let job_interval = i64::from(task_config.task_interval) * 60; + let start_time = OffsetDateTime::now_utc(); + + loop { + if shutdown_marker.load(Ordering::SeqCst) { + log::info!("RedisTask Stop."); + break; + } + + tokio::time::sleep(tokio::time::Duration::from_secs(3)).await; + if ((OffsetDateTime::now_utc() - start_time).whole_seconds() % job_interval) != 0 { + continue + } + + let _ = match redis::Client::open(task_config.redis_url.clone().as_str()) { + Ok(redis_client) => { + let _ = match redis_client.get_async_connection().await { + Ok(mut redis_connection) => { + let _ = match redis::cmd("keys").arg(&["*"]).query_async::<_, Vec>(&mut redis_connection).await { + Ok(ref_list) => { + let time_now = OffsetDateTime::now_utc(); + for ref_id in ref_list { + let _ = match redis::cmd("ZREMRANGEBYSCORE") + .arg(&[ + ref_id.as_str(), + "0", + time_now.unix_timestamp().to_string().as_str() + ]) + .query_async::<_, i32>(&mut redis_connection) + .await { + Ok(redis_status) => { + if redis_status != 0 { + log::info!("RedisTask: ref: {} clean with {} leases.", &ref_id, &redis_status); + } + } + Err(redis_err) => { + log::debug!("RedisTask: cannot remove ref: {}, Cause: {}", &ref_id, redis_err); + } + }; + } + } + Err(redis_err) => { + log::debug!("RedisTask: Cannot get keys! Cause: {}", redis_err); + } + }; + } + Err(_) => { + log::debug!("RedisTask: Cannot open redis connection!") + } + }; + } + Err(_) => { + log::debug!("RedisTask: Cannot open redis client!") + } + }; + log::debug!("RedisTask cleanup done."); + } + Ok(()) +} + +#[actix_web::main] +async fn main() -> std::io::Result<()> { + // log setting + env_logger::init_from_env(env_logger::Env::default().default_filter_or("debug")); + + // startup check + let config_data = load_config(); + let redis_client = web::Data::new(prepare_redis(config_data.redis_url.clone()).await); + let task_config = RedisTaskConfig { + redis_url: config_data.redis_url.clone(), + task_interval: config_data.redis_task_interval.clone(), + }; + + let shared_data = web::Data::new(AppConfigState { + req_host: config_data.req_host.clone(), + req_port: config_data.req_port.clone(), + scope_ref_list: config_data.scope_ref_list, + nls_service_instance_ref: config_data.nls_service_instance_ref, + lease_time: config_data.lease_time, + lease_renewal_factor: config_data.lease_renewal_factor, + rsa_client_token: config_data.rsa_client_token, + rsa_server_jwt: config_data.rsa_server_jwt, + }); + + + // tls content + let public_key_der = pem::parse(&config_data.cert_https.public_key).unwrap().contents; + let private_key_der = pem::parse(&config_data.cert_https.private_key).unwrap().contents; + + let public_key = vec![Certificate(public_key_der)]; + let private_key = PrivateKey(private_key_der); + + // configure certificate and private key used by https + let tls_config = ServerConfig::builder() + .with_safe_defaults() + .with_no_client_auth() + .with_single_cert(public_key, private_key) + .unwrap(); + + + // paste server addr and port + let bind_addr: SocketAddr = match format!("{}:{}", &config_data.server_addr, &config_data.server_port).parse() { + Ok(addr) => { + log::info!("starting HTTPS server at https://{}", addr); + addr + } + _ => { + log::error!("Error read bind address and port!"); + std::process::exit(1); + } + }; + + let server = HttpServer::new(move || { + let leases_auth = HttpAuthentication::bearer(leases_validator); + let leasing_scope = web::scope("/leasing") + .service(get_all_leases) + .service(add_lessor) + .service(update_lessor) + .service(delete_all_leases) + .wrap(leases_auth); + + App::new() + .wrap(middleware::Logger::default()) + .service(hello) + .service(gen_client_token) + .service(origin_req) + .service(code_req) + .service(auth_token) + .service(leasing_scope) + .app_data(shared_data.clone()) + .app_data(redis_client.clone()) + }) + .keep_alive(std::time::Duration::from_secs(5)) + .bind_rustls(bind_addr, tls_config)? + .workers(2) + .run(); + + let server_handle = server.handle(); + let task_shutdown_marker = Arc::new(AtomicBool::new(false)); + + // create my task + let server_task = tokio::spawn(server); + let worker_task = tokio::spawn(async_clean_lease(task_config, Arc::clone(&task_shutdown_marker))); + + let shutdown = tokio::spawn(async move { + // listen for ctrl-c + tokio::signal::ctrl_c().await.unwrap(); + + // start shutdown of tasks + let server_stop = server_handle.stop(true); + task_shutdown_marker.store(true, Ordering::SeqCst); + + // await shutdown of tasks + server_stop.await; + }); + + let _ = tokio::try_join!(server_task, worker_task, shutdown).expect("unable to join tasks"); + + Ok(()) +} diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..c27640b --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,251 @@ +use std::fs::OpenOptions; +use std::io::{Seek, Write}; +use std::path::Path; +use uuid::Uuid; +use serde::{Deserialize, Serialize}; +use obfstr::obfstr; +use crate::cert_tools::{gen_cert_rsa2048, gen_rsa2048}; + + +#[derive(Clone)] +pub struct MyRsaKeyPair { + pub public_key: Vec, + pub private_key: Vec, +} + +pub struct ConfigObj { + pub server_addr: String, + pub server_port: u16, + pub domain: String, + pub req_host: String, + pub req_port: u16, + pub redis_url: String, + pub redis_task_interval: u16, + pub scope_ref_list: Vec, + pub nls_service_instance_ref: Uuid, + pub lease_time: u16, + pub lease_renewal_factor: f32, + pub cert_https: MyRsaKeyPair, + pub rsa_client_token: MyRsaKeyPair, + pub rsa_server_jwt: MyRsaKeyPair, +} + + +#[derive(Serialize, Deserialize, Debug)] +struct KeyPairPath { + public_key: String, + private_key: String, +} + + +#[derive(Serialize, Deserialize, Debug)] +struct ConfigData { + server_addr: String, + server_port: u16, + domain: String, + req_host: String, + req_port: u16, + redis_url: String, + redis_task_interval: u16, + scope_ref_list: Vec, + nls_service_instance_ref: Uuid, + lease_time: u16, + lease_renewal_factor: u8, + cert_https: KeyPairPath, + rsa_client_token: KeyPairPath, +} + + +fn read_keypair(kp_path: &KeyPairPath, domain: Option) -> MyRsaKeyPair { + let public_key_path = Path::new(&kp_path.public_key); + let private_key_path = Path::new(&kp_path.private_key); + + if (public_key_path.exists()) && (private_key_path.exists()) { + MyRsaKeyPair { + public_key: std::fs::read(&public_key_path).expect("failed to read key"), + private_key: std::fs::read(&private_key_path).expect("failed to read key"), + } + } else { + let gen_keypair; + match domain { + Some(domain) => { + gen_keypair = gen_cert_rsa2048(domain); + } + None => { + gen_keypair = gen_rsa2048(); + } + } + + let mut public_key_file = OpenOptions::new() + .read(true) + .write(true) + .create(true) + .open(&public_key_path).expect("Unable to open public key file"); + public_key_file.write(&gen_keypair.public_key).expect("Unable to write public key file"); + + let mut private_key_file = OpenOptions::new() + .read(true) + .write(true) + .create(true) + .open(&private_key_path).expect("Unable to open private key file"); + private_key_file.write(&gen_keypair.private_key).expect("Unable to write private key file"); + gen_keypair + } +} + + +pub fn load_config() -> ConfigObj { + let data_path = Path::new(".").join("data"); + let config_path = &data_path.join("config.json"); + if !&data_path.exists() { + match std::fs::create_dir(&data_path) { + Ok(_) => {} + Err(_) => { + eprintln!("Failed to make data dir!"); + std::process::exit(1); + } + }; + } + + + let config_data: ConfigData = match OpenOptions::new() + .read(true) + .write(true) + .append(false) + .create(true) + .open(&config_path) { + Ok(mut file_obj) => { + let inner_data: ConfigData = match serde_json::from_reader(&file_obj) { + Ok(json_data) => json_data, + Err(deserialize_error) => { + log::error!("Failed to parse config: {:?}", deserialize_error); + log::warn!("Using Default Setting."); + + let default_configs = ConfigData { + server_addr: "127.0.0.1".to_string(), + server_port: 443, + req_host: "127.0.0.1".to_string(), + req_port: 443, + domain: "localhost".to_string(), + redis_url: "redis://127.0.0.1/".to_string(), + redis_task_interval: 30, + scope_ref_list: vec![Uuid::new_v4(), Uuid::new_v4()], + nls_service_instance_ref: Uuid::new_v4(), + lease_time: 1440, + lease_renewal_factor: 35, + cert_https: KeyPairPath { + public_key: "./data/https_cert.pem".to_string(), + private_key: "./data/https_key.pem".to_string(), + }, + rsa_client_token: KeyPairPath { + public_key: "./data/token_cert.pem".to_string(), + private_key: "./data/token_key.pem".to_string(), + }, + }; + // set write to start and remove nul + let _ = &file_obj.set_len(0); + let _ = file_obj.rewind().unwrap(); + match serde_json::to_writer_pretty(&file_obj, &default_configs) { + Ok(_) => { + log::warn!("Saved default config data.") + } + Err(_) => { + log::error!("Failed to save config data!") + } + }; + default_configs + } + }; + inner_data + } + Err(file_error) => { + log::error!("Failed to open config file: {:?}", file_error); + std::process::exit(1); + } + }; + + if config_data.lease_renewal_factor > 100 { + log::error!("Config: failed to get lease_renewal_factor, value must be between 1 and 100!"); + std::process::exit(1); + } + + + obfstr! { + let pub_key = "-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqd6EjBnZ68/Al/hQxCmz +5qW3eMXulTFYJb2WopgepjZCDvc2q/57qoekgVQEy9OwhXoXF8VnnTaoUaN7YZWA +r/woQ0Zkwe10FcWbT3Pju/DznqscmZPbSoru+SnUrxqZmzWeOo0q6l0w28tBZ2HC ++9ie95WHCfst/jVwZ+slsRAy7Uv5CwXeqIXubFhGwPV7+ICB2tmJiQPJcM+Y2tTK +FeaDyN9yKaUUjdjG80CGIKUnPdNCPEo/Cpf727rOCLl67kOd4mPmTrvyD0/nmREx +CQUSZt1smMFHR+uA11oN12I0yIy322gozwAyjd2r9Fok133/0EVTQqZ+ZmBExfor +3QIDAQAB +-----END PUBLIC KEY-----"; + let priv_key = "-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAqd6EjBnZ68/Al/hQxCmz5qW3eMXulTFYJb2WopgepjZCDvc2 +q/57qoekgVQEy9OwhXoXF8VnnTaoUaN7YZWAr/woQ0Zkwe10FcWbT3Pju/Dznqsc +mZPbSoru+SnUrxqZmzWeOo0q6l0w28tBZ2HC+9ie95WHCfst/jVwZ+slsRAy7Uv5 +CwXeqIXubFhGwPV7+ICB2tmJiQPJcM+Y2tTKFeaDyN9yKaUUjdjG80CGIKUnPdNC +PEo/Cpf727rOCLl67kOd4mPmTrvyD0/nmRExCQUSZt1smMFHR+uA11oN12I0yIy3 +22gozwAyjd2r9Fok133/0EVTQqZ+ZmBExfor3QIDAQABAoIBAGEY7WD74eH15du4 +N8p5H/kmHoKteRvUkdM41KLqGxLdDtNpIdocY+ntEO5P7VHpFgyl5g9Tak+mD35i +2ULFZ0Kw+v7BfRSQu3s6cfVvg+xI5ah7nKR4rK+mTMUl0QmqRcU/V8uWJ8LBNA1e +2GrUqdS1VOCmmwLsjbSyLSdpdSkI72pZYdP4FwF4MVfWu4gFrVf/vSxjy0l5wY/1 +iCma0sjzS8npFP4Wf58PeBqbYUMJ/bCwPF+UYkx2xaRlAWWWtJsMdCQE4NBHqa1w +ZfHC5Y7oLjdYi0EDQeinqjnDIcKD/dedtDvrK5N3yL9D3VxiE0J2irzk9tNXvezf +S6lIqC0CgYEA333pptjB5DAZ+HihtziWSOvYPd3Ibz5BhUFqKJy9TjQh/IC7sVix +4ieKl4uLPWvURPZeWWJi56ncWQSwMLjTsVyIt49XKCzznLdHnHijb4kGHg+ycGpu +kT4pbjm+Dxts/ZifQHVlzmnRuBHb2S/s7Gk1XTn6AbCSZIUUPuLQ7pMCgYEAwpPg +t6Qto5M8cKG20x0SyBpkge3SJTXm4aahm+cQUAf3ylVX6MIqSTF6zwAjlP7mL8a8 +ePFMHqwYZ2KRq/rrPwljmNHBMIx7Weh789S5q4meoa6yT2maQuA+7vRAmLqXwuLK +gz51mfAqFTbhGxLh2RpRicOK7CfC+byT3OF4kc8CgYAodGtR91SJkKdy0as8NjMF ++iMHd9jrQhKsI14rAcxGlqs8QLU48fwpGs08h1bqBFXFMe98MJIEqzumpXGbMCmp +pj1dNMYrEI/8YzTEPxYef2grEt5S+QEQq3bma+9aXrWI5hKVoWqPRZpfvmPUWZeC +Z7zwJil6GtM0/N3gUEBPnwKBgQCZeyoD0VZKtAY11emvhzxcaS0kq+JahbUUA2tw +3YepiU9043LPX/EZARWdGL/4dERAJWRfhf6EJz2stzyuyuMrOw276qCX2ggmuFKl +2AOJAqoFYRa3u1X6MIaT2Ejn8C9rg5c4hVkgTyfyyfIwd+l8Zd0xbPQ1KXwLoCuG +TLfdUwKBgHboiqjd22q6y753MUOFxr4TVHSOwYNTnzFjKyyjRZYXXz7r3e/xbVuW +Msgzaul+8rF3E83ZbR9u3Z2IURQZHKgA1e9rBMSf0dDnQ677oW/UubyoSHGwRuEV +BdLF6msAUzkXM1R1zS9Pk/5AVO54fj/HxYnsv+THMw8FvqGUMAz+ +-----END RSA PRIVATE KEY-----"; + } + + let config_return = ConfigObj { + server_addr: config_data.server_addr.clone(), + server_port: config_data.server_port.clone(), + domain: config_data.domain.clone(), + req_host: config_data.req_host.clone(), + req_port: config_data.req_port.clone(), + redis_url: config_data.redis_url.clone(), + redis_task_interval: config_data.redis_task_interval.clone(), + scope_ref_list: config_data.scope_ref_list.clone(), + nls_service_instance_ref: config_data.nls_service_instance_ref.clone(), + lease_time: config_data.lease_time.clone(), + lease_renewal_factor: f32::from(config_data.lease_renewal_factor.clone()) / 100.0, + cert_https: read_keypair(&config_data.cert_https, Option::from(config_data.domain.clone())), + rsa_client_token: read_keypair(&config_data.rsa_client_token, None), + rsa_server_jwt: MyRsaKeyPair { + public_key: pub_key.as_bytes().to_vec(), + private_key: priv_key.as_bytes().to_vec(), + }, + }; + config_return +} + +pub async fn prepare_redis(connection_url: String) -> redis::Client { + match redis::Client::open(connection_url) { + Ok(redis_client) => { + let _ = match redis_client.get_async_connection().await { + Ok(conn)=> conn, + Err(connection_error) =>{ + log::error!("Failed to get redis connection! Cause: {}", connection_error); + std::process::exit(1); + } + }; + redis_client + }, + Err(client_err) => { + log::error!("Failed to open redis client! Cause: {}", client_err); + std::process::exit(1); + } + } +}