Setup Base for Velocity (Proxy)
This commit is contained in:
parent
333bf64235
commit
ceb718d475
23
Cargo.lock
generated
23
Cargo.lock
generated
@ -312,6 +312,7 @@ dependencies = [
|
|||||||
"block-buffer 0.10.4",
|
"block-buffer 0.10.4",
|
||||||
"const-oid",
|
"const-oid",
|
||||||
"crypto-common 0.1.6",
|
"crypto-common 0.1.6",
|
||||||
|
"subtle",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -581,6 +582,15 @@ version = "0.3.9"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hmac"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
|
||||||
|
dependencies = [
|
||||||
|
"digest 0.10.7",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http"
|
name = "http"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@ -1186,6 +1196,7 @@ dependencies = [
|
|||||||
"crossbeam-channel",
|
"crossbeam-channel",
|
||||||
"dhat",
|
"dhat",
|
||||||
"digest 0.11.0-pre.9",
|
"digest 0.11.0-pre.9",
|
||||||
|
"hmac",
|
||||||
"image",
|
"image",
|
||||||
"log",
|
"log",
|
||||||
"mio",
|
"mio",
|
||||||
@ -1206,6 +1217,7 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sha1",
|
"sha1",
|
||||||
|
"sha2",
|
||||||
"simple_logger",
|
"simple_logger",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
@ -1635,6 +1647,17 @@ dependencies = [
|
|||||||
"digest 0.10.7",
|
"digest 0.10.7",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sha2"
|
||||||
|
version = "0.10.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"cpufeatures",
|
||||||
|
"digest 0.10.7",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signature"
|
name = "signature"
|
||||||
version = "2.2.0"
|
version = "2.2.0"
|
||||||
|
|||||||
@ -56,6 +56,7 @@ and customizable experience. It prioritizes performance and player enjoyment whi
|
|||||||
- [ ] Player Inventory
|
- [ ] Player Inventory
|
||||||
- [x] Player Combat
|
- [x] Player Combat
|
||||||
- Server
|
- Server
|
||||||
|
- [ ] Query
|
||||||
- [x] RCON
|
- [x] RCON
|
||||||
- [x] Inventories
|
- [x] Inventories
|
||||||
- [x] Chat
|
- [x] Chat
|
||||||
|
|||||||
@ -16,7 +16,7 @@ serde = { version = "1.0", features = ["derive"] }
|
|||||||
# to parse strings to json responses
|
# to parse strings to json responses
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
|
||||||
flate2 = "1.0.30"
|
flate2 = "1.0.31"
|
||||||
|
|
||||||
thiserror = "1.0.63"
|
thiserror = "1.0.63"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
|||||||
@ -295,6 +295,11 @@ impl ByteBuffer {
|
|||||||
pub fn copy_to_bytes(&mut self, len: usize) -> bytes::Bytes {
|
pub fn copy_to_bytes(&mut self, len: usize) -> bytes::Bytes {
|
||||||
self.buffer.copy_to_bytes(len)
|
self.buffer.copy_to_bytes(len)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn copy_to_slice(&mut self, dst: &mut [u8]) {
|
||||||
|
self.buffer.copy_to_slice(dst)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn put_slice(&mut self, src: &[u8]) {
|
pub fn put_slice(&mut self, src: &[u8]) {
|
||||||
self.buffer.put_slice(src)
|
self.buffer.put_slice(src)
|
||||||
}
|
}
|
||||||
|
|||||||
22
pumpkin-protocol/src/client/login/c_plugin_request.rs
Normal file
22
pumpkin-protocol/src/client/login/c_plugin_request.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
use pumpkin_macros::packet;
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
|
use crate::VarInt;
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
#[packet(0x04)]
|
||||||
|
pub struct CLoginPluginRequest<'a> {
|
||||||
|
message_id: VarInt,
|
||||||
|
channel: &'a str,
|
||||||
|
data: &'a [u8],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> CLoginPluginRequest<'a> {
|
||||||
|
pub fn new(message_id: VarInt, channel: &'a str, data: &'a [u8]) -> Self {
|
||||||
|
Self {
|
||||||
|
message_id,
|
||||||
|
channel,
|
||||||
|
data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,9 +1,11 @@
|
|||||||
mod c_encryption_request;
|
mod c_encryption_request;
|
||||||
mod c_login_disconnect;
|
mod c_login_disconnect;
|
||||||
mod c_login_success;
|
mod c_login_success;
|
||||||
|
mod c_plugin_request;
|
||||||
mod c_set_compression;
|
mod c_set_compression;
|
||||||
|
|
||||||
pub use c_encryption_request::*;
|
pub use c_encryption_request::*;
|
||||||
pub use c_login_disconnect::*;
|
pub use c_login_disconnect::*;
|
||||||
pub use c_login_success::*;
|
pub use c_login_success::*;
|
||||||
|
pub use c_plugin_request::*;
|
||||||
pub use c_set_compression::*;
|
pub use c_set_compression::*;
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
use bytes::BytesMut;
|
||||||
use pumpkin_macros::packet;
|
use pumpkin_macros::packet;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -6,18 +7,18 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
#[packet(0x02)]
|
#[packet(0x02)]
|
||||||
pub struct SLoginPluginResponse<'a> {
|
pub struct SLoginPluginResponse {
|
||||||
pub message_id: VarInt,
|
pub message_id: VarInt,
|
||||||
pub successful: bool,
|
pub successful: bool,
|
||||||
pub data: Option<&'a [u8]>,
|
pub data: Option<BytesMut>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ServerPacket for SLoginPluginResponse<'a> {
|
impl ServerPacket for SLoginPluginResponse {
|
||||||
fn read(bytebuf: &mut ByteBuffer) -> Result<Self, DeserializerError> {
|
fn read(bytebuf: &mut ByteBuffer) -> Result<Self, DeserializerError> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
message_id: bytebuf.get_var_int(),
|
message_id: bytebuf.get_var_int(),
|
||||||
successful: bytebuf.get_bool(),
|
successful: bytebuf.get_bool(),
|
||||||
data: None, // TODO
|
data: bytebuf.get_option(|v| v.get_slice()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,6 +43,10 @@ reqwest = { version = "0.12.5", features = ["json"]}
|
|||||||
sha1 = "0.10.6"
|
sha1 = "0.10.6"
|
||||||
digest = "=0.11.0-pre.9"
|
digest = "=0.11.0-pre.9"
|
||||||
|
|
||||||
|
# velocity en
|
||||||
|
hmac = "0.12.1"
|
||||||
|
sha2 = "0.10.8"
|
||||||
|
|
||||||
thiserror = "1.0.63"
|
thiserror = "1.0.63"
|
||||||
|
|
||||||
# icon loading
|
# icon loading
|
||||||
|
|||||||
@ -22,6 +22,7 @@ use sha1::{Digest, Sha1};
|
|||||||
use crate::{
|
use crate::{
|
||||||
client::authentication::{self, GameProfile},
|
client::authentication::{self, GameProfile},
|
||||||
entity::player::{ChatMode, Hand},
|
entity::player::{ChatMode, Hand},
|
||||||
|
proxy::velocity::velocity_login,
|
||||||
server::{Server, CURRENT_MC_VERSION},
|
server::{Server, CURRENT_MC_VERSION},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -34,6 +35,7 @@ use super::{
|
|||||||
/// Implements the `Client` Packets
|
/// Implements the `Client` Packets
|
||||||
impl Client {
|
impl Client {
|
||||||
pub fn handle_handshake(&mut self, _server: &mut Server, handshake: SHandShake) {
|
pub fn handle_handshake(&mut self, _server: &mut Server, handshake: SHandShake) {
|
||||||
|
dbg!("handshake");
|
||||||
self.protocol_version = handshake.protocol_version.0;
|
self.protocol_version = handshake.protocol_version.0;
|
||||||
self.connection_state = handshake.next_state;
|
self.connection_state = handshake.next_state;
|
||||||
if self.connection_state == ConnectionState::Login {
|
if self.connection_state == ConnectionState::Login {
|
||||||
@ -56,9 +58,17 @@ impl Client {
|
|||||||
self.close();
|
self.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_valid_player_name(name: &str) -> bool {
|
||||||
|
name.len() <= 16 && name.chars().all(|c| c > 32 as char && c < 127 as char)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn handle_login_start(&mut self, server: &mut Server, login_start: SLoginStart) {
|
pub fn handle_login_start(&mut self, server: &mut Server, login_start: SLoginStart) {
|
||||||
// TODO: do basic name validation
|
|
||||||
dbg!("login start");
|
dbg!("login start");
|
||||||
|
|
||||||
|
if !Self::is_valid_player_name(&login_start.name) {
|
||||||
|
self.kick("Invalid characters in username");
|
||||||
|
return;
|
||||||
|
}
|
||||||
// default game profile, when no online mode
|
// default game profile, when no online mode
|
||||||
// TODO: make offline uuid
|
// TODO: make offline uuid
|
||||||
self.gameprofile = Some(GameProfile {
|
self.gameprofile = Some(GameProfile {
|
||||||
@ -67,6 +77,13 @@ impl Client {
|
|||||||
properties: vec![],
|
properties: vec![],
|
||||||
profile_actions: None,
|
profile_actions: None,
|
||||||
});
|
});
|
||||||
|
let proxy = &server.advanced_config.proxy;
|
||||||
|
if proxy.enabled {
|
||||||
|
if proxy.velocity.enabled {
|
||||||
|
velocity_login(self)
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: check config for encryption
|
// TODO: check config for encryption
|
||||||
let verify_token: [u8; 4] = rand::random();
|
let verify_token: [u8; 4] = rand::random();
|
||||||
|
|||||||
@ -1,12 +1,14 @@
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use auth_config::AuthenticationConfig;
|
use auth_config::AuthenticationConfig;
|
||||||
|
use proxy::ProxyConfig;
|
||||||
use resource_pack::ResourcePackConfig;
|
use resource_pack::ResourcePackConfig;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{entity::player::GameMode, server::Difficulty};
|
use crate::{entity::player::GameMode, server::Difficulty};
|
||||||
|
|
||||||
pub mod auth_config;
|
pub mod auth_config;
|
||||||
|
pub mod proxy;
|
||||||
pub mod resource_pack;
|
pub mod resource_pack;
|
||||||
|
|
||||||
/// Current Config version of the Base Config
|
/// Current Config version of the Base Config
|
||||||
@ -17,10 +19,11 @@ const CURRENT_BASE_VERSION: &str = "1.0.0";
|
|||||||
/// This also allows you get some Performance or Resource boosts.
|
/// This also allows you get some Performance or Resource boosts.
|
||||||
/// Important: The Configuration should match Vanilla by default
|
/// Important: The Configuration should match Vanilla by default
|
||||||
pub struct AdvancedConfiguration {
|
pub struct AdvancedConfiguration {
|
||||||
pub commands: CommandsConfig,
|
pub proxy: ProxyConfig,
|
||||||
pub authentication: AuthenticationConfig,
|
pub authentication: AuthenticationConfig,
|
||||||
pub packet_compression: CompressionConfig,
|
pub packet_compression: CompressionConfig,
|
||||||
pub resource_pack: ResourcePackConfig,
|
pub resource_pack: ResourcePackConfig,
|
||||||
|
pub commands: CommandsConfig,
|
||||||
pub rcon: RCONConfig,
|
pub rcon: RCONConfig,
|
||||||
pub pvp: PVPConfig,
|
pub pvp: PVPConfig,
|
||||||
}
|
}
|
||||||
@ -107,6 +110,7 @@ impl Default for CompressionConfig {
|
|||||||
impl Default for AdvancedConfiguration {
|
impl Default for AdvancedConfiguration {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
proxy: ProxyConfig::default(),
|
||||||
authentication: AuthenticationConfig::default(),
|
authentication: AuthenticationConfig::default(),
|
||||||
commands: CommandsConfig::default(),
|
commands: CommandsConfig::default(),
|
||||||
packet_compression: CompressionConfig::default(),
|
packet_compression: CompressionConfig::default(),
|
||||||
|
|||||||
22
pumpkin/src/config/proxy.rs
Normal file
22
pumpkin/src/config/proxy.rs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize, Default)]
|
||||||
|
pub struct ProxyConfig {
|
||||||
|
pub enabled: bool,
|
||||||
|
pub velocity: VelocityConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub struct VelocityConfig {
|
||||||
|
pub enabled: bool,
|
||||||
|
pub secret: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for VelocityConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
enabled: false,
|
||||||
|
secret: "".into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -18,6 +18,7 @@ pub mod client;
|
|||||||
pub mod commands;
|
pub mod commands;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod entity;
|
pub mod entity;
|
||||||
|
pub mod proxy;
|
||||||
pub mod rcon;
|
pub mod rcon;
|
||||||
pub mod server;
|
pub mod server;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
@ -81,7 +82,7 @@ fn main() -> io::Result<()> {
|
|||||||
|
|
||||||
let mut server = Server::new((basic_config, advanced_configuration));
|
let mut server = Server::new((basic_config, advanced_configuration));
|
||||||
log::info!("Started Server took {}ms", time.elapsed().as_millis());
|
log::info!("Started Server took {}ms", time.elapsed().as_millis());
|
||||||
log::info!("You now can connect to the server");
|
log::info!("You now can connect to the server, Listening on {}", addr);
|
||||||
|
|
||||||
if use_console {
|
if use_console {
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
|
|||||||
1
pumpkin/src/proxy/mod.rs
Normal file
1
pumpkin/src/proxy/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
pub mod velocity;
|
||||||
69
pumpkin/src/proxy/velocity.rs
Normal file
69
pumpkin/src/proxy/velocity.rs
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
use std::net::SocketAddr;
|
||||||
|
|
||||||
|
use bytes::{BufMut, BytesMut};
|
||||||
|
use hmac::{Hmac, Mac};
|
||||||
|
use pumpkin_protocol::{
|
||||||
|
bytebuf::ByteBuffer, client::login::CLoginPluginRequest, server::login::SLoginPluginResponse,
|
||||||
|
};
|
||||||
|
use sha2::Sha256;
|
||||||
|
|
||||||
|
use crate::{client::Client, config::proxy::VelocityConfig};
|
||||||
|
|
||||||
|
type HmacSha256 = Hmac<Sha256>;
|
||||||
|
|
||||||
|
const MAX_SUPPORTED_FORWARDING_VERSION: i32 = 4;
|
||||||
|
const PLAYER_INFO_CHANNEL: &str = "velocity:player_info";
|
||||||
|
|
||||||
|
pub fn velocity_login(client: &mut Client) {
|
||||||
|
let velocity_message_id: i32 = 0;
|
||||||
|
|
||||||
|
let mut buf = BytesMut::new();
|
||||||
|
buf.put_u8(MAX_SUPPORTED_FORWARDING_VERSION as u8);
|
||||||
|
client.send_packet(&CLoginPluginRequest::new(
|
||||||
|
velocity_message_id.into(),
|
||||||
|
PLAYER_INFO_CHANNEL,
|
||||||
|
&buf,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check_integrity(data: (&[u8], &[u8]), secret: String) -> bool {
|
||||||
|
let (signature, data_without_signature) = data;
|
||||||
|
let mut mac =
|
||||||
|
HmacSha256::new_from_slice(secret.as_bytes()).expect("HMAC can take key of any size");
|
||||||
|
mac.update(data_without_signature);
|
||||||
|
mac.verify_slice(signature).is_ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn receive_plugin_response(
|
||||||
|
client: &mut Client,
|
||||||
|
config: VelocityConfig,
|
||||||
|
response: SLoginPluginResponse,
|
||||||
|
) {
|
||||||
|
dbg!("velocity response");
|
||||||
|
if let Some(data) = response.data {
|
||||||
|
let (signature, data_without_signature) = data.split_at(32);
|
||||||
|
|
||||||
|
if !check_integrity((signature, data_without_signature), config.secret) {
|
||||||
|
client.kick("Unable to verify player details");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let mut buf = ByteBuffer::new(BytesMut::new());
|
||||||
|
buf.put_slice(data_without_signature);
|
||||||
|
|
||||||
|
// check velocity version
|
||||||
|
let version = buf.get_var_int();
|
||||||
|
let version = version.0;
|
||||||
|
if version > MAX_SUPPORTED_FORWARDING_VERSION {
|
||||||
|
client.kick(&format!(
|
||||||
|
"Unsupported forwarding version {version}, Max: {MAX_SUPPORTED_FORWARDING_VERSION}"
|
||||||
|
));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// TODO: no unwrap
|
||||||
|
let addr: SocketAddr = buf.get_string().unwrap().parse().unwrap();
|
||||||
|
client.address = addr;
|
||||||
|
todo!()
|
||||||
|
} else {
|
||||||
|
client.kick("This server requires you to connect with Velocity.")
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user