From d1291635d94aad625339e0ac9b986d3cdfa199e7 Mon Sep 17 00:00:00 2001 From: arthomnix Date: Sat, 19 Nov 2022 11:43:51 +0000 Subject: [PATCH 1/6] Detect Prism Launcher and "couldn't extract native jar" issue --- libs/background-cat/src/lib.rs | 17 ++++++++++++++--- libs/background-cat/src/responses.rs | 6 ++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/libs/background-cat/src/lib.rs b/libs/background-cat/src/lib.rs index 79e47d7..789957d 100644 --- a/libs/background-cat/src/lib.rs +++ b/libs/background-cat/src/lib.rs @@ -12,7 +12,7 @@ pub fn common_mistakes(input: &str) -> Vec<(&str, String)> { pub(crate) type Check = fn(&str) -> Option<(&str, String)>; -pub(crate) const PARSERS: [Check; 15] = [ +pub(crate) const PARSERS: [Check; 16] = [ multimc_in_program_files, macos_too_new_java, multimc_in_onedrive_managed_folder, @@ -30,6 +30,7 @@ pub(crate) const PARSERS: [Check; 15] = [ using_system_glfw, using_system_openal, //old_multimc_version, + reboot_required, ]; fn multimc_in_program_files(log: &str) -> Option<(&str, String)> { @@ -247,6 +248,15 @@ fn old_multimc_version(log: &str) -> Option<(&str, String)> { } */ +fn reboot_required(log: &str) -> Option<(&str, String)> { + const TRIGGER: &str = "Couldn't extract native jar"; + if log.contains(TRIGGER) { + Some(("‼", RESPONSES.get("reboot-required")?.to_string())) + } else { + None + } +} + pub fn common_origins(input: &str) -> Vec<(&str, String)> { ORIGINS.iter().flat_map(|m| m(input)).collect() } @@ -288,8 +298,9 @@ fn pirated_build(log: &str) -> Option<(&str, String)> { fn forked_build(log: &str) -> Option<(&str, String)> { const POLYMC_BUILD: &str = "PolyMC version: "; const MANYMC_BUILD: &str = "ManyMC version: "; + const PRISM_BUILD: &str = "Prism Launcher version: "; - if log.contains(POLYMC_BUILD) || log.contains(MANYMC_BUILD) { + if log.contains(POLYMC_BUILD) || log.contains(MANYMC_BUILD) || log.contains(PRISM_BUILD) { Some(("‼", RESPONSES.get("forked-build")?.to_string())) } else { None @@ -304,4 +315,4 @@ fn m1_wrapper(log: &str) -> Option<(&str, String)> { } else { None } -} +} \ No newline at end of file diff --git a/libs/background-cat/src/responses.rs b/libs/background-cat/src/responses.rs index 0156654..26b8bc7 100644 --- a/libs/background-cat/src/responses.rs +++ b/libs/background-cat/src/responses.rs @@ -121,6 +121,12 @@ lazy_static! { indoc! { "You seem to be using your systems GLFW installation. This can cause the instance to crash if not properly setup. In case of a crash, make sure this isn't the cause of it." } + ), + ( + "reboot-required", + indoc! { + "Another process appears to be locking your native library JARs. To solve this, please reboot your computer." + } ) ]); } From 18a02333bd71ac21c86c706b6cd4120c423e01cf Mon Sep 17 00:00:00 2001 From: arthomnix Date: Sat, 19 Nov 2022 13:12:27 +0000 Subject: [PATCH 2/6] Upload logs posted as attachments to paste.ee This means a paste.ee API token is now required, the readme has been updated to reflect this. --- .env.example | 1 + Cargo.lock | 7 ++++++ README.md | 6 +++-- apps/discord-cat/Cargo.toml | 1 + apps/discord-cat/src/main.rs | 44 ++++++++++++++++++++++++++++++++++++ 5 files changed, 57 insertions(+), 2 deletions(-) diff --git a/.env.example b/.env.example index 926c9ac..d77d8ff 100644 --- a/.env.example +++ b/.env.example @@ -2,4 +2,5 @@ RUST_LOG=error DISCORD_TOKEN= +PASTE_EE_TOKEN= BACKGROUND_CAT_PREFIX=- diff --git a/Cargo.lock b/Cargo.lock index 65ee8e9..aa3a1d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -214,6 +214,7 @@ dependencies = [ "background-cat", "env_logger", "futures", + "json", "kankyo", "lazy_static", "log", @@ -582,6 +583,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "json" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd" + [[package]] name = "kankyo" version = "0.3.0" diff --git a/README.md b/README.md index 335fdd4..8be1800 100644 --- a/README.md +++ b/README.md @@ -9,12 +9,13 @@ I made this bot because it was brought to my attention that other discords also - Build the code: `cargo build --bin discord-cat` - Copy `.env.example` to `target/debug/` -- Customize `target/debug/.env` and include your Discord token in it, like this: +- Customize `target/debug/.env` and include your Discord and paste.ee tokens in it, like this: ``` # See https://docs.rs/env_logger RUST_LOG=error DISCORD_TOKEN=AAa0AAa0AAAaAaa... + PASTE_EE_TOKEN=aaAAaAa0AaAA0... BACKGROUND_CAT_PREFIX=- ``` - Run the bot: `cargo run -p discord-cat` @@ -22,12 +23,13 @@ I made this bot because it was brought to my attention that other discords also ## Running in production - Copy `.env.example` to `.env` -- Customize `.env` and include your Discord token in it, like this: +- Customize `.env` and include your Discord and paste.ee tokens in it, like this: ``` # See https://docs.rs/env_logger RUST_LOG=error DISCORD_TOKEN=AAa0AAa0AAAaAaa... + PASTE_EE_TOKEN=aaAAaAa0AaAA0... BACKGROUND_CAT_PREFIX=- ``` diff --git a/apps/discord-cat/Cargo.toml b/apps/discord-cat/Cargo.toml index eca97b4..7b947a5 100644 --- a/apps/discord-cat/Cargo.toml +++ b/apps/discord-cat/Cargo.toml @@ -15,6 +15,7 @@ kankyo = "0.3.0" tokio = { version = "1.17.0", features = ["macros", "rt-multi-thread"] } futures = "0.3.21" serde = { version = "1.0.136", features = ["derive"] } +json = "0.12.4" [dependencies.serenity] version = "0.11.2" diff --git a/apps/discord-cat/src/main.rs b/apps/discord-cat/src/main.rs index a885281..2e44cf0 100644 --- a/apps/discord-cat/src/main.rs +++ b/apps/discord-cat/src/main.rs @@ -142,6 +142,8 @@ impl EventHandler for Handler { if content_type.is_some() && str::starts_with(&content_type.unwrap(), "text/plain") { let log = String::from_utf8_lossy(&content).into_owned(); + upload_paste_ee(msg.channel_id, &log, &ctx).await; + let origins = common_origins(&log); if origins.is_empty() { @@ -184,6 +186,48 @@ impl EventHandler for Handler { } } +async fn upload_paste_ee(channel_id: ChannelId, log: &String, ctx: &Context) { + let paste_ee_token = env::var("PASTE_EE_TOKEN").expect("Expected paste.ee API token in $PASTE_EE_TOKEN"); + let client = reqwest::Client::new(); + + let request_body = json::object! { + description: "MultiMC Background Cat Log Upload", + sections: [{ contents: log.as_str() }] + }.dump(); + + let response = json::parse( + client.post("https://api.paste.ee/v1/pastes") + .header("Content-Type", "application/json") + .header("X-Auth-Token", paste_ee_token) + .body(request_body) + .send() + .await.unwrap() + .text() + .await.unwrap() + .as_str() + ).unwrap(); + + if !&response["success"].as_bool().unwrap_or_default() { + error!("paste.ee upload failed"); + } else { + let link = &response["link"]; + + if let Err(why) = channel_id.send_message(&ctx, |m| { + m.embed(|e| { + e.title("Uploaded Log"); + e.colour(Colour::DARK_TEAL); + e.field("Log uploaded to paste.ee:", link, true); + debug!("Embed: {:?}", e); + e + }); + debug!("Embed: {:?}", m); + m + }).await { + error!("Couldn't send message: {}", why); + } + info!("Uploaded attachment log to paste.ee: {}", link); + } +} async fn send_help_reply(channel_id: ChannelId, mistakes: Vec<(&str, String)>, ctx: Context) { if let Err(why) = channel_id From 1a34aca6a4d8a842e51e9a84e403cdf4849995fb Mon Sep 17 00:00:00 2001 From: arthomnix Date: Sat, 19 Nov 2022 15:38:18 +0000 Subject: [PATCH 3/6] Ask user for confirmation before uploading logs --- apps/discord-cat/Cargo.toml | 2 +- apps/discord-cat/src/main.rs | 148 ++++++++++++++++++++++++++--------- 2 files changed, 113 insertions(+), 37 deletions(-) diff --git a/apps/discord-cat/Cargo.toml b/apps/discord-cat/Cargo.toml index 7b947a5..5af9d12 100644 --- a/apps/discord-cat/Cargo.toml +++ b/apps/discord-cat/Cargo.toml @@ -20,4 +20,4 @@ json = "0.12.4" [dependencies.serenity] version = "0.11.2" default-features = false -features = ["client", "model", "gateway", "native_tls_backend", "cache", "utils", "framework", "standard_framework"] +features = ["client", "model", "collector", "gateway", "native_tls_backend", "cache", "utils", "framework", "standard_framework"] diff --git a/apps/discord-cat/src/main.rs b/apps/discord-cat/src/main.rs index 2e44cf0..8c1a7e9 100644 --- a/apps/discord-cat/src/main.rs +++ b/apps/discord-cat/src/main.rs @@ -3,6 +3,8 @@ use log::{debug, error, info}; use regex::Regex; use reqwest::get; use std::{collections::HashSet, env}; +use std::time::Duration; +use futures::StreamExt; use serenity::{ async_trait, @@ -14,9 +16,12 @@ use serenity::{ channel::Message, gateway::Ready, id::{ChannelId, UserId}, + user::User, + interactions::InteractionResponseType, }, prelude::*, utils::Colour, + builder::CreateButton, }; use background_cat::common_mistakes; @@ -142,7 +147,7 @@ impl EventHandler for Handler { if content_type.is_some() && str::starts_with(&content_type.unwrap(), "text/plain") { let log = String::from_utf8_lossy(&content).into_owned(); - upload_paste_ee(msg.channel_id, &log, &ctx).await; + upload_paste_ee(msg.channel_id, &log, &ctx, &msg.author).await; let origins = common_origins(&log); @@ -186,46 +191,117 @@ impl EventHandler for Handler { } } -async fn upload_paste_ee(channel_id: ChannelId, log: &String, ctx: &Context) { - let paste_ee_token = env::var("PASTE_EE_TOKEN").expect("Expected paste.ee API token in $PASTE_EE_TOKEN"); - let client = reqwest::Client::new(); - - let request_body = json::object! { +async fn upload_paste_ee(channel_id: ChannelId, log: &String, ctx: &Context, user: &User) { + let mut button = CreateButton::default(); + button.custom_id("upload-log"); + button.label("Upload Log"); + + match channel_id.send_message(&ctx, |m| { + m.embed(|e| { + e.title("Upload log to paste.ee?"); + e.colour(Colour::DARK_TEAL); + e.description("This will make it easier for people to read your log.\nThis button only works for the user who sent the log."); + debug!("Embed: {:?}", e); + e + }); + m.components(|c| { + c.create_action_row(|r| { + r.add_button(button); + r + }); + debug!("Components: {:?}", c); + c + }); + debug!("Embed: {:?}", m); + m + }).await { + Err(why) => error!("Couldn't send message: {}", why), + Ok(mut msg) => { + let mut interaction_stream = msg.await_component_interactions(&ctx).timeout(Duration::from_secs(180)).build(); + let mut uploaded = false; + + while let Some(interaction) = interaction_stream.next().await { + if interaction.user.id == user.id { + let paste_ee_token = env::var("PASTE_EE_TOKEN").expect("Expected paste.ee API token in $PASTE_EE_TOKEN"); + let client = reqwest::Client::new(); + + let request_body = json::object! { description: "MultiMC Background Cat Log Upload", sections: [{ contents: log.as_str() }] }.dump(); - let response = json::parse( - client.post("https://api.paste.ee/v1/pastes") - .header("Content-Type", "application/json") - .header("X-Auth-Token", paste_ee_token) - .body(request_body) - .send() - .await.unwrap() - .text() - .await.unwrap() - .as_str() - ).unwrap(); - - if !&response["success"].as_bool().unwrap_or_default() { - error!("paste.ee upload failed"); - } else { - let link = &response["link"]; - - if let Err(why) = channel_id.send_message(&ctx, |m| { - m.embed(|e| { - e.title("Uploaded Log"); - e.colour(Colour::DARK_TEAL); - e.field("Log uploaded to paste.ee:", link, true); - debug!("Embed: {:?}", e); - e - }); - debug!("Embed: {:?}", m); - m - }).await { - error!("Couldn't send message: {}", why); + let response = json::parse( + client.post("https://api.paste.ee/v1/pastes") + .header("Content-Type", "application/json") + .header("X-Auth-Token", paste_ee_token) + .body(request_body) + .send() + .await.unwrap() + .text() + .await.unwrap() + .as_str() + ).unwrap(); + + if !&response["success"].as_bool().unwrap_or_default() { + error!("paste.ee upload failed"); + } else { + let link = &response["link"]; + + interaction.create_interaction_response(&ctx, |r| { + r.kind(InteractionResponseType::UpdateMessage).interaction_response_data(|d| { + d.embed(|e| { + e.title("Uploaded log"); + e.colour(Colour::DARK_TEAL); + e.field("Log uploaded to paste.ee", link, true); + debug!("Embed: {:?}", e); + e + }); + d.components(|c| c); + debug!("Interaction response data: {:?}", d); + d + }); + debug!("Interaction response: {:?}", r); + r + }).await.unwrap(); + + uploaded = true; + info!("Uploaded attachment log to paste.ee: {}", link); + } + } else { + interaction.create_interaction_response(&ctx, |r| { + r.kind(InteractionResponseType::ChannelMessageWithSource).interaction_response_data(|d| { + d.ephemeral(true); + d.embed(|e| { + e.title("You are unauthorized to do this!"); + e.colour(Colour::DARK_TEAL); + e.description("Only the user who sent the log can upload it to paste.ee."); + debug!("Embed: {:?}", e); + e + }); + debug!("Interaction response data: {:?}", d); + d + }); + debug!("Interaction response: {:?}", r); + r + }).await.unwrap(); + } + } + + if !uploaded { + msg.edit(&ctx, |m| { + m.embed(|e| { + e.title("Timed out"); + e.colour(Colour::DARK_TEAL); + e.description("Log has not been uploaded"); + debug!("Embed: {:?}", e); + e + }); + m.components(|c| c); + debug!("Embed: {:?}", m); + m + }).await.unwrap(); + } } - info!("Uploaded attachment log to paste.ee: {}", link); } } From c23664d7fdf829a3da048775ebb2866bb4139670 Mon Sep 17 00:00:00 2001 From: arthomnix Date: Sat, 19 Nov 2022 15:54:04 +0000 Subject: [PATCH 4/6] Don't block when doing log upload to allow log parsing to run as well --- apps/discord-cat/src/main.rs | 46 ++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/apps/discord-cat/src/main.rs b/apps/discord-cat/src/main.rs index 8c1a7e9..aeb3bdd 100644 --- a/apps/discord-cat/src/main.rs +++ b/apps/discord-cat/src/main.rs @@ -125,14 +125,14 @@ impl EventHandler for Handler { if origins.is_empty() { let mistakes = common_mistakes(&log); if ! mistakes.is_empty() { - send_help_reply(msg.channel_id, mistakes, ctx).await; + send_help_reply(msg.channel_id, mistakes, &ctx).await; return; } else { info!("Didn't find any mistakes in log ({})", link.as_str()); } } else { info!("Detected pirated, custom or forked launcher ({})", link.as_str()); - send_origins_reply(msg.channel_id, origins, ctx).await; + send_origins_reply(msg.channel_id, origins, &ctx).await; return; } @@ -147,31 +147,35 @@ impl EventHandler for Handler { if content_type.is_some() && str::starts_with(&content_type.unwrap(), "text/plain") { let log = String::from_utf8_lossy(&content).into_owned(); - upload_paste_ee(msg.channel_id, &log, &ctx, &msg.author).await; + let paste_ee_future = upload_paste_ee(msg.channel_id, &log, &ctx, &msg.author); - let origins = common_origins(&log); + let log_parse_future = async { + let origins = common_origins(&log); - if origins.is_empty() { - let mistakes = common_mistakes(&log); + if origins.is_empty() { + let mistakes = common_mistakes(&log); - if !mistakes.is_empty() { - debug!("Mistakes found: {:?}", mistakes); - send_help_reply(msg.channel_id, mistakes, ctx).await; - return; + if !mistakes.is_empty() { + debug!("Mistakes found: {:?}", mistakes); + send_help_reply(msg.channel_id, mistakes, &ctx).await; + return; + } else { + info!( + "Didn't find any mistakes in attachment ({})", + attachment.filename + ); + } } else { info!( - "Didn't find any mistakes in attachment ({})", + "Detected pirated, custom or forked launcher ({})", attachment.filename ); + send_origins_reply(msg.channel_id, origins, &ctx).await; + return; } - } else { - info!( - "Detected pirated, custom or forked launcher ({})", - attachment.filename - ); - send_origins_reply(msg.channel_id, origins, ctx).await; - return; - } + }; + + futures::join!(paste_ee_future, log_parse_future); } } return; @@ -305,7 +309,7 @@ async fn upload_paste_ee(channel_id: ChannelId, log: &String, ctx: &Context, use } } -async fn send_help_reply(channel_id: ChannelId, mistakes: Vec<(&str, String)>, ctx: Context) { +async fn send_help_reply(channel_id: ChannelId, mistakes: Vec<(&str, String)>, ctx: &Context) { if let Err(why) = channel_id .send_message(&ctx, |m| { m.embed(|e| { @@ -330,7 +334,7 @@ async fn send_help_reply(channel_id: ChannelId, mistakes: Vec<(&str, String)>, c return; } -async fn send_origins_reply(channel_id: ChannelId, origins: Vec<(&str, String)>, ctx: Context) { +async fn send_origins_reply(channel_id: ChannelId, origins: Vec<(&str, String)>, ctx: &Context) { if let Err(why) = channel_id .send_message(&ctx, |m| { m.embed(|e| { From aa416da7ca68fb6530fb9168c78ec3307db34844 Mon Sep 17 00:00:00 2001 From: arthomnix Date: Sat, 19 Nov 2022 15:59:33 +0000 Subject: [PATCH 5/6] Fix formatting --- apps/discord-cat/src/main.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/discord-cat/src/main.rs b/apps/discord-cat/src/main.rs index aeb3bdd..22d4d8e 100644 --- a/apps/discord-cat/src/main.rs +++ b/apps/discord-cat/src/main.rs @@ -230,9 +230,9 @@ async fn upload_paste_ee(channel_id: ChannelId, log: &String, ctx: &Context, use let client = reqwest::Client::new(); let request_body = json::object! { - description: "MultiMC Background Cat Log Upload", - sections: [{ contents: log.as_str() }] - }.dump(); + description: "MultiMC Background Cat Log Upload", + sections: [{ contents: log.as_str() }] + }.dump(); let response = json::parse( client.post("https://api.paste.ee/v1/pastes") From 6f2b4be743528f8758481d55f7b744dc7e11883b Mon Sep 17 00:00:00 2001 From: arthomnix Date: Sat, 19 Nov 2022 16:11:19 +0000 Subject: [PATCH 6/6] Fix more formatting --- apps/discord-cat/src/main.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/discord-cat/src/main.rs b/apps/discord-cat/src/main.rs index 22d4d8e..023b00f 100644 --- a/apps/discord-cat/src/main.rs +++ b/apps/discord-cat/src/main.rs @@ -2,8 +2,7 @@ use lazy_static::lazy_static; use log::{debug, error, info}; use regex::Regex; use reqwest::get; -use std::{collections::HashSet, env}; -use std::time::Duration; +use std::{collections::HashSet, env, time::Duration}; use futures::StreamExt; use serenity::{