mirror of
https://github.com/shiroyashik/sculptor.git
synced 2025-12-06 04:51:13 +03:00
Fix compiler warnings, clean up safety errors
This commit is contained in:
parent
5e4e1219b7
commit
d7f04e7a9f
7 changed files with 53 additions and 70 deletions
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
10
src/auth.rs
10
src/auth.rs
|
|
@ -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()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
71
src/main.rs
71
src/main.rs
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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())
|
||||||
}
|
}
|
||||||
|
|
@ -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(),
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue