commit 33936366aeba1280ca092e3fd6dffc24f119d197 Author: legitnull Date: Fri Feb 17 01:38:32 2023 -0700 first commit diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..f6d86bd --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "kmsbot" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +openssl = "0.10.45" +async-openai = "0.6.1" +tokio = { version = "1.23.0", features = ["full"] } +rand = "0.8.4" +regex = "1.7.1" +config = "0.13.3" \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..856711f --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# G.1.R - GARBAGE INTERNET ROBOT + diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..ed0bd74 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,119 @@ +use std::io::prelude::*; +use std::net::TcpStream; +use std::time::{Instant, Duration}; +use std::fs; +use std::thread; +use toml::Value; +use std::io::{self, Write}; +use regex::Regex; +use rand::{thread_rng, Rng}; +use openssl::ssl::{SslMethod, SslConnector, SslStream}; +use async_openai::{Client, types::{CreateCompletionRequestArgs, ResponseFormat}}; + +mod modules { + pub trait Command { + fn handle(&self, message: &str) -> Vec; + } + pub mod ping; + pub mod kill; + pub mod ai; +} +use modules::ai::Ai; +use modules::ping::PingCommand; +use modules::kill::KillCommand; +use crate::modules::Command; +fn main() { + let rt = tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .unwrap(); + + let connector = SslConnector::builder(SslMethod::tls()).unwrap().build(); +// PUT CONFIG IN A SEPRATE FILE IE: YAML, JSON, CONFIG, TOML12 + let stream = TcpStream::connect("ircd.chat:6697").unwrap(); // setup tor & custom masking + let mut ssl_stream = connector.connect("ircd.chat", stream).unwrap(); + + let nick_command = "NICK g1r\r\n"; // set SASL Passwords User Nicks + let user_command = "USER g1r 0 * :g1r\r\n"; + + + let channels = vec!["#tcpdirect", "#macros"]; // CHANNELS + let join_command = format!("JOIN {}\r\n", channels.join(",")); + + let admin_users = vec!["s4d", "s4d[m]"]; // ADMINS + let ignored_users = vec!["maple", "aibird", "proffesserOak"]; // IGNORED +// ... + ssl_stream.write_all(nick_command.as_bytes()).unwrap(); + ssl_stream.write_all(user_command.as_bytes()).unwrap(); + ssl_stream.write_all(join_command.as_bytes()).unwrap(); + + let mut buf = [0; 512]; + loop { + match ssl_stream.read(&mut buf) { + Ok(0) => break, + Ok(n) => { + let received = String::from_utf8_lossy(&buf[0..n]); + let message = received.trim(); + + //debug chat + println!("{}", received); // ADD COLORS + + + // RESPOND TO PINGS + if message.starts_with("PING") { + println!("[%] PONG"); + ssl_stream.write_all("PONG ircd.chat\r\n".as_bytes()).unwrap(); + continue; // skip processing the PING message further + } + + // MODULES + let ping_command = PingCommand; + let kill_command = KillCommand; + let ai = Ai; + + // ADMIN MODULES + if message.starts_with(":") && message.contains(" :%") { + let parts: Vec<&str> = message.splitn(2, ' ').collect(); // Check if user is admin_user + let username = parts[0].trim_start_matches(':').split("!").next().unwrap(); + if !admin_users.contains(&username) { + println!("[!] UNAUTHORIZED: {}", username); + continue; // ... + } + if message.contains(":%ping") { + for response in ping_command.handle(message) { + ssl_stream.write_all(response.as_bytes()).unwrap(); + } + } else if message.contains(":%kill") { + for response in kill_command.handle(message) { + ssl_stream.write_all(response.as_bytes()).unwrap(); + } + } + } + + // Check if the message is user and respond via ai + else if message.starts_with(":") && message.contains("PRIVMSG ") && message.contains("g1r") { //modify for on mention + let channel = message.split("PRIVMSG ").nth(1).and_then(|s| s.splitn(2, ' ').next()).unwrap(); + if !channels.contains(&channel) { + continue; + } + // extract the username from the first part and check if ignored + let parts: Vec<&str> = message.splitn(2, ' ').collect(); // split the message into two parts at the first space + let username = parts[0].trim_start_matches(':').split("!").next().unwrap(); + if ignored_users.contains(&username) { + println!("[!] IGNORED: {}", username); + continue; + } + for response in ai.handle(message, ) { + ssl_stream.write_all(response.as_bytes()).unwrap(); + } + + } + + }, + Err(e) => { + println!("Error: {}", e); + break; + }, + } + } +} diff --git a/src/modules/ai.rs b/src/modules/ai.rs new file mode 100644 index 0000000..a75c499 --- /dev/null +++ b/src/modules/ai.rs @@ -0,0 +1,53 @@ +// Check if the message is user and respond via ai +use async_openai::{Client, types::{CreateCompletionRequestArgs}}; +use regex::Regex; +use crate::modules::Command; + +pub struct Ai; + +impl Command for Ai { + fn handle(&self, message: &str) -> Vec { + let mut responses = Vec::new(); + if message.starts_with(":") && message.contains("PRIVMSG ") && message.contains("g1r") { + let channel = message.split("PRIVMSG ").nth(1).and_then(|s| s.splitn(2, ' ').next()).unwrap(); + let user_message = "The following is a chat log:\n".to_owned() + message.split(&format!("PRIVMSG {} :", channel.to_string())).nth(1).unwrap() + "\nRespond funny, completely insane, and hyperactive as you are chatting as GIR from Invader Zim: \n\n"; + let parts: Vec<&str> = message.splitn(2, ' ').collect(); + let username = parts[0].trim_start_matches(':').split("!").next().unwrap(); + + let rt = tokio::runtime::Runtime::new().unwrap(); + let result = rt.block_on(ai(&user_message, &username, &channel)); + responses.extend(result); + } + + responses + } +} +async fn ai(user_message: &str, username: &str, channel: &str) -> Vec { + let api_key = "sk-*"; // set this from config and add rotatation + + let client = Client::new().with_api_key(api_key); + println!("[?] PROMPT: {}: {}", username, user_message); + let chat_request = CreateCompletionRequestArgs::default() + .prompt(user_message) + .max_tokens(40_u16) + .model("text-davinci-003") + .build() + .unwrap(); + let chat_response = client + .completions() + .create(chat_request) + .await + .unwrap(); + println!("[+] RESPONSE: {}", chat_response.choices.first().unwrap().text); + + let response_text = &chat_response.choices.first().unwrap().text; + let regex = Regex::new(r#""|[gG][1iI][rR]:\s*|[mM][eE]:?\s"#).unwrap(); + let response_text = regex.replace_all(response_text, "").trim().to_string(); + let response_lines = response_text.split("\n").filter(|line| !line.trim().is_empty()); + let mut responses = Vec::new(); + for line in response_lines { + responses.push(format!("PRIVMSG {} :{}: {}\r\n", channel, username, line)); + } + + responses +} diff --git a/src/modules/kill.rs b/src/modules/kill.rs new file mode 100644 index 0000000..2696506 --- /dev/null +++ b/src/modules/kill.rs @@ -0,0 +1,17 @@ + +use crate::modules::Command; + +pub struct KillCommand; +impl Command for KillCommand { + fn handle(&self, message: &str) -> Vec { + let mut response = vec![]; + + if message.contains("PRIVMSG") && message.contains(":%kill") { + let channel = message.split("PRIVMSG ").nth(1).and_then(|s| s.splitn(2, ' ').next()).unwrap(); + response.push(format!("PRIVMSG {} :SELF DESTRUCTING...\r\n", channel)); + println!("[!] KILLING!"); + std::process::exit(0); + } + response + } +} diff --git a/src/modules/ping.rs b/src/modules/ping.rs new file mode 100644 index 0000000..73db193 --- /dev/null +++ b/src/modules/ping.rs @@ -0,0 +1,18 @@ + +use std::time::{Instant}; +use crate::modules::Command; + +pub struct PingCommand; +impl Command for PingCommand { + fn handle(&self, message: &str) -> Vec { + let mut response = vec![]; + + if message.contains("PRIVMSG") && message.contains(":%ping") { + let channel = message.split("PRIVMSG ").nth(1).and_then(|s| s.splitn(2, ' ').next()).unwrap(); + let start = Instant::now(); + let elapsed = start.elapsed(); + response.push(format!("PRIVMSG {} :PONG: {:?}\r\n", channel, elapsed)); + } + response + } +}