Skip to content

Commit

Permalink
Configuration auto-update fixed and hex replaced with faster_hex
Browse files Browse the repository at this point in the history
  • Loading branch information
shiroyashik committed Nov 14, 2024
1 parent 4c0871e commit d76236b
Show file tree
Hide file tree
Showing 14 changed files with 1,437 additions and 281 deletions.
1,452 changes: 1,276 additions & 176 deletions Cargo.lock

Large diffs are not rendered by default.

17 changes: 11 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,29 @@ tracing = "0.1"

# Errors handelers
anyhow = "1.0"
thiserror = "1.0"
thiserror = "2.0"
chrono = { version = "0.4", features = ["now", "serde"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
toml = "0.8"

# Other
dashmap = { version = "6.0", features = ["serde"] }
hex = "0.4"
faster-hex = "0.10"
uuid = { version = "1.11", features = ["serde"] }
base64 = "0.22"
reqwest = { version = "0.12", features = ["blocking", "json"] }
dotenvy = "0.15"
semver = "1.0"
walkdir = "2.5"
<<<<<<< HEAD
indexmap = { version = "2.6", features = ["serde"] }
zip = "2.2"
lazy_static = "1.5"
notify = "7.0"
=======
sqlx = { version = "0.8", default-features = false, features = [ "runtime-tokio-native-tls", "macros", "sqlite", "chrono" ] }
>>>>>>> 6fd3dc11200cbc5b193f456297812e62c3ea9578

# Crypto
ring = "0.17"
Expand All @@ -37,10 +45,7 @@ rand = "0.8"
# Web framework
axum = { version = "0.7", features = ["ws", "macros", "http2"] }
tower-http = { version = "0.6", features = ["trace"] }
tokio = { version = "1.37", features = ["full"] }
indexmap = { version = "2.6", features = ["serde"] }
zip = "2.2"
lazy_static = "1.5"
tokio = { version = "1.41", features = ["full"] }

[dev-dependencies]
cross = "0.2.5"
Expand Down
2 changes: 1 addition & 1 deletion Config.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ customText = """
[limitations]
maxAvatarSize = 100 # KB
maxAvatars = 10 # It doesn't look like Figura has any actions implemented with this?
# P.S. And it doesn't look like the current API allows anything like that... Unless you store them directly in one file...
# P.S. And it doesn't look like the current API allows anything like that...

[advancedUsers.66004548-4de5-49de-bade-9c3933d8eb97]
username = "Shiroyashik"
Expand Down
2 changes: 1 addition & 1 deletion src/api/figura/assets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ async fn index_assets(version: &str) -> anyhow::Result<IndexMap<String, Value>>
entry.path().strip_prefix(version_path.clone())?.to_string_lossy().to_string()
};

map.insert(path, Value::from(hex::encode(digest(&SHA256, &data).as_ref())));
map.insert(path, Value::from(faster_hex::hex_string(digest(&SHA256, &data).as_ref())));
}

Ok(map)
Expand Down
14 changes: 7 additions & 7 deletions src/api/figura/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ async fn id(
State(state): State<AppState>,
) -> String {
let server_id =
hex::encode(&digest(&digest::SHA1_FOR_LEGACY_USE_ONLY, &rand()).as_ref()[0..20]);
faster_hex::hex_string(&digest(&digest::SHA1_FOR_LEGACY_USE_ONLY, &rand()).as_ref()[0..20]);
let state = state.user_manager;
state.pending_insert(server_id.clone(), query.username);
server_id
Expand All @@ -32,11 +32,11 @@ async fn verify(
State(state): State<AppState>,
) -> Response {
let server_id = query.id.clone();
let username = state.user_manager.pending_remove(&server_id).unwrap().1; // TODO: Add error check
let nickname = state.user_manager.pending_remove(&server_id).unwrap().1; // TODO: Add error check
let userinfo = match has_joined(
state.config.read().await.auth_providers.clone(),
&server_id,
&username
&nickname
).await {
Ok(d) => d,
Err(_e) => {
Expand All @@ -47,12 +47,12 @@ async fn verify(
if let Some((uuid, auth_provider)) = userinfo {
let umanager = state.user_manager;
if umanager.is_banned(&uuid) {
info!("[Authentication] {username} tried to log in, but was banned");
info!("[Authentication] {nickname} tried to log in, but was banned");
return (StatusCode::BAD_REQUEST, "You're banned!".to_string()).into_response();
}
info!("[Authentication] {username} logged in using {}", auth_provider.name);
info!("[Authentication] {nickname} logged in using {}", auth_provider.name);
let userinfo = Userinfo {
username,
nickname,
uuid,
token: Some(server_id.clone()),
auth_provider,
Expand All @@ -70,7 +70,7 @@ async fn verify(
}
(StatusCode::OK, server_id.to_string()).into_response()
} else {
info!("[Authentication] failed to verify {username}");
info!("[Authentication] failed to verify {nickname}");
(StatusCode::BAD_REQUEST, "failed to verify".to_string()).into_response()
}
}
4 changes: 2 additions & 2 deletions src/api/figura/profile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ pub async fn upload_avatar(
tracing::info!(
"{} ({}) trying to upload an avatar",
user_info.uuid,
user_info.username
user_info.nickname
);
let avatar_file = format!("{}/{}.moon", *AVATARS_VAR, user_info.uuid);
let mut file = BufWriter::new(fs::File::create(&avatar_file).await.map_err(internal_and_log)?);
Expand All @@ -121,7 +121,7 @@ pub async fn delete_avatar(Token(token): Token, State(state): State<AppState>) -
tracing::info!(
"{} ({}) is trying to delete the avatar",
user_info.uuid,
user_info.username
user_info.nickname
);
let avatar_file = format!("{}/{}.moon", *AVATARS_VAR, user_info.uuid);
fs::remove_file(avatar_file).await.map_err(internal_and_log)?;
Expand Down
12 changes: 6 additions & 6 deletions src/api/figura/websocket/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ async fn handle_socket(mut ws: WebSocket, state: AppState) {
}

async fn main_worker(session: &mut WSSession, ws: &mut WebSocket, state: &AppState) -> anyhow::Result<()> {
tracing::debug!("WebSocket control for {} is transferred to the main worker", session.user.username);
tracing::debug!("WebSocket control for {} is transferred to the main worker", session.user.nickname);
loop {
tokio::select! {
external_msg = ws.recv_and_decode() => {
Expand Down Expand Up @@ -96,7 +96,7 @@ async fn main_worker(session: &mut WSSession, ws: &mut WebSocket, state: &AppSta
let _ = session.subs_tx.send(s2c_ping);
},
C2SMessage::Sub(uuid) => {
tracing::debug!("[WebSocket] {} subscribes to {}", session.user.username, uuid);
tracing::debug!("[WebSocket] {} subscribes to {}", session.user.nickname, uuid);

// Doesn't allow to subscribe to yourself
if session.user.uuid != uuid {
Expand All @@ -114,11 +114,11 @@ async fn main_worker(session: &mut WSSession, ws: &mut WebSocket, state: &AppSta
}
},
C2SMessage::Unsub(uuid) => {
tracing::debug!("[WebSocket] {} unsubscribes from {}", session.user.username, uuid);
tracing::debug!("[WebSocket] {} unsubscribes from {}", session.user.nickname, uuid);

match session.sub_workers_aborthandles.get(&uuid) {
Some(handle) => handle.abort(),
None => tracing::warn!("[WebSocket] {} was not subscribed.", session.user.username),
None => tracing::warn!("[WebSocket] {} was not subscribed.", session.user.nickname),
};
},
}
Expand All @@ -134,7 +134,7 @@ async fn main_worker(session: &mut WSSession, ws: &mut WebSocket, state: &AppSta
.inspect_err(
|kind| tracing::warn!("[WebSocket] Didn't get the ban message due to {}", kind)
);
bail!("{} banned!", session.user.username)
bail!("{} banned!", session.user.nickname)
},
}
}
Expand Down Expand Up @@ -178,7 +178,7 @@ async fn authenticate(socket: &mut WebSocket, state: &AppState) -> Result<Userin
.inspect_err(
|kind| tracing::warn!("[WebSocket] Didn't get the ban message due to {}", kind)
);
Err(AuthModeError::Banned(user.username.clone()))
Err(AuthModeError::Banned(user.nickname.clone()))
}
},
None => {
Expand Down
2 changes: 1 addition & 1 deletion src/api/figura/websocket/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ impl RecvAndDecode for WebSocket {
match C2SMessage::try_from(msg.clone().into_data().as_slice()) {
Ok(decoded) => Ok(decoded),
Err(e) => {
Err(RADError::DecodeError(e, hex::encode(msg.into_data())))
Err(RADError::DecodeError(e, faster_hex::hex_string(&msg.into_data())))
},
}
}
Expand Down
6 changes: 4 additions & 2 deletions src/api/v1/http2ws.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ pub(super) async fn raw(
) -> ApiResult<&'static str> {
trace!(body = body);
state.config.read().await.clone().verify_token(&token)?;
let payload = hex::decode(body).map_err(|err| { warn!("not raw data"); error_and_log(err, crate::ApiError::NotAcceptable) })?;
let mut payload = vec![0; body.len() / 2];
faster_hex::hex_decode(body.as_bytes(), &mut payload).map_err(|err| { warn!("not raw data"); error_and_log(err, crate::ApiError::NotAcceptable) })?;
debug!("{:?}", payload);

match query.uuid {
Expand All @@ -47,7 +48,8 @@ pub(super) async fn sub_raw(
) -> ApiResult<&'static str> {
trace!(body = body);
state.config.read().await.clone().verify_token(&token)?;
let payload = hex::decode(body).map_err(|err| { warn!("not raw data"); error_and_log(err, crate::ApiError::NotAcceptable) })?;
let mut payload = vec![0; body.len() / 2];
faster_hex::hex_decode(body.as_bytes(), &mut payload).map_err(|err| { warn!("not raw data"); error_and_log(err, crate::ApiError::NotAcceptable) })?;
debug!("{:?}", payload);

match query.uuid {
Expand Down
14 changes: 9 additions & 5 deletions src/auth/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@ pub struct Token(pub String);

impl Token {
pub async fn check_auth(self, state: &AppState) -> ApiResult<()> {
if state.user_manager.is_authenticated(&self.0) {
Ok(())
if let Some(user) = state.user_manager.get(&self.0) {
if !user.banned {
Ok(())
} else {
Err(ApiError::Unauthorized)
}
} else {
Err(ApiError::Unauthorized)
}
Expand Down Expand Up @@ -191,7 +195,7 @@ impl UManager {
warn!("Rejected attempt to create a second session for the same user!");
return Err(())
}
debug!("`{}` already have token in registered profile (old token already removed from 'authenticated')", userinfo.username);
debug!("`{}` already have token in registered profile (old token already removed from 'authenticated')", userinfo.nickname);
}
}

Expand All @@ -205,7 +209,7 @@ impl UManager {
let usercopy = userinfo.clone();
self.registered.entry(uuid)
.and_modify(|exist| {
if !userinfo.username.is_empty() { exist.username = userinfo.username };
if !userinfo.nickname.is_empty() { exist.nickname = userinfo.nickname };
if !userinfo.auth_provider.is_empty() { exist.auth_provider = userinfo.auth_provider };
if userinfo.rank != Userinfo::default().rank { exist.rank = userinfo.rank };
if userinfo.token.is_some() { exist.token = userinfo.token };
Expand Down Expand Up @@ -236,7 +240,7 @@ impl UManager {
user.banned = false;
};
}
pub fn is_authenticated(&self, token: &String) -> bool {
pub fn _is_authenticated(&self, token: &String) -> bool {
self.authenticated.contains_key(token)
}
pub fn _is_registered(&self, uuid: &Uuid) -> bool {
Expand Down
5 changes: 2 additions & 3 deletions src/auth/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,20 @@ use uuid::Uuid;
#[serde(rename_all = "camelCase")]
pub struct Userinfo {
pub uuid: Uuid,
pub username: String,
pub nickname: String,
pub rank: String,
pub last_used: String,
pub auth_provider: AuthProvider,
pub token: Option<String>,
pub version: String,
pub banned: bool

}

impl Default for Userinfo {
fn default() -> Self {
Self {
uuid: Default::default(),
username: Default::default(),
nickname: Default::default(),
rank: "default".to_string(),
last_used: Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Millis, true),
auth_provider: Default::default(),
Expand Down
59 changes: 37 additions & 22 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ async fn main() -> Result<()> {

// 3. Display info about current instance and check updates
tracing::info!("The Sculptor v{SCULPTOR_VERSION} ({REPOSITORY})");
// let _ = check_updates(REPOSITORY, SCULPTOR_VERSION).await; // Currently, there is no need to do anything with the result of the function

match get_latest_version(REPOSITORY).await {
Ok(latest_version) => {
Expand Down Expand Up @@ -168,32 +167,50 @@ async fn app() -> Result<bool> {
config,
};

// FIXME: FIXME: FIXME: ПЕРЕДЕЛАЙ ЭТО! НЕМЕДЛЕННО! ЕБУЧИЙ ПОЗОР :<
// Automatic update of configuration while the server is running
let config_update = Arc::clone(&state.config);
let umanager = Arc::clone(&state.user_manager);
let session = Arc::clone(&state.session);
update_advanced_users(&config_update.read().await.advanced_users.clone(), &umanager, &session).await;
tokio::spawn(async move {
loop {
tokio::time::sleep(std::time::Duration::from_secs(10)).await;
let new_config = Config::parse(CONFIG_VAR.clone().into());
let mut config = config_update.write().await;

if new_config != *config {
tracing::info!("Server configuration modification detected!");
*config = new_config;
update_advanced_users(&config.advanced_users.clone(), &umanager, &session).await;
}
}
});
<<<<<<< HEAD
// Automatic update of configuration/ban list while the server is running
tokio::spawn(update_advanced_users(
CONFIG_VAR.clone().into(),
Arc::clone(&state.user_manager),
Arc::clone(&state.session),
Arc::clone(&state.config)
));
if state.config.read().await.mc_folder.exists() {
tokio::spawn(update_bans_from_minecraft(
state.config.read().await.mc_folder.clone(),
Arc::clone(&state.user_manager),
Arc::clone(&state.session)
));
}
=======
// FIXME: FIXME: FIXME: ПЕРЕДЕЛАЙ ЭТО! НЕМЕДЛЕННО! ЕБУЧИЙ ПОЗОР :<
// FIXME: DEPRICATED
// Automatic update of configuration while the server is running
// let config_update = Arc::clone(&state.config);
// let umanager = Arc::clone(&state.user_manager);
// let session = Arc::clone(&state.session);
// update_advanced_users(&config_update.read().await.advanced_users.clone(), &umanager, &session).await;
// tokio::spawn(async move {
// loop {
// tokio::time::sleep(std::time::Duration::from_secs(10)).await;
// let new_config = Config::parse(CONFIG_VAR.clone().into());
// let mut config = config_update.write().await;

// if new_config != *config {
// tracing::info!("Server configuration modification detected!");
// *config = new_config;
// update_advanced_users(&config.advanced_users.clone(), &umanager, &session).await;
// }
// }
// });
// if state.config.read().await.mc_folder.exists() {
// tokio::spawn(update_bans_from_minecraft(
// state.config.read().await.mc_folder.clone(),
// Arc::clone(&state.user_manager),
// Arc::clone(&state.session)
// ));
// }
>>>>>>> 6fd3dc11200cbc5b193f456297812e62c3ea9578

let api = Router::new()
.nest("//auth", api_auth::router()) // => /api//auth ¯\_(ツ)_/¯
Expand Down Expand Up @@ -242,11 +259,9 @@ async fn shutdown_signal() {
let terminate = std::future::pending::<()>();
tokio::select! {
() = ctrl_c => {
println!();
tracing::info!("Ctrl+C signal received");
},
() = terminate => {
println!();
tracing::info!("Terminate signal received");
},
}
Expand Down
2 changes: 1 addition & 1 deletion src/state/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ impl From<BannedPlayer> for Userinfo {
fn from(val: BannedPlayer) -> Self {
Userinfo {
uuid: val.uuid,
username: val.name,
nickname: val.name,
banned: true,
..Default::default()
}
Expand Down
Loading

0 comments on commit d76236b

Please sign in to comment.