Apply suggested rustfmt and clippy changes.

master
James T. Martin 2020-07-26 15:15:52 -07:00
parent 5302c04fa4
commit bdeb8bb6a4
Signed by: james
GPG Key ID: 4B7F3DA9351E577C
17 changed files with 141 additions and 113 deletions

8
rustfmt.toml Normal file
View File

@ -0,0 +1,8 @@
format_code_in_doc_comments = true
match_block_trailing_comma = true
max_width = 120
newline_style = "Native"
normalize_comments = true
normalize_doc_attributes = true
use_try_shorthand = true
wrap_comments = true

View File

@ -1,3 +1,4 @@
#![allow(incomplete_features)]
#![feature(const_generics)]
#![feature(never_type)]
@ -9,23 +10,30 @@ use crate::net::protocol::state::handshake::Handshake;
use crate::net::protocol::state::login::Login;
use crate::net::protocol::state::play::Play;
use crate::net::protocol::state::status::Status;
use tokio::net::{TcpListener, TcpStream};
use std::io;
use std::net::IpAddr;
use tokio::net::{TcpListener, TcpStream};
#[tokio::main]
async fn main() -> io::Result<()> {
use clap::{App, load_yaml};
use clap::{load_yaml, App};
let yaml = load_yaml!("cli.yml");
let args = App::from_yaml(yaml).get_matches();
let host: IpAddr = args.value_of("host").unwrap_or("::").parse()
let host: IpAddr = args
.value_of("host")
.unwrap_or("::")
.parse()
.expect("Invalid host IP address.");
let port: u16 = args.value_of("port").unwrap_or("25565").parse()
let port: u16 = args
.value_of("port")
.unwrap_or("25565")
.parse()
.expect("Port must be an integer between 1 an 65535.");
let listener = TcpListener::bind((host, port)).await
.expect(&format!("Failed to bind to {}:{}.", host, port));
let listener = TcpListener::bind((host, port))
.await
.unwrap_or_else(|_| panic!("Failed to bind to {}:{}.", host, port));
listen(listener).await;
@ -39,7 +47,7 @@ async fn listen(mut listener: TcpListener) {
Err(e) => {
eprintln!("Failed to accept client: {:?}", e);
continue;
}
},
};
tokio::spawn(accept_connection(socket));
@ -51,8 +59,12 @@ async fn accept_connection(socket: TcpStream) {
eprintln!("Client connected.");
match interact_handshake(con).await {
Err(err) => { eprintln!("Client disconnected with error: {:?}", err); },
Ok(_) => { eprintln!("Client disconnected without error."); }
Err(err) => {
eprintln!("Client disconnected with error: {:?}", err);
},
Ok(_) => {
eprintln!("Client disconnected without error.");
},
}
}
@ -69,9 +81,9 @@ async fn interact_handshake(mut con: Connection<Handshake>) -> io::Result<()> {
match handshake.next_state {
Status => interact_status(con.into_status()).await,
Login => interact_login(con.into_login()).await
Login => interact_login(con.into_login()).await,
}
}
},
}
}
@ -92,15 +104,16 @@ async fn interact_status(mut con: Connection<Status>) -> io::Result<()> {
online: 0,
sample: Vec::new(),
},
description: Chat { text: "Hello, world!".to_string() },
description: Chat {
text: "Hello, world!".to_string(),
},
favicon: None,
}
})).await?;
},
}))
.await?;
},
Serverbound::Ping(ping) => {
con.write(&Clientbound::Pong(Pong {
payload: ping.payload
})).await?;
con.write(&Clientbound::Pong(Pong { payload: ping.payload })).await?;
// The status ping is now over so the server ends the connection.
return Ok(());
@ -113,30 +126,35 @@ async fn interact_login(mut con: Connection<Login>) -> io::Result<()> {
use crate::net::protocol::state::login::*;
let name = match con.read().await? {
Serverbound::LoginStart(login_start) => {
login_start.name
},
Serverbound::LoginStart(login_start) => login_start.name,
_ => {
con.write(&Clientbound::Disconnect(Disconnect {
reason: Chat { text: "Unexpected packet (expected Login Start).".to_string() }
})).await?;
reason: Chat {
text: "Unexpected packet (expected Login Start).".to_string(),
},
}))
.await?;
return mk_err("Unexpected packet (expected Login Start).");
}
},
};
#[cfg(feature = "encryption")]
{
use rand::Rng;
use rand::rngs::OsRng;
use rsa::{RSAPrivateKey, PaddingScheme};
use rand::Rng;
use rsa::{PaddingScheme, RSAPrivateKey};
use std::fs::File;
use std::io::Read;
let mut public_key = Vec::new();
File::open("private/pub.der").expect("missing public key").read_to_end(&mut public_key)?;
File::open("private/pub.der")
.expect("missing public key")
.read_to_end(&mut public_key)?;
let mut private_key = Vec::new();
File::open("private/priv.der").expect("missing private key").read_to_end(&mut private_key)?;
File::open("private/priv.der")
.expect("missing private key")
.read_to_end(&mut private_key)?;
let key = RSAPrivateKey::from_pkcs1(&private_key).expect("Invalid private key.");
@ -150,13 +168,14 @@ async fn interact_login(mut con: Connection<Login>) -> io::Result<()> {
server_id: server_id.to_string().into_boxed_str(),
public_key: public_key.clone().into_boxed_slice(),
verify_token: verify_token.clone().into_boxed_slice(),
})).await?;
}))
.await?;
let secret = match con.read().await? {
Serverbound::EncryptionResponse(encryption_response) => {
let token = key.decrypt(PaddingScheme::PKCS1v15Encrypt,
&encryption_response.verify_token)
.expect("Failed to decrypt verify token.");
let token = key
.decrypt(PaddingScheme::PKCS1v15Encrypt, &encryption_response.verify_token)
.expect("Failed to decrypt verify token.");
if token.as_slice() != verify_token.as_slice() {
return mk_err("Incorrect verify token.");
}
@ -166,7 +185,7 @@ async fn interact_login(mut con: Connection<Login>) -> io::Result<()> {
},
_ => {
return mk_err("Unexpected packet (expected Encryption Response).");
}
},
};
con = con.set_encryption(&secret).expect("Failed to set encryption.");
@ -175,7 +194,7 @@ async fn interact_login(mut con: Connection<Login>) -> io::Result<()> {
{
let server_hash = {
let server_hash_bytes = {
use sha1::{Sha1, Digest};
use sha1::{Digest, Sha1};
let mut hasher = Sha1::new();
hasher.update(server_id.as_bytes());
hasher.update(&secret);
@ -188,10 +207,19 @@ async fn interact_login(mut con: Connection<Login>) -> io::Result<()> {
use reqwest::Client;
println!("{:?}", Client::new().get("https://sessionserver.mojang.com/session/minecraft/hasJoined")
.header("Content-Type", "application/json")
.query(&[("username", name.clone()), ("serverId", server_hash.into_boxed_str())])
.send().await.expect("Request failed.").text().await.unwrap());
println!(
"{:?}",
Client::new()
.get("https://sessionserver.mojang.com/session/minecraft/hasJoined")
.header("Content-Type", "application/json")
.query(&[("username", name.clone()), ("serverId", server_hash.into_boxed_str())])
.send()
.await
.expect("Request failed.")
.text()
.await
.unwrap()
);
}
}
@ -201,7 +229,8 @@ async fn interact_login(mut con: Connection<Login>) -> io::Result<()> {
con.write(&Clientbound::LoginSuccess(LoginSuccess {
uuid: uuid::Uuid::nil(),
username: name,
})).await?;
}))
.await?;
interact_play(con.into_play()).await
}
@ -210,8 +239,11 @@ async fn interact_play(mut con: Connection<Play>) -> io::Result<()> {
use crate::net::protocol::state::play::*;
con.write(&Clientbound::Disconnect(Disconnect {
reason: Chat { text: "Goodbye!".to_string() }
})).await?;
reason: Chat {
text: "Goodbye!".to_string(),
},
}))
.await?;
Ok(())
}

View File

@ -1,15 +1,15 @@
mod packet_format;
mod stream;
use crate::net::connection::packet_format::PacketFormat;
use crate::net::connection::packet_format::default::DefaultPacketFormat;
use crate::net::connection::packet_format::PacketFormat;
use crate::net::connection::stream::Stream;
use crate::net::protocol::packet_map::PacketMap;
use crate::net::protocol::state::ProtocolState;
use crate::net::protocol::state::handshake::Handshake;
use crate::net::protocol::state::login::Login;
use crate::net::protocol::state::play::Play;
use crate::net::protocol::state::status::Status;
use crate::net::protocol::state::ProtocolState;
use std::io;
use std::marker::PhantomData;
use tokio::io::BufStream;
@ -48,6 +48,7 @@ impl<St: ProtocolState> Connection<St> {
}
}
#[allow(dead_code)]
pub fn into_disconnected(self) -> Connection<!> {
self.into_state()
}
@ -75,15 +76,16 @@ impl Connection<Login> {
#[cfg(feature = "compression")]
pub async fn set_compression(&mut self, threshold: Option<u32>) -> io::Result<()> {
use crate::net::connection::packet_format::compressed::CompressedPacketFormat;
use crate::net::serialize::VarInt;
use crate::net::protocol::state::login::{Clientbound, SetCompression};
use crate::net::serialize::VarInt;
// Tell the client about the new compression threshold,
// using a packet compressed with the old compression threshold.
self.write(&Clientbound::SetCompression(SetCompression {
// A negative threshold will disable compression.
threshold: VarInt(threshold.map(|x| x as i32).unwrap_or(-1)),
})).await?;
}))
.await?;
// Further packets will use the new compression threshold.
match threshold {
@ -92,19 +94,20 @@ impl Connection<Login> {
},
None => {
self.fmt = Box::new(DefaultPacketFormat);
}
},
}
Ok(())
}
/// WARNING: This function is not idempontent.
/// Calling it twice will result in the underlying stream getting encrypted twice.
/// Calling it twice will result in the underlying stream getting encrypted
/// twice.
#[cfg(feature = "encryption")]
pub fn set_encryption(self, secret: &[u8]) -> Result<Self, String> {
use cfb8::Cfb8;
use cfb8::stream_cipher::NewStreamCipher;
use crate::net::connection::stream::encrypted::EncryptedStream;
use cfb8::stream_cipher::NewStreamCipher;
use cfb8::Cfb8;
let cipher: Cfb8<aes::Aes128> = Cfb8::new_var(secret, secret).map_err(|err| err.to_string())?;

View File

@ -23,7 +23,7 @@ pub async fn read_varint(src: &mut Reader) -> io::Result<(usize, i32)> {
let mut acc = 0;
while num_read < 5 {
let byte = src.read_u8().await?;
acc |= ((byte & 0b01111111) as i32) << num_read * 7;
acc |= ((byte & 0b01111111) as i32) << (num_read * 7);
num_read += 1;

View File

@ -1,6 +1,5 @@
use crate::net::connection::packet_format::{read_varint, PacketFormat, Reader, Writer, MAX_PACKET_SIZE};
use async_trait::async_trait;
use crate::net::connection::packet_format::
{PacketFormat, Reader, Writer, MAX_PACKET_SIZE, read_varint};
use std::boxed::Box;
use std::io;
@ -10,9 +9,7 @@ pub struct CompressedPacketFormat {
impl CompressedPacketFormat {
pub fn new(threshold: usize) -> Self {
Self {
threshold: threshold,
}
Self { threshold }
}
}
@ -87,9 +84,10 @@ impl PacketFormat for CompressedPacketFormat {
// in case the output data ends up larger than the input data
// (e.g. due to the zlib header).
// FIXME: Further research to figure out the exact maximum capacity necessary.
// Perhaps you only need space for the header and the data itself can't get bigger?
// And what is the limit to how much bigger the data will get?
// Currently I don't actually know for a fact that this won't ever drop data.
// Perhaps you only need space for the header and the data itself can't get
// bigger? And what is the limit to how much bigger the data will
// get? Currently I don't actually know for a fact that this won't
// ever drop data.
let mut compressed = Vec::with_capacity(1024 + data.len());
Compress::new(flate2::Compression::best(), true)
.compress_vec(data, &mut compressed, FlushCompress::Finish)

View File

@ -1,6 +1,5 @@
use crate::net::connection::packet_format::{read_varint, PacketFormat, Reader, Writer, MAX_PACKET_SIZE};
use async_trait::async_trait;
use crate::net::connection::packet_format::
{PacketFormat, Reader, Writer, MAX_PACKET_SIZE, read_varint};
use std::boxed::Box;
use std::io;
@ -15,10 +14,8 @@ impl PacketFormat for DefaultPacketFormat {
if length > MAX_PACKET_SIZE as i32 {
return Err(io::Error::new(io::ErrorKind::Other, "Packet was too long.".to_string()));
}
let length = length as usize;
let mut buf = Vec::with_capacity(length);
buf.resize(length, 0);
let mut buf = vec![0; length as usize];
src.read_exact(buf.as_mut_slice()).await?;
Ok(buf.into_boxed_slice())

View File

@ -3,5 +3,5 @@ pub mod encrypted;
use tokio::io::{AsyncRead, AsyncWrite};
pub trait Stream: AsyncRead + AsyncWrite + Send + Unpin { }
impl<S: AsyncRead + AsyncWrite + Send + Unpin> Stream for S { }
pub trait Stream: AsyncRead + AsyncWrite + Send + Unpin {}
impl<S: AsyncRead + AsyncWrite + Send + Unpin> Stream for S {}

View File

@ -1,10 +1,10 @@
use aes::Aes128;
use cfb8::Cfb8;
use cfb8::stream_cipher::StreamCipher;
use crate::net::connection::stream::Stream;
use aes::Aes128;
use cfb8::stream_cipher::StreamCipher;
use cfb8::Cfb8;
use std::pin::Pin;
use std::task::Poll;
use std::task::Context;
use std::task::Poll;
use tokio::io::{AsyncRead, AsyncWrite, Result};
pub struct EncryptedStream {
@ -16,18 +16,18 @@ pub struct EncryptedStream {
impl EncryptedStream {
pub fn new(rw: Box<dyn Stream>, cipher: Cfb8<Aes128>) -> Self {
Self {
rw: rw,
cipher: cipher,
rw,
cipher,
write_buf: Vec::new(),
}
}
fn flush(&mut self, cx: &mut Context) -> Poll<Result<()>> {
// We don't know when the internal writer will be ready,
// so we have to coax it into returning "pending" and scheduling an interrupt for us.
// Either that, or we finish writing our buffer and flush.
// so we have to coax it into returning "pending" and scheduling an interrupt
// for us. Either that, or we finish writing our buffer and flush.
loop {
if self.write_buf.len() == 0 {
if self.write_buf.is_empty() {
break;
}
@ -37,7 +37,7 @@ impl EncryptedStream {
new_buf.copy_from_slice(&self.write_buf[length..]);
self.write_buf = new_buf;
},
other => return other.map(|x| x.map(|_| ()))
other => return other.map(|x| x.map(|_| ())),
}
}
@ -54,7 +54,7 @@ impl AsyncRead for EncryptedStream {
me.cipher.decrypt(&mut buf[..bytes]);
Poll::Ready(Ok(bytes))
},
other => other
other => other,
}
}
}
@ -79,10 +79,8 @@ impl AsyncWrite for EncryptedStream {
let me = Pin::into_inner(self);
match me.flush(cx) {
Poll::Ready(Ok(())) => {
Pin::new(&mut me.rw).poll_shutdown(cx)
},
other => other
Poll::Ready(Ok(())) => Pin::new(&mut me.rw).poll_shutdown(cx),
other => other,
}
}
}

View File

@ -1,3 +1,3 @@
pub mod packet_map;
pub mod packet;
pub mod packet_map;
pub mod state;

View File

@ -16,7 +16,7 @@ macro_rules! define_packets {
deser.read_eof()?;
Ok($name {
$(
$field: $field,
$field,
)*
})
}

View File

@ -13,7 +13,7 @@ impl PacketMap for ! {
}
fn write(&self, _ser: &mut impl PacketSerializer) {
match *self { }
match *self {}
}
}

View File

@ -25,5 +25,5 @@ macro_rules! define_state {
type Clientbound = $cb;
type Serverbound = $sb;
}
}
};
}

View File

@ -1,5 +1,5 @@
use crate::{define_packets, define_packet_maps, define_state};
use crate::net::serialize::{PacketReadable, PacketWritable, PacketDeserializer, PacketSerializer, VarInt};
use crate::net::serialize::{PacketDeserializer, PacketReadable, PacketSerializer, PacketWritable, VarInt};
use crate::{define_packet_maps, define_packets, define_state};
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum HandshakeNextState {
@ -14,7 +14,7 @@ impl PacketReadable for HandshakeNextState {
Ok(match deser.read::<VarInt>()?.into() {
1 => Status,
2 => Login,
n => return Err(format!("Invalid next protocol state in handshake: {}", n))
n => return Err(format!("Invalid next protocol state in handshake: {}", n)),
})
}
}

View File

@ -1,6 +1,6 @@
use crate::{define_packets, define_packet_maps, define_state};
use crate::net::chat::Chat;
use crate::net::serialize::{Rest, VarInt};
use crate::{define_packet_maps, define_packets, define_state};
use uuid::Uuid;
define_packets! {

View File

@ -1,5 +1,5 @@
use crate::{define_packets, define_packet_maps, define_state};
use crate::net::chat::Chat;
use crate::{define_packet_maps, define_packets, define_state};
// TODO: This protocol state isn't even close to entirely mapped.

View File

@ -1,6 +1,6 @@
use crate::{define_packets, define_packet_maps, define_state};
use crate::net::chat::Chat;
use crate::net::serialize::{PacketJson};
use crate::net::serialize::PacketJson;
use crate::{define_packet_maps, define_packets, define_state};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
@ -22,7 +22,7 @@ impl PacketJson for ResponsePlayersSample {}
pub struct ResponsePlayers {
pub max: u32,
pub online: u32,
pub sample: Vec<ResponsePlayersSample>
pub sample: Vec<ResponsePlayersSample>,
}
impl PacketJson for ResponsePlayers {}

View File

@ -1,5 +1,5 @@
use serde::Serialize;
use serde::de::DeserializeOwned;
use serde::Serialize;
use std::borrow::Borrow;
use std::convert::{From, Into};
use uuid::Uuid;
@ -38,11 +38,8 @@ pub struct VecPacketDeserializer<'a> {
}
impl VecPacketDeserializer<'_> {
pub fn new<'a>(data: &'a [u8]) -> VecPacketDeserializer<'a> {
VecPacketDeserializer {
data: data,
index: 0,
}
pub fn new(data: &[u8]) -> VecPacketDeserializer<'_> {
VecPacketDeserializer { data, index: 0 }
}
}
@ -92,7 +89,7 @@ impl PacketReadable for bool {
match value {
0x00 => Ok(false),
0x01 => Ok(true),
n => Err(format!("{:0X} is not a valid boolean.", n))
n => Err(format!("{:0X} is not a valid boolean.", n)),
}
}
}
@ -158,7 +155,7 @@ macro_rules! impl_varnum {
}
// Make space for the rest of the bits.
acc = acc << 7;
acc <<= 7;
}
Err(format!("VarNum was more than {} bytes.", $length))
@ -170,7 +167,7 @@ macro_rules! impl_varnum {
let mut value = self.0;
loop {
let mut temp = (value & 0b01111111) as u8;
value = value >> 7;
value >>= 7;
if value != 0 {
temp |= 0b10000000;
}
@ -201,10 +198,8 @@ impl PacketReadable for Vec<u8> {
if length < 0 {
return Err("Array or string length cannot be negative.".to_string());
}
let length = length as usize;
let mut it = Vec::with_capacity(length);
it.resize(length, 0);
let mut it = vec![0; length as usize];
deser.read_exact(it.as_mut_slice())?;
Ok(it)
@ -286,12 +281,12 @@ impl PacketWritable for &Uuid {
}
}
/// A marker trait indicating that a JSON-serialiable type should be serialized as JSON in packets.
/// Most primitive types are already serializable as JSON,
/// A marker trait indicating that a JSON-serialiable type should be serialized
/// as JSON in packets. Most primitive types are already serializable as JSON,
/// but we explicitly *don't* want to serialize them as JSON in packets.
pub trait PacketJson { }
pub trait PacketJson {}
impl PacketJson for crate::net::chat::Chat { }
impl PacketJson for crate::net::chat::Chat {}
impl<S: DeserializeOwned + PacketJson + Sized> PacketReadable for S {
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
@ -307,20 +302,17 @@ impl<S: PacketJson + Serialize> PacketWritable for &S {
}
// Although according to my organizational scheme, this should go first,
// it goes last anyway because constant generics break Atom's syntax highlighting
// for all code below it.
// it goes last anyway because constant generics break Atom's syntax
// highlighting for all code below it.
impl<const N: usize> PacketReadable for [u8; N] {
fn read(deser: &mut impl PacketDeserializer) -> Result<Self, String> {
use std::convert::TryInto;
let mut buf = [0; N];
deser.read_exact(&mut buf)?;
Ok(buf.try_into().unwrap())
Ok(buf)
}
}
impl<const N: usize> PacketWritable for [u8; N] {
fn write(self, ser: &mut impl PacketSerializer) {
ser.write_exact(&self);