feat: add support for NoChatReports encryption
This commit is contained in:
@@ -4,6 +4,8 @@ use crate::{
|
||||
};
|
||||
use azalea::{brigadier::prelude::*, chat::ChatPacket, prelude::*};
|
||||
use futures::lock::Mutex;
|
||||
use mlua::{Function, Table};
|
||||
use ncr::utils::prepend_header;
|
||||
|
||||
pub type Ctx = CommandContext<Mutex<CommandSource>>;
|
||||
|
||||
@@ -11,16 +13,24 @@ pub struct CommandSource {
|
||||
pub client: Client,
|
||||
pub message: ChatPacket,
|
||||
pub state: State,
|
||||
pub ncr_options: Option<Table>,
|
||||
}
|
||||
|
||||
impl CommandSource {
|
||||
pub fn reply(&self, message: &str) {
|
||||
for chunk in message
|
||||
for mut chunk in message
|
||||
.chars()
|
||||
.collect::<Vec<char>>()
|
||||
.chunks(236)
|
||||
.chunks(if self.ncr_options.is_some() { 150 } else { 236 })
|
||||
.map(|chars| chars.iter().collect::<String>())
|
||||
{
|
||||
if let (Some(options), Ok(encrypt)) = (
|
||||
&self.ncr_options,
|
||||
self.state.lua.globals().get::<Function>("ncr_encrypt"),
|
||||
) && let Ok(encrypted) = encrypt.call::<String>((options, prepend_header(&chunk)))
|
||||
{
|
||||
chunk = encrypted
|
||||
}
|
||||
self.client.chat(
|
||||
&(if self.message.is_whisper()
|
||||
&& let Some(username) = self.message.username()
|
||||
|
@@ -9,7 +9,8 @@ use azalea::{prelude::*, protocol::packets::game::ClientboundGamePacket};
|
||||
use hyper::{server::conn::http1, service::service_fn};
|
||||
use hyper_util::rt::TokioIo;
|
||||
use log::{debug, error, info, trace};
|
||||
use mlua::IntoLuaMulti;
|
||||
use mlua::{Function, IntoLuaMulti, Table};
|
||||
use ncr::utils::trim_header;
|
||||
use std::process::exit;
|
||||
use tokio::net::TcpListener;
|
||||
|
||||
@@ -20,32 +21,44 @@ pub async fn handle_event(client: Client, event: Event, state: State) -> anyhow:
|
||||
call_listeners(&state, "add_player", Player::from(player_info)).await;
|
||||
}
|
||||
Event::Chat(message) => {
|
||||
let globals = state.lua.globals();
|
||||
let (sender, mut content) = message.split_sender_and_content();
|
||||
let formatted_message = message.message();
|
||||
info!("{}", formatted_message.to_ansi());
|
||||
|
||||
if message.is_whisper()
|
||||
&& let (Some(sender), content) = message.split_sender_and_content()
|
||||
&& state
|
||||
.lua
|
||||
.globals()
|
||||
.get::<Vec<String>>("Owners")?
|
||||
.contains(&sender)
|
||||
{
|
||||
if let Err(error) = state.commands.execute(
|
||||
content,
|
||||
CommandSource {
|
||||
client: client.clone(),
|
||||
message: message.clone(),
|
||||
state: state.clone(),
|
||||
if let Some(sender) = sender {
|
||||
let mut ncr_options = None;
|
||||
if let (Ok(options), Ok(decrypt)) = (
|
||||
globals.get::<Table>("NcrOptions"),
|
||||
globals.get::<Function>("ncr_decrypt"),
|
||||
) && let Ok(decrypted) =
|
||||
decrypt.call::<String>((options.clone(), content.clone()))
|
||||
&& let Ok(trimmed) = trim_header(&decrypted)
|
||||
{
|
||||
ncr_options = Some(options);
|
||||
content = trimmed.to_owned();
|
||||
info!("Decrypted message from {sender}: {content}");
|
||||
}
|
||||
|
||||
if message.is_whisper() && globals.get::<Vec<String>>("Owners")?.contains(&sender) {
|
||||
if let Err(error) = state.commands.execute(
|
||||
content,
|
||||
CommandSource {
|
||||
client: client.clone(),
|
||||
message: message.clone(),
|
||||
state: state.clone(),
|
||||
ncr_options: ncr_options.clone(),
|
||||
}
|
||||
.into(),
|
||||
) {
|
||||
CommandSource {
|
||||
client,
|
||||
message,
|
||||
state: state.clone(),
|
||||
ncr_options,
|
||||
}
|
||||
.reply(&format!("{error:?}"));
|
||||
}
|
||||
.into(),
|
||||
) {
|
||||
CommandSource {
|
||||
client,
|
||||
message,
|
||||
state: state.clone(),
|
||||
}
|
||||
.reply(&format!("{error:?}"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -4,6 +4,7 @@ pub mod container;
|
||||
pub mod direction;
|
||||
pub mod events;
|
||||
pub mod logging;
|
||||
pub mod nochatreports;
|
||||
pub mod player;
|
||||
pub mod system;
|
||||
pub mod vec3;
|
||||
@@ -39,6 +40,7 @@ pub fn register_functions(
|
||||
block::register_functions(lua, globals)?;
|
||||
events::register_functions(lua, globals, event_listeners)?;
|
||||
logging::register_functions(lua, globals)?;
|
||||
nochatreports::register_functions(lua, globals)?;
|
||||
system::register_functions(lua, globals)
|
||||
}
|
||||
|
||||
|
41
src/lua/nochatreports/crypt.rs
Normal file
41
src/lua/nochatreports/crypt.rs
Normal file
@@ -0,0 +1,41 @@
|
||||
macro_rules! crypt_with {
|
||||
($op:ident, $encoding:expr, $key:expr, $text:expr, $algo:ident) => {
|
||||
match $encoding {
|
||||
1 => $algo::<Base64Encoding>::$op($text, $key),
|
||||
2 => $algo::<Base64rEncoding>::$op($text, $key),
|
||||
_ => $algo::<NewBase64rEncoding>::$op($text, $key),
|
||||
}
|
||||
.map_err(|error| Error::external(error.to_string()))?
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! crypt {
|
||||
($op:ident, $encoding:expr, $options:expr, $text:expr) => {
|
||||
match $options.get("encryption").unwrap_or_default() {
|
||||
1 => CaesarEncryption::$op(&$text, &$options.get("key")?)
|
||||
.map_err(|error| Error::external(error.to_string()))?,
|
||||
2 => crypt_with!(
|
||||
$op,
|
||||
$encoding,
|
||||
&$options.get::<UserDataRef<AesKey>>("key")?.inner,
|
||||
&$text,
|
||||
EcbEncryption
|
||||
),
|
||||
3 => crypt_with!(
|
||||
$op,
|
||||
$encoding,
|
||||
&$options.get::<UserDataRef<AesKey>>("key")?.inner,
|
||||
&$text,
|
||||
GcmEncryption
|
||||
),
|
||||
_ => crypt_with!(
|
||||
$op,
|
||||
$encoding,
|
||||
&$options.get::<UserDataRef<AesKey>>("key")?.inner,
|
||||
&$text,
|
||||
Cfb8Encryption
|
||||
),
|
||||
}
|
||||
};
|
||||
}
|
12
src/lua/nochatreports/key.rs
Normal file
12
src/lua/nochatreports/key.rs
Normal file
@@ -0,0 +1,12 @@
|
||||
use mlua::UserData;
|
||||
|
||||
pub struct AesKey {
|
||||
pub inner: ncr::AesKey,
|
||||
}
|
||||
|
||||
impl UserData for AesKey {
|
||||
fn add_fields<F: mlua::UserDataFields<Self>>(f: &mut F) {
|
||||
f.add_field_method_get("base64", |_, this| Ok(this.inner.encode_base64()));
|
||||
f.add_field_method_get("bytes", |_, this| Ok(this.inner.as_ref().to_vec()));
|
||||
}
|
||||
}
|
81
src/lua/nochatreports/mod.rs
Normal file
81
src/lua/nochatreports/mod.rs
Normal file
@@ -0,0 +1,81 @@
|
||||
#[macro_use]
|
||||
pub mod crypt;
|
||||
pub mod key;
|
||||
|
||||
use key::AesKey;
|
||||
use mlua::{Error, Lua, Result, Table, UserDataRef};
|
||||
use ncr::{
|
||||
encoding::{Base64Encoding, Base64rEncoding, NewBase64rEncoding},
|
||||
encryption::{CaesarEncryption, Cfb8Encryption, EcbEncryption, Encryption, GcmEncryption},
|
||||
utils::{prepend_header, trim_header},
|
||||
};
|
||||
|
||||
pub fn register_functions(lua: &Lua, globals: &Table) -> Result<()> {
|
||||
globals.set(
|
||||
"ncr_aes_key_from_passphrase",
|
||||
lua.create_function(|_, passphrase: Vec<u8>| {
|
||||
Ok(AesKey {
|
||||
inner: ncr::AesKey::gen_from_passphrase(&passphrase),
|
||||
})
|
||||
})?,
|
||||
)?;
|
||||
|
||||
globals.set(
|
||||
"ncr_aes_key_from_base64",
|
||||
lua.create_function(|_, base64: String| {
|
||||
Ok(AesKey {
|
||||
inner: ncr::AesKey::decode_base64(&base64)
|
||||
.map_err(|error| Error::external(error.to_string()))?,
|
||||
})
|
||||
})?,
|
||||
)?;
|
||||
|
||||
globals.set(
|
||||
"ncr_generate_random_aes_key",
|
||||
lua.create_function(|_, (): ()| {
|
||||
Ok(AesKey {
|
||||
inner: ncr::AesKey::gen_random_key(),
|
||||
})
|
||||
})?,
|
||||
)?;
|
||||
|
||||
globals.set(
|
||||
"ncr_encrypt",
|
||||
lua.create_function(|_, (options, plaintext): (Table, String)| {
|
||||
Ok(crypt!(
|
||||
encrypt,
|
||||
options.get("encoding").unwrap_or_default(),
|
||||
options,
|
||||
plaintext
|
||||
))
|
||||
})?,
|
||||
)?;
|
||||
|
||||
globals.set(
|
||||
"ncr_decrypt",
|
||||
lua.create_function(|_, (options, ciphertext): (Table, String)| {
|
||||
Ok(crypt!(
|
||||
decrypt,
|
||||
options.get("encoding").unwrap_or_default(),
|
||||
options,
|
||||
ciphertext
|
||||
))
|
||||
})?,
|
||||
)?;
|
||||
|
||||
globals.set(
|
||||
"ncr_prepend_header",
|
||||
lua.create_function(|_, text: String| Ok(prepend_header(&text)))?,
|
||||
)?;
|
||||
|
||||
globals.set(
|
||||
"ncr_trim_header",
|
||||
lua.create_function(|_, text: String| {
|
||||
Ok(trim_header(&text)
|
||||
.map_err(|error| Error::external(error.to_string()))?
|
||||
.to_owned())
|
||||
})?,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
Reference in New Issue
Block a user