Format code

This commit is contained in:
Cappy Ishihara 2024-06-02 03:12:57 +07:00
parent 45192ef182
commit 026c6a950e
No known key found for this signature in database
GPG key ID: 50862C285CB76906
8 changed files with 145 additions and 86 deletions

View file

@ -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 {

View file

@ -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!");

View file

@ -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",

View file

@ -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")
"special": special, .and_then(Value::as_object_mut)
"pride": pride .unwrap();
}).as_object_mut().unwrap()) badges.append(
json!({
"special": special,
"pride": pride
})
.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!({ {
"id": "avatar", match calculate_file_sha256(&avatar_file) {
"owner": &formatted_uuid, Ok(hash) => equipped.push(json!({
"hash": hash "id": "avatar",
})) "owner": &formatted_uuid,
} "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 {
@ -92,8 +109,7 @@ pub async fn upload_avatar(
Token(token): Token, Token(token): Token,
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);

View file

@ -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()
} }

View file

@ -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;