diff --git a/Cargo.lock b/Cargo.lock index f098c2c441..901b3da8d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3878,6 +3878,7 @@ dependencies = [ name = "veloren-common" version = "0.5.0" dependencies = [ + "authc 1.0.0 (git+https://gitlab.com/veloren/auth.git?rev=7c1abde83f0ea7d83b0e7c655fac82eb9bb3d7ad)", "bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/client/src/lib.rs b/client/src/lib.rs index 723c348b11..6a169f8e4a 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -552,6 +552,7 @@ impl Client { ServerError::TooManyPlayers => return Err(Error::ServerWentMad), ServerError::InvalidAuth => return Err(Error::InvalidAuth), ServerError::AlreadyLoggedIn => return Err(Error::AlreadyLoggedIn), + ServerError::AuthError(_) => unreachable!(), //TODO: ServerError::InvalidAlias => return Err(Error::InvalidAlias), }, ServerMsg::Shutdown => return Err(Error::ServerShutdown), diff --git a/common/Cargo.toml b/common/Cargo.toml index f28f688c43..fe3123a720 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -33,6 +33,7 @@ crossbeam = "=0.7.2" notify = "5.0.0-pre.1" indexmap = "1.3.0" sum_type = "0.2.0" +authc = { git = "https://gitlab.com/veloren/auth.git", rev = "7c1abde83f0ea7d83b0e7c655fac82eb9bb3d7ad" } [dev-dependencies] criterion = "0.3" diff --git a/common/src/msg/server.rs b/common/src/msg/server.rs index c472bd1942..8159dfb874 100644 --- a/common/src/msg/server.rs +++ b/common/src/msg/server.rs @@ -4,6 +4,7 @@ use crate::{ terrain::{Block, TerrainChunk}, ChatType, }; +use authc::AuthClientError; use hashbrown::HashMap; use vek::*; @@ -88,9 +89,14 @@ pub enum ServerError { TooManyPlayers, InvalidAuth, AlreadyLoggedIn, + AuthError(String), //TODO: InvalidAlias, } +impl From for ServerError { + fn from(err: AuthClientError) -> Self { Self::AuthError(err.to_string()) } +} + impl ServerMsg { pub fn chat(message: String) -> ServerMsg { ServerMsg::ChatMsg { diff --git a/server/src/auth_provider.rs b/server/src/auth_provider.rs index 198df45c41..4e7861f0bf 100644 --- a/server/src/auth_provider.rs +++ b/server/src/auth_provider.rs @@ -1,8 +1,39 @@ -use authc::{AuthClient, AuthToken}; +use authc::{AuthClient, AuthToken, Uuid}; use common::msg::ServerError; use hashbrown::HashMap; use std::str::FromStr; +fn contains_value(map: &HashMap, value: &str) -> bool { + let mut contains = false; + for ev in map.values() { + if value == ev { + contains = true; + } + } + contains +} + +fn derive_uuid(username: &str) -> Uuid { + let mut state: [u8; 16] = [ + 52, 17, 19, 239, 52, 17, 19, 239, 52, 17, 19, 239, 52, 17, 19, 239, + ]; + for mix_byte_1 in username.as_bytes() { + for i in 0..16 { + let mix_byte_step: u8 = mix_byte_1 + .wrapping_pow(239) + .wrapping_mul((i as u8).wrapping_pow(43)); + let mix_byte_2 = state[i + mix_byte_step as usize % 16]; + let rot_step: u8 = mix_byte_1 + .wrapping_pow(29) + .wrapping_mul((i as u8).wrapping_pow(163)); + state[i] = (state[i] ^ mix_byte_1) + .wrapping_mul(mix_byte_2) + .rotate_left(rot_step as u32); + } + } + Uuid::from_slice(&state).unwrap() +} + pub struct AuthProvider { accounts: HashMap, auth_server: Option, @@ -27,28 +58,29 @@ impl AuthProvider { match &self.auth_server { // Token from auth server expected Some(srv) => { - // TODO: Check if already logged in! log::info!("Validating '{}' token.", &username_or_token); - match srv.validate( - AuthToken::from_str(&username_or_token).expect("Failed parsing token"), // TODO: POSSIBLE DOS, handle result! - ) { - Ok(id) => { - // TODO: Get username! - self.accounts.insert("peter".into(), id.to_string()); - Ok(true) - } - Err(e) => { - log::error!("{}", e); - Ok(false) + if let Ok(token) = AuthToken::from_str(&username_or_token) { + match srv.validate(token) { + Ok(id) => { + if contains_value(&self.accounts, &id.to_string()) { + return Err(ServerError::AlreadyLoggedIn); + } + let username = srv.uuid_to_username(id.clone())?; + self.accounts.insert(username, id.to_string()); + Ok(true) + }, + Err(e) => Err(ServerError::from(e)), } + } else { + Ok(false) } }, // Username is expected None => { if !self.accounts.contains_key(&username_or_token) { log::info!("New User '{}'", username_or_token); - self.accounts - .insert(username_or_token, "whateverUUID".into()); // TODO: generate UUID + let uuid = derive_uuid(&username_or_token); + self.accounts.insert(username_or_token, uuid.to_string()); Ok(true) } else { Err(ServerError::AlreadyLoggedIn)