Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3,017 changes: 1,793 additions & 1,224 deletions Cargo.lock

Large diffs are not rendered by default.

51 changes: 30 additions & 21 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,40 @@ edition = "2018"
license = "MIT"

[features]
default = ["ssl"]

ssl = ["openssl", "actix-web/ssl"]
rust-tls = ["rustls", "actix-web/rust-tls"]
default = ["rustls-tls"]
rustls-tls = ["dep:rustls", "dep:rustls-pemfile", "actix-web/rustls"]
openssl-tls = ["dep:openssl", "actix-web/openssl"]

[dependencies]
log = "0.4"
env_logger = "0.6"
structopt = "0.2"
env_logger = "0.10"
structopt = "0.3"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
toml = "0.5"
humantime = "1.2"
rand = "0.7"
rand_hc = "0.2"
uuid = { version = "0.7", features = ["serde", "u128"] }
derive_more = "0.15.0"
snafu = "0.4"
toml = "0.7"
humantime = "2.1"
rand = "0.8"
rand_hc = "0.3"
uuid = { version = "1.3", features = ["serde", "v4"] }
derive_more = "0.99"
snafu = "0.7"

# Updated web framework and related dependencies
actix-web = { version = "4.3", features = ["cookies"] }
actix-web-actors = "4.2"
actix = "0.13"
futures = "0.3"
tokio = { version = "1", features = ["full"] }

# Authentication
jsonwebtoken = "8.3"
ring = "0.16"

# TLS support
rustls = { version = "0.21", optional = true }
rustls-pemfile = { version = "1.0", optional = true }
openssl = { version = "0.10", features = ["v110"], optional = true }
rustls = { version = "0.15", optional = true }
ring = "0.14"
jsonwebtoken = "6.0"
actix-web = "1.0"
actix-web-actors = "1.0"
actix = "0.8"
futures = "0.1"
url = "1.7"

# URLs
url = "2.3"
reqwest = { version = "0.11", features = ["json"] }
Empty file added banned.txt
Empty file.
Empty file added moderators.txt
Empty file.
61 changes: 33 additions & 28 deletions src/auth.rs
Original file line number Diff line number Diff line change
@@ -1,46 +1,47 @@
use crate::error::*;
use log::*;

use actix_web::{client::Client, http::StatusCode};
use futures::Future;
use reqwest::{self, StatusCode};
use serde::{de::IgnoredAny, Deserialize, Serialize};
use url::Url;

use crate::config::AuthConfig;
use jsonwebtoken::{Header, Validation};
use jsonwebtoken::{DecodingKey, EncodingKey, Header, Validation};
use std::{
fs,
time::{Duration, SystemTime},
};
use uuid::Uuid;

pub fn authenticate(
username: &str,
server_id: &str,
) -> Result<impl Future<Item = AuthInfo, Error = Error>> {
pub async fn authenticate(username: &str, server_id: &str) -> Result<AuthInfo> {
let mut url =
Url::parse("https://sessionserver.mojang.com/session/minecraft/hasJoined").unwrap();
url.query_pairs_mut()
.append_pair("username", username)
.append_pair("serverId", server_id);

Ok(Client::new()
let client = reqwest::Client::new();
let response = client
.get(url.as_str())
.send()
.map_err(|err| Error::Actix { source: err.into() })
.and_then(|response| {
if response.status() == StatusCode::OK {
Ok(response)
} else {
debug!("Login status-code is {}", response.status());
Err(ClientError::LoginFailed.into())
}
})
.and_then(|mut response| {
response
.json()
.map_err(|err| Error::Actix { source: err.into() })
}))
.await
.map_err(|err| {
debug!("Reqwest error: {:?}", err);
Error::IO { source: std::io::Error::new(std::io::ErrorKind::Other, err) }
})?;

if response.status() == StatusCode::OK {
response
.json::<AuthInfo>()
.await
.map_err(|err| {
debug!("JSON deserialization error: {:?}", err);
Error::IO { source: std::io::Error::new(std::io::ErrorKind::Other, err) }
})
} else {
debug!("Login status-code is {}", response.status());
Err(ClientError::LoginFailed.into())
}
}

#[derive(Debug, Deserialize)]
Expand Down Expand Up @@ -85,22 +86,26 @@ pub fn encode_sha1_bytes(bytes: &[u8; 20]) -> String {
pub struct Authenticator {
validation: Validation,
header: Header,
key: Vec<u8>,
encoding_key: EncodingKey,
decoding_key: DecodingKey,
valid_time: Duration,
}

impl Authenticator {
pub fn new(cfg: &AuthConfig) -> Result<Authenticator> {
let key_data = fs::read(&cfg.key_file)?;

Ok(Authenticator {
validation: Validation::new(cfg.algorithm),
header: Header::new(cfg.algorithm),
key: fs::read(&cfg.key_file)?,
encoding_key: EncodingKey::from_secret(&key_data),
decoding_key: DecodingKey::from_secret(&key_data),
valid_time: *cfg.valid_time,
})
}

pub fn auth(&self, token: &str) -> Result<UserInfo> {
match jsonwebtoken::decode::<Claims>(token, &self.key, &self.validation) {
match jsonwebtoken::decode::<Claims>(token, &self.decoding_key, &self.validation) {
Ok(data) => Ok(data.claims.user),
Err(err) => Err(err.into()),
}
Expand All @@ -111,16 +116,16 @@ impl Authenticator {
.duration_since(SystemTime::UNIX_EPOCH)
.expect("system time is somehow before the unix epoch");
let claims = Claims {
exp: (unix_time + self.valid_time).as_secs(),
exp: (unix_time + self.valid_time).as_secs() as usize,
user: info,
};
jsonwebtoken::encode(&self.header, &claims, &self.key).map_err(|err| err.into())
jsonwebtoken::encode(&self.header, &claims, &self.encoding_key).map_err(|err| err.into())
}
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Claims {
exp: u64,
exp: usize,
user: UserInfo,
}

Expand Down
50 changes: 29 additions & 21 deletions src/chat/handler/ban.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::{ChatServer, ClientPacket};
use crate::chat::{InternalId, SuccessReason};
use crate::chat::{InternalId, SuccessReason, send_message};

use crate::error::*;
use log::*;
Expand All @@ -22,12 +22,13 @@ impl ChatServer {
if let Some(info) = &session.user {
if !self.moderation.is_moderator(&info.uuid) {
info!("`{}` tried to (un-)ban user without permission", user_id);
session
.addr
.do_send(ClientPacket::Error {
send_message(
&session.addr,
ClientPacket::Error {
message: ClientError::NotPermitted,
})
.ok();
},
"permission denied"
);
return;
}

Expand All @@ -45,33 +46,40 @@ impl ChatServer {
info!("User `{}` unbanned.", receiver);
SuccessReason::Unban
};
let _ = session.addr.do_send(ClientPacket::Success { reason });
send_message(
&session.addr,
ClientPacket::Success { reason },
"ban/unban success"
);
}
Err(Error::AxoChat { source }) => {
info!("Could not (un-)ban user `{}`: {}", receiver, source);
session
.addr
.do_send(ClientPacket::Error { message: source })
.ok();
send_message(
&session.addr,
ClientPacket::Error { message: source },
"ban/unban client error"
);
}
Err(err) => {
info!("Could not (un-)ban user `{}`: {}", receiver, err);
session
.addr
.do_send(ClientPacket::Error {
send_message(
&session.addr,
ClientPacket::Error {
message: ClientError::Internal,
})
.ok();
},
"ban/unban internal error"
);
}
}
} else {
info!("`{}` is not logged in.", user_id);
session
.addr
.do_send(ClientPacket::Error {
send_message(
&session.addr,
ClientPacket::Error {
message: ClientError::NotLoggedIn,
})
.ok();
},
"not logged in"
);
return;
}
}
Expand Down
36 changes: 23 additions & 13 deletions src/chat/handler/count.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::chat::{ChatServer, ClientPacket, InternalId};
use crate::chat::{ChatServer, ClientPacket, InternalId, send_message};
use crate::error::*;
use log::*;

Expand All @@ -15,23 +15,33 @@ impl ChatServer {
"`{}` tried to get the user count without permission",
user_id
);
let _ = session.addr.do_send(ClientPacket::Error {
message: ClientError::NotPermitted,
});
send_message(
&session.addr,
ClientPacket::Error {
message: ClientError::NotPermitted,
},
"permission denied for user count"
);
return;
}

if let Err(err) = session.addr.do_send(ClientPacket::UserCount {
connections: self.connections.len() as u32,
logged_in: self.users.len() as u32,
}) {
warn!("Could not send user count to user `{}`: {}", user_id, err);
}
send_message(
&session.addr,
ClientPacket::UserCount {
connections: self.connections.len() as u32,
logged_in: self.users.len() as u32,
},
"user count"
);
} else {
info!("`{}` is not logged in.", user_id);
let _ = session.addr.do_send(ClientPacket::Error {
message: ClientError::NotLoggedIn,
});
send_message(
&session.addr,
ClientPacket::Error {
message: ClientError::NotLoggedIn,
},
"not logged in for user count"
);
}
}
}
Loading
Loading