Initial commit

This commit is contained in:
kageru 2020-01-02 17:51:02 +01:00
commit c5b440311c
7 changed files with 138 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/target
**/*.rs.bk
secret

12
Cargo.toml Normal file
View File

@ -0,0 +1,12 @@
[package]
name = "rceaadb"
version = "0.1.0"
authors = ["kageru <kageru@encode.moe>"]
edition = "2018"
[dependencies]
serenity = "0.7"
serde = "1.0.104"
toml = "0.5.5"
lazy_static = "1.4.0"
itertools = "0.8.2"

21
README.md Normal file
View File

@ -0,0 +1,21 @@
# RCEAADB
## I’m sorry?
RCEAABD. Remote code execution as a discord bot.
Almost as good as ncmpcpp.
## But why? Do you hate security that much?
Evidently.
## Seriously, why?
I noticed a use for this.
More than once did people ask me (or someone else)
to restart a game server, a long-running script, a discord bot, etc.
because something was broken, and restarting it was the easiest way to ‘fix’ it.
The idea here is to give people you trust a way to selectively run certain commands on a server.
The bot will only ever execute the commands from the config.
The only user input are the triggers in discord messages that are then checked against the config.
No message content is ever executed, neither directly nor indirectly.
Every command is limited to one or multiple users.
See the example config for more information.

4
config.toml Normal file
View File

@ -0,0 +1,4 @@
[[command]]
trigger = ">restart_example"
command = "/usr/bin/restart_something"
users = [12345, 54321]

41
src/commands.rs Normal file
View File

@ -0,0 +1,41 @@
use itertools::Itertools;
use lazy_static;
use serde::Deserialize;
use serenity::model::channel::Message;
#[derive(Deserialize, Debug)]
pub struct Command<'a> {
trigger: &'a str,
command: &'a str,
users: Vec<u64>,
}
#[derive(Deserialize, Debug)]
struct Config {
#[serde(rename = "command")]
commands: Vec<Command<'static>>,
}
lazy_static! {
static ref RAW_CONFIG: String = super::file::read_file("config.toml").join("\n");
static ref COMMANDS: Vec<Command<'static>> = {
toml::from_str::<Config>(&RAW_CONFIG).expect("Error in config").commands
};
}
pub fn print_commands() {
COMMANDS.iter().for_each(|c| println!("{:?}", c));
}
pub fn find_matching(message: &str) -> Option<&Command> {
COMMANDS.iter().find(|&c| message.starts_with(&c.trigger))
}
impl<'a> Command<'a> {
pub fn execute(&self, msg: &Message) -> Result<(), &'static str> {
if !self.users.contains(&msg.author.id.0) {
return Err("You don’t have the permissions to execute this command.");
}
unimplemented!()
}
}

9
src/file.rs Normal file
View File

@ -0,0 +1,9 @@
use std::fs::File;
use std::io::{prelude::*, BufReader};
pub fn read_file(path: &'static str) -> impl Iterator<Item = String> {
let reader = BufReader::new(File::open(path).expect("File not found"));
reader
.lines()
.map(|l| l.expect(&format!("Could not read from file")))
}

48
src/main.rs Normal file
View File

@ -0,0 +1,48 @@
#[macro_use]
extern crate lazy_static;
use commands::*;
use serenity::model::channel::Message;
use serenity::model::id::ChannelId;
use serenity::prelude::*;
mod commands;
mod file;
pub fn main() {
/*
Client::new(
file::read_file("secret")
.next()
.expect("The file containing the login secret is present but empty"),
Handler,
)
.expect("Error creating client")
.start()
.expect("Could not connect to discord");
*/
print_commands();
}
const PREFIX: char = '$';
pub struct Handler;
impl EventHandler for Handler {
fn message(&self, ctx: Context, msg: Message) {
if !msg.content.starts_with(PREFIX) {
return;
}
if let Some(command) = find_matching(&msg.content) {
let response = match command.execute(&msg) {
Err(e) => e,
// TODO: maybe check the return code here?
Ok(()) => "Done",
};
send(msg.channel_id, response, &ctx);
}
}
}
pub fn send(target: ChannelId, message: &str, ctx: &Context) {
if let Err(cause) = target.say(&ctx.http, message) {
println!("Could not send message: {}", cause);
}
}