Initial commit
This commit is contained in:
commit
c5b440311c
|
@ -0,0 +1,3 @@
|
||||||
|
/target
|
||||||
|
**/*.rs.bk
|
||||||
|
secret
|
|
@ -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"
|
|
@ -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.
|
|
@ -0,0 +1,4 @@
|
||||||
|
[[command]]
|
||||||
|
trigger = ">restart_example"
|
||||||
|
command = "/usr/bin/restart_something"
|
||||||
|
users = [12345, 54321]
|
|
@ -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!()
|
||||||
|
}
|
||||||
|
}
|
|
@ -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")))
|
||||||
|
}
|
|
@ -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…
Reference in New Issue
Block a user