diff --git a/.gitignore b/.gitignore
index d0f40134..1fecf573 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@
docs/_build
man/*8
package/
+.tmp/
\ No newline at end of file
diff --git a/Cargo.lock b/Cargo.lock
index 84660d3f..a4ed1e64 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2,6 +2,189 @@
# It is not intended for manual editing.
version = 3
+[[package]]
+name = "actix-codec"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a"
+dependencies = [
+ "bitflags 2.6.0",
+ "bytes",
+ "futures-core",
+ "futures-sink",
+ "memchr",
+ "pin-project-lite",
+ "tokio",
+ "tokio-util",
+ "tracing",
+]
+
+[[package]]
+name = "actix-http"
+version = "3.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d48f96fc3003717aeb9856ca3d02a8c7de502667ad76eeacd830b48d2e91fac4"
+dependencies = [
+ "actix-codec",
+ "actix-rt",
+ "actix-service",
+ "actix-utils",
+ "ahash",
+ "base64",
+ "bitflags 2.6.0",
+ "brotli",
+ "bytes",
+ "bytestring",
+ "derive_more",
+ "encoding_rs",
+ "flate2",
+ "futures-core",
+ "h2 0.3.26",
+ "http 0.2.12",
+ "httparse",
+ "httpdate",
+ "itoa",
+ "language-tags",
+ "local-channel",
+ "mime",
+ "percent-encoding",
+ "pin-project-lite",
+ "rand",
+ "sha1",
+ "smallvec",
+ "tokio",
+ "tokio-util",
+ "tracing",
+ "zstd",
+]
+
+[[package]]
+name = "actix-macros"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb"
+dependencies = [
+ "quote",
+ "syn 2.0.87",
+]
+
+[[package]]
+name = "actix-router"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13d324164c51f63867b57e73ba5936ea151b8a41a1d23d1031eeb9f70d0236f8"
+dependencies = [
+ "bytestring",
+ "cfg-if",
+ "http 0.2.12",
+ "regex",
+ "regex-lite",
+ "serde",
+ "tracing",
+]
+
+[[package]]
+name = "actix-rt"
+version = "2.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24eda4e2a6e042aa4e55ac438a2ae052d3b5da0ecf83d7411e1a368946925208"
+dependencies = [
+ "futures-core",
+ "tokio",
+]
+
+[[package]]
+name = "actix-server"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ca2549781d8dd6d75c40cf6b6051260a2cc2f3c62343d761a969a0640646894"
+dependencies = [
+ "actix-rt",
+ "actix-service",
+ "actix-utils",
+ "futures-core",
+ "futures-util",
+ "mio",
+ "socket2",
+ "tokio",
+ "tracing",
+]
+
+[[package]]
+name = "actix-service"
+version = "2.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b894941f818cfdc7ccc4b9e60fa7e53b5042a2e8567270f9147d5591893373a"
+dependencies = [
+ "futures-core",
+ "paste",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "actix-utils"
+version = "3.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88a1dcdff1466e3c2488e1cb5c36a71822750ad43839937f85d2f4d9f8b705d8"
+dependencies = [
+ "local-waker",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "actix-web"
+version = "4.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9180d76e5cc7ccbc4d60a506f2c727730b154010262df5b910eb17dbe4b8cb38"
+dependencies = [
+ "actix-codec",
+ "actix-http",
+ "actix-macros",
+ "actix-router",
+ "actix-rt",
+ "actix-server",
+ "actix-service",
+ "actix-utils",
+ "actix-web-codegen",
+ "ahash",
+ "bytes",
+ "bytestring",
+ "cfg-if",
+ "cookie",
+ "derive_more",
+ "encoding_rs",
+ "futures-core",
+ "futures-util",
+ "impl-more",
+ "itoa",
+ "language-tags",
+ "log",
+ "mime",
+ "once_cell",
+ "pin-project-lite",
+ "regex",
+ "regex-lite",
+ "serde",
+ "serde_json",
+ "serde_urlencoded",
+ "smallvec",
+ "socket2",
+ "time",
+ "url",
+]
+
+[[package]]
+name = "actix-web-codegen"
+version = "4.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f591380e2e68490b5dfaf1dd1aa0ebe78d84ba7067078512b4ea6e4492d622b8"
+dependencies = [
+ "actix-router",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.87",
+]
+
[[package]]
name = "addr2line"
version = "0.24.2"
@@ -17,6 +200,30 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
+[[package]]
+name = "aes"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
+dependencies = [
+ "cfg-if",
+ "cipher",
+ "cpufeatures",
+]
+
+[[package]]
+name = "ahash"
+version = "0.8.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
+dependencies = [
+ "cfg-if",
+ "getrandom",
+ "once_cell",
+ "version_check",
+ "zerocopy",
+]
+
[[package]]
name = "aho-corasick"
version = "1.1.3"
@@ -26,6 +233,21 @@ 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 = "android-tzdata"
version = "0.1.1"
@@ -43,9 +265,9 @@ dependencies = [
[[package]]
name = "anstream"
-version = "0.6.17"
+version = "0.6.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23a1e53f0f5d86382dafe1cf314783b2044280f406e7e1506368220ad11b1338"
+checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
dependencies = [
"anstyle",
"anstyle-parse",
@@ -58,9 +280,9 @@ dependencies = [
[[package]]
name = "anstyle"
-version = "1.0.9"
+version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8365de52b16c035ff4fcafe0092ba9390540e3e352870ac09933bebcaa2c8c56"
+checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
[[package]]
name = "anstyle-parse"
@@ -90,12 +312,45 @@ dependencies = [
"windows-sys 0.59.0",
]
+[[package]]
+name = "atomic-waker"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
+
[[package]]
name = "autocfg"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
+[[package]]
+name = "aws-lc-rs"
+version = "1.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdd82dba44d209fddb11c190e0a94b78651f95299598e472215667417a03ff1d"
+dependencies = [
+ "aws-lc-sys",
+ "mirai-annotations",
+ "paste",
+ "zeroize",
+]
+
+[[package]]
+name = "aws-lc-sys"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df7a4168111d7eb622a31b214057b8509c0a7e1794f44c546d742330dc793972"
+dependencies = [
+ "bindgen",
+ "cc",
+ "cmake",
+ "dunce",
+ "fs_extra",
+ "libc",
+ "paste",
+]
+
[[package]]
name = "backtrace"
version = "0.3.74"
@@ -111,6 +366,18 @@ dependencies = [
"windows-targets 0.52.6",
]
+[[package]]
+name = "base64"
+version = "0.22.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+
+[[package]]
+name = "base64ct"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
+
[[package]]
name = "bincode"
version = "1.3.3"
@@ -120,6 +387,29 @@ dependencies = [
"serde",
]
+[[package]]
+name = "bindgen"
+version = "0.69.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088"
+dependencies = [
+ "bitflags 2.6.0",
+ "cexpr",
+ "clang-sys",
+ "itertools",
+ "lazy_static",
+ "lazycell",
+ "log",
+ "prettyplease",
+ "proc-macro2",
+ "quote",
+ "regex",
+ "rustc-hash",
+ "shlex",
+ "syn 2.0.87",
+ "which",
+]
+
[[package]]
name = "bitflags"
version = "1.3.2"
@@ -132,6 +422,45 @@ version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
+[[package]]
+name = "block-buffer"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "block-padding"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "brotli"
+version = "6.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b"
+dependencies = [
+ "alloc-no-stdlib",
+ "alloc-stdlib",
+ "brotli-decompressor",
+]
+
+[[package]]
+name = "brotli-decompressor"
+version = "4.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362"
+dependencies = [
+ "alloc-no-stdlib",
+ "alloc-stdlib",
+]
+
[[package]]
name = "bumpalo"
version = "3.16.0"
@@ -150,15 +479,44 @@ version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da"
+[[package]]
+name = "bytestring"
+version = "1.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74d80203ea6b29df88012294f62733de21cfeab47f17b41af3a38bc30a03ee72"
+dependencies = [
+ "bytes",
+]
+
+[[package]]
+name = "cbc"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6"
+dependencies = [
+ "cipher",
+]
+
[[package]]
name = "cc"
-version = "1.1.31"
+version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f"
+checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47"
dependencies = [
+ "jobserver",
+ "libc",
"shlex",
]
+[[package]]
+name = "cexpr"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
+dependencies = [
+ "nom",
+]
+
[[package]]
name = "cfg-if"
version = "1.0.0"
@@ -185,20 +543,41 @@ dependencies = [
"windows-targets 0.52.6",
]
+[[package]]
+name = "cipher"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
+dependencies = [
+ "crypto-common",
+ "inout",
+]
+
+[[package]]
+name = "clang-sys"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
+dependencies = [
+ "glob",
+ "libc",
+ "libloading",
+]
+
[[package]]
name = "clap"
-version = "4.5.20"
+version = "4.5.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8"
+checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f"
dependencies = [
"clap_builder",
]
[[package]]
name = "clap_builder"
-version = "4.5.20"
+version = "4.5.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54"
+checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec"
dependencies = [
"anstream",
"anstyle",
@@ -208,9 +587,18 @@ dependencies = [
[[package]]
name = "clap_lex"
-version = "0.7.2"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7"
+
+[[package]]
+name = "cmake"
+version = "0.1.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
+checksum = "fb1e43aa7fd152b1f968787f7dbcdeb306d1867ff373c69955211876c053f91a"
+dependencies = [
+ "cc",
+]
[[package]]
name = "colorchoice"
@@ -228,12 +616,54 @@ dependencies = [
"windows-sys 0.48.0",
]
+[[package]]
+name = "const-oid"
+version = "0.9.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
+
+[[package]]
+name = "convert_case"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
+
+[[package]]
+name = "cookie"
+version = "0.16.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb"
+dependencies = [
+ "percent-encoding",
+ "time",
+ "version_check",
+]
+
+[[package]]
+name = "core-foundation"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
[[package]]
name = "core-foundation-sys"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
+[[package]]
+name = "cpufeatures"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ca741a962e1b0bff6d724a1a0958b686406e853bb14061f218562e1896f95e6"
+dependencies = [
+ "libc",
+]
+
[[package]]
name = "crc32fast"
version = "1.4.2"
@@ -268,11 +698,21 @@ version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
+[[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 = "csv"
-version = "1.3.0"
+version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe"
+checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf"
dependencies = [
"csv-core",
"itoa",
@@ -290,40 +730,166 @@ dependencies = [
]
[[package]]
-name = "dirs-next"
-version = "2.0.0"
+name = "curve25519-dalek"
+version = "4.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
+checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be"
dependencies = [
"cfg-if",
- "dirs-sys-next",
+ "cpufeatures",
+ "curve25519-dalek-derive",
+ "digest",
+ "fiat-crypto",
+ "rustc_version",
+ "subtle",
+ "zeroize",
]
[[package]]
-name = "dirs-sys-next"
-version = "0.1.2"
+name = "curve25519-dalek-derive"
+version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
+checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
dependencies = [
- "libc",
- "redox_users",
- "winapi",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.87",
]
[[package]]
-name = "either"
-version = "1.13.0"
+name = "der"
+version = "0.7.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
+checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0"
+dependencies = [
+ "const-oid",
+ "pem-rfc7468",
+ "zeroize",
+]
[[package]]
-name = "encode_unicode"
-version = "1.0.0"
+name = "deranged"
+version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
+checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
+dependencies = [
+ "powerfmt",
+]
[[package]]
-name = "equivalent"
+name = "derive_more"
+version = "0.99.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce"
+dependencies = [
+ "convert_case",
+ "proc-macro2",
+ "quote",
+ "rustc_version",
+ "syn 2.0.87",
+]
+
+[[package]]
+name = "digest"
+version = "0.10.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
+dependencies = [
+ "block-buffer",
+ "const-oid",
+ "crypto-common",
+ "subtle",
+]
+
+[[package]]
+name = "dirs-next"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
+dependencies = [
+ "cfg-if",
+ "dirs-sys-next",
+]
+
+[[package]]
+name = "dirs-sys-next"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
+dependencies = [
+ "libc",
+ "redox_users",
+ "winapi",
+]
+
+[[package]]
+name = "displaydoc"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.87",
+]
+
+[[package]]
+name = "dunce"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
+
+[[package]]
+name = "ed25519"
+version = "2.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53"
+dependencies = [
+ "pkcs8",
+ "serde",
+ "signature",
+]
+
+[[package]]
+name = "ed25519-dalek"
+version = "2.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871"
+dependencies = [
+ "curve25519-dalek",
+ "ed25519",
+ "merlin",
+ "rand_core",
+ "serde",
+ "sha2",
+ "signature",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "either"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
+
+[[package]]
+name = "encode_unicode"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
+
+[[package]]
+name = "encoding_rs"
+version = "0.8.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
@@ -338,6 +904,18 @@ dependencies = [
"windows-sys 0.52.0",
]
+[[package]]
+name = "fastrand"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4"
+
+[[package]]
+name = "fiat-crypto"
+version = "0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d"
+
[[package]]
name = "flate2"
version = "1.0.34"
@@ -348,12 +926,166 @@ dependencies = [
"miniz_oxide",
]
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
+name = "foreign-types"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
+dependencies = [
+ "foreign-types-shared",
+]
+
+[[package]]
+name = "foreign-types-shared"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
+
+[[package]]
+name = "form_urlencoded"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
+dependencies = [
+ "percent-encoding",
+]
+
+[[package]]
+name = "fs2"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213"
+dependencies = [
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "fs_extra"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
+
[[package]]
name = "fst"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a"
+[[package]]
+name = "futures"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-executor",
+ "futures-io",
+ "futures-sink",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-channel"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+]
+
+[[package]]
+name = "futures-core"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
+
+[[package]]
+name = "futures-executor"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
+dependencies = [
+ "futures-core",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-io"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
+
+[[package]]
+name = "futures-macro"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.87",
+]
+
+[[package]]
+name = "futures-sink"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
+
+[[package]]
+name = "futures-task"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
+
+[[package]]
+name = "futures-util"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-macro",
+ "futures-sink",
+ "futures-task",
+ "memchr",
+ "pin-project-lite",
+ "pin-utils",
+ "slab",
+]
+
+[[package]]
+name = "fxhash"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
+dependencies = [
+ "byteorder",
+]
+
+[[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.15"
@@ -371,11 +1103,55 @@ version = "0.31.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
+[[package]]
+name = "glob"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
+
+[[package]]
+name = "h2"
+version = "0.3.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8"
+dependencies = [
+ "bytes",
+ "fnv",
+ "futures-core",
+ "futures-sink",
+ "futures-util",
+ "http 0.2.12",
+ "indexmap",
+ "slab",
+ "tokio",
+ "tokio-util",
+ "tracing",
+]
+
+[[package]]
+name = "h2"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205"
+dependencies = [
+ "atomic-waker",
+ "bytes",
+ "fnv",
+ "futures-core",
+ "futures-sink",
+ "http 1.1.0",
+ "indexmap",
+ "slab",
+ "tokio",
+ "tokio-util",
+ "tracing",
+]
+
[[package]]
name = "hashbrown"
-version = "0.15.0"
+version = "0.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb"
+checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3"
[[package]]
name = "hermit-abi"
@@ -395,6 +1171,153 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
+[[package]]
+name = "hmac"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
+dependencies = [
+ "digest",
+]
+
+[[package]]
+name = "home"
+version = "0.5.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
+dependencies = [
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "http"
+version = "0.2.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1"
+dependencies = [
+ "bytes",
+ "fnv",
+ "itoa",
+]
+
+[[package]]
+name = "http"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258"
+dependencies = [
+ "bytes",
+ "fnv",
+ "itoa",
+]
+
+[[package]]
+name = "http-body"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
+dependencies = [
+ "bytes",
+ "http 1.1.0",
+]
+
+[[package]]
+name = "http-body-util"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f"
+dependencies = [
+ "bytes",
+ "futures-util",
+ "http 1.1.0",
+ "http-body",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "httparse"
+version = "1.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946"
+
+[[package]]
+name = "httpdate"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
+
+[[package]]
+name = "hyper"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a"
+dependencies = [
+ "bytes",
+ "futures-channel",
+ "futures-util",
+ "h2 0.4.6",
+ "http 1.1.0",
+ "http-body",
+ "httparse",
+ "itoa",
+ "pin-project-lite",
+ "smallvec",
+ "tokio",
+ "want",
+]
+
+[[package]]
+name = "hyper-rustls"
+version = "0.27.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333"
+dependencies = [
+ "futures-util",
+ "http 1.1.0",
+ "hyper",
+ "hyper-util",
+ "rustls",
+ "rustls-pki-types",
+ "tokio",
+ "tokio-rustls",
+ "tower-service",
+]
+
+[[package]]
+name = "hyper-tls"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
+dependencies = [
+ "bytes",
+ "http-body-util",
+ "hyper",
+ "hyper-util",
+ "native-tls",
+ "tokio",
+ "tokio-native-tls",
+ "tower-service",
+]
+
+[[package]]
+name = "hyper-util"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4"
+dependencies = [
+ "bytes",
+ "futures-channel",
+ "futures-util",
+ "http 1.1.0",
+ "http-body",
+ "hyper",
+ "pin-project-lite",
+ "socket2",
+ "tokio",
+ "tower-service",
+ "tracing",
+]
+
[[package]]
name = "hyphenation"
version = "0.8.4"
@@ -441,6 +1364,151 @@ dependencies = [
"cc",
]
+[[package]]
+name = "icu_collections"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526"
+dependencies = [
+ "displaydoc",
+ "yoke",
+ "zerofrom",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locid"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637"
+dependencies = [
+ "displaydoc",
+ "litemap",
+ "tinystr",
+ "writeable",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locid_transform"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e"
+dependencies = [
+ "displaydoc",
+ "icu_locid",
+ "icu_locid_transform_data",
+ "icu_provider",
+ "tinystr",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locid_transform_data"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e"
+
+[[package]]
+name = "icu_normalizer"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f"
+dependencies = [
+ "displaydoc",
+ "icu_collections",
+ "icu_normalizer_data",
+ "icu_properties",
+ "icu_provider",
+ "smallvec",
+ "utf16_iter",
+ "utf8_iter",
+ "write16",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_normalizer_data"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516"
+
+[[package]]
+name = "icu_properties"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5"
+dependencies = [
+ "displaydoc",
+ "icu_collections",
+ "icu_locid_transform",
+ "icu_properties_data",
+ "icu_provider",
+ "tinystr",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_properties_data"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569"
+
+[[package]]
+name = "icu_provider"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9"
+dependencies = [
+ "displaydoc",
+ "icu_locid",
+ "icu_provider_macros",
+ "stable_deref_trait",
+ "tinystr",
+ "writeable",
+ "yoke",
+ "zerofrom",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_provider_macros"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.87",
+]
+
+[[package]]
+name = "idna"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
+dependencies = [
+ "idna_adapter",
+ "smallvec",
+ "utf8_iter",
+]
+
+[[package]]
+name = "idna_adapter"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71"
+dependencies = [
+ "icu_normalizer",
+ "icu_properties",
+]
+
+[[package]]
+name = "impl-more"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aae21c3177a27788957044151cc2800043d127acaa460a47ebb9b84dfa2c6aa0"
+
[[package]]
name = "indexmap"
version = "2.6.0"
@@ -449,6 +1517,26 @@ checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
dependencies = [
"equivalent",
"hashbrown",
+ "serde",
+]
+
+[[package]]
+name = "inout"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
+dependencies = [
+ "block-padding",
+ "generic-array",
+]
+
+[[package]]
+name = "instant"
+version = "0.1.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222"
+dependencies = [
+ "cfg-if",
]
[[package]]
@@ -462,6 +1550,12 @@ dependencies = [
"windows-sys 0.48.0",
]
+[[package]]
+name = "ipnet"
+version = "2.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708"
+
[[package]]
name = "is-terminal"
version = "0.4.13"
@@ -479,12 +1573,30 @@ version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
+[[package]]
+name = "itertools"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
+dependencies = [
+ "either",
+]
+
[[package]]
name = "itoa"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
+[[package]]
+name = "jobserver"
+version = "0.1.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0"
+dependencies = [
+ "libc",
+]
+
[[package]]
name = "js-sys"
version = "0.3.72"
@@ -494,17 +1606,57 @@ dependencies = [
"wasm-bindgen",
]
+[[package]]
+name = "keccak"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654"
+dependencies = [
+ "cpufeatures",
+]
+
+[[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.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+dependencies = [
+ "spin",
+]
+
+[[package]]
+name = "lazycell"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
name = "libc"
-version = "0.2.161"
+version = "0.2.162"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398"
+
+[[package]]
+name = "libloading"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4"
+dependencies = [
+ "cfg-if",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "libm"
+version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1"
+checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa"
[[package]]
name = "libredox"
@@ -520,18 +1672,29 @@ dependencies = [
name = "libsysinspect"
version = "0.2.0"
dependencies = [
+ "base64",
"chrono",
"colored",
+ "hex",
"indexmap",
"lazy_static",
"log",
"nix",
+ "once_cell",
+ "pem",
+ "pest",
+ "pest_derive",
"prettytable-rs",
+ "rand",
"regex",
+ "rsa",
"serde",
"serde_json",
"serde_yaml",
+ "sha2",
+ "sysinfo 0.32.0",
"textwrap",
+ "tokio",
"unicode-segmentation",
"walkdir",
]
@@ -548,6 +1711,29 @@ version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
+[[package]]
+name = "litemap"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704"
+
+[[package]]
+name = "local-channel"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6cbc85e69b8df4b8bb8b89ec634e7189099cea8927a276b7384ce5488e53ec8"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+ "local-waker",
+]
+
+[[package]]
+name = "local-waker"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d873d7c67ce09b42110d801813efbc9364414e356be9935700d368351657487"
+
[[package]]
name = "lock_api"
version = "0.4.12"
@@ -579,6 +1765,30 @@ dependencies = [
"autocfg",
]
+[[package]]
+name = "merlin"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d"
+dependencies = [
+ "byteorder",
+ "keccak",
+ "rand_core",
+ "zeroize",
+]
+
+[[package]]
+name = "mime"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
+
+[[package]]
+name = "minimal-lexical"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
+
[[package]]
name = "miniz_oxide"
version = "0.8.0"
@@ -596,10 +1806,34 @@ checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec"
dependencies = [
"hermit-abi 0.3.9",
"libc",
+ "log",
"wasi",
"windows-sys 0.52.0",
]
+[[package]]
+name = "mirai-annotations"
+version = "1.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c9be0862c1b3f26a88803c4a49de6889c10e608b3ee9344e6ef5b45fb37ad3d1"
+
+[[package]]
+name = "native-tls"
+version = "0.2.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466"
+dependencies = [
+ "libc",
+ "log",
+ "openssl",
+ "openssl-probe",
+ "openssl-sys",
+ "schannel",
+ "security-framework",
+ "security-framework-sys",
+ "tempfile",
+]
+
[[package]]
name = "neli"
version = "0.6.4"
@@ -653,6 +1887,16 @@ dependencies = [
"memoffset",
]
+[[package]]
+name = "nom"
+version = "7.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
+dependencies = [
+ "memchr",
+ "minimal-lexical",
+]
+
[[package]]
name = "ntapi"
version = "0.4.1"
@@ -662,6 +1906,49 @@ dependencies = [
"winapi",
]
+[[package]]
+name = "num-bigint-dig"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151"
+dependencies = [
+ "byteorder",
+ "lazy_static",
+ "libm",
+ "num-integer",
+ "num-iter",
+ "num-traits",
+ "rand",
+ "smallvec",
+ "zeroize",
+]
+
+[[package]]
+name = "num-conv"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
+
+[[package]]
+name = "num-integer"
+version = "0.1.46"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "num-iter"
+version = "0.1.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf"
+dependencies = [
+ "autocfg",
+ "num-integer",
+ "num-traits",
+]
+
[[package]]
name = "num-traits"
version = "0.2.19"
@@ -669,6 +1956,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
+ "libm",
]
[[package]]
@@ -686,6 +1974,61 @@ version = "1.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
+[[package]]
+name = "openssl"
+version = "0.10.68"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5"
+dependencies = [
+ "bitflags 2.6.0",
+ "cfg-if",
+ "foreign-types",
+ "libc",
+ "once_cell",
+ "openssl-macros",
+ "openssl-sys",
+]
+
+[[package]]
+name = "openssl-macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.87",
+]
+
+[[package]]
+name = "openssl-probe"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
+
+[[package]]
+name = "openssl-sys"
+version = "0.9.104"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+ "vcpkg",
+]
+
+[[package]]
+name = "parking_lot"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
+dependencies = [
+ "instant",
+ "lock_api",
+ "parking_lot_core 0.8.6",
+]
+
[[package]]
name = "parking_lot"
version = "0.12.3"
@@ -693,7 +2036,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
dependencies = [
"lock_api",
- "parking_lot_core",
+ "parking_lot_core 0.9.10",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.8.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc"
+dependencies = [
+ "cfg-if",
+ "instant",
+ "libc",
+ "redox_syscall 0.2.16",
+ "smallvec",
+ "winapi",
]
[[package]]
@@ -704,23 +2061,184 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
dependencies = [
"cfg-if",
"libc",
- "redox_syscall",
+ "redox_syscall 0.5.7",
"smallvec",
"windows-targets 0.52.6",
]
+[[package]]
+name = "paste"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
+
+[[package]]
+name = "pbkdf2"
+version = "0.12.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2"
+dependencies = [
+ "digest",
+ "hmac",
+]
+
+[[package]]
+name = "pem"
+version = "3.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae"
+dependencies = [
+ "base64",
+ "serde",
+]
+
+[[package]]
+name = "pem-rfc7468"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412"
+dependencies = [
+ "base64ct",
+]
+
+[[package]]
+name = "percent-encoding"
+version = "2.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
+
+[[package]]
+name = "pest"
+version = "2.7.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442"
+dependencies = [
+ "memchr",
+ "thiserror",
+ "ucd-trie",
+]
+
+[[package]]
+name = "pest_derive"
+version = "2.7.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d214365f632b123a47fd913301e14c946c61d1c183ee245fa76eb752e59a02dd"
+dependencies = [
+ "pest",
+ "pest_generator",
+]
+
+[[package]]
+name = "pest_generator"
+version = "2.7.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eb55586734301717aea2ac313f50b2eb8f60d2fc3dc01d190eefa2e625f60c4e"
+dependencies = [
+ "pest",
+ "pest_meta",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.87",
+]
+
+[[package]]
+name = "pest_meta"
+version = "2.7.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b75da2a70cf4d9cb76833c990ac9cd3923c9a8905a8929789ce347c84564d03d"
+dependencies = [
+ "once_cell",
+ "pest",
+ "sha2",
+]
+
[[package]]
name = "pin-project-lite"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff"
+[[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.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f"
+dependencies = [
+ "der",
+ "pkcs8",
+ "spki",
+]
+
+[[package]]
+name = "pkcs5"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e847e2c91a18bfa887dd028ec33f2fe6f25db77db3619024764914affe8b69a6"
+dependencies = [
+ "aes",
+ "cbc",
+ "der",
+ "pbkdf2",
+ "scrypt",
+ "sha2",
+ "spki",
+]
+
+[[package]]
+name = "pkcs8"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7"
+dependencies = [
+ "der",
+ "pkcs5",
+ "rand_core",
+ "spki",
+]
+
+[[package]]
+name = "pkg-config"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
+
[[package]]
name = "pocket-resources"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c135f38778ad324d9e9ee68690bac2c1a51f340fdf96ca13e2ab3914eb2e51d8"
+[[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.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
+dependencies = [
+ "zerocopy",
+]
+
+[[package]]
+name = "prettyplease"
+version = "0.2.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033"
+dependencies = [
+ "proc-macro2",
+ "syn 2.0.87",
+]
+
[[package]]
name = "prettytable-rs"
version = "0.10.0"
@@ -767,27 +2285,57 @@ dependencies = [
"flate2",
"hex",
"procfs-core",
- "rustix 0.38.38",
+ "rustix 0.38.40",
]
[[package]]
name = "procfs-core"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "239df02d8349b06fc07398a3a1697b06418223b1c7725085e801e7c0fc6a12ec"
+checksum = "239df02d8349b06fc07398a3a1697b06418223b1c7725085e801e7c0fc6a12ec"
+dependencies = [
+ "bitflags 2.6.0",
+ "chrono",
+ "hex",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
+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 = [
- "bitflags 2.6.0",
- "chrono",
- "hex",
+ "ppv-lite86",
+ "rand_core",
]
[[package]]
-name = "quote"
-version = "1.0.37"
+name = "rand_core"
+version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
- "proc-macro2",
+ "getrandom",
]
[[package]]
@@ -810,6 +2358,15 @@ dependencies = [
"crossbeam-utils",
]
+[[package]]
+name = "redox_syscall"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
+dependencies = [
+ "bitflags 1.3.2",
+]
+
[[package]]
name = "redox_syscall"
version = "0.5.7"
@@ -844,21 +2401,107 @@ dependencies = [
[[package]]
name = "regex-automata"
-version = "0.4.8"
+version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
+checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
+[[package]]
+name = "regex-lite"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a"
+
[[package]]
name = "regex-syntax"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
+[[package]]
+name = "reqwest"
+version = "0.12.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f"
+dependencies = [
+ "base64",
+ "bytes",
+ "encoding_rs",
+ "futures-core",
+ "futures-util",
+ "h2 0.4.6",
+ "http 1.1.0",
+ "http-body",
+ "http-body-util",
+ "hyper",
+ "hyper-rustls",
+ "hyper-tls",
+ "hyper-util",
+ "ipnet",
+ "js-sys",
+ "log",
+ "mime",
+ "native-tls",
+ "once_cell",
+ "percent-encoding",
+ "pin-project-lite",
+ "rustls-pemfile",
+ "serde",
+ "serde_json",
+ "serde_urlencoded",
+ "sync_wrapper",
+ "system-configuration",
+ "tokio",
+ "tokio-native-tls",
+ "tower-service",
+ "url",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+ "windows-registry",
+]
+
+[[package]]
+name = "ring"
+version = "0.17.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d"
+dependencies = [
+ "cc",
+ "cfg-if",
+ "getrandom",
+ "libc",
+ "spin",
+ "untrusted",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "rsa"
+version = "0.9.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc"
+dependencies = [
+ "const-oid",
+ "digest",
+ "num-bigint-dig",
+ "num-integer",
+ "num-traits",
+ "pkcs1",
+ "pkcs8",
+ "rand_core",
+ "sha1",
+ "sha2",
+ "signature",
+ "spki",
+ "subtle",
+ "zeroize",
+]
+
[[package]]
name = "run"
version = "0.2.0"
@@ -876,6 +2519,21 @@ version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
+[[package]]
+name = "rustc-hash"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
+
+[[package]]
+name = "rustc_version"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
+dependencies = [
+ "semver",
+]
+
[[package]]
name = "rustix"
version = "0.37.27"
@@ -892,9 +2550,9 @@ dependencies = [
[[package]]
name = "rustix"
-version = "0.38.38"
+version = "0.38.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa260229e6538e52293eeb577aabd09945a09d6d9cc0fc550ed7529056c2e32a"
+checksum = "99e4ea3e1cdc4b559b8e5650f9c8e5998e3e5c1343b4eaf034565f32318d63c0"
dependencies = [
"bitflags 2.6.0",
"errno",
@@ -903,6 +2561,48 @@ dependencies = [
"windows-sys 0.52.0",
]
+[[package]]
+name = "rustls"
+version = "0.23.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eee87ff5d9b36712a58574e12e9f0ea80f915a5b0ac518d322b24a465617925e"
+dependencies = [
+ "aws-lc-rs",
+ "log",
+ "once_cell",
+ "rustls-pki-types",
+ "rustls-webpki",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "rustls-pemfile"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
+dependencies = [
+ "rustls-pki-types",
+]
+
+[[package]]
+name = "rustls-pki-types"
+version = "1.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b"
+
+[[package]]
+name = "rustls-webpki"
+version = "0.102.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9"
+dependencies = [
+ "aws-lc-rs",
+ "ring",
+ "rustls-pki-types",
+ "untrusted",
+]
+
[[package]]
name = "rustversion"
version = "1.0.18"
@@ -915,6 +2615,15 @@ version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
+[[package]]
+name = "salsa20"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213"
+dependencies = [
+ "cipher",
+]
+
[[package]]
name = "same-file"
version = "1.0.6"
@@ -924,30 +2633,79 @@ dependencies = [
"winapi-util",
]
+[[package]]
+name = "schannel"
+version = "0.1.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1"
+dependencies = [
+ "windows-sys 0.59.0",
+]
+
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+[[package]]
+name = "scrypt"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f"
+dependencies = [
+ "pbkdf2",
+ "salsa20",
+ "sha2",
+]
+
+[[package]]
+name = "security-framework"
+version = "2.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
+dependencies = [
+ "bitflags 2.6.0",
+ "core-foundation",
+ "core-foundation-sys",
+ "libc",
+ "security-framework-sys",
+]
+
+[[package]]
+name = "security-framework-sys"
+version = "2.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "semver"
+version = "1.0.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
+
[[package]]
name = "serde"
-version = "1.0.214"
+version = "1.0.215"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5"
+checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.214"
+version = "1.0.215"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766"
+checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -962,6 +2720,18 @@ dependencies = [
"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 = "serde_yaml"
version = "0.9.34+deprecated"
@@ -975,6 +2745,38 @@ dependencies = [
"unsafe-libyaml",
]
+[[package]]
+name = "sha1"
+version = "0.10.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "digest",
+]
+
+[[package]]
+name = "sha2"
+version = "0.10.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "digest",
+ "sha2-asm",
+]
+
+[[package]]
+name = "sha2-asm"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b845214d6175804686b2bd482bcffe96651bb2d1200742b712003504a2dac1ab"
+dependencies = [
+ "cc",
+]
+
[[package]]
name = "shlex"
version = "1.3.0"
@@ -990,6 +2792,41 @@ dependencies = [
"libc",
]
+[[package]]
+name = "signature"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
+dependencies = [
+ "digest",
+ "rand_core",
+]
+
+[[package]]
+name = "slab"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "sled"
+version = "0.34.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f96b4737c2ce5987354855aed3797279def4ebf734436c6aa4552cf8e169935"
+dependencies = [
+ "crc32fast",
+ "crossbeam-epoch",
+ "crossbeam-utils",
+ "fs2",
+ "fxhash",
+ "libc",
+ "log",
+ "parking_lot 0.11.2",
+]
+
[[package]]
name = "smallvec"
version = "1.13.2"
@@ -1012,12 +2849,40 @@ dependencies = [
"windows-sys 0.52.0",
]
+[[package]]
+name = "spin"
+version = "0.9.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
+
+[[package]]
+name = "spki"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d"
+dependencies = [
+ "base64ct",
+ "der",
+]
+
+[[package]]
+name = "stable_deref_trait"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
+
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+[[package]]
+name = "subtle"
+version = "2.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
+
[[package]]
name = "syn"
version = "1.0.109"
@@ -1031,53 +2896,158 @@ dependencies = [
[[package]]
name = "syn"
-version = "2.0.85"
+version = "2.0.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56"
+checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
+[[package]]
+name = "sync_wrapper"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
+dependencies = [
+ "futures-core",
+]
+
+[[package]]
+name = "synstructure"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.87",
+]
+
[[package]]
name = "sysinfo"
version = "0.31.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "355dbe4f8799b304b05e1b0f05fc59b2a18d36645cf169607da45bde2f69a1be"
+checksum = "355dbe4f8799b304b05e1b0f05fc59b2a18d36645cf169607da45bde2f69a1be"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+ "memchr",
+ "ntapi",
+ "rayon",
+ "windows",
+]
+
+[[package]]
+name = "sysinfo"
+version = "0.32.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3b5ae3f4f7d64646c46c4cae4e3f01d1c5d255c7406fdd7c7f999a94e488791"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+ "memchr",
+ "ntapi",
+ "rayon",
+ "windows",
+]
+
+[[package]]
+name = "sysinspect"
+version = "0.2.0"
+dependencies = [
+ "chrono",
+ "clap",
+ "colored",
+ "libsysinspect",
+ "log",
+ "sysinfo 0.31.4",
+]
+
+[[package]]
+name = "sysmaster"
+version = "0.1.0"
+dependencies = [
+ "actix-web",
+ "clap",
+ "colored",
+ "ed25519-dalek",
+ "futures",
+ "libc",
+ "libsysinspect",
+ "log",
+ "rand",
+ "rsa",
+ "rustls",
+ "rustls-pemfile",
+ "serde",
+ "serde_json",
+ "serde_yaml",
+ "sled",
+ "tokio",
+ "tokio-rustls",
+ "uuid",
+]
+
+[[package]]
+name = "sysminion"
+version = "0.1.0"
+dependencies = [
+ "clap",
+ "colored",
+ "ed25519-dalek",
+ "glob",
+ "indexmap",
+ "libsysinspect",
+ "log",
+ "once_cell",
+ "rand",
+ "regex",
+ "reqwest",
+ "rsa",
+ "rustls",
+ "rustls-pemfile",
+ "serde",
+ "serde_json",
+ "serde_yaml",
+ "sysinfo 0.32.0",
+ "tokio",
+ "uuid",
+]
+
+[[package]]
+name = "system-configuration"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b"
dependencies = [
- "core-foundation-sys",
- "libc",
- "memchr",
- "ntapi",
- "rayon",
- "windows",
+ "bitflags 2.6.0",
+ "core-foundation",
+ "system-configuration-sys",
]
[[package]]
-name = "sysinfo"
-version = "0.32.0"
+name = "system-configuration-sys"
+version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3b5ae3f4f7d64646c46c4cae4e3f01d1c5d255c7406fdd7c7f999a94e488791"
+checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4"
dependencies = [
"core-foundation-sys",
"libc",
- "memchr",
- "ntapi",
- "rayon",
- "windows",
]
[[package]]
-name = "sysinspect"
-version = "0.2.0"
+name = "tempfile"
+version = "3.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c"
dependencies = [
- "chrono",
- "clap",
- "colored",
- "libsysinspect",
- "log",
- "sysinfo 0.31.4",
+ "cfg-if",
+ "fastrand",
+ "once_cell",
+ "rustix 0.38.40",
+ "windows-sys 0.59.0",
]
[[package]]
@@ -1116,35 +3086,76 @@ dependencies = [
[[package]]
name = "thiserror"
-version = "1.0.65"
+version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5"
+checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
-version = "1.0.65"
+version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602"
+checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
+]
+
+[[package]]
+name = "time"
+version = "0.3.36"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
+dependencies = [
+ "deranged",
+ "itoa",
+ "num-conv",
+ "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.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
+dependencies = [
+ "num-conv",
+ "time-core",
+]
+
+[[package]]
+name = "tinystr"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f"
+dependencies = [
+ "displaydoc",
+ "zerovec",
]
[[package]]
name = "tokio"
-version = "1.41.0"
+version = "1.41.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "145f3413504347a2be84393cc8a7d2fb4d863b375909ea59f2158261aa258bbb"
+checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33"
dependencies = [
"backtrace",
"bytes",
"libc",
"mio",
- "parking_lot",
+ "parking_lot 0.12.3",
"pin-project-lite",
"signal-hook-registry",
"socket2",
@@ -1160,9 +3171,87 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
+]
+
+[[package]]
+name = "tokio-native-tls"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
+dependencies = [
+ "native-tls",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-rustls"
+version = "0.26.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4"
+dependencies = [
+ "rustls",
+ "rustls-pki-types",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-util"
+version = "0.7.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "futures-sink",
+ "pin-project-lite",
+ "tokio",
+]
+
+[[package]]
+name = "tower-service"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
+
+[[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-core",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
+dependencies = [
+ "once_cell",
]
+[[package]]
+name = "try-lock"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
+
+[[package]]
+name = "typenum"
+version = "1.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
+
+[[package]]
+name = "ucd-trie"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971"
+
[[package]]
name = "unicode-ident"
version = "1.0.13"
@@ -1193,12 +3282,62 @@ version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
+[[package]]
+name = "untrusted"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
+
+[[package]]
+name = "url"
+version = "2.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada"
+dependencies = [
+ "form_urlencoded",
+ "idna",
+ "percent-encoding",
+]
+
+[[package]]
+name = "utf16_iter"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246"
+
+[[package]]
+name = "utf8_iter"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
+
[[package]]
name = "utf8parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
+[[package]]
+name = "uuid"
+version = "1.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "vcpkg"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
+
+[[package]]
+name = "version_check"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
+
[[package]]
name = "walkdir"
version = "2.5.0"
@@ -1209,6 +3348,15 @@ dependencies = [
"winapi-util",
]
+[[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"
@@ -1237,10 +3385,22 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
"wasm-bindgen-shared",
]
+[[package]]
+name = "wasm-bindgen-futures"
+version = "0.4.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "wasm-bindgen",
+ "web-sys",
+]
+
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.95"
@@ -1259,7 +3419,7 @@ checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@@ -1270,6 +3430,28 @@ version = "0.2.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d"
+[[package]]
+name = "web-sys"
+version = "0.3.72"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "which"
+version = "4.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
+dependencies = [
+ "either",
+ "home",
+ "once_cell",
+ "rustix 0.38.40",
+]
+
[[package]]
name = "winapi"
version = "0.3.9"
@@ -1328,7 +3510,7 @@ checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d"
dependencies = [
"windows-implement",
"windows-interface",
- "windows-result",
+ "windows-result 0.1.2",
"windows-targets 0.52.6",
]
@@ -1340,7 +3522,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
]
[[package]]
@@ -1351,7 +3533,18 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.85",
+ "syn 2.0.87",
+]
+
+[[package]]
+name = "windows-registry"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0"
+dependencies = [
+ "windows-result 0.2.0",
+ "windows-strings",
+ "windows-targets 0.52.6",
]
[[package]]
@@ -1363,6 +3556,25 @@ dependencies = [
"windows-targets 0.52.6",
]
+[[package]]
+name = "windows-result"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e"
+dependencies = [
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-strings"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
+dependencies = [
+ "windows-result 0.2.0",
+ "windows-targets 0.52.6",
+]
+
[[package]]
name = "windows-sys"
version = "0.48.0"
@@ -1510,3 +3722,151 @@ name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
+[[package]]
+name = "write16"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936"
+
+[[package]]
+name = "writeable"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
+
+[[package]]
+name = "yoke"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5"
+dependencies = [
+ "serde",
+ "stable_deref_trait",
+ "yoke-derive",
+ "zerofrom",
+]
+
+[[package]]
+name = "yoke-derive"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.87",
+ "synstructure",
+]
+
+[[package]]
+name = "zerocopy"
+version = "0.7.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
+dependencies = [
+ "byteorder",
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.7.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.87",
+]
+
+[[package]]
+name = "zerofrom"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55"
+dependencies = [
+ "zerofrom-derive",
+]
+
+[[package]]
+name = "zerofrom-derive"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.87",
+ "synstructure",
+]
+
+[[package]]
+name = "zeroize"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
+dependencies = [
+ "zeroize_derive",
+]
+
+[[package]]
+name = "zeroize_derive"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.87",
+]
+
+[[package]]
+name = "zerovec"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079"
+dependencies = [
+ "yoke",
+ "zerofrom",
+ "zerovec-derive",
+]
+
+[[package]]
+name = "zerovec-derive"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.87",
+]
+
+[[package]]
+name = "zstd"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9"
+dependencies = [
+ "zstd-safe",
+]
+
+[[package]]
+name = "zstd-safe"
+version = "7.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059"
+dependencies = [
+ "zstd-sys",
+]
+
+[[package]]
+name = "zstd-sys"
+version = "2.0.13+zstd.1.5.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa"
+dependencies = [
+ "cc",
+ "pkg-config",
+]
diff --git a/Cargo.toml b/Cargo.toml
index 8cad8e47..bf2c4787 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -15,7 +15,7 @@ sysinfo = { version = "0.31.4", features = ["linux-tmpfs"] }
[workspace]
resolver = "2"
-members = ["modules/sys/*", "libsysinspect"]
+members = ["modules/sys/*", "libsysinspect", "sysmaster", "sysminion"]
[profile.release]
strip = true
diff --git a/docs/genusage/distributed_model.rst b/docs/genusage/distributed_model.rst
new file mode 100644
index 00000000..78903131
--- /dev/null
+++ b/docs/genusage/distributed_model.rst
@@ -0,0 +1,160 @@
+.. raw:: html
+
+
+
+.. role:: u
+ :class: underlined
+
+.. role:: bi
+ :class: bolditalic
+
+.. _distributed_model:
+
+Distributed Model
+=================
+
+Distributed model means that the entities of it might be scattered
+across the system in different "boxes" or consist of different components,
+those are found in different network-connected places.
+
+Each entity keeps some claims about it. For example, a network consists of
+IP addresses, MAC addresses, some ports, some protocols etc. Each of these
+elements are *"building bricks"* of the whole network entity. Suppose,
+we need to ensure that the network across many "boxes" contains specific
+ports, protocols, addresses, routes etc. And each "box" has different configuration
+for it. This means each part of the network will have a different set of claims.
+
+For example, a router, which is :bi:`a part of the network entity`, has specific
+requirements on its own inside of it, and they are claims. But they are not a
+:bi:`global` claims, they are only claims that are specific to that router.
+However, we cannot admit that the network is healthy if only router alone works.
+We want to check many other places and settings all over the related "boxes"
+and see if each box on its own has their claims admitted as actual proven facts.
+Only if :bi:`all pieces comes together`, only if all checks on all boxes/places/segments
+are verified and are "green", only then we can admit that the "Network Entity"
+works as expected.
+
+To achieve this, we need to distribute the model.
+
+.. important::
+
+ The model is actually always distributed. It is just the way how do you write it.
+ However, the model is aimed to cover the entire :bi:`system`, which is not just
+ one or two "boxes" or software components, processes etc.
+
+Model Distribution Principle
+----------------------------
+
+The static model is always copied to each minion "as is". But that means that each
+minion supposed to be exactly the same in order to return a success result. However,
+in a complex system, some "boxes" are Database, some of them are routers, some of them
+are just storage systems, some of them are running middleware/services etc. And thus
+all of these "boxes" render a final heterogeneous distributed system.
+
+How Sysinspect dissects to the targets only what's needed?
+
+Let's take a look at the entity description:
+
+.. code-block:: yaml
+
+ # General section for all entities
+ entities:
+ router:
+ claims:
+ $:
+ - foo: ...
+
+ powered:
+ - foobar: ...
+
+In this case we have an entity, callsed **"router"**, which has some default common claims,
+accessible by globbing ``$`` (e.g. some admin interfaces are always there, config of hypervisor
+partitions etc), and it also has claims that are valid only when it is in ``powered``
+mode.
+
+.. pull-quote::
+
+ Now, what if we have :bi:`two different routers`, and yet they have to be
+ together, in order to let the whole network work as expected? How to split
+ facts between them?
+
+For this, an entity needs to match a minion by its traits, and claims are defined under
+the section, where traits are filtering (or selecting) :bi:`the relevant part` of the claims
+description in a declarative way.
+
+.. _splitting_claims:
+
+Splitting Claims
+----------------
+
+Let's continue with the same router example, but add another one. Say, the other one
+is running on ARM-64 architecture instead of on Intel x86_64, has much less memory
+and has a different hostname. By these traits we can distinguish those two routers,
+splitting claims among them.
+
+Here is an example:
+
+.. code-block:: yaml
+
+ # General section for all entities
+ entities:
+ router:
+ # Router 1
+ my-big-one:
+ traits:
+ system.cpu.arch: x86_64
+ system.mem.total: 16GB
+ net.hostname: crocodile.local
+ system.os.vendor: f5
+
+ # Specific flaims only for big, powerful "f5" Intel-based router
+ claims:
+ ...
+
+ # Router 2
+ my-small-one:
+ traits:
+ system.cpu.arch: ARM64
+ system.mem.total: 4GB
+ net.hostname: frog.local
+
+ # Specific flaims only for ARM-based router
+ claims:
+ ...
+
+ # Common claims for both routers
+ claims:
+ $:
+ - foo: ...
+
+ powered:
+ - foobar: ...
+
+The above is the entity description that is in the master Model. However,
+each minion will not get the entire model, but only :bi:`a subset` of the Model,
+which is relevant to only that specific minion.
+
+.. note::
+
+ Each minion will get only :bi:`a subset` of the Model, relevant only to
+ the current minion traits or other attributes!
+
+The mechanism works very similar to the Model Inheritance: matching section
+will replace the default claims section from the section that matches the minion.
+In case both sections are matching a minion, then they will be merged. If they
+overlap, then first wins. Therefore it is very important to be careful to point out
+the difference in traits or other attributes, ensuring the model is not overlapping
+on the minion side or renders wrong.
+
+.. important::
+
+ It is important to use granular and detailed targeting, in order to avoid
+ claims overlap between the minions, rendering false results.
\ No newline at end of file
diff --git a/docs/genusage/overview.rst b/docs/genusage/overview.rst
new file mode 100644
index 00000000..77c2cfc4
--- /dev/null
+++ b/docs/genusage/overview.rst
@@ -0,0 +1,50 @@
+Using Sysinspect
+================
+
+.. note::
+
+ This section explains how to use Sysinspect in "solo" mode and
+ in the network.
+
+
+Sysinspect can be used in two modes:
+
+1. Solo mode, where the entire model is for only one "box" or hardware
+2. Network-connected cluster, where entities can consist from more than one element
+ and Sysinspect needs to gather information from different places in order to construct
+ a final answer about a specific entity. Such entity, for example, can be the entire
+ network itself.
+
+19 Seconds Tutorial
+-------------------
+
+So you wrote a Model, using "Model Description" documentation and placed it to
+``/etc/sysinspect/models`` directory on your Master machine as ``my_model``.
+
+Then just call the entire model across all minions:
+
+.. code-block:: bash
+
+ sysinspect "my_model"
+
+You can call only a subset of your module, such as a specific state of a specific entity.
+For example:
+
+.. code-block:: bash
+
+ sysinspect "my_model/my_entity/my_state"
+
+For more information go ahead and dive in!
+
+Diving In
+---------
+
+To better understand how to use Sysinspect in those situation, read through the following
+sections:
+
+.. toctree::
+ :maxdepth: 2
+
+ distributed_model
+ systraits
+ targeting
diff --git a/docs/genusage/systraits.rst b/docs/genusage/systraits.rst
new file mode 100644
index 00000000..34355185
--- /dev/null
+++ b/docs/genusage/systraits.rst
@@ -0,0 +1,215 @@
+.. raw:: html
+
+
+
+.. role:: u
+ :class: underlined
+
+.. role:: bi
+ :class: bolditalic
+
+.. _systraits:
+
+System Traits
+=============
+
+.. note::
+
+ Definition and description of system traits and their purpose.
+
+Traits are essentially static attributes of a minion. They can be a literally anything
+in a form of key/value. There are different kinds of traits:
+
+**Common**
+
+ Common traits are given to each minion automatically. They are typical system
+ information and anything else that can be commonly fetched out of the "box": OS info,
+ kernel version, memory size, network settings, hostnames, machine Id etc.
+
+**Custom**
+
+ Custom traits are static data that set explicity onto a minion. Any data in
+ key/value form. They are usually various labels, rack number, physical floor,
+ Asset Tag, serial number etc.
+
+**Dynamic**
+
+ Dynamic traits are custom functions, where data obtained by relevant modules.
+ essentially, they are just like normal modules, except the resulting data is stored as
+ a criterion by which a specific minion is targeted. For example, *"memory less than X"*,
+ or *"runs process Y"* etc.
+
+Listing Traits
+--------------
+
+To list minion's traits, is enough to target a minion by its Id or hostname:
+
+.. code-block:: bash
+
+ $ sysinspect --minions
+ ...
+
+ $ sysinspect --info
+
+Using Traits in a Model
+-----------------------
+
+Using traits in a model is described in :ref:`splitting_claims` chapter of the :ref:`distributed_model` document.
+
+Static Minion Traits
+--------------------
+
+Traits can be also custom static data, which is placed in a minion configuration. Traits are just
+YAML files with key/value format, placed in ``$SYSINSPECT/traits`` directory of a minion. The naming
+of those files is not important, they will be anyway merged into one tree. Important is to ensure
+that trait keys do not repeat, so they do not overwrite each other. The ``$SYSINSPECT`` directory
+is ``/etc/sysinspect`` by default or is defined in the minion configuration.
+
+Example of a trait file:
+
+.. code-block:: yaml
+ :caption: File: ``/etc/sysinspect/traits/example.trait``
+
+ traits:
+ name: Fred
+
+From now on, the minion can be targeded by the trait ``name``:
+
+.. code-block:: bash
+ :caption: Targeting a minion by a custom trait
+
+ sysinspect "my_model/my_entity name:Fred"
+
+.. code-block::
+
+Populating Static Traits
+------------------------
+
+Populating traits is done in two steps:
+
+1. Writing a specific static trait in a trait description
+2. Populating the trait description to all targeted minions
+
+Synopsis of a trait description as follows:
+
+.. code-block:: text
+ :caption: Synopsis
+
+ :
+ [machine-id]:
+ - [list]
+ [hostname]:
+ - [list]
+ [traits]:
+ [key]: [value]
+ :
+ [key]: [value]
+
+ # Only for dynamic traits (functions)
+ [functions]:
+ - [list]
+
+For example, to make an alias for all Ubuntu running machines, the following valid trait description:
+
+.. code-block:: yaml
+ :caption: An alias to a system trait
+
+ # This is to select what minions should have
+ # the following traits assigned
+ query:
+ traits:
+ - system.os.kernel.version: 6.*
+
+ # Actual traits to be assigned
+ traits:
+ kernel: six
+
+Now it is possible to call all minions with any kernel of major version 6 like so:
+
+.. code-block:: bash
+ :caption: Target minions by own alias
+
+ sysinspect "my_model/my_entity kernel:six"
+
+The section ``functions`` is used for the dynamic traits, described below.
+
+Dynamic Traits
+--------------
+
+Dynamic traits are functions that are doing something on the machine. Since those functions
+are standalone executables, they do not accept any parameters. Functions are the same modules
+like any other modules and using the same protocol with the JSON format. The difference is that
+the module should return key/value structure. For example:
+
+.. code-block:: json
+
+ {
+ "key": "value",
+ }
+
+Example of using a custom module:
+
+.. code-block:: bash
+ :caption: File: ``my_trait.sh``
+
+ #!/usr/bin/bash
+ kernel=$(uname -r)
+ echo $(printf '{"kernel.release": "%s"}' $kernel)
+
+The output of this script is a JSON key/value structure:
+
+.. code-block:: json
+ :caption: Example output
+
+ {
+ "kernel.release": "5.19.0-50-generic"
+ }
+
+The function module must be portable, i.e. Minion has no responsibility to ensuring if the
+function module is actionable or not on a target system. I.e. user must ensure that the target
+system where the particular minion is running, should be equipped with Bash in ``/usr/bin``
+directory.
+
+Any modules that return non-zero return like system error more than ``1`` is simply ignored
+and error is logged.
+
+Populating Dynamic Traits
+-------------------------
+
+To populate dynamic trait there are three steps for this:
+
+1. Writing a specific trait in a Trait Description
+2. Placing the trait module to the file server so the minions can download it
+3. Populating the Trait Description to all targeted minions
+
+To write a specific trait in a Trait Description, the ``functions`` section must be specified.
+Example:
+
+.. code-block:: yaml
+
+ functions:
+ # Specify a relative path on the fileserver
+ - /functions/my_trait.sh
+
+The script ``my_trait.sh`` will be copied to ``$SYSINSPECT/functions``. When the minion starts,
+it will execute each function in alphabetical oder, read the JSON output and merge the result
+into the common traits tree. Then the traits tree will be synchronised with the Master.
+
+.. important::
+
+ While function traits are dynamic, they are still should be treated as static data.
+
+While function sounds dynamic, the trait is still an attribute :bi:`by which` a minion is queried.
+This means if the attribute will be different at every minion startup, it might be useless
+to target a minion by such attribute, unless it is matching to some regular expression. There
+might be a rare use cases, such as *"select minion or not, depending on its mood"* (because the
+function returns every time a different value), but generally this sort of dynamism is nearly
+outside of the scope of traits system.
\ No newline at end of file
diff --git a/docs/genusage/targeting.rst b/docs/genusage/targeting.rst
new file mode 100644
index 00000000..c8b1d99b
--- /dev/null
+++ b/docs/genusage/targeting.rst
@@ -0,0 +1,167 @@
+.. raw:: html
+
+
+
+.. role:: u
+ :class: underlined
+
+.. role:: bi
+ :class: bolditalic
+
+Targeting Entities
+==================
+
+.. note::
+
+ Entities are bound to the specific hardware, which is related to a specific minion.
+ This document explains how to target specific minions to complete entity description.
+
+General
+-------
+
+Sysinspect has a query mechanism where master can target remote minions by a specific
+criteria. Similarly, the Model itself can be called from different "entry points".
+
+**Checkbook**
+
+ A Checkbook is basically a list of "entry points" to a complex trees of entities,
+ essentially a group of entities that form a feature or a set of features to be checked.
+
+**Entities**
+
+ A regular Model entities. This type of entry is usually used to narrow down assessment
+ path.
+
+
+Checkbook query is using path-like tuples to target a feature (a group of entities etc)
+in the following format:
+
+.. code-block:: text
+ :caption: Precise model query synopsis
+
+ "model:///[entity]/[state] [traits query]"
+
+.. code-block:: text
+ :caption: Checkbook model query synopsis
+
+ "model:///[entity]:[checkbook labels]"
+
+Since there can be many models, it is essential to select one, therefore a model Id is
+always required. If ``entity`` and/or ``state`` are not specified, they are defaulted to
+``$`` (all).
+
+.. code-block:: bash
+ :caption: Example of Model targeting by precise query
+
+ sysinspect "model://router/network,devices/online"
+
+In the example above, a network is verified in a router only when it supposed to be online.
+Under the hood, omitted parts are translated to "all" (``$``). E.g. ``router/network`` is
+translated as ``router/network/$``, or Model name alone e.g. ``router`` is translated to
+``router/$/$`` etc.
+
+Traits query is separated with a space and essentially a list of possible traits with their
+values and logical operations. See :ref:`query_targeting` for more details.
+
+.. code-block:: bash
+ :caption: Example of Model targeting by checkbook labels
+
+ sysinspect "model://router:network,devices"
+
+The example above is the same as the previous one, except it is using Checkbook. Entities
+in the Checkbook are basically the top-high groups of other entities.
+
+Using Traits
+------------
+
+Every minion, running on the system can be targeted with specific criterion, describing it.
+Each :bi:`minion` has a set of attributes, called :ref:`systraits`. They are used to identify
+and target minions directly or from the Model.
+
+.. warning::
+
+ Using dynamic or static traits strongly depends on the use case of the Model. In terms of
+ portability, even though static traits are "hard-coding" claims, they are stable to the
+ system architecture. Likewise dynamic traits are move flexible, but they can also be more
+ difficult to debug, when they clash with each other.
+
+
+.. _query_targeting:
+
+Query Targeting
+---------------
+
+Additionally, traits can be incorporated in the query. The main use of traits are
+within the model, but sometimes one needs to target only a specific entity that has scope
+exclusively bound to a specific minion. In the nutshell, the idea is to filter-out other
+irrelevant minions, carrying *similar* entities.
+
+Synopsis of the query is as following:
+
+.. code-block:: text
+ :caption: Query synopsis
+
+ ...
+
+Query does not support grouping with `( ... )` parentheses and is read from left to right.
+Example:
+
+.. code-block:: bash
+
+ "system.os.vendor:Debian and system.os.arch:ARM64
+ or system.os.vendor:RHEL and system.os.arch:x86_64"
+
+The expression above is telling Sysinspect to target minions, those are:
+
+1. Running Linux Debian on ARM-64 architecture
+2. Running Linux RHEL on x86_64 architecture
+
+As it is very clear from the example above, the use of operators must be careful. Switch
+of them differently will cause different results. For example:
+
+.. code-block:: bash
+
+ "system.os.vendor:Debian or system.os.arch:ARM64
+ and system.os.vendor:RHEL or system.os.arch:x86_64"
+
+The expression above is telling Sysinspect to target minions, those are:
+
+1. Running Linux Debian
+2. Running Linux RHEL on x86_64 architecture
+3. Running on ARM-64 architecture
+
+
+Distributed Entity
+------------------
+
+.. warning::
+
+ ⚠️ Planned feature for future releases, not implemented yet.
+
+Some entities can be distributed across different boxes. For example, "Backup over WiFi"
+may involve a router, a WiFi antennae online and a storage with all disks in the RAID online.
+However, Sysinspect can query that feature directly by its label.
+
+The following synopsis of the distributed entity notation in Checkbook:
+
+.. code-block:: text
+
+ :
+ :
+
+For example, the use case of "Backup over WiFi" would be expressed the following way:
+
+.. code-block:: yaml
+
+ backup_over_wifi:
+ - antennae: 'status:online and freq_ghz:5' # Use of custom traits via functions
+ - raid: 'system.os.vendor:Debian and net.hostname:storage.local'
+ - router: 'system.os.mem:16GB and &raid' # References "raid" group by label
diff --git a/docs/global_config.rst b/docs/global_config.rst
index 03f55cde..900c54b0 100644
--- a/docs/global_config.rst
+++ b/docs/global_config.rst
@@ -1,34 +1,255 @@
+.. raw:: html
+
+
+
+.. role:: u
+ :class: underlined
+
+.. role:: bi
+ :class: bolditalic
+
+.. _configuration:
+
Configuration
=============
.. note::
- Configuration of Sysinspect
+ This document describes the configuration of Sysinspect system.
+
+Sysinspect can run in two modes:
-Setup
------
+- **Distributed Mode** using network-connected Minions, allowing many "boxes" to be subscribed
+ to a Master command center. This is a typical use.
+- **Solo Mode**, i.e. locally, only on the current local "box", affecting nothing else. This usage
+ is for a very small embedded systems only.
-Configuration files can be in three location and are searched in the following order:
+Config Location
+---------------
+
+Configuration files can be in three locations and are searched in the following order:
1. Current directory from which the app was launched: ``sysinspect.conf``.
2. "Dot-file" in the current user's home ``~/.sysinspect``
-3. As ``/etc/sysinspect.conf``.
+3. As ``/etc/sysinspect/sysinspect.conf``.
Synopsis
--------
-Configuration file supports the following format:
+Configuration is located under ``config`` section in a YAML file. This section
+has two important sub-sections:
-.. code-block:: text
- :caption: Configuration Synopsis
+- ``master`` for all settings of Sysinspect Master
+- ``minion`` for covering settings of Sysinspect Minion
- config:
- :
+Config Section
+--------------
+
+Main section of the entire configuration is ``config``. It is located at the root
+of the configuration file and contains the following directives:
``modules``
-^^^^^^^^^^^
-Section ``modules`` defines the root of built-in modules:
+ Path to location of the modules, used in the model and states. Default
+ value is ``/usr/share/sysinspect/modules`` according to the LSB standard.
+
+``master``
+
+ Sysinspect Master configuration.
+
+``minion``
+
+ Sysinspect Minion configuration.
+
+
+Master
+^^^^^^
+
+Sysinspect Master configuration is located under earlier mentioned ``master`` section,
+and contains the following directives:
+
+``socket``
+
+ Path for a FIFO socket to communicate with the ``sysinspect`` command,
+ which is issuing commands over the network.
+
+ Default value is ``/tmp/sysinspect-master.socket``.
+
+``bind.ip``
+
+ IPv4 address on which the Master is listening for all incoming and outgoing traffic
+ with Minion communication.
+
+ Default value is ``0.0.0.0``.
+
+``bind.port``
+
+ Network port number on which the Master is listening using ``bind.ip`` directive.
+
+ Sysinspect Master port is ``4200``.
+
+
+.. important::
+
+ Master runs a **File Server service**. This service is :bi:`very important` for all the minions,
+ as they are exchanging data with the master, by downloading all the required artefacts to be
+ processed on their targets.
+
+File Server service serves static data, which is continuously checked by each minion and updated,
+if that data changes. In particular, the artefacts are modules, trait configs, models, states etc.
+Typically, File Server service has the root of all the data in ``/etc/sysinspect/data``.
+
+.. warning::
+ Even though as of current version, there is no specific layout of the static data on the
+ File Server service to manager all the artifacts. However, this is a **subject to change**.
+
+Within the *"/data"* directory, *currently* one is free to organise the layout as they want.
+However, it is :bi:`strongly` advised to keep all the models, states and other artefacts
+separated from each other, using their own directories and namespaces. Future releases will have
+configurable default namespaces for each cathegory of the artefacts.
+
+Below are directives for the configuration of the File Server service:
+
+``fileserver.bind.ip``
+
+ Same as ``bind.ip``, but for the internal File Server service.
+
+``fileserver.bind.port``
+
+ Network port number on which the File Server service is listening.
+
+ File Server service port is ``4201``.
+
+``fileserver.models.root``
+
+ Relative path where are the master models kept.
+
+``fileserver.models``
+
+ List of subdirectories within ``fileserver.models.root``, exporting models. If a model is not
+ in the list, it will not be available for the minions.
+
+Example configuration for the Sysinspect Master:
+
+.. code-block:: yaml
+
+ config:
+ master:
+ socket: /tmp/sysinspect-master.socket
+ bind.ip: 0.0.0.0
+ bind.port: 4200
+
+ fileserver.bind.ip: 0.0.0.0
+ fileserver.bind.port: 4201
+
+ fileserver.models.root: /models
+ fileserver.models:
+ - my_model
+ - my_other_model
+
+
+Minion
+^^^^^^
+
+Sysinspect Minion configuration is located under earlier mentioned ``minion`` section,
+and contains the following directives:
+
+``root``
+
+ Typically, Minion if running standard, the root of all data kept by a Minion is
+ defaulted to ``/etc/sysinspect``, same as Master. However, in an embedded and custom
+ systems this might not be possible, especially if the system is usually read-only
+ and writable directories are limited to only a few. In this case *root* must be
+ set according to the system setup.
+
+``master.ip``
+
+ Corresponds to ``bind.ip`` of Master node and should be identical.
+
+``master.port``
+
+ Corresponds to ``bind.ip.port`` of Master node and should be identical.
+
+Example configuration for the Sysinspect Minion:
.. code-block:: yaml
- modules: /opt/sysinspect/modules
+ config:
+ minion:
+ # Root directory where minion keeps all data.
+ # Default: /etc/sysinspect — same as for master
+ root: /etc/sysinspect
+ master.ip: 192.168.2.31
+ master.port: 4200
+
+Layout of ``/etc/sysinspect``
+-----------------------------
+
+Ideally, both Master and Minion have the same location of configuration and data collection,
+which is defaulted to ``/etc/sysinspect``. This directory has many objects stored and has
+a specific structure and purpose. For more making paths more short, this directory will be
+referred as ``$SR`` *(Sysinspect Root)*.
+
+Common
+^^^^^^
+
+There are directories that are same on both Master and Minion:
+
+``$SR/functions``
+
+ Directory, containing custom trait functions. They are meant to be defined on the Master side
+ and then sync'ed to all the minions.
+
+Only on Master
+^^^^^^^^^^^^^^
+
+Public and private RSA keys of Master are:
+
+``$SR/master.rsa``
+
+ Master's private RSA key.
+
+``$SR/master.rsa.pub``
+
+ Master's public RSA key.
+
+``$SR/minion-keys``
+
+ Public keys from registered minions in format ``.rsa.pub``.
+
+ Each registered minion has its own Id. Typically it is ``/etc/machine-id`` or automatically
+ generated one, if this file does not exist.
+
+``$SR/minion-registry``
+
+ A binary cache of minion's data, such as minion traits, data about currently connected minions etc.
+ This is fully purge-able directory, i.e. data can be freely deleted. However, Sysinspect Master
+ needs to be restarted and all minions needs to reconnect.
+
+Only on Minion
+^^^^^^^^^^^^^^
+
+Public and private RSA keys of Master are:
+
+``$SR/master.rsa``
+
+ Minion's private RSA key.
+
+``$SR/master.rsa.pub``
+
+ Minion's public RSA key.
+
+``$SR/traits``
+
+ Directory, containing custom static traits of a Minion.
+
+``$SR/models``
+
+ Directory, containing models.
diff --git a/docs/index.rst b/docs/index.rst
index 9dbf824a..4e96438f 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -9,6 +9,7 @@ Welcome to the Project Sysinspect!
:maxdepth: 1
global_config
+ genusage/overview
modeldescr/overview
moddev/overview
moddescr/overview
diff --git a/docs/modeldescr/overview.rst b/docs/modeldescr/overview.rst
index 9052ac2c..6b630176 100644
--- a/docs/modeldescr/overview.rst
+++ b/docs/modeldescr/overview.rst
@@ -4,6 +4,8 @@ Model Description
.. note::
Document explains the Model Definition and its components.
+.. _model_description:
+
The Model is essentially a configuration of a system. It is written in YAML format,
and it is following a specific expression schema and logic.
diff --git a/libsysinspect/Cargo.toml b/libsysinspect/Cargo.toml
index 6c2477a4..8185bdf8 100644
--- a/libsysinspect/Cargo.toml
+++ b/libsysinspect/Cargo.toml
@@ -4,17 +4,28 @@ version = "0.2.0"
edition = "2021"
[dependencies]
+base64 = "0.22.1"
chrono = "0.4.38"
colored = "2.1.0"
-indexmap = "2.6.0"
+hex = "0.4.3"
+indexmap = { version = "2.6.0", features = ["serde"] }
lazy_static = "1.5.0"
log = "0.4.22"
nix = { version = "0.29.0", features = ["net", "user"] }
+once_cell = "1.20.2"
+pem = "3.0.4"
+pest = "2.7.14"
+pest_derive = "2.7.14"
prettytable-rs = "0.10.0"
+rand = "0.8.5"
regex = "1.10.6"
+rsa = { version = "0.9.6", features = ["pkcs5", "sha1", "sha2"] }
serde = { version = "1.0.210", features = ["derive"] }
serde_json = "1.0.128"
serde_yaml = "0.9.34"
+sha2 = "0.10.8"
+sysinfo = { version = "0.32.0", features = ["linux-tmpfs"] }
textwrap = { version = "0.16.1", features = ["hyphenation", "terminal_size"] }
+tokio = { version = "1.41.1", features = ["full"] }
unicode-segmentation = "1.12.0"
walkdir = "2.5.0"
diff --git a/libsysinspect/src/cfg/mmconf.rs b/libsysinspect/src/cfg/mmconf.rs
new file mode 100644
index 00000000..e508c218
--- /dev/null
+++ b/libsysinspect/src/cfg/mmconf.rs
@@ -0,0 +1,189 @@
+use crate::{intp::functions::get_by_namespace, SysinspectError};
+use serde::{Deserialize, Serialize};
+use serde_yaml::{from_str, from_value, Value};
+use std::{fs, path::PathBuf};
+
+// Network
+pub static DEFAULT_ADDR: &str = "0.0.0.0";
+pub static DEFAULT_PORT: u32 = 4200;
+pub static DEFAULT_FILESERVER_PORT: u32 = 4201;
+
+// Default directories
+pub static DEFAULT_SOCKET: &str = "/var/run/sysinspect-master.socket";
+pub static DEFAULT_SYSINSPECT_ROOT: &str = "/etc/sysinspect";
+pub static DEFAULT_MODULES_ROOT: &str = "/usr/share/sysinspect/modules";
+
+// All directories are relative to the sysinspect root
+pub static CFG_MINION_KEYS: &str = "minion-keys";
+pub static CFG_MINION_REGISTRY: &str = "minion-registry";
+pub static CFG_FILESERVER_ROOT: &str = "data";
+pub static CFG_MODELS_ROOT: &str = "models";
+pub static CFG_TRAITS_ROOT: &str = "traits";
+pub static CFG_TRAIT_FUNCTIONS_ROOT: &str = "functions";
+pub static CFG_DB: &str = "registry";
+
+// Key names
+pub static CFG_MASTER_KEY_PUB: &str = "master.rsa.pub";
+pub static CFG_MASTER_KEY_PRI: &str = "master.rsa";
+pub static CFG_MINION_RSA_PUB: &str = "minion.rsa.pub";
+pub static CFG_MINION_RSA_PRV: &str = "minion.rsa";
+
+#[derive(Debug, Serialize, Deserialize, Default, Clone)]
+pub struct MinionConfig {
+ /// Root directory where minion keeps all data.
+ /// Default: /etc/sysinspect — same as for master
+ root: Option,
+
+ /// IP address of Master
+ #[serde(rename = "master.ip")]
+ master_ip: String,
+
+ /// Port of Master. Default: 4200
+ #[serde(rename = "master.port")]
+ master_port: Option,
+
+ /// Port of Master's fileserver. Default: 4201
+ #[serde(rename = "master.fileserver.port")]
+ master_fileserver_port: Option,
+}
+
+impl MinionConfig {
+ pub fn new(p: PathBuf) -> Result {
+ let cp = p.as_os_str().to_str().unwrap_or_default();
+ if !p.exists() {
+ return Err(SysinspectError::ConfigError(format!("File not found: {}", cp)));
+ }
+
+ if let Some(cfgv) = get_by_namespace(Some(from_str::(&fs::read_to_string(&p)?)?), "config.minion") {
+ return Ok(from_value::(cfgv)?);
+ }
+
+ Err(SysinspectError::ConfigError(format!("Unable to read config at: {}", cp)))
+ }
+
+ /// Return master addr
+ pub fn master(&self) -> String {
+ format!("{}:{}", self.master_ip, self.master_port.unwrap_or(DEFAULT_PORT))
+ }
+
+ /// Return master fileserver addr
+ pub fn fileserver(&self) -> String {
+ format!("{}:{}", self.master_ip, self.master_fileserver_port.unwrap_or(DEFAULT_FILESERVER_PORT))
+ }
+
+ /// Get minion root directory
+ pub fn root_dir(&self) -> PathBuf {
+ PathBuf::from(self.root.clone().unwrap_or(DEFAULT_SYSINSPECT_ROOT.to_string()))
+ }
+
+ /// Get root directory for models
+ pub fn models_dir(&self) -> PathBuf {
+ self.root_dir().join(CFG_MODELS_ROOT)
+ }
+ /// Get root directory for functions
+ pub fn functions_dir(&self) -> PathBuf {
+ self.root_dir().join(CFG_TRAIT_FUNCTIONS_ROOT)
+ }
+
+ /// Get root directory for drop-in traits
+ pub fn traits_dir(&self) -> PathBuf {
+ self.root_dir().join(CFG_TRAITS_ROOT)
+ }
+}
+
+#[derive(Debug, Serialize, Deserialize, Default, Clone)]
+pub struct MasterConfig {
+ // Bind IP listener. Default "the world", i.e. 0.0.0.0
+ #[serde(rename = "bind.ip")]
+ bind_ip: Option,
+
+ // Bind port. Default 4200
+ #[serde(rename = "bind.port")]
+ bind_port: Option,
+
+ // Path to FIFO socket. Default: /var/run/sysinspect-master.socket
+ socket: Option,
+
+ #[serde(rename = "fileserver.bind.ip")]
+ fsr_ip: Option,
+
+ #[serde(rename = "fileserver.bind.port")]
+ fsr_port: Option,
+
+ // Exported models path root on the fileserver
+ #[serde(rename = "fileserver.models.root")]
+ fsr_models_root: String,
+
+ // Exported models on the fileserver
+ #[serde(rename = "fileserver.models")]
+ fsr_models: Vec,
+}
+
+impl MasterConfig {
+ pub fn new(p: PathBuf) -> Result {
+ let cp = p.as_os_str().to_str().unwrap_or_default();
+ if !p.exists() {
+ return Err(SysinspectError::ConfigError(format!("File not found: {}", cp)));
+ }
+
+ if let Some(cfgv) = get_by_namespace(Some(from_str::(&fs::read_to_string(&p)?)?), "config.master") {
+ return Ok(from_value::(cfgv)?);
+ }
+
+ Err(SysinspectError::ConfigError(format!("Unable to read config at: {}", cp)))
+ }
+
+ /// Return master addr
+ pub fn bind_addr(&self) -> String {
+ format!("{}:{}", self.bind_ip.to_owned().unwrap_or(DEFAULT_ADDR.to_string()), self.bind_port.unwrap_or(DEFAULT_PORT))
+ }
+
+ /// Get socket address
+ pub fn socket(&self) -> String {
+ self.socket.to_owned().unwrap_or(DEFAULT_SOCKET.to_string())
+ }
+
+ /// Return fileserver addr
+ pub fn fileserver_bind_addr(&self) -> String {
+ format!(
+ "{}:{}",
+ self.fsr_ip.to_owned().unwrap_or(DEFAULT_ADDR.to_string()),
+ self.fsr_port.unwrap_or(DEFAULT_FILESERVER_PORT)
+ )
+ }
+
+ /// Get a list of exported models from the fileserver
+ pub fn fileserver_models(&self) -> &Vec {
+ &self.fsr_models
+ }
+
+ /// Get fileserver root
+ pub fn fileserver_root(&self) -> PathBuf {
+ self.root_dir().join(CFG_FILESERVER_ROOT)
+ }
+
+ /// Get models root on the fileserver
+ pub fn fileserver_mdl_root(&self, alone: bool) -> PathBuf {
+ let mr = PathBuf::from(&self.fsr_models_root.strip_prefix("/").unwrap_or_default());
+ if alone {
+ mr
+ } else {
+ self.fileserver_root().join(mr)
+ }
+ }
+
+ /// Get default sysinspect root. For master it is always /etc/sysinspect
+ pub fn root_dir(&self) -> PathBuf {
+ PathBuf::from(DEFAULT_SYSINSPECT_ROOT.to_string())
+ }
+
+ /// Get minion keys store
+ pub fn keyman_root(&self) -> PathBuf {
+ self.root_dir().join(CFG_MINION_KEYS)
+ }
+
+ /// Get minion registry
+ pub fn minion_registry_root(&self) -> PathBuf {
+ self.root_dir().join(CFG_MINION_REGISTRY)
+ }
+}
diff --git a/libsysinspect/src/cfg/mod.rs b/libsysinspect/src/cfg/mod.rs
new file mode 100644
index 00000000..c5de2349
--- /dev/null
+++ b/libsysinspect/src/cfg/mod.rs
@@ -0,0 +1,52 @@
+/*
+Config reader
+ */
+
+pub mod mmconf;
+
+use crate::SysinspectError;
+use nix::unistd::Uid;
+use std::{env, path::PathBuf};
+
+pub const APP_CONF: &str = "sysinspect.conf";
+pub const APP_DOTCONF: &str = ".sysinspect";
+pub const APP_HOME: &str = "/etc/sysinspect";
+
+/// Select app conf
+pub fn select_config(p: Option) -> Result {
+ // Override path from options
+ if let Some(ovrp) = p {
+ let ovrp = PathBuf::from(ovrp);
+ if ovrp.exists() {
+ return Ok(ovrp);
+ }
+ }
+
+ // Current
+ let cfp: PathBuf = env::current_dir()?.canonicalize()?.join(APP_CONF);
+ if cfp.exists() {
+ return Ok(cfp);
+ }
+
+ // Dot-file
+ let cfp = env::var_os("HOME").map(PathBuf::from).or_else(|| {
+ #[cfg(unix)]
+ {
+ Some(PathBuf::from(format!("/home/{}", Uid::current())))
+ }
+ });
+ if let Some(cfp) = cfp {
+ let cfp = cfp.join(APP_DOTCONF);
+ if cfp.exists() {
+ return Ok(cfp);
+ }
+ }
+
+ // Global conf
+ let cfp = PathBuf::from(format!("{APP_HOME}/{APP_CONF}"));
+ if cfp.exists() {
+ return Ok(cfp);
+ }
+
+ Err(SysinspectError::ConfigError("No config has been found".to_string()))
+}
diff --git a/libsysinspect/src/inspector.rs b/libsysinspect/src/inspector.rs
new file mode 100644
index 00000000..f212843b
--- /dev/null
+++ b/libsysinspect/src/inspector.rs
@@ -0,0 +1,86 @@
+use crate::{
+ intp::{self, inspector::SysInspector},
+ mdescr::mspec,
+ reactor::evtproc::EventProcessor,
+};
+use intp::actproc::response::ActionResponse;
+
+#[derive(Debug, Default)]
+pub struct SysInspectRunner {
+ model_pth: String,
+ state: Option,
+ entities: Vec,
+
+ // Check book labels
+ cb_labels: Vec,
+}
+
+impl SysInspectRunner {
+ pub fn new() -> SysInspectRunner {
+ SysInspectRunner { ..Default::default() }
+ }
+
+ /// Set model path
+ pub fn set_model_path(&mut self, p: &str) {
+ self.model_pth = p.to_string()
+ }
+
+ /// Set process state
+ pub fn set_state(&mut self, state: Option) {
+ self.state = state;
+ }
+
+ /// Set entities to query
+ pub fn set_entities(&mut self, entities: Vec) {
+ self.entities = entities;
+ }
+
+ /// Set checkbook labels
+ pub fn set_checkbook_labels(&mut self, labels: Vec) {
+ self.cb_labels = labels;
+ }
+
+ pub fn start(&self) {
+ log::info!("Starting sysinspect runner");
+ match mspec::load(&self.model_pth) {
+ Ok(spec) => {
+ log::debug!("Initalising inspector");
+ match SysInspector::new(spec) {
+ Ok(isp) => {
+ // Setup event processor
+ let mut evtproc = EventProcessor::new().set_config(isp.cfg());
+
+ let actions = if !self.cb_labels.is_empty() {
+ isp.actions_by_relations(self.cb_labels.to_owned(), self.state.to_owned())
+ } else {
+ isp.actions_by_entities(self.entities.to_owned(), self.state.to_owned())
+ };
+
+ match actions {
+ Ok(actions) => {
+ for ac in actions {
+ match ac.run() {
+ Ok(response) => {
+ let response = response.unwrap_or(ActionResponse::default());
+ evtproc.receiver().register(response.eid().to_owned(), response);
+ }
+ Err(err) => {
+ log::error!("{err}")
+ }
+ }
+ }
+ evtproc.process();
+ }
+ Err(err) => {
+ log::error!("{}", err);
+ }
+ }
+ }
+ Err(err) => log::error!("{err}"),
+ }
+ log::debug!("Done");
+ }
+ Err(err) => log::error!("Error loading mspec: {}", err),
+ };
+ }
+}
diff --git a/libsysinspect/src/intp/README.txt b/libsysinspect/src/intp/README.txt
new file mode 100644
index 00000000..cf08bd8c
--- /dev/null
+++ b/libsysinspect/src/intp/README.txt
@@ -0,0 +1 @@
+Package interpreting module spec (runtime)
\ No newline at end of file
diff --git a/libsysinspect/src/intp/conf.rs b/libsysinspect/src/intp/conf.rs
index c34362a5..85e04ca7 100644
--- a/libsysinspect/src/intp/conf.rs
+++ b/libsysinspect/src/intp/conf.rs
@@ -1,4 +1,4 @@
-use crate::{util, SysinspectError};
+use crate::{cfg::mmconf::DEFAULT_MODULES_ROOT, util, SysinspectError};
use serde::{Deserialize, Serialize};
use serde_yaml::Value;
use std::{collections::HashMap, path::PathBuf};
@@ -69,7 +69,7 @@ impl EventConfig {
/// The entire config
#[derive(Debug, Serialize, Deserialize, Clone, Default)]
pub struct Config {
- modules: PathBuf,
+ modules: Option,
// EventId to config, added later
events: Option>,
@@ -87,7 +87,7 @@ impl Config {
/// Get module from the namespace
pub fn get_module(&self, namespace: &str) -> Result {
// Fool-proof cleanup, likely a bad idea
- let modpath = self.modules.join(
+ let modpath = &self.modules.to_owned().unwrap_or(PathBuf::from(DEFAULT_MODULES_ROOT)).join(
namespace
.trim_start_matches('.')
.trim_end_matches('.')
@@ -102,7 +102,7 @@ impl Config {
return Err(SysinspectError::ModuleError(format!("Module \"{}\" was not found at {:?}", namespace, modpath)));
}
- Ok(modpath)
+ Ok(modpath.to_owned())
}
/// Set events config
diff --git a/libsysinspect/src/lib.rs b/libsysinspect/src/lib.rs
index 6883283c..80aa2476 100644
--- a/libsysinspect/src/lib.rs
+++ b/libsysinspect/src/lib.rs
@@ -1,16 +1,22 @@
use std::{
error::Error,
+ ffi::NulError,
fmt::{Display, Formatter, Result},
io,
};
use mdescr::mspec;
+pub mod cfg;
+pub mod inspector;
pub mod intp;
pub mod logger;
pub mod mdescr;
pub mod modlib;
+pub mod proto;
pub mod reactor;
+pub mod rsa;
+pub mod traits;
pub mod util;
#[derive(Debug)]
@@ -20,11 +26,17 @@ pub enum SysinspectError {
ModelDSLError(String),
ModuleError(String),
ConfigError(String),
+ MasterGeneralError(String),
+ MinionGeneralError(String),
+ ProtoError(String),
// Wrappers for the system errors
IoErr(io::Error),
SerdeYaml(serde_yaml::Error),
SerdeJson(serde_json::Error),
+ FFINullError(NulError),
+ DynError(Box),
+ AsynDynError(Box),
}
impl Error for SysinspectError {
@@ -48,6 +60,12 @@ impl Display for SysinspectError {
SysinspectError::ModelDSLError(err) => format!("(DSL) {err}"),
SysinspectError::ModuleError(err) => format!("(Module) {err}"),
SysinspectError::ConfigError(err) => format!("(Config) {err}"),
+ SysinspectError::FFINullError(err) => format!("(System) {err}"),
+ SysinspectError::MasterGeneralError(err) => format!("(Master) {err}"),
+ SysinspectError::MinionGeneralError(err) => format!("(Minion) {err}"),
+ SysinspectError::ProtoError(err) => format!("(Protocol) {err}"),
+ SysinspectError::DynError(err) => format!("(General) {err}"),
+ SysinspectError::AsynDynError(err) => format!("(General part) {err}"),
};
write!(f, "{msg}")?;
@@ -75,3 +93,23 @@ impl From for SysinspectError {
SysinspectError::SerdeJson(err)
}
}
+
+/// Handle FFI Nul error
+impl From for SysinspectError {
+ fn from(err: NulError) -> Self {
+ SysinspectError::FFINullError(err)
+ }
+}
+
+// Implement From> for SysinspectError
+impl From> for SysinspectError {
+ fn from(err: Box) -> SysinspectError {
+ SysinspectError::DynError(err)
+ }
+}
+
+impl From> for SysinspectError {
+ fn from(err: Box) -> SysinspectError {
+ SysinspectError::DynError(err)
+ }
+}
diff --git a/libsysinspect/src/mdescr/README.txt b/libsysinspect/src/mdescr/README.txt
new file mode 100644
index 00000000..2d79db6f
--- /dev/null
+++ b/libsysinspect/src/mdescr/README.txt
@@ -0,0 +1 @@
+Package to work with the model spec (before actual runtime)
\ No newline at end of file
diff --git a/libsysinspect/src/mdescr/mspec.rs b/libsysinspect/src/mdescr/mspec.rs
index 7faeea95..755ed7a2 100644
--- a/libsysinspect/src/mdescr/mspec.rs
+++ b/libsysinspect/src/mdescr/mspec.rs
@@ -1,9 +1,7 @@
use super::{datapatch, mspecdef::ModelSpec};
-use crate::SysinspectError;
-use nix::unistd::Uid;
+use crate::{cfg::select_config, SysinspectError};
use serde_yaml::Value;
use std::{
- env::{self},
fs::{self},
path::{Path, PathBuf},
};
@@ -11,8 +9,6 @@ use walkdir::WalkDir;
pub const MODEL_INDEX: &str = "model.cfg";
pub const MODEL_FILE_EXT: &str = ".cfg";
-pub const APP_CONF: &str = "sysinspect.conf";
-pub const APP_DOTCONF: &str = ".sysinspect";
/// Spec loader object
struct SpecLoader {
@@ -70,7 +66,6 @@ impl SpecLoader {
fn merge_parts(&mut self, chunks: &mut Vec) -> Result {
if chunks.is_empty() {
return Err(SysinspectError::ModelMultipleIndex("No data found".to_string()));
- // XXX: Add one more exception
}
let mut base = chunks.remove(0);
@@ -104,37 +99,6 @@ impl SpecLoader {
Ok(base)
}
- /// Select app conf
- fn select_config(&self) -> Result {
- // Current
- let cfp: PathBuf = env::current_dir()?.canonicalize()?.join(APP_CONF);
- if cfp.exists() {
- return Ok(cfp);
- }
-
- // Dot-file
- let cfp = env::var_os("HOME").map(PathBuf::from).or_else(|| {
- #[cfg(unix)]
- {
- Some(PathBuf::from(format!("/home/{}", Uid::current())))
- }
- });
- if let Some(cfp) = cfp {
- let cfp = cfp.join(APP_DOTCONF);
- if cfp.exists() {
- return Ok(cfp);
- }
- }
-
- // Global conf
- let cfp = PathBuf::from(format!("/etc/{}", APP_CONF));
- if cfp.exists() {
- return Ok(cfp);
- }
-
- Err(SysinspectError::ConfigError("No config has been found".to_string()))
- }
-
/// Load model spec by merging all the data parts and validating
/// its content.
fn load(&mut self) -> Result {
@@ -157,7 +121,7 @@ impl SpecLoader {
}
// Load app config and merge to the main model
- base.push(serde_yaml::from_str::(&fs::read_to_string(self.select_config()?)?)?);
+ base.push(serde_yaml::from_str::(&fs::read_to_string(select_config(None)?)?)?);
let mut base = self.merge_parts(&mut base)?;
if !iht.is_empty() {
diff --git a/libsysinspect/src/modlib/README.txt b/libsysinspect/src/modlib/README.txt
new file mode 100644
index 00000000..fc766f85
--- /dev/null
+++ b/libsysinspect/src/modlib/README.txt
@@ -0,0 +1 @@
+Package to work with the external inspection modules.
\ No newline at end of file
diff --git a/libsysinspect/src/proto/README.md b/libsysinspect/src/proto/README.md
new file mode 100644
index 00000000..6cf345c5
--- /dev/null
+++ b/libsysinspect/src/proto/README.md
@@ -0,0 +1,176 @@
+# Master/minion protocol
+
+Protocol description about message exchange between master and a minion.
+
+## Message Structure
+
+### Master message structure
+
+The following is a message structure for a master:
+
+```json
+{
+ // Target Destinations
+ "t": [],
+
+ // Request Type
+ "r": "",
+
+ // Payload Data in base64 (anything)
+ "d": "",
+
+ // Return code int
+ "c": 0,
+}
+```
+
+The following types for "`r`" are available:
+
+- `add` — Minion registration request. Payload contains an RSA public key of a master.
+- `cmd` — A regular command to a minion(s).
+- `tr` — Request to return all minion traits for the database sync (payload is empty)
+or push new (payload exists). This must be used together with the targeting.
+- `rm` — Minion un-registration.
+
+## Targeting
+
+Type `t` (target) is a list of target structures. A target structure can target minions
+by the following criterias:
+
+1. Hostnames with UNIX type globbing. E.g.: `web*.com`.
+2. Machine Id
+3. Traits (any)
+
+### Target Structure
+
+```json
+{
+ // Trait Targeted traits
+ "t": {},
+
+ // Minion Id List of minion Ids
+ "id": [],
+
+ // Hostnames List of minion hostnames
+ "h": [],
+}
+```
+
+Example targeting by an IPv4 trait, using globbing:
+
+```json
+{
+ "t": {"system.net.*.ipv4": "192.168.*"},
+}
+```
+
+Example targeting by an Id:
+
+```json
+{
+ "id": "30006546535e428aba0a0caa6712e225",
+}
+```
+
+Example targeting by hosts, starting their domain names as "web":
+
+```json
+{
+ "h": "web*",
+}
+```
+
+Example targeting all minions:
+
+```json
+{
+ "h": ["*"],
+}
+```
+
+### Minion message structure
+
+The following is a message structure for a minion:
+
+```json
+{
+ // Id Machine id or pre-generated equivalent if none
+ "id": "",
+
+ // Request Type
+ "r": "",
+
+ // Payload Data in base64 (anything)
+ "d": "",
+
+ // Return code int
+ "c": 0,
+}
+```
+
+The following request types for "`r`" are available:
+
+- `add` — Minion registration context. Payload contains nothing.
+ In this case Master responds with `add` request, containing its RSA public key.
+ A Minion needs to accept it by a fingerprint.
+
+- `rsp` — A regular response to any command.
+- `ehlo` — Hello notice for a newly connected minion (any). Contains Minion Id RSA cipher.
+
+## Types
+
+### Request/Response
+
+- `add` — Add a minion, registration request.
+- `rm` — Remove a minion, un-registration.
+- `rsp` — Regular response to any Master command.
+- `cmd` — Regular command to any Minion.
+- `tr` — Request to return all minion traits.
+- `ehlo` — Hello message to initiate protocol.
+- `retry` — Retry connect (e.g. after the registration).
+- `pi` — Ping request.
+- `po` — Pong response.
+- `undef` — Unknown agent.
+
+### Return Codes
+
+- `Undef`: 0 — No specific return code or code is ignorable.
+- `Success`: 1 — Successfully completed the routine.
+- `GeneralFailure`: 2 — General failure, unspecified. Equal to 1 of POSIX.
+- `NotRegistered`: 3 — Minion is not registered. Registration sequence required.
+- `AlreadyRegistered`: 4 — Minion is already registered.
+- `AlreadyConnected`: 5 — Minion connection duplicate.
+- `Unknown`: N/A — Internal designator of unrecognised incoming error code.
+
+## Hello (ehlo)
+
+This sequence requires no established connection.
+
+1. Master listens.
+2. Minion sends type `ehlo` request with no payload.
+3. Master checks if the Id is registered.
+4. In case there is no Id registered, Master responds with the error code and kills
+the connection.
+5. Master responds with a non-zero return code, mapped to a successful connection.
+
+## Minion Registration Sequence
+
+This sequence requires no established connection.
+
+1. Master listens.
+2. Minion sends a request type `add` with an empty payload.
+3. Master checks if the Id is registered.
+4. In case there is an Id registered, Master responds with the error code and kills
+the connection, awaiting `ehlo` instead.
+5. Master sends type `add` response with RSA public key.
+6. Minion accepts the key, storing it and responds with type `ehlo`, containing own
+Id within RSA cipher, using Master's public key.
+7. Master responds with a non-zero return code, mapped to a successful connection.
+
+## Minion Call
+
+This sequence requires established successful connection.
+
+1. Master broadcasts type `cmd` to all minions with the destination mask.
+2. Each minion accepts the message and looks if a target matches it.
+3. Each Minion responds back with type `rsp`.
diff --git a/libsysinspect/src/proto/errcodes.rs b/libsysinspect/src/proto/errcodes.rs
new file mode 100644
index 00000000..68f75a63
--- /dev/null
+++ b/libsysinspect/src/proto/errcodes.rs
@@ -0,0 +1,25 @@
+use serde::{Deserialize, Serialize};
+
+#[derive(Serialize, Deserialize, Debug, Clone)]
+pub enum ProtoErrorCode {
+ /// No code
+ Undef = 0,
+
+ /// Successfully completed
+ Success = 1,
+
+ /// General unspecified failure
+ GeneralFailure = 2,
+
+ /// Minion is not registered
+ NotRegistered = 3,
+
+ /// Minion is already registered
+ AlreadyRegistered = 4,
+
+ /// Minion is already connected
+ AlreadyConnected = 5,
+
+ /// Unassigned, unknown
+ Unknown,
+}
diff --git a/libsysinspect/src/proto/mod.rs b/libsysinspect/src/proto/mod.rs
new file mode 100644
index 00000000..de9d9fc1
--- /dev/null
+++ b/libsysinspect/src/proto/mod.rs
@@ -0,0 +1,219 @@
+pub mod errcodes;
+pub mod payload;
+pub mod query;
+pub mod rqtypes;
+
+use crate::SysinspectError;
+use errcodes::ProtoErrorCode;
+use rqtypes::RequestType;
+use serde::{de::DeserializeOwned, Deserialize, Serialize};
+use serde_json::Value;
+
+/// Master message
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct MasterMessage {
+ #[serde(rename = "t")]
+ target: MinionTarget,
+
+ #[serde(rename = "r")]
+ request: RequestType,
+
+ #[serde(rename = "d")]
+ data: Value,
+
+ #[serde(rename = "c")]
+ retcode: usize,
+}
+
+impl MasterMessage {
+ /// Master message constructor
+ pub fn new(rtype: RequestType, data: Value) -> MasterMessage {
+ MasterMessage { target: Default::default(), request: rtype, data, retcode: ProtoErrorCode::Undef as usize }
+ }
+
+ /// Add a target.
+ pub fn set_target(&mut self, t: MinionTarget) {
+ self.target = t;
+ }
+
+ /// Set return code
+ pub fn set_retcode(&mut self, retcode: ProtoErrorCode) {
+ self.retcode = retcode as usize;
+ }
+
+ /// Get return code
+ pub fn get_retcode(&self) -> ProtoErrorCode {
+ match &self.retcode {
+ 0 => ProtoErrorCode::Undef,
+ 1 => ProtoErrorCode::Success,
+ 2 => ProtoErrorCode::GeneralFailure,
+ 3 => ProtoErrorCode::NotRegistered,
+ 4 => ProtoErrorCode::AlreadyRegistered,
+ 5 => ProtoErrorCode::AlreadyConnected,
+ _ => ProtoErrorCode::Unknown,
+ }
+ }
+
+ /// Request type
+ pub fn req_type(&self) -> &RequestType {
+ &self.request
+ }
+
+ /// Get payload
+ pub fn payload(&self) -> &Value {
+ &self.data
+ }
+
+ /// Get targeting means
+ pub fn get_target(&self) -> &MinionTarget {
+ &self.target
+ }
+}
+
+/// Minion message
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct MinionMessage {
+ id: String,
+ sid: String, // Temporary session Id
+
+ #[serde(rename = "r")]
+ request: RequestType,
+
+ #[serde(rename = "d")]
+ data: String,
+
+ #[serde(rename = "c")]
+ retcode: usize,
+}
+
+impl MinionMessage {
+ /// Message constructor
+ pub fn new(id: String, rtype: RequestType, data: String) -> MinionMessage {
+ MinionMessage { id, request: rtype, data, retcode: ProtoErrorCode::Undef as usize, sid: "".to_string() }
+ }
+
+ /// Set return code
+ pub fn set_retcode(&mut self, retcode: ProtoErrorCode) {
+ self.retcode = retcode as usize;
+ }
+
+ /// Get return code
+ pub fn get_retcode(&self) -> ProtoErrorCode {
+ match &self.retcode {
+ 0 => ProtoErrorCode::Undef,
+ 1 => ProtoErrorCode::Success,
+ 2 => ProtoErrorCode::GeneralFailure,
+ 3 => ProtoErrorCode::NotRegistered,
+ 4 => ProtoErrorCode::AlreadyRegistered,
+ 5 => ProtoErrorCode::AlreadyConnected,
+ _ => ProtoErrorCode::Unknown,
+ }
+ }
+
+ /// Set Session Id
+ pub fn set_sid(&mut self, sid: String) {
+ self.sid = sid
+ }
+
+ /// Request type
+ pub fn req_type(&self) -> &RequestType {
+ &self.request
+ }
+
+ /// Get minion Id
+ pub fn id(&self) -> &str {
+ &self.id
+ }
+
+ /// Get payload
+ pub fn payload(&self) -> &str {
+ &self.data
+ }
+}
+
+/// Minion target
+#[derive(Debug, Clone, Serialize, Deserialize, Default)]
+pub struct MinionTarget {
+ /// List of minion Ids
+ id: String,
+
+ /// Session Id
+ sid: String, // XXX: Should be gone
+
+ /// Scheme to call (model:// or state://)
+ #[serde(rename = "s")]
+ scheme: String,
+
+ /// Traits query that needs to be parsed at Minion
+ #[serde(rename = "qt")]
+ traits_query: String,
+
+ #[serde(rename = "h")]
+ hostnames: Vec,
+}
+
+impl MinionTarget {
+ pub fn new(mid: &str, sid: &str) -> MinionTarget {
+ MinionTarget { id: mid.to_string(), sid: sid.to_string(), ..Default::default() }
+ }
+
+ /// Add hostnames
+ pub fn add_hostname(&mut self, hostname: &str) {
+ self.hostnames.push(hostname.to_string());
+ }
+
+ pub fn id(&self) -> &String {
+ &self.id
+ }
+
+ pub fn sid(&self) -> &String {
+ &self.sid
+ }
+
+ pub fn hostnames(&self) -> &Vec {
+ &self.hostnames
+ }
+
+ /// Get scheme
+ pub fn scheme(&self) -> &String {
+ &self.scheme
+ }
+
+ /// Set scheme
+ pub fn set_scheme(&mut self, scheme: &str) {
+ self.scheme = scheme.to_string();
+ }
+
+ /// Set traits query
+ pub fn set_traits_query(&mut self, traits: &str) {
+ self.traits_query = traits.to_string();
+ }
+
+ /// Traits query itself.
+ pub fn traits_query(&self) -> &String {
+ &self.traits_query
+ }
+}
+
+pub trait ProtoConversion: Serialize + DeserializeOwned {
+ fn serialise(&self) -> Result;
+ fn sendable(&self) -> Result, SysinspectError>;
+}
+
+impl ProtoConversion for T
+where
+ T: Serialize + DeserializeOwned,
+{
+ /// Serialise self
+ fn serialise(&self) -> Result {
+ match serde_json::to_string(self) {
+ Ok(out) => Ok(out),
+ Err(err) => Err(SysinspectError::MinionGeneralError(format!("{err}"))),
+ }
+ }
+
+ /// Serialise self to bytes
+ fn sendable(&self) -> Result, SysinspectError> {
+ Ok(self.serialise()?.as_bytes().to_vec())
+ }
+}
diff --git a/libsysinspect/src/proto/payload.rs b/libsysinspect/src/proto/payload.rs
new file mode 100644
index 00000000..09ab9924
--- /dev/null
+++ b/libsysinspect/src/proto/payload.rs
@@ -0,0 +1,87 @@
+// XXX: Refactor: move all message types-related code here!
+
+/*
+Payload types and their deserialisation.
+*/
+
+use serde::{Deserialize, Serialize};
+use serde_json::{from_value, Value};
+use std::collections::HashMap;
+
+/// Payload types
+pub enum PayloadType {
+ ModelOrStatement(ModStatePayload),
+ Undef(Value),
+}
+
+impl TryFrom for PayloadType {
+ type Error = serde_json::Error;
+
+ fn try_from(value: Value) -> Result {
+ if let Ok(v) = from_value::(value.clone()) {
+ return Ok(PayloadType::ModelOrStatement(v));
+ }
+ Ok(PayloadType::Undef(value))
+ }
+}
+
+/// Message is sent to the Minion
+#[derive(Debug, Clone, Serialize, Deserialize, Default)]
+pub struct ModStatePayload {
+ // Each file has a SHA1 checksum to prevent huge bogus traffic
+ files: HashMap,
+
+ // Root where models starts. It corresponds to "fileserver.models.root" conf of Master.
+ // It will be substracted from each file path when saving
+ models_root: String,
+
+ // session Id
+ sid: String,
+
+ // sysinspect URI
+ uri: String,
+}
+
+impl ModStatePayload {
+ pub fn new(sid: String) -> Self {
+ ModStatePayload { sid, ..Default::default() }
+ }
+
+ /// Set URI
+ pub fn set_uri(mut self, uri: String) -> Self {
+ self.uri = uri;
+ self
+ }
+
+ /// Add files
+ pub fn add_files(mut self, files: HashMap) -> Self {
+ self.files.extend(files);
+ self
+ }
+
+ /// Set models root
+ pub fn set_models_root(mut self, mr: &str) -> Self {
+ self.models_root = mr.to_string();
+ self
+ }
+
+ /// Get list of files to download
+ pub fn files(&self) -> &HashMap {
+ &self.files
+ }
+
+ /// Get SID
+ pub fn sid(&self) -> &str {
+ &self.sid
+ }
+
+ /// Get URI
+ pub fn uri(&self) -> &str {
+ &self.uri
+ }
+
+ /// Get root of models
+ pub fn models_root(&self) -> &str {
+ &self.models_root
+ }
+}
diff --git a/libsysinspect/src/proto/query.rs b/libsysinspect/src/proto/query.rs
new file mode 100644
index 00000000..e10dd450
--- /dev/null
+++ b/libsysinspect/src/proto/query.rs
@@ -0,0 +1,99 @@
+use std::sync::{Arc, Mutex};
+
+use crate::SysinspectError;
+
+/// Targeting schemes
+pub static SCHEME_MODEL: &str = "model://";
+pub static SCHEME_STATE: &str = "state://";
+
+///
+/// Query parser (scheme).
+/// It has the following format:
+///
+/// /[entity]/[state]
+/// :[checkbook labels]
+///
+/// If `"entity"` and/or `"state"` are omitted, they are globbed to `"$"` (all).
+#[derive(Debug, Clone, Default)]
+pub struct MinionQuery {
+ src: String,
+ entity: Option,
+ state: Option,
+ scheme: String,
+ labels: Option,
+}
+
+impl MinionQuery {
+ pub fn new(q: &str) -> Result>, SysinspectError> {
+ let q = q.trim();
+ if !q.starts_with(SCHEME_STATE) && !q.starts_with(SCHEME_MODEL) {
+ return Err(SysinspectError::ProtoError("Query has unknown scheme".to_string()));
+ }
+
+ let sq: Vec<&str> = q.split("://").collect();
+ if sq.len() != 2 {
+ return Err(SysinspectError::ProtoError("Unable to parse scheme".to_string()));
+ }
+
+ let mut instance = Self { ..Default::default() };
+ instance.scheme = sq[0].to_owned();
+
+ let precise = sq[1].contains('/');
+ let sq: Vec<&str> = sq[1].split(if precise { '/' } else { ':' }).filter(|s| !s.is_empty()).collect();
+ match sq.len() {
+ 0 => {
+ return Err(SysinspectError::ProtoError("No model has been targeted".to_string()));
+ }
+ 1 => instance.src = sq[0].to_string(),
+ 2 => {
+ instance.src = sq[0].to_string();
+ if precise {
+ instance.entity = Some(sq[1].to_string());
+ } else {
+ instance.labels = Some(sq[1].to_string());
+ }
+ }
+ 3 => {
+ instance.src = sq[0].to_string();
+ if precise {
+ instance.entity = Some(sq[1].to_string());
+ instance.state = Some(sq[2].to_string());
+ }
+ }
+ _ => {}
+ }
+
+ Ok(Arc::new(Mutex::new(instance)))
+ }
+
+ /// Get target model name
+ pub fn target(&self) -> &str {
+ &self.src
+ }
+
+ /// Get entities, comma-separated
+ pub fn entities(&self) -> Vec {
+ if let Some(entity) = &self.entity {
+ return entity.split(',').map(|s| s.to_string()).collect();
+ }
+
+ vec![]
+ }
+
+ /// Get checkbook labels, comma-separated
+ pub fn checkbook_labels(&self) -> Vec {
+ if let Some(l) = &self.labels {
+ return l.split(',').map(|s| s.to_string()).collect();
+ }
+ vec![]
+ }
+
+ /// Get desired state of the model
+ pub fn state(&self) -> Option {
+ if let Some(state) = &self.state {
+ return Some(state.to_owned());
+ }
+
+ None
+ }
+}
diff --git a/libsysinspect/src/proto/rqtypes.rs b/libsysinspect/src/proto/rqtypes.rs
new file mode 100644
index 00000000..025edfb6
--- /dev/null
+++ b/libsysinspect/src/proto/rqtypes.rs
@@ -0,0 +1,44 @@
+use serde::{Deserialize, Serialize};
+
+#[derive(Serialize, Deserialize, Debug, Clone)]
+pub enum RequestType {
+ /// Minion registration request or context.
+ #[serde(rename = "add")]
+ Add,
+
+ /// Minion un-registration request.
+ #[serde(rename = "rm")]
+ Remove,
+
+ /// Regular response to any Master command
+ #[serde(rename = "rsp")]
+ Response,
+
+ /// Regular command to any Minion
+ #[serde(rename = "cmd")]
+ Command,
+
+ /// Request to return all minion traits
+ #[serde(rename = "tr")]
+ Traits,
+
+ /// Hello/ehlo
+ #[serde(rename = "ehlo")]
+ Ehlo,
+
+ /// Retry connect (e.g. after the registration)
+ #[serde(rename = "retry")]
+ Reconnect,
+
+ /// Unknown agent
+ #[serde(rename = "undef")]
+ AgentUnknown,
+
+ /// Ping
+ #[serde(rename = "pi")]
+ Ping,
+
+ /// Pong
+ #[serde(rename = "po")]
+ Pong,
+}
diff --git a/libsysinspect/src/reactor/README.txt b/libsysinspect/src/reactor/README.txt
new file mode 100644
index 00000000..b82bbdc9
--- /dev/null
+++ b/libsysinspect/src/reactor/README.txt
@@ -0,0 +1,2 @@
+Package that implements reactor, formatters, handlers etc.
+Everything related to them should go here.
\ No newline at end of file
diff --git a/libsysinspect/src/rsa/keys.rs b/libsysinspect/src/rsa/keys.rs
new file mode 100644
index 00000000..79a349a4
--- /dev/null
+++ b/libsysinspect/src/rsa/keys.rs
@@ -0,0 +1,155 @@
+use rand::rngs::OsRng;
+use rsa::{
+ pkcs1::{DecodeRsaPrivateKey, DecodeRsaPublicKey, EncodeRsaPrivateKey, EncodeRsaPublicKey},
+ pkcs1v15::{Signature, SigningKey, VerifyingKey},
+ sha2::{Digest, Sha256},
+ signature::SignerMut,
+ signature::{Keypair, SignatureEncoding, Verifier},
+ Pkcs1v15Encrypt, RsaPrivateKey, RsaPublicKey,
+};
+use std::{error::Error, fs, io, path::PathBuf};
+
+use crate::SysinspectError;
+
+/// Default key size.
+pub static DEFAULT_KEY_SIZE: usize = 1048;
+
+#[allow(clippy::large_enum_variant)]
+pub enum RsaKey {
+ Private(RsaPrivateKey),
+ Public(RsaPublicKey),
+}
+
+/// Generate RSA keys
+pub fn keygen(bits: usize) -> Result<(RsaPrivateKey, RsaPublicKey), Box> {
+ let mut rng = OsRng;
+ let prk = RsaPrivateKey::new(&mut rng, bits)?;
+ let pbk = RsaPublicKey::from(&prk);
+
+ Ok((prk, pbk))
+}
+
+/// Serializes RSA private and public keys to PEM format.
+pub fn to_pem(
+ prk: Option<&RsaPrivateKey>, pbk: Option<&RsaPublicKey>,
+) -> Result<(Option, Option), Box> {
+ Ok((
+ if prk.is_some() {
+ Some(pem::encode(&pem::Pem::new("RSA PRIVATE KEY", prk.unwrap().to_pkcs1_der()?.as_bytes().to_vec())))
+ } else {
+ None
+ },
+ if pbk.is_some() {
+ Some(pem::encode(&pem::Pem::new("RSA PUBLIC KEY", pbk.unwrap().to_pkcs1_der()?.as_bytes().to_vec())))
+ } else {
+ None
+ },
+ ))
+}
+
+/// Deserializes RSA private and public keys from PEM format.
+pub fn from_pem(
+ prk_pem: Option<&str>, pbk_pem: Option<&str>,
+) -> Result<(Option, Option), Box> {
+ Ok((
+ if prk_pem.is_some() {
+ Some(RsaPrivateKey::from_pkcs1_der(pem::parse(prk_pem.unwrap_or_default())?.contents())?)
+ } else {
+ None
+ },
+ if pbk_pem.is_some() {
+ Some(RsaPublicKey::from_pkcs1_der(pem::parse(pbk_pem.unwrap_or_default())?.contents())?)
+ } else {
+ None
+ },
+ ))
+}
+
+/// Sign data with the private key
+pub fn sign_data(prk: RsaPrivateKey, data: &[u8]) -> Result, Box> {
+ let mut sk = SigningKey::::new(prk);
+ let sig = sk.sign(data);
+ sk.verifying_key().verify(data, &sig)?;
+
+ Ok((*sig.to_bytes()).to_vec())
+}
+
+/// Verify signature from the pubic key
+pub fn verify_sign(pbk: &RsaPublicKey, data: &[u8], sig: Vec) -> Result> {
+ Ok(VerifyingKey::::new(pbk.clone()).verify(data, &Signature::try_from(sig.as_slice())?).is_ok())
+}
+
+/// Get fingerprint of a public key
+#[allow(clippy::format_collect)]
+pub fn get_fingerprint(pbk: &RsaPublicKey) -> Result> {
+ let mut digest = Sha256::new();
+ digest.update(pbk.to_pkcs1_der()?.as_bytes());
+ Ok(digest.finalize().iter().map(|byte| format!("{:02x}", byte)).collect())
+}
+
+// Encrypt data
+pub fn encrypt(pbk: RsaPublicKey, data: Vec) -> Result, Box> {
+ Ok(pbk.encrypt(&mut rand::thread_rng(), Pkcs1v15Encrypt, &data[..])?)
+}
+
+// Decrypt data
+pub fn decrypt(prk: RsaPrivateKey, cipher: Vec) -> Result, Box> {
+ Ok(prk.decrypt(Pkcs1v15Encrypt, &cipher)?)
+}
+
+/// Write private or a public key to a file
+pub fn key_to_file(prk: &RsaKey, p: &str, name: &str) -> Result<(), SysinspectError> {
+ let p = PathBuf::from(p).join(name);
+ if p.exists() {
+ return Err(SysinspectError::IoErr(io::Error::new(
+ io::ErrorKind::AlreadyExists,
+ format!("File {} already exists", p.to_str().unwrap_or_default()),
+ )));
+ }
+
+ let mut pem = String::default();
+ match prk {
+ RsaKey::Private(prk) => {
+ if let Ok((prk_pem, _)) = to_pem(Some(prk), None) {
+ if let Some(prk_pem) = prk_pem {
+ pem = prk_pem;
+ }
+ } else {
+ return Err(SysinspectError::IoErr(io::Error::new(io::ErrorKind::InvalidData, "Unable to create PEM key")));
+ }
+ }
+ RsaKey::Public(pbk) => {
+ if let Ok((_, pbk_pem)) = to_pem(None, Some(pbk)) {
+ if let Some(pbk_pem) = pbk_pem {
+ pem = pbk_pem;
+ }
+ } else {
+ return Err(SysinspectError::IoErr(io::Error::new(io::ErrorKind::InvalidData, "Unable to create PEM key")));
+ }
+ }
+ }
+ fs::write(&p, pem.as_bytes())?;
+ log::debug!("Wrote PEM file as {}", p.to_str().unwrap_or_default());
+
+ Ok(())
+}
+
+/// Read private or a public key from a file
+pub fn key_from_file(p: &str) -> Result