From 5a166ada79fc0b97bffab0b281453ff45ad510ab Mon Sep 17 00:00:00 2001 From: Arshdeep54 Date: Thu, 19 Dec 2024 14:47:24 +0530 Subject: [PATCH 01/30] Add custom logs --- Cargo.lock | 2033 +++++++++++++++++++++++++---------------- Cargo.toml | 2 + install/install.sh | 5 + src/auth.rs | 11 + src/lib/keyhouse.rs | 2 +- src/lib/lib.rs | 2 +- src/lib/logger.rs | 27 + src/ssh.rs | 11 + src/su.rs | 12 + src/sudo.rs | 13 +- tests/logger_tests.rs | 22 + 11 files changed, 1374 insertions(+), 766 deletions(-) create mode 100644 src/lib/logger.rs create mode 100644 tests/logger_tests.rs diff --git a/Cargo.lock b/Cargo.lock index 6782242..ebf232f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,1708 +1,2215 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 4 + [[package]] -name = "adler32" -version = "1.0.4" +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] [[package]] name = "ansi_term" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" dependencies = [ - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.9", ] [[package]] name = "ascii" version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" [[package]] name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi 0.1.19", + "libc", + "winapi 0.3.9", ] [[package]] name = "autocfg" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dde43e75fd43e8a1bf86103336bc699aa8d17ad1be60c76c0bdfd4828e19b78" +dependencies = [ + "autocfg 1.4.0", +] [[package]] name = "autocfg" -version = "1.0.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "backtrace" -version = "0.3.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "backtrace-sys" -version = "0.1.32" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ - "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "addr2line", + "cfg-if 1.0.0", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets", ] [[package]] name = "base64" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", ] [[package]] name = "bitflags" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" [[package]] name = "bitflags" -version = "1.2.1" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "byteorder" -version = "1.3.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", + "either", + "iovec", ] [[package]] -name = "c2-chacha" -version = "0.2.3" +name = "cc" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf" dependencies = [ - "ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "shlex", ] [[package]] -name = "cc" -version = "1.0.50" +name = "cfg-if" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "cfg-if" -version = "0.1.10" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.10" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" dependencies = [ - "num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-targets", ] [[package]] name = "clap" -version = "2.33.0" +version = "2.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ - "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ansi_term", + "atty", + "bitflags 1.3.2", + "strsim", + "textwrap", + "unicode-width", + "vec_map", ] [[package]] name = "cloudabi" version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.3.2", ] [[package]] name = "combine" version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680" dependencies = [ - "ascii 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ascii", + "byteorder", + "either", + "memchr", + "unreachable", ] [[package]] name = "cookie" version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "888604f00b3db336d2af898ec3c1d5d0ddf5e6d462220f2ededc33a87ac4bbd5" dependencies = [ - "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "time", + "url 1.7.2", ] [[package]] name = "cookie_store" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46750b3f362965f197996c4448e4a0935e791bf7d6631bfce9ee0af3d24c919c" dependencies = [ - "cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "publicsuffix 1.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "try_from 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cookie", + "failure", + "idna 0.1.5", + "log", + "publicsuffix", + "serde", + "serde_json", + "time", + "try_from", + "url 1.7.2", ] [[package]] name = "core-foundation" -version = "0.6.4" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ - "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation-sys", + "libc", ] [[package]] name = "core-foundation-sys" -version = "0.6.2" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "crc32fast" -version = "1.2.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", ] [[package]] name = "crossbeam-deque" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20ff29ded3204c5106278a81a38f4b482636ed4fa1e6cfbeef193291beb29ed" dependencies = [ - "crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-epoch", + "crossbeam-utils", + "maybe-uninit", ] [[package]] name = "crossbeam-epoch" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.4.0", + "cfg-if 0.1.10", + "crossbeam-utils", + "lazy_static", + "maybe-uninit", + "memoffset", + "scopeguard", ] [[package]] name = "crossbeam-queue" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10", + "crossbeam-utils", + "maybe-uninit", ] [[package]] name = "crossbeam-utils" -version = "0.7.0" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +dependencies = [ + "autocfg 1.4.0", + "cfg-if 0.1.10", + "lazy_static", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn 2.0.90", ] [[package]] name = "dtoa" -version = "0.4.5" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" [[package]] name = "either" -version = "1.5.3" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "encoding_rs" -version = "0.8.22" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", +] + +[[package]] +name = "errno" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +dependencies = [ + "libc", + "windows-sys", ] [[package]] name = "error-chain" -version = "0.12.1" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" dependencies = [ - "backtrace 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", - "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace", + "version_check", ] [[package]] name = "failure" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86" dependencies = [ - "backtrace 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace", + "failure_derive", ] [[package]] name = "failure_derive" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" dependencies = [ - "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn 1.0.109", + "synstructure 0.12.6", ] +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + [[package]] name = "flate2" -version = "1.0.13" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz_oxide 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "crc32fast", + "miniz_oxide", ] [[package]] name = "fnv" -version = "1.0.6" +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 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "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 2.3.1", +] [[package]] name = "fuchsia-cprng" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" [[package]] name = "fuchsia-zircon" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.3.2", + "fuchsia-zircon-sys", ] [[package]] name = "fuchsia-zircon-sys" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" [[package]] name = "futures" -version = "0.1.29" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678" [[package]] name = "futures-cpupool" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures", + "num_cpus", ] [[package]] name = "gcc" version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" [[package]] -name = "getrandom" -version = "0.1.14" +name = "gimli" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "h2" version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5b34c246847f938a410a03c5458c7fee2274436675e76d8b903c08efc29c462" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "indexmap 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", + "bytes", + "fnv", + "futures", + "http", + "indexmap", + "log", + "slab", + "string", + "tokio-io", ] +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + [[package]] name = "hermit-abi" -version = "0.1.6" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + [[package]] name = "http" version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6ccf5ede3a895d8856620237b2f02972c1bbc78d2965ad7fe8838d4a0ed41f0" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "fnv", + "itoa 0.4.8", ] [[package]] name = "http-body" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6741c859c1b2463a423a1dbce98d418e6c3c3fc720fb0d45528657320920292d" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "futures", + "http", + "tokio-buf", ] [[package]] name = "httparse" -version = "1.3.4" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "hyper" -version = "0.12.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "h2 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "http-body 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tcp 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "want 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +version = "0.12.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c843caf6296fc1f93444735205af9ed4e109a539005abb2564ae1d6fad34c52" +dependencies = [ + "bytes", + "futures", + "futures-cpupool", + "h2", + "http", + "http-body", + "httparse", + "iovec", + "itoa 0.4.8", + "log", + "net2", + "rustc_version", + "time", + "tokio", + "tokio-buf", + "tokio-executor", + "tokio-io", + "tokio-reactor", + "tokio-tcp", + "tokio-threadpool", + "tokio-timer", + "want", ] [[package]] name = "hyper-tls" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a800d6aa50af4b5850b2b0f659625ce9504df908e9733b635720483be26174f" +dependencies = [ + "bytes", + "futures", + "hyper", + "native-tls", + "tokio-io", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.12.35 (registry+https://github.com/rust-lang/crates.io-index)", - "native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +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 1.13.2", + "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.90", ] [[package]] name = "idna" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" dependencies = [ - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "matches", + "unicode-bidi", + "unicode-normalization", ] [[package]] name = "idna" -version = "0.2.0" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" dependencies = [ - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec 1.13.2", + "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 = "indexmap" -version = "1.3.2" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.4.0", + "hashbrown", ] [[package]] name = "iovec" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" dependencies = [ - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] name = "itoa" -version = "0.4.5" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" + +[[package]] +name = "itoa" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" + +[[package]] +name = "js-sys" +version = "0.3.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" +dependencies = [ + "once_cell", + "wasm-bindgen", +] [[package]] name = "kernel32-sys" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8", + "winapi-build", ] [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.66" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "linked-hash-map" -version = "0.5.2" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "litemap" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" [[package]] name = "lock_api" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" dependencies = [ - "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard", ] [[package]] name = "log" -version = "0.4.8" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "matches" -version = "0.1.8" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" [[package]] name = "maybe-uninit" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" [[package]] name = "memchr" -version = "2.3.0" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memoffset" -version = "0.5.3" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa" dependencies = [ - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.4.0", ] [[package]] name = "mime" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "mime_guess" -version = "2.0.1" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" dependencies = [ - "mime 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "mime", + "unicase", ] [[package]] name = "miniz_oxide" -version = "0.3.6" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" dependencies = [ - "adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "adler2", ] [[package]] name = "mio" -version = "0.6.21" +version = "0.6.23" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10", + "fuchsia-zircon", + "fuchsia-zircon-sys", + "iovec", + "kernel32-sys", + "libc", + "log", + "miow", + "net2", + "slab", + "winapi 0.2.8", ] [[package]] name = "miow" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "kernel32-sys", + "net2", + "winapi 0.2.8", + "ws2_32-sys", ] [[package]] name = "native-tls" -version = "0.2.3" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl 0.10.28 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.54 (registry+https://github.com/rust-lang/crates.io-index)", - "schannel 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "security-framework 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "security-framework-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", ] [[package]] name = "net2" -version = "0.2.33" +version = "0.2.39" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b13b648036a2339d06de780866fbdfda0dde886de7b3af2ddeba8b14f4ee34ac" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10", + "libc", + "winapi 0.3.9", ] [[package]] name = "nix" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2c5afeb0198ec7be8569d666644b574345aad2e95a53baf3a532da3e0f3fb32" dependencies = [ - "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 0.9.1", + "cfg-if 0.1.10", + "libc", + "void", ] [[package]] -name = "num-integer" -version = "0.1.42" +name = "num-traits" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.4.0", ] [[package]] -name = "num-traits" -version = "0.2.11" +name = "num_cpus" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi 0.3.9", + "libc", ] [[package]] -name = "num_cpus" -version = "1.12.0" +name = "object" +version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ - "hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr", ] +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + [[package]] name = "openssl" -version = "0.10.28" +version = "0.10.68" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.54 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 2.6.0", + "cfg-if 1.0.0", + "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.90", ] [[package]] name = "openssl-probe" -version = "0.1.2" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.54" +version = "0.9.104" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", - "vcpkg 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", + "libc", + "pkg-config", + "vcpkg", ] [[package]] name = "parking_lot" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" dependencies = [ - "lock_api 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "lock_api", + "parking_lot_core", + "rustc_version", ] [[package]] name = "parking_lot_core" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66b810a62be75176a80873726630147a5ca780cd33921e0b5709033e66b0a" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10", + "cloudabi", + "libc", + "redox_syscall", + "rustc_version", + "smallvec 0.6.14", + "winapi 0.3.9", ] [[package]] name = "percent-encoding" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" [[package]] name = "percent-encoding" -version = "2.1.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pkg-config" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "ppv-lite86" -version = "0.2.6" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "proc-macro2" -version = "1.0.8" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ - "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-ident", ] [[package]] name = "publicsuffix" -version = "1.5.4" +version = "1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95b4ce31ff0a27d93c8de1849cf58162283752f065a90d508f1105fa6c9a213f" dependencies = [ - "error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", - "idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "idna 0.2.3", + "url 2.5.4", ] [[package]] name = "quote" -version = "1.0.2" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ - "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", ] [[package]] name = "rand" version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" dependencies = [ - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "rand 0.4.6", ] [[package]] name = "rand" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" dependencies = [ - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi 0.3.9", ] [[package]] name = "rand" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.8", + "libc", + "rand_chacha", + "rand_core 0.4.2", + "rand_hc", + "rand_isaac", + "rand_jitter", + "rand_os", + "rand_pcg", + "rand_xorshift", + "winapi 0.3.9", ] [[package]] name = "rand_chacha" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_chacha" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.8", + "rand_core 0.3.1", ] [[package]] name = "rand_core" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" dependencies = [ - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.2", ] [[package]] name = "rand_core" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" [[package]] name = "rand_hc" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1", ] [[package]] name = "rand_isaac" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1", ] [[package]] name = "rand_jitter" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" dependencies = [ - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "rand_core 0.4.2", + "winapi 0.3.9", ] [[package]] name = "rand_os" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cloudabi", + "fuchsia-cprng", + "libc", + "rand_core 0.4.2", + "rdrand", + "winapi 0.3.9", ] [[package]] name = "rand_pcg" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.8", + "rand_core 0.4.2", ] [[package]] name = "rand_xorshift" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1", ] [[package]] name = "rdrand" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1", ] [[package]] name = "redox_syscall" -version = "0.1.56" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "regex" -version = "1.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "regex-syntax 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "regex-syntax" -version = "0.6.14" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "remove_dir_all" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" [[package]] name = "reqwest" version = "0.9.24" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cookie_store 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "encoding_rs 0.8.22 (registry+https://github.com/rust-lang/crates.io-index)", - "flate2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.12.35 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper-tls 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "mime 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", - "mime_guess 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_urlencoded 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", - "winreg 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", +checksum = "f88643aea3c1343c804950d7bf983bd2067f5ab59db6d613a08e05572f2714ab" +dependencies = [ + "base64", + "bytes", + "cookie", + "cookie_store", + "encoding_rs", + "flate2", + "futures", + "http", + "hyper", + "hyper-tls", + "log", + "mime", + "mime_guess", + "native-tls", + "serde", + "serde_json", + "serde_urlencoded", + "time", + "tokio", + "tokio-executor", + "tokio-io", + "tokio-threadpool", + "tokio-timer", + "url 1.7.2", + "uuid", + "winreg", ] [[package]] name = "rust-crypto" version = "0.2.36" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" dependencies = [ - "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc", + "libc", + "rand 0.3.23", + "rustc-serialize", + "time", ] [[package]] name = "rustc-demangle" -version = "0.1.16" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-serialize" -version = "0.3.24" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe834bc780604f4674073badbad26d7219cadfb4a2275802db12cbae17498401" [[package]] name = "rustc_version" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" dependencies = [ - "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "semver", +] + +[[package]] +name = "rustix" +version = "0.38.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" +dependencies = [ + "bitflags 2.6.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", ] [[package]] name = "ryu" -version = "1.0.2" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "schannel" -version = "0.1.17" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "windows-sys", ] [[package]] name = "scopeguard" -version = "1.0.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "security-framework" -version = "0.3.4" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "security-framework-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 2.6.0", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", ] [[package]] name = "security-framework-sys" -version = "0.3.3" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1863fd3768cd83c56a7f60faa4dc0d403f1b6df0a38c3c25f44b7894e45370d5" dependencies = [ - "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation-sys", + "libc", ] [[package]] name = "semver" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" dependencies = [ - "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "semver-parser", ] [[package]] name = "semver-parser" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.104" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" dependencies = [ - "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.104" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" dependencies = [ - "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn 2.0.90", ] [[package]] name = "serde_json" -version = "1.0.46" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ - "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 1.0.14", + "memchr", + "ryu", + "serde", ] [[package]] name = "serde_urlencoded" version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "642dd69105886af2efd227f75a520ec9b44a820d65bc133a9131f7d229fd165a" dependencies = [ - "dtoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "dtoa", + "itoa 0.4.8", + "serde", + "url 1.7.2", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "slab" -version = "0.4.2" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg 1.4.0", +] [[package]] name = "smallvec" -version = "0.6.13" +version = "0.6.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97fcaeba89edba30f044a10c6a3cc39df9c3f17d7cd829dd1446cab35f890e0" dependencies = [ - "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "maybe-uninit", ] [[package]] name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "stable_deref_trait" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "string" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", ] [[package]] name = "strsim" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" [[package]] name = "syn" -version = "1.0.14" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ - "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "unicode-ident", ] [[package]] name = "synstructure" -version = "0.12.3" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "unicode-xid", +] + +[[package]] +name = "synstructure" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ - "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn 2.0.90", ] [[package]] name = "tempfile" -version = "3.1.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "fastrand", + "once_cell", + "rustix", + "windows-sys", ] [[package]] name = "textwrap" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" dependencies = [ - "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width", ] [[package]] name = "time" -version = "0.1.42" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" +dependencies = [ + "libc", + "wasi", + "winapi 0.3.9", +] + +[[package]] +name = "tinystr" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" dependencies = [ - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "displaydoc", + "zerovec", ] +[[package]] +name = "tinyvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "tokio" version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-current-thread 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tcp 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "futures", + "mio", + "num_cpus", + "tokio-current-thread", + "tokio-executor", + "tokio-io", + "tokio-reactor", + "tokio-tcp", + "tokio-threadpool", + "tokio-timer", ] [[package]] name = "tokio-buf" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fb220f46c53859a4b7ec083e41dec9778ff0b1851c0942b211edb89e0ccdc46" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "either", + "futures", ] [[package]] name = "tokio-current-thread" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1de0e32a83f131e002238d7ccde18211c0a5397f60cbfffcb112868c2e0e20e" dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "futures", + "tokio-executor", ] [[package]] name = "tokio-executor" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb2d1b8f4548dbf5e1f7818512e9c406860678f29c300cdf0ebac72d1a3a1671" dependencies = [ - "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils", + "futures", ] [[package]] name = "tokio-io" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57fc868aae093479e3131e3d165c93b1c7474109d13c90ec0dda2a1bbfff0674" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "futures", + "log", ] [[package]] name = "tokio-reactor" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09bc590ec4ba8ba87652da2068d150dcada2cfa2e07faae270a5e0409aa51351" dependencies = [ - "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-sync 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils", + "futures", + "lazy_static", + "log", + "mio", + "num_cpus", + "parking_lot", + "slab", + "tokio-executor", + "tokio-io", + "tokio-sync", ] [[package]] name = "tokio-sync" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edfe50152bc8164fcc456dab7891fa9bf8beaf01c5ee7e1dd43a397c3cf87dee" dependencies = [ - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "fnv", + "futures", ] [[package]] name = "tokio-tcp" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98df18ed66e3b72e742f185882a9e201892407957e45fbff8da17ae7a7c51f72" dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes", + "futures", + "iovec", + "mio", + "tokio-io", + "tokio-reactor", ] [[package]] name = "tokio-threadpool" version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df720b6581784c118f0eb4310796b12b1d242a7eb95f716a8367855325c25f89" dependencies = [ - "crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque", + "crossbeam-queue", + "crossbeam-utils", + "futures", + "lazy_static", + "log", + "num_cpus", + "slab", + "tokio-executor", ] [[package]] name = "tokio-timer" version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93044f2d313c95ff1cb7809ce9a7a05735b012288a888b62d4434fd58c94f296" dependencies = [ - "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils", + "futures", + "slab", + "tokio-executor", ] [[package]] name = "toml" -version = "0.5.6" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde", ] [[package]] name = "toml_edit" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f53b1aca7d5fe2e17498a38cac0e1f5a33234d5b980fb36b9402bb93b98ae4" dependencies = [ - "chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "combine 3.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono", + "combine", + "linked-hash-map", ] [[package]] name = "try-lock" -version = "0.2.2" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "try_from" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "283d3b89e1368717881a9d51dad843cc435380d8109c9e47d38780a324698d8b" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10", ] [[package]] name = "unicase" -version = "2.6.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" [[package]] name = "unicode-bidi" -version = "0.3.4" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + +[[package]] +name = "unicode-ident" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-normalization" -version = "0.1.12" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ - "smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tinyvec", ] [[package]] name = "unicode-width" -version = "0.1.7" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-xid" -version = "0.2.0" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "unreachable" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" dependencies = [ - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "void", ] [[package]] name = "url" version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" dependencies = [ - "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "idna 0.1.5", + "matches", + "percent-encoding 1.0.1", ] [[package]] name = "url" -version = "2.1.1" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ - "idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "form_urlencoded", + "idna 1.0.3", + "percent-encoding 2.3.1", ] +[[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 = "uuid" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a" dependencies = [ - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5", ] [[package]] name = "vcpkg" -version = "0.2.8" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "vec_map" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" [[package]] name = "version_check" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "version_check" -version = "0.9.1" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "void" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" [[package]] name = "want" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6395efa4784b027708f7451087e647ec73cc74f5d9bc2e418404248d679a230" dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures", + "log", + "try-lock", ] [[package]] name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "wasm-bindgen" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" +dependencies = [ + "cfg-if 1.0.0", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn 2.0.90", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" [[package]] name = "watchdog" version = "0.1.0" dependencies = [ - "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", - "nix 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "reqwest 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "toml_edit 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "base64", + "clap", + "error-chain", + "nix", + "openssl", + "openssl-sys", + "reqwest", + "rust-crypto", + "serde", + "serde_derive", + "serde_json", + "toml", + "toml_edit", ] [[package]] name = "winapi" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" [[package]] name = "winapi" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-build" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winreg" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9" dependencies = [ - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.9", ] +[[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 = "ws2_32-sys" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[metadata] -"checksum adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2" -"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" -"checksum ascii 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" -"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" -"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" -"checksum backtrace 0.3.43 (registry+https://github.com/rust-lang/crates.io-index)" = "7f80256bc78f67e7df7e36d77366f636ed976895d91fe2ab9efa3973e8fe8c4f" -"checksum backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491" -"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" -"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" -"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" -"checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" -"checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" -"checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" -"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "31850b4a4d6bae316f7a09e691c944c28299298837edc0a03f755618c23cbc01" -"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" -"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum combine 3.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680" -"checksum cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "888604f00b3db336d2af898ec3c1d5d0ddf5e6d462220f2ededc33a87ac4bbd5" -"checksum cookie_store 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46750b3f362965f197996c4448e4a0935e791bf7d6631bfce9ee0af3d24c919c" -"checksum core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "25b9e03f145fd4f2bf705e07b900cd41fc636598fe5dc452fd0db1441c3f496d" -"checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" -"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" -"checksum crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3aa945d63861bfe624b55d153a39684da1e8c0bc8fba932f7ee3a3c16cea3ca" -"checksum crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5064ebdbf05ce3cb95e45c8b086f72263f4166b29b97f6baff7ef7fe047b55ac" -"checksum crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c695eeca1e7173472a32221542ae469b3e9aac3a4fc81f7696bcad82029493db" -"checksum crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4" -"checksum dtoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4358a9e11b9a09cf52383b451b49a169e8d797b68aa02301ff586d70d9661ea3" -"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" -"checksum encoding_rs 0.8.22 (registry+https://github.com/rust-lang/crates.io-index)" = "cd8d03faa7fe0c1431609dfad7bbe827af30f82e1e2ae6f7ee4fca6bd764bc28" -"checksum error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ab49e9dcb602294bc42f9a7dfc9bc6e936fca4418ea300dbfb84fe16de0b7d9" -"checksum failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9" -"checksum failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08" -"checksum flate2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6bd6d6f4752952feb71363cffc9ebac9411b75b87c6ab6058c40c8900cf43c0f" -"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" -"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -"checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" -"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" -"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" -"checksum futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1b980f2816d6ee8673b6517b52cb0e808a180efc92e5c19d02cdda79066703ef" -"checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" -"checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" -"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" -"checksum h2 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b34c246847f938a410a03c5458c7fee2274436675e76d8b903c08efc29c462" -"checksum hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772" -"checksum http 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "d6ccf5ede3a895d8856620237b2f02972c1bbc78d2965ad7fe8838d4a0ed41f0" -"checksum http-body 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6741c859c1b2463a423a1dbce98d418e6c3c3fc720fb0d45528657320920292d" -"checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" -"checksum hyper 0.12.35 (registry+https://github.com/rust-lang/crates.io-index)" = "9dbe6ed1438e1f8ad955a4701e9a944938e9519f6888d12d8558b645e247d5f6" -"checksum hyper-tls 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3a800d6aa50af4b5850b2b0f659625ce9504df908e9733b635720483be26174f" -"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" -"checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" -"checksum indexmap 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "076f042c5b7b98f31d205f1249267e12a6518c1481e9dae9764af19b707d2292" -"checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" -"checksum itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" -"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" -"checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" -"checksum lock_api 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "79b2de95ecb4691949fea4716ca53cdbcfccb2c612e19644a8bad05edcf9f47b" -"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" -"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" -"checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" -"checksum memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3197e20c7edb283f87c071ddfc7a2cca8f8e0b888c242959846a6fce03c72223" -"checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9" -"checksum mime 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" -"checksum mime_guess 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1a0ed03949aef72dbdf3116a383d7b38b4768e6f960528cd6a6044aa9ed68599" -"checksum miniz_oxide 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aa679ff6578b1cddee93d7e82e263b94a575e0bfced07284eb0c037c1d2416a5" -"checksum mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)" = "302dec22bcf6bae6dfb69c647187f4b4d0fb6f535521f7bc022430ce8e12008f" -"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" -"checksum native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b2df1a4c22fd44a62147fd8f13dd0f95c9d8ca7b2610299b2a2f9cf8964274e" -"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" -"checksum nix 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a2c5afeb0198ec7be8569d666644b574345aad2e95a53baf3a532da3e0f3fb32" -"checksum num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" -"checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" -"checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" -"checksum openssl 0.10.28 (registry+https://github.com/rust-lang/crates.io-index)" = "973293749822d7dd6370d6da1e523b0d1db19f06c459134c658b2a4261378b52" -"checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" -"checksum openssl-sys 0.9.54 (registry+https://github.com/rust-lang/crates.io-index)" = "1024c0a59774200a555087a6da3f253a9095a5f344e353b212ac4c8b8e450986" -"checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" -"checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" -"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" -"checksum percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" -"checksum pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" -"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" -"checksum proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3acb317c6ff86a4e579dfa00fc5e6cca91ecbb4e7eb2df0468805b674eb88548" -"checksum publicsuffix 1.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3bbaa49075179162b49acac1c6aa45fb4dafb5f13cf6794276d77bc7fd95757b" -"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" -"checksum rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" -"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" -"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" -"checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" -"checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" -"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" -"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" -"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" -"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" -"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" -"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" -"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" -"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" -"checksum regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "322cf97724bea3ee221b78fe25ac9c46114ebb51747ad5babd51a2fc6a8235a8" -"checksum regex-syntax 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b28dfe3fe9badec5dbf0a79a9cccad2cfc2ab5484bdb3e44cbd1ae8b3ba2be06" -"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" -"checksum reqwest 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)" = "f88643aea3c1343c804950d7bf983bd2067f5ab59db6d613a08e05572f2714ab" -"checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" -"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" -"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" -"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" -"checksum schannel 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "507a9e6e8ffe0a4e0ebb9a10293e62fdf7657c06f1b8bb07a8fcf697d2abf295" -"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" -"checksum security-framework 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8ef2429d7cefe5fd28bd1d2ed41c944547d4ff84776f5935b456da44593a16df" -"checksum security-framework-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e31493fc37615debb8c5090a7aeb4a9730bc61e77ab10b9af59f1a202284f895" -"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449" -"checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64" -"checksum serde_json 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)" = "21b01d7f0288608a01dca632cf1df859df6fd6ffa885300fc275ce2ba6221953" -"checksum serde_urlencoded 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "642dd69105886af2efd227f75a520ec9b44a820d65bc133a9131f7d229fd165a" -"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" -"checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" -"checksum smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc" -"checksum string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d24114bfcceb867ca7f71a0d3fe45d45619ec47a6fbfa98cb14e14250bfa5d6d" -"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" -"checksum syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "af6f3550d8dff9ef7dc34d384ac6f107e5d31c8f57d9f28e0081503f547ac8f5" -"checksum synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" -"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" -"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" -"checksum tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6" -"checksum tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8fb220f46c53859a4b7ec083e41dec9778ff0b1851c0942b211edb89e0ccdc46" -"checksum tokio-current-thread 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b1de0e32a83f131e002238d7ccde18211c0a5397f60cbfffcb112868c2e0e20e" -"checksum tokio-executor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "fb2d1b8f4548dbf5e1f7818512e9c406860678f29c300cdf0ebac72d1a3a1671" -"checksum tokio-io 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "57fc868aae093479e3131e3d165c93b1c7474109d13c90ec0dda2a1bbfff0674" -"checksum tokio-reactor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "09bc590ec4ba8ba87652da2068d150dcada2cfa2e07faae270a5e0409aa51351" -"checksum tokio-sync 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "edfe50152bc8164fcc456dab7891fa9bf8beaf01c5ee7e1dd43a397c3cf87dee" -"checksum tokio-tcp 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "98df18ed66e3b72e742f185882a9e201892407957e45fbff8da17ae7a7c51f72" -"checksum tokio-threadpool 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "df720b6581784c118f0eb4310796b12b1d242a7eb95f716a8367855325c25f89" -"checksum tokio-timer 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "93044f2d313c95ff1cb7809ce9a7a05735b012288a888b62d4434fd58c94f296" -"checksum toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a" -"checksum toml_edit 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87f53b1aca7d5fe2e17498a38cac0e1f5a33234d5b980fb36b9402bb93b98ae4" -"checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" -"checksum try_from 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "283d3b89e1368717881a9d51dad843cc435380d8109c9e47d38780a324698d8b" -"checksum unicase 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" -"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" -"checksum unicode-normalization 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5479532badd04e128284890390c1e876ef7a993d0570b3597ae43dfa1d59afa4" -"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" -"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" -"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" -"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" -"checksum url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb" -"checksum uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a" -"checksum vcpkg 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3fc439f2794e98976c88a2a2dafce96b930fe8010b0a256b3c2199a773933168" -"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" -"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" -"checksum version_check 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce" -"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum want 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b6395efa4784b027708f7451087e647ec73cc74f5d9bc2e418404248d679a230" -"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" -"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" -"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" -"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -"checksum winreg 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9" -"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" + "winapi 0.2.8", + "winapi-build", +] + +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", + "synstructure 0.13.1", +] + +[[package]] +name = "zerofrom" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", + "synstructure 0.13.1", +] + +[[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.90", +] diff --git a/Cargo.toml b/Cargo.toml index 6f67506..a09c574 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,8 @@ clap = "2.19" error-chain="0.12.1" toml_edit="0.1.5" nix = "0.9.0" +openssl = "0.10" +openssl-sys = "0.9.58" [[ bin ]] name = "watchdog" diff --git a/install/install.sh b/install/install.sh index 9195b3e..f293d25 100755 --- a/install/install.sh +++ b/install/install.sh @@ -6,6 +6,11 @@ mkdir -p /opt/watchdog/logs touch /opt/watchdog/logs/sudo.logs touch /opt/watchdog/logs/su.logs touch /opt/watchdog/logs/ssh.logs +mkdir -p /opt/watchdog/custom-logs +touch /opt/watchdog/custom-logs/ssh.logs +touch /opt/watchdog/custom-logs/sudo.logs +touch /opt/watchdog/custom-logs/su.logs +touch /opt/watchdog/custom-logs/auth.logs cp ../target/release/watchdog /opt/watchdog/bin/watchdog chown root /opt/watchdog/bin/watchdog diff --git a/src/auth.rs b/src/auth.rs index 414c25d..b289ecf 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -7,6 +7,7 @@ use lib::errors::*; use lib::init::init; use lib::keyhouse::{get_name, validate_user}; use lib::notifier; +use lib::logger; pub fn handle_auth(ssh_host_username: &str, ssh_key: &str) -> Result<()> { let config = read_config()?; @@ -32,6 +33,16 @@ pub fn handle_auth(ssh_host_username: &str, ssh_key: &str) -> Result<()> { match fork() { Ok(ForkResult::Parent { .. }) => {} Ok(ForkResult::Child) => { + match fork() { + Ok(ForkResult::Parent { .. }) => {} + Ok(ForkResult::Child) => { + if let Err(e) = logger::log("auth", "SUCCESS", &format!("User: {}", name)) { + println!("Failed to log: {}", e); + } + } + Err(_) => println!("Fork failed"), + } + notifier::post_ssh_summary( &config, false, diff --git a/src/lib/keyhouse.rs b/src/lib/keyhouse.rs index aee3577..2306f4b 100644 --- a/src/lib/keyhouse.rs +++ b/src/lib/keyhouse.rs @@ -50,7 +50,7 @@ fn get_content_from_github_json(json_text: &str) -> Result { .as_str() .ok_or(Error::from("")) .chain_err(|| "No key 'content' found in JSON recieved from GitHub.")?; - let len = str::len(encoded_content); + let _len = str::len(encoded_content); let content = base64::decode(&encoded_content.trim_end()) .chain_err(|| "Bad Base64 Encoding. Probably GitHub is facing some issues. Check https://githubstatus.com.")?; Ok(String::from_utf8(content).chain_err(|| { diff --git a/src/lib/lib.rs b/src/lib/lib.rs index dd151bd..240017d 100644 --- a/src/lib/lib.rs +++ b/src/lib/lib.rs @@ -4,7 +4,7 @@ pub mod init; pub mod keyhouse; pub mod notifier; pub mod utils; - +pub mod logger; #[macro_use] extern crate error_chain; diff --git a/src/lib/logger.rs b/src/lib/logger.rs new file mode 100644 index 0000000..b5a29d5 --- /dev/null +++ b/src/lib/logger.rs @@ -0,0 +1,27 @@ +use std::fs::OpenOptions; +use std::io::Write; +use std::time::{SystemTime, UNIX_EPOCH}; +use std::io::Result; + +pub fn log(filetype: &str, status: &str, message: &str) -> Result<()> { + let filename = match filetype { + "ssh" => "ssh.logs", + "sudo" => "sudo.logs", + "su" => "su.logs", + _ => return Err(std::io::Error::new(std::io::ErrorKind::InvalidInput, "Invalid filetype")), + }; + + let start = SystemTime::now(); + let since_the_epoch = start.duration_since(UNIX_EPOCH).expect("Time went backwards"); + let timestamp = since_the_epoch.as_secs(); + + let log_message = format!("{} - {} - {}\n", timestamp, status, message); + + let mut file = OpenOptions::new() + .append(true) + .create(true) + .open(filename)?; + + file.write_all(log_message.as_bytes())?; + Ok(()) +} \ No newline at end of file diff --git a/src/ssh.rs b/src/ssh.rs index 3a0cea9..73bffc2 100644 --- a/src/ssh.rs +++ b/src/ssh.rs @@ -10,6 +10,7 @@ use lib::init::init; use lib::keyhouse::get_name; use lib::notifier; use lib::utils::clear_file; +use lib::logger; pub fn handle_ssh() -> Result<()> { let pam_type = env::var("PAM_TYPE") @@ -27,6 +28,16 @@ pub fn handle_ssh() -> Result<()> { clear_file("/opt/watchdog/ssh_env")?; } Ok(ForkResult::Child) => { + match fork() { + Ok(ForkResult::Parent { .. }) => {} + Ok(ForkResult::Child) => { + if let Err(e) = logger::log("ssh", "SUCCESS", &format!("User: {}", name)) { + println!("Failed to log: {}", e); + } + } + Err(_) => println!("Fork failed"), + } + notifier::post_ssh_summary(&config, true, name, env.ssh_host_username)?; } Err(_) => println!("Fork failed"), diff --git a/src/su.rs b/src/su.rs index 0f87d1c..779db47 100644 --- a/src/su.rs +++ b/src/su.rs @@ -7,6 +7,7 @@ use lib::config::read_config; use lib::errors::*; use lib::init::init; use lib::notifier; +use lib::logger; pub fn handle_su() -> Result<()> { let pam_type = env::var("PAM_TYPE") @@ -25,6 +26,17 @@ pub fn handle_su() -> Result<()> { match fork() { Ok(ForkResult::Parent { .. }) => {} Ok(ForkResult::Child) => { + match fork() { + Ok(ForkResult::Parent { .. }) => {} + Ok(ForkResult::Child) => { + // Call the log function in this child process + if let Err(e) = logger::log("su", "SUCCESS", &format!("User: {}", pam_user)) { + println!("Failed to log: {}", e); + } + } + Err(_) => println!("Fork failed"), + } + notifier::post_su_summary(&config, pam_ruser, pam_user)?; } Err(_) => println!("Fork failed"), diff --git a/src/sudo.rs b/src/sudo.rs index abe1f78..442317d 100644 --- a/src/sudo.rs +++ b/src/sudo.rs @@ -7,7 +7,7 @@ use lib::config::read_config; use lib::errors::*; use lib::init::init; use lib::notifier; - +use lib::logger; pub fn handle_sudo() -> Result<()> { let pam_type = env::var("PAM_TYPE") .chain_err(|| "PAM_TYPE not set. If you are running this by `watchdog sudo`, please don't. It's an internal command, intended to be used by PAM.")?; @@ -22,6 +22,17 @@ pub fn handle_sudo() -> Result<()> { match fork() { Ok(ForkResult::Parent { .. }) => {} Ok(ForkResult::Child) => { + match fork() { + Ok(ForkResult::Parent { .. }) => {} + Ok(ForkResult::Child) => { + // Call the log function in this child process + if let Err(e) = logger::log("sudo", "SUCCESS", &format!("User: {}", pam_ruser)) { + println!("Failed to log: {}", e); + } + } + Err(_) => println!("Fork failed"), + } + notifier::post_sudo_summary(&config, pam_ruser)?; } Err(_) => println!("Fork failed"), diff --git a/tests/logger_tests.rs b/tests/logger_tests.rs new file mode 100644 index 0000000..c92a83d --- /dev/null +++ b/tests/logger_tests.rs @@ -0,0 +1,22 @@ +#[cfg(test)] +mod tests { + use std::fs; + use std::io::Read; + use lib::logger::log; + + #[test] + fn test_log() { + let filetype = "ssh"; + let status = "INFO"; + let message = "Test log message"; + + log(filetype, status, message).expect("Failed to write log"); + + let mut file = fs::File::open("ssh.logs").expect("Failed to open log file"); + let mut contents = String::new(); + file.read_to_string(&mut contents).expect("Failed to read log file"); + + assert!(contents.contains("Test log message")); + assert!(contents.contains("INFO")); + } +} \ No newline at end of file From 6f9ca23720ff0943c230b213418cb664a23d4d40 Mon Sep 17 00:00:00 2001 From: Arshdeep54 Date: Thu, 19 Dec 2024 21:37:09 +0530 Subject: [PATCH 02/30] correct log file path --- src/lib/logger.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/lib/logger.rs b/src/lib/logger.rs index b5a29d5..75106bd 100644 --- a/src/lib/logger.rs +++ b/src/lib/logger.rs @@ -5,9 +5,10 @@ use std::io::Result; pub fn log(filetype: &str, status: &str, message: &str) -> Result<()> { let filename = match filetype { - "ssh" => "ssh.logs", - "sudo" => "sudo.logs", - "su" => "su.logs", + "ssh" => "/opt/watchdog/custom-logs/ssh.logs", + "sudo" => "/opt/watchdog/custom-logs/sudo.logs", + "su" => "/opt/watchdog/custom-logs/su.logs", + "auth" => "/opt/watchdog/custom-logs/auth.logs", _ => return Err(std::io::Error::new(std::io::ErrorKind::InvalidInput, "Invalid filetype")), }; From 1772f4f9ed2b9d2cd1b2f263520cc01eef780612 Mon Sep 17 00:00:00 2001 From: Arshdeep54 Date: Thu, 19 Dec 2024 22:01:27 +0530 Subject: [PATCH 03/30] fix cargo test --- src/auth.rs | 5 ++++- src/lib/logger.rs | 12 ++---------- src/lib/utils.rs | 5 +++++ src/ssh.rs | 3 ++- src/su.rs | 4 ++-- src/sudo.rs | 5 +++-- tests/logger_tests.rs | 8 +++++--- 7 files changed, 23 insertions(+), 19 deletions(-) diff --git a/src/auth.rs b/src/auth.rs index b289ecf..a37e335 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -8,6 +8,7 @@ use lib::init::init; use lib::keyhouse::{get_name, validate_user}; use lib::notifier; use lib::logger; +use lib::utils::AUTH_LOG_PATH; pub fn handle_auth(ssh_host_username: &str, ssh_key: &str) -> Result<()> { let config = read_config()?; @@ -36,9 +37,10 @@ pub fn handle_auth(ssh_host_username: &str, ssh_key: &str) -> Result<()> { match fork() { Ok(ForkResult::Parent { .. }) => {} Ok(ForkResult::Child) => { - if let Err(e) = logger::log("auth", "SUCCESS", &format!("User: {}", name)) { + if let Err(e) = logger::log(AUTH_LOG_PATH, "SUCCESS", &format!("User: {}", name)) { println!("Failed to log: {}", e); } + std::process::exit(0); } Err(_) => println!("Fork failed"), } @@ -49,6 +51,7 @@ pub fn handle_auth(ssh_host_username: &str, ssh_key: &str) -> Result<()> { name, ssh_host_username.to_string(), )?; + std::process::exit(0); } Err(_) => println!("Fork failed"), } diff --git a/src/lib/logger.rs b/src/lib/logger.rs index 75106bd..59455b8 100644 --- a/src/lib/logger.rs +++ b/src/lib/logger.rs @@ -3,15 +3,7 @@ use std::io::Write; use std::time::{SystemTime, UNIX_EPOCH}; use std::io::Result; -pub fn log(filetype: &str, status: &str, message: &str) -> Result<()> { - let filename = match filetype { - "ssh" => "/opt/watchdog/custom-logs/ssh.logs", - "sudo" => "/opt/watchdog/custom-logs/sudo.logs", - "su" => "/opt/watchdog/custom-logs/su.logs", - "auth" => "/opt/watchdog/custom-logs/auth.logs", - _ => return Err(std::io::Error::new(std::io::ErrorKind::InvalidInput, "Invalid filetype")), - }; - +pub fn log(filepath: &str, status: &str, message: &str) -> Result<()> { let start = SystemTime::now(); let since_the_epoch = start.duration_since(UNIX_EPOCH).expect("Time went backwards"); let timestamp = since_the_epoch.as_secs(); @@ -21,7 +13,7 @@ pub fn log(filetype: &str, status: &str, message: &str) -> Result<()> { let mut file = OpenOptions::new() .append(true) .create(true) - .open(filename)?; + .open(filepath)?; file.write_all(log_message.as_bytes())?; Ok(()) diff --git a/src/lib/utils.rs b/src/lib/utils.rs index 36c8590..1e0351a 100644 --- a/src/lib/utils.rs +++ b/src/lib/utils.rs @@ -2,6 +2,11 @@ use std::fs; use crate::errors::*; +pub const AUTH_LOG_PATH: &str = "/opt/watchdog/custom-logs/auth.logs"; +pub const SSH_LOG_PATH: &str = "/opt/watchdog/custom-logs/ssh.logs"; +pub const SUDO_LOG_PATH: &str = "/opt/watchdog/custom-logs/sudo.logs"; +pub const SU_LOG_PATH: &str = "/opt/watchdog/custom-logs/su.logs"; + pub fn clear_file(path: &str) -> Result<()> { fs::write(path, "")?; Ok(()) diff --git a/src/ssh.rs b/src/ssh.rs index 73bffc2..ecf9c2e 100644 --- a/src/ssh.rs +++ b/src/ssh.rs @@ -11,6 +11,7 @@ use lib::keyhouse::get_name; use lib::notifier; use lib::utils::clear_file; use lib::logger; +use lib::utils::SSH_LOG_PATH; pub fn handle_ssh() -> Result<()> { let pam_type = env::var("PAM_TYPE") @@ -31,7 +32,7 @@ pub fn handle_ssh() -> Result<()> { match fork() { Ok(ForkResult::Parent { .. }) => {} Ok(ForkResult::Child) => { - if let Err(e) = logger::log("ssh", "SUCCESS", &format!("User: {}", name)) { + if let Err(e) = logger::log(SSH_LOG_PATH, "SUCCESS", &format!("User: {}", name)) { println!("Failed to log: {}", e); } } diff --git a/src/su.rs b/src/su.rs index 779db47..65d7f09 100644 --- a/src/su.rs +++ b/src/su.rs @@ -8,6 +8,7 @@ use lib::errors::*; use lib::init::init; use lib::notifier; use lib::logger; +use lib::utils::SU_LOG_PATH; pub fn handle_su() -> Result<()> { let pam_type = env::var("PAM_TYPE") @@ -29,8 +30,7 @@ pub fn handle_su() -> Result<()> { match fork() { Ok(ForkResult::Parent { .. }) => {} Ok(ForkResult::Child) => { - // Call the log function in this child process - if let Err(e) = logger::log("su", "SUCCESS", &format!("User: {}", pam_user)) { + if let Err(e) = logger::log(SU_LOG_PATH, "SUCCESS", &format!("User: {}", pam_user)) { println!("Failed to log: {}", e); } } diff --git a/src/sudo.rs b/src/sudo.rs index 442317d..51445a5 100644 --- a/src/sudo.rs +++ b/src/sudo.rs @@ -8,6 +8,8 @@ use lib::errors::*; use lib::init::init; use lib::notifier; use lib::logger; +use lib::utils::SUDO_LOG_PATH; + pub fn handle_sudo() -> Result<()> { let pam_type = env::var("PAM_TYPE") .chain_err(|| "PAM_TYPE not set. If you are running this by `watchdog sudo`, please don't. It's an internal command, intended to be used by PAM.")?; @@ -25,8 +27,7 @@ pub fn handle_sudo() -> Result<()> { match fork() { Ok(ForkResult::Parent { .. }) => {} Ok(ForkResult::Child) => { - // Call the log function in this child process - if let Err(e) = logger::log("sudo", "SUCCESS", &format!("User: {}", pam_ruser)) { + if let Err(e) = logger::log(SUDO_LOG_PATH, "SUCCESS", &format!("User: {}", pam_ruser)) { println!("Failed to log: {}", e); } } diff --git a/tests/logger_tests.rs b/tests/logger_tests.rs index c92a83d..523fff0 100644 --- a/tests/logger_tests.rs +++ b/tests/logger_tests.rs @@ -6,17 +6,19 @@ mod tests { #[test] fn test_log() { - let filetype = "ssh"; + let filepath = "test_ssh.logs"; let status = "INFO"; let message = "Test log message"; - log(filetype, status, message).expect("Failed to write log"); + log(filepath, status, message).expect("Failed to write log"); - let mut file = fs::File::open("ssh.logs").expect("Failed to open log file"); + let mut file = fs::File::open(filepath).expect("Failed to open log file"); let mut contents = String::new(); file.read_to_string(&mut contents).expect("Failed to read log file"); assert!(contents.contains("Test log message")); assert!(contents.contains("INFO")); + + fs::remove_file(filepath).expect("Failed to delete test log file"); } } \ No newline at end of file From 6dd0690fdd54682e40af270b159af8d8ab6723c7 Mon Sep 17 00:00:00 2001 From: Arshdeep54 Date: Fri, 20 Dec 2024 20:28:21 +0530 Subject: [PATCH 04/30] fix log implementation --- src/auth.rs | 15 +++------------ src/ssh.rs | 20 +++++--------------- src/su.rs | 14 +++----------- src/sudo.rs | 14 +++----------- 4 files changed, 14 insertions(+), 49 deletions(-) diff --git a/src/auth.rs b/src/auth.rs index a37e335..249f555 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -30,21 +30,12 @@ pub fn handle_auth(ssh_host_username: &str, ssh_key: &str) -> Result<()> { Ok(false) => { let name = get_name(&config, ssh_key)?; - + if let Err(e) = logger::log(AUTH_LOG_PATH, "SUCCESS", &format!("User: {}", name)) { + println!("Failed to log: {}", e); + } match fork() { Ok(ForkResult::Parent { .. }) => {} Ok(ForkResult::Child) => { - match fork() { - Ok(ForkResult::Parent { .. }) => {} - Ok(ForkResult::Child) => { - if let Err(e) = logger::log(AUTH_LOG_PATH, "SUCCESS", &format!("User: {}", name)) { - println!("Failed to log: {}", e); - } - std::process::exit(0); - } - Err(_) => println!("Fork failed"), - } - notifier::post_ssh_summary( &config, false, diff --git a/src/ssh.rs b/src/ssh.rs index ecf9c2e..ff92d00 100644 --- a/src/ssh.rs +++ b/src/ssh.rs @@ -9,7 +9,7 @@ use lib::errors::*; use lib::init::init; use lib::keyhouse::get_name; use lib::notifier; -use lib::utils::clear_file; +//use lib::utils::clear_file; use lib::logger; use lib::utils::SSH_LOG_PATH; @@ -23,22 +23,12 @@ pub fn handle_ssh() -> Result<()> { let env = read_temp_env("/opt/watchdog/ssh_env")?; let name = get_name(&config, &env.ssh_key)?; - + if let Err(e) = logger::log(SSH_LOG_PATH, "SUCCESS", &format!("User: {}", name)) { + println!("Failed to log: {}", e); + } match fork() { - Ok(ForkResult::Parent { .. }) => { - clear_file("/opt/watchdog/ssh_env")?; - } + Ok(ForkResult::Parent { .. }) => {} Ok(ForkResult::Child) => { - match fork() { - Ok(ForkResult::Parent { .. }) => {} - Ok(ForkResult::Child) => { - if let Err(e) = logger::log(SSH_LOG_PATH, "SUCCESS", &format!("User: {}", name)) { - println!("Failed to log: {}", e); - } - } - Err(_) => println!("Fork failed"), - } - notifier::post_ssh_summary(&config, true, name, env.ssh_host_username)?; } Err(_) => println!("Fork failed"), diff --git a/src/su.rs b/src/su.rs index 65d7f09..9d1cb12 100644 --- a/src/su.rs +++ b/src/su.rs @@ -23,20 +23,12 @@ pub fn handle_su() -> Result<()> { if pam_type == "open_session" { let config = read_config()?; init(&config)?; - + if let Err(e) = logger::log(SU_LOG_PATH, "SUCCESS", &format!("User: {}", pam_user)) { + println!("Failed to log: {}", e); + } match fork() { Ok(ForkResult::Parent { .. }) => {} Ok(ForkResult::Child) => { - match fork() { - Ok(ForkResult::Parent { .. }) => {} - Ok(ForkResult::Child) => { - if let Err(e) = logger::log(SU_LOG_PATH, "SUCCESS", &format!("User: {}", pam_user)) { - println!("Failed to log: {}", e); - } - } - Err(_) => println!("Fork failed"), - } - notifier::post_su_summary(&config, pam_ruser, pam_user)?; } Err(_) => println!("Fork failed"), diff --git a/src/sudo.rs b/src/sudo.rs index 51445a5..4a36694 100644 --- a/src/sudo.rs +++ b/src/sudo.rs @@ -20,20 +20,12 @@ pub fn handle_sudo() -> Result<()> { if pam_type == "open_session" { let config = read_config()?; init(&config)?; - + if let Err(e) = logger::log(SUDO_LOG_PATH, "SUCCESS", &format!("User: {}", pam_ruser)) { + println!("Failed to log: {}", e); + } match fork() { Ok(ForkResult::Parent { .. }) => {} Ok(ForkResult::Child) => { - match fork() { - Ok(ForkResult::Parent { .. }) => {} - Ok(ForkResult::Child) => { - if let Err(e) = logger::log(SUDO_LOG_PATH, "SUCCESS", &format!("User: {}", pam_ruser)) { - println!("Failed to log: {}", e); - } - } - Err(_) => println!("Fork failed"), - } - notifier::post_sudo_summary(&config, pam_ruser)?; } Err(_) => println!("Fork failed"), From f46758a3d5eed7c4b5c2d5360a4e447d3c6d6802 Mon Sep 17 00:00:00 2001 From: Arshdeep54 Date: Sun, 22 Dec 2024 15:29:23 +0530 Subject: [PATCH 05/30] adds debug statements as logs --- Cargo.lock | 1 + Cargo.toml | 1 + src/auth.rs | 20 +++++++++++++++----- src/lib/logger.rs | 26 +++++++++++++++++++++++--- src/main.rs | 6 +++++- src/ssh.rs | 6 +++++- src/sudo.rs | 4 +++- 7 files changed, 53 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ebf232f..d38242f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1986,6 +1986,7 @@ name = "watchdog" version = "0.1.0" dependencies = [ "base64", + "chrono", "clap", "error-chain", "nix", diff --git a/Cargo.toml b/Cargo.toml index a09c574..280a0cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ toml_edit="0.1.5" nix = "0.9.0" openssl = "0.10" openssl-sys = "0.9.58" +chrono = "0.4" [[ bin ]] name = "watchdog" diff --git a/src/auth.rs b/src/auth.rs index 249f555..f071074 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -13,9 +13,10 @@ use lib::utils::AUTH_LOG_PATH; pub fn handle_auth(ssh_host_username: &str, ssh_key: &str) -> Result<()> { let config = read_config()?; init(&config)?; - + logger::logln(&format!("ssh_key in handle_auth: {}", ssh_key)); match validate_user(&config, ssh_host_username.to_string(), ssh_key) { Ok(true) => { + logger::logln("User validated"); let data = format!( "ssh_host_username = '{}'\nssh_key = '{}'\n", ssh_host_username, ssh_key @@ -23,16 +24,23 @@ pub fn handle_auth(ssh_host_username: &str, ssh_key: &str) -> Result<()> { fs::write("/opt/watchdog/ssh_env", data) .chain_err(|| "Cannot write temporary environment file. Please check if the watchdog `auth_keys_cmd` is run by the root user")?; - + logger::logln("Temporary environment file written"); println!("{}", ssh_key); + let name = get_name(&config, ssh_key)?; + if let Err(e) = logger::log(AUTH_LOG_PATH, "SUCCESS", &format!("User: {}", name)) { + println!("Failed to log: {}", e); + } + logger::logln("Logging successful"); Ok(()) } Ok(false) => { + logger::logln("User not validated"); let name = get_name(&config, ssh_key)?; - if let Err(e) = logger::log(AUTH_LOG_PATH, "SUCCESS", &format!("User: {}", name)) { + if let Err(e) = logger::log(AUTH_LOG_PATH, "Failed", &format!("User: {}", name)) { println!("Failed to log: {}", e); } + logger::logln("Logging failed"); match fork() { Ok(ForkResult::Parent { .. }) => {} Ok(ForkResult::Child) => { @@ -48,7 +56,9 @@ pub fn handle_auth(ssh_host_username: &str, ssh_key: &str) -> Result<()> { } Ok(()) } - - Err(e) => Err(e).chain_err(|| "Error while validating user from keyhouse"), + Err(e) => { + logger::logln("Error while validating user from keyhouse"); + Err(e).chain_err(|| "Error while validating user from keyhouse") + } } } diff --git a/src/lib/logger.rs b/src/lib/logger.rs index 59455b8..3bb3ac8 100644 --- a/src/lib/logger.rs +++ b/src/lib/logger.rs @@ -2,13 +2,15 @@ use std::fs::OpenOptions; use std::io::Write; use std::time::{SystemTime, UNIX_EPOCH}; use std::io::Result; +use chrono::{DateTime, Utc}; pub fn log(filepath: &str, status: &str, message: &str) -> Result<()> { let start = SystemTime::now(); let since_the_epoch = start.duration_since(UNIX_EPOCH).expect("Time went backwards"); let timestamp = since_the_epoch.as_secs(); - - let log_message = format!("{} - {} - {}\n", timestamp, status, message); + let datetime = DateTime::::from(SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(timestamp)); + let readable_time = datetime.format("%Y-%m-%d %H:%M:%S").to_string(); + let log_message = format!("{} - {} - {}\n", readable_time, status, message); let mut file = OpenOptions::new() .append(true) @@ -17,4 +19,22 @@ pub fn log(filepath: &str, status: &str, message: &str) -> Result<()> { file.write_all(log_message.as_bytes())?; Ok(()) -} \ No newline at end of file +} + +pub fn logln(message: &str) { + let start = SystemTime::now(); + let since_the_epoch = start.duration_since(UNIX_EPOCH).expect("Time went backwards"); + let timestamp = since_the_epoch.as_secs(); + let datetime = DateTime::::from(SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(timestamp)); + let readable_time = datetime.format("%Y-%m-%d %H:%M:%S").to_string(); + let log_message = format!("{} - {}\n", readable_time, message); + + let filepath = "/opt/watchdog/custom-logs/watchdog.logs"; + let mut file = OpenOptions::new() + .append(true) + .create(true) + .open(filepath).expect("Failed to open log file"); + + + file.write_all(log_message.as_bytes()).expect("Failed to write to log file"); + } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index e01bcaa..b5db349 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,7 +11,7 @@ use clap::{App, AppSettings, Arg, SubCommand}; use lib::config::{get_config_value, set_config_value}; use lib::errors::Error; - +use lib::logger; use auth::handle_auth; use ssh::{handle_ssh, handle_ssh_logs}; use su::{handle_su, handle_su_logs}; @@ -94,6 +94,7 @@ fn main() { std::process::exit(1); } } else if let Some(ref _matches) = matches.subcommand_matches("ssh") { + logger::logln("SSH Command"); if let Err(e) = handle_ssh() { println!("watchdog-ssh error: {}", e); print_traceback(e); @@ -104,13 +105,16 @@ fn main() { let keytype = matches.value_of("keytype").unwrap(); let user = matches.value_of("user").unwrap(); let ssh_key = format!("{} {}", keytype, pubkey); + logger::logln(&format!("ssh_key: {}", ssh_key)); if let Err(e) = handle_auth(&user, &ssh_key) { println!("watchdog-auth error: {}", e); + logger::logln(&format!("watchdog-auth error: {}", e)); print_traceback(e); std::process::exit(1); } } else if let Some(ref matches) = matches.subcommand_matches("logs") { let filter = matches.value_of("filter").unwrap(); + logger::logln(&format!("Filter: {}", filter)); if filter == "all" { handle_all_logs(); } else if filter == "sudo" { diff --git a/src/ssh.rs b/src/ssh.rs index ff92d00..6593295 100644 --- a/src/ssh.rs +++ b/src/ssh.rs @@ -14,18 +14,21 @@ use lib::logger; use lib::utils::SSH_LOG_PATH; pub fn handle_ssh() -> Result<()> { + logger::logln("in handle_ssh SSH Command"); let pam_type = env::var("PAM_TYPE") .chain_err(|| "PAM_TYPE not set. If you are running this by `watchdog ssh`, please don't. It's an internal command, intended to be used by PAM.")?; - + logger::logln(&format!("PAM_TYPE: {}", pam_type)); if pam_type == "open_session" { let config = read_config()?; init(&config)?; let env = read_temp_env("/opt/watchdog/ssh_env")?; + logger::logln(&format!("env: {{ ssh_host_username: {}, ssh_key: {} }}", env.ssh_host_username, env.ssh_key)); let name = get_name(&config, &env.ssh_key)?; if let Err(e) = logger::log(SSH_LOG_PATH, "SUCCESS", &format!("User: {}", name)) { println!("Failed to log: {}", e); } + logger::logln("Logging successful"); match fork() { Ok(ForkResult::Parent { .. }) => {} Ok(ForkResult::Child) => { @@ -38,6 +41,7 @@ pub fn handle_ssh() -> Result<()> { } pub fn handle_ssh_logs() { + logger::logln("in handle_ssh_logs"); Command::new("less") .arg("/opt/watchdog/logs/ssh.logs") .status() diff --git a/src/sudo.rs b/src/sudo.rs index 4a36694..c048ac7 100644 --- a/src/sudo.rs +++ b/src/sudo.rs @@ -16,13 +16,15 @@ pub fn handle_sudo() -> Result<()> { let pam_ruser = env::var("PAM_RUSER") .chain_err(|| "PAM_RUSER not set. If you are running this by `watchdog sudo`, please don't. It's an internal command, intended to be used by PAM.")?; - + logger::logln(&format!("PAM_RUSER: {}", pam_ruser)); + logger::logln(&format!("PAM_TYPE: {}", pam_type)); if pam_type == "open_session" { let config = read_config()?; init(&config)?; if let Err(e) = logger::log(SUDO_LOG_PATH, "SUCCESS", &format!("User: {}", pam_ruser)) { println!("Failed to log: {}", e); } + logger::logln("Logging successful"); match fork() { Ok(ForkResult::Parent { .. }) => {} Ok(ForkResult::Child) => { From d30e0b270ec0317a25e7c3d9f5ecc01424d0ec24 Mon Sep 17 00:00:00 2001 From: Arshdeep54 Date: Wed, 26 Feb 2025 16:47:18 +0530 Subject: [PATCH 06/30] add debug flag in logging Signed-off-by: Arshdeep54 --- sample.config.toml | 4 ++++ src/lib/config.rs | 10 ++++++++++ src/lib/logger.rs | 20 ++++++++++++++++++-- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/sample.config.toml b/sample.config.toml index 55644cd..d861a3d 100644 --- a/sample.config.toml +++ b/sample.config.toml @@ -22,3 +22,7 @@ token = 'secret_token' # app(https://slack.com/apps/A0F7XDUAZ-incoming-webhooks) # and paste the hook URL here. You can customize the icon and name as you like. slack = 'https://hooks.slack.com/services/ABCDEFGHI/ABCDEFGHI/abcdefghijklmnopqrstuvwx' + +# Logging +[logging] +debug=true \ No newline at end of file diff --git a/src/lib/config.rs b/src/lib/config.rs index fcc23d2..edb5713 100644 --- a/src/lib/config.rs +++ b/src/lib/config.rs @@ -16,11 +16,17 @@ pub struct NotifiersConf { pub slack: String, } +#[derive(Deserialize, Clone)] +pub struct LoggingConf { + pub debug: bool, +} + #[derive(Deserialize, Clone)] pub struct Config { pub hostname: String, pub keyhouse: KeyhouseConf, pub notifiers: NotifiersConf, + pub logging: LoggingConf, } pub fn read_config() -> Result { @@ -47,6 +53,9 @@ pub fn set_config_value(key: &str, val: &str) -> Result<()> { "notifiers.slack" => { doc["notifiers"]["slack"] = value(val); } + "logging.debug" => { + doc["logging"]["debug"] = value(val); + } _ => { return Err("Invalid Key passed".into()); } @@ -65,6 +74,7 @@ pub fn get_config_value(key: &str) -> Result { "keyhouse.base_url" => doc["keyhouse"]["base_url"].as_str(), "keyhouse.token" => doc["keyhouse"]["token"].as_str(), "notifiers.slack" => doc["notifiers"]["slack"].as_str(), + "logging.debug" => doc["logging"]["debug"].as_str(), _ => { return Err("Invalid Key passed".into()); } diff --git a/src/lib/logger.rs b/src/lib/logger.rs index 3bb3ac8..00fe88e 100644 --- a/src/lib/logger.rs +++ b/src/lib/logger.rs @@ -3,6 +3,7 @@ use std::io::Write; use std::time::{SystemTime, UNIX_EPOCH}; use std::io::Result; use chrono::{DateTime, Utc}; +use crate::config::{read_config, Config}; pub fn log(filepath: &str, status: &str, message: &str) -> Result<()> { let start = SystemTime::now(); @@ -22,6 +23,18 @@ pub fn log(filepath: &str, status: &str, message: &str) -> Result<()> { } pub fn logln(message: &str) { + let config = match read_config(){ + Ok(config) => config, + Err(_) => { + log("/opt/watchdog/custom-logs/watchdog.logs", "FAILURE", "Failed to read config").expect("Failed to log"); + return; + }, + }; + let debug=get_debug(&config); + if debug==false { + log("/opt/watchdog/custom-logs/watchdog.logs", "FAILURE", "debug false in logln").expect("Failed to log"); + return; + } let start = SystemTime::now(); let since_the_epoch = start.duration_since(UNIX_EPOCH).expect("Time went backwards"); let timestamp = since_the_epoch.as_secs(); @@ -35,6 +48,9 @@ pub fn logln(message: &str) { .create(true) .open(filepath).expect("Failed to open log file"); - file.write_all(log_message.as_bytes()).expect("Failed to write to log file"); - } \ No newline at end of file +} + +pub fn get_debug(config: &Config) -> bool { + config.logging.debug +} \ No newline at end of file From 518c01fa6a5c8e46e3a9b6b4d4980686a6aba430 Mon Sep 17 00:00:00 2001 From: Arshdeep54 Date: Sat, 22 Mar 2025 21:22:58 +0530 Subject: [PATCH 07/30] Implement projects as groups Signed-off-by: Arshdeep54 --- sample.config.toml | 3 ++- src/auth.rs | 22 +++-------------- src/lib/config.rs | 5 ++++ src/lib/keyhouse.rs | 57 +++++++++++++++++++++++++++++++++++++++++- src/lib/logger.rs | 11 +++++---- src/lib/notifier.rs | 10 ++++---- src/lib/utils.rs | 60 ++++++++++++++++++++++++++++++++++++++++++--- src/ssh.rs | 32 ++++++++++++++++++------ 8 files changed, 158 insertions(+), 42 deletions(-) diff --git a/sample.config.toml b/sample.config.toml index d861a3d..48965d6 100644 --- a/sample.config.toml +++ b/sample.config.toml @@ -25,4 +25,5 @@ slack = 'https://hooks.slack.com/services/ABCDEFGHI/ABCDEFGHI/abcdefghijklmnopqr # Logging [logging] -debug=true \ No newline at end of file +debug=true +offset="+5:30" \ No newline at end of file diff --git a/src/auth.rs b/src/auth.rs index f071074..854e2e6 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -1,5 +1,3 @@ -use std::fs; - use nix::unistd::{fork, ForkResult}; use lib::config::read_config; @@ -16,21 +14,7 @@ pub fn handle_auth(ssh_host_username: &str, ssh_key: &str) -> Result<()> { logger::logln(&format!("ssh_key in handle_auth: {}", ssh_key)); match validate_user(&config, ssh_host_username.to_string(), ssh_key) { Ok(true) => { - logger::logln("User validated"); - let data = format!( - "ssh_host_username = '{}'\nssh_key = '{}'\n", - ssh_host_username, ssh_key - ); - - fs::write("/opt/watchdog/ssh_env", data) - .chain_err(|| "Cannot write temporary environment file. Please check if the watchdog `auth_keys_cmd` is run by the root user")?; - logger::logln("Temporary environment file written"); - println!("{}", ssh_key); - let name = get_name(&config, ssh_key)?; - if let Err(e) = logger::log(AUTH_LOG_PATH, "SUCCESS", &format!("User: {}", name)) { - println!("Failed to log: {}", e); - } - logger::logln("Logging successful"); + logger::logln("User validated by handle auth"); Ok(()) } @@ -47,8 +31,8 @@ pub fn handle_auth(ssh_host_username: &str, ssh_key: &str) -> Result<()> { notifier::post_ssh_summary( &config, false, - name, - ssh_host_username.to_string(), + &name, + &ssh_host_username.to_string(), )?; std::process::exit(0); } diff --git a/src/lib/config.rs b/src/lib/config.rs index edb5713..7cbe75f 100644 --- a/src/lib/config.rs +++ b/src/lib/config.rs @@ -19,6 +19,7 @@ pub struct NotifiersConf { #[derive(Deserialize, Clone)] pub struct LoggingConf { pub debug: bool, + pub offset: String, } #[derive(Deserialize, Clone)] @@ -56,6 +57,9 @@ pub fn set_config_value(key: &str, val: &str) -> Result<()> { "logging.debug" => { doc["logging"]["debug"] = value(val); } + "logging.offset" => { + doc["logging"]["offset"] = value(val); + } _ => { return Err("Invalid Key passed".into()); } @@ -75,6 +79,7 @@ pub fn get_config_value(key: &str) -> Result { "keyhouse.token" => doc["keyhouse"]["token"].as_str(), "notifiers.slack" => doc["notifiers"]["slack"].as_str(), "logging.debug" => doc["logging"]["debug"].as_str(), + "logging.offset" => doc["logging"]["offset"].as_str(), _ => { return Err("Invalid Key passed".into()); } diff --git a/src/lib/keyhouse.rs b/src/lib/keyhouse.rs index 2306f4b..ad1922f 100644 --- a/src/lib/keyhouse.rs +++ b/src/lib/keyhouse.rs @@ -9,7 +9,7 @@ use crypto::digest::Digest; use crypto::sha2::Sha256; use crate::config::Config; -use crate::errors::*; +use crate::{errors::*, logger}; pub fn validate_user(config: &Config, user: String, ssh_key: &str) -> Result { let mut hasher = Sha256::new(); @@ -90,3 +90,58 @@ pub fn get_name(config: &Config, ssh_key: &str) -> Result { Err(e) => Err(Error::from(format!("Unknown reqwest error \n-> {}", e))), } } + +pub fn fetch_github_projects(config: &Config, user: &str) -> Result> { + let client = reqwest::Client::builder() + .timeout(Duration::from_secs(10)) + .build()?; + let res = client + .get(&format!( + "{}/data/hosts/{}?ref=master", + config.keyhouse.base_url, user + )) + .header( + "Authorization", + &format!("Bearer {}", config.keyhouse.token), + ) + .send(); + match res { + Ok(mut r) => { + if r.status().is_success() { + let json_text = r.text()?; + let json: serde_json::Value = serde_json::from_str(&json_text) + .map_err(|e| { + logger::logln(&format!("Failed to parse JSON from GitHub: {}", e)); + e + }) + .chain_err(|| "Invalid JSON received from GitHub.")?; + + let encoded_content = json["content"] + .as_str() + .ok_or_else(|| Error::from("Missing 'content' field in JSON."))?; + let content = base64::decode(encoded_content.trim_end()) + .chain_err(|| "Base64 decoding failed.")?; + let decoded_str = + String::from_utf8(content).chain_err(|| "UTF-8 decoding failed.")?; + logger::logln(&format!("Decoded string: {}", decoded_str)); + let projects = decoded_str + .lines() + .filter_map(|line| line.split('|').nth(1)) + .map(String::from) + .collect::>(); + logger::logln(&format!("Projects: {:?}", projects)); + Ok(projects) + } else { + logger::logln(&format!( + "GitHub API request failed with status: {}", + r.status() + )); + Err(Error::from(format!( + "GitHub API request failed with status: {}", + r.status() + ))) + } + } + Err(e) => Err(Error::from(format!("Unknown reqwest error \n-> {}", e))), + } +} diff --git a/src/lib/logger.rs b/src/lib/logger.rs index 00fe88e..5a0e228 100644 --- a/src/lib/logger.rs +++ b/src/lib/logger.rs @@ -4,6 +4,7 @@ use std::time::{SystemTime, UNIX_EPOCH}; use std::io::Result; use chrono::{DateTime, Utc}; use crate::config::{read_config, Config}; +use crate::utils::parse_offset; pub fn log(filepath: &str, status: &str, message: &str) -> Result<()> { let start = SystemTime::now(); @@ -35,11 +36,11 @@ pub fn logln(message: &str) { log("/opt/watchdog/custom-logs/watchdog.logs", "FAILURE", "debug false in logln").expect("Failed to log"); return; } - let start = SystemTime::now(); - let since_the_epoch = start.duration_since(UNIX_EPOCH).expect("Time went backwards"); - let timestamp = since_the_epoch.as_secs(); - let datetime = DateTime::::from(SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(timestamp)); - let readable_time = datetime.format("%Y-%m-%d %H:%M:%S").to_string(); + let offset = parse_offset(&config.logging.offset).expect("Invalid time offset format"); + let now_utc: DateTime = Utc::now(); + let local_time = now_utc.with_timezone(&offset); + + let readable_time = local_time.format("%Y-%m-%d %H:%M:%S").to_string(); let log_message = format!("{} - {}\n", readable_time, message); let filepath = "/opt/watchdog/custom-logs/watchdog.logs"; diff --git a/src/lib/notifier.rs b/src/lib/notifier.rs index a86f1d4..7f4ac73 100644 --- a/src/lib/notifier.rs +++ b/src/lib/notifier.rs @@ -63,13 +63,13 @@ pub fn post_su_summary(conf: &Config, from: String, to: String) -> Result<()> { pub fn post_ssh_summary( conf: &Config, success: bool, - user: String, - pam_ruser: String, + user: &String, + pam_ruser: &String, ) -> Result<()> { let global_notifier = setup(conf); for notif in &global_notifier.0 { - let user_copy = String::from(&user); - let pam_ruser_copy = String::from(&pam_ruser); + let user_copy = String::from(user); + let pam_ruser_copy = String::from(pam_ruser); notif.post_ssh_summary(conf, success, user_copy, pam_ruser_copy)?; } Ok(()) @@ -142,7 +142,7 @@ impl Notifier for Slack { } fn post_sudo_summary(&self, conf: &Config, pam_ruser: String) -> Result<()> { - let text = format!("sudo attempted on {}@{}", pam_ruser, conf.hostname); + let text = format!("{} attempted sudo on {}", pam_ruser, conf.hostname); let json = Slack::create_json(&text, "#36a64f")?; self.make_request(json) .chain_err(|| "Couldn't post sudo summary to Slack")?; diff --git a/src/lib/utils.rs b/src/lib/utils.rs index 1e0351a..46b0262 100644 --- a/src/lib/utils.rs +++ b/src/lib/utils.rs @@ -1,6 +1,6 @@ -use std::fs; - -use crate::errors::*; +use std::{fs, process::Command}; +use chrono::{DateTime, FixedOffset, Utc}; +use crate::{errors::*, logger}; pub const AUTH_LOG_PATH: &str = "/opt/watchdog/custom-logs/auth.logs"; pub const SSH_LOG_PATH: &str = "/opt/watchdog/custom-logs/ssh.logs"; @@ -12,10 +12,51 @@ pub fn clear_file(path: &str) -> Result<()> { Ok(()) } +pub fn add_user_to_groups(user: &str, groups: &[String]) -> Result<()> { + for group in groups { + if group != user { + Command::new("usermod") + .arg("-aG") + .arg(group) + .arg(user) + .output() + .chain_err(|| format!("Failed to add user {} to group {}", user, group))?; + logger::logln(&format!("User {} added to group {}", user, group)); + } + } + Ok(()) +} + +pub fn parse_offset(offset_str: &str) -> Result { + let sign = if offset_str.starts_with('+') { 1 } else { -1 }; + let parts: Vec<&str> = offset_str.trim_start_matches(&['+', '-'][..]).split(':').collect(); + + if parts.len() != 2 { + return Err("Invalid offset format".into()); + } + + let hours: i32 = parts[0].parse().map_err(|_| "Invalid hour format")?; + let minutes: i32 = parts[1].parse().map_err(|_| "Invalid minute format")?; + + let total_offset = sign * (hours * 3600 + minutes * 60); + let offset=FixedOffset::east_opt(total_offset).chain_err(|| "Invalid offset"); + let now_utc: DateTime = Utc::now(); + let offset_value = offset.unwrap(); + let local_time = now_utc.with_timezone(&offset_value); + + let readable_time = local_time.format("%Y-%m-%d %H:%M:%S").to_string(); + let log_message = format!("{} - {}\n", readable_time, "logging here in parse_offset_test"); + logger::logln(&log_message); + Ok(offset_value) +} + + #[cfg(test)] mod tests { + + use super::*; - use std::env; + use std::{env, fs}; #[test] fn clear_file_test() -> Result<()> { @@ -31,4 +72,15 @@ mod tests { assert_eq!(content, ""); Ok(()) } + + #[test] + fn parse_offset_test() -> Result<()> { + let offset_str = "+05:30"; + let offset = parse_offset(offset_str)?; + assert_eq!(offset, FixedOffset::east(19800)); + let offset_str = "-05:30"; + let offset = parse_offset(offset_str)?; + assert_eq!(offset, FixedOffset::west(19800)); + Ok(()) + } } diff --git a/src/ssh.rs b/src/ssh.rs index 6593295..440dce1 100644 --- a/src/ssh.rs +++ b/src/ssh.rs @@ -1,13 +1,13 @@ use std::env; use std::process::Command; +use lib::keyhouse::fetch_github_projects; +use lib::utils::add_user_to_groups; use nix::unistd::{fork, ForkResult}; use lib::config::read_config; -use lib::environment::read_temp_env; use lib::errors::*; use lib::init::init; -use lib::keyhouse::get_name; use lib::notifier; //use lib::utils::clear_file; use lib::logger; @@ -18,24 +18,40 @@ pub fn handle_ssh() -> Result<()> { let pam_type = env::var("PAM_TYPE") .chain_err(|| "PAM_TYPE not set. If you are running this by `watchdog ssh`, please don't. It's an internal command, intended to be used by PAM.")?; logger::logln(&format!("PAM_TYPE: {}", pam_type)); + let pam_ruser= env::var("PAM_RUSER") + .chain_err(|| "PAM_RUSER not set. If you are running this by `watchdog ssh`, please don't. It's an internal command, intended to be used by PAM.")?; if pam_type == "open_session" { let config = read_config()?; init(&config)?; - let env = read_temp_env("/opt/watchdog/ssh_env")?; - logger::logln(&format!("env: {{ ssh_host_username: {}, ssh_key: {} }}", env.ssh_host_username, env.ssh_key)); - let name = get_name(&config, &env.ssh_key)?; - if let Err(e) = logger::log(SSH_LOG_PATH, "SUCCESS", &format!("User: {}", name)) { + if let Err(e) = logger::log(SSH_LOG_PATH, "SUCCESS", &format!("User: {}", pam_ruser)) { println!("Failed to log: {}", e); } logger::logln("Logging successful"); match fork() { Ok(ForkResult::Parent { .. }) => {} Ok(ForkResult::Child) => { - notifier::post_ssh_summary(&config, true, name, env.ssh_host_username)?; + notifier::post_ssh_summary(&config, true, &pam_ruser,&pam_ruser)?; } Err(_) => println!("Fork failed"), } + + let mut projects = fetch_github_projects(&config, &pam_ruser)?; + + logger::logln(&format!("Fetched projects: {:?}", projects)); + + projects.retain(|p| p != &config.hostname); + + logger::logln(&format!("Filtered projects (excluding self): {:?}", projects)); + + match add_user_to_groups(&pam_ruser, &projects) { + Ok(_) => {} + Err(e) => { + logger::logln(&format!("Failed to add user to project groups: {}", e)); + } + } + + logger::logln("User successfully added to project groups."); } Ok(()) } @@ -47,3 +63,5 @@ pub fn handle_ssh_logs() { .status() .expect("Something went wrong. Is `less` command present in your environment?"); } + + From e85608603780a82cf5b6f02b0c2640a89d878dcf Mon Sep 17 00:00:00 2001 From: Arshdeep54 Date: Thu, 10 Apr 2025 23:59:11 +0530 Subject: [PATCH 08/30] Add watchdog update function Signed-off-by: Arshdeep54 --- src/auth.rs | 1 + src/lib/keyhouse.rs | 41 +++++++++++++++++++++++++++++++++++++++++ src/lib/utils.rs | 8 +------- src/main.rs | 14 ++++++++++++-- src/ssh.rs | 18 ------------------ src/update.rs | 44 ++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 99 insertions(+), 27 deletions(-) create mode 100644 src/update.rs diff --git a/src/auth.rs b/src/auth.rs index 854e2e6..d193d97 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -15,6 +15,7 @@ pub fn handle_auth(ssh_host_username: &str, ssh_key: &str) -> Result<()> { match validate_user(&config, ssh_host_username.to_string(), ssh_key) { Ok(true) => { logger::logln("User validated by handle auth"); + println!("{}", ssh_key); Ok(()) } diff --git a/src/lib/keyhouse.rs b/src/lib/keyhouse.rs index ad1922f..f301e08 100644 --- a/src/lib/keyhouse.rs +++ b/src/lib/keyhouse.rs @@ -7,6 +7,8 @@ use std::time::Duration; use crypto::digest::Digest; use crypto::sha2::Sha256; +use reqwest::Client; +use serde_json::Value; use crate::config::Config; use crate::{errors::*, logger}; @@ -145,3 +147,42 @@ pub fn fetch_github_projects(config: &Config, user: &str) -> Result> Err(e) => Err(Error::from(format!("Unknown reqwest error \n-> {}", e))), } } + +pub fn fetch_file_names( + base_url: &str, + directory: &str, + token: &str, + file_names: &mut Vec, +) -> Result<()> { + let client = Client::builder() + .timeout(std::time::Duration::from_secs(10)) + .build()?; + println!( + "Fetching file names from {}/{}?ref=master and token {}", + base_url, directory, token + ); + let mut response = client + .get(&format!("{}/{}?ref=master", base_url, directory)) + .header("Authorization", &format!("Bearer {}", token)) + .send()?; + + if response.status().is_success() { + let contents: Value = response.json()?; + if let Some(files) = contents.as_array() { + for file in files { + if let Some(file_name) = file["name"].as_str() { + file_names.push(file_name.to_string()); + } + } + } + } else { + return Err(format!( + "GitHub API request failed with status: {}", + response.status() + ) + .into()); + } + + println!("Fetched file names: {:?}", file_names); + Ok(()) +} \ No newline at end of file diff --git a/src/lib/utils.rs b/src/lib/utils.rs index 46b0262..63f6d56 100644 --- a/src/lib/utils.rs +++ b/src/lib/utils.rs @@ -1,5 +1,5 @@ use std::{fs, process::Command}; -use chrono::{DateTime, FixedOffset, Utc}; +use chrono::FixedOffset; use crate::{errors::*, logger}; pub const AUTH_LOG_PATH: &str = "/opt/watchdog/custom-logs/auth.logs"; @@ -40,13 +40,7 @@ pub fn parse_offset(offset_str: &str) -> Result { let total_offset = sign * (hours * 3600 + minutes * 60); let offset=FixedOffset::east_opt(total_offset).chain_err(|| "Invalid offset"); - let now_utc: DateTime = Utc::now(); let offset_value = offset.unwrap(); - let local_time = now_utc.with_timezone(&offset_value); - - let readable_time = local_time.format("%Y-%m-%d %H:%M:%S").to_string(); - let log_message = format!("{} - {}\n", readable_time, "logging here in parse_offset_test"); - logger::logln(&log_message); Ok(offset_value) } diff --git a/src/main.rs b/src/main.rs index b5db349..10b2683 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,7 +4,7 @@ mod auth; mod ssh; mod su; mod sudo; - +mod update; use std::process::Command; use clap::{App, AppSettings, Arg, SubCommand}; @@ -16,6 +16,7 @@ use auth::handle_auth; use ssh::{handle_ssh, handle_ssh_logs}; use su::{handle_su, handle_su_logs}; use sudo::{handle_sudo, handle_sudo_logs}; +use update::handle_update; fn make_app<'a, 'b>() -> App<'a, 'b> { App::new("Watchdog") @@ -65,6 +66,8 @@ fn make_app<'a, 'b>() -> App<'a, 'b> { .arg(Arg::with_name("value") .index(2) .help("Value to be set for the . If no value is passed, the current value is returned."))) + .subcommand(SubCommand::with_name("update")) + .about("Update users and groups from Keyhouse") } fn print_traceback(e: Error) { @@ -151,7 +154,14 @@ fn main() { } } }; - } else { + } else if let Some(ref _matches)= matches.subcommand_matches("update") { + if let Err(e) = handle_update() { + println!("watchdog-update error: {}", e); + print_traceback(e); + std::process::exit(1); + } + } + else { println!("No command passed"); std::process::exit(1); } diff --git a/src/ssh.rs b/src/ssh.rs index 440dce1..b3d59a3 100644 --- a/src/ssh.rs +++ b/src/ssh.rs @@ -1,8 +1,6 @@ use std::env; use std::process::Command; -use lib::keyhouse::fetch_github_projects; -use lib::utils::add_user_to_groups; use nix::unistd::{fork, ForkResult}; use lib::config::read_config; @@ -36,22 +34,6 @@ pub fn handle_ssh() -> Result<()> { Err(_) => println!("Fork failed"), } - let mut projects = fetch_github_projects(&config, &pam_ruser)?; - - logger::logln(&format!("Fetched projects: {:?}", projects)); - - projects.retain(|p| p != &config.hostname); - - logger::logln(&format!("Filtered projects (excluding self): {:?}", projects)); - - match add_user_to_groups(&pam_ruser, &projects) { - Ok(_) => {} - Err(e) => { - logger::logln(&format!("Failed to add user to project groups: {}", e)); - } - } - - logger::logln("User successfully added to project groups."); } Ok(()) } diff --git a/src/update.rs b/src/update.rs new file mode 100644 index 0000000..c05c130 --- /dev/null +++ b/src/update.rs @@ -0,0 +1,44 @@ + +use lib::keyhouse::fetch_file_names; +use lib::keyhouse::fetch_github_projects; +use lib::utils::add_user_to_groups; + +use lib::config::read_config; +use lib::errors::*; +use lib::init::init; +use lib::logger; + +pub fn handle_update() -> Result<()> { + let mut users: Vec= Vec::new(); + logger::logln("in handle_update"); + let config= read_config()?; + init(&config)?; + let _ = fetch_file_names(&config.keyhouse.base_url, "data/hosts", &config.keyhouse.token, &mut users)?; + logger::logln(&format!("Fetched users: {:?}", users)); + println!("Fetched users: {:?}", users); + for user in users.iter() { + match fetch_github_projects(&config, user) { + Ok(mut projects) => { + logger::logln(&format!("Fetched projects: {:?}", projects)); + projects.retain(|p| p != &config.hostname); + logger::logln(&format!( + "Filtered projects (excluding self): {:?}", + projects + )); + if let Err(e) = add_user_to_groups(user, &projects) { + logger::logln(&format!( + "Failed to add user {} to project groups: {}", + user, e + )); + } + } + Err(e) => { + logger::logln(&format!( + "Failed to fetch projects for user {}: {}", + user, e + )); + } + } + } + Ok(()) +} From 7d5e978fc03dba26fc369d4227635119376c7b4b Mon Sep 17 00:00:00 2001 From: Arshdeep54 Date: Fri, 11 Apr 2025 23:14:37 +0530 Subject: [PATCH 09/30] Restrict user to only login to his account Signed-off-by: Arshdeep54 --- src/lib/keyhouse.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/lib/keyhouse.rs b/src/lib/keyhouse.rs index f301e08..a10ee0e 100644 --- a/src/lib/keyhouse.rs +++ b/src/lib/keyhouse.rs @@ -14,6 +14,12 @@ use crate::config::Config; use crate::{errors::*, logger}; pub fn validate_user(config: &Config, user: String, ssh_key: &str) -> Result { + let name = get_name(&config, ssh_key)?; + logger::logln(&format!("User name: {}", name)); + if name != user { + return Ok(false); + } + let mut hasher = Sha256::new(); hasher.input_str(&ssh_key); From 9b3b9e18b47f63823fd104bd6cbc6ffeccca8829 Mon Sep 17 00:00:00 2001 From: Arshdeep54 Date: Sat, 12 Apr 2025 19:02:58 +0530 Subject: [PATCH 10/30] Update pam_ruser to pam_user Signed-off-by: Arshdeep54 --- sample.config.toml | 2 +- src/lib/config.rs | 2 +- src/lib/keyhouse.rs | 6 ++++-- src/lib/logger.rs | 6 +----- src/lib/notifier.rs | 14 +++++++------- src/ssh.rs | 8 ++++---- 6 files changed, 18 insertions(+), 20 deletions(-) diff --git a/sample.config.toml b/sample.config.toml index 48965d6..dc9b1c8 100644 --- a/sample.config.toml +++ b/sample.config.toml @@ -25,5 +25,5 @@ slack = 'https://hooks.slack.com/services/ABCDEFGHI/ABCDEFGHI/abcdefghijklmnopqr # Logging [logging] -debug=true +debug='true' offset="+5:30" \ No newline at end of file diff --git a/src/lib/config.rs b/src/lib/config.rs index 7cbe75f..4432a88 100644 --- a/src/lib/config.rs +++ b/src/lib/config.rs @@ -18,7 +18,7 @@ pub struct NotifiersConf { #[derive(Deserialize, Clone)] pub struct LoggingConf { - pub debug: bool, + pub debug: String, pub offset: String, } diff --git a/src/lib/keyhouse.rs b/src/lib/keyhouse.rs index a10ee0e..e22ef04 100644 --- a/src/lib/keyhouse.rs +++ b/src/lib/keyhouse.rs @@ -15,10 +15,12 @@ use crate::{errors::*, logger}; pub fn validate_user(config: &Config, user: String, ssh_key: &str) -> Result { let name = get_name(&config, ssh_key)?; - logger::logln(&format!("User name: {}", name)); - if name != user { + logger::logln(&format!("User name: {} ,user {}", name,user)); + if name.trim() != user.trim() { + logger::logln("User didnt match with name"); return Ok(false); } + logger::logln("User match with name"); let mut hasher = Sha256::new(); diff --git a/src/lib/logger.rs b/src/lib/logger.rs index 5a0e228..ce711f2 100644 --- a/src/lib/logger.rs +++ b/src/lib/logger.rs @@ -31,8 +31,7 @@ pub fn logln(message: &str) { return; }, }; - let debug=get_debug(&config); - if debug==false { + if &config.logging.debug=="false" { log("/opt/watchdog/custom-logs/watchdog.logs", "FAILURE", "debug false in logln").expect("Failed to log"); return; } @@ -52,6 +51,3 @@ pub fn logln(message: &str) { file.write_all(log_message.as_bytes()).expect("Failed to write to log file"); } -pub fn get_debug(config: &Config) -> bool { - config.logging.debug -} \ No newline at end of file diff --git a/src/lib/notifier.rs b/src/lib/notifier.rs index 7f4ac73..4c6f054 100644 --- a/src/lib/notifier.rs +++ b/src/lib/notifier.rs @@ -32,7 +32,7 @@ pub trait Notifier { conf: &Config, success: bool, user: String, - pam_ruser: String, + pam_user: String, ) -> Result<()>; } @@ -64,13 +64,13 @@ pub fn post_ssh_summary( conf: &Config, success: bool, user: &String, - pam_ruser: &String, + pam_user: &String, ) -> Result<()> { let global_notifier = setup(conf); for notif in &global_notifier.0 { let user_copy = String::from(user); - let pam_ruser_copy = String::from(pam_ruser); - notif.post_ssh_summary(conf, success, user_copy, pam_ruser_copy)?; + let pam_user_copy = String::from(pam_user); + notif.post_ssh_summary(conf, success, user_copy, pam_user_copy)?; } Ok(()) } @@ -162,17 +162,17 @@ impl Notifier for Slack { conf: &Config, success: bool, user: String, - pam_ruser: String, + pam_user: String, ) -> Result<()> { let color: &str; let text: String; if success { - text = format!("{} logged in on {}@{}", user, pam_ruser, conf.hostname); + text = format!("{} logged in on {}@{}", user, pam_user, conf.hostname); color = "#36a64f"; } else { text = format!( "{} tried to log in on {}@{}", - user, pam_ruser, conf.hostname + user, pam_user, conf.hostname ); color = "#f29513"; } diff --git a/src/ssh.rs b/src/ssh.rs index b3d59a3..2a145f6 100644 --- a/src/ssh.rs +++ b/src/ssh.rs @@ -16,20 +16,20 @@ pub fn handle_ssh() -> Result<()> { let pam_type = env::var("PAM_TYPE") .chain_err(|| "PAM_TYPE not set. If you are running this by `watchdog ssh`, please don't. It's an internal command, intended to be used by PAM.")?; logger::logln(&format!("PAM_TYPE: {}", pam_type)); - let pam_ruser= env::var("PAM_RUSER") - .chain_err(|| "PAM_RUSER not set. If you are running this by `watchdog ssh`, please don't. It's an internal command, intended to be used by PAM.")?; + let pam_user= env::var("PAM_USER") + .chain_err(|| "PAM_USER not set. If you are running this by `watchdog ssh`, please don't. It's an internal command, intended to be used by PAM.")?; if pam_type == "open_session" { let config = read_config()?; init(&config)?; - if let Err(e) = logger::log(SSH_LOG_PATH, "SUCCESS", &format!("User: {}", pam_ruser)) { + if let Err(e) = logger::log(SSH_LOG_PATH, "SUCCESS", &format!("User: {}", pam_user)) { println!("Failed to log: {}", e); } logger::logln("Logging successful"); match fork() { Ok(ForkResult::Parent { .. }) => {} Ok(ForkResult::Child) => { - notifier::post_ssh_summary(&config, true, &pam_ruser,&pam_ruser)?; + notifier::post_ssh_summary(&config, true, &pam_user,&pam_user)?; } Err(_) => println!("Fork failed"), } From 9dac407f1018482e61b4e05345b816f1564abf92 Mon Sep 17 00:00:00 2001 From: Arshdeep54 Date: Sun, 13 Apr 2025 17:20:05 +0530 Subject: [PATCH 11/30] Update validate user function Signed-off-by: Arshdeep54 --- src/lib/keyhouse.rs | 80 ++++++++++++++++++++++++++++++++------------- src/lib/logger.rs | 22 +++++++++---- 2 files changed, 73 insertions(+), 29 deletions(-) diff --git a/src/lib/keyhouse.rs b/src/lib/keyhouse.rs index e22ef04..a1b6f0f 100644 --- a/src/lib/keyhouse.rs +++ b/src/lib/keyhouse.rs @@ -1,6 +1,5 @@ extern crate base64; extern crate crypto; -extern crate reqwest; extern crate serde_json; use std::time::Duration; @@ -8,49 +7,86 @@ use std::time::Duration; use crypto::digest::Digest; use crypto::sha2::Sha256; use reqwest::Client; +use serde::Deserialize; use serde_json::Value; use crate::config::Config; use crate::{errors::*, logger}; +#[derive(Debug, Deserialize)] +struct NameFile { + name: String, +} + pub fn validate_user(config: &Config, user: String, ssh_key: &str) -> Result { let name = get_name(&config, ssh_key)?; - logger::logln(&format!("User name: {} ,user {}", name,user)); + logger::logln(&format!("User name: {} ,user {}", name, user)); if name.trim() != user.trim() { - logger::logln("User didnt match with name"); + logger::logln("User didn't match with name"); return Ok(false); } logger::logln("User match with name"); - - let mut hasher = Sha256::new(); + let mut hasher = Sha256::new(); hasher.input_str(&ssh_key); let hex = hasher.result_str(); + let host = &config.hostname; + + logger::logln(&format!("Found user hash {}", hex)); let client = reqwest::Client::builder() .timeout(Duration::from_secs(10)) .build()?; - let res = client - .get(&format!( - "{}/access/{}/{}/{}?ref=build", - config.keyhouse.base_url, config.hostname, user, hex - )) - .header( - "Authorization", - &format!("Bearer {}", config.keyhouse.token), - ) - .send(); - match res { + logger::logln(&format!("user {},host {}", user, host)); + + let host_url = format!("{}/access/{}?ref=build", config.keyhouse.base_url, host); + logger::logln(&format!("Host URL: {}", host_url)); + let name_files: Vec = match client + .get(&host_url) + .header("Authorization", format!("Bearer {}", config.keyhouse.token)) + .header("Accept", "application/vnd.github.v3+json") + .send() + { + Ok(mut r) if r.status().is_success() => { + let text = r.text()?; + logger::logln(&format!("Response: {:?}", text)); + serde_json::from_str(&text).unwrap_or_default() + } Ok(r) => { - if r.status().is_success() { + logger::logln(&format!("Failed to fetch names: {}", r.status())); + vec![] + } + Err(e) => { + logger::logln(&format!("Error fetching names: {:?}", e)); + vec![] + } + }; + let projects: Vec = name_files.into_iter().map(|f| f.name).collect(); + + logger::logln(&format!("Found projects: {:?} for host {}", projects, host)); + for project in &projects { + let project_url = format!( + "{}/access/{}/{}/{}?ref=build", + config.keyhouse.base_url, host, project, hex + ); + + match client + .get(&project_url) + .header("Authorization", format!("Bearer {}", config.keyhouse.token)) + .send() + { + Ok(mut resp) if resp.status().is_success() => { + let text = resp.text()?; + logger::logln(&format!("Response: {:?}", text)); + logger::logln("User validated"); return Ok(true); - } else { - return Ok(false); } + Ok(_) | Err(_) => continue, } - Err(e) => Err(Error::from(format!("Unknown reqwest error \n-> {}", e))), } + + Ok(false) } fn get_content_from_github_json(json_text: &str) -> Result { @@ -173,7 +209,7 @@ pub fn fetch_file_names( .get(&format!("{}/{}?ref=master", base_url, directory)) .header("Authorization", &format!("Bearer {}", token)) .send()?; - + if response.status().is_success() { let contents: Value = response.json()?; if let Some(files) = contents.as_array() { @@ -193,4 +229,4 @@ pub fn fetch_file_names( println!("Fetched file names: {:?}", file_names); Ok(()) -} \ No newline at end of file +} diff --git a/src/lib/logger.rs b/src/lib/logger.rs index ce711f2..9c61a03 100644 --- a/src/lib/logger.rs +++ b/src/lib/logger.rs @@ -1,17 +1,25 @@ use std::fs::OpenOptions; use std::io::Write; -use std::time::{SystemTime, UNIX_EPOCH}; use std::io::Result; use chrono::{DateTime, Utc}; -use crate::config::{read_config, Config}; +use crate::config::read_config; use crate::utils::parse_offset; pub fn log(filepath: &str, status: &str, message: &str) -> Result<()> { - let start = SystemTime::now(); - let since_the_epoch = start.duration_since(UNIX_EPOCH).expect("Time went backwards"); - let timestamp = since_the_epoch.as_secs(); - let datetime = DateTime::::from(SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(timestamp)); - let readable_time = datetime.format("%Y-%m-%d %H:%M:%S").to_string(); + let config = match read_config(){ + Ok(config) => config, + Err(_) => { + return Ok(()); + }, + }; + if config.logging.debug == "false" { + return Ok(()); + } + let offset = parse_offset(&config.logging.offset).expect("Invalid time offset format"); + let now_utc: DateTime = Utc::now(); + let local_time = now_utc.with_timezone(&offset); + + let readable_time = local_time.format("%Y-%m-%d %H:%M:%S").to_string(); let log_message = format!("{} - {} - {}\n", readable_time, status, message); let mut file = OpenOptions::new() From 29b2cc70b031cdd7012f7939dd408bbbe0852d6b Mon Sep 17 00:00:00 2001 From: Arshdeep54 Date: Mon, 14 Apr 2025 01:10:08 +0530 Subject: [PATCH 12/30] Update ssh message with threads Signed-off-by: Arshdeep54 --- sample.config.toml | 3 +- src/lib/config.rs | 13 ++- src/lib/notifier.rs | 185 ++++++++++++++++++++++-------------------- src/sudo.rs | 9 +- tests/logger_tests.rs | 24 ------ 5 files changed, 118 insertions(+), 116 deletions(-) delete mode 100644 tests/logger_tests.rs diff --git a/sample.config.toml b/sample.config.toml index dc9b1c8..a90cace 100644 --- a/sample.config.toml +++ b/sample.config.toml @@ -21,7 +21,8 @@ token = 'secret_token' # Make an incoming hook to your Slack workspace from this # app(https://slack.com/apps/A0F7XDUAZ-incoming-webhooks) # and paste the hook URL here. You can customize the icon and name as you like. -slack = 'https://hooks.slack.com/services/ABCDEFGHI/ABCDEFGHI/abcdefghijklmnopqrstuvwx' +token = 'bot_token' +channel = 'C0123456789' # Logging [logging] diff --git a/src/lib/config.rs b/src/lib/config.rs index 4432a88..90ed595 100644 --- a/src/lib/config.rs +++ b/src/lib/config.rs @@ -13,7 +13,8 @@ pub struct KeyhouseConf { #[derive(Deserialize, Clone)] pub struct NotifiersConf { - pub slack: String, + pub token: String, + pub channel: String, } #[derive(Deserialize, Clone)] @@ -51,8 +52,11 @@ pub fn set_config_value(key: &str, val: &str) -> Result<()> { "keyhouse.token" => { doc["keyhouse"]["token"] = value(val); } - "notifiers.slack" => { - doc["notifiers"]["slack"] = value(val); + "notifiers.token" => { + doc["notifiers"]["token"] = value(val); + } + "notifiers.channel" => { + doc["notifiers"]["channel"] = value(val); } "logging.debug" => { doc["logging"]["debug"] = value(val); @@ -77,7 +81,8 @@ pub fn get_config_value(key: &str) -> Result { "hostname" => doc["hostname"].as_str(), "keyhouse.base_url" => doc["keyhouse"]["base_url"].as_str(), "keyhouse.token" => doc["keyhouse"]["token"].as_str(), - "notifiers.slack" => doc["notifiers"]["slack"].as_str(), + "notifiers.token" => doc["notifiers"]["token"].as_str(), + "notifiers.channel" => doc["notifiers"]["channel"].as_str(), "logging.debug" => doc["logging"]["debug"].as_str(), "logging.offset" => doc["logging"]["offset"].as_str(), _ => { diff --git a/src/lib/notifier.rs b/src/lib/notifier.rs index 4c6f054..0a741b9 100644 --- a/src/lib/notifier.rs +++ b/src/lib/notifier.rs @@ -1,13 +1,12 @@ extern crate reqwest; extern crate serde_json; -use std::time::{SystemTime, UNIX_EPOCH}; - -use reqwest::header::CONTENT_TYPE; +use reqwest::header::{AUTHORIZATION, CONTENT_TYPE}; +use reqwest::Client; use serde_json::json; use crate::config::Config; -use crate::errors::*; +use crate::{errors::*, logger}; /// Notifier is an abstract trait to post messages to webhook /// @@ -18,12 +17,8 @@ pub trait Notifier { fn new(conf: &Config) -> Option where Self: Sized; - /// URL returns the webhook url of the Notifier - fn url(&self) -> &str; - /// Send request with message - fn make_request(&self, json: String) -> Result<()>; /// Post summary for sudo attempts - fn post_sudo_summary(&self, conf: &Config, pam_ruser: String) -> Result<()>; + fn post_sudo_summary(&self, conf: &Config, pam_ruser: String,pwd:String) -> Result<()>; /// Post summary for su attempts fn post_su_summary(&self, conf: &Config, from: String, to: String) -> Result<()>; /// Post summary for ssh attempts @@ -39,11 +34,10 @@ pub trait Notifier { struct GlobalNotifier(Vec>); /// Post summary for sudo attempts -pub fn post_sudo_summary(conf: &Config, pam_ruser: String) -> Result<()> { +pub fn post_sudo_summary(conf: &Config, pam_ruser: String,pwd:String) -> Result<()> { let global_notifier = setup(conf); for notif in &global_notifier.0 { - let pam_ruser_copy = String::from(&pam_ruser); - notif.post_sudo_summary(conf, pam_ruser_copy)? + notif.post_sudo_summary(conf, pam_ruser.clone(),pwd.clone())? } Ok(()) } @@ -52,9 +46,7 @@ pub fn post_sudo_summary(conf: &Config, pam_ruser: String) -> Result<()> { pub fn post_su_summary(conf: &Config, from: String, to: String) -> Result<()> { let global_notifier = setup(conf); for notif in &global_notifier.0 { - let from_copy = String::from(&from); - let to_copy = String::from(&to); - notif.post_su_summary(conf, from_copy, to_copy)?; + notif.post_su_summary(conf, from.clone(), to.clone())?; } Ok(()) } @@ -68,92 +60,122 @@ pub fn post_ssh_summary( ) -> Result<()> { let global_notifier = setup(conf); for notif in &global_notifier.0 { - let user_copy = String::from(user); - let pam_user_copy = String::from(pam_user); - notif.post_ssh_summary(conf, success, user_copy, pam_user_copy)?; + notif.post_ssh_summary(conf, success, user.clone(), pam_user.clone())?; } Ok(()) } fn setup(conf: &Config) -> GlobalNotifier { let mut register: Vec> = Vec::new(); - match Slack::new(conf) { - Some(slack) => { - register.push(Box::new(slack)); - } - None => {} - }; + if let Some(slack) = Slack::new(conf) { + register.push(Box::new(slack)); + } GlobalNotifier(register) } /// Implements `Notifier` trait for slack #[derive(Debug)] -pub struct Slack(String); +pub struct Slack { + token: String, + channel: String, + client: Client, +} impl Slack { - /// Creates JSON to be sent in the make_request - /// - /// Takes two arguments: `text` and `color`. - /// * `text` is the message to be displayed in the message on Slack. - /// It accepts markdown format string. - /// * `color` is a hexcode color string prefixed with `#`. - /// It's the color of message accent on Slack. - fn create_json(text: &str, color: &str) -> Result { - let start = SystemTime::now(); - let since_the_epoch = start.duration_since(UNIX_EPOCH)?; - let json_text = json!({ - "attachments": [ - { - "text": format!("{}", text), - "mrkdwn_in": ["text"], - "ts": format!("{}", since_the_epoch.as_secs()), - "color": format!("{}", color) - } - ] - }) - .to_string(); - Ok(json_text) + fn post_message(&self, text: &str, thread_ts: Option<&str>) -> Result<()> { + let mut payload = json!({ + "channel": self.channel, + "text": text + }); + if let Some(ts) = thread_ts { + payload["thread_ts"] = json!(ts); + } + logger::logln(&format!("Slack payload: {:?}", payload)); + let mut res = self + .client + .post("https://slack.com/api/chat.postMessage") + .header(AUTHORIZATION, format!("Bearer {}", self.token)) + .header(CONTENT_TYPE, "application/json") + .json(&payload) + .send() + .chain_err(|| "Failed to send Slack message")?; + + let body: serde_json::Value = res.json().chain_err(|| "Invalid JSON from Slack")?; + if !body["ok"].as_bool().unwrap_or(false) { + return Err(format!( + "Slack API error: {}", + body["error"].as_str().unwrap_or("unknown") + ) + .into()); + } + + Ok(()) + } + + fn fetch_latest_ts(&self) -> Result { + let mut res = self + .client + .get("https://slack.com/api/conversations.history") + .header(AUTHORIZATION, format!("Bearer {}", self.token)) + .query(&[("channel", &self.channel), ("limit", &"1".to_string())]) + .send() + .chain_err(|| "Failed to fetch message history")?; + logger::logln(&format!("Slack response: {:?}", res)); + let body: serde_json::Value = res.json().chain_err(|| "Invalid JSON from Slack")?; + if !body["ok"].as_bool().unwrap_or(false) { + return Err(format!( + "Slack history API error: {}", + body["error"].as_str().unwrap_or("unknown") + ) + .into()); + } + logger::logln(&format!("Slack body: {:?}", body)); + let ts = body["messages"] + .as_array() + .and_then(|arr| arr.first()) + .and_then(|msg| msg["ts"].as_str()) + .ok_or("No messages found in channel")?; + logger::logln(&format!("Slack timestamp: {:?}", ts)); + Ok(ts.to_string()) } } impl Notifier for Slack { fn new(conf: &Config) -> Option { - let url: &str = conf.notifiers.slack.trim(); - if url.len() == 0 { + let token = conf.notifiers.token.trim(); + let channel = conf.notifiers.channel.trim(); + + if token.is_empty() || channel.is_empty() { return None; } - Some(Slack(String::from(url))) - } - fn url(&self) -> &str { - &self.0 + Some(Slack { + token: token.to_string(), + channel: channel.to_string(), + client: Client::new(), + }) } - fn make_request(&self, json: String) -> Result<()> { - let client = reqwest::Client::new(); - let res = client - .post(self.url()) - .header(CONTENT_TYPE, "application/json") - .body(json) - .send(); + fn post_sudo_summary(&self, conf: &Config, pam_ruser: String,pwd:String) -> Result<()> { + let parent_text = format!("{} attempted sudo on {}", pam_ruser, conf.hostname); + self.post_message(&parent_text, None)?; + logger::logln(&format!("Posted parent message: {:?}", parent_text)); - res.chain_err(|| "Error while creating a request to Slack Webhook")?; - Ok(()) - } + let thread_ts = self.fetch_latest_ts()?; + logger::logln(&format!("Fetched thread timestamp: {:?}", thread_ts)); + + let pwd_text = format!("Attempted in :{} ", pwd); + self.post_message(&pwd_text, Some(&thread_ts))?; - fn post_sudo_summary(&self, conf: &Config, pam_ruser: String) -> Result<()> { - let text = format!("{} attempted sudo on {}", pam_ruser, conf.hostname); - let json = Slack::create_json(&text, "#36a64f")?; - self.make_request(json) - .chain_err(|| "Couldn't post sudo summary to Slack")?; Ok(()) } fn post_su_summary(&self, conf: &Config, from: String, to: String) -> Result<()> { - let text = format!("switched user from {} to {} on {}", from, to, conf.hostname); - let json = Slack::create_json(&text, "#36a64f")?; - self.make_request(json) - .chain_err(|| "Couldn't post su summary to Slack")?; + let text = format!( + "Switched user from *{}* to *{}* on {}", + from, to, conf.hostname + ); + self.post_message(&text, None)?; Ok(()) } @@ -164,21 +186,12 @@ impl Notifier for Slack { user: String, pam_user: String, ) -> Result<()> { - let color: &str; - let text: String; - if success { - text = format!("{} logged in on {}@{}", user, pam_user, conf.hostname); - color = "#36a64f"; + let text = if success { + format!("{} logged in on {}@{}", user, pam_user, conf.hostname) } else { - text = format!( - "{} tried to log in on {}@{}", - user, pam_user, conf.hostname - ); - color = "#f29513"; - } - let json = Slack::create_json(&text, color)?; - self.make_request(json) - .chain_err(|| "Couldn't post ssh summary to Slack")?; + format!("{} tried to log in on {}@{}", user, pam_user, conf.hostname) + }; + self.post_message(&text, None)?; Ok(()) } } diff --git a/src/sudo.rs b/src/sudo.rs index c048ac7..426f1f5 100644 --- a/src/sudo.rs +++ b/src/sudo.rs @@ -11,6 +11,7 @@ use lib::logger; use lib::utils::SUDO_LOG_PATH; pub fn handle_sudo() -> Result<()> { + logger::logln("Handling sudo command"); let pam_type = env::var("PAM_TYPE") .chain_err(|| "PAM_TYPE not set. If you are running this by `watchdog sudo`, please don't. It's an internal command, intended to be used by PAM.")?; @@ -28,7 +29,13 @@ pub fn handle_sudo() -> Result<()> { match fork() { Ok(ForkResult::Parent { .. }) => {} Ok(ForkResult::Child) => { - notifier::post_sudo_summary(&config, pam_ruser)?; + let pwd = env::var("PWD").unwrap_or_else(|_| { + std::env::current_dir() + .map(|p| p.display().to_string()) + .unwrap_or_else(|_| "".to_string()) + }); + logger::logln(&format!("PWD: {}", pwd)); + notifier::post_sudo_summary(&config, pam_ruser,pwd)?; } Err(_) => println!("Fork failed"), } diff --git a/tests/logger_tests.rs b/tests/logger_tests.rs deleted file mode 100644 index 523fff0..0000000 --- a/tests/logger_tests.rs +++ /dev/null @@ -1,24 +0,0 @@ -#[cfg(test)] -mod tests { - use std::fs; - use std::io::Read; - use lib::logger::log; - - #[test] - fn test_log() { - let filepath = "test_ssh.logs"; - let status = "INFO"; - let message = "Test log message"; - - log(filepath, status, message).expect("Failed to write log"); - - let mut file = fs::File::open(filepath).expect("Failed to open log file"); - let mut contents = String::new(); - file.read_to_string(&mut contents).expect("Failed to read log file"); - - assert!(contents.contains("Test log message")); - assert!(contents.contains("INFO")); - - fs::remove_file(filepath).expect("Failed to delete test log file"); - } -} \ No newline at end of file From badc2ed0eb855d7884cf1f754db900e2f0f4b724 Mon Sep 17 00:00:00 2001 From: Arshdeep54 Date: Tue, 15 Apr 2025 17:51:18 +0530 Subject: [PATCH 13/30] Implement logging with fern Signed-off-by: Arshdeep54 --- Cargo.lock | 12 ++++ Cargo.toml | 5 +- sample.config.toml | 2 +- src/auth.rs | 18 +++--- src/lib/keyhouse.rs | 47 +++++++------- src/lib/lib.rs | 2 +- src/lib/logger.rs | 146 ++++++++++++++++++++++++++++++-------------- src/lib/notifier.rs | 28 ++++----- src/lib/utils.rs | 19 +++--- src/main.rs | 24 +++++--- src/ssh.rs | 26 +++----- src/su.rs | 12 ++-- src/sudo.rs | 23 +++---- src/update.rs | 44 ++++++------- 14 files changed, 226 insertions(+), 182 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d38242f..26b35c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -391,6 +391,15 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "fern" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9f0c14694cbd524c8720dd69b0e3179344f04ebb5f90f2e4a440c6ea3b2f1ee" +dependencies = [ + "log", +] + [[package]] name = "flate2" version = "1.0.35" @@ -1989,6 +1998,9 @@ dependencies = [ "chrono", "clap", "error-chain", + "fern", + "lazy_static", + "log", "nix", "openssl", "openssl-sys", diff --git a/Cargo.toml b/Cargo.toml index 280a0cc..2290a92 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,9 @@ nix = "0.9.0" openssl = "0.10" openssl-sys = "0.9.58" chrono = "0.4" +log = "0.4" +fern = "0.6" +lazy_static = "1.5.0" [[ bin ]] name = "watchdog" @@ -26,4 +29,4 @@ path = "src/main.rs" [lib] name = "lib" -path = "src/lib/lib.rs" \ No newline at end of file +path = "src/lib/lib.rs" diff --git a/sample.config.toml b/sample.config.toml index a90cace..6edd0d5 100644 --- a/sample.config.toml +++ b/sample.config.toml @@ -27,4 +27,4 @@ channel = 'C0123456789' # Logging [logging] debug='true' -offset="+5:30" \ No newline at end of file +offset='+5:30' \ No newline at end of file diff --git a/src/auth.rs b/src/auth.rs index d193d97..83c86f2 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -1,3 +1,4 @@ +use log::{info,error}; use nix::unistd::{fork, ForkResult}; use lib::config::read_config; @@ -5,27 +6,22 @@ use lib::errors::*; use lib::init::init; use lib::keyhouse::{get_name, validate_user}; use lib::notifier; -use lib::logger; -use lib::utils::AUTH_LOG_PATH; pub fn handle_auth(ssh_host_username: &str, ssh_key: &str) -> Result<()> { let config = read_config()?; init(&config)?; - logger::logln(&format!("ssh_key in handle_auth: {}", ssh_key)); + info!(target: "auth", "ssh_key in handle_auth: {}", ssh_key); match validate_user(&config, ssh_host_username.to_string(), ssh_key) { Ok(true) => { - logger::logln("User validated by handle auth"); + info!(target: "auth", "User validated by handle auth"); println!("{}", ssh_key); Ok(()) } Ok(false) => { - logger::logln("User not validated"); + info!(target: "auth", "User not validated"); let name = get_name(&config, ssh_key)?; - if let Err(e) = logger::log(AUTH_LOG_PATH, "Failed", &format!("User: {}", name)) { - println!("Failed to log: {}", e); - } - logger::logln("Logging failed"); + info!(target: "auth", "Logging failed"); match fork() { Ok(ForkResult::Parent { .. }) => {} Ok(ForkResult::Child) => { @@ -35,14 +31,14 @@ pub fn handle_auth(ssh_host_username: &str, ssh_key: &str) -> Result<()> { &name, &ssh_host_username.to_string(), )?; - std::process::exit(0); + std::process::exit(0); } Err(_) => println!("Fork failed"), } Ok(()) } Err(e) => { - logger::logln("Error while validating user from keyhouse"); + error!(target: "auth", "Error while validating user from keyhouse"); Err(e).chain_err(|| "Error while validating user from keyhouse") } } diff --git a/src/lib/keyhouse.rs b/src/lib/keyhouse.rs index a1b6f0f..95a06ba 100644 --- a/src/lib/keyhouse.rs +++ b/src/lib/keyhouse.rs @@ -6,12 +6,13 @@ use std::time::Duration; use crypto::digest::Digest; use crypto::sha2::Sha256; +use log::info; use reqwest::Client; use serde::Deserialize; use serde_json::Value; use crate::config::Config; -use crate::{errors::*, logger}; +use crate::errors::*; #[derive(Debug, Deserialize)] struct NameFile { @@ -20,28 +21,28 @@ struct NameFile { pub fn validate_user(config: &Config, user: String, ssh_key: &str) -> Result { let name = get_name(&config, ssh_key)?; - logger::logln(&format!("User name: {} ,user {}", name, user)); + info!(target: "auth", "User name: {} ,user {}", name, user); if name.trim() != user.trim() { - logger::logln("User didn't match with name"); + info!(target: "auth", "User didn't match with name"); return Ok(false); } - logger::logln("User match with name"); + info!(target: "auth", "User match with name"); let mut hasher = Sha256::new(); hasher.input_str(&ssh_key); let hex = hasher.result_str(); let host = &config.hostname; - logger::logln(&format!("Found user hash {}", hex)); + info!(target: "auth", "Found user hash {}", hex); let client = reqwest::Client::builder() .timeout(Duration::from_secs(10)) .build()?; - logger::logln(&format!("user {},host {}", user, host)); + info!(target: "auth", "user {},host {}", user, host); let host_url = format!("{}/access/{}?ref=build", config.keyhouse.base_url, host); - logger::logln(&format!("Host URL: {}", host_url)); + info!(target: "auth", "Host URL: {}", host_url); let name_files: Vec = match client .get(&host_url) .header("Authorization", format!("Bearer {}", config.keyhouse.token)) @@ -50,21 +51,21 @@ pub fn validate_user(config: &Config, user: String, ssh_key: &str) -> Result { let text = r.text()?; - logger::logln(&format!("Response: {:?}", text)); + info!(target: "auth", "Response: {:?}", text); serde_json::from_str(&text).unwrap_or_default() } Ok(r) => { - logger::logln(&format!("Failed to fetch names: {}", r.status())); + info!(target: "auth", "Failed to fetch names: {}", r.status()); vec![] } Err(e) => { - logger::logln(&format!("Error fetching names: {:?}", e)); + info!(target: "auth", "Error fetching names: {:?}", e); vec![] } }; let projects: Vec = name_files.into_iter().map(|f| f.name).collect(); - logger::logln(&format!("Found projects: {:?} for host {}", projects, host)); + info!(target: "auth", "Found projects: {:?} for host {}", projects, host); for project in &projects { let project_url = format!( "{}/access/{}/{}/{}?ref=build", @@ -78,8 +79,8 @@ pub fn validate_user(config: &Config, user: String, ssh_key: &str) -> Result { let text = resp.text()?; - logger::logln(&format!("Response: {:?}", text)); - logger::logln("User validated"); + info!(target: "auth", "Response: {:?}", text); + info!(target: "auth", "User validated"); return Ok(true); } Ok(_) | Err(_) => continue, @@ -157,31 +158,27 @@ pub fn fetch_github_projects(config: &Config, user: &str) -> Result> let json_text = r.text()?; let json: serde_json::Value = serde_json::from_str(&json_text) .map_err(|e| { - logger::logln(&format!("Failed to parse JSON from GitHub: {}", e)); + info!(target: "update", "Failed to parse JSON from GitHub: {}", e); e }) .chain_err(|| "Invalid JSON received from GitHub.")?; - let encoded_content = json["content"] .as_str() .ok_or_else(|| Error::from("Missing 'content' field in JSON."))?; - let content = base64::decode(encoded_content.trim_end()) - .chain_err(|| "Base64 decoding failed.")?; + let cleaned_encoded = encoded_content.replace('\n', "").replace('\r', ""); + let content = + base64::decode(&cleaned_encoded).chain_err(|| "Base64 decoding failed.")?; let decoded_str = String::from_utf8(content).chain_err(|| "UTF-8 decoding failed.")?; - logger::logln(&format!("Decoded string: {}", decoded_str)); + info!(target: "update", "Decoded string: {}", decoded_str); let projects = decoded_str .lines() .filter_map(|line| line.split('|').nth(1)) .map(String::from) .collect::>(); - logger::logln(&format!("Projects: {:?}", projects)); Ok(projects) } else { - logger::logln(&format!( - "GitHub API request failed with status: {}", - r.status() - )); + info!(target: "update", "GitHub API request failed with status: {}", r.status()); Err(Error::from(format!( "GitHub API request failed with status: {}", r.status() @@ -201,7 +198,7 @@ pub fn fetch_file_names( let client = Client::builder() .timeout(std::time::Duration::from_secs(10)) .build()?; - println!( + info!(target: "update", "Fetching file names from {}/{}?ref=master and token {}", base_url, directory, token ); @@ -227,6 +224,6 @@ pub fn fetch_file_names( .into()); } - println!("Fetched file names: {:?}", file_names); + info!(target: "update", "Fetched file names: {:?}", file_names); Ok(()) } diff --git a/src/lib/lib.rs b/src/lib/lib.rs index 240017d..8d415dd 100644 --- a/src/lib/lib.rs +++ b/src/lib/lib.rs @@ -2,9 +2,9 @@ pub mod config; pub mod environment; pub mod init; pub mod keyhouse; +pub mod logger; pub mod notifier; pub mod utils; -pub mod logger; #[macro_use] extern crate error_chain; diff --git a/src/lib/logger.rs b/src/lib/logger.rs index 9c61a03..02463b5 100644 --- a/src/lib/logger.rs +++ b/src/lib/logger.rs @@ -1,61 +1,115 @@ -use std::fs::OpenOptions; -use std::io::Write; -use std::io::Result; -use chrono::{DateTime, Utc}; +use fern::{Dispatch, InitError}; +use log::{LevelFilter, Log}; +use std::{ + collections::HashMap, + fs, io, + sync::Mutex, +}; + use crate::config::read_config; use crate::utils::parse_offset; -pub fn log(filepath: &str, status: &str, message: &str) -> Result<()> { - let config = match read_config(){ - Ok(config) => config, - Err(_) => { - return Ok(()); - }, - }; +lazy_static::lazy_static! { + static ref TARGET_LOGGERS: Mutex>> = Mutex::new(HashMap::new()); +} + +pub fn init_logger() -> Result<(), InitError> { + let config = read_config().map_err(|_| { + InitError::from(io::Error::new( + io::ErrorKind::Other, + "Could not read config", + )) + })?; + if config.logging.debug == "false" { - return Ok(()); + return Ok(()); // No logging } - let offset = parse_offset(&config.logging.offset).expect("Invalid time offset format"); - let now_utc: DateTime = Utc::now(); - let local_time = now_utc.with_timezone(&offset); - let readable_time = local_time.format("%Y-%m-%d %H:%M:%S").to_string(); - let log_message = format!("{} - {} - {}\n", readable_time, status, message); + let offset = parse_offset(&config.logging.offset).map_err(|_| { + InitError::from(io::Error::new( + io::ErrorKind::Other, + "Invalid offset in config", + )) + })?; - let mut file = OpenOptions::new() - .append(true) - .create(true) - .open(filepath)?; + let base_dir = "/opt/watchdog/custom-logs"; + fs::create_dir_all(base_dir).map_err(|e| { + InitError::from(io::Error::new( + io::ErrorKind::Other, + format!("Failed to create log directory: {}", e), + )) + })?; - file.write_all(log_message.as_bytes())?; - Ok(()) + let logger = Box::new(PerTargetLogger { + base_dir: base_dir.to_string(), + offset, + }); + + log::set_boxed_logger(logger) + .map(|()| log::set_max_level(LevelFilter::Info)) + .map_err(InitError::SetLoggerError) } -pub fn logln(message: &str) { - let config = match read_config(){ - Ok(config) => config, - Err(_) => { - log("/opt/watchdog/custom-logs/watchdog.logs", "FAILURE", "Failed to read config").expect("Failed to log"); - return; - }, - }; - if &config.logging.debug=="false" { - log("/opt/watchdog/custom-logs/watchdog.logs", "FAILURE", "debug false in logln").expect("Failed to log"); - return; +use chrono::FixedOffset; + +struct PerTargetLogger { + base_dir: String, + offset: FixedOffset, +} + +impl log::Log for PerTargetLogger { + fn enabled(&self, metadata: &log::Metadata) -> bool { + metadata.level() <= LevelFilter::Info } - let offset = parse_offset(&config.logging.offset).expect("Invalid time offset format"); - let now_utc: DateTime = Utc::now(); - let local_time = now_utc.with_timezone(&offset); - let readable_time = local_time.format("%Y-%m-%d %H:%M:%S").to_string(); - let log_message = format!("{} - {}\n", readable_time, message); + fn log(&self, record: &log::Record) { + if !self.enabled(record.metadata()) { + return; + } + + let target = if record.target().is_empty(){ + "watchdog" + }else{ + record.target() + }; + let mut loggers = TARGET_LOGGERS.lock().unwrap(); - let filepath = "/opt/watchdog/custom-logs/watchdog.logs"; - let mut file = OpenOptions::new() - .append(true) - .create(true) - .open(filepath).expect("Failed to open log file"); + if !loggers.contains_key(target) { + let log_path = format!("{}/{}.logs", self.base_dir, target); + match fern::log_file(&log_path) { + Ok(file) => { + let (_level_filter, logger): (_, Box) = Dispatch::new() + .level(LevelFilter::Info) + .format({ + let offset = self.offset; + move |out, message, record| { + let time = chrono::Utc::now() + .with_timezone(&offset) + .format("%Y-%m-%d %H:%M:%S"); + out.finish(format_args!( + "{} [{}] {}", + time, + record.level(), + message + )) + } + }) + .chain(file) + .into_log(); - file.write_all(log_message.as_bytes()).expect("Failed to write to log file"); -} + loggers.insert(target.to_string(), logger); + } + Err(e) => { + eprintln!("Failed to create log file for {}: {}", target, e); + return; + } + } + } + if let Some(logger) = loggers.get(target) { + logger.log(record); + } + } + + fn flush(&self) {} +} diff --git a/src/lib/notifier.rs b/src/lib/notifier.rs index 0a741b9..e8263c1 100644 --- a/src/lib/notifier.rs +++ b/src/lib/notifier.rs @@ -1,13 +1,13 @@ extern crate reqwest; extern crate serde_json; +use crate::config::Config; +use crate::errors::*; +use log::info; use reqwest::header::{AUTHORIZATION, CONTENT_TYPE}; use reqwest::Client; use serde_json::json; -use crate::config::Config; -use crate::{errors::*, logger}; - /// Notifier is an abstract trait to post messages to webhook /// /// This trait can be implemented for various webhook based applications @@ -18,7 +18,7 @@ pub trait Notifier { where Self: Sized; /// Post summary for sudo attempts - fn post_sudo_summary(&self, conf: &Config, pam_ruser: String,pwd:String) -> Result<()>; + fn post_sudo_summary(&self, conf: &Config, pam_ruser: String, pwd: String) -> Result<()>; /// Post summary for su attempts fn post_su_summary(&self, conf: &Config, from: String, to: String) -> Result<()>; /// Post summary for ssh attempts @@ -34,10 +34,10 @@ pub trait Notifier { struct GlobalNotifier(Vec>); /// Post summary for sudo attempts -pub fn post_sudo_summary(conf: &Config, pam_ruser: String,pwd:String) -> Result<()> { +pub fn post_sudo_summary(conf: &Config, pam_ruser: String, pwd: String) -> Result<()> { let global_notifier = setup(conf); for notif in &global_notifier.0 { - notif.post_sudo_summary(conf, pam_ruser.clone(),pwd.clone())? + notif.post_sudo_summary(conf, pam_ruser.clone(), pwd.clone())? } Ok(()) } @@ -90,7 +90,7 @@ impl Slack { if let Some(ts) = thread_ts { payload["thread_ts"] = json!(ts); } - logger::logln(&format!("Slack payload: {:?}", payload)); + info!(target: "watchdog", "Slack payload: {:?}", payload); let mut res = self .client .post("https://slack.com/api/chat.postMessage") @@ -120,7 +120,7 @@ impl Slack { .query(&[("channel", &self.channel), ("limit", &"1".to_string())]) .send() .chain_err(|| "Failed to fetch message history")?; - logger::logln(&format!("Slack response: {:?}", res)); + info!(target: "watchdog", "Slack response: {:?}", res); let body: serde_json::Value = res.json().chain_err(|| "Invalid JSON from Slack")?; if !body["ok"].as_bool().unwrap_or(false) { return Err(format!( @@ -129,13 +129,13 @@ impl Slack { ) .into()); } - logger::logln(&format!("Slack body: {:?}", body)); + info!(target: "watchdog", "Slack body: {:?}", body); let ts = body["messages"] .as_array() .and_then(|arr| arr.first()) .and_then(|msg| msg["ts"].as_str()) .ok_or("No messages found in channel")?; - logger::logln(&format!("Slack timestamp: {:?}", ts)); + info!(target: "watchdog", "Slack timestamp: {:?}", ts); Ok(ts.to_string()) } } @@ -156,14 +156,14 @@ impl Notifier for Slack { }) } - fn post_sudo_summary(&self, conf: &Config, pam_ruser: String,pwd:String) -> Result<()> { + fn post_sudo_summary(&self, conf: &Config, pam_ruser: String, pwd: String) -> Result<()> { let parent_text = format!("{} attempted sudo on {}", pam_ruser, conf.hostname); self.post_message(&parent_text, None)?; - logger::logln(&format!("Posted parent message: {:?}", parent_text)); + info!(target: "watchdog", "Posted parent message: {:?}", parent_text); let thread_ts = self.fetch_latest_ts()?; - logger::logln(&format!("Fetched thread timestamp: {:?}", thread_ts)); - + info!(target: "watchdog", "Fetched thread timestamp: {:?}", thread_ts); + let pwd_text = format!("Attempted in :{} ", pwd); self.post_message(&pwd_text, Some(&thread_ts))?; diff --git a/src/lib/utils.rs b/src/lib/utils.rs index 63f6d56..1c0c3d5 100644 --- a/src/lib/utils.rs +++ b/src/lib/utils.rs @@ -1,7 +1,7 @@ -use std::{fs, process::Command}; +use crate::errors::*; use chrono::FixedOffset; -use crate::{errors::*, logger}; - +use log::info; +use std::{fs, process::Command}; pub const AUTH_LOG_PATH: &str = "/opt/watchdog/custom-logs/auth.logs"; pub const SSH_LOG_PATH: &str = "/opt/watchdog/custom-logs/ssh.logs"; pub const SUDO_LOG_PATH: &str = "/opt/watchdog/custom-logs/sudo.logs"; @@ -21,15 +21,18 @@ pub fn add_user_to_groups(user: &str, groups: &[String]) -> Result<()> { .arg(user) .output() .chain_err(|| format!("Failed to add user {} to group {}", user, group))?; - logger::logln(&format!("User {} added to group {}", user, group)); - } + info!(target: "update", "User {} added to group {}", user, group); + } } Ok(()) } pub fn parse_offset(offset_str: &str) -> Result { let sign = if offset_str.starts_with('+') { 1 } else { -1 }; - let parts: Vec<&str> = offset_str.trim_start_matches(&['+', '-'][..]).split(':').collect(); + let parts: Vec<&str> = offset_str + .trim_start_matches(&['+', '-'][..]) + .split(':') + .collect(); if parts.len() != 2 { return Err("Invalid offset format".into()); @@ -39,15 +42,13 @@ pub fn parse_offset(offset_str: &str) -> Result { let minutes: i32 = parts[1].parse().map_err(|_| "Invalid minute format")?; let total_offset = sign * (hours * 3600 + minutes * 60); - let offset=FixedOffset::east_opt(total_offset).chain_err(|| "Invalid offset"); + let offset = FixedOffset::east_opt(total_offset).chain_err(|| "Invalid offset"); let offset_value = offset.unwrap(); Ok(offset_value) } - #[cfg(test)] mod tests { - use super::*; use std::{env, fs}; diff --git a/src/main.rs b/src/main.rs index 10b2683..46d1d38 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,10 +9,11 @@ use std::process::Command; use clap::{App, AppSettings, Arg, SubCommand}; +use auth::handle_auth; use lib::config::{get_config_value, set_config_value}; use lib::errors::Error; -use lib::logger; -use auth::handle_auth; +use lib::logger::init_logger; +use log::{info,error}; use ssh::{handle_ssh, handle_ssh_logs}; use su::{handle_su, handle_su_logs}; use sudo::{handle_sudo, handle_sudo_logs}; @@ -83,23 +84,27 @@ fn print_traceback(e: Error) { fn main() { let app = make_app(); let matches = app.get_matches(); - + init_logger().unwrap(); + info!(target: "watchdog", "Watchdog started."); if let Some(ref _matches) = matches.subcommand_matches("sudo") { if let Err(e) = handle_sudo() { println!("watchdog-sudo error: {}", e); + error!("watchdog-sudo error: {}", e); print_traceback(e); std::process::exit(1); } } else if let Some(ref _matches) = matches.subcommand_matches("su") { if let Err(e) = handle_su() { println!("watchdog-su error: {}", e); + error!("watchdog-su error: {}", e); print_traceback(e); std::process::exit(1); } } else if let Some(ref _matches) = matches.subcommand_matches("ssh") { - logger::logln("SSH Command"); + info!("SSH Command"); if let Err(e) = handle_ssh() { println!("watchdog-ssh error: {}", e); + error!("watchdog-ssh error: {}", e); print_traceback(e); std::process::exit(1); } @@ -108,16 +113,15 @@ fn main() { let keytype = matches.value_of("keytype").unwrap(); let user = matches.value_of("user").unwrap(); let ssh_key = format!("{} {}", keytype, pubkey); - logger::logln(&format!("ssh_key: {}", ssh_key)); if let Err(e) = handle_auth(&user, &ssh_key) { println!("watchdog-auth error: {}", e); - logger::logln(&format!("watchdog-auth error: {}", e)); + error!("watchdog-auth error: {}", e); print_traceback(e); std::process::exit(1); } } else if let Some(ref matches) = matches.subcommand_matches("logs") { let filter = matches.value_of("filter").unwrap(); - logger::logln(&format!("Filter: {}", filter)); + info!("Filter: {}", filter); if filter == "all" { handle_all_logs(); } else if filter == "sudo" { @@ -154,14 +158,14 @@ fn main() { } } }; - } else if let Some(ref _matches)= matches.subcommand_matches("update") { + } else if let Some(ref _matches) = matches.subcommand_matches("update") { if let Err(e) = handle_update() { println!("watchdog-update error: {}", e); + error!("watchdog-update error: {}", e); print_traceback(e); std::process::exit(1); } - } - else { + } else { println!("No command passed"); std::process::exit(1); } diff --git a/src/ssh.rs b/src/ssh.rs index 2a145f6..43425c5 100644 --- a/src/ssh.rs +++ b/src/ssh.rs @@ -1,49 +1,39 @@ use std::env; use std::process::Command; -use nix::unistd::{fork, ForkResult}; - use lib::config::read_config; use lib::errors::*; use lib::init::init; use lib::notifier; -//use lib::utils::clear_file; -use lib::logger; -use lib::utils::SSH_LOG_PATH; +use log::{info, error}; +use nix::unistd::{fork, ForkResult}; pub fn handle_ssh() -> Result<()> { - logger::logln("in handle_ssh SSH Command"); + info!(target: "ssh", "in handle_ssh SSH Command"); let pam_type = env::var("PAM_TYPE") .chain_err(|| "PAM_TYPE not set. If you are running this by `watchdog ssh`, please don't. It's an internal command, intended to be used by PAM.")?; - logger::logln(&format!("PAM_TYPE: {}", pam_type)); + info!(target: "ssh", "PAM_TYPE: {}", pam_type); let pam_user= env::var("PAM_USER") .chain_err(|| "PAM_USER not set. If you are running this by `watchdog ssh`, please don't. It's an internal command, intended to be used by PAM.")?; if pam_type == "open_session" { let config = read_config()?; init(&config)?; - - if let Err(e) = logger::log(SSH_LOG_PATH, "SUCCESS", &format!("User: {}", pam_user)) { - println!("Failed to log: {}", e); - } - logger::logln("Logging successful"); + info!(target: "ssh", "Logging successful"); match fork() { Ok(ForkResult::Parent { .. }) => {} Ok(ForkResult::Child) => { - notifier::post_ssh_summary(&config, true, &pam_user,&pam_user)?; + notifier::post_ssh_summary(&config, true, &pam_user, &pam_user)?; } - Err(_) => println!("Fork failed"), + Err(_) => error!("Fork failed"), } - } Ok(()) } pub fn handle_ssh_logs() { - logger::logln("in handle_ssh_logs"); + info!(target: "ssh", "in handle_ssh_logs"); Command::new("less") .arg("/opt/watchdog/logs/ssh.logs") .status() .expect("Something went wrong. Is `less` command present in your environment?"); } - - diff --git a/src/su.rs b/src/su.rs index 9d1cb12..eb4d37f 100644 --- a/src/su.rs +++ b/src/su.rs @@ -1,14 +1,13 @@ use std::env; use std::process::Command; +use log::{info, error}; use nix::unistd::{fork, ForkResult}; use lib::config::read_config; use lib::errors::*; use lib::init::init; use lib::notifier; -use lib::logger; -use lib::utils::SU_LOG_PATH; pub fn handle_su() -> Result<()> { let pam_type = env::var("PAM_TYPE") @@ -19,19 +18,18 @@ pub fn handle_su() -> Result<()> { let pam_user = env::var("PAM_USER") .chain_err(|| "PAM_USER not set. If you are running this by `watchdog su`, please don't. It's an internal command, intended to be used by PAM.")?; - + info!(target: "su", "PAM_RUSER: {}", pam_ruser); + info!(target: "su", "PAM_USER: {}", pam_user); + info!(target: "su", "PAM_TYPE: {}", pam_type); if pam_type == "open_session" { let config = read_config()?; init(&config)?; - if let Err(e) = logger::log(SU_LOG_PATH, "SUCCESS", &format!("User: {}", pam_user)) { - println!("Failed to log: {}", e); - } match fork() { Ok(ForkResult::Parent { .. }) => {} Ok(ForkResult::Child) => { notifier::post_su_summary(&config, pam_ruser, pam_user)?; } - Err(_) => println!("Fork failed"), + Err(_) => error!("Fork failed"), } } Ok(()) diff --git a/src/sudo.rs b/src/sudo.rs index 426f1f5..b5f60d8 100644 --- a/src/sudo.rs +++ b/src/sudo.rs @@ -1,31 +1,26 @@ use std::env; use std::process::Command; -use nix::unistd::{fork, ForkResult}; - use lib::config::read_config; use lib::errors::*; use lib::init::init; use lib::notifier; -use lib::logger; -use lib::utils::SUDO_LOG_PATH; +use log::{info, error}; +use nix::unistd::{fork, ForkResult}; pub fn handle_sudo() -> Result<()> { - logger::logln("Handling sudo command"); + info!(target: "sudo", "Handling sudo command"); let pam_type = env::var("PAM_TYPE") .chain_err(|| "PAM_TYPE not set. If you are running this by `watchdog sudo`, please don't. It's an internal command, intended to be used by PAM.")?; let pam_ruser = env::var("PAM_RUSER") .chain_err(|| "PAM_RUSER not set. If you are running this by `watchdog sudo`, please don't. It's an internal command, intended to be used by PAM.")?; - logger::logln(&format!("PAM_RUSER: {}", pam_ruser)); - logger::logln(&format!("PAM_TYPE: {}", pam_type)); + info!(target: "sudo", "PAM_RUSER: {}", pam_ruser); + info!(target: "sudo", "PAM_TYPE: {}", pam_type); if pam_type == "open_session" { let config = read_config()?; init(&config)?; - if let Err(e) = logger::log(SUDO_LOG_PATH, "SUCCESS", &format!("User: {}", pam_ruser)) { - println!("Failed to log: {}", e); - } - logger::logln("Logging successful"); + info!(target: "sudo", "Logging successful"); match fork() { Ok(ForkResult::Parent { .. }) => {} Ok(ForkResult::Child) => { @@ -34,10 +29,10 @@ pub fn handle_sudo() -> Result<()> { .map(|p| p.display().to_string()) .unwrap_or_else(|_| "".to_string()) }); - logger::logln(&format!("PWD: {}", pwd)); - notifier::post_sudo_summary(&config, pam_ruser,pwd)?; + info!(target: "sudo", "PWD: {}", pwd); + notifier::post_sudo_summary(&config, pam_ruser, pwd)?; } - Err(_) => println!("Fork failed"), + Err(_) => error!("Fork failed"), } } diff --git a/src/update.rs b/src/update.rs index c05c130..5c7d12b 100644 --- a/src/update.rs +++ b/src/update.rs @@ -1,44 +1,38 @@ - -use lib::keyhouse::fetch_file_names; -use lib::keyhouse::fetch_github_projects; -use lib::utils::add_user_to_groups; - use lib::config::read_config; use lib::errors::*; use lib::init::init; -use lib::logger; +use lib::keyhouse::fetch_file_names; +use lib::keyhouse::fetch_github_projects; +use lib::utils::add_user_to_groups; +use log::{info, error}; pub fn handle_update() -> Result<()> { - let mut users: Vec= Vec::new(); - logger::logln("in handle_update"); - let config= read_config()?; + let mut users: Vec = Vec::new(); + log::info!(target: "update", "Watchdog update triggered."); + let config = read_config()?; init(&config)?; - let _ = fetch_file_names(&config.keyhouse.base_url, "data/hosts", &config.keyhouse.token, &mut users)?; - logger::logln(&format!("Fetched users: {:?}", users)); + let _ = fetch_file_names( + &config.keyhouse.base_url, + "data/hosts", + &config.keyhouse.token, + &mut users, + )?; + info!(target: "update", "Fetched users: {:?}", users); println!("Fetched users: {:?}", users); for user in users.iter() { match fetch_github_projects(&config, user) { Ok(mut projects) => { - logger::logln(&format!("Fetched projects: {:?}", projects)); + info!(target: "update", "Fetched projects for {}: {:?}",user, projects); projects.retain(|p| p != &config.hostname); - logger::logln(&format!( - "Filtered projects (excluding self): {:?}", - projects - )); + info!(target: "update","Filtered projects (excluding self): {:?}", projects); if let Err(e) = add_user_to_groups(user, &projects) { - logger::logln(&format!( - "Failed to add user {} to project groups: {}", - user, e - )); + info!(target: "update","Failed to add user {} to project groups: {}", user, e); } } Err(e) => { - logger::logln(&format!( - "Failed to fetch projects for user {}: {}", - user, e - )); + error!(target: "update", "Failed to fetch projects for user {}: {}", user, e); } } } - Ok(()) + Ok(()) } From abcac32d72b8d1cb8aaa0db3216993828c4c48a7 Mon Sep 17 00:00:00 2001 From: Arshdeep54 Date: Wed, 16 Apr 2025 00:02:44 +0530 Subject: [PATCH 14/30] Add logs filtering Signed-off-by: Arshdeep54 --- src/auth.rs | 2 +- src/lib/keyhouse.rs | 2 +- src/lib/logger.rs | 101 +++++++++++++++++++++++++--- src/main.rs | 156 ++++++++++++++++++++++++++------------------ src/ssh.rs | 11 +--- src/su.rs | 10 +-- src/sudo.rs | 10 +-- src/update.rs | 2 +- 8 files changed, 191 insertions(+), 103 deletions(-) diff --git a/src/auth.rs b/src/auth.rs index 83c86f2..6cc4edf 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -1,4 +1,4 @@ -use log::{info,error}; +use log::{error, info}; use nix::unistd::{fork, ForkResult}; use lib::config::read_config; diff --git a/src/lib/keyhouse.rs b/src/lib/keyhouse.rs index 95a06ba..0f3d5c8 100644 --- a/src/lib/keyhouse.rs +++ b/src/lib/keyhouse.rs @@ -198,7 +198,7 @@ pub fn fetch_file_names( let client = Client::builder() .timeout(std::time::Duration::from_secs(10)) .build()?; - info!(target: "update", + info!(target: "update", "Fetching file names from {}/{}?ref=master and token {}", base_url, directory, token ); diff --git a/src/lib/logger.rs b/src/lib/logger.rs index 02463b5..8ac190d 100644 --- a/src/lib/logger.rs +++ b/src/lib/logger.rs @@ -1,10 +1,9 @@ use fern::{Dispatch, InitError}; use log::{LevelFilter, Log}; -use std::{ - collections::HashMap, - fs, io, - sync::Mutex, -}; +use std::fs::File; +use std::io::{BufRead, BufReader}; +use std::path::Path; +use std::{collections::HashMap, fs, io, sync::Mutex}; use crate::config::read_config; use crate::utils::parse_offset; @@ -22,7 +21,7 @@ pub fn init_logger() -> Result<(), InitError> { })?; if config.logging.debug == "false" { - return Ok(()); // No logging + return Ok(()); } let offset = parse_offset(&config.logging.offset).map_err(|_| { @@ -50,7 +49,7 @@ pub fn init_logger() -> Result<(), InitError> { .map_err(InitError::SetLoggerError) } -use chrono::FixedOffset; +use chrono::{DateTime, FixedOffset, NaiveDateTime, TimeZone, Utc}; struct PerTargetLogger { base_dir: String, @@ -67,9 +66,9 @@ impl log::Log for PerTargetLogger { return; } - let target = if record.target().is_empty(){ + let target = if record.target().is_empty() { "watchdog" - }else{ + } else { record.target() }; let mut loggers = TARGET_LOGGERS.lock().unwrap(); @@ -113,3 +112,87 @@ impl log::Log for PerTargetLogger { fn flush(&self) {} } + +pub fn handle_logs_for(component: &str, level: Option<&str>) { + let path = format!("/opt/watchdog/custom-logs/{}.logs", component); + let path = Path::new(&path); + + if !path.exists() { + eprintln!("Log file for component '{}' does not exist.", component); + return; + } + + let file = File::open(path).expect("Unable to open log file"); + let reader = BufReader::new(file); + + let filter_level = level.map(|lvl| lvl.to_uppercase()); + + for line in reader.lines() { + let line = line.unwrap_or_default(); + + if let Some(start) = line.find('[') { + if let Some(end) = line.find(']') { + let level_in_line = &line[start + 1..end]; + + if let Some(ref lvl) = filter_level { + if level_in_line == lvl { + println!("{}", line); + } + } else { + println!("{}", line); + } + } + } + } +} + +pub fn handle_logs_all(level: Option<&str>) { + let log_dir = Path::new("/opt/watchdog/custom-logs"); + let mut all_logs = Vec::new(); + println!("Fetching logs from directory: {}", log_dir.display()); + + if let Ok(entries) = fs::read_dir(log_dir) { + for entry in entries.flatten() { + println!("Processing file: {}", entry.path().display()); + if let Ok(file) = fs::File::open(entry.path()) { + let reader = io::BufReader::new(file); + + for line in reader.lines().flatten() { + if let Some((timestamp_str, rest)) = line.split_once(' ') { + let full_ts = timestamp_str.to_string() + + " " + + rest.split_whitespace().next().unwrap_or(""); + + if let Ok(naive_dt) = + NaiveDateTime::parse_from_str(&full_ts, "%Y-%m-%d %H:%M:%S") + { + let datetime: DateTime = Utc.from_utc_datetime(&naive_dt); + + let message = line[full_ts.len()..].trim_start(); + + let passes_level_filter = match level { + Some(target_level) => { + let formatted_level = + format!("[{}]", target_level.to_uppercase()); + message.contains(&formatted_level) + } + None => true, + }; + + if passes_level_filter { + all_logs.push((datetime, line.clone())); + } + } + } + } + } + } + } + + println!("Sorting logs by timestamp...{}", all_logs.len()); + all_logs.sort_by_key(|(dt, _)| *dt); + + for (_, log_line) in all_logs { + println!("{}", log_line); + } +} diff --git a/src/main.rs b/src/main.rs index 46d1d38..e376385 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,18 +5,16 @@ mod ssh; mod su; mod sudo; mod update; -use std::process::Command; use clap::{App, AppSettings, Arg, SubCommand}; use auth::handle_auth; -use lib::config::{get_config_value, set_config_value}; use lib::errors::Error; -use lib::logger::init_logger; -use log::{info,error}; -use ssh::{handle_ssh, handle_ssh_logs}; -use su::{handle_su, handle_su_logs}; -use sudo::{handle_sudo, handle_sudo_logs}; +use lib::logger::{handle_logs_all, handle_logs_for, init_logger}; +use log::{error, info}; +use ssh::handle_ssh; +use su::handle_su; +use sudo::handle_sudo; use update::handle_update; fn make_app<'a, 'b>() -> App<'a, 'b> { @@ -24,14 +22,68 @@ fn make_app<'a, 'b>() -> App<'a, 'b> { .version("0.1.0") .author("SDSLabs ") .about("Simple server access management system on a binary") - .subcommand(SubCommand::with_name("logs") - .about("Get the global watchdog logs") - .arg(Arg::with_name("filter") - .short("f") - .long("filter") - .help("Filter logs according to service. Can take value among `su`, `sudo`, `ssh` or `all`") - .takes_value(true) - .default_value("all"))) + .subcommand( + SubCommand::with_name("logs") + .about("Fetch logs from watchdog components") + .arg(Arg::with_name("level") + .long("level") + .takes_value(true) + .help("Filter log level when no component is specified (defaults to 'watchdog')")) + .subcommand( + SubCommand::with_name("all") + .about("Logs from whole watchdog") + .arg(Arg::with_name("level") + .short("l") + .long("level") + .takes_value(true) + .help("Filter by log level: info, warn, error")) + ) + .subcommand( + SubCommand::with_name("update") + .about("Logs from watchdog update") + .arg(Arg::with_name("level") + .short("l") + .long("level") + .takes_value(true) + .help("Filter by log level: info, warn, error")) + ) + .subcommand( + SubCommand::with_name("sudo") + .about("Logs from sudo") + .arg(Arg::with_name("level") + .short("l") + .long("level") + .takes_value(true) + .help("Filter by log level")) + ) + .subcommand( + SubCommand::with_name("su") + .about("Logs from su") + .arg(Arg::with_name("level") + .short("l") + .long("level") + .takes_value(true) + .help("Filter by log level")) + ) + .subcommand( + SubCommand::with_name("ssh") + .about("Logs from ssh") + .arg(Arg::with_name("level") + .short("l") + .long("level") + .takes_value(true) + .help("Filter by log level")) + ) + .subcommand( + SubCommand::with_name("watchdog") + .about("Logs from watchdog") + .arg(Arg::with_name("level") + .short("l") + .long("level") + .takes_value(true) + .help("Filter by log level")) + ) + ) .subcommand(SubCommand::with_name("sudo") .about("Handles the PAM sudo calls by pam_exec for Watchdog")) .subcommand(SubCommand::with_name("su") @@ -86,7 +138,32 @@ fn main() { let matches = app.get_matches(); init_logger().unwrap(); info!(target: "watchdog", "Watchdog started."); - if let Some(ref _matches) = matches.subcommand_matches("sudo") { + if let Some(logs_matches) = matches.subcommand_matches("logs") { + let level = logs_matches.value_of("level"); + match logs_matches.subcommand() { + ("all", Some(sub_m)) => { + handle_logs_all(sub_m.value_of("level").or(level)); + } + ("update", Some(sub_m)) => { + handle_logs_for("update", sub_m.value_of("level").or(level)); + } + ("sudo", Some(sub_m)) => { + handle_logs_for("sudo", sub_m.value_of("level").or(level)); + } + ("su", Some(sub_m)) => { + handle_logs_for("su", sub_m.value_of("level").or(level)); + } + ("ssh", Some(sub_m)) => { + handle_logs_for("ssh", sub_m.value_of("level").or(level)); + } + ("watchdog", Some(sub_m)) => { + handle_logs_for("watchdog", sub_m.value_of("level").or(level)); + } + _ => { + handle_logs_for("watchdog", level); + } + } + } else if let Some(ref _matches) = matches.subcommand_matches("sudo") { if let Err(e) = handle_sudo() { println!("watchdog-sudo error: {}", e); error!("watchdog-sudo error: {}", e); @@ -119,45 +196,6 @@ fn main() { print_traceback(e); std::process::exit(1); } - } else if let Some(ref matches) = matches.subcommand_matches("logs") { - let filter = matches.value_of("filter").unwrap(); - info!("Filter: {}", filter); - if filter == "all" { - handle_all_logs(); - } else if filter == "sudo" { - handle_sudo_logs(); - } else if filter == "su" { - handle_su_logs(); - } else if filter == "ssh" { - handle_ssh_logs(); - } else { - println!("Invalid Filter"); - std::process::exit(1); - } - } else if let Some(ref matches) = matches.subcommand_matches("config") { - let key = matches.value_of("key").unwrap(); - let val = matches.value_of("value"); - let _ = match val { - Some(v) => { - match set_config_value(key, v) { - Ok(()) => {} - Err(e) => { - println!("watchdog-config error: {}", e); - std::process::exit(1); - } - }; - } - None => { - let v = get_config_value(key); - match v { - Ok(s) => println!("{}", s), - Err(e) => { - println!("watchdog-config error: {}", e); - std::process::exit(1); - } - } - } - }; } else if let Some(ref _matches) = matches.subcommand_matches("update") { if let Err(e) = handle_update() { println!("watchdog-update error: {}", e); @@ -170,11 +208,3 @@ fn main() { std::process::exit(1); } } - -fn handle_all_logs() { - /* TODO: Unimplemented function */ - Command::new("less") - .arg("/opt/watchdog/logs/sudo.logs") - .status() - .expect("Something went wrong. Is `less` command present in your environment?"); -} diff --git a/src/ssh.rs b/src/ssh.rs index 43425c5..505d79a 100644 --- a/src/ssh.rs +++ b/src/ssh.rs @@ -1,11 +1,10 @@ use std::env; -use std::process::Command; use lib::config::read_config; use lib::errors::*; use lib::init::init; use lib::notifier; -use log::{info, error}; +use log::{error, info}; use nix::unistd::{fork, ForkResult}; pub fn handle_ssh() -> Result<()> { @@ -29,11 +28,3 @@ pub fn handle_ssh() -> Result<()> { } Ok(()) } - -pub fn handle_ssh_logs() { - info!(target: "ssh", "in handle_ssh_logs"); - Command::new("less") - .arg("/opt/watchdog/logs/ssh.logs") - .status() - .expect("Something went wrong. Is `less` command present in your environment?"); -} diff --git a/src/su.rs b/src/su.rs index eb4d37f..6102d39 100644 --- a/src/su.rs +++ b/src/su.rs @@ -1,7 +1,6 @@ use std::env; -use std::process::Command; -use log::{info, error}; +use log::{error, info}; use nix::unistd::{fork, ForkResult}; use lib::config::read_config; @@ -34,10 +33,3 @@ pub fn handle_su() -> Result<()> { } Ok(()) } - -pub fn handle_su_logs() { - Command::new("less") - .arg("/opt/watchdog/logs/su.logs") - .status() - .expect("Something went wrong. Is `less` command present in your environment?"); -} diff --git a/src/sudo.rs b/src/sudo.rs index b5f60d8..1058b52 100644 --- a/src/sudo.rs +++ b/src/sudo.rs @@ -1,11 +1,10 @@ use std::env; -use std::process::Command; use lib::config::read_config; use lib::errors::*; use lib::init::init; use lib::notifier; -use log::{info, error}; +use log::{error, info}; use nix::unistd::{fork, ForkResult}; pub fn handle_sudo() -> Result<()> { @@ -38,10 +37,3 @@ pub fn handle_sudo() -> Result<()> { Ok(()) } - -pub fn handle_sudo_logs() { - Command::new("less") - .arg("/opt/watchdog/logs/sudo.logs") - .status() - .expect("Something went wrong. Is `less` command present in your environment?"); -} diff --git a/src/update.rs b/src/update.rs index 5c7d12b..8f85fec 100644 --- a/src/update.rs +++ b/src/update.rs @@ -4,7 +4,7 @@ use lib::init::init; use lib::keyhouse::fetch_file_names; use lib::keyhouse::fetch_github_projects; use lib::utils::add_user_to_groups; -use log::{info, error}; +use log::{error, info}; pub fn handle_update() -> Result<()> { let mut users: Vec = Vec::new(); From 80da0a0e3c7dd5f22049d468fefffb951193b3cd Mon Sep 17 00:00:00 2001 From: Arshdeep54 Date: Wed, 16 Apr 2025 00:30:30 +0530 Subject: [PATCH 15/30] Update handle_update to add new users Signed-off-by: Arshdeep54 --- src/lib/utils.rs | 11 +++++++++++ src/update.rs | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/lib/utils.rs b/src/lib/utils.rs index 1c0c3d5..a7cdf43 100644 --- a/src/lib/utils.rs +++ b/src/lib/utils.rs @@ -27,6 +27,17 @@ pub fn add_user_to_groups(user: &str, groups: &[String]) -> Result<()> { Ok(()) } +pub fn create_linux_user(username: &str) -> Result<()> { + Command::new("useradd") + .arg("--no-create-home") + .arg("--system") + .arg(username) + .status() + .chain_err(|| format!("Failed to add user {}", username))?; + info!(target: "update", "User {} added", username); + Ok(()) +} + pub fn parse_offset(offset_str: &str) -> Result { let sign = if offset_str.starts_with('+') { 1 } else { -1 }; let parts: Vec<&str> = offset_str diff --git a/src/update.rs b/src/update.rs index 8f85fec..9c88b64 100644 --- a/src/update.rs +++ b/src/update.rs @@ -1,9 +1,12 @@ +use std::process::Command; + use lib::config::read_config; use lib::errors::*; use lib::init::init; use lib::keyhouse::fetch_file_names; use lib::keyhouse::fetch_github_projects; use lib::utils::add_user_to_groups; +use lib::utils::create_linux_user; use log::{error, info}; pub fn handle_update() -> Result<()> { @@ -20,6 +23,14 @@ pub fn handle_update() -> Result<()> { info!(target: "update", "Fetched users: {:?}", users); println!("Fetched users: {:?}", users); for user in users.iter() { + match create_linux_user(user) { + Ok(_) => { + info!(target: "update", "User {} created successfully.", user); + } + Err(e) => { + error!(target: "update", "Failed to create user {}: {}", user, e); + } + } match fetch_github_projects(&config, user) { Ok(mut projects) => { info!(target: "update", "Fetched projects for {}: {:?}",user, projects); From 86ed5735e056692c67723eaae7bb1f0781d16643 Mon Sep 17 00:00:00 2001 From: Arshdeep54 Date: Thu, 17 Apr 2025 21:49:34 +0530 Subject: [PATCH 16/30] Update logs and create_user function Signed-off-by: Arshdeep54 --- src/lib/keyhouse.rs | 4 ++-- src/lib/utils.rs | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/lib/keyhouse.rs b/src/lib/keyhouse.rs index 0f3d5c8..4a2a60b 100644 --- a/src/lib/keyhouse.rs +++ b/src/lib/keyhouse.rs @@ -199,8 +199,8 @@ pub fn fetch_file_names( .timeout(std::time::Duration::from_secs(10)) .build()?; info!(target: "update", - "Fetching file names from {}/{}?ref=master and token {}", - base_url, directory, token + "Fetching file names from {}/{}?ref=master", + base_url, directory ); let mut response = client .get(&format!("{}/{}?ref=master", base_url, directory)) diff --git a/src/lib/utils.rs b/src/lib/utils.rs index a7cdf43..0b3f1b0 100644 --- a/src/lib/utils.rs +++ b/src/lib/utils.rs @@ -29,8 +29,10 @@ pub fn add_user_to_groups(user: &str, groups: &[String]) -> Result<()> { pub fn create_linux_user(username: &str) -> Result<()> { Command::new("useradd") - .arg("--no-create-home") - .arg("--system") + .arg("-m") + .arg("-d") + .arg("/home") + .args(&["-s", "/bin/bash"]) .arg(username) .status() .chain_err(|| format!("Failed to add user {}", username))?; From e090e78bb34553de61db99073cf6682a59a18a69 Mon Sep 17 00:00:00 2001 From: Arshdeep54 Date: Fri, 18 Apr 2025 23:47:49 +0530 Subject: [PATCH 17/30] Fix fetching from master branch Signed-off-by: Arshdeep54 --- src/lib/keyhouse.rs | 151 ++++++++++++++++++++++++-------------------- src/lib/utils.rs | 4 +- src/update.rs | 26 ++++---- 3 files changed, 99 insertions(+), 82 deletions(-) diff --git a/src/lib/keyhouse.rs b/src/lib/keyhouse.rs index 4a2a60b..38c85fc 100644 --- a/src/lib/keyhouse.rs +++ b/src/lib/keyhouse.rs @@ -2,11 +2,12 @@ extern crate base64; extern crate crypto; extern crate serde_json; +use std::collections::HashMap; use std::time::Duration; use crypto::digest::Digest; use crypto::sha2::Sha256; -use log::info; +use log::{debug, info}; use reqwest::Client; use serde::Deserialize; use serde_json::Value; @@ -138,92 +139,108 @@ pub fn get_name(config: &Config, ssh_key: &str) -> Result { } } -pub fn fetch_github_projects(config: &Config, user: &str) -> Result> { +pub fn fetch_github_projects(config: &Config, key_hash: &str) -> Result> { + debug!(target: "update", "Fetching projects for key hash: {}", key_hash); let client = reqwest::Client::builder() .timeout(Duration::from_secs(10)) .build()?; - let res = client - .get(&format!( - "{}/data/hosts/{}?ref=master", - config.keyhouse.base_url, user - )) - .header( - "Authorization", - &format!("Bearer {}", config.keyhouse.token), - ) - .send(); - match res { - Ok(mut r) => { - if r.status().is_success() { - let json_text = r.text()?; - let json: serde_json::Value = serde_json::from_str(&json_text) - .map_err(|e| { - info!(target: "update", "Failed to parse JSON from GitHub: {}", e); - e - }) - .chain_err(|| "Invalid JSON received from GitHub.")?; - let encoded_content = json["content"] - .as_str() - .ok_or_else(|| Error::from("Missing 'content' field in JSON."))?; - let cleaned_encoded = encoded_content.replace('\n', "").replace('\r', ""); - let content = - base64::decode(&cleaned_encoded).chain_err(|| "Base64 decoding failed.")?; - let decoded_str = - String::from_utf8(content).chain_err(|| "UTF-8 decoding failed.")?; - info!(target: "update", "Decoded string: {}", decoded_str); - let projects = decoded_str - .lines() - .filter_map(|line| line.split('|').nth(1)) - .map(String::from) - .collect::>(); - Ok(projects) - } else { - info!(target: "update", "GitHub API request failed with status: {}", r.status()); - Err(Error::from(format!( - "GitHub API request failed with status: {}", - r.status() - ))) + let host_url = format!( + "{}/access/{}?ref=build", + config.keyhouse.base_url, config.hostname + ); + + let name_files: Vec = match client + .get(&host_url) + .header("Authorization", format!("Bearer {}", config.keyhouse.token)) + .header("Accept", "application/vnd.github.v3+json") + .send() + { + Ok(mut r) if r.status().is_success() => { + let text = r.text()?; + info!(target: "update", "Response: {:?}", text); + serde_json::from_str(&text).unwrap_or_default() + } + Ok(r) => { + info!(target: "update", "Failed to fetch names: {}", r.status()); + vec![] + } + Err(e) => { + info!(target: "update", "Error fetching names: {:?}", e); + vec![] + } + }; + debug!(target: "update", "Fetched names: {:?}", name_files); + let projects: Vec = name_files.into_iter().map(|f| f.name).collect(); + debug!(target: "update", "Found projects: {:?} for host {}", projects, config.hostname); + let mut user_projects: Vec = Vec::new(); + for project in &projects { + let project_url = format!( + "{}/access/{}/{}/{}?ref=build", + config.keyhouse.base_url, config.hostname, project, key_hash + ); + + match client + .get(&project_url) + .header("Authorization", format!("Bearer {}", config.keyhouse.token)) + .send() + { + Ok(mut resp) if resp.status().is_success() => { + let text = resp.text()?; + info!(target: "auth", "Response: {:?}", text); + user_projects.push(project.to_string()); } + Ok(_) | Err(_) => continue, } - Err(e) => Err(Error::from(format!("Unknown reqwest error \n-> {}", e))), } + Ok(user_projects) } pub fn fetch_file_names( base_url: &str, directory: &str, token: &str, - file_names: &mut Vec, + user_to_key: &mut HashMap, ) -> Result<()> { - let client = Client::builder() - .timeout(std::time::Duration::from_secs(10)) - .build()?; - info!(target: "update", - "Fetching file names from {}/{}?ref=master", - base_url, directory - ); + let client = Client::builder().timeout(Duration::from_secs(10)).build()?; + + let list_url = format!("{}/{}?ref=build", base_url, directory); let mut response = client - .get(&format!("{}/{}?ref=master", base_url, directory)) - .header("Authorization", &format!("Bearer {}", token)) + .get(&list_url) + .header("Authorization", format!("Bearer {}", token)) .send()?; - if response.status().is_success() { - let contents: Value = response.json()?; - if let Some(files) = contents.as_array() { - for file in files { - if let Some(file_name) = file["name"].as_str() { - file_names.push(file_name.to_string()); + let files: Value = response.json()?; + + if let Some(entries) = files.as_array() { + for entry in entries { + if let Some(key_hash) = entry["name"].as_str() { + let file_url = format!("{}/{}/{}?ref=build", base_url, directory, key_hash); + + let mut file_response = client + .get(&file_url) + .header("Authorization", format!("Bearer {}", token)) + .send()?; + + if file_response.status().is_success() { + let file_json: Value = file_response.json()?; + + if let (Some(encoded), Some(encoding)) = ( + file_json.get("content").and_then(|v| v.as_str()), + file_json.get("encoding").and_then(|v| v.as_str()), + ) { + if encoding == "base64" { + let cleaned = encoded.replace('\n', "").replace('\r', ""); + let decoded_bytes = base64::decode(&cleaned)?; + let username = String::from_utf8(decoded_bytes)?.trim().to_string(); + + user_to_key.insert(username, key_hash.to_string()); + } + } } } } - } else { - return Err(format!( - "GitHub API request failed with status: {}", - response.status() - ) - .into()); } + info!(target: "update", "Fetched user to key mapping: {:?}", user_to_key); - info!(target: "update", "Fetched file names: {:?}", file_names); Ok(()) } diff --git a/src/lib/utils.rs b/src/lib/utils.rs index 0b3f1b0..cedba19 100644 --- a/src/lib/utils.rs +++ b/src/lib/utils.rs @@ -31,12 +31,12 @@ pub fn create_linux_user(username: &str) -> Result<()> { Command::new("useradd") .arg("-m") .arg("-d") - .arg("/home") + .arg("/home") .args(&["-s", "/bin/bash"]) .arg(username) .status() .chain_err(|| format!("Failed to add user {}", username))?; - info!(target: "update", "User {} added", username); + info!(target: "update", "User {} added", username); Ok(()) } diff --git a/src/update.rs b/src/update.rs index 9c88b64..b8a5fe4 100644 --- a/src/update.rs +++ b/src/update.rs @@ -1,4 +1,4 @@ -use std::process::Command; +use std::collections::HashMap; use lib::config::read_config; use lib::errors::*; @@ -7,22 +7,23 @@ use lib::keyhouse::fetch_file_names; use lib::keyhouse::fetch_github_projects; use lib::utils::add_user_to_groups; use lib::utils::create_linux_user; +use log::debug; use log::{error, info}; pub fn handle_update() -> Result<()> { - let mut users: Vec = Vec::new(); + let mut user_to_key: HashMap = HashMap::new(); log::info!(target: "update", "Watchdog update triggered."); let config = read_config()?; init(&config)?; let _ = fetch_file_names( &config.keyhouse.base_url, - "data/hosts", + "names", &config.keyhouse.token, - &mut users, + &mut user_to_key, )?; - info!(target: "update", "Fetched users: {:?}", users); - println!("Fetched users: {:?}", users); - for user in users.iter() { + info!(target: "update", "Fetched users: {:?}", user_to_key); + debug!("Fetched users: {:?}", user_to_key); + for (user, key_hash) in user_to_key.iter() { match create_linux_user(user) { Ok(_) => { info!(target: "update", "User {} created successfully.", user); @@ -31,13 +32,12 @@ pub fn handle_update() -> Result<()> { error!(target: "update", "Failed to create user {}: {}", user, e); } } - match fetch_github_projects(&config, user) { - Ok(mut projects) => { - info!(target: "update", "Fetched projects for {}: {:?}",user, projects); - projects.retain(|p| p != &config.hostname); - info!(target: "update","Filtered projects (excluding self): {:?}", projects); + debug!("User: {}, Key Hash: {}", user, key_hash); + match fetch_github_projects(&config, key_hash) { + Ok(projects) => { + info!(target: "update", "Fetched projects for {}: {:?}", user, projects); if let Err(e) = add_user_to_groups(user, &projects) { - info!(target: "update","Failed to add user {} to project groups: {}", user, e); + info!(target: "update", "Failed to add user {} to project groups: {}", user, e); } } Err(e) => { From c8b4a1148d9f696bc88fd770f0d0d54b6def3e34 Mon Sep 17 00:00:00 2001 From: Arshdeep54 Date: Tue, 22 Apr 2025 00:07:04 +0530 Subject: [PATCH 18/30] Add constant.rs and enums Signed-off-by: Arshdeep54 --- src/auth.rs | 11 ++++---- src/lib/config.rs | 10 +++---- src/lib/constants.rs | 2 ++ src/lib/keyhouse.rs | 41 ++++++++++++++-------------- src/lib/lib.rs | 2 ++ src/lib/logger.rs | 31 +++++++++++++++++++--- src/lib/notifier.rs | 13 ++++----- src/lib/utils.rs | 63 +++++++++++++++++++++++++++++++++----------- src/main.rs | 12 ++++----- src/ssh.rs | 8 +++--- src/su.rs | 7 ++--- src/sudo.rs | 12 ++++----- src/update.rs | 15 ++++++----- 13 files changed, 147 insertions(+), 80 deletions(-) create mode 100644 src/lib/constants.rs diff --git a/src/auth.rs b/src/auth.rs index 6cc4edf..6066f6d 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -1,3 +1,4 @@ +use lib::logger::LogTarget; use log::{error, info}; use nix::unistd::{fork, ForkResult}; @@ -10,18 +11,18 @@ use lib::notifier; pub fn handle_auth(ssh_host_username: &str, ssh_key: &str) -> Result<()> { let config = read_config()?; init(&config)?; - info!(target: "auth", "ssh_key in handle_auth: {}", ssh_key); + info!(target: LogTarget::AUTH.as_str(), "ssh_key in handle_auth: {}", ssh_key); match validate_user(&config, ssh_host_username.to_string(), ssh_key) { Ok(true) => { - info!(target: "auth", "User validated by handle auth"); + info!(target: LogTarget::AUTH.as_str(), "User validated by handle auth"); println!("{}", ssh_key); Ok(()) } Ok(false) => { - info!(target: "auth", "User not validated"); + info!(target: LogTarget::AUTH.as_str(), "User not validated"); let name = get_name(&config, ssh_key)?; - info!(target: "auth", "Logging failed"); + info!(target: LogTarget::AUTH.as_str(), "Logging failed"); match fork() { Ok(ForkResult::Parent { .. }) => {} Ok(ForkResult::Child) => { @@ -38,7 +39,7 @@ pub fn handle_auth(ssh_host_username: &str, ssh_key: &str) -> Result<()> { Ok(()) } Err(e) => { - error!(target: "auth", "Error while validating user from keyhouse"); + error!(target: LogTarget::AUTH.as_str(), "Error while validating user from keyhouse"); Err(e).chain_err(|| "Error while validating user from keyhouse") } } diff --git a/src/lib/config.rs b/src/lib/config.rs index 90ed595..cb13edc 100644 --- a/src/lib/config.rs +++ b/src/lib/config.rs @@ -3,7 +3,7 @@ use std::fs; use serde_derive::Deserialize; use toml_edit::{value, Document}; -use crate::errors::*; +use crate::{constants::CONFIG_PATH, errors::*}; #[derive(Deserialize, Clone)] pub struct KeyhouseConf { @@ -32,13 +32,13 @@ pub struct Config { } pub fn read_config() -> Result { - let toml_str = fs::read_to_string("/opt/watchdog/config.toml")?; + let toml_str = fs::read_to_string(CONFIG_PATH)?; let config: Config = toml::from_str(&toml_str)?; Ok(config) } pub fn set_config_value(key: &str, val: &str) -> Result<()> { - let toml_str = fs::read_to_string("/opt/watchdog/config.toml")?; + let toml_str = fs::read_to_string(CONFIG_PATH)?; let mut doc = toml_str.parse::().chain_err(|| { "Invalid TOML file. Please reverify if /opt/watchdog/config.toml is a valid toml file." })?; @@ -68,12 +68,12 @@ pub fn set_config_value(key: &str, val: &str) -> Result<()> { return Err("Invalid Key passed".into()); } } - fs::write("/opt/watchdog/config.toml", doc.to_string())?; + fs::write(CONFIG_PATH, doc.to_string())?; Ok(()) } pub fn get_config_value(key: &str) -> Result { - let toml_str = fs::read_to_string("/opt/watchdog/config.toml")?; + let toml_str = fs::read_to_string(CONFIG_PATH)?; let doc = toml_str.parse::().chain_err(|| { "Invalid TOML file. Please reverify if /opt/watchdog/config.toml is a valid toml file." })?; diff --git a/src/lib/constants.rs b/src/lib/constants.rs new file mode 100644 index 0000000..ab5eb46 --- /dev/null +++ b/src/lib/constants.rs @@ -0,0 +1,2 @@ +pub const CONFIG_PATH: &str = "/opt/watchdog/config.toml"; +pub const LOG_PATH: &str = "/opt/watchdog/custom-logs"; diff --git a/src/lib/keyhouse.rs b/src/lib/keyhouse.rs index 38c85fc..3debb17 100644 --- a/src/lib/keyhouse.rs +++ b/src/lib/keyhouse.rs @@ -14,6 +14,7 @@ use serde_json::Value; use crate::config::Config; use crate::errors::*; +use crate::logger::LogTarget; #[derive(Debug, Deserialize)] struct NameFile { @@ -22,28 +23,28 @@ struct NameFile { pub fn validate_user(config: &Config, user: String, ssh_key: &str) -> Result { let name = get_name(&config, ssh_key)?; - info!(target: "auth", "User name: {} ,user {}", name, user); + info!(target: LogTarget::AUTH.as_str(), "User name: {} ,user {}", name, user); if name.trim() != user.trim() { - info!(target: "auth", "User didn't match with name"); + info!(target: LogTarget::AUTH.as_str(), "User didn't match with name"); return Ok(false); } - info!(target: "auth", "User match with name"); + info!(target: LogTarget::AUTH.as_str(), "User match with name"); let mut hasher = Sha256::new(); hasher.input_str(&ssh_key); let hex = hasher.result_str(); let host = &config.hostname; - info!(target: "auth", "Found user hash {}", hex); + info!(target: LogTarget::AUTH.as_str(), "Found user hash {}", hex); let client = reqwest::Client::builder() .timeout(Duration::from_secs(10)) .build()?; - info!(target: "auth", "user {},host {}", user, host); + info!(target: LogTarget::AUTH.as_str(), "user {},host {}", user, host); let host_url = format!("{}/access/{}?ref=build", config.keyhouse.base_url, host); - info!(target: "auth", "Host URL: {}", host_url); + info!(target: LogTarget::AUTH.as_str(), "Host URL: {}", host_url); let name_files: Vec = match client .get(&host_url) .header("Authorization", format!("Bearer {}", config.keyhouse.token)) @@ -52,21 +53,21 @@ pub fn validate_user(config: &Config, user: String, ssh_key: &str) -> Result { let text = r.text()?; - info!(target: "auth", "Response: {:?}", text); + info!(target: LogTarget::AUTH.as_str(), "Response: {:?}", text); serde_json::from_str(&text).unwrap_or_default() } Ok(r) => { - info!(target: "auth", "Failed to fetch names: {}", r.status()); + info!(target: LogTarget::AUTH.as_str(), "Failed to fetch names: {}", r.status()); vec![] } Err(e) => { - info!(target: "auth", "Error fetching names: {:?}", e); + info!(target: LogTarget::AUTH.as_str(), "Error fetching names: {:?}", e); vec![] } }; let projects: Vec = name_files.into_iter().map(|f| f.name).collect(); - info!(target: "auth", "Found projects: {:?} for host {}", projects, host); + info!(target: LogTarget::AUTH.as_str(), "Found projects: {:?} for host {}", projects, host); for project in &projects { let project_url = format!( "{}/access/{}/{}/{}?ref=build", @@ -80,8 +81,8 @@ pub fn validate_user(config: &Config, user: String, ssh_key: &str) -> Result { let text = resp.text()?; - info!(target: "auth", "Response: {:?}", text); - info!(target: "auth", "User validated"); + info!(target: LogTarget::AUTH.as_str(), "Response: {:?}", text); + info!(target: LogTarget::AUTH.as_str(), "User validated"); return Ok(true); } Ok(_) | Err(_) => continue, @@ -140,7 +141,7 @@ pub fn get_name(config: &Config, ssh_key: &str) -> Result { } pub fn fetch_github_projects(config: &Config, key_hash: &str) -> Result> { - debug!(target: "update", "Fetching projects for key hash: {}", key_hash); + debug!(target: LogTarget::UPDATE.as_str(), "Fetching projects for key hash: {}", key_hash); let client = reqwest::Client::builder() .timeout(Duration::from_secs(10)) .build()?; @@ -157,21 +158,21 @@ pub fn fetch_github_projects(config: &Config, key_hash: &str) -> Result { let text = r.text()?; - info!(target: "update", "Response: {:?}", text); + info!(target: LogTarget::UPDATE.as_str(), "Response: {:?}", text); serde_json::from_str(&text).unwrap_or_default() } Ok(r) => { - info!(target: "update", "Failed to fetch names: {}", r.status()); + info!(target: LogTarget::UPDATE.as_str(), "Failed to fetch names: {}", r.status()); vec![] } Err(e) => { - info!(target: "update", "Error fetching names: {:?}", e); + info!(target: LogTarget::UPDATE.as_str(), "Error fetching names: {:?}", e); vec![] } }; - debug!(target: "update", "Fetched names: {:?}", name_files); + debug!(target: LogTarget::UPDATE.as_str(), "Fetched names: {:?}", name_files); let projects: Vec = name_files.into_iter().map(|f| f.name).collect(); - debug!(target: "update", "Found projects: {:?} for host {}", projects, config.hostname); + debug!(target: LogTarget::UPDATE.as_str(), "Found projects: {:?} for host {}", projects, config.hostname); let mut user_projects: Vec = Vec::new(); for project in &projects { let project_url = format!( @@ -186,7 +187,7 @@ pub fn fetch_github_projects(config: &Config, key_hash: &str) -> Result { let text = resp.text()?; - info!(target: "auth", "Response: {:?}", text); + info!(target: LogTarget::AUTH.as_str(), "Response: {:?}", text); user_projects.push(project.to_string()); } Ok(_) | Err(_) => continue, @@ -240,7 +241,7 @@ pub fn fetch_file_names( } } } - info!(target: "update", "Fetched user to key mapping: {:?}", user_to_key); + info!(target: LogTarget::UPDATE.as_str(), "Fetched user to key mapping: {:?}", user_to_key); Ok(()) } diff --git a/src/lib/lib.rs b/src/lib/lib.rs index 8d415dd..9c94263 100644 --- a/src/lib/lib.rs +++ b/src/lib/lib.rs @@ -5,6 +5,8 @@ pub mod keyhouse; pub mod logger; pub mod notifier; pub mod utils; +pub mod constants; + #[macro_use] extern crate error_chain; diff --git a/src/lib/logger.rs b/src/lib/logger.rs index 8ac190d..a9add87 100644 --- a/src/lib/logger.rs +++ b/src/lib/logger.rs @@ -6,8 +6,33 @@ use std::path::Path; use std::{collections::HashMap, fs, io, sync::Mutex}; use crate::config::read_config; +use crate::constants::LOG_PATH; use crate::utils::parse_offset; +pub enum LogTarget { + UPDATE, + AUTH, + SUDO, + WATCHDOG, + SSH, + SU, + Other(String), +} + +impl LogTarget { + pub fn as_str(&self) -> &str { + match self { + LogTarget::UPDATE => "update", + LogTarget::AUTH => "auth", + LogTarget::SSH => "ssh", + LogTarget::SUDO => "sudo", + LogTarget::SU => "su", + LogTarget::WATCHDOG => "watchdog", + LogTarget::Other(s) => s.as_str(), + } + } +} + lazy_static::lazy_static! { static ref TARGET_LOGGERS: Mutex>> = Mutex::new(HashMap::new()); } @@ -31,7 +56,7 @@ pub fn init_logger() -> Result<(), InitError> { )) })?; - let base_dir = "/opt/watchdog/custom-logs"; + let base_dir = LOG_PATH; fs::create_dir_all(base_dir).map_err(|e| { InitError::from(io::Error::new( io::ErrorKind::Other, @@ -114,7 +139,7 @@ impl log::Log for PerTargetLogger { } pub fn handle_logs_for(component: &str, level: Option<&str>) { - let path = format!("/opt/watchdog/custom-logs/{}.logs", component); + let path = format!("{}/{}.logs",LOG_PATH, component); let path = Path::new(&path); if !path.exists() { @@ -147,7 +172,7 @@ pub fn handle_logs_for(component: &str, level: Option<&str>) { } pub fn handle_logs_all(level: Option<&str>) { - let log_dir = Path::new("/opt/watchdog/custom-logs"); + let log_dir = Path::new(LOG_PATH); let mut all_logs = Vec::new(); println!("Fetching logs from directory: {}", log_dir.display()); diff --git a/src/lib/notifier.rs b/src/lib/notifier.rs index e8263c1..3511aff 100644 --- a/src/lib/notifier.rs +++ b/src/lib/notifier.rs @@ -3,6 +3,7 @@ extern crate serde_json; use crate::config::Config; use crate::errors::*; +use crate::logger::LogTarget; use log::info; use reqwest::header::{AUTHORIZATION, CONTENT_TYPE}; use reqwest::Client; @@ -90,7 +91,7 @@ impl Slack { if let Some(ts) = thread_ts { payload["thread_ts"] = json!(ts); } - info!(target: "watchdog", "Slack payload: {:?}", payload); + info!(target: LogTarget::WATCHDOG.as_str(), "Slack payload: {:?}", payload); let mut res = self .client .post("https://slack.com/api/chat.postMessage") @@ -120,7 +121,7 @@ impl Slack { .query(&[("channel", &self.channel), ("limit", &"1".to_string())]) .send() .chain_err(|| "Failed to fetch message history")?; - info!(target: "watchdog", "Slack response: {:?}", res); + info!(target: LogTarget::WATCHDOG.as_str(), "Slack response: {:?}", res); let body: serde_json::Value = res.json().chain_err(|| "Invalid JSON from Slack")?; if !body["ok"].as_bool().unwrap_or(false) { return Err(format!( @@ -129,13 +130,13 @@ impl Slack { ) .into()); } - info!(target: "watchdog", "Slack body: {:?}", body); + info!(target: LogTarget::WATCHDOG.as_str(), "Slack body: {:?}", body); let ts = body["messages"] .as_array() .and_then(|arr| arr.first()) .and_then(|msg| msg["ts"].as_str()) .ok_or("No messages found in channel")?; - info!(target: "watchdog", "Slack timestamp: {:?}", ts); + info!(target: LogTarget::WATCHDOG.as_str(), "Slack timestamp: {:?}", ts); Ok(ts.to_string()) } } @@ -159,10 +160,10 @@ impl Notifier for Slack { fn post_sudo_summary(&self, conf: &Config, pam_ruser: String, pwd: String) -> Result<()> { let parent_text = format!("{} attempted sudo on {}", pam_ruser, conf.hostname); self.post_message(&parent_text, None)?; - info!(target: "watchdog", "Posted parent message: {:?}", parent_text); + info!(target: LogTarget::WATCHDOG.as_str(), "Posted parent message: {:?}", parent_text); let thread_ts = self.fetch_latest_ts()?; - info!(target: "watchdog", "Fetched thread timestamp: {:?}", thread_ts); + info!(target: LogTarget::WATCHDOG.as_str(), "Fetched thread timestamp: {:?}", thread_ts); let pwd_text = format!("Attempted in :{} ", pwd); self.post_message(&pwd_text, Some(&thread_ts))?; diff --git a/src/lib/utils.rs b/src/lib/utils.rs index cedba19..b365bc2 100644 --- a/src/lib/utils.rs +++ b/src/lib/utils.rs @@ -1,11 +1,7 @@ -use crate::errors::*; +use crate::{errors::*, logger::LogTarget}; use chrono::FixedOffset; -use log::info; +use log::{error, info}; use std::{fs, process::Command}; -pub const AUTH_LOG_PATH: &str = "/opt/watchdog/custom-logs/auth.logs"; -pub const SSH_LOG_PATH: &str = "/opt/watchdog/custom-logs/ssh.logs"; -pub const SUDO_LOG_PATH: &str = "/opt/watchdog/custom-logs/sudo.logs"; -pub const SU_LOG_PATH: &str = "/opt/watchdog/custom-logs/su.logs"; pub fn clear_file(path: &str) -> Result<()> { fs::write(path, "")?; @@ -15,29 +11,66 @@ pub fn clear_file(path: &str) -> Result<()> { pub fn add_user_to_groups(user: &str, groups: &[String]) -> Result<()> { for group in groups { if group != user { - Command::new("usermod") + let output = Command::new("usermod") .arg("-aG") .arg(group) .arg(user) .output() - .chain_err(|| format!("Failed to add user {} to group {}", user, group))?; - info!(target: "update", "User {} added to group {}", user, group); + .chain_err(|| { + format!( + "Failed to execute usermod for user {} and group {}", + user, group + ) + })?; + + if output.status.success() { + info!(target: LogTarget::UPDATE.as_str(), "User {} successfully added to group {}", user, group); + } else { + let stderr = String::from_utf8_lossy(&output.stderr); + error!(target: LogTarget::UPDATE.as_str(), "usermod failed for user {} and group {}: {}", user, group, stderr.trim()); + return Err(Error::from(format!( + "usermod failed for user {} and group {}: {}", + user, + group, + stderr.trim() + ))); + } } } Ok(()) } pub fn create_linux_user(username: &str) -> Result<()> { - Command::new("useradd") + let check = Command::new("id").arg(username).status(); + + if let Ok(status) = check { + if status.success() { + info!(target: LogTarget::UPDATE.as_str(), "User {} already exists, skipping creation.", username); + return Ok(()); + } + } + + let status = Command::new("useradd") .arg("-m") .arg("-d") - .arg("/home") - .args(&["-s", "/bin/bash"]) + .arg(format!("/home/{}", username)) + .arg("-s") + .arg("/bin/bash") .arg(username) .status() - .chain_err(|| format!("Failed to add user {}", username))?; - info!(target: "update", "User {} added", username); - Ok(()) + .chain_err(|| format!("Failed to run useradd command for {}", username))?; + + if status.success() { + info!(target: LogTarget::UPDATE.as_str(), "User {} added successfully.", username); + Ok(()) + } else { + let code = status.code().unwrap_or(-1); + error!(target: LogTarget::UPDATE.as_str(), "useradd failed for user {} with exit code {}", username, code); + Err(Error::from(format!( + "useradd failed for user {} with exit code {}", + username, code + ))) + } } pub fn parse_offset(offset_str: &str) -> Result { diff --git a/src/main.rs b/src/main.rs index e376385..e0863ae 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,7 +10,7 @@ use clap::{App, AppSettings, Arg, SubCommand}; use auth::handle_auth; use lib::errors::Error; -use lib::logger::{handle_logs_all, handle_logs_for, init_logger}; +use lib::logger::{handle_logs_all, handle_logs_for, init_logger, LogTarget}; use log::{error, info}; use ssh::handle_ssh; use su::handle_su; @@ -145,19 +145,19 @@ fn main() { handle_logs_all(sub_m.value_of("level").or(level)); } ("update", Some(sub_m)) => { - handle_logs_for("update", sub_m.value_of("level").or(level)); + handle_logs_for(LogTarget::UPDATE.as_str(), sub_m.value_of("level").or(level)); } ("sudo", Some(sub_m)) => { - handle_logs_for("sudo", sub_m.value_of("level").or(level)); + handle_logs_for(LogTarget::SUDO.as_str(), sub_m.value_of("level").or(level)); } ("su", Some(sub_m)) => { - handle_logs_for("su", sub_m.value_of("level").or(level)); + handle_logs_for(LogTarget::SU.as_str(), sub_m.value_of("level").or(level)); } ("ssh", Some(sub_m)) => { - handle_logs_for("ssh", sub_m.value_of("level").or(level)); + handle_logs_for(LogTarget::SSH.as_str(), sub_m.value_of("level").or(level)); } ("watchdog", Some(sub_m)) => { - handle_logs_for("watchdog", sub_m.value_of("level").or(level)); + handle_logs_for(LogTarget::WATCHDOG.as_str(), sub_m.value_of("level").or(level)); } _ => { handle_logs_for("watchdog", level); diff --git a/src/ssh.rs b/src/ssh.rs index 505d79a..6306c61 100644 --- a/src/ssh.rs +++ b/src/ssh.rs @@ -1,6 +1,6 @@ use std::env; -use lib::config::read_config; +use lib::{config::read_config, logger::LogTarget}; use lib::errors::*; use lib::init::init; use lib::notifier; @@ -8,16 +8,16 @@ use log::{error, info}; use nix::unistd::{fork, ForkResult}; pub fn handle_ssh() -> Result<()> { - info!(target: "ssh", "in handle_ssh SSH Command"); + info!(target: LogTarget::SSH.as_str(), "in handle_ssh SSH Command"); let pam_type = env::var("PAM_TYPE") .chain_err(|| "PAM_TYPE not set. If you are running this by `watchdog ssh`, please don't. It's an internal command, intended to be used by PAM.")?; - info!(target: "ssh", "PAM_TYPE: {}", pam_type); + info!(target: LogTarget::SSH.as_str(), "PAM_TYPE: {}", pam_type); let pam_user= env::var("PAM_USER") .chain_err(|| "PAM_USER not set. If you are running this by `watchdog ssh`, please don't. It's an internal command, intended to be used by PAM.")?; if pam_type == "open_session" { let config = read_config()?; init(&config)?; - info!(target: "ssh", "Logging successful"); + info!(target: LogTarget::SSH.as_str(), "Logging successful"); match fork() { Ok(ForkResult::Parent { .. }) => {} Ok(ForkResult::Child) => { diff --git a/src/su.rs b/src/su.rs index 6102d39..d19e2d2 100644 --- a/src/su.rs +++ b/src/su.rs @@ -1,5 +1,6 @@ use std::env; +use lib::logger::LogTarget; use log::{error, info}; use nix::unistd::{fork, ForkResult}; @@ -17,9 +18,9 @@ pub fn handle_su() -> Result<()> { let pam_user = env::var("PAM_USER") .chain_err(|| "PAM_USER not set. If you are running this by `watchdog su`, please don't. It's an internal command, intended to be used by PAM.")?; - info!(target: "su", "PAM_RUSER: {}", pam_ruser); - info!(target: "su", "PAM_USER: {}", pam_user); - info!(target: "su", "PAM_TYPE: {}", pam_type); + info!(target: LogTarget::SU.as_str(), "PAM_RUSER: {}", pam_ruser); + info!(target: LogTarget::SU.as_str(), "PAM_USER: {}", pam_user); + info!(target: LogTarget::SU.as_str(), "PAM_TYPE: {}", pam_type); if pam_type == "open_session" { let config = read_config()?; init(&config)?; diff --git a/src/sudo.rs b/src/sudo.rs index 1058b52..2e76df9 100644 --- a/src/sudo.rs +++ b/src/sudo.rs @@ -1,6 +1,6 @@ use std::env; -use lib::config::read_config; +use lib::{config::read_config, logger::LogTarget}; use lib::errors::*; use lib::init::init; use lib::notifier; @@ -8,18 +8,18 @@ use log::{error, info}; use nix::unistd::{fork, ForkResult}; pub fn handle_sudo() -> Result<()> { - info!(target: "sudo", "Handling sudo command"); + info!(target: LogTarget::SUDO.as_str(), "Handling sudo command"); let pam_type = env::var("PAM_TYPE") .chain_err(|| "PAM_TYPE not set. If you are running this by `watchdog sudo`, please don't. It's an internal command, intended to be used by PAM.")?; let pam_ruser = env::var("PAM_RUSER") .chain_err(|| "PAM_RUSER not set. If you are running this by `watchdog sudo`, please don't. It's an internal command, intended to be used by PAM.")?; - info!(target: "sudo", "PAM_RUSER: {}", pam_ruser); - info!(target: "sudo", "PAM_TYPE: {}", pam_type); + info!(target: LogTarget::SUDO.as_str(), "PAM_RUSER: {}", pam_ruser); + info!(target: LogTarget::SUDO.as_str(), "PAM_TYPE: {}", pam_type); if pam_type == "open_session" { let config = read_config()?; init(&config)?; - info!(target: "sudo", "Logging successful"); + info!(target: LogTarget::SUDO.as_str(), "Logging successful"); match fork() { Ok(ForkResult::Parent { .. }) => {} Ok(ForkResult::Child) => { @@ -28,7 +28,7 @@ pub fn handle_sudo() -> Result<()> { .map(|p| p.display().to_string()) .unwrap_or_else(|_| "".to_string()) }); - info!(target: "sudo", "PWD: {}", pwd); + info!(target: LogTarget::SUDO.as_str(), "PWD: {}", pwd); notifier::post_sudo_summary(&config, pam_ruser, pwd)?; } Err(_) => error!("Fork failed"), diff --git a/src/update.rs b/src/update.rs index b8a5fe4..132480a 100644 --- a/src/update.rs +++ b/src/update.rs @@ -5,6 +5,7 @@ use lib::errors::*; use lib::init::init; use lib::keyhouse::fetch_file_names; use lib::keyhouse::fetch_github_projects; +use lib::logger::LogTarget; use lib::utils::add_user_to_groups; use lib::utils::create_linux_user; use log::debug; @@ -12,7 +13,7 @@ use log::{error, info}; pub fn handle_update() -> Result<()> { let mut user_to_key: HashMap = HashMap::new(); - log::info!(target: "update", "Watchdog update triggered."); + log::info!(target: LogTarget::UPDATE.as_str(), "Watchdog update triggered."); let config = read_config()?; init(&config)?; let _ = fetch_file_names( @@ -21,27 +22,27 @@ pub fn handle_update() -> Result<()> { &config.keyhouse.token, &mut user_to_key, )?; - info!(target: "update", "Fetched users: {:?}", user_to_key); + info!(target: LogTarget::UPDATE.as_str(), "Fetched users: {:?}", user_to_key); debug!("Fetched users: {:?}", user_to_key); for (user, key_hash) in user_to_key.iter() { match create_linux_user(user) { Ok(_) => { - info!(target: "update", "User {} created successfully.", user); + info!(target: LogTarget::UPDATE.as_str(), "User {} created successfully.", user); } Err(e) => { - error!(target: "update", "Failed to create user {}: {}", user, e); + error!(target: LogTarget::UPDATE.as_str(), "Failed to create user {}: {}", user, e); } } debug!("User: {}, Key Hash: {}", user, key_hash); match fetch_github_projects(&config, key_hash) { Ok(projects) => { - info!(target: "update", "Fetched projects for {}: {:?}", user, projects); + info!(target: LogTarget::UPDATE.as_str(), "Fetched projects for {}: {:?}", user, projects); if let Err(e) = add_user_to_groups(user, &projects) { - info!(target: "update", "Failed to add user {} to project groups: {}", user, e); + info!(target: LogTarget::UPDATE.as_str(), "Failed to add user {} to project groups: {}", user, e); } } Err(e) => { - error!(target: "update", "Failed to fetch projects for user {}: {}", user, e); + error!(target: LogTarget::UPDATE.as_str(), "Failed to fetch projects for user {}: {}", user, e); } } } From 94f9e0a7b30e77f28c09273bc7166e8cbcb725e6 Mon Sep 17 00:00:00 2001 From: Arshdeep54 Date: Tue, 22 Apr 2025 01:16:33 +0530 Subject: [PATCH 19/30] Update user's bashrc with group's bashrc Signed-off-by: Arshdeep54 --- src/lib/constants.rs | 1 + src/lib/lib.rs | 2 +- src/lib/logger.rs | 2 +- src/lib/utils.rs | 31 ++++++++++++++++++++++++++++--- src/main.rs | 10 ++++++++-- src/ssh.rs | 2 +- src/sudo.rs | 2 +- src/update.rs | 9 +++++++++ 8 files changed, 50 insertions(+), 9 deletions(-) diff --git a/src/lib/constants.rs b/src/lib/constants.rs index ab5eb46..ff7bf3b 100644 --- a/src/lib/constants.rs +++ b/src/lib/constants.rs @@ -1,2 +1,3 @@ pub const CONFIG_PATH: &str = "/opt/watchdog/config.toml"; pub const LOG_PATH: &str = "/opt/watchdog/custom-logs"; +pub const HOME_DIR: &str = "/opt/watchdog/users"; diff --git a/src/lib/lib.rs b/src/lib/lib.rs index 9c94263..2625ae3 100644 --- a/src/lib/lib.rs +++ b/src/lib/lib.rs @@ -1,11 +1,11 @@ pub mod config; +pub mod constants; pub mod environment; pub mod init; pub mod keyhouse; pub mod logger; pub mod notifier; pub mod utils; -pub mod constants; #[macro_use] extern crate error_chain; diff --git a/src/lib/logger.rs b/src/lib/logger.rs index a9add87..57876bd 100644 --- a/src/lib/logger.rs +++ b/src/lib/logger.rs @@ -139,7 +139,7 @@ impl log::Log for PerTargetLogger { } pub fn handle_logs_for(component: &str, level: Option<&str>) { - let path = format!("{}/{}.logs",LOG_PATH, component); + let path = format!("{}/{}.logs", LOG_PATH, component); let path = Path::new(&path); if !path.exists() { diff --git a/src/lib/utils.rs b/src/lib/utils.rs index b365bc2..4835c0e 100644 --- a/src/lib/utils.rs +++ b/src/lib/utils.rs @@ -1,7 +1,11 @@ -use crate::{errors::*, logger::LogTarget}; +use crate::{constants::HOME_DIR, errors::*, logger::LogTarget}; use chrono::FixedOffset; use log::{error, info}; -use std::{fs, process::Command}; +use std::{ + fs::{self, OpenOptions}, + io::Write, + process::Command, +}; pub fn clear_file(path: &str) -> Result<()> { fs::write(path, "")?; @@ -53,7 +57,7 @@ pub fn create_linux_user(username: &str) -> Result<()> { let status = Command::new("useradd") .arg("-m") .arg("-d") - .arg(format!("/home/{}", username)) + .arg(format!("{}/{}", HOME_DIR, username)) .arg("-s") .arg("/bin/bash") .arg(username) @@ -73,6 +77,27 @@ pub fn create_linux_user(username: &str) -> Result<()> { } } +pub fn update_user_bashrc(user: &str) -> Result<()> { + let bashrc_path = format!("{}/{}/.bashrc", HOME_DIR, user); + let bashrc_lines = r#" +# Load group-specific config if present +for group in $(id -nG "$USER"); do + group_bashrc="/home/$group/.bashrc" + [ -f "$group_bashrc" ] && source "$group_bashrc" +done +"#; + + let mut file = OpenOptions::new() + .append(true) + .create(true) + .open(&bashrc_path)?; + + file.write_all(bashrc_lines.as_bytes())?; + info!("Appended group-config loader to '{}'.", bashrc_path); + + Ok(()) +} + pub fn parse_offset(offset_str: &str) -> Result { let sign = if offset_str.starts_with('+') { 1 } else { -1 }; let parts: Vec<&str> = offset_str diff --git a/src/main.rs b/src/main.rs index e0863ae..3b98029 100644 --- a/src/main.rs +++ b/src/main.rs @@ -145,7 +145,10 @@ fn main() { handle_logs_all(sub_m.value_of("level").or(level)); } ("update", Some(sub_m)) => { - handle_logs_for(LogTarget::UPDATE.as_str(), sub_m.value_of("level").or(level)); + handle_logs_for( + LogTarget::UPDATE.as_str(), + sub_m.value_of("level").or(level), + ); } ("sudo", Some(sub_m)) => { handle_logs_for(LogTarget::SUDO.as_str(), sub_m.value_of("level").or(level)); @@ -157,7 +160,10 @@ fn main() { handle_logs_for(LogTarget::SSH.as_str(), sub_m.value_of("level").or(level)); } ("watchdog", Some(sub_m)) => { - handle_logs_for(LogTarget::WATCHDOG.as_str(), sub_m.value_of("level").or(level)); + handle_logs_for( + LogTarget::WATCHDOG.as_str(), + sub_m.value_of("level").or(level), + ); } _ => { handle_logs_for("watchdog", level); diff --git a/src/ssh.rs b/src/ssh.rs index 6306c61..a00d7dc 100644 --- a/src/ssh.rs +++ b/src/ssh.rs @@ -1,9 +1,9 @@ use std::env; -use lib::{config::read_config, logger::LogTarget}; use lib::errors::*; use lib::init::init; use lib::notifier; +use lib::{config::read_config, logger::LogTarget}; use log::{error, info}; use nix::unistd::{fork, ForkResult}; diff --git a/src/sudo.rs b/src/sudo.rs index 2e76df9..4ed3ffa 100644 --- a/src/sudo.rs +++ b/src/sudo.rs @@ -1,9 +1,9 @@ use std::env; -use lib::{config::read_config, logger::LogTarget}; use lib::errors::*; use lib::init::init; use lib::notifier; +use lib::{config::read_config, logger::LogTarget}; use log::{error, info}; use nix::unistd::{fork, ForkResult}; diff --git a/src/update.rs b/src/update.rs index 132480a..66c0c75 100644 --- a/src/update.rs +++ b/src/update.rs @@ -8,6 +8,7 @@ use lib::keyhouse::fetch_github_projects; use lib::logger::LogTarget; use lib::utils::add_user_to_groups; use lib::utils::create_linux_user; +use lib::utils::update_user_bashrc; use log::debug; use log::{error, info}; @@ -33,6 +34,14 @@ pub fn handle_update() -> Result<()> { error!(target: LogTarget::UPDATE.as_str(), "Failed to create user {}: {}", user, e); } } + match update_user_bashrc(user) { + Ok(_) => { + info!(target: LogTarget::UPDATE.as_str(), "User {} bashrc updated successfully.", user); + } + Err(e) => { + error!(target: LogTarget::UPDATE.as_str(), "Failed to update user {} bashrc: {}", user, e); + } + } debug!("User: {}, Key Hash: {}", user, key_hash); match fetch_github_projects(&config, key_hash) { Ok(projects) => { From c116d0be631641224962b253ec7c7a2d84d05f94 Mon Sep 17 00:00:00 2001 From: Arshdeep54 Date: Fri, 25 Apr 2025 22:47:14 +0530 Subject: [PATCH 20/30] Update add to sudo and wheel group Signed-off-by: Arshdeep54 --- src/lib/utils.rs | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/lib/utils.rs b/src/lib/utils.rs index 4835c0e..9bf04bb 100644 --- a/src/lib/utils.rs +++ b/src/lib/utils.rs @@ -14,28 +14,35 @@ pub fn clear_file(path: &str) -> Result<()> { pub fn add_user_to_groups(user: &str, groups: &[String]) -> Result<()> { for group in groups { - if group != user { + let mut target_group = group.as_str(); + if group == "sudo" { + if !group_exists("sudo") && group_exists("wheel") { + target_group = "wheel"; + } + } + + if target_group != user { let output = Command::new("usermod") .arg("-aG") - .arg(group) + .arg(target_group) .arg(user) .output() .chain_err(|| { format!( "Failed to execute usermod for user {} and group {}", - user, group + user, target_group ) })?; if output.status.success() { - info!(target: LogTarget::UPDATE.as_str(), "User {} successfully added to group {}", user, group); + info!(target: LogTarget::UPDATE.as_str(), "User {} successfully added to group {}", user, target_group); } else { let stderr = String::from_utf8_lossy(&output.stderr); - error!(target: LogTarget::UPDATE.as_str(), "usermod failed for user {} and group {}: {}", user, group, stderr.trim()); + error!(target: LogTarget::UPDATE.as_str(), "usermod failed for user {} and group {}: {}", user, target_group, stderr.trim()); return Err(Error::from(format!( "usermod failed for user {} and group {}: {}", user, - group, + target_group, stderr.trim() ))); } @@ -44,6 +51,7 @@ pub fn add_user_to_groups(user: &str, groups: &[String]) -> Result<()> { Ok(()) } + pub fn create_linux_user(username: &str) -> Result<()> { let check = Command::new("id").arg(username).status(); @@ -85,6 +93,7 @@ for group in $(id -nG "$USER"); do group_bashrc="/home/$group/.bashrc" [ -f "$group_bashrc" ] && source "$group_bashrc" done +cd /home "#; let mut file = OpenOptions::new() @@ -118,6 +127,12 @@ pub fn parse_offset(offset_str: &str) -> Result { Ok(offset_value) } +fn group_exists(group: &str) -> bool { + fs::read_to_string("/etc/group") + .map(|content| content.lines().any(|line| line.starts_with(&format!("{}:", group)))) + .unwrap_or(false) +} + #[cfg(test)] mod tests { From ac21dabc5332fe2b63666806696a7be4805873c4 Mon Sep 17 00:00:00 2001 From: Arshdeep54 Date: Sat, 3 May 2025 19:21:43 +0530 Subject: [PATCH 21/30] Add auto-update feature in handle_auth Signed-off-by: Arshdeep54 --- Cargo.toml | 4 ++++ src/auth.rs | 17 +++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 2290a92..6250c94 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,3 +30,7 @@ path = "src/main.rs" [lib] name = "lib" path = "src/lib/lib.rs" + +[features] +default = [] +auto-update = [] \ No newline at end of file diff --git a/src/auth.rs b/src/auth.rs index 6066f6d..4789145 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -8,10 +8,27 @@ use lib::init::init; use lib::keyhouse::{get_name, validate_user}; use lib::notifier; +#[cfg(feature = "auto-update")] +use crate::update::handle_update; + pub fn handle_auth(ssh_host_username: &str, ssh_key: &str) -> Result<()> { let config = read_config()?; init(&config)?; info!(target: LogTarget::AUTH.as_str(), "ssh_key in handle_auth: {}", ssh_key); + + #[cfg(feature = "auto-update")] + { + match handle_update() { + Ok(_) => { + info!(target: LogTarget::UPDATE.as_str(), "Update handled successfully"); + } + Err(e) => { + error!(target: LogTarget::UPDATE.as_str(), "Error handling update: {}", e); + return Err(e); + } + } + } + match validate_user(&config, ssh_host_username.to_string(), ssh_key) { Ok(true) => { info!(target: LogTarget::AUTH.as_str(), "User validated by handle auth"); From 0f912241651089c91b1d3b28471164fc80dc30d1 Mon Sep 17 00:00:00 2001 From: Arshdeep54 Date: Sat, 3 May 2025 19:32:58 +0530 Subject: [PATCH 22/30] Fix multiple appends in .bashrc Signed-off-by: Arshdeep54 --- src/lib/utils.rs | 7 +++++++ src/update.rs | 33 ++++++++++++++++++++------------- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/lib/utils.rs b/src/lib/utils.rs index 9bf04bb..5699607 100644 --- a/src/lib/utils.rs +++ b/src/lib/utils.rs @@ -133,6 +133,13 @@ fn group_exists(group: &str) -> bool { .unwrap_or(false) } +pub fn user_exists(username: &str) -> bool { + match Command::new("id").arg(username).status() { + Ok(status) => status.success(), + Err(_) => false, + } +} + #[cfg(test)] mod tests { diff --git a/src/update.rs b/src/update.rs index 66c0c75..c9c2bbb 100644 --- a/src/update.rs +++ b/src/update.rs @@ -9,6 +9,7 @@ use lib::logger::LogTarget; use lib::utils::add_user_to_groups; use lib::utils::create_linux_user; use lib::utils::update_user_bashrc; +use lib::utils::user_exists; use log::debug; use log::{error, info}; @@ -26,21 +27,27 @@ pub fn handle_update() -> Result<()> { info!(target: LogTarget::UPDATE.as_str(), "Fetched users: {:?}", user_to_key); debug!("Fetched users: {:?}", user_to_key); for (user, key_hash) in user_to_key.iter() { - match create_linux_user(user) { - Ok(_) => { - info!(target: LogTarget::UPDATE.as_str(), "User {} created successfully.", user); - } - Err(e) => { - error!(target: LogTarget::UPDATE.as_str(), "Failed to create user {}: {}", user, e); - } - } - match update_user_bashrc(user) { - Ok(_) => { - info!(target: LogTarget::UPDATE.as_str(), "User {} bashrc updated successfully.", user); + if !user_exists(user) { + match create_linux_user(user) { + Ok(_) => { + info!(target: LogTarget::UPDATE.as_str(), "User {} created successfully.", user); + } + Err(e) => { + error!(target: LogTarget::UPDATE.as_str(), "Failed to create user {}: {}", user, e); + continue; + } } - Err(e) => { - error!(target: LogTarget::UPDATE.as_str(), "Failed to update user {} bashrc: {}", user, e); + + match update_user_bashrc(user) { + Ok(_) => { + info!(target: LogTarget::UPDATE.as_str(), "User {} bashrc updated successfully.", user); + } + Err(e) => { + error!(target: LogTarget::UPDATE.as_str(), "Failed to update user {} bashrc: {}", user, e); + } } + } else { + info!(target: LogTarget::UPDATE.as_str(), "User {} already exists. Skipping creation and bashrc update.", user); } debug!("User: {}, Key Hash: {}", user, key_hash); match fetch_github_projects(&config, key_hash) { From f7dd03c252f6b1f845a43e698f97b6b4f544c5aa Mon Sep 17 00:00:00 2001 From: Arshdeep54 Date: Sat, 3 May 2025 20:59:30 +0530 Subject: [PATCH 23/30] Log sudo command on slack Signed-off-by: Arshdeep54 --- src/lib/notifier.rs | 11 +++++++---- src/lib/utils.rs | 26 ++++++++++++++++++++++++++ src/sudo.rs | 8 +++++++- 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/src/lib/notifier.rs b/src/lib/notifier.rs index 3511aff..dc08e2c 100644 --- a/src/lib/notifier.rs +++ b/src/lib/notifier.rs @@ -19,7 +19,7 @@ pub trait Notifier { where Self: Sized; /// Post summary for sudo attempts - fn post_sudo_summary(&self, conf: &Config, pam_ruser: String, pwd: String) -> Result<()>; + fn post_sudo_summary(&self, conf: &Config, pam_ruser: String, pwd: String, cmd: String) -> Result<()>; /// Post summary for su attempts fn post_su_summary(&self, conf: &Config, from: String, to: String) -> Result<()>; /// Post summary for ssh attempts @@ -35,10 +35,10 @@ pub trait Notifier { struct GlobalNotifier(Vec>); /// Post summary for sudo attempts -pub fn post_sudo_summary(conf: &Config, pam_ruser: String, pwd: String) -> Result<()> { +pub fn post_sudo_summary(conf: &Config, pam_ruser: String, pwd: String,cmd: String) -> Result<()> { let global_notifier = setup(conf); for notif in &global_notifier.0 { - notif.post_sudo_summary(conf, pam_ruser.clone(), pwd.clone())? + notif.post_sudo_summary(conf, pam_ruser.clone(), pwd.clone(),cmd.clone())? } Ok(()) } @@ -157,7 +157,7 @@ impl Notifier for Slack { }) } - fn post_sudo_summary(&self, conf: &Config, pam_ruser: String, pwd: String) -> Result<()> { + fn post_sudo_summary(&self, conf: &Config, pam_ruser: String, pwd: String, cmd: String) -> Result<()> { let parent_text = format!("{} attempted sudo on {}", pam_ruser, conf.hostname); self.post_message(&parent_text, None)?; info!(target: LogTarget::WATCHDOG.as_str(), "Posted parent message: {:?}", parent_text); @@ -168,6 +168,9 @@ impl Notifier for Slack { let pwd_text = format!("Attempted in :{} ", pwd); self.post_message(&pwd_text, Some(&thread_ts))?; + let cmd_text = format!("Command :{} ", cmd); + self.post_message(&cmd_text, Some(&thread_ts))?; + Ok(()) } diff --git a/src/lib/utils.rs b/src/lib/utils.rs index 5699607..805d91d 100644 --- a/src/lib/utils.rs +++ b/src/lib/utils.rs @@ -140,6 +140,32 @@ pub fn user_exists(username: &str) -> bool { } } +pub fn extract_sudo_command() -> Result { + let pid = std::process::id(); + let status_path = format!("/proc/{}/status", pid); + + let parent_pid = fs::read_to_string(&status_path)? + .lines() + .find(|line| line.starts_with("PPid:")) + .and_then(|line| line.split_whitespace().nth(1)) + .ok_or("Could not find PPid in /proc/[pid]/status")? + .parse::() + .chain_err(|| "Failed to parse PPid")?; + + let cmdline_path = format!("/proc/{}/cmdline", parent_pid); + let cmdline = fs::read(&cmdline_path) + .map(|bytes| { + bytes + .split(|b| *b == 0) + .map(|part| String::from_utf8_lossy(part).to_string()) + .collect::>() + .join(" ") + }) + .unwrap_or_else(|_| "UNKNOWN".to_string()); + + Ok(cmdline) +} + #[cfg(test)] mod tests { diff --git a/src/sudo.rs b/src/sudo.rs index 4ed3ffa..a588f22 100644 --- a/src/sudo.rs +++ b/src/sudo.rs @@ -3,6 +3,7 @@ use std::env; use lib::errors::*; use lib::init::init; use lib::notifier; +use lib::utils::extract_sudo_command; use lib::{config::read_config, logger::LogTarget}; use log::{error, info}; use nix::unistd::{fork, ForkResult}; @@ -29,7 +30,12 @@ pub fn handle_sudo() -> Result<()> { .unwrap_or_else(|_| "".to_string()) }); info!(target: LogTarget::SUDO.as_str(), "PWD: {}", pwd); - notifier::post_sudo_summary(&config, pam_ruser, pwd)?; + let cmd = extract_sudo_command().unwrap_or_else(|_| { + error!("Failed to extract sudo command"); + "UNKNOWN".to_string() + }); + info!(target: LogTarget::SUDO.as_str(), "Command: {}", cmd); + notifier::post_sudo_summary(&config, pam_ruser, pwd,cmd)?; } Err(_) => error!("Fork failed"), } From 045c7bc394c5735061d633f6cdf17150273998b0 Mon Sep 17 00:00:00 2001 From: Arshdeep54 Date: Fri, 16 May 2025 18:40:35 +0530 Subject: [PATCH 24/30] Update based on last commit Signed-off-by: Arshdeep54 --- Cargo.lock | 39 ++++++++++ Cargo.toml | 1 + src/auth.rs | 2 +- src/lib/constants.rs | 1 + src/lib/keyhouse.rs | 165 ++++++++++++++++++++++++++++++++++++++++++- src/lib/notifier.rs | 20 ++++-- src/lib/utils.rs | 125 +++++++++++++++++++++++++++++++- src/sudo.rs | 2 +- src/update.rs | 87 +++++++++++++++++++++++ 9 files changed, 433 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 26b35c4..2c19967 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,15 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + [[package]] name = "android-tzdata" version = "0.1.1" @@ -1298,6 +1307,35 @@ version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[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.9.24" @@ -2004,6 +2042,7 @@ dependencies = [ "nix", "openssl", "openssl-sys", + "regex", "reqwest", "rust-crypto", "serde", diff --git a/Cargo.toml b/Cargo.toml index 6250c94..07357a2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ chrono = "0.4" log = "0.4" fern = "0.6" lazy_static = "1.5.0" +regex = "1.11.1" [[ bin ]] name = "watchdog" diff --git a/src/auth.rs b/src/auth.rs index 4789145..e3eeb8f 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -28,7 +28,7 @@ pub fn handle_auth(ssh_host_username: &str, ssh_key: &str) -> Result<()> { } } } - + match validate_user(&config, ssh_host_username.to_string(), ssh_key) { Ok(true) => { info!(target: LogTarget::AUTH.as_str(), "User validated by handle auth"); diff --git a/src/lib/constants.rs b/src/lib/constants.rs index ff7bf3b..63f12e5 100644 --- a/src/lib/constants.rs +++ b/src/lib/constants.rs @@ -1,3 +1,4 @@ +pub const BASE_COMMIT_PATH: &str = "/opt/watchdog/base_commmit.txt"; pub const CONFIG_PATH: &str = "/opt/watchdog/config.toml"; pub const LOG_PATH: &str = "/opt/watchdog/custom-logs"; pub const HOME_DIR: &str = "/opt/watchdog/users"; diff --git a/src/lib/keyhouse.rs b/src/lib/keyhouse.rs index 3debb17..d5ae97a 100644 --- a/src/lib/keyhouse.rs +++ b/src/lib/keyhouse.rs @@ -7,7 +7,8 @@ use std::time::Duration; use crypto::digest::Digest; use crypto::sha2::Sha256; -use log::{debug, info}; +use log::{debug, info, warn}; +use reqwest::header::ACCEPT; use reqwest::Client; use serde::Deserialize; use serde_json::Value; @@ -21,6 +22,11 @@ struct NameFile { name: String, } +#[derive(Debug, Deserialize)] +pub struct CommitInfo { + pub sha: String, +} + pub fn validate_user(config: &Config, user: String, ssh_key: &str) -> Result { let name = get_name(&config, ssh_key)?; info!(target: LogTarget::AUTH.as_str(), "User name: {} ,user {}", name, user); @@ -245,3 +251,160 @@ pub fn fetch_file_names( Ok(()) } + +pub fn fetch_recent_commit(config: &Config) -> Result { + let client = reqwest::Client::builder() + .timeout(Duration::from_secs(10)) + .build()?; + + let url = format!("{}/commits?sha=build&per_page=1", config.keyhouse.base_url); + info!(target: LogTarget::UPDATE.as_str(), "Fetching recent commit from URL: {}", url); + + let mut response = match client + .get(&url) + .header("Authorization", format!("Bearer {}", config.keyhouse.token)) + .header("Accept", "application/vnd.github.v3+json") + .send() + { + Ok(resp) => resp, + Err(e) => { + log::error!("Error sending request to GitHub: {}", e); + return Err(Error::from(format!( + "Failed to send request to GitHub: {}", + e + ))); + } + }; + + if !response.status().is_success() { + log::error!( + "GitHub API returned non-success status: {}", + response.status() + ); + return Err(Error::from(format!( + "GitHub API returned error status: {}", + response.status() + ))); + } + + let text = response + .text() + .chain_err(|| "Failed to read response body")?; + info!(target: LogTarget::UPDATE.as_str(), "GitHub commits response: {}", text); + + let commits: Vec = serde_json::from_str(&text) + .chain_err(|| "Failed to parse GitHub commits response into JSON")?; + + if let Some(commit) = commits.first() { + log::info!("Fetched latest commit SHA: {}", commit.sha); + Ok(commit.sha.clone()) + } else { + log::error!("No commits found in GitHub response"); + Err(Error::from("No commits found in the GitHub response")) + } +} + +pub fn fetch_diff(config: &Config, base: &str, merge: &str) -> Result { + let client = reqwest::Client::builder() + .timeout(Duration::from_secs(10)) + .build() + .chain_err(|| "Failed to build HTTP client")?; + + let url = format!("{}/compare/{}...{}", config.keyhouse.base_url, base, merge); + + info!("Fetching diff from GitHub: {}", url); + + let mut response = match client + .get(&url) + .header(ACCEPT, "application/vnd.github.v3.diff") + .bearer_auth(&config.keyhouse.token) + .send() + { + Ok(resp) => resp, + Err(e) => { + log::error!("Error sending request to GitHub: {}", e); + return Err(Error::from(format!( + "Failed to send request to GitHub: {}", + e + ))); + } + }; + + if !response.status().is_success() { + log::error!( + "GitHub API returned non-success status: {}", + response.status() + ); + return Err(Error::from(format!( + "GitHub API returned error status: {}", + response.status() + ))); + } + + let diff = response + .text() + .chain_err(|| "Failed to read GitHub diff response body")?; + + info!("Fetched diff between {} and {}", base, merge); + Ok(diff) +} + +pub fn fetch_and_decode_file( + config: &Config, + hash: &str, + status: &str, + base_commit: &str, +) -> Result> { + let commit_ref = if status == "deleted" || status == "deleteduser" { + base_commit + } else { + "build" + }; + + let url = format!( + "{}/contents/names/{}?ref={}", + config.keyhouse.base_url, hash, commit_ref + ); + + let client = reqwest::Client::builder() + .timeout(Duration::from_secs(10)) + .build() + .chain_err(|| "Failed to build HTTP client")?; + + let mut file_resp = client + .get(&url) + .bearer_auth(&config.keyhouse.token) + .header(ACCEPT, "application/vnd.github.v3+json") + .send() + .map_err(|e| { + log::error!("Failed to fetch file from GitHub for hash {}: {}", hash, e); + Error::from(format!("Failed to fetch file for hash {}: {}", hash, e)) + })?; + + if !file_resp.status().is_success() { + warn!( + "GitHub API returned error for file at hash {}: {}", + hash, + file_resp.status() + ); + return Ok(None); // Gracefully handle non-success HTTP codes + } + + let file_json = file_resp + .json::() + .chain_err(|| "Failed to parse file response as JSON")?; + + if let Some(base64_content) = file_json["content"].as_str() { + let clean_base64 = base64_content.replace('\n', ""); + let decoded = + base64::decode(&clean_base64).chain_err(|| "Failed to decode base64 content")?; + let decoded_str = + String::from_utf8(decoded).chain_err(|| "Decoded content is not valid UTF-8")?; + + info!("Decoded file for hash {}", hash); + Ok(Some(decoded_str)) + } else { + warn!("No 'content' field found for file hash {}", hash); + Ok(None) + } +} diff --git a/src/lib/notifier.rs b/src/lib/notifier.rs index dc08e2c..aa1021a 100644 --- a/src/lib/notifier.rs +++ b/src/lib/notifier.rs @@ -19,7 +19,13 @@ pub trait Notifier { where Self: Sized; /// Post summary for sudo attempts - fn post_sudo_summary(&self, conf: &Config, pam_ruser: String, pwd: String, cmd: String) -> Result<()>; + fn post_sudo_summary( + &self, + conf: &Config, + pam_ruser: String, + pwd: String, + cmd: String, + ) -> Result<()>; /// Post summary for su attempts fn post_su_summary(&self, conf: &Config, from: String, to: String) -> Result<()>; /// Post summary for ssh attempts @@ -35,10 +41,10 @@ pub trait Notifier { struct GlobalNotifier(Vec>); /// Post summary for sudo attempts -pub fn post_sudo_summary(conf: &Config, pam_ruser: String, pwd: String,cmd: String) -> Result<()> { +pub fn post_sudo_summary(conf: &Config, pam_ruser: String, pwd: String, cmd: String) -> Result<()> { let global_notifier = setup(conf); for notif in &global_notifier.0 { - notif.post_sudo_summary(conf, pam_ruser.clone(), pwd.clone(),cmd.clone())? + notif.post_sudo_summary(conf, pam_ruser.clone(), pwd.clone(), cmd.clone())? } Ok(()) } @@ -157,7 +163,13 @@ impl Notifier for Slack { }) } - fn post_sudo_summary(&self, conf: &Config, pam_ruser: String, pwd: String, cmd: String) -> Result<()> { + fn post_sudo_summary( + &self, + conf: &Config, + pam_ruser: String, + pwd: String, + cmd: String, + ) -> Result<()> { let parent_text = format!("{} attempted sudo on {}", pam_ruser, conf.hostname); self.post_message(&parent_text, None)?; info!(target: LogTarget::WATCHDOG.as_str(), "Posted parent message: {:?}", parent_text); diff --git a/src/lib/utils.rs b/src/lib/utils.rs index 805d91d..9aa244b 100644 --- a/src/lib/utils.rs +++ b/src/lib/utils.rs @@ -1,12 +1,13 @@ use crate::{constants::HOME_DIR, errors::*, logger::LogTarget}; use chrono::FixedOffset; use log::{error, info}; +use regex::Regex; use std::{ + collections::HashMap, fs::{self, OpenOptions}, io::Write, process::Command, }; - pub fn clear_file(path: &str) -> Result<()> { fs::write(path, "")?; Ok(()) @@ -51,6 +52,54 @@ pub fn add_user_to_groups(user: &str, groups: &[String]) -> Result<()> { Ok(()) } +pub fn remove_user_from_groups(user: &str, groups: &[String]) -> Result<()> { + for group in groups { + let mut target_group = group.as_str(); + if group == "sudo" { + if !group_exists("sudo") && group_exists("wheel") { + target_group = "wheel"; + } + } + + if target_group != user { + let output = Command::new("gpasswd") + .arg("-d") + .arg(user) + .arg(target_group) + .output() + .chain_err(|| { + format!( + "Failed to execute gpasswd for user {} and group {}", + user, target_group + ) + })?; + + if output.status.success() { + info!( + target: LogTarget::UPDATE.as_str(), + "User {} successfully removed from group {}", + user, target_group + ); + } else { + let stderr = String::from_utf8_lossy(&output.stderr); + error!( + target: LogTarget::UPDATE.as_str(), + "gpasswd failed for user {} and group {}: {}", + user, + target_group, + stderr.trim() + ); + return Err(Error::from(format!( + "gpasswd failed for user {} and group {}: {}", + user, + target_group, + stderr.trim() + ))); + } + } + } + Ok(()) +} pub fn create_linux_user(username: &str) -> Result<()> { let check = Command::new("id").arg(username).status(); @@ -85,6 +134,30 @@ pub fn create_linux_user(username: &str) -> Result<()> { } } +pub fn delete_user(user: &str) -> Result<()> { + let output = Command::new("sudo") + .arg("userdel") + .arg("-r") + .arg(user) + .output()?; + + if output.status.success() { + info!("User '{}' deleted successfully.", user); + Ok(()) + } else { + error!( + "Failed to delete user '{}': {}", + user, + String::from_utf8_lossy(&output.stderr) + ); + Err(Error::from(format!( + "Failed to delete user '{}': {}", + user, + String::from_utf8_lossy(&output.stderr) + ))) + } +} + pub fn update_user_bashrc(user: &str) -> Result<()> { let bashrc_path = format!("{}/{}/.bashrc", HOME_DIR, user); let bashrc_lines = r#" @@ -129,7 +202,11 @@ pub fn parse_offset(offset_str: &str) -> Result { fn group_exists(group: &str) -> bool { fs::read_to_string("/etc/group") - .map(|content| content.lines().any(|line| line.starts_with(&format!("{}:", group)))) + .map(|content| { + content + .lines() + .any(|line| line.starts_with(&format!("{}:", group))) + }) .unwrap_or(false) } @@ -166,6 +243,50 @@ pub fn extract_sudo_command() -> Result { Ok(cmdline) } +pub fn extract_diff_parts(diff_data: &str) -> Vec<(String, String, String, String)> { + let re_access = Regex::new(r"diff --git a/(access/([^/]+)/([^/]+)/([\w\d]+))").unwrap(); + let re_names = Regex::new(r"diff --git a/(names/([\w\d]+))").unwrap(); + let mut parts_with_status = HashMap::new(); + for line in diff_data.lines() { + if let Some(caps) = re_access.captures(line) { + let full_path = &caps[1]; + let project = &caps[2]; + let provider = &caps[3]; + let hash = &caps[4]; + let status = if diff_data.contains("new file mode") && line.contains(full_path) { + "added" + } else if diff_data.contains("deleted file mode") && line.contains(full_path) { + "deleted" + } else { + "modified" + }; + info!( + "Access file change detected: {}/{}/{}, status: {}", + project, provider, hash, status + ); + parts_with_status + .entry((project.to_string(), provider.to_string(), hash.to_string())) + .or_insert(status.to_string()); + } else if let Some(caps) = re_names.captures(line) { + let full_path = &caps[1]; + let hash = &caps[2]; + let status = if diff_data.contains("deleted file mode") && line.contains(full_path) { + "deleteduser" + } else { + "modifieduser" + }; + info!("Name file change detected: {}, status: {}", hash, status); + parts_with_status + .entry(("".to_string(), "names".to_string(), hash.to_string())) + .or_insert(status.to_string()); + } + } + parts_with_status + .into_iter() + .map(|((proj, prov, hash), status)| (proj, prov, hash, status)) + .collect() +} + #[cfg(test)] mod tests { diff --git a/src/sudo.rs b/src/sudo.rs index a588f22..b79f2ab 100644 --- a/src/sudo.rs +++ b/src/sudo.rs @@ -35,7 +35,7 @@ pub fn handle_sudo() -> Result<()> { "UNKNOWN".to_string() }); info!(target: LogTarget::SUDO.as_str(), "Command: {}", cmd); - notifier::post_sudo_summary(&config, pam_ruser, pwd,cmd)?; + notifier::post_sudo_summary(&config, pam_ruser, pwd, cmd)?; } Err(_) => error!("Fork failed"), } diff --git a/src/update.rs b/src/update.rs index c9c2bbb..9301ac8 100644 --- a/src/update.rs +++ b/src/update.rs @@ -1,13 +1,22 @@ use std::collections::HashMap; +use std::fs; use lib::config::read_config; +use lib::config::Config; +use lib::constants::BASE_COMMIT_PATH; use lib::errors::*; use lib::init::init; +use lib::keyhouse::fetch_and_decode_file; +use lib::keyhouse::fetch_diff; use lib::keyhouse::fetch_file_names; use lib::keyhouse::fetch_github_projects; +use lib::keyhouse::fetch_recent_commit; use lib::logger::LogTarget; use lib::utils::add_user_to_groups; use lib::utils::create_linux_user; +use lib::utils::delete_user; +use lib::utils::extract_diff_parts; +use lib::utils::remove_user_from_groups; use lib::utils::update_user_bashrc; use lib::utils::user_exists; use log::debug; @@ -18,6 +27,26 @@ pub fn handle_update() -> Result<()> { log::info!(target: LogTarget::UPDATE.as_str(), "Watchdog update triggered."); let config = read_config()?; init(&config)?; + + let base_commit = fs::read_to_string(BASE_COMMIT_PATH) + .unwrap_or_default() + .trim() + .to_string(); + + if !base_commit.is_empty() { + info!(target: LogTarget::UPDATE.as_str(), "Found base_commit: {}. Running incremental update.", base_commit); + match update_from_commit(&config, &base_commit) { + Ok(_) => { + info!(target: LogTarget::UPDATE.as_str(), "Incremental update completed successfully."); + } + Err(e) => { + error!(target: LogTarget::UPDATE.as_str(), "Incremental update failed: {}", e); + return Err(e); + } + } + return Ok(()); + } + let _ = fetch_file_names( &config.keyhouse.base_url, "names", @@ -64,3 +93,61 @@ pub fn handle_update() -> Result<()> { } Ok(()) } + +pub fn update_from_commit(config: &Config, base_commit: &str) -> Result<()> { + info!(target: LogTarget::UPDATE.as_str(), "Performing incremental update from commit: {}", base_commit); + let merge_commit = match fetch_recent_commit(config) { + Ok(commit) => { + info!(target: LogTarget::UPDATE.as_str(), "Fetched merge commit: {}", commit); + commit + } + Err(e) => { + error!(target: LogTarget::UPDATE.as_str(), "Failed to fetch merge commit: {}", e); + return Err(e); + } + }; + let diff = match fetch_diff(&config, &base_commit, &merge_commit) { + Ok(diff) => { + info!(target: LogTarget::UPDATE.as_str(), "Fetched diff: {}", diff); + diff + } + Err(e) => { + error!(target: LogTarget::UPDATE.as_str(), "Failed to fetch diff: {}", e); + return Err(e); + } + }; + for (cloud_provider, project, hash, status) in extract_diff_parts(&diff) { + info!( + "Parsed diff - Project: {}, Cloud Provider: {}, Hash: {}, Status: {}", + project, cloud_provider, hash, status + ); + if cloud_provider != config.hostname { + info!(target: LogTarget::UPDATE.as_str(), "Skipping cloud provider {} as it does not match the config hostname {}", cloud_provider, config.hostname); + continue; + } + if let Ok(Some(decoded_str)) = fetch_and_decode_file(&config, &hash, &status, &base_commit) + { + info!("Decoded file for hash {}", hash); + if status == "added" { + info!("Adding user to group..."); + add_user_to_groups(&decoded_str, &[project.clone()]).unwrap_or_else(|e| { + error!("Failed to add user to group: {}", e); + }); + } else if status == "deleted" { + info!("Removing user from group..."); + remove_user_from_groups(&decoded_str, &[project.clone()]).unwrap_or_else(|e| { + error!("Failed to remove user from group: {}", e); + }); + } else if status == "deleteduser" { + info!("Deleting user..."); + delete_user(&decoded_str).unwrap_or_else(|e| { + error!("Failed to delete user: {}", e); + }); + } + } + } + info!(target: LogTarget::UPDATE.as_str(), "Incremental update completed."); + fs::write(BASE_COMMIT_PATH, merge_commit.clone())?; + info!(target: LogTarget::UPDATE.as_str(), "Updated base commit to: {}", merge_commit); + Ok(()) +} From 6189738e54ee695ba47a7b1d700074b7a52d8ef8 Mon Sep 17 00:00:00 2001 From: Arshdeep54 Date: Fri, 16 May 2025 21:59:41 +0530 Subject: [PATCH 25/30] Fix base_url in handle_update Signed-off-by: Arshdeep54 --- src/lib/constants.rs | 2 +- src/lib/keyhouse.rs | 28 +++++++++++++++------------- src/lib/utils.rs | 4 ++-- src/update.rs | 6 +++--- 4 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/lib/constants.rs b/src/lib/constants.rs index 63f12e5..e8bd171 100644 --- a/src/lib/constants.rs +++ b/src/lib/constants.rs @@ -1,4 +1,4 @@ -pub const BASE_COMMIT_PATH: &str = "/opt/watchdog/base_commmit.txt"; +pub const BASE_COMMIT_PATH: &str = "/opt/watchdog/base_commit.txt"; pub const CONFIG_PATH: &str = "/opt/watchdog/config.toml"; pub const LOG_PATH: &str = "/opt/watchdog/custom-logs"; pub const HOME_DIR: &str = "/opt/watchdog/users"; diff --git a/src/lib/keyhouse.rs b/src/lib/keyhouse.rs index d5ae97a..c6e75e7 100644 --- a/src/lib/keyhouse.rs +++ b/src/lib/keyhouse.rs @@ -257,7 +257,8 @@ pub fn fetch_recent_commit(config: &Config) -> Result { .timeout(Duration::from_secs(10)) .build()?; - let url = format!("{}/commits?sha=build&per_page=1", config.keyhouse.base_url); + let clean_base: &str = config.keyhouse.base_url.trim_end_matches("/contents"); + let url = format!("{}/commits?sha=build&per_page=1", clean_base); info!(target: LogTarget::UPDATE.as_str(), "Fetching recent commit from URL: {}", url); let mut response = match client @@ -296,10 +297,10 @@ pub fn fetch_recent_commit(config: &Config) -> Result { .chain_err(|| "Failed to parse GitHub commits response into JSON")?; if let Some(commit) = commits.first() { - log::info!("Fetched latest commit SHA: {}", commit.sha); + log::info!(target: LogTarget::UPDATE.as_str(),"Fetched latest commit SHA: {}", commit.sha); Ok(commit.sha.clone()) } else { - log::error!("No commits found in GitHub response"); + log::error!(target: LogTarget::UPDATE.as_str(),"No commits found in GitHub response"); Err(Error::from("No commits found in the GitHub response")) } } @@ -310,9 +311,10 @@ pub fn fetch_diff(config: &Config, base: &str, merge: &str) -> Result { .build() .chain_err(|| "Failed to build HTTP client")?; - let url = format!("{}/compare/{}...{}", config.keyhouse.base_url, base, merge); + let clean_base: &str = config.keyhouse.base_url.trim_end_matches("/contents"); + let url = format!("{}/compare/{}...{}", clean_base, base, merge); - info!("Fetching diff from GitHub: {}", url); + info!(target: LogTarget::UPDATE.as_str(),"Fetching diff from GitHub: {}", url); let mut response = match client .get(&url) @@ -322,7 +324,7 @@ pub fn fetch_diff(config: &Config, base: &str, merge: &str) -> Result { { Ok(resp) => resp, Err(e) => { - log::error!("Error sending request to GitHub: {}", e); + log::error!(target: LogTarget::UPDATE.as_str(),"Error sending request to GitHub: {}", e); return Err(Error::from(format!( "Failed to send request to GitHub: {}", e @@ -331,7 +333,7 @@ pub fn fetch_diff(config: &Config, base: &str, merge: &str) -> Result { }; if !response.status().is_success() { - log::error!( + log::error!(target: LogTarget::UPDATE.as_str(), "GitHub API returned non-success status: {}", response.status() ); @@ -345,7 +347,7 @@ pub fn fetch_diff(config: &Config, base: &str, merge: &str) -> Result { .text() .chain_err(|| "Failed to read GitHub diff response body")?; - info!("Fetched diff between {} and {}", base, merge); + info!(target: LogTarget::UPDATE.as_str(),"Fetched diff between {} and {}", base, merge); Ok(diff) } @@ -362,7 +364,7 @@ pub fn fetch_and_decode_file( }; let url = format!( - "{}/contents/names/{}?ref={}", + "{}/names/{}?ref={}", config.keyhouse.base_url, hash, commit_ref ); @@ -377,12 +379,12 @@ pub fn fetch_and_decode_file( .header(ACCEPT, "application/vnd.github.v3+json") .send() .map_err(|e| { - log::error!("Failed to fetch file from GitHub for hash {}: {}", hash, e); + log::error!(target: LogTarget::UPDATE.as_str(),"Failed to fetch file from GitHub for hash {}: {}", hash, e); Error::from(format!("Failed to fetch file for hash {}: {}", hash, e)) })?; if !file_resp.status().is_success() { - warn!( + warn!(target: LogTarget::UPDATE.as_str(), "GitHub API returned error for file at hash {}: {}", hash, file_resp.status() @@ -401,10 +403,10 @@ pub fn fetch_and_decode_file( let decoded_str = String::from_utf8(decoded).chain_err(|| "Decoded content is not valid UTF-8")?; - info!("Decoded file for hash {}", hash); + info!(target: LogTarget::UPDATE.as_str(),"Decoded file for hash {}", hash); Ok(Some(decoded_str)) } else { - warn!("No 'content' field found for file hash {}", hash); + warn!(target: LogTarget::UPDATE.as_str(),"No 'content' field found for file hash {}", hash); Ok(None) } } diff --git a/src/lib/utils.rs b/src/lib/utils.rs index 9aa244b..0ee55c7 100644 --- a/src/lib/utils.rs +++ b/src/lib/utils.rs @@ -261,7 +261,7 @@ pub fn extract_diff_parts(diff_data: &str) -> Vec<(String, String, String, Strin "modified" }; info!( - "Access file change detected: {}/{}/{}, status: {}", + target: LogTarget::UPDATE.as_str(),"Access file change detected: {}/{}/{}, status: {}", project, provider, hash, status ); parts_with_status @@ -275,7 +275,7 @@ pub fn extract_diff_parts(diff_data: &str) -> Vec<(String, String, String, Strin } else { "modifieduser" }; - info!("Name file change detected: {}, status: {}", hash, status); + info!(target: LogTarget::UPDATE.as_str(),"Name file change detected: {}, status: {}", hash, status); parts_with_status .entry(("".to_string(), "names".to_string(), hash.to_string())) .or_insert(status.to_string()); diff --git a/src/update.rs b/src/update.rs index 9301ac8..a076cf1 100644 --- a/src/update.rs +++ b/src/update.rs @@ -118,7 +118,7 @@ pub fn update_from_commit(config: &Config, base_commit: &str) -> Result<()> { }; for (cloud_provider, project, hash, status) in extract_diff_parts(&diff) { info!( - "Parsed diff - Project: {}, Cloud Provider: {}, Hash: {}, Status: {}", + target: LogTarget::UPDATE.as_str(),"Parsed diff - Project: {}, Cloud Provider: {}, Hash: {}, Status: {}", project, cloud_provider, hash, status ); if cloud_provider != config.hostname { @@ -127,9 +127,9 @@ pub fn update_from_commit(config: &Config, base_commit: &str) -> Result<()> { } if let Ok(Some(decoded_str)) = fetch_and_decode_file(&config, &hash, &status, &base_commit) { - info!("Decoded file for hash {}", hash); + info!(target: LogTarget::UPDATE.as_str(),"Decoded file for hash {}", hash); if status == "added" { - info!("Adding user to group..."); + info!(target: LogTarget::UPDATE.as_str(),"Adding user to group..."); add_user_to_groups(&decoded_str, &[project.clone()]).unwrap_or_else(|e| { error!("Failed to add user to group: {}", e); }); From cc23e54510bb3af073a43d926085783998053518 Mon Sep 17 00:00:00 2001 From: Arshdeep54 Date: Fri, 16 May 2025 23:16:23 +0530 Subject: [PATCH 26/30] Fix verbose logging Signed-off-by: Arshdeep54 --- src/lib/keyhouse.rs | 2 +- src/lib/logger.rs | 18 ++++++++++-------- src/main.rs | 22 ++++++++++++++++++++-- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/lib/keyhouse.rs b/src/lib/keyhouse.rs index c6e75e7..3821936 100644 --- a/src/lib/keyhouse.rs +++ b/src/lib/keyhouse.rs @@ -389,7 +389,7 @@ pub fn fetch_and_decode_file( hash, file_resp.status() ); - return Ok(None); // Gracefully handle non-success HTTP codes + return Ok(None); } let file_json = file_resp diff --git a/src/lib/logger.rs b/src/lib/logger.rs index 57876bd..5428389 100644 --- a/src/lib/logger.rs +++ b/src/lib/logger.rs @@ -37,7 +37,7 @@ lazy_static::lazy_static! { static ref TARGET_LOGGERS: Mutex>> = Mutex::new(HashMap::new()); } -pub fn init_logger() -> Result<(), InitError> { +pub fn init_logger(global_level: LevelFilter) -> Result<(), InitError> { let config = read_config().map_err(|_| { InitError::from(io::Error::new( io::ErrorKind::Other, @@ -67,23 +67,25 @@ pub fn init_logger() -> Result<(), InitError> { let logger = Box::new(PerTargetLogger { base_dir: base_dir.to_string(), offset, + global_level, }); - log::set_boxed_logger(logger) - .map(|()| log::set_max_level(LevelFilter::Info)) - .map_err(InitError::SetLoggerError) + log::set_boxed_logger(logger).map(|()| log::set_max_level(global_level))?; + + Ok(()) } use chrono::{DateTime, FixedOffset, NaiveDateTime, TimeZone, Utc}; - struct PerTargetLogger { - base_dir: String, - offset: FixedOffset, + base_dir: String, + offset: FixedOffset, + global_level: LevelFilter, } + impl log::Log for PerTargetLogger { fn enabled(&self, metadata: &log::Metadata) -> bool { - metadata.level() <= LevelFilter::Info + metadata.level() <= self.global_level } fn log(&self, record: &log::Record) { diff --git a/src/main.rs b/src/main.rs index 3b98029..c449cd1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,7 +11,7 @@ use clap::{App, AppSettings, Arg, SubCommand}; use auth::handle_auth; use lib::errors::Error; use lib::logger::{handle_logs_all, handle_logs_for, init_logger, LogTarget}; -use log::{error, info}; +use log::{error, info, LevelFilter}; use ssh::handle_ssh; use su::handle_su; use sudo::handle_sudo; @@ -22,6 +22,13 @@ fn make_app<'a, 'b>() -> App<'a, 'b> { .version("0.1.0") .author("SDSLabs ") .about("Simple server access management system on a binary") + .arg( + Arg::with_name("verbose") + .short("v") + .long("verbose") + .multiple(true) + .help("Increases logging verbosity each use for up to 3 times"), + ) .subcommand( SubCommand::with_name("logs") .about("Fetch logs from watchdog components") @@ -136,7 +143,18 @@ fn print_traceback(e: Error) { fn main() { let app = make_app(); let matches = app.get_matches(); - init_logger().unwrap(); + let verbosity = matches.occurrences_of("verbose"); + + let level = match verbosity { + 0 => LevelFilter::Warn, + 1 => LevelFilter::Info, + 2 => LevelFilter::Debug, + _ => LevelFilter::Trace, + }; + + init_logger(level).unwrap_or_else(|e| { + eprintln!("Logger failed to initialize: {}", e); + }); info!(target: "watchdog", "Watchdog started."); if let Some(logs_matches) = matches.subcommand_matches("logs") { let level = logs_matches.value_of("level"); From a17cf104f53ced82611ef7efd45241ed39a4f601 Mon Sep 17 00:00:00 2001 From: Arshdeep54 Date: Sun, 18 May 2025 10:30:40 +0530 Subject: [PATCH 27/30] Add verbose level in config Signed-off-by: Arshdeep54 --- sample.config.toml | 3 ++- src/lib/config.rs | 5 +++++ src/lib/keyhouse.rs | 2 +- src/lib/logger.rs | 19 ++++++++++++++----- src/main.rs | 19 ++----------------- 5 files changed, 24 insertions(+), 24 deletions(-) diff --git a/sample.config.toml b/sample.config.toml index 6edd0d5..a05d7ae 100644 --- a/sample.config.toml +++ b/sample.config.toml @@ -27,4 +27,5 @@ channel = 'C0123456789' # Logging [logging] debug='true' -offset='+5:30' \ No newline at end of file +offset='+5:30' +verbosity='v' \ No newline at end of file diff --git a/src/lib/config.rs b/src/lib/config.rs index cb13edc..7d2cb8d 100644 --- a/src/lib/config.rs +++ b/src/lib/config.rs @@ -21,6 +21,7 @@ pub struct NotifiersConf { pub struct LoggingConf { pub debug: String, pub offset: String, + pub verbosity: String, } #[derive(Deserialize, Clone)] @@ -64,6 +65,9 @@ pub fn set_config_value(key: &str, val: &str) -> Result<()> { "logging.offset" => { doc["logging"]["offset"] = value(val); } + "logging.verbosity" => { + doc["logging"]["verbosity"] = value(val); + } _ => { return Err("Invalid Key passed".into()); } @@ -85,6 +89,7 @@ pub fn get_config_value(key: &str) -> Result { "notifiers.channel" => doc["notifiers"]["channel"].as_str(), "logging.debug" => doc["logging"]["debug"].as_str(), "logging.offset" => doc["logging"]["offset"].as_str(), + "logging.verbosity" => doc["logging"]["verbosity"].as_str(), _ => { return Err("Invalid Key passed".into()); } diff --git a/src/lib/keyhouse.rs b/src/lib/keyhouse.rs index 3821936..1cc9052 100644 --- a/src/lib/keyhouse.rs +++ b/src/lib/keyhouse.rs @@ -389,7 +389,7 @@ pub fn fetch_and_decode_file( hash, file_resp.status() ); - return Ok(None); + return Ok(None); } let file_json = file_resp diff --git a/src/lib/logger.rs b/src/lib/logger.rs index 5428389..5617a08 100644 --- a/src/lib/logger.rs +++ b/src/lib/logger.rs @@ -33,11 +33,20 @@ impl LogTarget { } } +fn verbosity_to_level_filter(verbosity: &str) -> LevelFilter { + match verbosity { + "v" => LevelFilter::Info, + "vv" => LevelFilter::Debug, + "vvv" => LevelFilter::Trace, + _ => LevelFilter::Warn, + } +} + lazy_static::lazy_static! { static ref TARGET_LOGGERS: Mutex>> = Mutex::new(HashMap::new()); } -pub fn init_logger(global_level: LevelFilter) -> Result<(), InitError> { +pub fn init_logger() -> Result<(), InitError> { let config = read_config().map_err(|_| { InitError::from(io::Error::new( io::ErrorKind::Other, @@ -48,6 +57,7 @@ pub fn init_logger(global_level: LevelFilter) -> Result<(), InitError> { if config.logging.debug == "false" { return Ok(()); } + let global_level = verbosity_to_level_filter(&config.logging.verbosity); let offset = parse_offset(&config.logging.offset).map_err(|_| { InitError::from(io::Error::new( @@ -77,12 +87,11 @@ pub fn init_logger(global_level: LevelFilter) -> Result<(), InitError> { use chrono::{DateTime, FixedOffset, NaiveDateTime, TimeZone, Utc}; struct PerTargetLogger { - base_dir: String, - offset: FixedOffset, - global_level: LevelFilter, + base_dir: String, + offset: FixedOffset, + global_level: LevelFilter, } - impl log::Log for PerTargetLogger { fn enabled(&self, metadata: &log::Metadata) -> bool { metadata.level() <= self.global_level diff --git a/src/main.rs b/src/main.rs index c449cd1..9bec1ff 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,7 +11,7 @@ use clap::{App, AppSettings, Arg, SubCommand}; use auth::handle_auth; use lib::errors::Error; use lib::logger::{handle_logs_all, handle_logs_for, init_logger, LogTarget}; -use log::{error, info, LevelFilter}; +use log::{error, info}; use ssh::handle_ssh; use su::handle_su; use sudo::handle_sudo; @@ -22,13 +22,6 @@ fn make_app<'a, 'b>() -> App<'a, 'b> { .version("0.1.0") .author("SDSLabs ") .about("Simple server access management system on a binary") - .arg( - Arg::with_name("verbose") - .short("v") - .long("verbose") - .multiple(true) - .help("Increases logging verbosity each use for up to 3 times"), - ) .subcommand( SubCommand::with_name("logs") .about("Fetch logs from watchdog components") @@ -143,16 +136,8 @@ fn print_traceback(e: Error) { fn main() { let app = make_app(); let matches = app.get_matches(); - let verbosity = matches.occurrences_of("verbose"); - - let level = match verbosity { - 0 => LevelFilter::Warn, - 1 => LevelFilter::Info, - 2 => LevelFilter::Debug, - _ => LevelFilter::Trace, - }; - init_logger(level).unwrap_or_else(|e| { + init_logger().unwrap_or_else(|e| { eprintln!("Logger failed to initialize: {}", e); }); info!(target: "watchdog", "Watchdog started."); From b84fd19cddd71121cb3139100f3f807d82ad8f7a Mon Sep 17 00:00:00 2001 From: Arshdeep54 Date: Sun, 18 May 2025 10:43:21 +0530 Subject: [PATCH 28/30] Add default logs to watchdog.logs Signed-off-by: Arshdeep54 --- src/lib/logger.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/logger.rs b/src/lib/logger.rs index 5617a08..daeb9ef 100644 --- a/src/lib/logger.rs +++ b/src/lib/logger.rs @@ -28,7 +28,7 @@ impl LogTarget { LogTarget::SUDO => "sudo", LogTarget::SU => "su", LogTarget::WATCHDOG => "watchdog", - LogTarget::Other(s) => s.as_str(), + LogTarget::Other(_) => "watchdog", } } } From 58d6f92c561ca5c857e52b2d6270f8474a4f40be Mon Sep 17 00:00:00 2001 From: Arshdeep54 Date: Sun, 18 May 2025 11:08:51 +0530 Subject: [PATCH 29/30] Add dependencies logs in dependencies.logs Signed-off-by: Arshdeep54 --- src/lib/logger.rs | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/lib/logger.rs b/src/lib/logger.rs index daeb9ef..bad5a76 100644 --- a/src/lib/logger.rs +++ b/src/lib/logger.rs @@ -85,6 +85,14 @@ pub fn init_logger() -> Result<(), InitError> { Ok(()) } + +fn classify_target(raw_target: &str) -> String { + match raw_target { + "update" | "auth" | "ssh" | "sudo" | "su" | "watchdog" => raw_target.to_string(), + _ => "dependencies".to_string(), // Third-party logs go here + } +} + use chrono::{DateTime, FixedOffset, NaiveDateTime, TimeZone, Utc}; struct PerTargetLogger { base_dir: String, @@ -102,14 +110,17 @@ impl log::Log for PerTargetLogger { return; } - let target = if record.target().is_empty() { + let raw_target = if record.target().is_empty() { "watchdog" } else { record.target() }; + + let target = classify_target(raw_target); + let mut loggers = TARGET_LOGGERS.lock().unwrap(); - if !loggers.contains_key(target) { + if !loggers.contains_key(&target) { let log_path = format!("{}/{}.logs", self.base_dir, target); match fern::log_file(&log_path) { Ok(file) => { @@ -122,9 +133,10 @@ impl log::Log for PerTargetLogger { .with_timezone(&offset) .format("%Y-%m-%d %H:%M:%S"); out.finish(format_args!( - "{} [{}] {}", + "{} [{}] [{}] {}", time, record.level(), + record.target(), message )) } @@ -132,7 +144,7 @@ impl log::Log for PerTargetLogger { .chain(file) .into_log(); - loggers.insert(target.to_string(), logger); + loggers.insert(target.clone(), logger); } Err(e) => { eprintln!("Failed to create log file for {}: {}", target, e); @@ -141,7 +153,7 @@ impl log::Log for PerTargetLogger { } } - if let Some(logger) = loggers.get(target) { + if let Some(logger) = loggers.get(&target) { logger.log(record); } } From 3d020691e3f74f02adad7b94045ae1b33a5ea474 Mon Sep 17 00:00:00 2001 From: Arshdeep54 Date: Sun, 6 Jul 2025 23:45:58 +0530 Subject: [PATCH 30/30] Fix HOME env in update_user_bashrc Signed-off-by: Arshdeep54 --- src/lib/logger.rs | 1 - src/lib/utils.rs | 20 ++++++++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/lib/logger.rs b/src/lib/logger.rs index bad5a76..a1bbc22 100644 --- a/src/lib/logger.rs +++ b/src/lib/logger.rs @@ -85,7 +85,6 @@ pub fn init_logger() -> Result<(), InitError> { Ok(()) } - fn classify_target(raw_target: &str) -> String { match raw_target { "update" | "auth" | "ssh" | "sudo" | "su" | "watchdog" => raw_target.to_string(), diff --git a/src/lib/utils.rs b/src/lib/utils.rs index 0ee55c7..2307690 100644 --- a/src/lib/utils.rs +++ b/src/lib/utils.rs @@ -161,14 +161,30 @@ pub fn delete_user(user: &str) -> Result<()> { pub fn update_user_bashrc(user: &str) -> Result<()> { let bashrc_path = format!("{}/{}/.bashrc", HOME_DIR, user); let bashrc_lines = r#" -# Load group-specific config if present +# Load group-specific config [WATCHDOG] for group in $(id -nG "$USER"); do + group_home="/home/$group" group_bashrc="/home/$group/.bashrc" - [ -f "$group_bashrc" ] && source "$group_bashrc" + if [ -f "$group_bashrc" ]; then + OLD_HOME="$HOME" + HOME="$group_home" + source "$group_bashrc" + HOME="$OLD_HOME" + fi done cd /home "#; + if let Ok(contents) = std::fs::read_to_string(&bashrc_path) { + if contents.contains("Load group-specific config [WATCHDOG]") { + info!( + "Group-config loader already present in '{}'. Skipping append.", + bashrc_path + ); + return Ok(()); + } + } + let mut file = OpenOptions::new() .append(true) .create(true)