Skip to content

Commit

Permalink
Add server whitelist support, use generic server files watcher to reload
Browse files Browse the repository at this point in the history
  • Loading branch information
timvisee committed Nov 28, 2021
1 parent 69de7a9 commit c477e45
Show file tree
Hide file tree
Showing 10 changed files with 319 additions and 121 deletions.
3 changes: 3 additions & 0 deletions res/lazymc.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ command = "java -Xmx1G -Xms1G -jar server.jar --nogui"
#start_timeout = 300
#stop_timeout = 150

# To wake server, user must be in server whitelist if enabled on server.
#wake_whitelist = true

# Block banned IPs as listed in banned-ips.json in server directory.
#block_banned_ips = true

Expand Down
4 changes: 4 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,10 @@ pub struct Server {
#[serde(default = "u32_150")]
pub stop_timeout: u32,

/// To wake server, user must be in server whitelist if enabled on server.
#[serde(default = "bool_true")]
pub wake_whitelist: bool,

/// Block banned IPs as listed in banned-ips.json in server directory.
#[serde(default = "bool_true")]
pub block_banned_ips: bool,
Expand Down
1 change: 1 addition & 0 deletions src/mc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub mod rcon;
pub mod server_properties;
#[cfg(feature = "lobby")]
pub mod uuid;
pub mod whitelist;

/// Minecraft ticks per second.
#[allow(unused)]
Expand Down
107 changes: 107 additions & 0 deletions src/mc/whitelist.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
use std::error::Error;
use std::fs;
use std::path::Path;

use serde::Deserialize;

/// Whitelist file name.
pub const WHITELIST_FILE: &str = "whitelist.json";

/// OPs file name.
pub const OPS_FILE: &str = "ops.json";

/// Whitelisted users.
///
/// Includes list of OPs, which are also automatically whitelisted.
#[derive(Debug, Default)]
pub struct Whitelist {
/// Whitelisted users.
whitelist: Vec<String>,

/// OPd users.
ops: Vec<String>,
}

impl Whitelist {
/// Check whether a user is whitelisted.
pub fn is_whitelisted(&self, username: &str) -> bool {
self.whitelist.iter().any(|u| u == username) || self.ops.iter().any(|u| u == username)
}
}

/// A whitelist user.
#[derive(Debug, Deserialize, Clone)]
pub struct WhitelistUser {
/// Whitelisted username.
#[serde(rename = "name", alias = "username")]
pub username: String,

/// Whitelisted UUID.
pub uuid: Option<String>,
}

/// An OP user.
#[derive(Debug, Deserialize, Clone)]
pub struct OpUser {
/// OP username.
#[serde(rename = "name", alias = "username")]
pub username: String,

/// OP UUID.
pub uuid: Option<String>,

/// OP level.
pub level: Option<u32>,

/// Whether OP can bypass player limit.
#[serde(rename = "bypassesPlayerLimit")]
pub byapsses_player_limit: Option<bool>,
}

/// Load whitelist from directory.
pub fn load_dir(path: &Path) -> Result<Whitelist, Box<dyn Error>> {
let whitelist_file = path.join(WHITELIST_FILE);
let ops_file = path.join(OPS_FILE);

// Load whitelist users
let whitelist = if whitelist_file.is_file() {
load_whitelist(&whitelist_file)?
} else {
vec![]
};

// Load OPd users
let ops = if ops_file.is_file() {
load_ops(&ops_file)?
} else {
vec![]
};

debug!(target: "lazymc", "Loaded {} whitelist and {} OP users", whitelist.len(), ops.len());

Ok(Whitelist { whitelist, ops })
}

/// Load whitelist from file.
fn load_whitelist(path: &Path) -> Result<Vec<String>, Box<dyn Error>> {
// Load file contents
let contents = fs::read_to_string(path)?;

// Parse contents
let users: Vec<WhitelistUser> = serde_json::from_str(&contents)?;

// Pluck usernames
Ok(users.into_iter().map(|user| user.username).collect())
}

/// Load OPs from file.
fn load_ops(path: &Path) -> Result<Vec<String>, Box<dyn Error>> {
// Load file contents
let contents = fs::read_to_string(path)?;

// Parse contents
let users: Vec<OpUser> = serde_json::from_str(&contents)?;

// Pluck usernames
Ok(users.into_iter().map(|user| user.username).collect())
}
27 changes: 27 additions & 0 deletions src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use tokio::time;

use crate::config::{Config, Server as ConfigServer};
use crate::mc::ban::{BannedIp, BannedIps};
use crate::mc::whitelist::Whitelist;
use crate::os;
use crate::proto::packets::play::join_game::JoinGameData;

Expand Down Expand Up @@ -73,6 +74,9 @@ pub struct Server {
/// List of banned IPs.
banned_ips: RwLock<BannedIps>,

/// Whitelist if enabled.
whitelist: RwLock<Option<Whitelist>>,

/// Lock for exclusive RCON operations.
#[cfg(feature = "rcon")]
rcon_lock: Semaphore,
Expand Down Expand Up @@ -346,6 +350,18 @@ impl Server {
futures::executor::block_on(async { self.is_banned_ip(ip).await })
}

/// Check whether the given username is whitelisted.
///
/// Returns `true` if no whitelist is currently used.
pub async fn is_whitelisted(&self, username: &str) -> bool {
self.whitelist
.read()
.await
.as_ref()
.map(|w| w.is_whitelisted(username))
.unwrap_or(true)
}

/// Update the list of banned IPs.
pub async fn set_banned_ips(&self, ips: BannedIps) {
*self.banned_ips.write().await = ips;
Expand All @@ -355,6 +371,16 @@ impl Server {
pub fn set_banned_ips_blocking(&self, ips: BannedIps) {
futures::executor::block_on(async { self.set_banned_ips(ips).await })
}

/// Update the whitelist.
pub async fn set_whitelist(&self, whitelist: Option<Whitelist>) {
*self.whitelist.write().await = whitelist;
}

/// Update the whitelist.
pub fn set_whitelist_blocking(&self, whitelist: Option<Whitelist>) {
futures::executor::block_on(async { self.set_whitelist(whitelist).await })
}
}

impl Default for Server {
Expand All @@ -371,6 +397,7 @@ impl Default for Server {
keep_online_until: Default::default(),
kill_at: Default::default(),
banned_ips: Default::default(),
whitelist: Default::default(),
#[cfg(feature = "rcon")]
rcon_lock: Semaphore::new(1),
#[cfg(feature = "rcon")]
Expand Down
119 changes: 0 additions & 119 deletions src/service/ban_reload.rs

This file was deleted.

Loading

0 comments on commit c477e45

Please sign in to comment.