prevent double logins
This commit is contained in:
parent
05596cec4f
commit
c802bceb3c
@ -58,7 +58,6 @@ fn main() {
|
||||
team_id: None,
|
||||
banned_until: None,
|
||||
muted_until: None,
|
||||
created_at: chrono::Utc::now(),
|
||||
flags: 0,
|
||||
activated: true,
|
||||
};
|
||||
|
@ -21,9 +21,24 @@ pub struct NewUserAccountEntity {
|
||||
pub team_id: Option<u32>,
|
||||
pub banned_until: Option<chrono::DateTime<chrono::Utc>>,
|
||||
pub muted_until: Option<chrono::DateTime<chrono::Utc>>,
|
||||
pub created_at: chrono::DateTime<chrono::Utc>,
|
||||
pub flags: u32,
|
||||
pub activated: bool,
|
||||
pub activated: bool
|
||||
}
|
||||
|
||||
impl Default for NewUserAccountEntity {
|
||||
fn default() -> NewUserAccountEntity {
|
||||
NewUserAccountEntity {
|
||||
email: "".into(),
|
||||
username: "".into(),
|
||||
password: "".into(),
|
||||
guildcard: 0xFFFFFFFF,
|
||||
team_id: None,
|
||||
banned_until: None,
|
||||
muted_until: None,
|
||||
flags: 0,
|
||||
activated: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@ -38,8 +53,18 @@ pub struct UserAccountEntity {
|
||||
pub created_at: chrono::DateTime<chrono::Utc>,
|
||||
pub flags: u32, // TODO: is this used for anything other than character creation?
|
||||
pub activated: bool,
|
||||
pub at_login: bool,
|
||||
pub at_character: bool,
|
||||
pub at_ship: bool,
|
||||
}
|
||||
|
||||
impl UserAccountEntity {
|
||||
pub fn is_currently_online(&self) -> bool {
|
||||
self.at_login | self.at_character | self.at_ship
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct NewUserSettingsEntity {
|
||||
pub user_id: UserAccountId,
|
||||
|
@ -45,9 +45,12 @@ impl EntityGateway for InMemoryGateway {
|
||||
team_id: user.team_id,
|
||||
banned_until: user.banned_until,
|
||||
muted_until: user.muted_until,
|
||||
created_at: user.created_at,
|
||||
created_at: chrono::Utc::now(),
|
||||
flags: user.flags,
|
||||
activated: user.activated,
|
||||
at_login: false,
|
||||
at_character: false,
|
||||
at_ship: false,
|
||||
};
|
||||
users.insert(user.id, user.clone());
|
||||
Ok(user)
|
||||
|
@ -9,7 +9,10 @@ create table user_accounts (
|
||||
flags integer default 0 not null,
|
||||
activated boolean default false not null,
|
||||
game_session integer,
|
||||
interserver_session integer
|
||||
interserver_session integer,
|
||||
at_login boolean default false not null,
|
||||
at_character boolean default false not null,
|
||||
at_ship boolean default false not null
|
||||
);
|
||||
|
||||
create table user_settings (
|
||||
|
@ -18,6 +18,9 @@ pub struct PgUserAccount {
|
||||
created_at: chrono::DateTime<chrono::Utc>,
|
||||
flags: i32,
|
||||
activated: bool,
|
||||
at_login: bool,
|
||||
at_character: bool,
|
||||
at_ship: bool,
|
||||
}
|
||||
|
||||
impl Into<UserAccountEntity> for PgUserAccount {
|
||||
@ -32,7 +35,10 @@ impl Into<UserAccountEntity> for PgUserAccount {
|
||||
flags: self.flags as u32,
|
||||
guildcard: self.id as u32 + 1,
|
||||
team_id: None,
|
||||
activated: self.activated
|
||||
activated: self.activated,
|
||||
at_login: self.at_login,
|
||||
at_character: self.at_character,
|
||||
at_ship: self.at_ship,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ use crate::entity::item::tool::Tool;
|
||||
use crate::entity::item::mag::Mag;
|
||||
use crate::entity::character::{CharacterEntity, NewCharacterEntity, CharacterClass, TechLevel};
|
||||
|
||||
use crate::login::login::get_login_status;
|
||||
use crate::login::login::{get_login_status, check_if_already_online};
|
||||
|
||||
pub const CHARACTER_PORT: u16 = 12001;
|
||||
const SHIP_MENU_ID: u32 = 1;
|
||||
@ -39,6 +39,7 @@ pub enum CharacterError {
|
||||
CouldNotLoadSettings,
|
||||
CouldNotLoadCharacters,
|
||||
CouldNotLoadGuildcard,
|
||||
DbError,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -280,8 +281,11 @@ impl<EG: EntityGateway> CharacterServerState<EG> {
|
||||
|
||||
async fn validate_login(&mut self, id: ClientId, pkt: &Login) -> Result<Vec<SendCharacterPacket>, CharacterError> {
|
||||
let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?;
|
||||
Ok(match get_login_status(&self.entity_gateway, pkt).await {
|
||||
Ok(user) => {
|
||||
Ok(match get_login_status(&self.entity_gateway, pkt).await.and_then(check_if_already_online) {
|
||||
Ok(mut user) => {
|
||||
user.at_character = true;
|
||||
self.entity_gateway.save_user(&user).await.map_err(|_| CharacterError::DbError)?;
|
||||
|
||||
let mut response = LoginResponse::by_status(AccountStatus::Ok, Session::new());
|
||||
response.guildcard = user.guildcard;
|
||||
response.team_id = user.team_id.map_or(0, |ti| ti) as u32;
|
||||
@ -471,7 +475,7 @@ impl<EG: EntityGateway> ServerState for CharacterServerState<EG> {
|
||||
type RecvPacket = RecvCharacterPacket;
|
||||
type PacketError = CharacterError;
|
||||
|
||||
fn on_connect(&mut self, id: ClientId) -> Vec<OnConnect<Self::SendPacket>> {
|
||||
async fn on_connect(&mut self, id: ClientId) -> Vec<OnConnect<Self::SendPacket>> {
|
||||
self.clients.insert(id, ClientState::new());
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
@ -531,7 +535,13 @@ impl<EG: EntityGateway> ServerState for CharacterServerState<EG> {
|
||||
})
|
||||
}
|
||||
|
||||
fn on_disconnect(&mut self, _id: ClientId) -> Vec<(ClientId, SendCharacterPacket)> {
|
||||
async fn on_disconnect(&mut self, id: ClientId) -> Vec<(ClientId, SendCharacterPacket)> {
|
||||
if let Some(client) = self.clients.remove(&id) {
|
||||
if let Some(mut user) = client.user {
|
||||
user.at_character= false;
|
||||
self.entity_gateway.save_user(&user).await;
|
||||
}
|
||||
}
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
@ -684,6 +694,9 @@ mod test {
|
||||
team_id: None,
|
||||
flags: 0,
|
||||
activated: true,
|
||||
at_login: false,
|
||||
at_character: false,
|
||||
at_ship: false,
|
||||
});
|
||||
server.clients.insert(ClientId(5), clientstate);
|
||||
|
||||
@ -728,6 +741,9 @@ mod test {
|
||||
created_at: chrono::Utc::now(),
|
||||
flags: 0,
|
||||
activated: true,
|
||||
at_login: false,
|
||||
at_character: false,
|
||||
at_ship: false,
|
||||
});
|
||||
|
||||
let mut server = CharacterServerState::new(test_data.clone());
|
||||
|
@ -1,5 +1,6 @@
|
||||
// TODO: rename this module to auth
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::net;
|
||||
|
||||
use rand::Rng;
|
||||
@ -21,6 +22,7 @@ pub const COMMUNICATION_PORT: u16 = 12123;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum LoginError {
|
||||
DbError
|
||||
}
|
||||
|
||||
|
||||
@ -61,6 +63,10 @@ pub async fn get_login_status(entity_gateway: &impl EntityGateway, pkt: &Login)
|
||||
let username = array_to_utf8(pkt.username).map_err(|_err| AccountStatus::Error)?;
|
||||
let password = array_to_utf8(pkt.password).map_err(|_err| AccountStatus::Error)?;
|
||||
let user = entity_gateway.get_user_by_name(username).await.map_err(|_| AccountStatus::InvalidUser)?;
|
||||
if user.is_currently_online() {
|
||||
return Err(AccountStatus::AlreadyOnline)
|
||||
}
|
||||
|
||||
if !user.activated {
|
||||
return Err(AccountStatus::PayUp)
|
||||
}
|
||||
@ -77,10 +83,19 @@ pub async fn get_login_status(entity_gateway: &impl EntityGateway, pkt: &Login)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_if_already_online(user: UserAccountEntity) -> Result<UserAccountEntity, AccountStatus> {
|
||||
if user.is_currently_online() {
|
||||
Err(AccountStatus::PayUp)
|
||||
}
|
||||
else {
|
||||
Ok(user)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct LoginServerState<EG: EntityGateway> {
|
||||
character_server_ip: net::Ipv4Addr,
|
||||
entity_gateway: EG,
|
||||
clients: HashMap<ClientId, String>,
|
||||
}
|
||||
|
||||
impl<EG: EntityGateway> LoginServerState<EG> {
|
||||
@ -88,20 +103,24 @@ impl<EG: EntityGateway> LoginServerState<EG> {
|
||||
LoginServerState {
|
||||
entity_gateway: entity_gateway,
|
||||
character_server_ip: character_server_ip.into(),
|
||||
clients: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
async fn validate_login(&mut self, pkt: &Login) -> Vec<SendLoginPacket> {
|
||||
match get_login_status(&self.entity_gateway, pkt).await {
|
||||
Ok(_user) => {
|
||||
async fn validate_login(&mut self, id: ClientId, pkt: &Login) -> Result<Vec<SendLoginPacket>, LoginError> {
|
||||
match get_login_status(&self.entity_gateway, pkt).await.and_then(check_if_already_online) {
|
||||
Ok(mut user) => {
|
||||
user.at_login = true;
|
||||
self.entity_gateway.save_user(&user).await.map_err(|_| LoginError::DbError)?;
|
||||
self.clients.insert(id, user.username.clone());
|
||||
|
||||
let response = SendLoginPacket::LoginResponse(LoginResponse::by_status(AccountStatus::Ok, pkt.session));
|
||||
//let ip = net::Ipv4Addr::new(127,0,0,1);
|
||||
let ip = u32::from_ne_bytes(self.character_server_ip.octets());
|
||||
vec![response,
|
||||
SendLoginPacket::RedirectClient(RedirectClient::new(ip, crate::login::character::CHARACTER_PORT))]
|
||||
Ok(vec![response,
|
||||
SendLoginPacket::RedirectClient(RedirectClient::new(ip, crate::login::character::CHARACTER_PORT))])
|
||||
},
|
||||
Err(err) => {
|
||||
vec![SendLoginPacket::LoginResponse(LoginResponse::by_status(err, pkt.session))]
|
||||
Ok(vec![SendLoginPacket::LoginResponse(LoginResponse::by_status(err, pkt.session))])
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -131,7 +150,7 @@ impl<EG: EntityGateway> ServerState for LoginServerState<EG> {
|
||||
-> Result<Box<dyn Iterator<Item = (ClientId, Self::SendPacket)> + Send>, LoginError> {
|
||||
Ok(match pkt {
|
||||
RecvLoginPacket::Login(login) => {
|
||||
Box::new(self.validate_login(login).await
|
||||
Box::new(self.validate_login(id, login).await?
|
||||
.into_iter()
|
||||
.map(move |pkt| {
|
||||
(id, pkt)
|
||||
@ -140,7 +159,13 @@ impl<EG: EntityGateway> ServerState for LoginServerState<EG> {
|
||||
})
|
||||
}
|
||||
|
||||
async fn on_disconnect(&mut self, _id: ClientId) -> Vec<(ClientId, SendLoginPacket)> {
|
||||
async fn on_disconnect(&mut self, id: ClientId) -> Vec<(ClientId, SendLoginPacket)> {
|
||||
if let Some(username) = self.clients.remove(&id) {
|
||||
if let Ok(mut user) = self.entity_gateway.get_user_by_name(username).await {
|
||||
user.at_login = false;
|
||||
self.entity_gateway.save_user(&user).await;
|
||||
}
|
||||
}
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
@ -197,6 +222,9 @@ mod test {
|
||||
created_at: chrono::Utc::now(),
|
||||
flags: 0,
|
||||
activated: true,
|
||||
at_login: false,
|
||||
at_character: false,
|
||||
at_ship: false,
|
||||
})
|
||||
}
|
||||
};
|
||||
@ -282,6 +310,9 @@ mod test {
|
||||
created_at: chrono::Utc::now(),
|
||||
flags: 0,
|
||||
activated: true,
|
||||
at_login: false,
|
||||
at_character: false,
|
||||
at_ship: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -328,6 +359,9 @@ mod test {
|
||||
created_at: chrono::Utc::now(),
|
||||
flags: 0,
|
||||
activated: true,
|
||||
at_login: false,
|
||||
at_character: false,
|
||||
at_ship: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ use libpso::packet::login::{Login, LoginResponse, AccountStatus, Session};
|
||||
use libpso::packet::ship::*;
|
||||
use crate::common::serverstate::ClientId;
|
||||
use crate::ship::ship::{SendShipPacket, ShipError, ClientState, Clients};
|
||||
use crate::login::login::get_login_status;
|
||||
use crate::login::login::{get_login_status, check_if_already_online};
|
||||
use crate::entity::gateway::EntityGateway;
|
||||
use crate::ship::items::ItemManager;
|
||||
|
||||
@ -13,8 +13,11 @@ pub async fn validate_login<EG: EntityGateway>(id: ClientId,
|
||||
item_manager: &mut ItemManager,
|
||||
ship_name: &String)
|
||||
-> Result<Vec<SendShipPacket>, ShipError> {
|
||||
Ok(match get_login_status(entity_gateway, pkt).await {
|
||||
Ok(user) => {
|
||||
Ok(match get_login_status(entity_gateway, pkt).await.and_then(check_if_already_online) {
|
||||
Ok(mut user) => {
|
||||
user.at_ship= true;
|
||||
entity_gateway.save_user(&user).await?;
|
||||
|
||||
let mut response = LoginResponse::by_status(AccountStatus::Ok, Session::new());
|
||||
response.guildcard = user.id.0 as u32;
|
||||
response.team_id = user.team_id.map_or(31, |ti| ti) as u32;
|
||||
|
@ -600,6 +600,11 @@ impl<EG: EntityGateway> ServerState for ShipServerState<EG> {
|
||||
self.client_location.remove_client_from_area(id);
|
||||
self.item_manager.remove_character_from_room(&client.character);
|
||||
|
||||
if let Some(mut client) = self.clients.remove(&id) {
|
||||
client.user.at_ship = false;
|
||||
self.entity_gateway.save_user(&client.user).await;
|
||||
}
|
||||
|
||||
neighbors.into_iter().map(|n| {
|
||||
(n.client, pkt.clone())
|
||||
}).collect()
|
||||
|
@ -18,12 +18,8 @@ pub async fn new_user_character<EG: EntityGateway>(entity_gateway: &mut EG, user
|
||||
username: username.into(),
|
||||
password: bcrypt::hash(password, 5).unwrap(),
|
||||
guildcard: 1,
|
||||
team_id: None,
|
||||
banned_until: None,
|
||||
muted_until: None,
|
||||
created_at: chrono::Utc::now(),
|
||||
flags: 0,
|
||||
activated: true,
|
||||
..NewUserAccountEntity::default()
|
||||
};
|
||||
|
||||
let user = entity_gateway.create_user(new_user).await.unwrap();
|
||||
|
Loading…
x
Reference in New Issue
Block a user