Browse Source

Initial commit

master
kageru 2 years ago
commit
c5b440311c
  1. 3
      .gitignore
  2. 12
      Cargo.toml
  3. 21
      README.md
  4. 4
      config.toml
  5. 41
      src/commands.rs
  6. 9
      src/file.rs
  7. 48
      src/main.rs

3
.gitignore vendored

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

12
Cargo.toml

@ -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

@ -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

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

41
src/commands.rs

@ -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

@ -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

@ -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);
}
}
Loading…
Cancel
Save