From ba6df3b5eed8dcd24464375bdb39b32f153cbf0b Mon Sep 17 00:00:00 2001 From: Shayne Hartford Date: Thu, 7 Nov 2024 15:09:36 -0500 Subject: [PATCH] 0.6.0 - Whitelist --- Cargo.lock | 355 +++++++++++++++++++++++++++--- Cargo.toml | 4 +- src/lib.rs | 8 +- src/ncr.rs | 19 +- src/plugins/auto_eat.rs | 1 - src/plugins/auto_look.rs | 1 - src/plugins/auto_totem.rs | 1 - src/plugins/commands/discord.rs | 40 ++-- src/plugins/commands/mod.rs | 82 ++++--- src/plugins/commands/pearl.rs | 65 ++++-- src/plugins/commands/playtime.rs | 4 +- src/plugins/commands/prelude.rs | 2 +- src/plugins/commands/seen.rs | 4 +- src/plugins/commands/whitelist.rs | 115 ++++++++++ src/plugins/mod.rs | 1 + src/plugins/pearl_tracker.rs | 2 - src/settings.rs | 88 ++++---- 17 files changed, 644 insertions(+), 148 deletions(-) create mode 100644 src/plugins/commands/whitelist.rs diff --git a/Cargo.lock b/Cargo.lock index 2e6285c..c36447c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -103,9 +103,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.92" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74f37166d7d48a0284b99dd824694c26119c700b53bf0d1540cdb147dbdaaf13" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" [[package]] name = "arrayvec" @@ -893,9 +893,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.34" +version = "1.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b9470d453346108f93a59222a9a1a5724db32d0a4727b7ab7ace4b4d822dc9" +checksum = "baee610e9452a8f6f0a1b6194ec09ff9e2d85dea54432acdae41aa0761c95d70" dependencies = [ "shlex", ] @@ -1219,6 +1219,17 @@ dependencies = [ "subtle", ] +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "downcast-rs" version = "1.2.1" @@ -1231,7 +1242,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97af9b5f014e228b33e77d75ee0e6e87960124f0f4b16337b586a6bec91867b1" dependencies = [ - "heck", + "heck 0.5.0", "proc-macro2", "proc-macro2-diagnostics", ] @@ -1251,7 +1262,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" dependencies = [ - "heck", + "heck 0.5.0", "proc-macro2", "quote", "syn 2.0.87", @@ -1566,9 +1577,15 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.0" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" + +[[package]] +name = "heck" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "heck" @@ -1782,6 +1799,124 @@ dependencies = [ "cc", ] +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -1800,12 +1935,23 @@ dependencies = [ [[package]] name = "idna" -version = "0.5.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", ] [[package]] @@ -1826,7 +1972,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.15.0", + "hashbrown 0.15.1", "serde", ] @@ -1923,6 +2069,12 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +[[package]] +name = "litemap" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" + [[package]] name = "lock_api" version = "0.4.12" @@ -2434,9 +2586,9 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e346e016eacfff12233c243718197ca12f148c84e1e84268a896699b41c71780" +checksum = "7d5a626c6807713b15cac82a6acaccd6043c9a5408c24baae07611fec3f243da" dependencies = [ "cfg_aliases", "libc", @@ -2700,9 +2852,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.38" +version = "0.38.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa260229e6538e52293eeb577aabd09945a09d6d9cc0fc550ed7529056c2e32a" +checksum = "375116bee2be9ed569afe2154ea6a99dfdffd257f533f187498c2a8f5feaf4ee" dependencies = [ "bitflags 2.6.0", "errno", @@ -3033,7 +3185,7 @@ dependencies = [ [[package]] name = "shaysbot" -version = "0.5.1" +version = "0.6.0" dependencies = [ "anyhow", "azalea", @@ -3049,6 +3201,7 @@ dependencies = [ "serde_with", "serenity", "smart-default", + "structstruck", "terminal-link", "tokio", "tracing", @@ -3239,6 +3392,12 @@ dependencies = [ "der", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "static_assertions" version = "1.1.0" @@ -3251,6 +3410,18 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "structstruck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a052ec87a2d9bdd3a35f85ec6a07a5ac0816e4190b1cbede9d67cccb47ea66d" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "venial", +] + [[package]] name = "subtle" version = "2.6.1" @@ -3294,6 +3465,17 @@ dependencies = [ "futures-core", ] +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "system-configuration" version = "0.5.1" @@ -3342,18 +3524,18 @@ checksum = "253bcead4f3aa96243b0f8fa46f9010e87ca23bd5d0c723d474ff1d2417bbdf8" [[package]] name = "thiserror" -version = "1.0.67" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3c6efbfc763e64eb85c11c25320f0737cb7364c4b6336db90aa9ebe27a0bbd" +checksum = "02dd99dc800bbb97186339685293e1cc5d9df1f8fae2d0aecd9ff1c77efea892" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.67" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b607164372e89797d78b8e23a6d67d5d1038c1c65efd52e1389ef8b77caba2a6" +checksum = "a7c61ec9a6f64d2793d8a45faba21efbe3ced62a886d44c36a009b2b519b4c7e" dependencies = [ "proc-macro2", "quote", @@ -3411,6 +3593,16 @@ dependencies = [ "time-core", ] +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "tinyvec" version = "1.8.0" @@ -3428,9 +3620,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.41.0" +version = "1.41.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145f3413504347a2be84393cc8a7d2fb4d863b375909ea59f2158261aa258bbb" +checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" dependencies = [ "backtrace", "bytes", @@ -3748,9 +3940,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "typesize" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dece5c06268af6a9ff4541788601e560a4284ffebfb357f713d676f13b964db" +checksum = "549e54551d85ba6718a95333d9bc4367f69793d7aba638de30f8d25a1f554a1d" dependencies = [ "chrono", "dashmap", @@ -3766,9 +3958,9 @@ dependencies = [ [[package]] name = "typesize-derive" -version = "0.1.7" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "905e88c2a4cc27686bd57e495121d451f027e441388a67f773be729ad4be1ea8" +checksum = "fd9fc0ad9e03a2b0c2e2a0eafaecccef2121829e1ab6ce9c9d790e6c6766bd1c" dependencies = [ "proc-macro2", "quote", @@ -3856,12 +4048,12 @@ dependencies = [ [[package]] name = "url" -version = "2.5.2" +version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada" dependencies = [ "form_urlencoded", - "idna 0.5.0", + "idna 1.0.3", "percent-encoding", "serde", ] @@ -3872,6 +4064,18 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[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 = "1.11.0" @@ -3905,6 +4109,16 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "venial" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61584a325b16f97b5b25fcc852eb9550843a251057a5e3e5992d2376f3df4bb2" +dependencies = [ + "proc-macro2", + "quote", +] + [[package]] name = "version_check" version = "0.9.5" @@ -4297,12 +4511,48 @@ dependencies = [ "windows-sys 0.48.0", ] +[[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 = "yansi" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" +[[package]] +name = "yoke" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", + "synstructure", +] + [[package]] name = "zerocopy" version = "0.7.35" @@ -4324,8 +4574,51 @@ dependencies = [ "syn 2.0.87", ] +[[package]] +name = "zerofrom" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", + "synstructure", +] + [[package]] name = "zeroize" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] diff --git a/Cargo.toml b/Cargo.toml index 5a28ca2..5e13193 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "shaysbot" -version = "0.5.1" +version = "0.6.0" authors = ["Shayne Hartford "] edition = "2021" description = "My personal Minecraft bot using Azalea" @@ -28,6 +28,7 @@ serde = "1" serde_with = "3" serenity = "0.12" smart-default = "0.7" +structstruck = "0.4" terminal-link = "0.1" tokio = { version = "1", features = ["full"] } tracing = "0.1" @@ -53,3 +54,4 @@ pedantic = { level = "warn", priority = -1 } nursery = { level = "warn", priority = -1 } # cargo = { level = "warn", priority = -1 } multiple_crate_versions = "allow" +needless_pass_by_value = "allow" diff --git a/src/lib.rs b/src/lib.rs index 65507e5..d0e1b17 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,8 @@ extern crate lazy_regex; #[macro_use] extern crate serde_with; #[macro_use] +extern crate structstruck; +#[macro_use] extern crate tracing; pub mod ncr; @@ -68,10 +70,10 @@ pub async fn start() -> anyhow::Result<()> { let trapdoors = Trapdoors::load().unwrap_or_default(); let address = settings.server_address.clone(); let token = settings.discord_token.clone(); - let account = if settings.online { - Account::microsoft(&settings.username).await? + let account = if settings.online_mode { + Account::microsoft(&settings.account_username).await? } else { - Account::offline(&settings.username) + Account::offline(&settings.account_username) }; settings.save()?; diff --git a/src/ncr.rs b/src/ncr.rs index 8679836..f6c35ba 100644 --- a/src/ncr.rs +++ b/src/ncr.rs @@ -90,7 +90,7 @@ impl Encryption for EncryptionType { } #[must_use] -pub fn find_encryption(ciphertext: &str, key: &AesKey) -> (Option, String) { +pub fn find_encryption(content: &str, key: &AesKey) -> (Option, String) { for &encoder in ENCODERS.iter() { let encryptors = [ EncryptionType::CFB(encoder), @@ -99,7 +99,7 @@ pub fn find_encryption(ciphertext: &str, key: &AesKey) -> (Option (Option, - plaintext: String, + content: String, ) -> String { if chat_encryption.mode == EncryptionMode::Never { - return plaintext; + return content; } let key = AesKey::decode_base64(&chat_encryption.key).unwrap_or_else(|_| KEY.clone()); + let plaintext = prepend_header(&content); if let Some(encryption) = type_encryption { - if let Ok(ciphertext) = encryption.encrypt(&prepend_header(&plaintext), &key) { + if let Ok(ciphertext) = encryption.encrypt(&plaintext, &key) { return ciphertext; } } else if chat_encryption.mode == EncryptionMode::Always { - if let Ok(ciphertext) = - Cfb8Encryption(NewBase64rEncoding).encrypt(&prepend_header(&plaintext), &key) - { + if let Ok(ciphertext) = Cfb8Encryption(NewBase64rEncoding).encrypt(&plaintext, &key) { return ciphertext; } } - plaintext + content } diff --git a/src/plugins/auto_eat.rs b/src/plugins/auto_eat.rs index eea847a..2b87778 100644 --- a/src/plugins/auto_eat.rs +++ b/src/plugins/auto_eat.rs @@ -40,7 +40,6 @@ impl Plugin for AutoEatPlugin { type QueryData<'a> = (Entity, &'a Hunger, &'a Inventory, &'a LookDirection); type QueryFilter = (With, With); -#[allow(clippy::needless_pass_by_value)] pub fn handle_auto_eat( mut query: Query, mut packet_events: EventWriter, diff --git a/src/plugins/auto_look.rs b/src/plugins/auto_look.rs index f06ae6c..858dc79 100644 --- a/src/plugins/auto_look.rs +++ b/src/plugins/auto_look.rs @@ -17,7 +17,6 @@ impl Plugin for AutoLookPlugin { } } -#[allow(clippy::needless_pass_by_value)] pub fn handle_auto_look( mut query: Query, With)>, entities: EntityFinder>, diff --git a/src/plugins/auto_totem.rs b/src/plugins/auto_totem.rs index 23d31cb..5f148d3 100644 --- a/src/plugins/auto_totem.rs +++ b/src/plugins/auto_totem.rs @@ -32,7 +32,6 @@ impl Plugin for AutoTotemPlugin { type QueryData<'a> = (Entity, &'a Inventory); type QueryFilter = (With, With); -#[allow(clippy::needless_pass_by_value)] pub fn handle_auto_totem( mut query: Query, mut container_click_events: EventWriter, diff --git a/src/plugins/commands/discord.rs b/src/plugins/commands/discord.rs index 1cc55f2..641c445 100644 --- a/src/plugins/commands/discord.rs +++ b/src/plugins/commands/discord.rs @@ -6,7 +6,7 @@ use azalea::{ use bevy_discord::{bot::events::BMessage, http::DiscordHttpResource, runtime::tokio_runtime}; use serenity::json::json; -use super::{CommandEvent, CommandSource, Registry, WhisperEvent}; +use super::{CommandEvent, CommandSender, CommandSource, Registry, WhisperEvent}; use crate::settings::Settings; pub struct DiscordCommandsPlugin; @@ -17,7 +17,6 @@ impl Plugin for DiscordCommandsPlugin { } } -#[allow(clippy::needless_pass_by_value)] pub fn handle_message_event( mut command_events: EventWriter, mut message_events: EventReader, @@ -30,38 +29,53 @@ pub fn handle_message_event( continue; }; - let http = event.ctx.http.clone(); let message = event.new_message.clone(); - let Some((args, command)) = registry.find_command(&message.content, &settings.chat_prefix) + let Some((args, command)) = + registry.find_command(&message.content, &settings.command_prefix) else { continue; }; - let Some(sender) = args.front().map(String::to_owned) else { + // Check if whitelist is enabled and if the user is whitelisted. + if !settings.whitelist.is_empty() + && !settings + .whitelist + .iter() + .filter_map(|(uuid, user_id)| user_id.as_ref().map(|user_id| (*uuid, user_id))) + .any(|(_, user_id)| user_id == &message.author.id.to_string()) + { + let http = event.ctx.http.clone(); + let prefix = settings.command_prefix.clone(); + let user_id = message.author.id.to_string(); tokio_runtime().spawn(async move { - let map = &json!({ - "content": "[404] Missing Player Name!" + let content = [ + String::from("[404] Your Discord account isn't linked to a Minecraft account."), + format!("Message the bot in-game '{prefix}whitelist link {user_id}' to link."), + ] + .join("\n"); + + let map = json!({ + "content": content, }); - if let Err(error) = http.send_message(message.channel_id, Vec::new(), map).await { + if let Err(error) = http.send_message(message.channel_id, vec![], &map).await { error!("{error}"); }; }); continue; - }; + } command_events.send(CommandEvent { - source: CommandSource::Discord(message.channel_id), entity, - sender, - command: *command, args, + command: *command, + source: CommandSource::Discord(message.channel_id), + sender: CommandSender::Discord(message.author.id), }); } } -#[allow(clippy::needless_pass_by_value)] pub fn handle_discord_whisper_event( mut whisper_events: EventReader, discord: Res, diff --git a/src/plugins/commands/mod.rs b/src/plugins/commands/mod.rs index ef5df62..eb0b137 100644 --- a/src/plugins/commands/mod.rs +++ b/src/plugins/commands/mod.rs @@ -4,6 +4,7 @@ mod discord; mod pearl; mod playtime; mod seen; +mod whitelist; use std::collections::{HashMap, VecDeque}; @@ -12,9 +13,10 @@ use azalea::{ chat::{handle_send_chat_event, ChatPacketKind, ChatReceivedEvent, SendChatKindEvent}, ecs::prelude::*, prelude::*, + TabList, }; use ncr::AesKey; -use serenity::all::ChannelId; +use serenity::all::{ChannelId, UserId}; use crate::{ ncr::{find_encryption, try_encrypt, EncryptionType, KEY}, @@ -26,6 +28,13 @@ pub enum Command { Pearl, Playtime, Seen, + Whitelist, +} + +#[derive(Clone, Debug)] +pub enum CommandSender { + Discord(UserId), + Minecraft(String), } #[derive(Clone, Debug)] @@ -34,21 +43,21 @@ pub enum CommandSource { Minecraft(Option), } -#[derive(Debug, Event)] +#[derive(Clone, Debug, Event)] pub struct CommandEvent { - pub source: CommandSource, pub entity: Entity, - pub sender: String, - pub command: Command, pub args: VecDeque, + pub command: Command, + pub sender: CommandSender, + pub source: CommandSource, } -#[derive(Debug, Event)] +#[derive(Clone, Debug, Event)] pub struct WhisperEvent { pub entity: Entity, - pub source: CommandSource, - pub sender: String, pub content: String, + pub sender: CommandSender, + pub source: CommandSource, } #[derive(Default, Resource)] @@ -97,10 +106,10 @@ impl Plugin for CommandsPlugin { } } -#[allow(clippy::needless_pass_by_value)] pub fn handle_chat_received_event( mut events: EventReader, mut command_events: EventWriter, + query: Query<&TabList>, registry: Res, settings: Res, ) { @@ -119,39 +128,62 @@ pub fn handle_chat_received_event( let key = AesKey::decode_base64(&settings.encryption.key).unwrap_or_else(|_| KEY.clone()); let (encryption, content) = find_encryption(&content, &key); - let Some((args, command)) = registry.find_command(&content, &settings.chat_prefix) else { + let Some((args, command)) = registry.find_command(&content, &settings.command_prefix) + else { continue; }; + if !settings.whitelist.is_empty() { + let Ok(tab_list) = query.get_single() else { + continue; + }; + + let Some((uuid, _info)) = tab_list + .iter() + .find(|(_, info)| info.profile.name == sender) + else { + continue; /* Not Online */ + }; + + if !settings.whitelist.contains_key(uuid) { + continue; /* Not Whitelisted */ + } + } + command_events.send(CommandEvent { - source: CommandSource::Minecraft(encryption), entity: event.entity, - sender, - command: *command, args, + command: *command, + sender: CommandSender::Minecraft(sender), + source: CommandSource::Minecraft(encryption), }); } } -#[allow(clippy::needless_pass_by_value)] pub fn handle_minecraft_whisper_event( mut chat_kind_events: EventWriter, mut whisper_events: EventReader, settings: Res, ) { - for event in whisper_events.read() { - if let CommandSource::Minecraft(encryption) = event.source { - if settings.quiet { - continue; - } + for event in whisper_events.read().cloned() { + let CommandSender::Minecraft(sender) = event.sender else { + continue; + }; - let content = try_encrypt(&settings.encryption, encryption, event.content.clone()); + let CommandSource::Minecraft(type_encryption) = event.source else { + continue; + }; - chat_kind_events.send(SendChatKindEvent { - entity: event.entity, - kind: ChatPacketKind::Command, - content: format!("w {} {content}", event.sender), - }); + if settings.disable_responses { + continue; } + + let content = try_encrypt(&settings.encryption, type_encryption, event.content); + + chat_kind_events.send(SendChatKindEvent { + entity: event.entity, + kind: ChatPacketKind::Command, + content: format!("w {sender} {content}"), + }); } } diff --git a/src/plugins/commands/pearl.rs b/src/plugins/commands/pearl.rs index 9d53179..dca7c90 100644 --- a/src/plugins/commands/pearl.rs +++ b/src/plugins/commands/pearl.rs @@ -34,43 +34,74 @@ pub fn handle_pearl_register(mut registry: ResMut) { } } -#[allow(clippy::needless_pass_by_value)] pub fn handle_pearl_command_event( mut command_events: EventReader, mut pearl_events: EventWriter, mut whisper_events: EventWriter, query: Query<(&TabList, &Position)>, + settings: Res, trapdoors: Res, ) { - for event in command_events.read() { - let Ok((tab_list, position)) = query.get(event.entity) else { - continue; - }; - + for mut event in command_events.read().cloned() { if event.command != Command::Pearl { continue; } - let sender = &event.sender; + let Ok((tab_list, position)) = query.get(event.entity) else { + continue; + }; + let mut whisper_event = WhisperEvent { entity: event.entity, - source: event.source.clone(), + source: event.source, sender: event.sender.clone(), content: String::new(), }; - if sender.is_empty() { - whisper_event.content = String::from("[404] Missing Sender!"); - whisper_events.send(whisper_event); - continue; - } + let sender = match event.sender { + CommandSender::Minecraft(username) => username, + CommandSender::Discord(user_id) => { + let Some(username) = event.args.pop_front() else { + whisper_event.content = String::from("[404] Missing username"); + whisper_events.send(whisper_event); + continue; + }; + + let Some((uuid, _info)) = tab_list + .iter() + .find(|(_, info)| info.profile.name == username) + else { + continue; + }; + + if !settings.whitelist.is_empty() { + let Some(whitelist) = settings.whitelist.get(uuid) else { + continue; + }; + + let Some(discord_id) = whitelist else { + whisper_event.content = String::from("[404] Link not found"); + whisper_events.send(whisper_event); + continue; + }; + + if discord_id != &user_id.to_string() { + whisper_event.content = String::from("[403] Not your account"); + whisper_events.send(whisper_event); + continue; + } + } + + username + } + }; let Some(uuid) = tab_list .iter() - .find(|(_, info)| &info.profile.name == sender) + .find(|(_, info)| info.profile.name == sender) .map(|(uuid, _)| uuid) else { - whisper_event.content = format!("[404] Sender not found: {sender}"); + whisper_event.content = format!("[404] {sender} is not online"); whisper_events.send(whisper_event); continue; }; @@ -97,12 +128,12 @@ pub fn handle_pearl_command_event( (shared_count, distance) }) else { - whisper_event.content = String::from("[404] Pearl not found."); + whisper_event.content = String::from("[404] Pearl not found"); whisper_events.send(whisper_event); continue; }; - whisper_event.content = String::from("[202] I'm on my way!"); + whisper_event.content = String::from("[202] I'm on my way"); whisper_events.send(whisper_event); pearl_events.send(PearlGotoEvent { diff --git a/src/plugins/commands/playtime.rs b/src/plugins/commands/playtime.rs index 2f48c4c..f6d4333 100644 --- a/src/plugins/commands/playtime.rs +++ b/src/plugins/commands/playtime.rs @@ -46,7 +46,7 @@ pub fn handle_playtime_command_event( }; let Some(player_name) = event.args.iter().next() else { - whisper_event.content = String::from("[400] Missing player name!"); + whisper_event.content = String::from("[400] Missing player name"); whisper_events.send(whisper_event); continue; }; @@ -58,7 +58,7 @@ pub fn handle_playtime_command_event( { Ok(response) => response, Err(error) => { - whisper_event.content = String::from("[404] Player not found."); + whisper_event.content = format!("[404] Player not found: {player_name}"); whisper_events.send(whisper_event); error!("{error}"); continue; diff --git a/src/plugins/commands/prelude.rs b/src/plugins/commands/prelude.rs index 298885d..9dbff9f 100644 --- a/src/plugins/commands/prelude.rs +++ b/src/plugins/commands/prelude.rs @@ -1 +1 @@ -pub use super::{discord::*, pearl::*, playtime::*, seen::*, *}; +pub use super::{discord::*, pearl::*, playtime::*, seen::*, whitelist::*, *}; diff --git a/src/plugins/commands/seen.rs b/src/plugins/commands/seen.rs index bca5f00..a3419a8 100644 --- a/src/plugins/commands/seen.rs +++ b/src/plugins/commands/seen.rs @@ -46,7 +46,7 @@ pub fn handle_seen_command_event( }; let Some(player_name) = event.args.iter().next() else { - whisper_event.content = String::from("[400] Missing player name!"); + whisper_event.content = String::from("[400] Missing player name"); whisper_events.send(whisper_event); continue; }; @@ -66,7 +66,7 @@ pub fn handle_seen_command_event( }; if response.status() == 204 { - whisper_event.content = String::from("[204] Player doesn't exist."); + whisper_event.content = format!("[204] Player not found: {player_name}"); whisper_events.send(whisper_event); continue; } diff --git a/src/plugins/commands/whitelist.rs b/src/plugins/commands/whitelist.rs new file mode 100644 index 0000000..70254e3 --- /dev/null +++ b/src/plugins/commands/whitelist.rs @@ -0,0 +1,115 @@ +use azalea::{ + app::{App, Plugin, Startup, Update}, + ecs::prelude::*, + TabList, +}; +use derive_config::DeriveTomlConfig; + +use crate::plugins::commands::prelude::*; + +/// Whitelist command +pub struct WhitelistCommandPlugin; + +impl Plugin for WhitelistCommandPlugin { + fn build(&self, app: &mut App) { + app.add_systems(Startup, handle_whitelist_register) + .add_systems( + Update, + handle_whitelist_command_event + .ambiguous_with_all() + .before(handle_discord_whisper_event) + .before(handle_minecraft_whisper_event) + .after(handle_chat_received_event), + ); + } +} + +pub fn handle_whitelist_register(mut registry: ResMut) { + registry.register("whitelist", Command::Whitelist); +} + +/// # Panics +/// Will panic if `DeriveTomlConfig::save` fails. +pub fn handle_whitelist_command_event( + mut command_events: EventReader, + mut whisper_events: EventWriter, + mut settings: ResMut, + query: Query<&TabList>, +) { + for event in command_events.read() { + if event.command != Command::Whitelist { + continue; + } + + let Ok(tab_list) = query.get_single() else { + continue; + }; + + let mut args = event.args.clone(); + let mut whisper_event = WhisperEvent { + entity: event.entity, + source: event.source.clone(), + sender: event.sender.clone(), + content: String::new(), + }; + + let Some(action) = args.pop_front() else { + whisper_event.content = + String::from("[400] Missing Action: 'add', 'remove', or 'link'"); + whisper_events.send(whisper_event); + continue; + }; + + let Some(username) = args.pop_front() else { + whisper_event.content = String::from("[400] Missing username"); + whisper_events.send(whisper_event); + continue; + }; + + let Some((uuid, _info)) = tab_list + .iter() + .find(|(_, info)| info.profile.name == username) + else { + whisper_event.content = String::from("[404] Player not found"); + whisper_events.send(whisper_event); + continue; + }; + + whisper_event.content = match action.as_ref() { + "add" => { + if settings.whitelist.contains_key(uuid) { + String::from("[409] Already whitelisted.") + } else { + settings.whitelist.insert(*uuid, None); + settings.save().expect("Failed to save settings"); + + String::from("[200] Successfully added") + } + } + "remove" => { + if settings.whitelist.contains_key(uuid) { + settings.whitelist.remove(uuid); + settings.save().expect("Failed to save settings"); + + String::from("[200] Succesfully removed") + } else { + String::from("[409] Already not whitelisted") + } + } + "link" => match &event.sender { + CommandSender::Discord(_) => { + String::from("[403] You must run this sub-command in-game") + } + CommandSender::Minecraft(_) => { + settings.whitelist.insert(*uuid, Some(username)); + settings.save().expect("Failed to save settings"); + + String::from("[200] Successfully linked") + } + }, + _ => String::from("[400] Invalid Action: 'add', 'remove', or 'link'"), + }; + + whisper_events.send(whisper_event); + } +} diff --git a/src/plugins/mod.rs b/src/plugins/mod.rs index 4b5e047..1126666 100644 --- a/src/plugins/mod.rs +++ b/src/plugins/mod.rs @@ -22,6 +22,7 @@ impl PluginGroup for ShaysPluginGroup { .add(PearlCommandPlugin) .add(PlaytimeCommandPlugin) .add(SeenCommandPlugin) + .add(WhitelistCommandPlugin) .add(AntiAfkPlugin) .add(AutoEatPlugin) .add(AutoExitPlugin) diff --git a/src/plugins/pearl_tracker.rs b/src/plugins/pearl_tracker.rs index bd64796..deaf304 100644 --- a/src/plugins/pearl_tracker.rs +++ b/src/plugins/pearl_tracker.rs @@ -51,7 +51,6 @@ pub fn handle_packet_events( /// # Panics /// Will panic if `MinecraftEntityId` is out of bounds. /// Will panic of `Settings::save` fails. -#[allow(clippy::needless_pass_by_value)] pub fn handle_add_entity_packet( mut events: EventReader, mut packet_events: ResMut, @@ -138,7 +137,6 @@ pub fn handle_block_update_packet( /// # Panics /// Will panic of `Settings::save` fails. -#[allow(clippy::needless_pass_by_value)] pub fn handle_remove_entities_packet( mut events: EventReader, mut query: Query<&Position>, diff --git a/src/settings.rs b/src/settings.rs index 438e929..49a2d64 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -1,10 +1,14 @@ +use std::collections::HashMap; + use azalea::{ app::{App, Plugin}, prelude::*, }; use derive_config::DeriveTomlConfig; use serde::{Deserialize, Serialize}; +use serde_with::NoneAsEmptyString; use smart_default::SmartDefault; +use uuid::Uuid; #[derive(Clone, Default, Deserialize, Eq, PartialEq, Serialize)] pub enum EncryptionMode { @@ -14,53 +18,61 @@ pub enum EncryptionMode { Never, } -#[derive(Clone, Deserialize, Serialize, SmartDefault)] -pub struct ChatEncryption { - /// `OnDemand` | `Always` | `Never` - #[default(EncryptionMode::OnDemand)] - pub mode: EncryptionMode, +strike! { + #[strikethrough[serde_as]] + #[strikethrough[derive(Clone, Deserialize, Serialize, SmartDefault)]] + #[strikethrough[serde(default)]] + #[derive(DeriveTomlConfig, Resource)] + pub struct Settings { + /// Minecraft server ender pearl view distance in blocks. + /// It is better to under-estimate than to over-estimate. + #[default(64)] + pub pearl_view_distance: i32, - /// Default No Chat Reports mod key - #[default("blfrngArk3chG6wzncOZ5A==")] - pub key: String, -} + /// Disable in-game command responses globally. + #[default(false)] + #[serde(alias = "quiet")] /* Deprecated: 0.6.0 */ + pub disable_responses: bool, -#[derive(Clone, DeriveTomlConfig, Deserialize, Resource, Serialize, SmartDefault)] -#[serde(default)] /* Default new or missing fields instead of the whole struct */ -pub struct Settings { - /// This is the distance in blocks that ender pearls are visible from the player. - /// It is better to under-estimate the value than to over-estimate it. - /// If you notice pearls not saving outside visual range, try decreasing this value. - /// If you notice manually pulled pearls not being removed, try increasing this value. - #[default(64)] - pub pearl_view_distance: i32, + /// Minecraft online-mode auth. + #[default(true)] + #[serde(alias = "online")] /* Deprecated: 0.6.0 */ + pub online_mode: bool, - /// Minecraft Server Address - #[default("play.vengeancecraft.net")] - pub server_address: String, + /// Minecraft account username. + #[default("ShaysBot")] + #[serde(alias = "username")] /* Deprecated: 0.6.0 */ + pub account_username: String, - /// Discord Client Token (Optional) - #[default("")] - pub discord_token: String, + /// Minecraft server address. + #[default("play.vengeancecraft.net")] + pub server_address: String, - /// Minecraft Chat Prefix - #[default("!")] - pub chat_prefix: String, + /// Discord client token. (Optional) + #[default("")] + pub discord_token: String, - /// Minecraft Account Username - #[default("ShaysBot")] - pub username: String, + /// Chat command prefix. + #[default("!")] + #[serde(alias = "chat_prefix")] /* Deprecated: 0.6.0 */ + pub command_prefix: String, - /// Minecraft Online Auth - #[default(true)] - pub online: bool, + /// Chat encryption using the NCR (No Chat Reports) mod. + pub encryption: pub struct ChatEncryption { + /// Encryption key (default is public) + #[default("blfrngArk3chG6wzncOZ5A==")] + pub key: String, - /// Disable in-game command responses - #[default(false)] - pub quiet: bool, + /// Encryption response mode. (OnDemand, Always, or Never) + #[default(EncryptionMode::OnDemand)] + pub mode: EncryptionMode, + }, - /// Minecraft Encryption Mode (NCR Mod) - pub encryption: ChatEncryption, + /// Minecraft and Discord users allowed to use the bot. + /// The whitelist is disabled if it's empty. + #[serde_as(as = "HashMap<_, NoneAsEmptyString>")] + pub whitelist: HashMap>, + } } impl Plugin for Settings {