first commit
This commit is contained in:
commit
33936366ae
14
Cargo.toml
Normal file
14
Cargo.toml
Normal file
@ -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"
|
119
src/main.rs
Normal file
119
src/main.rs
Normal file
@ -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<String>;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
53
src/modules/ai.rs
Normal file
53
src/modules/ai.rs
Normal file
@ -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<String> {
|
||||||
|
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<String> {
|
||||||
|
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
|
||||||
|
}
|
17
src/modules/kill.rs
Normal file
17
src/modules/kill.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
|
||||||
|
use crate::modules::Command;
|
||||||
|
|
||||||
|
pub struct KillCommand;
|
||||||
|
impl Command for KillCommand {
|
||||||
|
fn handle(&self, message: &str) -> Vec<String> {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
18
src/modules/ping.rs
Normal file
18
src/modules/ping.rs
Normal file
@ -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<String> {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user