mirror of
https://github.com/shiroyashik/sculptor.git
synced 2025-12-06 13:01:12 +03:00
Format code
This commit is contained in:
parent
45192ef182
commit
026c6a950e
8 changed files with 145 additions and 86 deletions
62
src/auth.rs
62
src/auth.rs
|
|
@ -1,10 +1,17 @@
|
||||||
use anyhow::anyhow;
|
|
||||||
use axum::{async_trait, debug_handler, extract::{FromRequestParts, Query, State}, http::{request::Parts, StatusCode}, response::{IntoResponse, Response}, routing::get, Router};
|
|
||||||
use log::{debug, info, trace};
|
|
||||||
use serde::Deserialize;
|
|
||||||
use ring::digest::{self, digest};
|
|
||||||
use uuid::Uuid;
|
|
||||||
use crate::utils::*;
|
use crate::utils::*;
|
||||||
|
use anyhow::anyhow;
|
||||||
|
use axum::{
|
||||||
|
async_trait, debug_handler,
|
||||||
|
extract::{FromRequestParts, Query, State},
|
||||||
|
http::{request::Parts, StatusCode},
|
||||||
|
response::{IntoResponse, Response},
|
||||||
|
routing::get,
|
||||||
|
Router,
|
||||||
|
};
|
||||||
|
use log::{debug, info, trace};
|
||||||
|
use ring::digest::{self, digest};
|
||||||
|
use serde::Deserialize;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::AppState;
|
use crate::AppState;
|
||||||
|
|
||||||
|
|
@ -14,27 +21,33 @@ pub fn router() -> Router<AppState> {
|
||||||
.route("/verify", get(verify))
|
.route("/verify", get(verify))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Web
|
// Web
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct Id {username: String}
|
struct Id {
|
||||||
|
username: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[debug_handler]
|
#[debug_handler]
|
||||||
async fn id( // First stage of authentication
|
async fn id(
|
||||||
|
// First stage of authentication
|
||||||
Query(query): Query<Id>,
|
Query(query): Query<Id>,
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
) -> String {
|
) -> String {
|
||||||
let server_id = bytes_into_string(&digest(&digest::SHA1_FOR_LEGACY_USE_ONLY, &rand()).as_ref()[0 .. 20]);
|
let server_id =
|
||||||
|
bytes_into_string(&digest(&digest::SHA1_FOR_LEGACY_USE_ONLY, &rand()).as_ref()[0..20]);
|
||||||
let state = state.pending;
|
let state = state.pending;
|
||||||
state.insert(server_id.clone(), query.username);
|
state.insert(server_id.clone(), query.username);
|
||||||
server_id
|
server_id
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct Verify {id: String}
|
struct Verify {
|
||||||
|
id: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[debug_handler]
|
#[debug_handler]
|
||||||
async fn verify( // Second stage of authentication
|
async fn verify(
|
||||||
|
// Second stage of authentication
|
||||||
Query(query): Query<Verify>,
|
Query(query): Query<Verify>,
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
) -> String {
|
) -> String {
|
||||||
|
|
@ -44,7 +57,15 @@ async fn verify( // Second stage of authentication
|
||||||
info!("[Authorization] {username} logged in using {auth_system:?}");
|
info!("[Authorization] {username} logged in using {auth_system:?}");
|
||||||
let authenticated = state.authenticated;
|
let authenticated = state.authenticated;
|
||||||
// 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
|
||||||
server_id.to_string()
|
server_id.to_string()
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -52,10 +73,7 @@ async fn verify( // Second stage of authentication
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn status(
|
pub async fn status(Token(token): Token, State(state): State<AppState>) -> Response {
|
||||||
Token(token): Token,
|
|
||||||
State(state): State<AppState>,
|
|
||||||
) -> Response {
|
|
||||||
match token {
|
match token {
|
||||||
Some(token) => {
|
Some(token) => {
|
||||||
if state.authenticated.contains_token(&token) {
|
if state.authenticated.contains_token(&token) {
|
||||||
|
|
@ -65,16 +83,15 @@ pub async fn status(
|
||||||
// format!("unauthorized") // 401
|
// format!("unauthorized") // 401
|
||||||
(StatusCode::UNAUTHORIZED, "unauthorized".to_string()).into_response()
|
(StatusCode::UNAUTHORIZED, "unauthorized".to_string()).into_response()
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
None => {
|
None => {
|
||||||
// format!("bad request") // 400
|
// format!("bad request") // 400
|
||||||
(StatusCode::BAD_REQUEST, "bad request".to_string()).into_response()
|
(StatusCode::BAD_REQUEST, "bad request".to_string()).into_response()
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Web End
|
// Web End
|
||||||
|
|
||||||
|
|
||||||
// It's an extractor that pulls a token from the Header.
|
// It's an extractor that pulls a token from the Header.
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Debug)]
|
||||||
pub struct Token(pub Option<String>);
|
pub struct Token(pub Option<String>);
|
||||||
|
|
@ -117,7 +134,10 @@ impl ToString for AuthSystem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn has_joined(server_id: &str, username: &str) -> anyhow::Result<Option<(Uuid, AuthSystem)>> {
|
pub async fn has_joined(
|
||||||
|
server_id: &str,
|
||||||
|
username: &str,
|
||||||
|
) -> anyhow::Result<Option<(Uuid, AuthSystem)>> {
|
||||||
let client = reqwest::Client::new();
|
let client = reqwest::Client::new();
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
Ok(Some(res)) = async {
|
Ok(Some(res)) = async {
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ pub struct Config {
|
||||||
pub advanced_users: Table,
|
pub advanced_users: Table,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn parse(path: PathBuf) -> Self {
|
pub fn parse(path: PathBuf) -> Self {
|
||||||
let mut file = std::fs::File::open(path).expect("Access denied or file doesn't exists!");
|
let mut file = std::fs::File::open(path).expect("Access denied or file doesn't exists!");
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
use axum::Json;
|
use axum::Json;
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
|
|
||||||
|
|
||||||
pub async fn version() -> Json<Value> {
|
pub async fn version() -> Json<Value> {
|
||||||
Json(json!({
|
Json(json!({
|
||||||
"release": "0.1.4",
|
"release": "0.1.4",
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,31 @@
|
||||||
use anyhow_http::{http_error_ret, response::Result};
|
use anyhow_http::{http_error_ret, response::Result};
|
||||||
use axum::{body::Bytes, debug_handler, extract::{Path, State}, Json};
|
use axum::{
|
||||||
|
body::Bytes,
|
||||||
|
debug_handler,
|
||||||
|
extract::{Path, State},
|
||||||
|
Json,
|
||||||
|
};
|
||||||
use log::{debug, warn};
|
use log::{debug, warn};
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
use tokio::{fs, io::{AsyncReadExt, BufWriter, self}};
|
use tokio::{
|
||||||
|
fs,
|
||||||
|
io::{self, AsyncReadExt, BufWriter},
|
||||||
|
};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::{auth::Token, utils::{calculate_file_sha256, format_uuid, get_correct_array}, ws::S2CMessage, AppState};
|
use crate::{
|
||||||
|
auth::Token,
|
||||||
|
utils::{calculate_file_sha256, format_uuid, get_correct_array},
|
||||||
|
ws::S2CMessage,
|
||||||
|
AppState,
|
||||||
|
};
|
||||||
|
|
||||||
#[debug_handler]
|
#[debug_handler]
|
||||||
pub async fn user_info(
|
pub async fn user_info(
|
||||||
Path(uuid): Path<Uuid>,
|
Path(uuid): Path<Uuid>,
|
||||||
State(state): State<AppState>, // FIXME: Variable doesn't using!
|
State(state): State<AppState>, // FIXME: Variable doesn't using!
|
||||||
) -> Json<Value> {
|
) -> Json<Value> {
|
||||||
log::info!("Receiving profile information for {}",uuid);
|
log::info!("Receiving profile information for {}", uuid);
|
||||||
|
|
||||||
let formatted_uuid = format_uuid(&uuid);
|
let formatted_uuid = format_uuid(&uuid);
|
||||||
|
|
||||||
|
|
@ -40,36 +53,40 @@ pub async fn user_info(
|
||||||
if let Some(settings) = state.advanced_users.lock().await.get(&formatted_uuid) {
|
if let Some(settings) = state.advanced_users.lock().await.get(&formatted_uuid) {
|
||||||
let pride = get_correct_array(settings.get("pride").unwrap());
|
let pride = get_correct_array(settings.get("pride").unwrap());
|
||||||
let special = get_correct_array(settings.get("special").unwrap());
|
let special = get_correct_array(settings.get("special").unwrap());
|
||||||
let badges = user_info_response.get_mut("equippedBadges").and_then(Value::as_object_mut).unwrap();
|
let badges = user_info_response
|
||||||
badges.append(json!({
|
.get_mut("equippedBadges")
|
||||||
|
.and_then(Value::as_object_mut)
|
||||||
|
.unwrap();
|
||||||
|
badges.append(
|
||||||
|
json!({
|
||||||
"special": special,
|
"special": special,
|
||||||
"pride": pride
|
"pride": pride
|
||||||
}).as_object_mut().unwrap())
|
})
|
||||||
|
.as_object_mut()
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if fs::metadata(&avatar_file).await.is_ok() {
|
if fs::metadata(&avatar_file).await.is_ok() {
|
||||||
if let Some(equipped) = user_info_response.get_mut("equipped").and_then(Value::as_array_mut){
|
if let Some(equipped) = user_info_response
|
||||||
match calculate_file_sha256(&avatar_file){
|
.get_mut("equipped")
|
||||||
Ok(hash) => {
|
.and_then(Value::as_array_mut)
|
||||||
equipped.push(json!({
|
{
|
||||||
|
match calculate_file_sha256(&avatar_file) {
|
||||||
|
Ok(hash) => equipped.push(json!({
|
||||||
"id": "avatar",
|
"id": "avatar",
|
||||||
"owner": &formatted_uuid,
|
"owner": &formatted_uuid,
|
||||||
"hash": hash
|
"hash": hash
|
||||||
}))
|
})),
|
||||||
}
|
|
||||||
Err(_e) => {}
|
Err(_e) => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Json(user_info_response)
|
Json(user_info_response)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[debug_handler]
|
#[debug_handler]
|
||||||
pub async fn download_avatar(
|
pub async fn download_avatar(Path(uuid): Path<Uuid>) -> Result<Vec<u8>> {
|
||||||
Path(uuid): Path<Uuid>,
|
|
||||||
) -> Result<Vec<u8>> {
|
|
||||||
let uuid = format_uuid(&uuid);
|
let uuid = format_uuid(&uuid);
|
||||||
log::info!("Requesting an avatar: {}", uuid);
|
log::info!("Requesting an avatar: {}", uuid);
|
||||||
let mut file = if let Ok(file) = fs::File::open(format!("avatars/{}.moon", uuid)).await {
|
let mut file = if let Ok(file) = fs::File::open(format!("avatars/{}.moon", uuid)).await {
|
||||||
|
|
@ -93,7 +110,6 @@ pub async fn upload_avatar(
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
body: Bytes,
|
body: Bytes,
|
||||||
) -> Result<String> {
|
) -> Result<String> {
|
||||||
|
|
||||||
let request_data = body;
|
let request_data = body;
|
||||||
|
|
||||||
let token = match token {
|
let token = match token {
|
||||||
|
|
@ -102,37 +118,46 @@ pub async fn upload_avatar(
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(user_info) = state.authenticated.get(&token) {
|
if let Some(user_info) = state.authenticated.get(&token) {
|
||||||
log::info!("{} ({}) trying to upload an avatar",user_info.uuid,user_info.username);
|
log::info!(
|
||||||
let avatar_file = format!("avatars/{}.moon",user_info.uuid);
|
"{} ({}) trying to upload an avatar",
|
||||||
|
user_info.uuid,
|
||||||
|
user_info.username
|
||||||
|
);
|
||||||
|
let avatar_file = format!("avatars/{}.moon", user_info.uuid);
|
||||||
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("ok".to_string())
|
Ok("ok".to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn equip_avatar(
|
pub async fn equip_avatar(Token(token): Token, State(state): State<AppState>) -> String {
|
||||||
Token(token): Token,
|
|
||||||
State(state): State<AppState>,
|
|
||||||
) -> String {
|
|
||||||
debug!("[API] S2C : Equip");
|
debug!("[API] S2C : Equip");
|
||||||
let uuid = state.authenticated.get(&token.unwrap()).unwrap().uuid;
|
let uuid = state.authenticated.get(&token.unwrap()).unwrap().uuid;
|
||||||
if state.broadcasts.get(&uuid).unwrap().send(S2CMessage::Event(uuid).to_vec()).is_err() {
|
if state
|
||||||
warn!("[WebSocket] Failed to send Event! Maybe there is no one to send") // FIXME: Засунуть в Handler
|
.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
|
||||||
};
|
};
|
||||||
"ok".to_string()
|
"ok".to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn delete_avatar(
|
pub async fn delete_avatar(Token(token): Token, State(state): State<AppState>) -> Result<String> {
|
||||||
Token(token): Token,
|
|
||||||
State(state): State<AppState>,
|
|
||||||
) -> Result<String> {
|
|
||||||
let token = match token {
|
let token = match token {
|
||||||
Some(t) => t,
|
Some(t) => t,
|
||||||
None => http_error_ret!(UNAUTHORIZED, "Authentication error!"),
|
None => http_error_ret!(UNAUTHORIZED, "Authentication error!"),
|
||||||
};
|
};
|
||||||
if let Some(user_info) = state.authenticated.get(&token) {
|
if let Some(user_info) = state.authenticated.get(&token) {
|
||||||
log::info!("{} ({}) is trying to delete the avatar",user_info.uuid,user_info.username);
|
log::info!(
|
||||||
let avatar_file = format!("avatars/{}.moon",user_info.uuid);
|
"{} ({}) is trying to delete the avatar",
|
||||||
|
user_info.uuid,
|
||||||
|
user_info.username
|
||||||
|
);
|
||||||
|
let avatar_file = format!("avatars/{}.moon", user_info.uuid);
|
||||||
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);
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,26 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use axum::{extract::{ws::{Message, WebSocket}, State, WebSocketUpgrade}, response::Response};
|
use axum::{
|
||||||
|
extract::{
|
||||||
|
ws::{Message, WebSocket},
|
||||||
|
State, WebSocketUpgrade,
|
||||||
|
},
|
||||||
|
response::Response,
|
||||||
|
};
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use log::{debug, error, info, trace, warn};
|
use log::{debug, error, info, trace, warn};
|
||||||
use tokio::sync::{broadcast::{self, Receiver}, mpsc, Notify};
|
use tokio::sync::{
|
||||||
|
broadcast::{self, Receiver},
|
||||||
|
mpsc, Notify,
|
||||||
|
};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::{ws::{C2SMessage, S2CMessage}, AppState};
|
use crate::{
|
||||||
|
ws::{C2SMessage, S2CMessage},
|
||||||
|
AppState,
|
||||||
|
};
|
||||||
|
|
||||||
pub async fn handler(
|
pub async fn handler(ws: WebSocketUpgrade, State(state): State<AppState>) -> Response {
|
||||||
ws: WebSocketUpgrade,
|
|
||||||
State(state): State<AppState>,
|
|
||||||
) -> Response {
|
|
||||||
ws.on_upgrade(|socket| handle_socket(socket, state))
|
ws.on_upgrade(|socket| handle_socket(socket, state))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -185,7 +194,11 @@ async fn handle_socket(mut socket: WebSocket, state: AppState) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn subscribe(socket: mpsc::Sender<Vec<u8>>, mut rx: Receiver<Vec<u8>>, shutdown: Arc<Notify>) {
|
async fn subscribe(
|
||||||
|
socket: mpsc::Sender<Vec<u8>>,
|
||||||
|
mut rx: Receiver<Vec<u8>>,
|
||||||
|
shutdown: Arc<Notify>,
|
||||||
|
) {
|
||||||
loop {
|
loop {
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
_ = shutdown.notified() => {
|
_ = shutdown.notified() => {
|
||||||
|
|
@ -204,5 +217,8 @@ async fn subscribe(socket: mpsc::Sender<Vec<u8>>, mut rx: Receiver<Vec<u8>>, shu
|
||||||
|
|
||||||
fn into_s2c_ping(buf: Vec<u8>, uuid: Uuid) -> Vec<u8> {
|
fn into_s2c_ping(buf: Vec<u8>, uuid: Uuid) -> Vec<u8> {
|
||||||
use std::iter::once;
|
use std::iter::once;
|
||||||
once(1).chain(uuid.into_bytes().iter().copied()).chain(buf.as_slice()[1..].iter().copied()).collect()
|
once(1)
|
||||||
|
.chain(uuid.into_bytes().iter().copied())
|
||||||
|
.chain(buf.as_slice()[1..].iter().copied())
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
mod c2s;
|
mod c2s;
|
||||||
mod s2c;
|
|
||||||
mod handler;
|
|
||||||
mod errors;
|
mod errors;
|
||||||
|
mod handler;
|
||||||
|
mod s2c;
|
||||||
|
|
||||||
pub use c2s::C2SMessage;
|
pub use c2s::C2SMessage;
|
||||||
pub use s2c::S2CMessage;
|
|
||||||
pub use handler::handler;
|
|
||||||
pub use errors::MessageLoadError;
|
pub use errors::MessageLoadError;
|
||||||
|
pub use handler::handler;
|
||||||
|
pub use s2c::S2CMessage;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue