From adcacfba810a7c49855df75683366ab24c778356 Mon Sep 17 00:00:00 2001 From: Westly Ward Date: Wed, 11 Aug 2021 09:04:48 -0600 Subject: [PATCH] Bumping to version 0.1.5. Added the violence command, along with a user registration system and plugins to go with it. --- .gitignore | 2 +- Cargo.nix | 217 +++++++++++++++++++++++++++++++++++++++- Cargo.toml | 8 +- sonicmacros/src/lib.rs | 6 +- sonicobject/src/lib.rs | 14 +-- src/lib.rs | 149 ++++++++++++++++++++------- src/main.rs | 8 +- src/msgfmts.rs | 3 +- src/plugins/addhost.rs | 44 ++++++++ src/plugins/choose.rs | 2 +- src/plugins/greet.rs | 4 +- src/plugins/join.rs | 2 +- src/plugins/nickreg.rs | 47 +++++++++ src/plugins/part.rs | 2 +- src/plugins/pm.rs | 2 +- src/plugins/randfact.rs | 2 +- src/plugins/seen.rs | 2 +- src/plugins/violence.rs | 28 ++++++ src/socketwrapper.rs | 2 +- 19 files changed, 474 insertions(+), 70 deletions(-) create mode 100644 src/plugins/addhost.rs create mode 100644 src/plugins/nickreg.rs create mode 100644 src/plugins/violence.rs diff --git a/.gitignore b/.gitignore index 7937d70..d0db3eb 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,4 @@ /sonicobject/test.db /sonicmacros/target /sonicmacros/Cargo.lock - +/sftp.json diff --git a/Cargo.nix b/Cargo.nix index 7defe5a..7adc891 100644 --- a/Cargo.nix +++ b/Cargo.nix @@ -87,7 +87,7 @@ rec { # inject test dependencies into the build crates = { - "acid-store" = rec { + "acid-store 0.8.0" = rec { crateName = "acid-store"; version = "0.8.0"; edition = "2018"; @@ -183,6 +183,89 @@ rec { }; resolvedDefaultFeatures = [ "default" "store-directory" ]; }; + "acid-store 0.9.1" = rec { + crateName = "acid-store"; + version = "0.9.1"; + edition = "2018"; + sha256 = "0jqzswjd7xld0ycvwj2iyj5v3mlh66fm289gc83pklpjziv5inpk"; + authors = [ + "Wren Powell " + ]; + dependencies = [ + { + name = "anyhow"; + packageId = "anyhow"; + } + { + name = "bitflags"; + packageId = "bitflags"; + } + { + name = "blake3"; + packageId = "blake3"; + } + { + name = "cdchunking"; + packageId = "cdchunking"; + } + { + name = "digest"; + packageId = "digest"; + } + { + name = "hex-literal"; + packageId = "hex-literal"; + } + { + name = "once_cell"; + packageId = "once_cell"; + } + { + name = "rmp"; + packageId = "rmp"; + } + { + name = "rmp-serde"; + packageId = "rmp-serde"; + } + { + name = "secrecy"; + packageId = "secrecy"; + } + { + name = "serde"; + packageId = "serde"; + features = [ "derive" "rc" ]; + } + { + name = "thiserror"; + packageId = "thiserror"; + } + { + name = "uuid"; + packageId = "uuid"; + features = [ "serde" "v4" ]; + } + { + name = "weak-table"; + packageId = "weak-table"; + } + ]; + features = { + "compression" = [ "lz4" ]; + "encryption" = [ "sodiumoxide" "rand" ]; + "file-metadata" = [ "repo-file" "nix" "filetime" "xattr" "users" "exacl" ]; + "fuse-mount" = [ "fuse" "bimap" "time" "tempfile" "file-metadata" ]; + "hash-algorithms" = [ "blake2" "sha2" "sha3" ]; + "repo-file" = [ "relative-path" "walkdir" "hole-punch" ]; + "store-rclone" = [ "store-sftp" "rand" ]; + "store-redis" = [ "redis" ]; + "store-s3" = [ "rust-s3" "tokio" ]; + "store-sftp" = [ "ssh2" ]; + "store-sqlite" = [ "rusqlite" ]; + }; + resolvedDefaultFeatures = [ "default" "store-directory" ]; + }; "adler32" = rec { crateName = "adler32"; version = "1.2.0"; @@ -597,6 +680,22 @@ rec { }; resolvedDefaultFeatures = [ "default" "std" ]; }; + "block-buffer" = rec { + crateName = "block-buffer"; + version = "0.9.0"; + edition = "2018"; + sha256 = "1r4pf90s7d7lj1wdjhlnqa26vvbm6pnc33z138lxpnp9srpi2lj1"; + authors = [ + "RustCrypto Developers" + ]; + dependencies = [ + { + name = "generic-array"; + packageId = "generic-array"; + } + ]; + + }; "bumpalo" = rec { crateName = "bumpalo"; version = "3.7.0"; @@ -1057,6 +1156,28 @@ rec { "asio" = [ "asio-sys" "num-traits" ]; }; }; + "cpufeatures" = rec { + crateName = "cpufeatures"; + version = "0.1.5"; + edition = "2018"; + sha256 = "1vvid867wpnz5wzma3f4x2ijl83fgr6x1fc6shspzpf9ysb9djb6"; + authors = [ + "RustCrypto Developers" + ]; + dependencies = [ + { + name = "libc"; + packageId = "libc"; + target = { target, features }: (stdenv.hostPlatform.config == "aarch64-apple-darwin"); + } + { + name = "libc"; + packageId = "libc"; + target = { target, features }: ((target."arch" == "aarch64") && (target."os" == "linux")); + } + ]; + + }; "crc32fast" = rec { crateName = "crc32fast"; version = "1.2.1"; @@ -1815,6 +1936,20 @@ rec { }; resolvedDefaultFeatures = [ "default" ]; }; + "hex" = rec { + crateName = "hex"; + version = "0.4.3"; + edition = "2018"; + sha256 = "0w1a4davm1lgzpamwnba907aysmlrnygbqmfis2mqjx5m552a93z"; + authors = [ + "KokaKiwi " + ]; + features = { + "default" = [ "std" ]; + "std" = [ "alloc" ]; + }; + resolvedDefaultFeatures = [ "alloc" "default" "std" ]; + }; "hex-literal" = rec { crateName = "hex-literal"; version = "0.2.1"; @@ -3510,6 +3645,16 @@ rec { }; resolvedDefaultFeatures = [ "alloc" "default" "race" "std" ]; }; + "opaque-debug" = rec { + crateName = "opaque-debug"; + version = "0.3.0"; + edition = "2018"; + sha256 = "1m8kzi4nd6shdqimn0mgb24f0hxslhnqd1whakyq06wcqd086jk2"; + authors = [ + "RustCrypto Developers" + ]; + + }; "parking_lot" = rec { crateName = "parking_lot"; version = "0.11.1"; @@ -4805,6 +4950,62 @@ rec { ]; }; + "sha2" = rec { + crateName = "sha2"; + version = "0.9.5"; + edition = "2018"; + sha256 = "04lzf4swq6cijvxnc6facr3g72h5v7a5z8lz3xrkf8gxa9bswqmk"; + authors = [ + "RustCrypto Developers" + ]; + dependencies = [ + { + name = "block-buffer"; + packageId = "block-buffer"; + } + { + name = "cfg-if"; + packageId = "cfg-if 1.0.0"; + } + { + name = "cpufeatures"; + packageId = "cpufeatures"; + target = { target, features }: (stdenv.hostPlatform.config == "aarch64-apple-darwin"); + } + { + name = "cpufeatures"; + packageId = "cpufeatures"; + target = { target, features }: ((target."arch" == "aarch64") && (target."os" == "linux")); + } + { + name = "cpufeatures"; + packageId = "cpufeatures"; + target = { target, features }: ((target."arch" == "x86") || (target."arch" == "x86_64")); + } + { + name = "digest"; + packageId = "digest"; + } + { + name = "opaque-debug"; + packageId = "opaque-debug"; + } + ]; + devDependencies = [ + { + name = "digest"; + packageId = "digest"; + features = [ "dev" ]; + } + ]; + features = { + "asm" = [ "sha2-asm" ]; + "asm-aarch64" = [ "asm" ]; + "default" = [ "std" ]; + "std" = [ "digest/std" ]; + }; + resolvedDefaultFeatures = [ "default" "std" ]; + }; "shlex" = rec { crateName = "shlex"; version = "0.1.1"; @@ -4901,7 +5102,7 @@ rec { }; "sonicbot" = rec { crateName = "sonicbot"; - version = "0.1.4"; + version = "0.1.5"; edition = "2018"; crateBin = [ { name = "sonicbot"; path = "src/main.rs"; } @@ -4913,9 +5114,13 @@ rec { dependencies = [ { name = "acid-store"; - packageId = "acid-store"; + packageId = "acid-store 0.9.1"; features = [ "store-directory" ]; } + { + name = "hex"; + packageId = "hex"; + } { name = "humantime"; packageId = "humantime"; @@ -4957,6 +5162,10 @@ rec { name = "serde_json"; packageId = "serde_json"; } + { + name = "sha2"; + packageId = "sha2"; + } { name = "sonicmacros"; packageId = "sonicmacros"; @@ -5002,7 +5211,7 @@ rec { dependencies = [ { name = "acid-store"; - packageId = "acid-store"; + packageId = "acid-store 0.8.0"; features = [ "store-directory" ]; } { diff --git a/Cargo.toml b/Cargo.toml index 8f234af..acc324e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sonicbot" -version = "0.1.4" +version = "0.1.5" authors = ["Westly Ward "] edition = "2018" @@ -20,14 +20,15 @@ rand = "0.8.4" reqwest = { version = "0.10", default-features = false, features = ["blocking", "rustls-tls"] } #sled = "0.34.6" sonicobject = { path = "./sonicobject" } -acid-store = { version = "0.8.0", features = ["store-directory"] } +acid-store = { version = "0.9.1", features = ["store-directory"] } sonicmacros = { path = "./sonicmacros" } humantime = "2.1.0" textwrap = "0.14.2" regex = "1.5.4" +hex = "0.4.3" +sha2 = "0.9.5" #empty-option = "0.1.1" - [target.'cfg(target_os = "android")'.dependencies] macroquad = "0.3.7" linewrapper = { path = "./linewrapper" } @@ -44,6 +45,7 @@ linewrapper = { path = "./linewrapper" } #ndk = "0.3.0" #ndk-glue = "0.3.0" + [[package.metadata.android.permission]] name = "android.permission.INTERNET" diff --git a/sonicmacros/src/lib.rs b/sonicmacros/src/lib.rs index 01fbd3e..85ce724 100644 --- a/sonicmacros/src/lib.rs +++ b/sonicmacros/src/lib.rs @@ -48,7 +48,7 @@ pub fn backinsert(item: TokenStream) -> TokenStream { } //println!("1"); let lastitemindex = items.len() - 1; - let lastvalue = items.last().unwrap(); + //let lastvalue = items.last().unwrap(); let firstvalue = &items.clone()[0]; //println!("2"); for (num, token) in items.clone().into_iter().enumerate() { @@ -107,7 +107,7 @@ use crate::msgfmts; } code.push_str(r#"pub struct ModList { pub modnames: Vec, - pub mainfunctions: HashMap Vec>>, + pub mainfunctions: HashMap Vec>>, pub permissions: HashMap, pub syntaxes: HashMap, pub helps: HashMap, @@ -115,7 +115,7 @@ use crate::msgfmts; } impl ModList { pub fn new() -> Self { - let mut mainfunctions: HashMap Vec>> = HashMap::new(); + let mut mainfunctions: HashMap Vec>> = HashMap::new(); let mut permissions: HashMap = HashMap::new(); let mut syntaxes: HashMap = HashMap::new(); let mut helps: HashMap = HashMap::new(); diff --git a/sonicobject/src/lib.rs b/sonicobject/src/lib.rs index 23eb18c..1808aeb 100644 --- a/sonicobject/src/lib.rs +++ b/sonicobject/src/lib.rs @@ -29,11 +29,11 @@ impl SonicObject { SonicObject::new(self.value.get(key.to_string()).unwrap().to_owned()) } pub fn contains(&mut self, key: &str) -> bool { - let mut svalue = self.value.as_object_mut().unwrap(); + let svalue = self.value.as_object_mut().unwrap(); svalue.contains_key(key) } pub fn insert(&mut self, key: &str, value: impl Serialize) -> () { - let mut svalue = self.value.as_object_mut().unwrap(); + let svalue = self.value.as_object_mut().unwrap(); //println!("svalue is now '{:?}'", svalue); ////println!("svalue = '{:?}'", svalue); let sobject = serde_json::to_string(&value).unwrap(); @@ -60,7 +60,7 @@ impl SonicObject { self.value = v; } pub fn remove(&mut self, key: &str) -> () { - let mut svalue = self.value.as_object_mut().unwrap(); + let svalue = self.value.as_object_mut().unwrap(); ////println!("svalue = '{:?}'", svalue); //let sobject = serde_json::to_string(&value).unwrap(); ////println!("sobject = '{:?}'", sobject); @@ -97,7 +97,7 @@ impl SonicObject { } impl SonicPersistObject { pub fn new(filepath: PathBuf) -> Self { - let mut tree = OpenOptions::new().mode(OpenMode::Create).open(&DirectoryConfig{ path: filepath }).unwrap();//sled::open(&filepath).unwrap(); + let tree = OpenOptions::new().mode(OpenMode::Create).open(&DirectoryConfig{ path: filepath }).unwrap();//sled::open(&filepath).unwrap(); Self { tree: tree, } @@ -132,11 +132,11 @@ pub fn getemptyvalue() -> Value { #[cfg(test)] mod tests { use std::fs; - use std::path::{Path, PathBuf}; + use std::path::{Path}; use crate::SonicPersistObject; - use serde_json::Value; + use serde_json::json; - use std::collections::HashMap; + #[test] fn it_works() { if Path::new("test.db").exists() { diff --git a/src/lib.rs b/src/lib.rs index 27b3491..18d5a4b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,21 +4,21 @@ mod plugins; mod msgfmts; //use std::collections::BTreeMap; //use std::collections::HashMap; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use std::time::SystemTime; use parser::{IRCMessage}; use socketwrapper::SocketWrapper; //use macroquad::prelude::*; -use std::sync::mpsc::TryRecvError; +//use std::sync::mpsc::TryRecvError; //use acid_store::repo::{OpenOptions, value::ValueRepo, OpenMode}; //use acid_store::store::{DirectoryConfig}; //use acid_store::store::MemoryStore; //use rand::seq::SliceRandom; //use sled::Db; -use std::io::Write; -use serde::{Deserialize, Serialize}; +//use std::io::Write; +//use serde::{Deserialize, Serialize}; //use serde_json::Result; -use std::fs; +//use std::fs; //use linewrapper::LineWrapper; use sonicmacros::backinsert; use sonicobject::{SonicPersistObject, SonicObject}; @@ -28,6 +28,14 @@ pub enum CommandErrorReason { NoSuchCommand(String), NoCommandMatch(bool), } +pub enum PermissionErrorReason { + HostMismatch(bool), + NotOwner(bool), + NotChannelOwner(String), + NotAdmin(bool), + NotRegistered(bool), + LevelTooLow(u8), +} //#[allow(dead_code)] pub struct SonicbotData { swrapper: Box, @@ -41,8 +49,9 @@ pub struct SonicbotData { comprefix: String, wholeversion: String, hostlabel: String, - datadir: PathBuf, + //datadir: PathBuf, db: SonicPersistObject, + networkdata: SonicObject, essentialslist: Vec, onandroid: bool, tx: std::sync::mpsc::Sender, @@ -53,7 +62,7 @@ impl SonicbotData { //let rep = OpenOptions::new(MemoryStore::new()).create::>().unwrap(); let mut db = SonicPersistObject::new(datadir.as_path().join(format!("sonicbotdata_{}", hostlabel).as_str())); let modlist = plugins::ModList::new(); - let essentialslist = vec!["PRIVMSG".to_string(), "JOIN".to_string(), "PART".to_string()]; + let essentialslist = vec!["PRIVMSG".to_string(), "JOIN".to_string(), "PART".to_string(), "NICK".to_string()]; if !db.contains("essentials") { db.insert("essentials", sonicobject::getemptyvalue()); } @@ -74,6 +83,12 @@ impl SonicbotData { db.insert("plugins", newinsert.value); } } + if !db.contains("users") { + db.insert("users", sonicobject::getemptyvalue()); + } + let mut networkdata = SonicObject::new(sonicobject::getemptyvalue()); + networkdata.insert("channels", sonicobject::getemptyvalue()); + networkdata.insert("nicks", sonicobject::getemptyvalue()); //let mut linew = LineWrapper::new(); Self { swrapper: Box::new(SocketWrapper::new(host.to_string(), port, ssl)), @@ -87,8 +102,9 @@ impl SonicbotData { comprefix: comprefix.to_string(), wholeversion: wholeversion, hostlabel: hostlabel, - datadir: datadir, + //datadir: datadir, db: db, + networkdata: networkdata, essentialslist: essentialslist, onandroid: onandroid, tx: tx.clone(), @@ -107,9 +123,9 @@ impl SonicbotData { fn rawsend(&mut self, msg: String) -> () { self.swrapper.write_all(msg.as_str().to_string()); if !self.onandroid { - println!("[OUT] {}", msg.as_str().to_string().replace("\r", "").replace("\n", "")); + println!("[OUT {}] {}", self.hostlabel, msg.as_str().to_string().replace("\r", "").replace("\n", "")); } else { - self.tx.send(format!("[OUT] {}", msg.as_str().to_string().replace("\r", "").replace("\n", ""))).unwrap(); + self.tx.send(format!("[OUT {}] {}", self.hostlabel, msg.as_str().to_string().replace("\r", "").replace("\n", ""))).unwrap(); } } fn nicksend(&mut self) -> () { @@ -128,9 +144,9 @@ impl SonicbotData { if line != String::new() { if self.onandroid { self.tx.send(format!("[IN] {}", line)).unwrap(); - println!("[IN] {}", line); + println!("[IN {}] {}", self.hostlabel, line); } else { - println!("[IN] {}", line); + println!("[IN {}] {}", self.hostlabel, line); } let ircmsg = parser::parse(line.to_string(), self.nick.clone(), self.comprefix.clone()); exitwith = self.takeaction(ircmsg, initialchannels.as_ref()); @@ -179,22 +195,80 @@ impl SonicbotData { self.sendnotice(recipient, message); } } - fn haspermission(&mut self, ircmsg: &IRCMessage, permlevel: u8) -> bool { - if permlevel == 5 { + fn haspermission(&mut self, ircmsg: &IRCMessage, permlevel: u8) -> Result { + if ircmsg.sender.as_ref().unwrap() == self.ownernick.as_str() && ircmsg.hostname.as_ref().unwrap() == self.ownerhost.as_str() { + return Ok(true); + } else if permlevel == 5 { if ircmsg.sender.as_ref().unwrap() == self.ownernick.as_str() && ircmsg.hostname.as_ref().unwrap() == self.ownerhost.as_str() { - return true; + return Ok(true); } else { //println!("'{}' != '{}' and '{}' != '{}'", ircmsg.sender.as_ref().unwrap(), self.ownernick.as_str(), ircmsg.hostname.as_ref().unwrap(), self.ownerhost.as_str()); - return false; + return Err(PermissionErrorReason::NotOwner(false)); + } + } else if permlevel == 4 { + return Err(PermissionErrorReason::NotAdmin(false)); + } else if permlevel == 3 { + return Err(PermissionErrorReason::NotChannelOwner(ircmsg.channel.as_ref().unwrap().to_string())) + } else if permlevel == 2 { + if self.db.get("users").contains(ircmsg.sender.as_ref().unwrap()) { + let mut thisuser = self.db.get("users").get(ircmsg.sender.as_ref().unwrap()); + let hostvec: Vec = thisuser.getvalue("hostnames").as_array().unwrap().to_vec().iter().filter_map(|x| Some(x.as_str().unwrap().to_string())).collect(); + if hostvec.contains(ircmsg.hostname.as_ref().unwrap()) { + return Ok(true); + } else { + return Err(PermissionErrorReason::HostMismatch(false)); + } + } else { + return Err(PermissionErrorReason::NotRegistered(false)); } + } else if permlevel == 1 { + return Ok(true); } else { - return true; + return Err(PermissionErrorReason::LevelTooLow(permlevel)); + } + } + fn handle_haspermission(&mut self, ircmsg: &IRCMessage, permlevel: u8) -> bool { + match self.haspermission(ircmsg, permlevel) { + Ok(x) => return x, + Err(PermissionErrorReason::HostMismatch(_x)) => { + self.sendmsg(ircmsg.channel.as_ref().unwrap().to_string(), "Your hostname does not match any of the registered hostnames for your nick. If it is really you, try using the addhost command.".to_string()); + return false; + }, + Err(PermissionErrorReason::NotOwner(_x)) => { + self.sendmsg(ircmsg.channel.as_ref().unwrap().to_string(), "You are not the owner of this bot.".to_string()); + return false; + }, + Err(PermissionErrorReason::NotAdmin(_x)) => { + self.sendmsg(ircmsg.channel.as_ref().unwrap().to_string(), "You are not an admin of this bot.".to_string()); + return false; + }, + Err(PermissionErrorReason::NotChannelOwner(_x)) => { + self.sendmsg(ircmsg.channel.as_ref().unwrap().to_string(), "You are not registered with this bot as owner of this channel.".to_string()); + return false; + }, + Err(PermissionErrorReason::NotRegistered(_x)) => { + self.sendmsg(ircmsg.channel.as_ref().unwrap().to_string(), "This command requires you to be registered with this bot. Use the nickreg command to register your nick.".to_string()); + return false; + }, + Err(PermissionErrorReason::LevelTooLow(x)) => { + self.sendmsg(ircmsg.channel.as_ref().unwrap().to_string(), format!("Your user level is too low. This command requires a minimum user level of {}.", x)); + return false; + }, + } + } + fn handle_haspermission_noreason(&mut self, ircmsg: &IRCMessage, permlevel: u8) -> bool { + match self.haspermission(ircmsg, permlevel) { + Ok(_x) => return true, + Err(_) => { + //self.sendmsg(ircmsg.sender.as_ref().unwrap().to_string(), "Your hostname does not match any of the registered hostnames for your nick. If it is really you, try using the addhost command.".to_string()); + return false; + }, } } fn commandok(&mut self, command: &str, permlevel: u8, ircmsg: &IRCMessage, minargs: u8) -> Result { let modlist = plugins::ModList::new(); if modlist.modnames.clone().contains(&command.to_string()) { - if ircmsg.command.as_ref().unwrap() == command && self.haspermission(ircmsg, permlevel) { + if ircmsg.command.as_ref().unwrap() == command && self.handle_haspermission(ircmsg, permlevel) { if minargs == 0 { Ok(true) } else if ircmsg.commandargs.is_some() { @@ -218,27 +292,27 @@ impl SonicbotData { fn handle_commandok(&mut self, command: &str, permlevel: u8, ircmsg: &IRCMessage, minargs: u8) -> bool { match self.commandok(command, permlevel, ircmsg, minargs) { Ok(x) => return x, - Err(CommandErrorReason::NoSuchCommand(x)) => { + Err(CommandErrorReason::NoSuchCommand(_x)) => { self.sendmsg(ircmsg.channel.as_ref().unwrap().to_string(), format!("No such command: {}.", command)); return false; }, - Err(CommandErrorReason::PermissionError(x)) => { - self.sendmsg(ircmsg.channel.as_ref().unwrap().to_string(), format!("{}: You do not have the required permissions to run this command.", ircmsg.sender.as_ref().unwrap())); + Err(CommandErrorReason::PermissionError(_x)) => { + //self.sendmsg(ircmsg.channel.as_ref().unwrap().to_string(), format!("{}: You do not have the required permissions to run this command.", ircmsg.sender.as_ref().unwrap())); return false; }, Err(CommandErrorReason::MinArgsError(x)) => { if minargs > 1 { - self.sendmsg(ircmsg.channel.as_ref().unwrap().to_string(), format!("{}: Minimum number of arguments not met. The {} command requires at least {} arguments.", ircmsg.sender.as_ref().unwrap(), command, minargs)); + self.sendmsg(ircmsg.channel.as_ref().unwrap().to_string(), format!("{}: Minimum number of arguments not met. The {} command requires at least {} arguments.", ircmsg.sender.as_ref().unwrap(), command, x)); } else { - self.sendmsg(ircmsg.channel.as_ref().unwrap().to_string(), format!("{}: Minimum number of arguments not met. The {} command requires at least {} argument.", ircmsg.sender.as_ref().unwrap(), command, minargs)); + self.sendmsg(ircmsg.channel.as_ref().unwrap().to_string(), format!("{}: Minimum number of arguments not met. The {} command requires at least {} argument.", ircmsg.sender.as_ref().unwrap(), command, x)); } return false; }, - Err(CommandErrorReason::NoCommandMatch(x)) => return false, + Err(CommandErrorReason::NoCommandMatch(_x)) => return false, }; } fn handle_commandok_notthere(&mut self, command: &str, permlevel: u8, ircmsg: &IRCMessage, minargs: u8) -> bool { - if ircmsg.command.as_ref().unwrap() == command && self.haspermission(ircmsg, permlevel) { + if ircmsg.command.as_ref().unwrap() == command && self.handle_haspermission_noreason(ircmsg, permlevel) { if minargs == 0 { true } else if ircmsg.commandargs.is_some() { @@ -254,24 +328,25 @@ impl SonicbotData { false } } - fn handle_commandok_noreason(&mut self, command: &str, permlevel: u8, ircmsg: &IRCMessage, minargs: u8) -> bool { - match self.commandok(command, permlevel, ircmsg, minargs) { - Ok(x) => return x, - Err(CommandErrorReason::MinArgsError(x)) => return false, - Err(CommandErrorReason::PermissionError(x)) => return false, - Err(CommandErrorReason::NoSuchCommand(x)) => return false, - Err(CommandErrorReason::NoCommandMatch(x)) => return false, - } - } + //fn handle_commandok_noreason(&mut self, command: &str, permlevel: u8, ircmsg: &IRCMessage, minargs: u8) -> bool { + // match self.commandok(command, permlevel, ircmsg, minargs) { + // Ok(x) => return x, + // Err(CommandErrorReason::MinArgsError(_x)) => return false, + // Err(CommandErrorReason::PermissionError(_x)) => return false, + // Err(CommandErrorReason::NoSuchCommand(_x)) => return false, + // Err(CommandErrorReason::NoCommandMatch(_x)) => return false, + // } + //} fn runplugin(&mut self, commands: Vec) -> () { for msg in commands { match msg { msgfmts::Message::SendMsg(recipient, message) => self.sendmsg(recipient, message), - msgfmts::Message::SaveData(pluginname, data) => { + msgfmts::Message::SavePluginData(pluginname, data) => { let mut newinsert = self.db.get("plugins"); newinsert.insert(pluginname.as_str(), data.value); self.db.insert("plugins", newinsert.value); }, + msgfmts::Message::SaveUserData(data) => self.db.insert("users", data.value), msgfmts::Message::SendRawData(rawdata) => self.rawsend(rawdata), msgfmts::Message::JoinChannel(channelname) => self.joinchannel(channelname), msgfmts::Message::PartChannel(channelname, reason) => self.partchannel(channelname, reason), @@ -313,10 +388,10 @@ impl SonicbotData { self.sendpm(ircmsg.sender.as_ref().unwrap().to_string(), format!("\x01VERSION {}\x01.", self.wholeversion)); } } else if ircmsg.command.is_some() { - let mut modlist = plugins::ModList::new(); + let modlist = plugins::ModList::new(); if modlist.modnames.clone().contains(ircmsg.command.as_ref().unwrap()) { if self.handle_commandok(ircmsg.command.as_ref().unwrap(), modlist.permissions[ircmsg.command.as_ref().unwrap()], ircmsg, modlist.minargs[ircmsg.command.as_ref().unwrap()]) { - self.runplugin(modlist.mainfunctions[ircmsg.command.as_ref().unwrap()](ircmsg.clone(), &mut self.db.get("plugins").get(ircmsg.command.as_ref().unwrap().as_str()), self.db.get("essentials"))); + self.runplugin(modlist.mainfunctions[ircmsg.command.as_ref().unwrap()](ircmsg.clone(), &mut self.db.get("plugins").get(ircmsg.command.as_ref().unwrap().as_str()), self.db.get("essentials"), &mut self.db.get("users"))); } } if self.handle_commandok_notthere("quit", 5, ircmsg, 0) { diff --git a/src/main.rs b/src/main.rs index 3e4f20f..dd7c24a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,6 @@ use sonicbot::SonicbotData; -use std::path::{Path, PathBuf}; +use std::path::{Path}; use std::io::Write; use serde::{Deserialize, Serialize}; use std::fs; @@ -91,7 +91,7 @@ async fn main() { #[cfg(not(target_os = "android"))] fn main() { - let (tx, rx) = channel::(); + let (tx, _rx) = channel::(); const VERSION: Option<&'static str> = option_env!("CARGO_PKG_VERSION"); let defaultdata = include_str!("../conf.json.dist").to_string(); let onandroid = false; @@ -119,8 +119,8 @@ fn main() { let wholeversion: String = format!("sonicbot_rust_v{}", VERSION.unwrap()); let data = fs::read_to_string(confpath.to_str().unwrap()).unwrap(); let p: SonicbotConfig = serde_json::from_str(data.as_str()).unwrap(); - let password = p.password.as_str().to_string(); - let channels = p.channels.to_vec(); + //let password = p.password.as_str().to_string(); + //let channels = p.channels.to_vec(); //onandroid = true; let mut sbot = SonicbotData::new(p.host, p.port, p.nick, p.ssl, p.ident, p.realname, p.ownernick, p.ownerhost, p.trigger, p.hostlabel, wholeversion, datadirbuf, onandroid, tx.clone()); //let mut sonicb = sbot.as_mut(); diff --git a/src/msgfmts.rs b/src/msgfmts.rs index e45abae..6adb1ed 100644 --- a/src/msgfmts.rs +++ b/src/msgfmts.rs @@ -1,7 +1,8 @@ use crate::SonicObject; pub enum Message { SendMsg(String, String), - SaveData(String, SonicObject), + SavePluginData(String, SonicObject), + SaveUserData(SonicObject), PartChannel(String, Option), JoinChannel(String), SendRawData(String), diff --git a/src/plugins/addhost.rs b/src/plugins/addhost.rs new file mode 100644 index 0000000..271eea4 --- /dev/null +++ b/src/plugins/addhost.rs @@ -0,0 +1,44 @@ +use crate::msgfmts; +use crate::parser::IRCMessage; +use crate::SonicObject; +//use rand::seq::SliceRandom; +use sha2::{Sha512, Digest}; +//use serde_json::json; +//use acid_store::repo::value::ValueRepo; +pub fn permissionlevel() -> u8 { + 2 +} +pub fn minargs() -> u8 { + 1 +} +pub fn syntax() -> String { + "addhost ".to_string() +} +pub fn help() -> String { + "Adds your current hostname to your account.".to_string() +} +pub fn main(ircmsg: IRCMessage, _db: &mut SonicObject, _essentials: SonicObject, userdata: &mut SonicObject) -> Vec { + let mut returnmsgs: Vec = Vec::new(); + if userdata.contains(ircmsg.sender.as_ref().unwrap()) { + let saltstring = userdata.get(ircmsg.sender.as_ref().unwrap()).getvalue("salt"); + let mut unhashed = ircmsg.commandargs.as_ref().unwrap()[0].to_string(); + unhashed.push_str(saltstring.as_str().unwrap()); + let mut hasher = Sha512::new(); + hasher.update(unhashed.as_bytes()); + let result = hasher.finalize(); + let hexresult = hex::encode(result); + if hexresult == userdata.get(ircmsg.sender.as_ref().unwrap()).getvalue("hash").as_str().unwrap() { + let mut thisuser = userdata.get(ircmsg.sender.as_ref().unwrap()); + let mut hostnames = thisuser.get("hostnames"); + hostnames.push(ircmsg.hostname.as_ref().unwrap().to_string()); + thisuser.insert("hostnames", hostnames.value); + returnmsgs.push(msgfmts::Message::SaveUserData(userdata.clone())); + returnmsgs.push(msgfmts::Message::SendMsg(ircmsg.sender.as_ref().unwrap().to_string(), format!("Successfully added your hostname."))); + } else { + returnmsgs.push(msgfmts::Message::SendMsg(ircmsg.sender.as_ref().unwrap().to_string(), format!("Incorrect password."))); + } + } else { + returnmsgs.push(msgfmts::Message::SendMsg(ircmsg.sender.as_ref().unwrap().to_string(), format!("This nick has not been registered."))); + } + returnmsgs +} \ No newline at end of file diff --git a/src/plugins/choose.rs b/src/plugins/choose.rs index 0cc4d46..56067ae 100644 --- a/src/plugins/choose.rs +++ b/src/plugins/choose.rs @@ -15,7 +15,7 @@ pub fn syntax() -> String { pub fn help() -> String { "Chooses a random choice from .".to_string() } -pub fn main(ircmsg: IRCMessage, db: &mut SonicObject, essentials: SonicObject) -> Vec { +pub fn main(ircmsg: IRCMessage, _db: &mut SonicObject, _essentials: SonicObject, _userdata: &mut SonicObject) -> Vec { let mut returnmsgs: Vec = Vec::new(); let choices = ircmsg.argstring.as_ref().unwrap().split(" or ").collect::>(); let choice = choices.choose(&mut rand::thread_rng()).unwrap().to_string(); diff --git a/src/plugins/greet.rs b/src/plugins/greet.rs index 667f1a2..3b8019c 100644 --- a/src/plugins/greet.rs +++ b/src/plugins/greet.rs @@ -13,10 +13,8 @@ pub fn syntax() -> String { pub fn help() -> String { "Greets you.".to_string() } -pub fn main(ircmsg: IRCMessage, db: &mut SonicObject, essentials: SonicObject) -> Vec { +pub fn main(ircmsg: IRCMessage, _db: &mut SonicObject, _essentials: SonicObject, _userdata: &mut SonicObject) -> Vec { let mut returnmsgs: Vec = Vec::new(); - //let channel = &ircmsg.commandargs.as_ref().unwrap()[0]; - //let choice = choices.choose(&mut rand::thread_rng()).unwrap().to_string(); returnmsgs.push(msgfmts::Message::SendMsg(ircmsg.channel.as_ref().unwrap().to_string(), format!("Hello {}.", ircmsg.sender.as_ref().unwrap()))); returnmsgs } diff --git a/src/plugins/join.rs b/src/plugins/join.rs index 206443c..19b5477 100644 --- a/src/plugins/join.rs +++ b/src/plugins/join.rs @@ -13,7 +13,7 @@ pub fn syntax() -> String { pub fn help() -> String { "Joins .".to_string() } -pub fn main(ircmsg: IRCMessage, db: &mut SonicObject, essentials: SonicObject) -> Vec { +pub fn main(ircmsg: IRCMessage, _db: &mut SonicObject, _essentials: SonicObject, _userdata: &mut SonicObject) -> Vec { let mut returnmsgs: Vec = Vec::new(); let channel = &ircmsg.commandargs.as_ref().unwrap()[0]; //let choice = choices.choose(&mut rand::thread_rng()).unwrap().to_string(); diff --git a/src/plugins/nickreg.rs b/src/plugins/nickreg.rs new file mode 100644 index 0000000..2391290 --- /dev/null +++ b/src/plugins/nickreg.rs @@ -0,0 +1,47 @@ +use crate::msgfmts; +use crate::parser::IRCMessage; +use crate::SonicObject; +use rand::seq::SliceRandom; +use sha2::{Sha512, Digest}; +use serde_json::json; +//use acid_store::repo::value::ValueRepo; +pub fn permissionlevel() -> u8 { + 1 +} +pub fn minargs() -> u8 { + 1 +} +pub fn syntax() -> String { + "nickreg ".to_string() +} +pub fn help() -> String { + "Registers your nick.".to_string() +} +pub fn main(ircmsg: IRCMessage, _db: &mut SonicObject, _essentials: SonicObject, userdata: &mut SonicObject) -> Vec { + let mut returnmsgs: Vec = Vec::new(); + if !userdata.contains(ircmsg.sender.as_ref().unwrap()) { + let posssalt: Vec = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()_+=-\\|[]:;,./<>?:\"{}".chars().collect(); + let mut rseed = rand::thread_rng(); + let mut saltstring = String::new(); + for _x in 1..6 { + saltstring.push(*posssalt.choose(&mut rseed).unwrap()) + } + let mut unhashed = ircmsg.commandargs.as_ref().unwrap()[0].to_string(); + unhashed.push_str(saltstring.as_str()); + let mut hasher = Sha512::new(); + hasher.update(unhashed.as_bytes()); + let result = hasher.finalize(); + let hexresult = hex::encode(result); + let mut thisuser = SonicObject::new(sonicobject::getemptyvalue()); + thisuser.insert("salt", saltstring); + thisuser.insert("hash", hexresult); + thisuser.insert("hostnames", json!([ircmsg.hostname.as_ref().unwrap()])); + thisuser.insert("userlevel", 2); + userdata.insert(ircmsg.sender.as_ref().unwrap(), thisuser.value); + returnmsgs.push(msgfmts::Message::SaveUserData(userdata.clone())); + returnmsgs.push(msgfmts::Message::SendMsg(ircmsg.sender.as_ref().unwrap().to_string(), format!("Successfully registered {}.", ircmsg.sender.as_ref().unwrap().to_string()))); + } else { + returnmsgs.push(msgfmts::Message::SendMsg(ircmsg.sender.as_ref().unwrap().to_string(), format!("This username has already been taken."))); + } + returnmsgs +} \ No newline at end of file diff --git a/src/plugins/part.rs b/src/plugins/part.rs index d95e24c..d965eac 100644 --- a/src/plugins/part.rs +++ b/src/plugins/part.rs @@ -14,7 +14,7 @@ pub fn syntax() -> String { pub fn help() -> String { "Parts from with [reason] as a reason if it is given.".to_string() } -pub fn main(ircmsg: IRCMessage, db: &mut SonicObject, essentials: SonicObject) -> Vec { +pub fn main(ircmsg: IRCMessage, _db: &mut SonicObject, _essentials: SonicObject, _userdata: &mut SonicObject) -> Vec { let mut returnmsgs: Vec = Vec::new(); let reason: Option; if ircmsg.commandargs.as_ref().unwrap().len() > 1 { diff --git a/src/plugins/pm.rs b/src/plugins/pm.rs index 7b92149..631a93d 100644 --- a/src/plugins/pm.rs +++ b/src/plugins/pm.rs @@ -13,7 +13,7 @@ pub fn syntax() -> String { pub fn help() -> String { "Sends a pm to with a ".to_string() } -pub fn main(ircmsg: IRCMessage, db: &mut SonicObject, essentials: SonicObject) -> Vec { +pub fn main(ircmsg: IRCMessage, _db: &mut SonicObject, _essentials: SonicObject, _userdata: &mut SonicObject) -> Vec { let mut returnmsgs: Vec = Vec::new(); returnmsgs.push(msgfmts::Message::SendPM(ircmsg.commandargs.as_ref().unwrap()[0].to_string(), format!("{}", ircmsg.commandargs.as_ref().unwrap()[1..].join(" ").to_string()))); returnmsgs diff --git a/src/plugins/randfact.rs b/src/plugins/randfact.rs index b1f859f..b2a455e 100644 --- a/src/plugins/randfact.rs +++ b/src/plugins/randfact.rs @@ -14,7 +14,7 @@ pub fn syntax() -> String { pub fn help() -> String { "Returns a random fact.".to_string() } -pub fn main(ircmsg: IRCMessage, db: &mut SonicObject, essentials: SonicObject) -> Vec { +pub fn main(ircmsg: IRCMessage, _db: &mut SonicObject, _essentials: SonicObject, _userdata: &mut SonicObject) -> Vec { let data = reqwest::blocking::get("http://randomfunfacts.com/").unwrap().text().unwrap(); let matcher = Regex::new(r#"(.*)"#).unwrap(); let mut returnmsgs: Vec = Vec::new(); diff --git a/src/plugins/seen.rs b/src/plugins/seen.rs index 5e69c07..147c0f2 100644 --- a/src/plugins/seen.rs +++ b/src/plugins/seen.rs @@ -19,7 +19,7 @@ pub fn syntax() -> String { pub fn help() -> String { "Returns time since was seen.".to_string() } -pub fn main(ircmsg: IRCMessage, db: &mut SonicObject, essentials: SonicObject) -> Vec { +pub fn main(ircmsg: IRCMessage, _db: &mut SonicObject, essentials: SonicObject, _userdata: &mut SonicObject) -> Vec { let mut returnmsgs: Vec = Vec::new(); if essentials.get("PRIVMSG").get("seen").contains(ircmsg.commandargs.as_ref().unwrap()[0].as_str()) { let dur = essentials.get("PRIVMSG").get("seen").getvalue(ircmsg.commandargs.as_ref().unwrap()[0].as_str()); diff --git a/src/plugins/violence.rs b/src/plugins/violence.rs new file mode 100644 index 0000000..075eb59 --- /dev/null +++ b/src/plugins/violence.rs @@ -0,0 +1,28 @@ +use rand::seq::SliceRandom; +use crate::msgfmts; +use crate::parser::IRCMessage; +use crate::SonicObject; +pub fn permissionlevel() -> u8 { + 1 +} +pub fn minargs() -> u8 { + 1 +} +pub fn syntax() -> String { + "violence ".to_string() +} +pub fn help() -> String { + "Generates a random attack".to_string() +} +pub fn main(ircmsg: IRCMessage, _db: &mut SonicObject, _essentials: SonicObject, _userdata: &mut SonicObject) -> Vec { + let mut rseed = rand::thread_rng(); + let verbs = vec!["slaps", "kicks", "barfs on", "punches", "force feeds", "squishes", "stomps on", "bodyslams", "shoots", "smacks", "compresses", "crunches"]; + let adjectives = vec!["sweet", "dirty", "corny", "ugly", "magical", "smelly", "gross old", "old", "tasty", "messy", "blue", "red", "yellow", "pink", "purple", "green", "classic", "stinky"]; + let nouns = vec!["man", "woman", "admin", "IRCop", "car", "fish", "bomb", "missile", "computer", "keyboard", "football", "set of speakers", "monopoly set"]; + let noun = nouns.choose(&mut rseed).unwrap().to_string(); + let adjective = adjectives.choose(&mut rseed).unwrap().to_string(); + let verb = verbs.choose(&mut rseed).unwrap().to_string(); + let mut returnmsgs: Vec = Vec::new(); + returnmsgs.push(msgfmts::Message::SendMsg(ircmsg.channel.as_ref().unwrap().to_string(), format!("\x01ACTION {} {} with a {} {}.\x01", verb, ircmsg.commandargs.as_ref().unwrap()[0], adjective, noun))); + returnmsgs +} diff --git a/src/socketwrapper.rs b/src/socketwrapper.rs index 7478e3a..4993c7f 100644 --- a/src/socketwrapper.rs +++ b/src/socketwrapper.rs @@ -33,7 +33,7 @@ impl SocketWrapper { pub fn connect(&mut self) -> () { println!("{}:{}", self.host, self.port.to_string()); let socket = TcpStream::connect(format!("{}:{}", self.host, self.port.to_string())).unwrap(); - socket.set_read_timeout(Some(std::time::Duration::new(1, 0))).unwrap(); + socket.set_read_timeout(Some(std::time::Duration::from_millis(500))).unwrap(); //socket.set_nodelay(true).unwrap(); println!("Connected"); if self.ssl {