Fix compiler warnings, clean up safety errors

This commit is contained in:
Cappy Ishihara 2024-06-02 01:01:57 +07:00
parent 5e4e1219b7
commit d7f04e7a9f
No known key found for this signature in database
GPG key ID: 50862C285CB76906
7 changed files with 53 additions and 70 deletions

View file

@ -6,6 +6,8 @@ Implements Ping transmission functionality via Websocket and full avatar upload
And also a distinctive feature is the possibility of player identification through the third-party authorization system [Ely.By](https://ely.by/) And also a distinctive feature is the possibility of player identification through the third-party authorization system [Ely.By](https://ely.by/)
> This is a personal fork of Sculptor, made to be a workaround for a private server.
### Running with Docker ### Running with Docker
You will need an already configured Docker with Traefik (you can use any reverse proxy) You will need an already configured Docker with Traefik (you can use any reverse proxy)

View file

@ -3,6 +3,7 @@ name: sculptor
services: services:
sculptor: sculptor:
build: . build: .
image: ghcr.io/korewachino/sculptor:latest
container_name: sculptor container_name: sculptor
restart: unless-stopped restart: unless-stopped
volumes: volumes:

View file

@ -46,9 +46,9 @@ async fn verify( // Second stage of authentication
// let link = state.authenticated_link.lock().await; // // Реализация поиска пользователя в HashMap по UUID // let link = state.authenticated_link.lock().await; // // Реализация поиска пользователя в HashMap по UUID
authenticated.insert(uuid, server_id.clone(), crate::Userinfo { username, uuid, auth_system }); authenticated.insert(uuid, server_id.clone(), crate::Userinfo { username, uuid, auth_system });
// link.insert(uuid, crate::AuthenticatedLink(server_id.clone())); // Реализация поиска пользователя в HashMap по UUID // link.insert(uuid, crate::AuthenticatedLink(server_id.clone())); // Реализация поиска пользователя в HashMap по UUID
return format!("{server_id}") server_id.to_string()
} else { } else {
return String::from("failed to verify") String::from("failed to verify")
} }
} }
@ -60,15 +60,15 @@ pub async fn status(
Some(token) => { Some(token) => {
if state.authenticated.contains_token(&token) { if state.authenticated.contains_token(&token) {
// format!("ok") // 200 // format!("ok") // 200
(StatusCode::OK, format!("ok")).into_response() (StatusCode::OK, "ok".to_string()).into_response()
} else { } else {
// format!("unauthorized") // 401 // format!("unauthorized") // 401
(StatusCode::UNAUTHORIZED, format!("unauthorized")).into_response() (StatusCode::UNAUTHORIZED, "unauthorized".to_string()).into_response()
} }
}, },
None => { None => {
// format!("bad request") // 400 // format!("bad request") // 400
(StatusCode::BAD_REQUEST, format!("bad request")).into_response() (StatusCode::BAD_REQUEST, "bad request".to_string()).into_response()
}, },
} }
} }

View file

@ -1,15 +1,17 @@
use anyhow::Result; use anyhow::Result;
use axum::{ use axum::{
middleware::from_extractor, routing::{delete, get, post, put}, Router middleware::from_extractor,
routing::{delete, get, post, put},
Router,
}; };
use chrono::prelude::*; use chrono::prelude::*;
use dashmap::DashMap; use dashmap::DashMap;
use fern::colors::{Color, ColoredLevelConfig}; use fern::colors::{Color, ColoredLevelConfig};
use log::info; use log::info;
use uuid::Uuid;
use std::sync::Arc; use std::sync::Arc;
use tokio::sync::{broadcast, Mutex}; use tokio::sync::{broadcast, Mutex};
use tower_http::trace::TraceLayer; use tower_http::trace::TraceLayer;
use uuid::Uuid;
// WebSocket worker // WebSocket worker
mod ws; mod ws;
@ -38,7 +40,6 @@ pub struct Userinfo {
username: String, username: String,
uuid: Uuid, uuid: Uuid,
auth_system: api_auth::AuthSystem, auth_system: api_auth::AuthSystem,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -49,18 +50,27 @@ struct Authenticated {
impl Authenticated { impl Authenticated {
fn new() -> Self { fn new() -> Self {
Self { user_data: DashMap::new(), uuid: DashMap::new() } Self {
user_data: DashMap::new(),
uuid: DashMap::new(),
}
} }
pub fn insert(&self, uuid: Uuid, token: String, userinfo: Userinfo) -> Option<Userinfo> { pub fn insert(&self, uuid: Uuid, token: String, userinfo: Userinfo) -> Option<Userinfo> {
self.uuid.insert(uuid, token.clone()); self.uuid.insert(uuid, token.clone());
self.user_data.insert(token, userinfo) self.user_data.insert(token, userinfo)
} }
pub fn get(&self, token: &String) -> Option<dashmap::mapref::one::Ref<'_, std::string::String, Userinfo>> { pub fn get(
&self,
token: &String,
) -> Option<dashmap::mapref::one::Ref<'_, std::string::String, Userinfo>> {
self.user_data.get(token) self.user_data.get(token)
} }
pub fn get_by_uuid(&self, uuid: &Uuid) -> Option<dashmap::mapref::one::Ref<'_, std::string::String, Userinfo>> { pub fn get_by_uuid(
&self,
uuid: &Uuid,
) -> Option<dashmap::mapref::one::Ref<'_, std::string::String, Userinfo>> {
if let Some(token) = self.uuid.get(uuid) { if let Some(token) = self.uuid.get(uuid) {
self.user_data.get(&token.to_string()) self.user_data.get(&token.clone())
} else { } else {
None None
} }
@ -121,7 +131,7 @@ async fn main() -> Result<()> {
broadcasts: Arc::new(DashMap::new()), broadcasts: Arc::new(DashMap::new()),
advanced_users: Arc::new(Mutex::new(config.advanced_users)), advanced_users: Arc::new(Mutex::new(config.advanced_users)),
}; };
// Automatic update of advanced_users while the server is running // Automatic update of advanced_users while the server is running
let advanced_users = state.advanced_users.clone(); let advanced_users = state.advanced_users.clone();
tokio::spawn(async move { tokio::spawn(async move {
@ -138,42 +148,15 @@ async fn main() -> Result<()> {
}); });
let api = Router::new() let api = Router::new()
.nest( .nest("//auth", api_auth::router())
"//auth", .route("/limits", get(api_info::limits)) // TODO:
api_auth::router() .route("/version", get(api_info::version))
) .route("/motd", get(|| async { config.motd }))
.route( .route("/equip", post(api_profile::equip_avatar))
"/limits", .route("/:uuid", get(api_profile::user_info))
get(api_info::limits) .route("/:uuid/avatar", get(api_profile::download_avatar))
) // TODO: .route("/avatar", put(api_profile::upload_avatar))
.route( .route("/avatar", delete(api_profile::delete_avatar)); // delete Avatar
"/version",
get(api_info::version),
)
.route(
"/motd",
get(|| async { config.motd }),
)
.route(
"/equip",
post(api_profile::equip_avatar)
)
.route(
"/:uuid",
get(api_profile::user_info),
)
.route(
"/:uuid/avatar",
get(api_profile::download_avatar),
)
.route(
"/avatar",
put(api_profile::upload_avatar),
)
.route(
"/avatar",
delete(api_profile::delete_avatar),
); // delete Avatar
let app = Router::new() let app = Router::new()
.nest("/api", api) .nest("/api", api)

View file

@ -107,7 +107,7 @@ pub async fn upload_avatar(
let mut file = BufWriter::new(fs::File::create(&avatar_file).await?); let mut file = BufWriter::new(fs::File::create(&avatar_file).await?);
io::copy(&mut request_data.as_ref(), &mut file).await?; io::copy(&mut request_data.as_ref(), &mut file).await?;
} }
Ok(format!("ok")) Ok("ok".to_string())
} }
pub async fn equip_avatar( pub async fn equip_avatar(
@ -119,7 +119,7 @@ pub async fn equip_avatar(
if state.broadcasts.get(&uuid).unwrap().send(S2CMessage::Event(uuid).to_vec()).is_err() { if state.broadcasts.get(&uuid).unwrap().send(S2CMessage::Event(uuid).to_vec()).is_err() {
warn!("[WebSocket] Failed to send Event! Maybe there is no one to send") // FIXME: Засунуть в Handler warn!("[WebSocket] Failed to send Event! Maybe there is no one to send") // FIXME: Засунуть в Handler
}; };
format!("ok") "ok".to_string()
} }
pub async fn delete_avatar( pub async fn delete_avatar(
@ -136,5 +136,5 @@ pub async fn delete_avatar(
fs::remove_file(avatar_file).await?; fs::remove_file(avatar_file).await?;
} }
// let avatar_file = format!("avatars/{}.moon",user_info.uuid); // let avatar_file = format!("avatars/{}.moon",user_info.uuid);
Ok(format!("ok")) Ok("ok".to_string())
} }

View file

@ -15,7 +15,7 @@ pub enum C2SMessage<'a> {
impl<'a> TryFrom<&'a [u8]> for C2SMessage<'a> { impl<'a> TryFrom<&'a [u8]> for C2SMessage<'a> {
type Error = MessageLoadError; type Error = MessageLoadError;
fn try_from(buf: &'a [u8]) -> Result<Self, <Self as TryFrom<&'a [u8]>>::Error> { fn try_from(buf: &'a [u8]) -> Result<Self, <Self as TryFrom<&'a [u8]>>::Error> {
if buf.len() == 0 { if buf.is_empty() {
Err(MessageLoadError::BadLength("C2SMessage", 1, false, 0)) Err(MessageLoadError::BadLength("C2SMessage", 1, false, 0))
} else { } else {
match buf[0] { match buf[0] {
@ -73,15 +73,15 @@ impl<'a> TryFrom<&'a [u8]> for C2SMessage<'a> {
} }
} }
} }
impl<'a> Into<Box<[u8]>> for C2SMessage<'a> { impl<'a> From<C2SMessage<'a>> for Box<[u8]> {
fn into(self) -> Box<[u8]> { fn from(val: C2SMessage<'a>) -> Self {
use std::iter; use std::iter;
let a: Box<[u8]> = match self { let a: Box<[u8]> = match val {
C2SMessage::Token(t) => iter::once(0).chain(t.into_iter().copied()).collect(), C2SMessage::Token(t) => iter::once(0).chain(t.iter().copied()).collect(),
C2SMessage::Ping(p, s, d) => iter::once(1) C2SMessage::Ping(p, s, d) => iter::once(1)
.chain(p.to_be_bytes()) .chain(p.to_be_bytes())
.chain(iter::once(s.into())) .chain(iter::once(s.into()))
.chain(d.into_iter().copied()) .chain(d.iter().copied())
.collect(), .collect(),
C2SMessage::Sub(s) => iter::once(2).chain(s.into_bytes()).collect(), C2SMessage::Sub(s) => iter::once(2).chain(s.into_bytes()).collect(),
C2SMessage::Unsub(s) => iter::once(3).chain(s.into_bytes()).collect(), C2SMessage::Unsub(s) => iter::once(3).chain(s.into_bytes()).collect(),

View file

@ -16,7 +16,7 @@ pub enum S2CMessage<'a> {
impl<'a> TryFrom<&'a [u8]> for S2CMessage<'a> { impl<'a> TryFrom<&'a [u8]> for S2CMessage<'a> {
type Error = MessageLoadError; type Error = MessageLoadError;
fn try_from(buf: &'a [u8]) -> Result<Self, <Self as TryFrom<&'a [u8]>>::Error> { fn try_from(buf: &'a [u8]) -> Result<Self, <Self as TryFrom<&'a [u8]>>::Error> {
if buf.len() == 0 { if buf.is_empty() {
Err(MessageLoadError::BadLength("S2CMessage", 1, false, 0)) Err(MessageLoadError::BadLength("S2CMessage", 1, false, 0))
} else { } else {
use MessageLoadError::*; use MessageLoadError::*;
@ -43,9 +43,7 @@ impl<'a> TryFrom<&'a [u8]> for S2CMessage<'a> {
} }
2 => { 2 => {
if buf.len() == 17 { if buf.len() == 17 {
Ok(Event(Uuid::from_bytes( Ok(Event(Uuid::from_bytes((&buf[1..17]).try_into().unwrap())))
(&buf[1..17]).try_into().unwrap(),
)))
} else { } else {
Err(BadLength("S2CMessage::Event", 17, true, buf.len())) Err(BadLength("S2CMessage::Event", 17, true, buf.len()))
} }
@ -58,26 +56,25 @@ impl<'a> TryFrom<&'a [u8]> for S2CMessage<'a> {
} }
} }
} }
impl<'a> Into<Box<[u8]>> for S2CMessage<'a> { impl<'a> From<S2CMessage<'a>> for Box<[u8]> {
fn into(self) -> Box<[u8]> { fn from(val: S2CMessage<'a>) -> Self {
use std::iter::once; use std::iter::once;
use S2CMessage::*; use S2CMessage::*;
match self { match val {
Auth => Box::new([0]), Auth => Box::new([0]),
Ping(u, i, s, d) => once(1) Ping(u, i, s, d) => once(1)
.chain(u.into_bytes().iter().copied()) .chain(u.into_bytes().iter().copied())
.chain(i.to_be_bytes().iter().copied()) .chain(i.to_be_bytes().iter().copied())
.chain(once(if s { 1 } else { 0 })) .chain(once(if s { 1 } else { 0 }))
.chain(d.into_iter().copied()) .chain(d.iter().copied())
.collect(), .collect(),
Event(u) => once(2).chain(u.into_bytes().iter().copied()).collect(), Event(u) => once(2).chain(u.into_bytes().iter().copied()).collect(),
Toast(t, h, d) => once(3) Toast(t, h, d) => once(3)
.chain(once(t)) .chain(once(t))
.chain(h.as_bytes().into_iter().copied()) .chain(h.as_bytes().iter().copied())
.chain( .chain(
d.into_iter() d.into_iter()
.map(|s| once(0).chain(s.as_bytes().into_iter().copied())) .flat_map(|s| once(0).chain(s.as_bytes().iter().copied())),
.flatten(),
) )
.collect(), .collect(),
Chat(c) => once(4).chain(c.as_bytes().iter().copied()).collect(), Chat(c) => once(4).chain(c.as_bytes().iter().copied()).collect(),
@ -93,4 +90,4 @@ impl<'a> S2CMessage<'a> {
pub fn to_vec(self) -> Vec<u8> { pub fn to_vec(self) -> Vec<u8> {
self.to_array().to_vec() self.to_array().to_vec()
} }
} }