diff --git a/.gitignore b/.gitignore index a202137..57ae07f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,4 @@ config.json pending.json -nftables.conf -interfaces.conf -go.work -nfsense -nfsense.exe -out/* -out \ No newline at end of file +/target + diff --git a/.vscode/settings.json b/.vscode/settings.json index 86e78e0..1ddd901 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,5 +3,9 @@ "editor.formatOnSave": false, "editor.codeActionsOnSave": { "source.fixAll.eslint": true + }, + "[rust]": { + "editor.defaultFormatter": "rust-lang.rust-analyzer", + "editor.formatOnSave": true } } \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..16b72f9 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1638 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + +[[package]] +name = "async-trait" +version = "0.1.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "axum" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" +dependencies = [ + "async-trait", + "axum-core", + "bitflags 1.3.2", + "bytes", + "futures-util", + "http", + "http-body", + "hyper", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http", + "http-body", + "mime", + "rustversion", + "tower-layer", + "tower-service", +] + +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "beef" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "blowfish" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32fa6a061124e37baba002e496d203e23ba3d7b73750be82dbfbc92913048a5b" +dependencies = [ + "byteorder", + "cipher", + "opaque-debug", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cipher" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" +dependencies = [ + "generic-array", +] + +[[package]] +name = "cookie" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7efb37c3e1ccb1ff97164ad95ac1606e8ccd35b3fa0a7d99a304c7f4a428cc24" +dependencies = [ + "percent-encoding", + "time", + "version_check", +] + +[[package]] +name = "cpufeatures" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fbc60abd742b35f2492f808e1abbb83d45f72db402e14c55057edc9c7b1e9e4" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-mac" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff07008ec701e8028e2ceb8f83f0e4274ee62bd2dbdc4fefff2e9a91824081a" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "custom_error" +version = "1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f8a51dd197fa6ba5b4dc98a990a43cc13693c23eb0089ebb0fcc1f04152bca6" + +[[package]] +name = "deranged" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[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.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" + +[[package]] +name = "futures-io" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" + +[[package]] +name = "futures-macro" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "futures-sink" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" + +[[package]] +name = "futures-task" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" + +[[package]] +name = "futures-util" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +dependencies = [ + "futures-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.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" + +[[package]] +name = "h2" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" +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.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" + +[[package]] +name = "hmac" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15" +dependencies = [ + "crypto-mac", + "digest", +] + +[[package]] +name = "http" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "http-range-header" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" + +[[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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.4.10", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "if_chain" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "ipnet" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +dependencies = [ + "serde", +] + +[[package]] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + +[[package]] +name = "jsonrpsee" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "affdc52f7596ccb2d7645231fc6163bb314630c989b64998f3699a28b4d5d4dc" +dependencies = [ + "jsonrpsee-core", + "jsonrpsee-server", + "jsonrpsee-types", + "tokio", +] + +[[package]] +name = "jsonrpsee-core" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da2327ba8df2fdbd5e897e2b5ed25ce7f299d345b9736b6828814c3dbd1fd47b" +dependencies = [ + "anyhow", + "async-trait", + "beef", + "futures-util", + "hyper", + "jsonrpsee-types", + "parking_lot", + "rand", + "rustc-hash", + "serde", + "serde_json", + "soketto", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "jsonrpsee-server" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82c39a00449c9ef3f50b84fc00fc4acba20ef8f559f07902244abf4c15c5ab9c" +dependencies = [ + "futures-util", + "http", + "hyper", + "jsonrpsee-core", + "jsonrpsee-types", + "route-recognizer", + "serde", + "serde_json", + "soketto", + "thiserror", + "tokio", + "tokio-stream", + "tokio-util", + "tower", + "tracing", +] + +[[package]] +name = "jsonrpsee-types" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be0be325642e850ed0bdff426674d2e66b2b7117c9be23a7caef68a2902b7d9" +dependencies = [ + "anyhow", + "beef", + "serde", + "serde_json", + "thiserror", + "tracing", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "macaddr" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baee0bbc17ce759db233beb01648088061bf678383130602a298e6998eedb2d8" +dependencies = [ + "serde", +] + +[[package]] +name = "matches" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" + +[[package]] +name = "matchit" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + +[[package]] +name = "md-5" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5a279bb9607f9f53c22d496eade00d138d1bdcccd07d74650387cf94942a15" +dependencies = [ + "block-buffer", + "digest", + "opaque-debug", +] + +[[package]] +name = "memchr" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +dependencies = [ + "libc", + "wasi", + "windows-sys", +] + +[[package]] +name = "nfsense" +version = "0.1.0" +dependencies = [ + "async-trait", + "axum", + "custom_error", + "ipnet", + "jsonrpsee", + "macaddr", + "pwhash", + "serde", + "serde_json", + "thiserror", + "tokio", + "tower-cookies", + "tower-http", + "tracing", + "tracing-subscriber", + "uuid", + "validator", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[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.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + +[[package]] +name = "percent-encoding" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" + +[[package]] +name = "pin-project" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "pwhash" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "419a3ad8fa9f9d445e69d9b185a24878ae6e6f55c96e4512f4a0e28cd3bc5c56" +dependencies = [ + "blowfish", + "byteorder", + "hmac", + "md-5", + "rand", + "sha-1", + "sha2", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "regex" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "route-recognizer" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afab94fb28594581f62d981211a9a4d53cc8130bbcbbb89a0440d9b8e81a7746" + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + +[[package]] +name = "ryu" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "serde" +version = "1.0.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "serde_json" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4beec8bce849d58d06238cb50db2e1c417cfeafa4c63f692b15c82b7c80f8335" +dependencies = [ + "itoa", + "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 = "sha-1" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" +dependencies = [ + "block-buffer", + "cfg-if", + "cpufeatures", + "digest", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer", + "cfg-if", + "cpufeatures", + "digest", + "opaque-debug", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" + +[[package]] +name = "socket2" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "socket2" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "soketto" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d1c5305e39e09653383c2c7244f2f78b3bcae37cf50c64cb4789c9f5096ec2" +dependencies = [ + "base64", + "bytes", + "futures", + "http", + "httparse", + "log", + "rand", + "sha-1", +] + +[[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.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "thiserror" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "thread_local" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "time" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" +dependencies = [ + "deranged", + "itoa", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" +dependencies = [ + "time-core", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2 0.5.5", + "tokio-macros", + "windows-sys", +] + +[[package]] +name = "tokio-macros" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "tokio-stream" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +dependencies = [ + "bytes", + "futures-core", + "futures-io", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-cookies" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40f38d941a2ffd8402b36e02ae407637a9caceb693aaf2edc910437db0f36984" +dependencies = [ + "async-trait", + "axum-core", + "cookie", + "futures-util", + "http", + "parking_lot", + "pin-project-lite", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" +dependencies = [ + "bitflags 2.4.1", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-range-header", + "pin-project-lite", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +dependencies = [ + "lazy_static", + "log", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" +dependencies = [ + "nu-ansi-term", + "sharded-slab", + "smallvec", + "thread_local", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "try-lock" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "url" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +dependencies = [ + "form_urlencoded", + "idna 0.4.0", + "percent-encoding", +] + +[[package]] +name = "uuid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc" +dependencies = [ + "getrandom", +] + +[[package]] +name = "validator" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f07b0a1390e01c0fc35ebb26b28ced33c9a3808f7f9fbe94d3cc01e233bfeed5" +dependencies = [ + "idna 0.2.3", + "lazy_static", + "regex", + "serde", + "serde_derive", + "serde_json", + "url", + "validator_derive", +] + +[[package]] +name = "validator_derive" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea7ed5e8cf2b6bdd64a6c4ce851da25388a89327b17b88424ceced6bd5017923" +dependencies = [ + "if_chain", + "lazy_static", + "proc-macro-error", + "proc-macro2", + "quote", + "regex", + "syn 1.0.109", + "validator_types", +] + +[[package]] +name = "validator_types" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2ddf34293296847abfc1493b15c6e2f5d3cd19f57ad7d22673bf4c6278da329" +dependencies = [ + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +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.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..43ca43e --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "nfsense" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +async-trait = "0.1.74" +axum = "0.6.20" +custom_error = "1.9.2" +ipnet = { version = "2.8.0", features = ["serde"] } +jsonrpsee = { version = "0.20.3", features = ["server"] } +macaddr = { version = "1.0.1", features = ["serde"] } +pwhash = "1.0.0" +serde = { version = "1.0.189", features = ["derive"] } +serde_json = "1.0.107" +thiserror = "1.0.50" +tokio = { version = "1.33.0", features = ["full"] } +tower-cookies = "0.9.0" +tower-http = "0.4.4" +tracing = "0.1.40" +tracing-subscriber = "0.3.17" +uuid = { version = "1.5.0", features = ["v4"] } +validator = { version = "0.15", features = ["derive"] } diff --git a/src/api/mod.rs b/src/api/mod.rs new file mode 100644 index 0000000..585ab03 --- /dev/null +++ b/src/api/mod.rs @@ -0,0 +1,48 @@ +mod network; +mod system; + +use crate::state::RpcState; +use jsonrpsee::{ + types::{error::ErrorCode, ErrorObject}, + RpcModule, +}; + +use custom_error::custom_error; +use tracing::info; + +custom_error! { pub ApiError + InvalidParams = "Invalid Parameters", + Leet = "1337", +} + +impl Into> for ApiError { + fn into(self) -> ErrorObject<'static> { + match self { + Self::InvalidParams => ErrorCode::InvalidParams, + Self::Leet => ErrorCode::ServerError(1337), + _ => ErrorCode::InternalError, + } + .into() + } +} + +pub fn new_rpc_module(state: RpcState) -> RpcModule { + let mut module = RpcModule::new(state); + + module + .register_method("ping", |_, _| { + info!("ping called"); + "pong" + }) + .unwrap(); + + module + .register_method("system.get_users", system::get_users) + .unwrap(); + + module + .register_method("network.get_static_routes", network::get_static_routes) + .unwrap(); + + module +} diff --git a/src/api/network.rs b/src/api/network.rs new file mode 100644 index 0000000..bf92118 --- /dev/null +++ b/src/api/network.rs @@ -0,0 +1,13 @@ +use jsonrpsee::types::Params; + +use crate::{definitions::network::StaticRoute, state::RpcState}; + +use super::ApiError; + +pub fn get_static_routes(_: Params, state: &RpcState) -> Result, ApiError> { + Ok(state + .config_manager + .get_pending_config() + .network + .static_routes) +} diff --git a/src/api/system.rs b/src/api/system.rs new file mode 100644 index 0000000..01ec35e --- /dev/null +++ b/src/api/system.rs @@ -0,0 +1,10 @@ +use std::collections::HashMap; + +use crate::{definitions::system::User, state::RpcState}; +use jsonrpsee::types::Params; + +use super::ApiError; + +pub fn get_users(_: Params, state: &RpcState) -> Result, ApiError> { + Ok(state.config_manager.get_pending_config().system.users) +} diff --git a/src/config_manager.rs b/src/config_manager.rs new file mode 100644 index 0000000..79c2db2 --- /dev/null +++ b/src/config_manager.rs @@ -0,0 +1,127 @@ +use validator::Validate; + +use super::definitions::config::Config; +use std::fs; +use std::sync::{Arc, Mutex, MutexGuard}; +use std::{io, result::Result}; + +use custom_error::custom_error; + +use pwhash::sha512_crypt; + +custom_error! { pub ConfigError + IoError{source: io::Error} = "io error", + SerdeError{source: serde_json::Error} = "serde json error", + ValidatonError{source: validator::ValidationErrors} = "validation failed", + HashError{source: pwhash::error::Error} = "password hash generation", + UnsupportedVersionError = "unsupported config version", +} + +pub const CURRENT_CONFIG_PATH: &str = "config.json"; +pub const PENDING_CONFIG_PATH: &str = "pending.json"; + +#[derive(Clone)] +pub struct ConfigManager { + shared_data: Arc>, +} + +struct SharedData { + current_config: Config, + pending_config: Config, +} + +// Note, using unwarp on a mutex lock is ok since that only errors with mutex poisoning + +impl ConfigManager { + pub fn new() -> Result { + Ok(Self { + shared_data: Arc::new(Mutex::new(SharedData { + current_config: read_file_to_config(CURRENT_CONFIG_PATH)?, + // TODO Dont Fail if pending config is missing, use current instead + pending_config: read_file_to_config(PENDING_CONFIG_PATH)?, + })), + }) + } + + pub fn get_current_config(&self) -> Config { + self.shared_data.lock().unwrap().current_config.clone() + } + + pub fn get_pending_config(&self) -> Config { + self.shared_data.lock().unwrap().pending_config.clone() + } + + pub fn apply_pending_changes(&mut self) -> Result<(), ConfigError> { + let mut data = self.shared_data.lock().unwrap(); + // TODO run Apply functions + // TODO Revert on Apply Failure and Return + write_config_to_file(CURRENT_CONFIG_PATH, data.pending_config.clone())?; + // TODO revert if config save fails + // TODO Remove Pending Config File + data.current_config = data.pending_config.clone(); + Ok(()) + } + + pub fn discard_pending_changes(&mut self) -> Result<(), ConfigError> { + let mut data = self.shared_data.lock().unwrap(); + // TODO Remove Pending Config File + + data.pending_config = data.current_config.clone(); + Ok(()) + } + + pub fn start_transaction(&mut self) -> Result { + let data = self.shared_data.lock().unwrap(); + + Ok(ConfigTransaction { + finished: false, + changes: data.pending_config.clone(), + shared_data: data, + }) + } +} + +pub struct ConfigTransaction<'a> { + finished: bool, + shared_data: MutexGuard<'a, SharedData>, + pub changes: Config, +} + +impl<'a> ConfigTransaction<'a> { + pub fn commit(mut self) -> Result<(), ConfigError> { + let ch = self.changes.clone(); + ch.validate()?; + self.shared_data.pending_config = ch.clone(); + write_config_to_file(PENDING_CONFIG_PATH, ch.clone())?; + Ok(()) + } +} + +fn read_file_to_config(path: &str) -> Result { + let data = fs::read_to_string(path)?; + let conf: Config = serde_json::from_str(&data)?; + if conf.config_version != 1 { + return Err(ConfigError::UnsupportedVersionError); + } + Ok(conf) +} + +fn write_config_to_file(path: &str, conf: Config) -> Result<(), ConfigError> { + let data: String = serde_json::to_string_pretty(&conf)?; + fs::write(path, data)?; + Ok(()) +} + +pub fn generate_default_config(path: &str) -> Result<(), ConfigError> { + let mut conf = Config::default(); + let hash = sha512_crypt::hash("nfsense")?; + conf.config_version = 1; + conf.system.users.insert( + "admin".to_string(), + crate::definitions::system::User { + comment: "Default Admin".to_string(), + hash: hash, + }, + ); + write_config_to_file(path, conf) +} diff --git a/src/definitions/config.rs b/src/definitions/config.rs new file mode 100644 index 0000000..0545196 --- /dev/null +++ b/src/definitions/config.rs @@ -0,0 +1,20 @@ +use serde::{Deserialize, Serialize}; +use validator::Validate; + +use super::firewall; +use super::network; +use super::object; +use super::service; +use super::system; +use super::vpn; + +#[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)] +pub struct Config { + pub config_version: u64, + pub network: network::Network, + pub object: object::Object, + pub system: system::System, + pub service: service::Service, + pub vpn: vpn::VPN, + pub firewall: firewall::Firewall, +} diff --git a/src/definitions/firewall.rs b/src/definitions/firewall.rs new file mode 100644 index 0000000..81b9b01 --- /dev/null +++ b/src/definitions/firewall.rs @@ -0,0 +1,61 @@ +use serde::{Deserialize, Serialize}; +use validator::Validate; + +#[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)] +pub struct Firewall { + pub forward_rules: Vec, + pub destination_nat_rules: Vec, + pub source_nat_rules: Vec, +} + +#[derive(Serialize, Deserialize, Clone, Validate, Debug)] +pub struct ForwardRule { + pub name: String, + pub services: Vec, + pub source_addresses: Vec, + pub destination_addresses: Vec, + pub comment: String, + pub counter: bool, + pub verdict: Verdict, +} + +#[derive(Serialize, Deserialize, Clone, Validate, Debug)] +pub struct DestinationNATRule { + pub name: String, + pub services: Vec, + pub source_addresses: Vec, + pub destination_addresses: Vec, + pub comment: String, + pub counter: bool, + pub dnat_address: String, + pub dnat_service: String, +} + +#[derive(Serialize, Deserialize, Clone, Validate, Debug)] +pub struct SourceNATRule { + pub name: String, + pub services: Vec, + pub source_addresses: Vec, + pub destination_addresses: Vec, + pub comment: String, + pub counter: bool, + pub snat_type: SNATType, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(rename_all = "snake_case")] +pub enum Verdict { + Accept, + Drop, + Continue, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(rename_all = "snake_case")] +pub enum SNATType { + SNAT { + snat_address: String, + snat_service: String, + }, + Masquerade, +} diff --git a/src/definitions/mod.rs b/src/definitions/mod.rs new file mode 100644 index 0000000..7909971 --- /dev/null +++ b/src/definitions/mod.rs @@ -0,0 +1,7 @@ +pub mod config; +pub mod firewall; +pub mod network; +pub mod object; +pub mod service; +pub mod system; +pub mod vpn; diff --git a/src/definitions/network.rs b/src/definitions/network.rs new file mode 100644 index 0000000..498b491 --- /dev/null +++ b/src/definitions/network.rs @@ -0,0 +1,44 @@ +use ipnet::IpNet; +use serde::{Deserialize, Serialize}; +use std::{collections::HashMap, net::IpAddr}; +use validator::Validate; + +#[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)] +pub struct Network { + pub interfaces: HashMap, + pub static_routes: Vec, +} + +#[derive(Serialize, Deserialize, Clone, Validate, Debug)] +pub struct NetworkInterface { + pub alias: String, + pub comment: String, + pub interface_type: NetworkInterfaceType, + pub addressing_mode: AddressingMode, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(rename_all = "snake_case")] +pub enum NetworkInterfaceType { + Hardware { device: String }, + Vlan { id: i32, parent: String }, + Bond { members: Vec }, + Bridge { members: Vec }, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(rename_all = "snake_case")] +pub enum AddressingMode { + None, + Static { address: String }, + DHCP, +} + +#[derive(Serialize, Deserialize, Clone, Validate, Debug)] +pub struct StaticRoute { + pub name: String, + pub interface: String, + pub gateway: IpAddr, + pub destination: IpNet, + pub metric: u64, +} diff --git a/src/definitions/object.rs b/src/definitions/object.rs new file mode 100644 index 0000000..59f7758 --- /dev/null +++ b/src/definitions/object.rs @@ -0,0 +1,54 @@ +use ipnet::IpNet; +use serde::{Deserialize, Serialize}; +use std::{collections::HashMap, net::IpAddr}; +use validator::Validate; + +#[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)] +pub struct Object { + pub addresses: HashMap, + pub services: HashMap, +} + +#[derive(Serialize, Deserialize, Clone, Validate, Debug)] +pub struct Address { + pub address_type: AddressType, + pub comment: String, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(rename_all = "snake_case")] +pub enum AddressType { + Host { host: String }, + Range { range: IpAddr }, + Network { network: IpNet }, + Group { children: Vec }, +} + +#[derive(Serialize, Deserialize, Clone, Validate, Debug)] +pub struct Service { + pub service_type: ServiceType, + pub comment: String, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(rename_all = "snake_case")] +pub enum ServiceType { + TCP { + source_port: u64, + source_port_end: Option, + destination_port: u64, + destination_port_end: Option, + }, + UDP { + source_port: u64, + source_port_end: Option, + destination_port: u64, + destination_port_end: Option, + }, + ICMP { + code: u8, + }, + Group { + children: Vec, + }, +} diff --git a/src/definitions/service.rs b/src/definitions/service.rs new file mode 100644 index 0000000..ea27f2f --- /dev/null +++ b/src/definitions/service.rs @@ -0,0 +1,67 @@ +use core::time; +use macaddr::MacAddr8; +use serde::{Deserialize, Serialize}; +use std::net::IpAddr; +use validator::Validate; + +#[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)] +pub struct Service { + pub dhcp_servers: Vec, + pub dns_servers: Vec, + pub ntp_servers: Vec, +} + +#[derive(Serialize, Deserialize, Clone, Validate, Debug)] +pub struct DHCPServer { + pub interface: String, + pub pool: Vec, + pub lease_time: time::Duration, + pub gateway_mode: GatewayMode, + pub dns_server_mode: DNSServerMode, + pub ntp_server_mode: NTPServerMode, + pub reservations: Vec, + pub comment: String, +} + +#[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)] +pub struct DNSServer { + pub interface: String, + pub comment: String, +} + +#[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)] +pub struct NTPServer { + pub interface: String, + pub comment: String, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(rename_all = "snake_case")] +pub enum GatewayMode { + None, + Interface, + Specify { gateway: String }, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(rename_all = "snake_case")] +pub enum DNSServerMode { + None, + Interface, + Specify { dns_servers: Vec }, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(rename_all = "snake_case")] +pub enum NTPServerMode { + None, + Interface, + Specify { ntp_servers: Vec }, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Reservation { + pub ip_address: IpAddr, + pub hardware_address: MacAddr8, + pub comment: String, +} diff --git a/src/definitions/system.rs b/src/definitions/system.rs new file mode 100644 index 0000000..48f01ff --- /dev/null +++ b/src/definitions/system.rs @@ -0,0 +1,14 @@ +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; +use validator::Validate; + +#[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)] +pub struct System { + pub users: HashMap, +} + +#[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)] +pub struct User { + pub comment: String, + pub hash: String, +} diff --git a/src/definitions/vpn.rs b/src/definitions/vpn.rs new file mode 100644 index 0000000..84104f7 --- /dev/null +++ b/src/definitions/vpn.rs @@ -0,0 +1,33 @@ +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; +use validator::Validate; + +#[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)] +pub struct VPN { + pub wireguard: Wireguard, +} + +#[derive(Serialize, Deserialize, Clone, Validate, Default, Debug)] +pub struct Wireguard { + pub interfaces: HashMap, + pub peers: HashMap, +} + +#[derive(Serialize, Deserialize, Clone, Validate, Debug)] +pub struct WireguardInterface { + pub public_key: String, + pub private_key: String, + pub listen_port: u64, + pub peers: Vec, + pub comment: String, +} + +#[derive(Serialize, Deserialize, Clone, Validate, Debug)] +pub struct WireguardPeer { + pub public_key: String, + pub preshared_key: Option, + pub allowed_ips: Vec, + pub endpoint: Option, + pub persistent_keepalive: Option, + pub comment: String, +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..9fda6f9 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,143 @@ +#![allow(dead_code)] + +use std::{ + collections::HashMap, + sync::{Arc, RwLock}, +}; + +use crate::state::RpcState; +use axum::{middleware, Router}; +use config_manager::ConfigManager; +use state::AppState; +use std::env; +use std::fs; +use tower_cookies::CookieManagerLayer; +use tracing::info; +use tracing_subscriber; +use web::auth::SessionState; + +mod api; +mod config_manager; +mod definitions; +mod state; +mod web; + +#[tokio::main] +async fn main() { + tracing_subscriber::fmt::init(); + info!("Starting..."); + + let args: Vec = env::args().collect(); + + if args.len() > 1 && args[1] == "generate-default" { + info!("Generating default config..."); + config_manager::generate_default_config(config_manager::CURRENT_CONFIG_PATH).unwrap(); + fs::copy( + config_manager::CURRENT_CONFIG_PATH, + config_manager::PENDING_CONFIG_PATH, + ) + .unwrap(); + info!("Done! Exiting..."); + return; + } + + // TODO Check Config Manager Setup Error + let config_manager = ConfigManager::new().unwrap(); + let session_state = SessionState { + sessions: Arc::new(RwLock::new(HashMap::new())), + }; + + let app_state = AppState { + config_manager: config_manager.clone(), + session_state: session_state.clone(), + rpc_module: api::new_rpc_module(RpcState { + config_manager, + session_state, + }), + }; + + // Note: The Router Works Bottom Up, So the auth middleware will only applies to everything above it. + let main_router = Router::new() + .merge(web::rpc::routes()) + .layer(middleware::from_fn_with_state( + app_state.clone(), + web::auth::mw_auth, + )) + .merge(web::auth::routes()) + .with_state(app_state) + .layer(CookieManagerLayer::new()); + // .fallback_service(service) + + info!("Server started successfully"); + axum::Server::bind(&"[::]:8080".parse().unwrap()) + .serve(main_router.into_make_service()) + .await + .unwrap(); + + /* + let mut tx = config_manager.start_transaction().unwrap(); + + tx.changes + .firewall + .forward_rules + .push(definitions::firewall::ForwardRule { + name: "name".to_string(), + comment: "test".to_string(), + counter: true, + verdict: definitions::firewall::Verdict::Accept, + services: Vec::new(), + destination_addresses: Vec::new(), + source_addresses: Vec::new(), + }); + + tx.commit().unwrap(); + + config_manager.apply_pending_changes().unwrap(); + + let mut tx2 = config_manager.start_transaction().unwrap(); + + tx2.changes.network.interfaces.insert( + "inter1".to_string(), + definitions::network::NetworkInterface { + alias: "test".to_owned(), + comment: "test comment".to_owned(), + interface_type: definitions::network::NetworkInterfaceType::Hardware { + device: "eth0".to_owned(), + }, + addressing_mode: definitions::network::AddressingMode::None, + }, + ); + + tx2.changes.network.interfaces.insert( + "inter2".to_string(), + definitions::network::NetworkInterface { + alias: "test2".to_owned(), + comment: "test comment".to_owned(), + interface_type: definitions::network::NetworkInterfaceType::Hardware { + device: "eth0".to_owned(), + }, + addressing_mode: definitions::network::AddressingMode::Static { + address: "192.168.1.1".to_owned(), + }, + }, + ); + + tx2.changes + .network + .static_routes + .push(definitions::network::StaticRoute { + name: "test1".to_string(), + interface: "eth0".to_string(), + gateway: "192.168.1.1".parse().unwrap(), + destination: "10.42.42.0/24".parse().unwrap(), + metric: 0, + }); + + tx2.commit().unwrap(); + + config_manager.apply_pending_changes().unwrap(); + + let applied_config = config_manager.get_current_config(); + info!("applied_config = {:#?}", applied_config); + */ +} diff --git a/src/state.rs b/src/state.rs new file mode 100644 index 0000000..fb63902 --- /dev/null +++ b/src/state.rs @@ -0,0 +1,17 @@ +use jsonrpsee::RpcModule; + +use super::config_manager::ConfigManager; +use super::web::auth::SessionState; + +#[derive(Clone)] +pub struct AppState { + pub config_manager: ConfigManager, + pub session_state: SessionState, + pub rpc_module: RpcModule, +} + +#[derive(Clone)] +pub struct RpcState { + pub config_manager: ConfigManager, + pub session_state: SessionState, +} diff --git a/src/web/auth.rs b/src/web/auth.rs new file mode 100644 index 0000000..526c1a2 --- /dev/null +++ b/src/web/auth.rs @@ -0,0 +1,153 @@ +use std::collections::HashMap; +use std::error::Error; +use std::hash::Hash; +use std::sync::{Arc, RwLock}; +use uuid::Uuid; + +use super::super::AppState; +use axum::routing::post; +use axum::{Json, Router}; +use serde::Deserialize; +use tower_cookies::{Cookie, Cookies}; + +use axum::{ + extract::Extension, + extract::State, + http::{Request, StatusCode}, + middleware::{self, Next}, + response::{IntoResponse, Response}, +}; + +use pwhash::sha512_crypt; +use tracing::info; + +use custom_error::custom_error; + +custom_error! { AuthError + NoSessionCookie = "No Session Cookie Found", + InvalidSession = "Invalid Session" +} + +const SESSION_COOKIE: &str = "session"; + +#[derive(Clone, Debug)] +pub struct SessionState { + pub sessions: Arc>>, +} + +#[derive(Clone, Debug)] +pub struct Session { + pub username: String, + //expires: time, + // TODO have permissions here for fast access, update Permissions with a config manager apply function + // permissions +} + +#[derive(Clone, Debug, Deserialize)] +struct LoginParameters { + username: String, + password: String, +} + +pub fn routes() -> Router { + Router::new() + .route("/login", post(login_handler)) + .route("/logout", post(logout_handler)) + .route("/session", post(session_handler)) +} + +async fn login_handler( + cookies: Cookies, + State(state): State, + Json(payload): Json, +) -> impl IntoResponse { + if let Some(user) = state + .config_manager + .get_current_config() + .system + .users + .get(&payload.username.to_string()) + { + if sha512_crypt::verify(payload.password, &user.hash) { + let mut sessions = state.session_state.sessions.write().unwrap(); + let id = Uuid::new_v4().to_string(); + + sessions.insert( + id.clone(), + Session { + username: payload.username.clone(), + }, + ); + + cookies.add(Cookie::new(SESSION_COOKIE, id)); + info!("user logged in: {:?}", payload.username); + return StatusCode::OK; + } + } + + info!("user login failed: {:?}", payload.username); + StatusCode::UNAUTHORIZED +} + +async fn logout_handler(cookies: Cookies, state: State) -> impl IntoResponse { + let session_cookie = cookies.get(SESSION_COOKIE); + match session_cookie { + Some(s) => { + let session_id = s.value(); + + let mut sessions = state.session_state.sessions.write().unwrap(); + + // TODO Fix Cookie remove + // cookies.remove(s.clone()); + + if let Some(session) = sessions.get(session_id) { + info!("user logged out: {:?}", session.username); + sessions.remove(session_id); + return StatusCode::OK; + } + return StatusCode::UNAUTHORIZED; + } + None => return StatusCode::UNAUTHORIZED, + } +} + +fn get_session(cookies: Cookies, state: SessionState) -> Result { + let session_cookie = cookies.get(SESSION_COOKIE); + match session_cookie { + Some(s) => { + let session_id = s.value(); + + let sessions = state.sessions.write().unwrap(); + + if let Some(session) = sessions.get(session_id) { + return Ok(session.clone()); + } + return Err(AuthError::InvalidSession); + } + None => return Err(AuthError::NoSessionCookie), + } +} + +async fn session_handler(cookies: Cookies, State(state): State) -> impl IntoResponse { + match get_session(cookies, state.session_state) { + // TODO Return build git commit hash as json result for frontend reloading + Ok(_) => return StatusCode::OK, + Err(_) => return StatusCode::UNAUTHORIZED, + } +} + +pub async fn mw_auth( + state: State, + cookies: Cookies, + mut req: Request, + next: Next, + // session_state: SessionState, +) -> Result { + match get_session(cookies, state.session_state.clone()) { + Ok(session) => { + req.extensions_mut().insert(session.clone()); + return Ok(next.run(req).await); + } + Err(_) => return Err(StatusCode::UNAUTHORIZED), + } +} diff --git a/src/web/mod.rs b/src/web/mod.rs new file mode 100644 index 0000000..6a60678 --- /dev/null +++ b/src/web/mod.rs @@ -0,0 +1,2 @@ +pub mod auth; +pub mod rpc; diff --git a/src/web/rpc.rs b/src/web/rpc.rs new file mode 100644 index 0000000..d980b98 --- /dev/null +++ b/src/web/rpc.rs @@ -0,0 +1,101 @@ +use crate::AppState; +use axum::routing::post; +use axum::{Json, Router}; +use jsonrpsee::core::traits::ToRpcParams; +use jsonrpsee::core::Error; +use serde::{Deserialize, Serialize}; +use serde_json::value::RawValue; + +use axum::{extract::Extension, extract::State, response::IntoResponse}; + +use tracing::info; + +// TODO fix this "workaround" +struct ParamConverter { + params: Option>, +} + +impl ToRpcParams for ParamConverter { + fn to_rpc_params(self) -> Result>, Error> { + let s = String::from_utf8(serde_json::to_vec(&self.params)?); + match s { + Ok(s) => { + return RawValue::from_string(s) + .map(Some) + .map_err(Error::ParseError) + } + // TODO make this a Parse error wrapping Utf8Error + Err(err) => return Err(Error::AlreadyStopped), + } + } +} + +#[derive(Deserialize)] +struct RpcRequest { + id: i64, + params: Option>, + jsonrpc: String, + method: String, +} + +#[derive(Clone, Deserialize, Serialize)] +struct RpcResponse { + id: i64, + jsonrpc: String, + #[serde(skip_serializing_if = "Option::is_none")] + result: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + error: Option, +} + +#[derive(Clone, Deserialize, Serialize)] + +struct RpcErrorObject { + code: i64, + message: String, + #[serde(skip_serializing_if = "Option::is_none")] + data: Option>, +} + +pub fn routes() -> Router { + Router::new().route("/api", post(api_handler)) +} + +async fn api_handler( + State(state): State, + session: Extension, + body: String, +) -> impl IntoResponse { + info!("api hit! user: {:?}", session.username); + + // TODO handle Parse Error + let req: RpcRequest = serde_json::from_str(&body).unwrap(); + + // TODO check version + + let params = ParamConverter { params: req.params }; + + // TODO check Permissions for method here? + + let res: Result>, Error> = + state.rpc_module.call(&req.method, params).await; + + match res { + Ok(res) => Json(RpcResponse { + id: req.id, + jsonrpc: req.jsonrpc, + result: res, + error: None, + }), + Err(err) => Json(RpcResponse { + id: req.id, + jsonrpc: req.jsonrpc, + result: None, + error: Some(RpcErrorObject { + code: 10, + message: err.to_string(), + data: None, + }), + }), + } +}