From 2fb97cc2b6e8a4b845da2ee9c7b610fc2d80e64c Mon Sep 17 00:00:00 2001 From: Jake Probst Date: Fri, 23 Aug 2019 23:01:36 -0700 Subject: [PATCH] data access interface --- src/common/client.rs | 4 +- src/login/character.rs | 22 ++++------ src/login/dataaccess.rs | 48 +++++++++++++++++++++ src/login/login.rs | 94 ++++++++++++----------------------------- src/login/main.rs | 51 ++++++++++++++++------ src/main.rs | 8 ---- src/patch/main.rs | 7 +-- 7 files changed, 129 insertions(+), 105 deletions(-) create mode 100644 src/login/dataaccess.rs delete mode 100644 src/main.rs diff --git a/src/common/client.rs b/src/common/client.rs index 3369f0e..a813586 100644 --- a/src/common/client.rs +++ b/src/common/client.rs @@ -61,6 +61,7 @@ impl Client { // TODO: this may need to pad to 8 bytes for bb cipher fn send(&mut self, pkt: &dyn PSOPacket) { + println!("[send] {:?}", pkt); let buf = pkt.as_bytes(); let mut cbuf = self.cipher_out.encrypt(&buf).unwrap(); self.send_buffer.append(&mut cbuf); @@ -90,6 +91,7 @@ impl Client { match pkt { Ok(pkt) => { + println!("[recv] {:?}", pkt); let response = self.state.handle(&pkt); for r in response { self.send(&*r); @@ -98,7 +100,7 @@ impl Client { Err(err) => { match err { PacketNetworkError::ClientDisconnected => self.running = false, - _ => println!("error recv-ing packet with {:?}: {:?}", self.socket, err), + _ => {} //println!("error recv-ing packet with {:?}: {:?}", self.socket, err), } break; } diff --git a/src/login/character.rs b/src/login/character.rs index 282d4bb..62c2062 100644 --- a/src/login/character.rs +++ b/src/login/character.rs @@ -3,11 +3,6 @@ use std::net; use rand::{Rng, RngCore}; use bcrypt::{DEFAULT_COST, hash, verify}; -use diesel::r2d2; -use diesel::prelude::*; -use diesel::pg::PgConnection; -use elseware::schema::*; - use libpso::packet::login::*; use libpso::{PacketParseError, PSOPacket}; use libpso::crypto::{CipherError, PSOCipher, NullCipher}; @@ -21,11 +16,11 @@ use elseware::common::client::Client; use elseware::common::serverstate::{ServerPacket, ServerState, OnConnect}; use elseware::common::util::array_to_utf8; +use crate::dataaccess::DataAccess; use crate::login::{SharedLoginState, get_login_status}; use crate::models::UserAccount; pub const CHARACTER_PORT: u16 = 12001; -type ConnectionPool = r2d2::Pool>; #[derive(Debug)] pub enum CharacterError { @@ -47,13 +42,13 @@ impl ServerPacket for CharacterPacket { } } -pub struct CharacterServerState { - shared_state: SharedLoginState, +pub struct CharacterServerState { + shared_state: SharedLoginState, user: Option, } -impl CharacterServerState { - fn new(shared_state: SharedLoginState) -> CharacterServerState { +impl CharacterServerState { + fn new(shared_state: SharedLoginState) -> CharacterServerState { CharacterServerState { shared_state: shared_state, user: None, @@ -61,7 +56,7 @@ impl CharacterServerState { } fn validate_login(&mut self, pkt: &Login) -> Box { - match get_login_status(&self.shared_state.connection_pool, pkt) { + match get_login_status(&self.shared_state.data_access, pkt) { Ok(user) => { let mut response = LoginResponse::by_status(AccountStatus::Ok, pkt.security_data); response.guildcard = user.guildcard.map_or(0, |gc| gc) as u32; @@ -80,7 +75,7 @@ impl CharacterServerState { } } -impl ServerState for CharacterServerState { +impl ServerState for CharacterServerState { type Packet = CharacterPacket; type PacketError = CharacterError; @@ -107,7 +102,6 @@ impl ServerState for CharacterServerState { CharacterPacket::RequestSettings(_req) => { self.get_settings() } - } } } @@ -116,7 +110,7 @@ impl ServerState for CharacterServerState { -pub fn new_client(socket: mio::tcp::TcpStream, shared_state: SharedLoginState) { +pub fn new_client(socket: mio::tcp::TcpStream, shared_state: SharedLoginState) { let state = CharacterServerState::new(shared_state); let client = Client::new(socket, Box::new(state)); client.io_loop(); diff --git a/src/login/dataaccess.rs b/src/login/dataaccess.rs new file mode 100644 index 0000000..3a719d2 --- /dev/null +++ b/src/login/dataaccess.rs @@ -0,0 +1,48 @@ +use diesel::r2d2; +use diesel::prelude::*; +use diesel::pg::PgConnection; + +use crate::models::*; + +type ConnectionPool = r2d2::Pool>; + +pub trait DataAccess { + fn get_user_by_id(&self, id: u32) -> Option { + unimplemented!(); + } + + fn get_user_by_name(&self, username: String) -> Option { + unimplemented!(); + } +} + +#[derive(Clone)] +pub struct DBAccess { + connection_pool: ConnectionPool, +} + +impl DBAccess { + pub fn new(pool: ConnectionPool) -> DBAccess { + DBAccess { + connection_pool: pool, + } + } +} + + +impl DataAccess for DBAccess { + fn get_user_by_name(&self, name: String) -> Option { + use elseware::schema::user_accounts::dsl::{user_accounts, username}; + self.connection_pool.get() + .map(|conn| { + user_accounts.filter(username.eq(name)).load::(&conn) + .map(|mut user| user.pop()).unwrap_or(None) + }) + .unwrap_or(None) + } +} + + +/*impl DataAccess for DatabaseAccess { +}*/ + diff --git a/src/login/login.rs b/src/login/login.rs index 28e99bc..963777a 100644 --- a/src/login/login.rs +++ b/src/login/login.rs @@ -1,13 +1,10 @@ +// TODO: rename this module to auth + use std::net; use rand::{Rng, RngCore}; use bcrypt::{DEFAULT_COST, hash, verify}; -use diesel::r2d2; -use diesel::prelude::*; -use diesel::pg::PgConnection; -use elseware::schema::*; - use libpso::packet::login::*; use libpso::{PacketParseError, PSOPacket}; use libpso::crypto::{CipherError, PSOCipher, NullCipher}; @@ -16,15 +13,16 @@ use libpso::crypto::bb::PSOBBCipher; use elseware::pktvec; use elseware::common::pktvec::PktVec; use elseware::common::cipherkeys::{ELSEWHERE_PRIVATE_KEY, ELSEWHERE_PARRAY}; -use elseware::common::network::{PacketNetworkError}; +//use elseware::common::network::{PacketNetworkError}; use elseware::common::client::Client; use elseware::common::serverstate::{ServerPacket, ServerState, OnConnect}; use elseware::common::util::array_to_utf8; +use crate::dataaccess::DataAccess; use crate::models::UserAccount; pub const LOGIN_PORT: u16 = 12000; -type ConnectionPool = r2d2::Pool>; +//type ConnectionPool = r2d2::Pool>; #[derive(Debug)] pub enum LoginError { @@ -46,78 +44,45 @@ impl ServerPacket for LoginPacket { } #[derive(Clone)] -pub struct SharedLoginState { - pub connection_pool: ConnectionPool, +pub struct SharedLoginState { + pub data_access: DA, } -impl SharedLoginState { - pub fn new(pool: ConnectionPool) -> SharedLoginState { +impl SharedLoginState { + pub fn new(data_access: DA) -> SharedLoginState { SharedLoginState { - connection_pool: pool, + data_access: data_access, } } } -pub struct LoginServerState { - pub shared_state: SharedLoginState, +pub struct LoginServerState { + pub shared_state: SharedLoginState, } -pub fn get_login_status(connection_pool: &ConnectionPool, pkt: &Login) -> Result { - use elseware::schema::user_accounts::dsl::{user_accounts, username}; - connection_pool.get() - .map_err(|_err| AccountStatus::Error) - .and_then(|conn| { - array_to_utf8(pkt.username) - .map(|username_str| { - (conn, username_str) - }) - .map_err(|err| { - println!("utf err: {:?}", err); - AccountStatus::Error - }) - }) - .and_then(|(conn, username_str)| { - user_accounts.filter(username.eq(username_str)).load::(&conn) - .map_err(|err| { - println!("sql err: {:?}", err); - AccountStatus::Error - }) - }) - .and_then(|mut result| { - result.pop().ok_or(AccountStatus::InvalidUser) - }) - .and_then(|user| { - array_to_utf8(pkt.password) - .map(|password| { - (user, password) - }) - .map_err(|_err| AccountStatus::Error) - }) - .and_then(|(user, password)| { - bcrypt::verify(password, user.password.as_str()) - .map_err(|err| { - println!("bcrypt err: {:?}", err); - AccountStatus::Error - }) - .and_then(|correct_password| { - match correct_password { - true => Ok(user), - false => Err(AccountStatus::InvalidPassword), - } - }) - }) + +pub fn get_login_status(data_access: &dyn DataAccess, pkt: &Login) -> Result { + 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 = data_access.get_user_by_name(username).ok_or(AccountStatus::InvalidUser)?; + let verified = bcrypt::verify(password, user.password.as_str()).map_err(|_err| AccountStatus::Error)?; + match verified { + true => Ok(user), + false => Err(AccountStatus::InvalidPassword) + } } -impl LoginServerState { - fn new(shared_state: SharedLoginState) -> LoginServerState { + +impl LoginServerState { + fn new(shared_state: SharedLoginState) -> LoginServerState { LoginServerState { shared_state: shared_state, } } fn validate_login(&mut self, pkt: &Login) -> Box { - match get_login_status(&self.shared_state.connection_pool, pkt) { + match get_login_status(&self.shared_state.data_access, pkt) { Ok(_user) => { let response = LoginResponse::by_status(AccountStatus::Ok, pkt.security_data); let ip = net::Ipv4Addr::new(127,0,0,1); @@ -131,7 +96,7 @@ impl LoginServerState { } } -impl ServerState for LoginServerState { +impl ServerState for LoginServerState { type Packet = LoginPacket; type PacketError = LoginError; @@ -150,7 +115,6 @@ impl ServerState for LoginServerState { } fn handle(&mut self, pkt: &LoginPacket) -> Box>> { - println!("[login: recv] {:?}", pkt); match pkt { LoginPacket::Login(login) => { self.validate_login(login) @@ -160,9 +124,7 @@ impl ServerState for LoginServerState { } - - -pub fn new_client(socket: mio::tcp::TcpStream, shared_state: SharedLoginState) { +pub fn new_client(socket: mio::tcp::TcpStream, shared_state: SharedLoginState) { let state = LoginServerState::new(shared_state); let client = Client::new(socket, Box::new(state)); client.io_loop(); diff --git a/src/login/main.rs b/src/login/main.rs index 9dfea04..c0490d8 100644 --- a/src/login/main.rs +++ b/src/login/main.rs @@ -1,9 +1,12 @@ +#![feature(const_generics)] + mod login; mod character; +mod dataaccess; mod models; use std::net::{SocketAddr, Ipv4Addr}; -use std::net; +//use std::net; use std::thread; use std::env; @@ -12,28 +15,50 @@ use mio::{Events, Poll, Token, Ready, PollOpt}; use dotenv::dotenv; use diesel::r2d2; -use diesel::prelude::*; +//use diesel::prelude::*; use diesel::pg::PgConnection; -use models::{NewUser, UserAccount}; +//use models::{NewUser, UserAccount, UserSettings, NewUserSettings}; +use dataaccess::DBAccess; fn main() { dotenv().ok(); + let database_url = env::var("DATABASE_URL").unwrap(); - //let database_url = env::var("DATABASE_URL").unwrap(); - //let conn = PgConnection::establish(&database_url).unwrap(); + /*if let Some(arg) = env::args().nth(1) { + if arg == "dbstuff" { + let conn = PgConnection::establish(&database_url).unwrap(); - //use elseware::schema::user_accounts::dsl::*; - //use elseware::schema::user_accounts::table; + use elseware::schema::user_accounts::dsl::*; + use elseware::schema::user_settings::dsl::*; - /*let u = NewUser::new("hi".to_string(), "qwer".to_string()); - diesel::insert_into(user_accounts).values(&u).execute(&conn).unwrap(); - let u = NewUser::new("hi2".to_string(), "qwer".to_string()); - diesel::insert_into(user_accounts).values(&u).execute(&conn).unwrap();*/ + let u = NewUser::new("hi".to_string(), "qwer".to_string()); + diesel::insert_into(user_accounts).values(&u).execute(&conn).unwrap(); + let u = NewUser::new("hi2".to_string(), "qwer".to_string()); + let user: UserAccount = diesel::insert_into(user_accounts).values(&u).get_result(&conn).unwrap(); + + let mut s = models::EUserSettings(libpso::character::settings::UserSettings::default()); + s.0.blocked_users[5] = 99; + s.0.blocked_users[6] = 123; + + diesel::insert_into(user_settings).values(& NewUserSettings { + user_id: user.id, + settings: s, + }).execute(&conn).unwrap(); + + let us = user_settings.load::(&conn).unwrap(); + for u in us { + println!("{:?}", u.settings.0.blocked_users[4]); + println!("{:?}", u.settings.0.blocked_users[5]); + println!("{:?}", u.settings.0.blocked_users[6]); + } + } + }*/ + + //let database_url = env::var("DATABASE_URL").unwrap(); println!("[login+character] starting server"); - let database_url = env::var("DATABASE_URL").unwrap(); let connection_manager = r2d2::ConnectionManager::::new(database_url); let connection_pool = r2d2::Pool::builder() .build(connection_manager).unwrap(); @@ -41,7 +66,7 @@ fn main() { let login_listener = TcpListener::bind(&SocketAddr::from((Ipv4Addr::new(0,0,0,0), login::LOGIN_PORT))).unwrap(); let character_listener = TcpListener::bind(&SocketAddr::from((Ipv4Addr::new(0,0,0,0), character::CHARACTER_PORT))).unwrap(); - let login_shared_state = login::SharedLoginState::new(connection_pool); + let login_shared_state = login::SharedLoginState::new(DBAccess::new(connection_pool)); let poll = Poll::new().unwrap(); poll.register(&login_listener, Token(0), Ready::readable(), PollOpt::edge()).unwrap(); diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index 428f09d..0000000 --- a/src/main.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(async_await)] - -mod common; -//mod patch; - -fn main() { - // something or other? -} diff --git a/src/patch/main.rs b/src/patch/main.rs index 81a1e68..6315ba6 100644 --- a/src/patch/main.rs +++ b/src/patch/main.rs @@ -9,6 +9,7 @@ use std::path::{Path, PathBuf, Components}; use std::convert::AsRef; use rand::{Rng, RngCore}; use crc::{crc32, Hasher32}; +use mio::tcp::TcpStream; use libpso::{PacketParseError, PSOPacket}; use libpso::packet::patch::*; use libpso::crypto::pc::PSOPCCipher; @@ -348,7 +349,7 @@ impl Iterator for SendFileIterator { fn new_client(socket: net::TcpStream, patch_file_tree: PatchFileTree, patch_file_lookup: HashMap) { let state = PatchServerState::new(patch_file_tree, patch_file_lookup); - let client = Client::new(socket, Box::new(state)); + let client = Client::new(TcpStream::from_stream(socket).unwrap(), Box::new(state)); client.io_loop(); } @@ -357,8 +358,6 @@ fn new_client(socket: net::TcpStream, patch_file_tree: PatchFileTree, patch_file fn main() { println!("[patch] starting server"); - let listener = TcpListener::bind(&SocketAddr::from((Ipv4Addr::new(0,0,0,0), PATCH_PORT))).unwrap(); - let (patch_file_tree, patch_file_lookup) = generate_patch_tree("patchfiles/"); println!("[patch] files to patch:"); let mut indent = 0; @@ -379,6 +378,8 @@ fn main() { } } + let listener = TcpListener::bind(&SocketAddr::from((Ipv4Addr::new(0,0,0,0), PATCH_PORT))).unwrap(); + println!("[patch] waiting for connections"); while let Ok((socket, addr)) = listener.accept() { let local_patch_file_tree = patch_file_tree.clone();