mirror of
https://github.com/Pumpkin-MC/Pumpkin.git
synced 2026-08-31 08:22:33 +00:00
Setup Base for Velocity (Proxy)
This commit is contained in:
23
Cargo.lock
generated
23
Cargo.lock
generated
@@ -312,6 +312,7 @@ dependencies = [
|
||||
"block-buffer 0.10.4",
|
||||
"const-oid",
|
||||
"crypto-common 0.1.6",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -581,6 +582,15 @@ version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "http"
|
||||
version = "1.1.0"
|
||||
@@ -1186,6 +1196,7 @@ dependencies = [
|
||||
"crossbeam-channel",
|
||||
"dhat",
|
||||
"digest 0.11.0-pre.9",
|
||||
"hmac",
|
||||
"image",
|
||||
"log",
|
||||
"mio",
|
||||
@@ -1206,6 +1217,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha1",
|
||||
"sha2",
|
||||
"simple_logger",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
@@ -1635,6 +1647,17 @@ dependencies = [
|
||||
"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]]
|
||||
name = "signature"
|
||||
version = "2.2.0"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
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_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::*;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use bytes::BytesMut;
|
||||
use pumpkin_macros::packet;
|
||||
|
||||
use crate::{
|
||||
@@ -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()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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},
|
||||
};
|
||||
|
||||
@@ -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 {
|
||||
@@ -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 {
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
@@ -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,
|
||||
}
|
||||
@@ -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(),
|
||||
|
||||
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 config;
|
||||
pub mod entity;
|
||||
pub mod proxy;
|
||||
pub mod rcon;
|
||||
pub mod server;
|
||||
pub mod util;
|
||||
@@ -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 || {
|
||||
|
||||
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.")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user