mirror of
https://github.com/MeexReay/bRAC.git
synced 2025-05-06 05:28:02 +03:00
wrac compatibility (no tests)
This commit is contained in:
parent
06c27aac63
commit
73f7c565e1
138
Cargo.lock
generated
138
Cargo.lock
generated
@ -106,6 +106,7 @@ dependencies = [
|
|||||||
"serde_default",
|
"serde_default",
|
||||||
"serde_yml",
|
"serde_yml",
|
||||||
"socks",
|
"socks",
|
||||||
|
"tungstenite",
|
||||||
"winapi",
|
"winapi",
|
||||||
"winresource",
|
"winresource",
|
||||||
]
|
]
|
||||||
@ -122,6 +123,15 @@ version = "2.9.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
|
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "block-buffer"
|
||||||
|
version = "0.10.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.17.0"
|
version = "3.17.0"
|
||||||
@ -134,6 +144,12 @@ version = "1.5.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bytes"
|
||||||
|
version = "1.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cairo-rs"
|
name = "cairo-rs"
|
||||||
version = "0.20.7"
|
version = "0.20.7"
|
||||||
@ -264,6 +280,25 @@ version = "0.8.7"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cpufeatures"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crypto-common"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
"typenum",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "darling"
|
name = "darling"
|
||||||
version = "0.20.11"
|
version = "0.20.11"
|
||||||
@ -299,6 +334,22 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "data-encoding"
|
||||||
|
version = "2.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "digest"
|
||||||
|
version = "0.10.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||||
|
dependencies = [
|
||||||
|
"block-buffer",
|
||||||
|
"crypto-common",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "equivalent"
|
name = "equivalent"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
@ -499,6 +550,16 @@ dependencies = [
|
|||||||
"system-deps",
|
"system-deps",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "generic-array"
|
||||||
|
version = "0.14.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||||
|
dependencies = [
|
||||||
|
"typenum",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
@ -775,6 +836,23 @@ dependencies = [
|
|||||||
"windows",
|
"windows",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "http"
|
||||||
|
version = "1.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"fnv",
|
||||||
|
"itoa",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httparse"
|
||||||
|
version = "1.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iana-time-zone"
|
name = "iana-time-zone"
|
||||||
version = "0.1.63"
|
version = "0.1.63"
|
||||||
@ -1267,6 +1345,17 @@ dependencies = [
|
|||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sha1"
|
||||||
|
version = "0.10.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cpufeatures",
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "shlex"
|
name = "shlex"
|
||||||
version = "1.3.0"
|
version = "1.3.0"
|
||||||
@ -1349,6 +1438,26 @@ dependencies = [
|
|||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror"
|
||||||
|
version = "2.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror-impl",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror-impl"
|
||||||
|
version = "2.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml"
|
name = "toml"
|
||||||
version = "0.8.20"
|
version = "0.8.20"
|
||||||
@ -1383,12 +1492,41 @@ dependencies = [
|
|||||||
"winnow",
|
"winnow",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tungstenite"
|
||||||
|
version = "0.26.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4793cb5e56680ecbb1d843515b23b6de9a75eb04b66643e256a396d43be33c13"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"data-encoding",
|
||||||
|
"http",
|
||||||
|
"httparse",
|
||||||
|
"log",
|
||||||
|
"rand",
|
||||||
|
"sha1",
|
||||||
|
"thiserror",
|
||||||
|
"utf-8",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typenum"
|
||||||
|
version = "1.18.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.16"
|
version = "1.0.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
|
checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utf-8"
|
||||||
|
version = "0.7.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "utf8parse"
|
name = "utf8parse"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
|
@ -19,6 +19,7 @@ socks = "0.3.4"
|
|||||||
libnotify = { version = "1.0.3", optional = true }
|
libnotify = { version = "1.0.3", optional = true }
|
||||||
gdk-pixbuf = { version = "0.3.0", optional = true }
|
gdk-pixbuf = { version = "0.3.0", optional = true }
|
||||||
winapi = { version = "0.3.9", optional = true, features = ["wincon", "winuser"] }
|
winapi = { version = "0.3.9", optional = true, features = ["wincon", "winuser"] }
|
||||||
|
tungstenite = "0.26.2"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
|
@ -26,6 +26,7 @@ pub struct Config {
|
|||||||
#[serde(default = "default_true")] pub chunked_enabled: bool,
|
#[serde(default = "default_true")] pub chunked_enabled: bool,
|
||||||
#[serde(default = "default_true")] pub formatting_enabled: bool,
|
#[serde(default = "default_true")] pub formatting_enabled: bool,
|
||||||
#[serde(default = "default_true")] pub commands_enabled: bool,
|
#[serde(default = "default_true")] pub commands_enabled: bool,
|
||||||
|
#[serde(default)] pub wrac_enabled: bool,
|
||||||
#[serde(default)] pub proxy: Option<String>,
|
#[serde(default)] pub proxy: Option<String>,
|
||||||
#[serde(default = "default_true")] pub notifications_enabled: bool,
|
#[serde(default = "default_true")] pub notifications_enabled: bool,
|
||||||
}
|
}
|
||||||
@ -117,6 +118,7 @@ pub struct Args {
|
|||||||
#[arg(long)] pub formatting_enabled: Option<bool>,
|
#[arg(long)] pub formatting_enabled: Option<bool>,
|
||||||
#[arg(long)] pub commands_enabled: Option<bool>,
|
#[arg(long)] pub commands_enabled: Option<bool>,
|
||||||
#[arg(long)] pub notifications_enabled: Option<bool>,
|
#[arg(long)] pub notifications_enabled: Option<bool>,
|
||||||
|
#[arg(long)] pub wrac_enabled: Option<bool>,
|
||||||
#[arg(long)] pub proxy: Option<String>,
|
#[arg(long)] pub proxy: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,5 +138,6 @@ impl Args {
|
|||||||
if let Some(v) = self.formatting_enabled { config.formatting_enabled = v }
|
if let Some(v) = self.formatting_enabled { config.formatting_enabled = v }
|
||||||
if let Some(v) = self.commands_enabled { config.commands_enabled = v }
|
if let Some(v) = self.commands_enabled { config.commands_enabled = v }
|
||||||
if let Some(v) = self.notifications_enabled { config.notifications_enabled = v }
|
if let Some(v) = self.notifications_enabled { config.notifications_enabled = v }
|
||||||
|
if let Some(v) = self.wrac_enabled { config.wrac_enabled = v }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -77,7 +77,8 @@ macro_rules! connect_rac {
|
|||||||
&mut connect(
|
&mut connect(
|
||||||
&$ctx.config(|o| o.host.clone()),
|
&$ctx.config(|o| o.host.clone()),
|
||||||
$ctx.config(|o| o.ssl_enabled),
|
$ctx.config(|o| o.ssl_enabled),
|
||||||
$ctx.config(|o| o.proxy.clone())
|
$ctx.config(|o| o.proxy.clone()),
|
||||||
|
$ctx.config(|o| o.wrac_enabled)
|
||||||
)?
|
)?
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -165,6 +165,7 @@ fn open_settings(ctx: Arc<Context>, app: &Application) {
|
|||||||
let show_other_ip_entry = gui_checkbox_setting!("Show Other IP", show_other_ip, ctx, vbox);
|
let show_other_ip_entry = gui_checkbox_setting!("Show Other IP", show_other_ip, ctx, vbox);
|
||||||
let auth_enabled_entry = gui_checkbox_setting!("Fake Auth Enabled", auth_enabled, ctx, vbox);
|
let auth_enabled_entry = gui_checkbox_setting!("Fake Auth Enabled", auth_enabled, ctx, vbox);
|
||||||
let ssl_enabled_entry = gui_checkbox_setting!("SSL Enabled", ssl_enabled, ctx, vbox);
|
let ssl_enabled_entry = gui_checkbox_setting!("SSL Enabled", ssl_enabled, ctx, vbox);
|
||||||
|
let wrac_enabled_entry = gui_checkbox_setting!("WRAC Enabled", wrac_enabled, ctx, vbox);
|
||||||
let chunked_enabled_entry = gui_checkbox_setting!("Chunked Enabled", chunked_enabled, ctx, vbox);
|
let chunked_enabled_entry = gui_checkbox_setting!("Chunked Enabled", chunked_enabled, ctx, vbox);
|
||||||
let formatting_enabled_entry = gui_checkbox_setting!("Formatting Enabled", formatting_enabled, ctx, vbox);
|
let formatting_enabled_entry = gui_checkbox_setting!("Formatting Enabled", formatting_enabled, ctx, vbox);
|
||||||
let commands_enabled_entry = gui_checkbox_setting!("Commands Enabled", commands_enabled, ctx, vbox);
|
let commands_enabled_entry = gui_checkbox_setting!("Commands Enabled", commands_enabled, ctx, vbox);
|
||||||
@ -191,6 +192,7 @@ fn open_settings(ctx: Arc<Context>, app: &Application) {
|
|||||||
#[weak] formatting_enabled_entry,
|
#[weak] formatting_enabled_entry,
|
||||||
#[weak] commands_enabled_entry,
|
#[weak] commands_enabled_entry,
|
||||||
#[weak] notifications_enabled_entry,
|
#[weak] notifications_enabled_entry,
|
||||||
|
#[weak] wrac_enabled_entry,
|
||||||
#[weak] proxy_entry,
|
#[weak] proxy_entry,
|
||||||
move |_| {
|
move |_| {
|
||||||
let config = Config {
|
let config = Config {
|
||||||
@ -231,6 +233,7 @@ fn open_settings(ctx: Arc<Context>, app: &Application) {
|
|||||||
show_other_ip: show_other_ip_entry.is_active(),
|
show_other_ip: show_other_ip_entry.is_active(),
|
||||||
auth_enabled: auth_enabled_entry.is_active(),
|
auth_enabled: auth_enabled_entry.is_active(),
|
||||||
ssl_enabled: ssl_enabled_entry.is_active(),
|
ssl_enabled: ssl_enabled_entry.is_active(),
|
||||||
|
wrac_enabled: wrac_enabled_entry.is_active(),
|
||||||
chunked_enabled: chunked_enabled_entry.is_active(),
|
chunked_enabled: chunked_enabled_entry.is_active(),
|
||||||
formatting_enabled: formatting_enabled_entry.is_active(),
|
formatting_enabled: formatting_enabled_entry.is_active(),
|
||||||
commands_enabled: commands_enabled_entry.is_active(),
|
commands_enabled: commands_enabled_entry.is_active(),
|
||||||
@ -267,6 +270,7 @@ fn open_settings(ctx: Arc<Context>, app: &Application) {
|
|||||||
#[weak] show_other_ip_entry,
|
#[weak] show_other_ip_entry,
|
||||||
#[weak] auth_enabled_entry,
|
#[weak] auth_enabled_entry,
|
||||||
#[weak] ssl_enabled_entry,
|
#[weak] ssl_enabled_entry,
|
||||||
|
#[weak] wrac_enabled_entry,
|
||||||
#[weak] chunked_enabled_entry,
|
#[weak] chunked_enabled_entry,
|
||||||
#[weak] formatting_enabled_entry,
|
#[weak] formatting_enabled_entry,
|
||||||
#[weak] commands_enabled_entry,
|
#[weak] commands_enabled_entry,
|
||||||
@ -286,6 +290,7 @@ fn open_settings(ctx: Arc<Context>, app: &Application) {
|
|||||||
show_other_ip_entry.set_active(config.show_other_ip);
|
show_other_ip_entry.set_active(config.show_other_ip);
|
||||||
auth_enabled_entry.set_active(config.auth_enabled);
|
auth_enabled_entry.set_active(config.auth_enabled);
|
||||||
ssl_enabled_entry.set_active(config.ssl_enabled);
|
ssl_enabled_entry.set_active(config.ssl_enabled);
|
||||||
|
wrac_enabled_entry.set_active(config.wrac_enabled);
|
||||||
chunked_enabled_entry.set_active(config.chunked_enabled);
|
chunked_enabled_entry.set_active(config.chunked_enabled);
|
||||||
formatting_enabled_entry.set_active(config.formatting_enabled);
|
formatting_enabled_entry.set_active(config.formatting_enabled);
|
||||||
commands_enabled_entry.set_active(config.commands_enabled);
|
commands_enabled_entry.set_active(config.commands_enabled);
|
||||||
|
@ -2,12 +2,9 @@ use std::{
|
|||||||
error::Error, sync::Arc, thread, time::{Duration, SystemTime, UNIX_EPOCH}
|
error::Error, sync::Arc, thread, time::{Duration, SystemTime, UNIX_EPOCH}
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{connect_rac, proto::{register_user, send_message_auth}};
|
use crate::connect_rac;
|
||||||
|
|
||||||
use super::{
|
use super::proto::{connect, read_messages, send_message, send_message_spoof_auth, register_user, send_message_auth};
|
||||||
proto::{connect, read_messages, send_message, send_message_spoof_auth},
|
|
||||||
util::sanitize_text
|
|
||||||
};
|
|
||||||
|
|
||||||
use gui::{add_chat_message, clear_chat_messages};
|
use gui::{add_chat_message, clear_chat_messages};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
@ -19,15 +16,18 @@ pub use gui::run_main_loop;
|
|||||||
|
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref DATE_REGEX: Regex = Regex::new(r"\[(.*?)\] (.*)").unwrap();
|
static ref ANSI_REGEX: Regex = Regex::new(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])").unwrap();
|
||||||
pub static ref IP_REGEX: Regex = Regex::new(r"\{(.*?)\} (.*)").unwrap();
|
static ref CONTROL_CHARS_REGEX: Regex = Regex::new(r"[\x00-\x1F\x7F]").unwrap();
|
||||||
|
|
||||||
pub static ref COLORED_USERNAMES: Vec<(Regex, String)> = vec![
|
pub static ref DATE_REGEX: Regex = Regex::new(r"\[(.*?)\] (.*)").unwrap();
|
||||||
(Regex::new(r"\u{B9AC}\u{3E70}<(.*?)> (.*)").unwrap(), "green".to_string()), // bRAC
|
pub static ref IP_REGEX: Regex = Regex::new(r"\{(.*?)\} (.*)").unwrap();
|
||||||
(Regex::new(r"\u{2550}\u{2550}\u{2550}<(.*?)> (.*)").unwrap(), "red".to_string()), // CRAB
|
|
||||||
(Regex::new(r"\u{00B0}\u{0298}<(.*?)> (.*)").unwrap(), "magenta".to_string()), // Mefidroniy
|
pub static ref COLORED_USERNAMES: Vec<(Regex, String)> = vec![
|
||||||
(Regex::new(r"<(.*?)> (.*)").unwrap(), "cyan".to_string()), // clRAC
|
(Regex::new(r"\u{B9AC}\u{3E70}<(.*?)> (.*)").unwrap(), "green".to_string()), // bRAC
|
||||||
];
|
(Regex::new(r"\u{2550}\u{2550}\u{2550}<(.*?)> (.*)").unwrap(), "red".to_string()), // CRAB
|
||||||
|
(Regex::new(r"\u{00B0}\u{0298}<(.*?)> (.*)").unwrap(), "magenta".to_string()), // Mefidroniy
|
||||||
|
(Regex::new(r"<(.*?)> (.*)").unwrap(), "cyan".to_string()), // clRAC
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -44,6 +44,11 @@ const HELP_MESSAGE: &str = "Help message:
|
|||||||
/spam n text - send message with text n times
|
/spam n text - send message with text n times
|
||||||
/ping - check server ping";
|
/ping - check server ping";
|
||||||
|
|
||||||
|
pub fn sanitize_text(input: &str) -> String {
|
||||||
|
let without_ansi = ANSI_REGEX.replace_all(input, "");
|
||||||
|
let cleaned_text = CONTROL_CHARS_REGEX.replace_all(&without_ansi, "");
|
||||||
|
cleaned_text.into_owned()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add_message(ctx: Arc<Context>, message: &str) -> Result<(), Box<dyn Error>> {
|
pub fn add_message(ctx: Arc<Context>, message: &str) -> Result<(), Box<dyn Error>> {
|
||||||
for i in message.split("\n")
|
for i in message.split("\n")
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
|
|
||||||
pub mod chat;
|
pub mod chat;
|
||||||
pub mod util;
|
|
||||||
pub mod proto;
|
pub mod proto;
|
@ -20,7 +20,7 @@ fn main() {
|
|||||||
let mut config = load_config(config_path);
|
let mut config = load_config(config_path);
|
||||||
|
|
||||||
if args.read_messages {
|
if args.read_messages {
|
||||||
let mut stream = connect(&config.host, config.ssl_enabled, config.proxy.clone()).expect("Error reading message");
|
let mut stream = connect(&config.host, config.ssl_enabled, config.proxy.clone(), config.wrac_enabled).expect("Error reading message");
|
||||||
|
|
||||||
print!("{}", read_messages(
|
print!("{}", read_messages(
|
||||||
&mut stream,
|
&mut stream,
|
||||||
@ -35,7 +35,7 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(message) = &args.send_message {
|
if let Some(message) = &args.send_message {
|
||||||
let mut stream = connect(&config.host, config.ssl_enabled, config.proxy.clone()).expect("Error sending message");
|
let mut stream = connect(&config.host, config.ssl_enabled, config.proxy.clone(), config.wrac_enabled).expect("Error sending message");
|
||||||
|
|
||||||
send_message(
|
send_message(
|
||||||
&mut stream,
|
&mut stream,
|
||||||
|
@ -1,49 +1,72 @@
|
|||||||
#![allow(unused)]
|
use std::{error::Error, fmt::Debug, io::{Read, Write}, net::{TcpStream, ToSocketAddrs}, time::Duration};
|
||||||
|
|
||||||
use std::{error::Error, fmt::Debug, io::{Read, Write}, net::{SocketAddr, TcpStream, ToSocketAddrs}, str::FromStr, time::Duration};
|
|
||||||
use native_tls::{TlsConnector, TlsStream};
|
use native_tls::{TlsConnector, TlsStream};
|
||||||
use socks::Socks5Stream;
|
use socks::Socks5Stream;
|
||||||
|
use tungstenite::WebSocket;
|
||||||
|
|
||||||
use crate::util::parse_socks5_url;
|
pub mod rac;
|
||||||
|
pub mod wrac;
|
||||||
|
|
||||||
pub trait RacStream: Read + Write + Unpin + Send + Sync + Debug {
|
pub trait Stream: Read + Write + Unpin + Send + Sync + Debug {
|
||||||
fn set_read_timeout(&self, timeout: Duration);
|
fn set_read_timeout(&self, timeout: Duration);
|
||||||
fn set_write_timeout(&self, timeout: Duration);
|
fn set_write_timeout(&self, timeout: Duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RacStream for TcpStream {
|
impl Stream for TcpStream {
|
||||||
fn set_read_timeout(&self, timeout: Duration) { let _ = TcpStream::set_read_timeout(&self, Some(timeout)); }
|
fn set_read_timeout(&self, timeout: Duration) { let _ = TcpStream::set_read_timeout(&self, Some(timeout)); }
|
||||||
fn set_write_timeout(&self, timeout: Duration) { let _ = TcpStream::set_write_timeout(&self, Some(timeout)); }
|
fn set_write_timeout(&self, timeout: Duration) { let _ = TcpStream::set_write_timeout(&self, Some(timeout)); }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RacStream for Socks5Stream {
|
impl Stream for Socks5Stream {
|
||||||
fn set_read_timeout(&self, timeout: Duration) { let _ = TcpStream::set_read_timeout(self.get_ref(), Some(timeout)); }
|
fn set_read_timeout(&self, timeout: Duration) { let _ = TcpStream::set_read_timeout(self.get_ref(), Some(timeout)); }
|
||||||
fn set_write_timeout(&self, timeout: Duration) { let _ = TcpStream::set_write_timeout(self.get_ref(), Some(timeout)); }
|
fn set_write_timeout(&self, timeout: Duration) { let _ = TcpStream::set_write_timeout(self.get_ref(), Some(timeout)); }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: RacStream> RacStream for TlsStream<T> {
|
impl<T: Stream> Stream for TlsStream<T> {
|
||||||
fn set_read_timeout(&self, timeout: Duration) { self.get_ref().set_read_timeout(timeout); }
|
fn set_read_timeout(&self, timeout: Duration) { self.get_ref().set_read_timeout(timeout); }
|
||||||
fn set_write_timeout(&self, timeout: Duration) { self.get_ref().set_write_timeout(timeout); }
|
fn set_write_timeout(&self, timeout: Duration) { self.get_ref().set_write_timeout(timeout); }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RacStream for TlsStream<Box<dyn RacStream>> {
|
impl Stream for TlsStream<Box<dyn Stream>> {
|
||||||
fn set_read_timeout(&self, timeout: Duration) { self.get_ref().set_read_timeout(timeout); }
|
fn set_read_timeout(&self, timeout: Duration) { self.get_ref().set_read_timeout(timeout); }
|
||||||
fn set_write_timeout(&self, timeout: Duration) { self.get_ref().set_write_timeout(timeout); }
|
fn set_write_timeout(&self, timeout: Duration) { self.get_ref().set_write_timeout(timeout); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum RacStream {
|
||||||
|
WRAC(WebSocket<Box<dyn Stream>>),
|
||||||
|
RAC(Box<dyn Stream>)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `socks5://user:pass@127.0.0.1:12345/path -> ("127.0.0.1:12345", ("user", "pass"))` \
|
||||||
|
/// `socks5://127.0.0.1:12345 -> ("127.0.0.1:12345", None)` \
|
||||||
|
/// `https://127.0.0.1:12345 -> ("127.0.0.1:12345", None)` \
|
||||||
|
/// `127.0.0.1:12345 -> ("127.0.0.1:12345", None)` \
|
||||||
|
/// `user:pass@127.0.0.1:12345 -> ("127.0.0.1:12345", ("user", "pass"))`
|
||||||
|
pub fn parse_socks5_url(url: &str) -> Option<(String, Option<(String, String)>)> {
|
||||||
|
let (_, url) = url.split_once("://").unwrap_or(("", url));
|
||||||
|
let (url, _) = url.split_once("/").unwrap_or((url, ""));
|
||||||
|
if let Some((auth, url)) = url.split_once("@") {
|
||||||
|
let (user, pass) = auth.split_once(":")?;
|
||||||
|
Some((url.to_string(), Some((user.to_string(), pass.to_string()))))
|
||||||
|
} else {
|
||||||
|
Some((url.to_string(), None))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Create RAC connection (also you can just TcpStream::connect)
|
/// Create RAC connection (also you can just TcpStream::connect)
|
||||||
///
|
///
|
||||||
/// host - host string, example: "example.com:12345", "example.com" (default port is 42666)
|
/// host - host string, example: "example.com:12345", "example.com" (default port is 42666)
|
||||||
/// ssl - wrap with ssl client, write false if you dont know what it is
|
/// ssl - wrap with ssl client, write false if you dont know what it is
|
||||||
/// proxy - socks5 proxy (host, (user, pass))
|
/// proxy - socks5 proxy (host, (user, pass))
|
||||||
pub fn connect(host: &str, ssl: bool, proxy: Option<String>) -> Result<Box<dyn RacStream>, Box<dyn Error>> {
|
/// wrac - to use wrac protocol
|
||||||
|
pub fn connect(host: &str, ssl: bool, proxy: Option<String>, wrac: bool) -> Result<RacStream, Box<dyn Error>> {
|
||||||
let host = if host.contains(":") {
|
let host = if host.contains(":") {
|
||||||
host.to_string()
|
host.to_string()
|
||||||
} else {
|
} else {
|
||||||
format!("{host}:42666")
|
format!("{host}:42666")
|
||||||
};
|
};
|
||||||
|
|
||||||
let stream: Box<dyn RacStream> = if let Some(proxy) = proxy {
|
let stream: Box<dyn Stream> = if let Some(proxy) = proxy {
|
||||||
if let Some((proxy, auth)) = parse_socks5_url(&proxy) {
|
if let Some((proxy, auth)) = parse_socks5_url(&proxy) {
|
||||||
if let Some((user, pass)) = auth {
|
if let Some((user, pass)) = auth {
|
||||||
Box::new(Socks5Stream::connect_with_password(&proxy, host.as_str(), &user, &pass)?)
|
Box::new(Socks5Stream::connect_with_password(&proxy, host.as_str(), &user, &pass)?)
|
||||||
@ -76,16 +99,50 @@ pub fn connect(host: &str, ssl: bool, proxy: Option<String>) -> Result<Box<dyn R
|
|||||||
stream.set_read_timeout(Duration::from_secs(3));
|
stream.set_read_timeout(Duration::from_secs(3));
|
||||||
stream.set_write_timeout(Duration::from_secs(3));
|
stream.set_write_timeout(Duration::from_secs(3));
|
||||||
|
|
||||||
Ok(stream)
|
if wrac {
|
||||||
|
Ok(RacStream::WRAC(tungstenite::accept(stream)?))
|
||||||
|
} else {
|
||||||
|
Ok(RacStream::RAC(stream))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Send message with fake auth
|
||||||
|
///
|
||||||
|
/// Explaination:
|
||||||
|
///
|
||||||
|
/// let (name, message) = message.split("> ") else { return send_message(stream, message) }
|
||||||
|
/// if send_message_auth(name, name, message) != 0 {
|
||||||
|
/// let name = "\x1f" + name
|
||||||
|
/// register_user(stream, name, name)
|
||||||
|
/// send_message_spoof_auth(stream, name + "> " + message)
|
||||||
|
/// }
|
||||||
|
pub fn send_message_spoof_auth(stream: &mut RacStream, message: &str, remove_null: bool) -> Result<(), Box<dyn Error>> {
|
||||||
|
let Some((name, message)) = message.split_once("> ") else { return send_message(stream, message) };
|
||||||
|
|
||||||
|
if let Ok(f) = send_message_auth(stream, &name, &message, &message, remove_null) {
|
||||||
|
if f != 0 {
|
||||||
|
let name = format!("\x1f{name}");
|
||||||
|
register_user(stream, &name, &name, remove_null)?;
|
||||||
|
send_message_spoof_auth(stream, &format!("{name}> {message}"), remove_null)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Send message
|
/// Send message
|
||||||
///
|
///
|
||||||
/// stream - any stream that can be written to
|
/// stream - any stream that can be written to
|
||||||
/// message - message text
|
/// message - message text
|
||||||
pub fn send_message(stream: &mut impl Write, message: &str) -> Result<(), Box<dyn Error>> {
|
pub fn send_message(
|
||||||
stream.write_all(format!("\x01{message}").as_bytes())?;
|
stream: &mut RacStream,
|
||||||
Ok(())
|
message: &str
|
||||||
|
) -> Result<(), Box<dyn Error>> {
|
||||||
|
match stream {
|
||||||
|
RacStream::WRAC(websocket) => wrac::send_message(websocket, message),
|
||||||
|
RacStream::RAC(stream) => rac::send_message(stream, message)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Register user
|
/// Register user
|
||||||
@ -97,25 +154,14 @@ pub fn send_message(stream: &mut impl Write, message: &str) -> Result<(), Box<dy
|
|||||||
///
|
///
|
||||||
/// returns whether the user was registered
|
/// returns whether the user was registered
|
||||||
pub fn register_user(
|
pub fn register_user(
|
||||||
stream: &mut (impl Write + Read),
|
stream: &mut RacStream,
|
||||||
name: &str,
|
name: &str,
|
||||||
password: &str,
|
password: &str,
|
||||||
remove_null: bool
|
remove_null: bool
|
||||||
) -> Result<bool, Box<dyn Error>> {
|
) -> Result<bool, Box<dyn Error>> {
|
||||||
stream.write_all(format!("\x03{name}\n{password}").as_bytes())?;
|
match stream {
|
||||||
if remove_null {
|
RacStream::WRAC(websocket) => wrac::register_user(websocket, name, password),
|
||||||
if let Ok(out) = skip_null(stream) {
|
RacStream::RAC(stream) => rac::register_user(stream, name, password, remove_null)
|
||||||
Ok(out[0] == 0)
|
|
||||||
} else {
|
|
||||||
Ok(true)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let mut buf = vec![0];
|
|
||||||
if let Ok(1) = stream.read(&mut buf) {
|
|
||||||
Ok(buf[0] == 0)
|
|
||||||
} else {
|
|
||||||
Ok(true)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,73 +177,18 @@ pub fn register_user(
|
|||||||
/// returns 1 if the user does not exist
|
/// returns 1 if the user does not exist
|
||||||
/// returns 2 if the password is incorrect
|
/// returns 2 if the password is incorrect
|
||||||
pub fn send_message_auth(
|
pub fn send_message_auth(
|
||||||
stream: &mut (impl Write + Read),
|
stream: &mut RacStream,
|
||||||
name: &str,
|
name: &str,
|
||||||
password: &str,
|
password: &str,
|
||||||
message: &str,
|
message: &str,
|
||||||
remove_null: bool
|
remove_null: bool
|
||||||
) -> Result<u8, Box<dyn Error>> {
|
) -> Result<u8, Box<dyn Error>> {
|
||||||
stream.write_all(format!("\x02{name}\n{password}\n{message}").as_bytes())?;
|
match stream {
|
||||||
|
RacStream::WRAC(websocket) => wrac::send_message_auth(websocket, name, password, message),
|
||||||
if remove_null {
|
RacStream::RAC(stream) => rac::send_message_auth(stream, name, password, message, remove_null)
|
||||||
if let Ok(out) = skip_null(stream) {
|
|
||||||
Ok(out[0])
|
|
||||||
} else {
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let mut buf = vec![0];
|
|
||||||
if let Ok(1) = stream.read(&mut buf) {
|
|
||||||
Ok(buf[0])
|
|
||||||
} else {
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send message with fake auth
|
|
||||||
///
|
|
||||||
/// Explaination:
|
|
||||||
///
|
|
||||||
/// let (name, message) = message.split("> ") else { return send_message(stream, message) }
|
|
||||||
/// if send_message_auth(name, name, message) != 0 {
|
|
||||||
/// let name = "\x1f" + name
|
|
||||||
/// register_user(stream, name, name)
|
|
||||||
/// send_message_spoof_auth(stream, name + "> " + message)
|
|
||||||
/// }
|
|
||||||
pub fn send_message_spoof_auth(stream: &mut (impl Write + Read), message: &str, remove_null: bool) -> Result<(), Box<dyn Error>> {
|
|
||||||
let Some((name, message)) = message.split_once("> ") else { return send_message(stream, message) };
|
|
||||||
|
|
||||||
if let Ok(f) = send_message_auth(stream, &name, &message, &message, remove_null) {
|
|
||||||
if f != 0 {
|
|
||||||
let name = format!("\x1f{name}");
|
|
||||||
register_user(stream, &name, &name, remove_null);
|
|
||||||
send_message_spoof_auth(stream, &format!("{name}> {message}"), remove_null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Skip null bytes and return first non-null byte
|
|
||||||
pub fn skip_null(stream: &mut impl Read) -> Result<Vec<u8>, Box<dyn Error>> {
|
|
||||||
loop {
|
|
||||||
let mut buf = vec![0; 1];
|
|
||||||
stream.read_exact(&mut buf)?;
|
|
||||||
if buf[0] != 0 {
|
|
||||||
break Ok(buf)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// remove trailing null bytes in vector
|
|
||||||
pub fn remove_trailing_null(vec: &mut Vec<u8>) -> Result<(), Box<dyn Error>> {
|
|
||||||
while vec.ends_with(&[0]) {
|
|
||||||
vec.remove(vec.len()-1);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Read messages
|
/// Read messages
|
||||||
///
|
///
|
||||||
/// max_messages - max messages in list
|
/// max_messages - max messages in list
|
||||||
@ -207,66 +198,14 @@ pub fn remove_trailing_null(vec: &mut Vec<u8>) -> Result<(), Box<dyn Error>> {
|
|||||||
///
|
///
|
||||||
/// returns (messages, packet size)
|
/// returns (messages, packet size)
|
||||||
pub fn read_messages(
|
pub fn read_messages(
|
||||||
stream: &mut (impl Read + Write),
|
stream: &mut RacStream,
|
||||||
max_messages: usize,
|
max_messages: usize,
|
||||||
last_size: usize,
|
last_size: usize,
|
||||||
remove_null: bool,
|
remove_null: bool,
|
||||||
chunked: bool
|
chunked: bool
|
||||||
) -> Result<Option<(Vec<String>, usize)>, Box<dyn Error>> {
|
) -> Result<Option<(Vec<String>, usize)>, Box<dyn Error>> {
|
||||||
stream.write_all(&[0x00])?;
|
match stream {
|
||||||
|
RacStream::WRAC(websocket) => wrac::read_messages(websocket, max_messages, last_size, chunked),
|
||||||
let packet_size = {
|
RacStream::RAC(stream) => rac::read_messages(stream, max_messages, last_size, remove_null, chunked)
|
||||||
let data = if remove_null {
|
|
||||||
let mut data = skip_null(stream)?;
|
|
||||||
let mut buf = vec![0; 10];
|
|
||||||
let len = stream.read(&mut buf)?;
|
|
||||||
buf.truncate(len);
|
|
||||||
data.append(&mut buf);
|
|
||||||
remove_trailing_null(&mut data)?;
|
|
||||||
data
|
|
||||||
} else {
|
|
||||||
let mut data = vec![0; 10];
|
|
||||||
let len = stream.read(&mut data)?;
|
|
||||||
data.truncate(len);
|
|
||||||
data
|
|
||||||
};
|
|
||||||
|
|
||||||
String::from_utf8(data)?
|
|
||||||
.trim_matches(char::from(0))
|
|
||||||
.parse()?
|
|
||||||
};
|
|
||||||
|
|
||||||
if last_size == packet_size {
|
|
||||||
return Ok(None);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let to_read = if !chunked || last_size == 0 {
|
|
||||||
stream.write_all(&[0x01])?;
|
|
||||||
packet_size
|
|
||||||
} else {
|
|
||||||
stream.write_all(format!("\x02{}", last_size).as_bytes())?;
|
|
||||||
packet_size - last_size
|
|
||||||
};
|
|
||||||
|
|
||||||
let packet_data = if remove_null {
|
|
||||||
let mut data = skip_null(stream)?;
|
|
||||||
let mut buf = vec![0; to_read - 1];
|
|
||||||
stream.read_exact(&mut buf)?;
|
|
||||||
data.append(&mut buf);
|
|
||||||
data
|
|
||||||
} else {
|
|
||||||
let mut data = vec![0; to_read];
|
|
||||||
stream.read_exact(&mut data)?;
|
|
||||||
data
|
|
||||||
};
|
|
||||||
|
|
||||||
let packet_data = String::from_utf8_lossy(&packet_data).to_string();
|
|
||||||
|
|
||||||
let lines: Vec<&str> = packet_data.split("\n").collect();
|
|
||||||
let lines: Vec<String> = lines.clone().into_iter()
|
|
||||||
.skip(if lines.len() >= max_messages { lines.len() - max_messages } else { 0 })
|
|
||||||
.map(|o| o.to_string())
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
Ok(Some((lines, packet_size)))
|
|
||||||
}
|
}
|
169
src/proto/rac.rs
Normal file
169
src/proto/rac.rs
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
use std::{error::Error, io::{Read, Write}};
|
||||||
|
|
||||||
|
/// Send message
|
||||||
|
///
|
||||||
|
/// stream - any stream that can be written to
|
||||||
|
/// message - message text
|
||||||
|
pub fn send_message(stream: &mut impl Write, message: &str) -> Result<(), Box<dyn Error>> {
|
||||||
|
stream.write_all(format!("\x01{message}").as_bytes())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Register user
|
||||||
|
///
|
||||||
|
/// stream - any stream that can be written to
|
||||||
|
/// name - user name
|
||||||
|
/// password - user password
|
||||||
|
/// remove_null - remove null bytes on reading
|
||||||
|
///
|
||||||
|
/// returns whether the user was registered
|
||||||
|
pub fn register_user(
|
||||||
|
stream: &mut (impl Write + Read),
|
||||||
|
name: &str,
|
||||||
|
password: &str,
|
||||||
|
remove_null: bool
|
||||||
|
) -> Result<bool, Box<dyn Error>> {
|
||||||
|
stream.write_all(format!("\x03{name}\n{password}").as_bytes())?;
|
||||||
|
if remove_null {
|
||||||
|
if let Ok(out) = skip_null(stream) {
|
||||||
|
Ok(out[0] == 0)
|
||||||
|
} else {
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let mut buf = vec![0];
|
||||||
|
if let Ok(1) = stream.read(&mut buf) {
|
||||||
|
Ok(buf[0] == 0)
|
||||||
|
} else {
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Send message with auth
|
||||||
|
///
|
||||||
|
/// stream - any stream that can be written to
|
||||||
|
/// message - message text
|
||||||
|
/// name - user name
|
||||||
|
/// password - user password
|
||||||
|
/// remove_null - remove null bytes on reading
|
||||||
|
///
|
||||||
|
/// returns 0 if the message was sent successfully
|
||||||
|
/// returns 1 if the user does not exist
|
||||||
|
/// returns 2 if the password is incorrect
|
||||||
|
pub fn send_message_auth(
|
||||||
|
stream: &mut (impl Write + Read),
|
||||||
|
name: &str,
|
||||||
|
password: &str,
|
||||||
|
message: &str,
|
||||||
|
remove_null: bool
|
||||||
|
) -> Result<u8, Box<dyn Error>> {
|
||||||
|
stream.write_all(format!("\x02{name}\n{password}\n{message}").as_bytes())?;
|
||||||
|
|
||||||
|
if remove_null {
|
||||||
|
if let Ok(out) = skip_null(stream) {
|
||||||
|
Ok(out[0])
|
||||||
|
} else {
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let mut buf = vec![0];
|
||||||
|
if let Ok(1) = stream.read(&mut buf) {
|
||||||
|
Ok(buf[0])
|
||||||
|
} else {
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Skip null bytes and return first non-null byte
|
||||||
|
pub fn skip_null(stream: &mut impl Read) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||||
|
loop {
|
||||||
|
let mut buf = vec![0; 1];
|
||||||
|
stream.read_exact(&mut buf)?;
|
||||||
|
if buf[0] != 0 {
|
||||||
|
break Ok(buf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// remove trailing null bytes in vector
|
||||||
|
pub fn remove_trailing_null(vec: &mut Vec<u8>) -> Result<(), Box<dyn Error>> {
|
||||||
|
while vec.ends_with(&[0]) {
|
||||||
|
vec.remove(vec.len()-1);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read messages
|
||||||
|
///
|
||||||
|
/// max_messages - max messages in list
|
||||||
|
/// last_size - last returned packet size
|
||||||
|
/// remove_null - start with skipping null bytes
|
||||||
|
/// chunked - is chunked reading enabled
|
||||||
|
///
|
||||||
|
/// returns (messages, packet size)
|
||||||
|
pub fn read_messages(
|
||||||
|
stream: &mut (impl Read + Write),
|
||||||
|
max_messages: usize,
|
||||||
|
last_size: usize,
|
||||||
|
remove_null: bool,
|
||||||
|
chunked: bool
|
||||||
|
) -> Result<Option<(Vec<String>, usize)>, Box<dyn Error>> {
|
||||||
|
stream.write_all(&[0x00])?;
|
||||||
|
|
||||||
|
let packet_size = {
|
||||||
|
let data = if remove_null {
|
||||||
|
let mut data = skip_null(stream)?;
|
||||||
|
let mut buf = vec![0; 10];
|
||||||
|
let len = stream.read(&mut buf)?;
|
||||||
|
buf.truncate(len);
|
||||||
|
data.append(&mut buf);
|
||||||
|
remove_trailing_null(&mut data)?;
|
||||||
|
data
|
||||||
|
} else {
|
||||||
|
let mut data = vec![0; 10];
|
||||||
|
let len = stream.read(&mut data)?;
|
||||||
|
data.truncate(len);
|
||||||
|
data
|
||||||
|
};
|
||||||
|
|
||||||
|
String::from_utf8(data)?
|
||||||
|
.trim_matches(char::from(0))
|
||||||
|
.parse()?
|
||||||
|
};
|
||||||
|
|
||||||
|
if last_size == packet_size {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
let to_read = if !chunked || last_size == 0 {
|
||||||
|
stream.write_all(&[0x01])?;
|
||||||
|
packet_size
|
||||||
|
} else {
|
||||||
|
stream.write_all(format!("\x02{}", last_size).as_bytes())?;
|
||||||
|
packet_size - last_size
|
||||||
|
};
|
||||||
|
|
||||||
|
let packet_data = if remove_null {
|
||||||
|
let mut data = skip_null(stream)?;
|
||||||
|
let mut buf = vec![0; to_read - 1];
|
||||||
|
stream.read_exact(&mut buf)?;
|
||||||
|
data.append(&mut buf);
|
||||||
|
data
|
||||||
|
} else {
|
||||||
|
let mut data = vec![0; to_read];
|
||||||
|
stream.read_exact(&mut data)?;
|
||||||
|
data
|
||||||
|
};
|
||||||
|
|
||||||
|
let packet_data = String::from_utf8_lossy(&packet_data).to_string();
|
||||||
|
|
||||||
|
let lines: Vec<&str> = packet_data.split("\n").collect();
|
||||||
|
let lines: Vec<String> = lines.clone().into_iter()
|
||||||
|
.skip(if lines.len() >= max_messages { lines.len() - max_messages } else { 0 })
|
||||||
|
.map(|o| o.to_string())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Ok(Some((lines, packet_size)))
|
||||||
|
}
|
123
src/proto/wrac.rs
Normal file
123
src/proto/wrac.rs
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
use std::{error::Error, io::{Read, Write}};
|
||||||
|
use tungstenite::{WebSocket, Message};
|
||||||
|
|
||||||
|
|
||||||
|
/// Send message
|
||||||
|
///
|
||||||
|
/// stream - any stream that can be written to
|
||||||
|
/// message - message text
|
||||||
|
pub fn send_message(
|
||||||
|
stream: &mut WebSocket<impl Write + Read>,
|
||||||
|
message: &str
|
||||||
|
) -> Result<(), Box<dyn Error>> {
|
||||||
|
stream.write(Message::Binary(format!("\x01{message}").as_bytes().to_vec().into()))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Register user
|
||||||
|
///
|
||||||
|
/// stream - any stream that can be written to
|
||||||
|
/// name - user name
|
||||||
|
/// password - user password
|
||||||
|
///
|
||||||
|
/// returns whether the user was registered
|
||||||
|
pub fn register_user(
|
||||||
|
stream: &mut WebSocket<impl Write + Read>,
|
||||||
|
name: &str,
|
||||||
|
password: &str
|
||||||
|
) -> Result<bool, Box<dyn Error>> {
|
||||||
|
stream.write(Message::Binary(format!("\x03{name}\n{password}").as_bytes().to_vec().into()))?;
|
||||||
|
if let Ok(msg) = stream.read() {
|
||||||
|
Ok(!msg.is_binary() || msg.into_data().get(0).unwrap_or(&0) == &0)
|
||||||
|
} else {
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Send message with auth
|
||||||
|
///
|
||||||
|
/// stream - any stream that can be written to
|
||||||
|
/// message - message text
|
||||||
|
/// name - user name
|
||||||
|
/// password - user password
|
||||||
|
///
|
||||||
|
/// returns 0 if the message was sent successfully
|
||||||
|
/// returns 1 if the user does not exist
|
||||||
|
/// returns 2 if the password is incorrect
|
||||||
|
pub fn send_message_auth(
|
||||||
|
stream: &mut WebSocket<impl Write + Read>,
|
||||||
|
name: &str,
|
||||||
|
password: &str,
|
||||||
|
message: &str
|
||||||
|
) -> Result<u8, Box<dyn Error>> {
|
||||||
|
stream.write(Message::Binary(format!("\x02{name}\n{password}\n{message}").as_bytes().to_vec().into()))?;
|
||||||
|
if let Ok(msg) = stream.read() {
|
||||||
|
if msg.is_binary() {
|
||||||
|
Ok(0)
|
||||||
|
} else {
|
||||||
|
Ok(*msg.into_data().get(0).unwrap_or(&0))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read messages
|
||||||
|
///
|
||||||
|
/// max_messages - max messages in list
|
||||||
|
/// last_size - last returned packet size
|
||||||
|
/// chunked - is chunked reading enabled
|
||||||
|
///
|
||||||
|
/// returns (messages, packet size)
|
||||||
|
pub fn read_messages(
|
||||||
|
stream: &mut WebSocket<impl Write + Read>,
|
||||||
|
max_messages: usize,
|
||||||
|
last_size: usize,
|
||||||
|
chunked: bool
|
||||||
|
) -> Result<Option<(Vec<String>, usize)>, Box<dyn Error>> {
|
||||||
|
stream.write(Message::Binary(vec![0x00].into()))?;
|
||||||
|
|
||||||
|
let packet_size = {
|
||||||
|
let msg = stream.read()?;
|
||||||
|
if !msg.is_binary() {
|
||||||
|
return Err("msg is not binary".into());
|
||||||
|
}
|
||||||
|
let len = msg.into_data().to_vec();
|
||||||
|
|
||||||
|
String::from_utf8(len)?
|
||||||
|
.trim_matches(char::from(0))
|
||||||
|
.parse()?
|
||||||
|
};
|
||||||
|
|
||||||
|
if last_size == packet_size {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
let to_read = if !chunked || last_size == 0 {
|
||||||
|
stream.write(Message::Binary(vec![0x00, 0x01].into()))?;
|
||||||
|
packet_size
|
||||||
|
} else {
|
||||||
|
stream.write(Message::Binary(format!("\x00\x02{}", last_size).as_bytes().to_vec().into()))?;
|
||||||
|
packet_size - last_size
|
||||||
|
};
|
||||||
|
|
||||||
|
let msg = stream.read()?;
|
||||||
|
if !msg.is_binary() {
|
||||||
|
return Err("msg is not binary".into());
|
||||||
|
}
|
||||||
|
let packet_data = msg.into_data().to_vec();
|
||||||
|
|
||||||
|
if packet_data.len() > to_read {
|
||||||
|
return Err("too big msg".into());
|
||||||
|
}
|
||||||
|
|
||||||
|
let packet_data = String::from_utf8_lossy(&packet_data).to_string();
|
||||||
|
|
||||||
|
let lines: Vec<&str> = packet_data.split("\n").collect();
|
||||||
|
let lines: Vec<String> = lines.clone().into_iter()
|
||||||
|
.skip(if lines.len() >= max_messages { lines.len() - max_messages } else { 0 })
|
||||||
|
.map(|o| o.to_string())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Ok(Some((lines, packet_size)))
|
||||||
|
}
|
29
src/util.rs
29
src/util.rs
@ -1,29 +0,0 @@
|
|||||||
use lazy_static::lazy_static;
|
|
||||||
use regex::Regex;
|
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
static ref ANSI_REGEX: Regex = Regex::new(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])").unwrap();
|
|
||||||
static ref CONTROL_CHARS_REGEX: Regex = Regex::new(r"[\x00-\x1F\x7F]").unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sanitize_text(input: &str) -> String {
|
|
||||||
let without_ansi = ANSI_REGEX.replace_all(input, "");
|
|
||||||
let cleaned_text = CONTROL_CHARS_REGEX.replace_all(&without_ansi, "");
|
|
||||||
cleaned_text.into_owned()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `socks5://user:pass@127.0.0.1:12345/path -> ("127.0.0.1:12345", ("user", "pass"))` \
|
|
||||||
/// `socks5://127.0.0.1:12345 -> ("127.0.0.1:12345", None)` \
|
|
||||||
/// `https://127.0.0.1:12345 -> ("127.0.0.1:12345", None)` \
|
|
||||||
/// `127.0.0.1:12345 -> ("127.0.0.1:12345", None)` \
|
|
||||||
/// `user:pass@127.0.0.1:12345 -> ("127.0.0.1:12345", ("user", "pass"))`
|
|
||||||
pub fn parse_socks5_url(url: &str) -> Option<(String, Option<(String, String)>)> {
|
|
||||||
let (_, url) = url.split_once("://").unwrap_or(("", url));
|
|
||||||
let (url, _) = url.split_once("/").unwrap_or((url, ""));
|
|
||||||
if let Some((auth, url)) = url.split_once("@") {
|
|
||||||
let (user, pass) = auth.split_once(":")?;
|
|
||||||
Some((url.to_string(), Some((user.to_string(), pass.to_string()))))
|
|
||||||
} else {
|
|
||||||
Some((url.to_string(), None))
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user