Skip to content

Commit

Permalink
Setup Base for Velocity (Proxy)
Browse files Browse the repository at this point in the history
  • Loading branch information
Snowiiii committed Aug 15, 2024
1 parent 333bf64 commit ceb718d
Show file tree
Hide file tree
Showing 14 changed files with 180 additions and 8 deletions.
23 changes: 23 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ and customizable experience. It prioritizes performance and player enjoyment whi
- [ ] Player Inventory
- [x] Player Combat
- Server
- [ ] Query
- [x] RCON
- [x] Inventories
- [x] Chat
Expand Down
2 changes: 1 addition & 1 deletion pumpkin-protocol/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ serde = { version = "1.0", features = ["derive"] }
# to parse strings to json responses
serde_json = "1.0"

flate2 = "1.0.30"
flate2 = "1.0.31"

thiserror = "1.0.63"
log = "0.4"
Expand Down
5 changes: 5 additions & 0 deletions pumpkin-protocol/src/bytebuf/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,11 @@ impl ByteBuffer {
pub fn copy_to_bytes(&mut self, len: usize) -> bytes::Bytes {
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]) {
self.buffer.put_slice(src)
}
Expand Down
22 changes: 22 additions & 0 deletions pumpkin-protocol/src/client/login/c_plugin_request.rs
Original file line number Diff line number Diff line change
@@ -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,
}
}
}
2 changes: 2 additions & 0 deletions pumpkin-protocol/src/client/login/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
mod c_encryption_request;
mod c_login_disconnect;
mod c_login_success;
mod c_plugin_request;
mod c_set_compression;

pub use c_encryption_request::*;
pub use c_login_disconnect::*;
pub use c_login_success::*;
pub use c_plugin_request::*;
pub use c_set_compression::*;
9 changes: 5 additions & 4 deletions pumpkin-protocol/src/server/login/s_plugin_response.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use bytes::BytesMut;
use pumpkin_macros::packet;

use crate::{
Expand All @@ -6,18 +7,18 @@ use crate::{
};

#[packet(0x02)]
pub struct SLoginPluginResponse<'a> {
pub struct SLoginPluginResponse {
pub message_id: VarInt,
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> {
Ok(Self {
message_id: bytebuf.get_var_int(),
successful: bytebuf.get_bool(),
data: None, // TODO
data: bytebuf.get_option(|v| v.get_slice()),
})
}
}
4 changes: 4 additions & 0 deletions pumpkin/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ reqwest = { version = "0.12.5", features = ["json"]}
sha1 = "0.10.6"
digest = "=0.11.0-pre.9"

# velocity en
hmac = "0.12.1"
sha2 = "0.10.8"

thiserror = "1.0.63"

# icon loading
Expand Down
19 changes: 18 additions & 1 deletion pumpkin/src/client/client_packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use sha1::{Digest, Sha1};
use crate::{
client::authentication::{self, GameProfile},
entity::player::{ChatMode, Hand},
proxy::velocity::velocity_login,
server::{Server, CURRENT_MC_VERSION},
};

Expand All @@ -34,6 +35,7 @@ use super::{
/// Implements the `Client` Packets
impl Client {
pub fn handle_handshake(&mut self, _server: &mut Server, handshake: SHandShake) {
dbg!("handshake");
self.protocol_version = handshake.protocol_version.0;
self.connection_state = handshake.next_state;
if self.connection_state == ConnectionState::Login {
Expand All @@ -56,9 +58,17 @@ impl Client {
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) {
// TODO: do basic name validation
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
// TODO: make offline uuid
self.gameprofile = Some(GameProfile {
Expand All @@ -67,6 +77,13 @@ impl Client {
properties: vec![],
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
let verify_token: [u8; 4] = rand::random();
Expand Down
6 changes: 5 additions & 1 deletion pumpkin/src/config/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
use std::path::Path;

use auth_config::AuthenticationConfig;
use proxy::ProxyConfig;
use resource_pack::ResourcePackConfig;
use serde::{Deserialize, Serialize};

use crate::{entity::player::GameMode, server::Difficulty};

pub mod auth_config;
pub mod proxy;
pub mod resource_pack;

/// Current Config version of the Base Config
Expand All @@ -17,10 +19,11 @@ const CURRENT_BASE_VERSION: &str = "1.0.0";
/// This also allows you get some Performance or Resource boosts.
/// Important: The Configuration should match Vanilla by default
pub struct AdvancedConfiguration {
pub commands: CommandsConfig,
pub proxy: ProxyConfig,
pub authentication: AuthenticationConfig,
pub packet_compression: CompressionConfig,
pub resource_pack: ResourcePackConfig,
pub commands: CommandsConfig,
pub rcon: RCONConfig,
pub pvp: PVPConfig,
}
Expand Down Expand Up @@ -107,6 +110,7 @@ impl Default for CompressionConfig {
impl Default for AdvancedConfiguration {
fn default() -> Self {
Self {
proxy: ProxyConfig::default(),
authentication: AuthenticationConfig::default(),
commands: CommandsConfig::default(),
packet_compression: CompressionConfig::default(),
Expand Down
22 changes: 22 additions & 0 deletions pumpkin/src/config/proxy.rs
Original file line number Diff line number Diff line change
@@ -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(),
}
}
}
3 changes: 2 additions & 1 deletion pumpkin/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub mod client;
pub mod commands;
pub mod config;
pub mod entity;
pub mod proxy;
pub mod rcon;
pub mod server;
pub mod util;
Expand Down Expand Up @@ -81,7 +82,7 @@ fn main() -> io::Result<()> {

let mut server = Server::new((basic_config, advanced_configuration));
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 {
thread::spawn(move || {
Expand Down
1 change: 1 addition & 0 deletions pumpkin/src/proxy/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod velocity;
69 changes: 69 additions & 0 deletions pumpkin/src/proxy/velocity.rs
Original file line number Diff line number Diff line change
@@ -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.")
}
}

0 comments on commit ceb718d

Please sign in to comment.