mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Made commands a distinct ClientMsg to avoid possible sanitisation problems for clients
This commit is contained in:
parent
f132c3fcb4
commit
96cbf60c3f
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -707,6 +707,12 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "comma"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "96677551532ffe910f470bd767a9a7daf9ba53b1f5532e0891dba6c735f692e5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "concurrent-queue"
|
name = "concurrent-queue"
|
||||||
version = "1.2.2"
|
version = "1.2.2"
|
||||||
@ -6049,6 +6055,7 @@ dependencies = [
|
|||||||
"bincode",
|
"bincode",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
"comma",
|
||||||
"conrod_core",
|
"conrod_core",
|
||||||
"conrod_winit",
|
"conrod_winit",
|
||||||
"copy_dir",
|
"copy_dir",
|
||||||
|
@ -808,9 +808,9 @@ impl Client {
|
|||||||
//Only in game, terrain
|
//Only in game, terrain
|
||||||
ClientGeneral::TerrainChunkRequest { .. } => &mut self.terrain_stream,
|
ClientGeneral::TerrainChunkRequest { .. } => &mut self.terrain_stream,
|
||||||
//Always possible
|
//Always possible
|
||||||
ClientGeneral::ChatMsg(_) | ClientGeneral::Terminate => {
|
ClientGeneral::ChatMsg(_)
|
||||||
&mut self.general_stream
|
| ClientGeneral::Command(_, _)
|
||||||
},
|
| ClientGeneral::Terminate => &mut self.general_stream,
|
||||||
};
|
};
|
||||||
stream.send(msg)
|
stream.send(msg)
|
||||||
},
|
},
|
||||||
@ -1370,6 +1370,11 @@ impl Client {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Send a command to the server.
|
||||||
|
pub fn send_command(&mut self, name: String, args: Vec<String>) {
|
||||||
|
self.send_msg(ClientGeneral::Command(name, args));
|
||||||
|
}
|
||||||
|
|
||||||
/// Remove all cached terrain
|
/// Remove all cached terrain
|
||||||
pub fn clear_terrain(&mut self) {
|
pub fn clear_terrain(&mut self) {
|
||||||
self.state.clear_terrain();
|
self.state.clear_terrain();
|
||||||
|
@ -80,6 +80,7 @@ pub enum ClientGeneral {
|
|||||||
},
|
},
|
||||||
//Always possible
|
//Always possible
|
||||||
ChatMsg(String),
|
ChatMsg(String),
|
||||||
|
Command(String, Vec<String>),
|
||||||
Terminate,
|
Terminate,
|
||||||
RequestPlayerPhysics {
|
RequestPlayerPhysics {
|
||||||
server_authoritative: bool,
|
server_authoritative: bool,
|
||||||
@ -129,7 +130,9 @@ impl ClientMsg {
|
|||||||
c_type == ClientType::Game && presence.is_some()
|
c_type == ClientType::Game && presence.is_some()
|
||||||
},
|
},
|
||||||
//Always possible
|
//Always possible
|
||||||
ClientGeneral::ChatMsg(_) | ClientGeneral::Terminate => true,
|
ClientGeneral::ChatMsg(_)
|
||||||
|
| ClientGeneral::Command(_, _)
|
||||||
|
| ClientGeneral::Terminate => true,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ClientMsg::Ping(_) => true,
|
ClientMsg::Ping(_) => true,
|
||||||
|
@ -140,7 +140,7 @@ pub enum ServerEvent {
|
|||||||
ClientDisconnect(EcsEntity, DisconnectReason),
|
ClientDisconnect(EcsEntity, DisconnectReason),
|
||||||
ClientDisconnectWithoutPersistence(EcsEntity),
|
ClientDisconnectWithoutPersistence(EcsEntity),
|
||||||
ChunkRequest(EcsEntity, Vec2<i32>),
|
ChunkRequest(EcsEntity, Vec2<i32>),
|
||||||
ChatCmd(EcsEntity, String),
|
ChatCmd(EcsEntity, String, Vec<String>),
|
||||||
/// Send a chat message to the player from an npc or other player
|
/// Send a chat message to the player from an npc or other player
|
||||||
Chat(comp::UnresolvedChatMsg),
|
Chat(comp::UnresolvedChatMsg),
|
||||||
Aura {
|
Aura {
|
||||||
|
@ -52,11 +52,15 @@ use scan_fmt::{scan_fmt, scan_fmt_some};
|
|||||||
use tracing::{error, info, warn};
|
use tracing::{error, info, warn};
|
||||||
|
|
||||||
pub trait ChatCommandExt {
|
pub trait ChatCommandExt {
|
||||||
fn execute(&self, server: &mut Server, entity: EcsEntity, args: String);
|
fn execute(&self, server: &mut Server, entity: EcsEntity, args: Vec<String>);
|
||||||
}
|
}
|
||||||
impl ChatCommandExt for ChatCommand {
|
impl ChatCommandExt for ChatCommand {
|
||||||
#[allow(clippy::needless_return)] // TODO: Pending review in #587
|
#[allow(clippy::needless_return)] // TODO: Pending review in #587
|
||||||
fn execute(&self, server: &mut Server, entity: EcsEntity, args: String) {
|
fn execute(&self, server: &mut Server, entity: EcsEntity, args: Vec<String>) {
|
||||||
|
// TODO: Pass arguments to commands as Vec<String>, not String, to support
|
||||||
|
// proper parsing.
|
||||||
|
let args = args.join(" ");
|
||||||
|
|
||||||
if let Err(err) = do_command(server, entity, entity, args, self) {
|
if let Err(err) = do_command(server, entity, entity, args, self) {
|
||||||
server.notify_client(
|
server.notify_client(
|
||||||
entity,
|
entity,
|
||||||
@ -101,6 +105,7 @@ fn do_command(
|
|||||||
cmd.keyword()
|
cmd.keyword()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let handler: CommandHandler = match cmd {
|
let handler: CommandHandler = match cmd {
|
||||||
ChatCommand::Adminify => handle_adminify,
|
ChatCommand::Adminify => handle_adminify,
|
||||||
ChatCommand::Airship => handle_spawn_airship,
|
ChatCommand::Airship => handle_spawn_airship,
|
||||||
|
@ -188,8 +188,8 @@ impl Server {
|
|||||||
ServerEvent::ChunkRequest(entity, key) => {
|
ServerEvent::ChunkRequest(entity, key) => {
|
||||||
requested_chunks.push((entity, key));
|
requested_chunks.push((entity, key));
|
||||||
},
|
},
|
||||||
ServerEvent::ChatCmd(entity, cmd) => {
|
ServerEvent::ChatCmd(entity, name, args) => {
|
||||||
chat_commands.push((entity, cmd));
|
chat_commands.push((entity, name, args));
|
||||||
},
|
},
|
||||||
ServerEvent::Chat(msg) => {
|
ServerEvent::Chat(msg) => {
|
||||||
chat_messages.push(msg);
|
chat_messages.push(msg);
|
||||||
@ -229,8 +229,8 @@ impl Server {
|
|||||||
self.generate_chunk(entity, key);
|
self.generate_chunk(entity, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (entity, cmd) in chat_commands {
|
for (entity, name, args) in chat_commands {
|
||||||
self.process_chat_cmd(entity, cmd);
|
self.process_chat_cmd(entity, name, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
for msg in chat_messages {
|
for msg in chat_messages {
|
||||||
|
@ -983,16 +983,9 @@ impl Server {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_chat_cmd(&mut self, entity: EcsEntity, cmd: String) {
|
fn process_chat_cmd(&mut self, entity: EcsEntity, name: String, args: Vec<String>) {
|
||||||
// Separate string into keyword and arguments.
|
|
||||||
let sep = cmd.find(' ');
|
|
||||||
let (kwd, args) = match sep {
|
|
||||||
Some(i) => (cmd[..i].to_string(), cmd[(i + 1)..].to_string()),
|
|
||||||
None => (cmd, "".to_string()),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Find the command object and run its handler.
|
// Find the command object and run its handler.
|
||||||
if let Ok(command) = kwd.parse::<ChatCommand>() {
|
if let Ok(command) = name.parse::<ChatCommand>() {
|
||||||
command.execute(self, entity, args);
|
command.execute(self, entity, args);
|
||||||
} else {
|
} else {
|
||||||
#[cfg(feature = "plugins")]
|
#[cfg(feature = "plugins")]
|
||||||
@ -1020,8 +1013,8 @@ impl Server {
|
|||||||
let rs = plugin_manager.execute_event(
|
let rs = plugin_manager.execute_event(
|
||||||
&ecs_world,
|
&ecs_world,
|
||||||
&plugin_api::event::ChatCommandEvent {
|
&plugin_api::event::ChatCommandEvent {
|
||||||
command: kwd.clone(),
|
command: name.clone(),
|
||||||
command_args: args.split(' ').map(|x| x.to_owned()).collect(),
|
command_args: args.clone(),
|
||||||
player: plugin_api::event::Player { id: uid },
|
player: plugin_api::event::Player { id: uid },
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -1035,7 +1028,7 @@ impl Server {
|
|||||||
format!(
|
format!(
|
||||||
"Unknown command '/{}'.\nType '/help' for available \
|
"Unknown command '/{}'.\nType '/help' for available \
|
||||||
commands",
|
commands",
|
||||||
kwd
|
name
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -1059,7 +1052,7 @@ impl Server {
|
|||||||
comp::ChatType::CommandError,
|
comp::ChatType::CommandError,
|
||||||
format!(
|
format!(
|
||||||
"Error occurred while executing command '/{}'.\n{}",
|
"Error occurred while executing command '/{}'.\n{}",
|
||||||
kwd, e
|
name, e
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -1068,7 +1061,7 @@ impl Server {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!(?e, "Can't execute command {} {}", kwd, args);
|
error!(?e, "Can't execute command {} {:?}", name, args);
|
||||||
self.notify_client(
|
self.notify_client(
|
||||||
entity,
|
entity,
|
||||||
ServerGeneral::server_msg(
|
ServerGeneral::server_msg(
|
||||||
@ -1076,7 +1069,7 @@ impl Server {
|
|||||||
format!(
|
format!(
|
||||||
"Internal error while executing '/{}'.\nContact the server \
|
"Internal error while executing '/{}'.\nContact the server \
|
||||||
administrator",
|
administrator",
|
||||||
kwd
|
name
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -29,12 +29,7 @@ impl Sys {
|
|||||||
if player.is_some() {
|
if player.is_some() {
|
||||||
match validate_chat_msg(&message) {
|
match validate_chat_msg(&message) {
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
if let Some(message) = message.strip_prefix('/') {
|
if let Some(from) = uids.get(entity) {
|
||||||
if !message.is_empty() {
|
|
||||||
let argv = String::from(message);
|
|
||||||
server_emitter.emit(ServerEvent::ChatCmd(entity, argv));
|
|
||||||
}
|
|
||||||
} else if let Some(from) = uids.get(entity) {
|
|
||||||
const CHAT_MODE_DEFAULT: &ChatMode = &ChatMode::default();
|
const CHAT_MODE_DEFAULT: &ChatMode = &ChatMode::default();
|
||||||
let mode = chat_modes.get(entity).unwrap_or(CHAT_MODE_DEFAULT);
|
let mode = chat_modes.get(entity).unwrap_or(CHAT_MODE_DEFAULT);
|
||||||
// Send chat message
|
// Send chat message
|
||||||
@ -52,6 +47,11 @@ impl Sys {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
ClientGeneral::Command(name, args) => {
|
||||||
|
if player.is_some() {
|
||||||
|
server_emitter.emit(ServerEvent::ChatCmd(entity, name, args));
|
||||||
|
}
|
||||||
|
},
|
||||||
ClientGeneral::Terminate => {
|
ClientGeneral::Terminate => {
|
||||||
debug!(?entity, "Client send message to terminate session");
|
debug!(?entity, "Client send message to terminate session");
|
||||||
server_emitter.emit(ServerEvent::ClientDisconnect(
|
server_emitter.emit(ServerEvent::ClientDisconnect(
|
||||||
|
@ -78,6 +78,7 @@ backtrace = "0.3.40"
|
|||||||
bincode = "1.3.1"
|
bincode = "1.3.1"
|
||||||
chrono = { version = "0.4.9", features = ["serde"] }
|
chrono = { version = "0.4.9", features = ["serde"] }
|
||||||
cpal = "0.13"
|
cpal = "0.13"
|
||||||
|
comma = "0.1"
|
||||||
copy_dir = "0.1.2"
|
copy_dir = "0.1.2"
|
||||||
crossbeam-utils = "0.8.1"
|
crossbeam-utils = "0.8.1"
|
||||||
crossbeam-channel = "0.5"
|
crossbeam-channel = "0.5"
|
||||||
|
@ -168,6 +168,7 @@ pub struct State {
|
|||||||
pub enum Event {
|
pub enum Event {
|
||||||
TabCompletionStart(String),
|
TabCompletionStart(String),
|
||||||
SendMessage(String),
|
SendMessage(String),
|
||||||
|
SendCommand(String, Vec<String>),
|
||||||
Focus(Id),
|
Focus(Id),
|
||||||
ChangeChatTab(Option<usize>),
|
ChangeChatTab(Option<usize>),
|
||||||
ShowChatTabSettings(usize),
|
ShowChatTabSettings(usize),
|
||||||
@ -645,8 +646,18 @@ impl<'a> Widget for Chat<'a> {
|
|||||||
s.history.truncate(self.history_max);
|
s.history.truncate(self.history_max);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
if let Some(msg) = msg.strip_prefix('/') {
|
||||||
|
match msg.parse::<comma::Command>() {
|
||||||
|
Ok(cmd) => events.push(Event::SendCommand(cmd.name, cmd.arguments)),
|
||||||
|
Err(err) => self.new_messages.push_back(ChatMsg {
|
||||||
|
chat_type: ChatType::CommandError,
|
||||||
|
message: err.to_string(),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
events.push(Event::SendMessage(msg));
|
events.push(Event::SendMessage(msg));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
events
|
events
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -375,6 +375,7 @@ pub struct HudInfo {
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
SendMessage(String),
|
SendMessage(String),
|
||||||
|
SendCommand(String, Vec<String>),
|
||||||
|
|
||||||
CharacterSelection,
|
CharacterSelection,
|
||||||
UseSlot {
|
UseSlot {
|
||||||
@ -2722,6 +2723,9 @@ impl Hud {
|
|||||||
chat::Event::SendMessage(message) => {
|
chat::Event::SendMessage(message) => {
|
||||||
events.push(Event::SendMessage(message));
|
events.push(Event::SendMessage(message));
|
||||||
},
|
},
|
||||||
|
chat::Event::SendCommand(name, args) => {
|
||||||
|
events.push(Event::SendCommand(name, args));
|
||||||
|
},
|
||||||
chat::Event::Focus(focus_id) => {
|
chat::Event::Focus(focus_id) => {
|
||||||
self.to_focus = Some(Some(focus_id));
|
self.to_focus = Some(Some(focus_id));
|
||||||
},
|
},
|
||||||
|
@ -1032,6 +1032,9 @@ impl PlayState for SessionState {
|
|||||||
// TODO: Handle result
|
// TODO: Handle result
|
||||||
self.client.borrow_mut().send_chat(msg);
|
self.client.borrow_mut().send_chat(msg);
|
||||||
},
|
},
|
||||||
|
HudEvent::SendCommand(name, args) => {
|
||||||
|
self.client.borrow_mut().send_command(name, args);
|
||||||
|
},
|
||||||
HudEvent::CharacterSelection => {
|
HudEvent::CharacterSelection => {
|
||||||
self.client.borrow_mut().request_remove_character()
|
self.client.borrow_mut().request_remove_character()
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user