mirror of
https://github.com/shiroyashik/sculptor.git
synced 2025-12-06 13:01:12 +03:00
added sending authSystem to user request
This commit is contained in:
parent
59440154c1
commit
2b5258d551
6 changed files with 81 additions and 47 deletions
27
src/auth.rs
27
src/auth.rs
|
|
@ -15,7 +15,7 @@ pub fn router() -> Router<AppState> {
|
|||
}
|
||||
|
||||
|
||||
// Веб функции
|
||||
// Web
|
||||
#[derive(Deserialize)]
|
||||
struct Id {username: String}
|
||||
|
||||
|
|
@ -25,7 +25,7 @@ async fn id( // First stage of authentication
|
|||
State(state): State<AppState>,
|
||||
) -> String {
|
||||
let server_id = bytes_into_string(&digest(&digest::SHA1_FOR_LEGACY_USE_ONLY, &rand()).as_ref()[0 .. 20]);
|
||||
let state = state.pending.lock().await;
|
||||
let state = state.pending;
|
||||
state.insert(server_id.clone(), query.username);
|
||||
server_id
|
||||
}
|
||||
|
|
@ -39,12 +39,12 @@ async fn verify( // Second stage of authentication
|
|||
State(state): State<AppState>,
|
||||
) -> String {
|
||||
let server_id = query.id.clone();
|
||||
let username = state.pending.lock().await.remove(&server_id).unwrap().1;
|
||||
let username = state.pending.remove(&server_id).unwrap().1;
|
||||
if let Some((uuid, auth_system)) = has_joined(&server_id, &username).await.unwrap() {
|
||||
info!("[Authorization] {username} logged in using {auth_system:?}");
|
||||
let authenticated = state.authenticated.lock().await;
|
||||
let authenticated = state.authenticated;
|
||||
// let link = state.authenticated_link.lock().await; // // Реализация поиска пользователя в HashMap по UUID
|
||||
authenticated.insert(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
|
||||
return format!("{server_id}")
|
||||
} else {
|
||||
|
|
@ -58,7 +58,7 @@ pub async fn status(
|
|||
) -> Response {
|
||||
match token {
|
||||
Some(token) => {
|
||||
if state.authenticated.lock().await.contains_key(&token) {
|
||||
if state.authenticated.contains_token(&token) {
|
||||
// format!("ok") // 200
|
||||
(StatusCode::OK, format!("ok")).into_response()
|
||||
} else {
|
||||
|
|
@ -72,10 +72,10 @@ pub async fn status(
|
|||
},
|
||||
}
|
||||
}
|
||||
// Конец веб функций
|
||||
// Web End
|
||||
|
||||
|
||||
// Это экстрактор достающий из Заголовка зовущегося токен, соответственно ТОКЕН.
|
||||
// It's an extractor that pulls a token from the Header.
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub struct Token(pub Option<String>);
|
||||
|
||||
|
|
@ -98,7 +98,7 @@ where
|
|||
}
|
||||
}
|
||||
}
|
||||
// Конец экстрактора
|
||||
// End Extractor
|
||||
|
||||
// Work with external APIs
|
||||
|
||||
|
|
@ -108,6 +108,15 @@ pub enum AuthSystem {
|
|||
Mojang,
|
||||
}
|
||||
|
||||
impl ToString for AuthSystem {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
AuthSystem::ElyBy => String::from("elyby"),
|
||||
AuthSystem::Mojang => String::from("mojang"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn has_joined(server_id: &str, username: &str) -> anyhow::Result<Option<(Uuid, AuthSystem)>> {
|
||||
let client = reqwest::Client::new();
|
||||
tokio::select! {
|
||||
|
|
|
|||
41
src/main.rs
41
src/main.rs
|
|
@ -41,14 +41,43 @@ pub struct Userinfo {
|
|||
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Authenticated {
|
||||
user_data: DashMap<String, Userinfo>,
|
||||
uuid: DashMap<Uuid, String>,
|
||||
}
|
||||
|
||||
impl Authenticated {
|
||||
fn new() -> Self {
|
||||
Self { user_data: DashMap::new(), uuid: DashMap::new() }
|
||||
}
|
||||
pub fn insert(&self, uuid: Uuid, token: String, userinfo: Userinfo) -> Option<Userinfo> {
|
||||
self.uuid.insert(uuid, token.clone());
|
||||
self.user_data.insert(token, userinfo)
|
||||
}
|
||||
pub fn get(&self, token: &String) -> Option<dashmap::mapref::one::Ref<'_, std::string::String, Userinfo>> {
|
||||
self.user_data.get(token)
|
||||
}
|
||||
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) {
|
||||
self.user_data.get(&token.to_string())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
pub fn contains_token(&self, token: &String) -> bool {
|
||||
self.user_data.contains_key(token)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AppState {
|
||||
// Users with incomplete authentication
|
||||
pending: Arc<Mutex<DashMap<String, String>>>, // <SHA1 serverId, USERNAME>
|
||||
pending: Arc<DashMap<String, String>>, // <SHA1 serverId, USERNAME>
|
||||
// Authenticated users
|
||||
authenticated: Arc<Mutex<DashMap<String, Userinfo>>>, // <SHA1 serverId, Userinfo> NOTE: In the future, try it in a separate LockRw branch
|
||||
authenticated: Arc<Authenticated>, // <SHA1 serverId, Userinfo> NOTE: In the future, try it in a separate LockRw branch
|
||||
// Ping broadcasts for WebSocket connections
|
||||
broadcasts: Arc<Mutex<DashMap<Uuid, broadcast::Sender<Vec<u8>>>>>,
|
||||
broadcasts: Arc<DashMap<Uuid, broadcast::Sender<Vec<u8>>>>,
|
||||
// Advanced configured users
|
||||
advanced_users: Arc<Mutex<toml::Table>>,
|
||||
}
|
||||
|
|
@ -83,9 +112,9 @@ async fn main() -> Result<()> {
|
|||
|
||||
// State
|
||||
let state = AppState {
|
||||
pending: Arc::new(Mutex::new(DashMap::new())),
|
||||
authenticated: Arc::new(Mutex::new(DashMap::new())),
|
||||
broadcasts: Arc::new(Mutex::new(DashMap::new())),
|
||||
pending: Arc::new(DashMap::new()),
|
||||
authenticated: Arc::new(Authenticated::new()),
|
||||
broadcasts: Arc::new(DashMap::new()),
|
||||
advanced_users: Arc::new(Mutex::new(config.advanced_users)),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -14,10 +14,15 @@ pub async fn user_info(
|
|||
) -> Json<Value> {
|
||||
log::info!("Receiving profile information for {}",uuid);
|
||||
|
||||
let formatted_uuid = format_uuid(uuid);
|
||||
let formatted_uuid = format_uuid(&uuid);
|
||||
|
||||
let avatar_file = format!("avatars/{}.moon", formatted_uuid);
|
||||
|
||||
let auth_system = match state.authenticated.get_by_uuid(&uuid) {
|
||||
Some(d) => d.auth_system.to_string(),
|
||||
None => return Json(json!("err")),
|
||||
};
|
||||
|
||||
let mut user_info_response = json!({
|
||||
"uuid": &formatted_uuid,
|
||||
"rank": "default",
|
||||
|
|
@ -28,7 +33,8 @@ pub async fn user_info(
|
|||
"pride": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
|
||||
},
|
||||
"version": "0.1.4+1.20.1",
|
||||
"banned": false
|
||||
"banned": false,
|
||||
"authSystem": auth_system // add Trust
|
||||
});
|
||||
|
||||
if let Some(settings) = state.advanced_users.lock().await.get(&formatted_uuid) {
|
||||
|
|
@ -64,7 +70,7 @@ pub async fn user_info(
|
|||
pub async fn download_avatar(
|
||||
Path(uuid): Path<Uuid>,
|
||||
) -> Result<Vec<u8>> {
|
||||
let uuid = format_uuid(uuid);
|
||||
let uuid = format_uuid(&uuid);
|
||||
log::info!("Requesting an avatar: {}", uuid);
|
||||
let mut file = if let Ok(file) = fs::File::open(format!("avatars/{}.moon", uuid)).await {
|
||||
file
|
||||
|
|
@ -94,9 +100,8 @@ pub async fn upload_avatar(
|
|||
Some(t) => t,
|
||||
None => http_error_ret!(UNAUTHORIZED, "Authentication error!"),
|
||||
};
|
||||
let userinfos = state.authenticated.lock().await;
|
||||
|
||||
if let Some(user_info) = userinfos.get(token.as_str()) {
|
||||
if let Some(user_info) = state.authenticated.get(&token) {
|
||||
log::info!("{} ({}) 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?);
|
||||
|
|
@ -110,8 +115,8 @@ pub async fn equip_avatar(
|
|||
State(state): State<AppState>,
|
||||
) -> String {
|
||||
debug!("[API] S2C : Equip");
|
||||
let uuid = state.authenticated.lock().await.get(&token.unwrap()).unwrap().uuid;
|
||||
if state.broadcasts.lock().await.get(&uuid).unwrap().send(S2CMessage::Event(uuid).to_vec()).is_err() {
|
||||
let uuid = state.authenticated.get(&token.unwrap()).unwrap().uuid;
|
||||
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
|
||||
};
|
||||
format!("ok")
|
||||
|
|
@ -125,8 +130,7 @@ pub async fn delete_avatar(
|
|||
Some(t) => t,
|
||||
None => http_error_ret!(UNAUTHORIZED, "Authentication error!"),
|
||||
};
|
||||
let userinfos = state.authenticated.lock().await;
|
||||
if let Some(user_info) = userinfos.get(token.as_str()) {
|
||||
if let Some(user_info) = state.authenticated.get(&token) {
|
||||
log::info!("{} ({}) 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?;
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ pub fn get_correct_array(value: &toml::Value) -> Vec<u8> {
|
|||
value.as_array().unwrap().iter().map(move |x| x.as_integer().unwrap() as u8).collect()
|
||||
}
|
||||
|
||||
pub fn format_uuid(uuid: Uuid) -> String {
|
||||
pub fn format_uuid(uuid: &Uuid) -> String {
|
||||
// let uuid = Uuid::parse_str(&uuid)?; TODO: Вероятно format_uuid стоит убрать
|
||||
// .map_err(|_| tide::Error::from_str(StatusCode::InternalServerError, "Failed to parse UUID"))?;
|
||||
uuid.as_hyphenated().to_string()
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ async fn handle_socket(mut socket: WebSocket, state: AppState) {
|
|||
if let Message::Close(_) = msg {
|
||||
info!("[WebSocket{}] Connection successfully closed!", owner.name());
|
||||
if let Some(u) = owner.0 {
|
||||
remove_broadcast(state.broadcasts.clone(), u.uuid).await;
|
||||
state.broadcasts.remove(&u.uuid);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -57,7 +57,7 @@ async fn handle_socket(mut socket: WebSocket, state: AppState) {
|
|||
} else {
|
||||
warn!("[WebSocket{}] Receive error! Connection terminated!", owner.name());
|
||||
if let Some(u) = owner.0 {
|
||||
remove_broadcast(state.broadcasts.clone(), u.uuid).await;
|
||||
state.broadcasts.remove(&u.uuid);
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
|
@ -70,7 +70,7 @@ async fn handle_socket(mut socket: WebSocket, state: AppState) {
|
|||
Err(e) => {
|
||||
error!("[WebSocket{}] This message is not from Figura! {e:?}", owner.name());
|
||||
if let Some(u) = owner.0 {
|
||||
remove_broadcast(state.broadcasts.clone(), u.uuid).await;
|
||||
state.broadcasts.remove(&u.uuid);
|
||||
}
|
||||
return;
|
||||
},
|
||||
|
|
@ -82,20 +82,18 @@ async fn handle_socket(mut socket: WebSocket, state: AppState) {
|
|||
C2SMessage::Token(token) => { // FIXME: Написать переменную спомощью которой бужет проверяться авторизовался ли пользователь или нет
|
||||
debug!("[WebSocket{}] C2S : Token", owner.name());
|
||||
let token = String::from_utf8(token.to_vec()).unwrap();
|
||||
let authenticated = state.authenticated.lock().await;
|
||||
match authenticated.get(&token) { // Принцип прост: если токена в authenticated нет, значит это trash
|
||||
match state.authenticated.get(&token) { // Принцип прост: если токена в authenticated нет, значит это trash
|
||||
Some(t) => {
|
||||
//username = t.username.clone();
|
||||
owner.0 = Some(WSUser { username: t.username.clone(), token, uuid: t.uuid });
|
||||
msg = Message::Binary(S2CMessage::Auth.to_vec());
|
||||
let bcs = state.broadcasts.lock().await;
|
||||
match bcs.get(&t.uuid) {
|
||||
match state.broadcasts.get(&t.uuid) {
|
||||
Some(tx) => {
|
||||
bctx = Some(tx.to_owned());
|
||||
},
|
||||
None => {
|
||||
let (tx, _rx) = broadcast::channel(64);
|
||||
bcs.insert(t.uuid, tx.clone());
|
||||
state.broadcasts.insert(t.uuid, tx.clone());
|
||||
bctx = Some(tx.to_owned());
|
||||
},
|
||||
};
|
||||
|
|
@ -104,7 +102,7 @@ async fn handle_socket(mut socket: WebSocket, state: AppState) {
|
|||
warn!("[WebSocket] Authenticaton error! Connection terminated!");
|
||||
debug!("[WebSocket] Tried to log in with {token}"); // Tried to log in with token: {token}
|
||||
if let Some(u) = owner.0 {
|
||||
remove_broadcast(state.broadcasts.clone(), u.uuid).await;
|
||||
state.broadcasts.remove(&u.uuid);
|
||||
}
|
||||
return; // TODO: Прописать код отключения
|
||||
},
|
||||
|
|
@ -115,7 +113,7 @@ async fn handle_socket(mut socket: WebSocket, state: AppState) {
|
|||
let data = into_s2c_ping(msg_vec, owner.0.clone().unwrap().uuid);
|
||||
match bctx.clone().unwrap().send(data) {
|
||||
Ok(_) => (),
|
||||
Err(_) => warn!("[WebSocket{}] Failed to send Ping! Maybe there's no one to send", owner.name()),
|
||||
Err(_) => debug!("[WebSocket{}] Failed to send Ping! Maybe there's no one to send", owner.name()),
|
||||
};
|
||||
continue;
|
||||
},
|
||||
|
|
@ -126,13 +124,12 @@ async fn handle_socket(mut socket: WebSocket, state: AppState) {
|
|||
continue;
|
||||
};
|
||||
|
||||
let broadcast = state.broadcasts.lock().await;
|
||||
let rx = match broadcast.get(&uuid) {
|
||||
let rx = match state.broadcasts.get(&uuid) {
|
||||
Some(rx) => rx.to_owned().subscribe(),
|
||||
None => {
|
||||
warn!("[WebSocket{}] Attention! The required UUID for subscription was not found!", owner.name());
|
||||
let (tx, rx) = broadcast::channel(64);
|
||||
broadcast.insert(uuid, tx);
|
||||
state.broadcasts.insert(uuid, tx);
|
||||
rx
|
||||
},
|
||||
};
|
||||
|
|
@ -159,7 +156,7 @@ async fn handle_socket(mut socket: WebSocket, state: AppState) {
|
|||
if socket.send(msg).await.is_err() {
|
||||
warn!("[WebSocket{}] Send error! Connection terminated!", owner.name());
|
||||
if let Some(u) = owner.0 {
|
||||
remove_broadcast(state.broadcasts.clone(), u.uuid).await;
|
||||
state.broadcasts.remove(&u.uuid);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -172,7 +169,7 @@ async fn handle_socket(mut socket: WebSocket, state: AppState) {
|
|||
Err(_) => {
|
||||
warn!("[WebSocketSubscriber{}] Send error! Connection terminated!", owner.name());
|
||||
if let Some(u) = owner.0 {
|
||||
remove_broadcast(state.broadcasts.clone(), u.uuid).await;
|
||||
state.broadcasts.remove(&u.uuid);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -202,9 +199,4 @@ 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> {
|
||||
use std::iter::once;
|
||||
once(1).chain(uuid.into_bytes().iter().copied()).chain(buf.as_slice()[1..].iter().copied()).collect()
|
||||
}
|
||||
|
||||
async fn remove_broadcast(broadcasts: Arc<tokio::sync::Mutex<DashMap<Uuid, broadcast::Sender<Vec<u8>>>>>, uuid: Uuid) {
|
||||
let map = broadcasts.lock().await;
|
||||
map.remove(&uuid);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue