From 2b06c83ea0494e84a14f80a2aff92ae1c61ecd6c Mon Sep 17 00:00:00 2001 From: ntr Date: Sun, 16 Jun 2019 14:24:05 +1000 Subject: [PATCH] accounts are back --- client/src/socket.jsx | 2 +- server/src/account.rs | 2 - server/src/net.rs | 93 +++++++++++++++++++++++++++---------------- server/src/rpc.rs | 92 ++++++++++++++++++++---------------------- 4 files changed, 103 insertions(+), 86 deletions(-) diff --git a/client/src/socket.jsx b/client/src/socket.jsx index 6d3b6849..523faccf 100644 --- a/client/src/socket.jsx +++ b/client/src/socket.jsx @@ -209,7 +209,7 @@ function createSocket(events) { // when the server sends a reply it will have one of these message types // this object wraps the reply types to a function const handlers = { - Account: onAccount, + AccountState: onAccount, AccountConstructs: onAccountConstructs, AccountInstances: onAccountInstances, GameState: onGameState, diff --git a/server/src/account.rs b/server/src/account.rs index 5cc62349..e084ac4a 100644 --- a/server/src/account.rs +++ b/server/src/account.rs @@ -19,7 +19,6 @@ static PASSWORD_MIN_LEN: usize = 11; pub struct Account { pub id: Uuid, pub name: String, - token: String, } #[derive(Debug,Clone,Serialize,Deserialize)] @@ -50,7 +49,6 @@ pub fn account_from_token(token: String, tx: &mut Transaction) -> Result; type PgPool = Pool; @@ -36,6 +33,7 @@ pub struct MnmlSocket { /// otherwise we drop connection. hb: Instant, pool: PgPool, + account: Option, } impl Actor for MnmlSocket { @@ -50,10 +48,22 @@ impl Actor for MnmlSocket { /// Handler for `ws::Message` impl StreamHandler for MnmlSocket { + fn started(&mut self, ctx: &mut Self::Context) { + match self.account.as_ref() { + Some(a) => { + info!("user connected {:?}", a); + let account_state = to_vec(&RpcResult::AccountState(a.clone())) + .expect("could not serialize account state"); + ctx.binary(account_state) + }, + None => info!("new connection"), + } + } + fn handle(&mut self, msg: ws::Message, ctx: &mut Self::Context) { // process websocket messages let begin = Instant::now(); - println!("msg: {:?}", msg); + debug!("msg: {:?}", msg); match msg { ws::Message::Ping(msg) => { self.hb = Instant::now(); @@ -64,12 +74,16 @@ impl StreamHandler for MnmlSocket { } ws::Message::Text(_text) => (), ws::Message::Close(_) => { + match self.account.as_ref() { + Some(a) => info!("disconnected {:?}", a), + None => info!("disconnected"), + } ctx.stop(); } ws::Message::Nop => (), ws::Message::Binary(bin) => { let db_connection = self.pool.get().expect("unable to get db connection"); - match receive(bin.to_vec(), &db_connection, ctx, begin) { + match receive(bin.to_vec(), &db_connection, ctx, begin, self.account.as_ref()) { Ok(reply) => { let response = to_vec(&reply) .expect("failed to serialize response"); @@ -87,10 +101,10 @@ impl StreamHandler for MnmlSocket { } impl MnmlSocket { - fn new(state: web::Data) -> MnmlSocket { + fn new(state: web::Data, account: Option) -> MnmlSocket { // idk why this has to be cloned again // i guess because each socket is added as a new thread? - MnmlSocket { hb: Instant::now(), pool: state.pool.clone() } + MnmlSocket { hb: Instant::now(), pool: state.pool.clone(), account } } // starts the keepalive interval once actor started @@ -137,8 +151,32 @@ impl ResponseError for MnmlError { // the req obj itself which we need for cookies // the application state // and the websocket stream -fn ws(r: HttpRequest, state: web::Data, stream: web::Payload) -> Result { - ws::start(MnmlSocket::new(state), &r, stream) +fn connect(r: HttpRequest, state: web::Data, stream: web::Payload) -> Result { + let account: Option = match r.cookie("x-auth-token") { + Some(t) => { + let db = state.pool.get().or(Err(MnmlError::ServerError))?; + let mut tx = db.transaction().or(Err(MnmlError::ServerError))?; + match account_from_token(t.value().to_string(), &mut tx) { + Ok(a) => Some(a), + Err(_) => None, + } + }, + None => None, + }; + + ws::start(MnmlSocket::new(state, account), &r, stream) +} + +fn token_res(token: String, secure: bool) -> HttpResponse { + HttpResponse::Ok() + .cookie(Cookie::build("x-auth-token", token) + // .path("/") + .secure(secure) // needs to be enabled for prod + .http_only(true) + .same_site(SameSite::Strict) + .max_age(60 * 60 * 24 * 7) // 1 week + .finish()) + .finish() } fn login(state: web::Data, params: web::Json::) -> Result { @@ -148,14 +186,7 @@ fn login(state: web::Data, params: web::Json::) -> Re match account_login(¶ms.name, ¶ms.password, &mut tx) { Ok(token) => { tx.commit().or(Err(MnmlError::ServerError))?; - Ok(HttpResponse::Ok() - .cookie(Cookie::build("x-auth-token", token) - // .path("/") - .http_only(true) - // .secure(true) - .max_age(60 * 60 * 24 * 7) // 1 week - .finish()) - .finish()) + Ok(token_res(token, state.secure)) }, Err(e) => { info!("{:?}", e); @@ -171,18 +202,11 @@ fn register(state: web::Data, params: web::Json::) - match account_create(¶ms.name, ¶ms.password, ¶ms.code, &mut tx) { Ok(token) => { tx.commit().or(Err(MnmlError::ServerError))?; - Ok(HttpResponse::Created() - .cookie(Cookie::build("x-auth-token", token) - .path("/") - .http_only(true) - .secure(true) - .max_age(60 * 60 * 24 * 7) // 1 week - .finish()) - .finish()) + Ok(token_res(token, state.secure)) }, Err(e) => { info!("{:?}", e); - Err(MnmlError::Unauthorized) + Err(MnmlError::BadRequest) } } } @@ -199,6 +223,7 @@ fn create_pool(url: String) -> Pool { struct State { pool: PgPool, + secure: bool, } pub fn start() { @@ -211,22 +236,22 @@ pub fn start() { Ok(_) => { warn!("enabling dev CORS middleware"); HttpServer::new(move || App::new() - .data(State { pool: pool.clone() }) + .data(State { pool: pool.clone(), secure: false }) .wrap(middleware::Logger::default()) .wrap(Cors::new().supports_credentials()) .service(web::resource("/login").route(web::post().to(login))) .service(web::resource("/register").route(web::post().to(register))) - .service(web::resource("/ws/").route(web::get().to(ws)))) + .service(web::resource("/ws/").route(web::get().to(connect)))) .bind("127.0.0.1:40000").expect("could not bind to port") .run().expect("could not start http server") }, Err(_) => HttpServer::new(move || App::new() - .data(State { pool: pool.clone() }) + .data(State { pool: pool.clone(), secure: true }) .wrap(middleware::Logger::default()) .service(web::resource("/login").route(web::post().to(login))) .service(web::resource("/register").route(web::post().to(register))) - .service(web::resource("/ws/").route(web::get().to(ws)))) + .service(web::resource("/ws/").route(web::get().to(connect)))) .bind("127.0.0.1:40000").expect("could not bind to port") .run().expect("could not start http server"), } diff --git a/server/src/rpc.rs b/server/src/rpc.rs index 75fcfa5d..e60bb198 100644 --- a/server/src/rpc.rs +++ b/server/src/rpc.rs @@ -11,7 +11,7 @@ use failure::err_msg; use net::{Db, MnmlSocket}; use construct::{Construct, construct_spawn, construct_delete}; use game::{Game, game_state, game_skill, game_ready}; -use account::{Account, account_from_token, account_constructs, account_instances}; +use account::{Account, account_constructs, account_instances}; use skill::{Skill}; use instance::{Instance, instance_state, instance_list, instance_new, instance_ready, instance_join}; use vbox::{vbox_accept, vbox_apply, vbox_discard, vbox_combine, vbox_reclaim, vbox_unequip}; @@ -19,7 +19,7 @@ use item::{Item, ItemInfoCtr, item_info}; type MnmlWs = ws::WebsocketContext; -pub fn receive(data: Vec, db: &Db, _client: &mut MnmlWs, begin: Instant) -> Result { +pub fn receive(data: Vec, db: &Db, _client: &mut MnmlWs, begin: Instant, account: Option<&Account>) -> Result { // cast the msg to this type to receive method name match from_slice::(&data) { Ok(v) => { @@ -29,11 +29,6 @@ pub fn receive(data: Vec, db: &Db, _client: &mut MnmlWs, begin: Instant) -> let mut tx = db.transaction()?; - let account: Option = match v.token { - Some(t) => Some(account_from_token(t, &mut tx)?), - None => None, - }; - let account_name = match &account { Some(a) => a.name.clone(), None => "none".to_string(), @@ -51,37 +46,36 @@ pub fn receive(data: Vec, db: &Db, _client: &mut MnmlWs, begin: Instant) -> }, }; + let account = account.unwrap(); + // now we have the method name // match on that to determine what fn to call let response = match v.method.as_ref() { - // NO AUTH - // "account_create" => handle_account_create(data, &mut tx), - // "account_login" => handle_account_login(data, &mut tx), "item_info" => Ok(RpcResult::ItemInfo(item_info())), + "account_state" => Ok(RpcResult::AccountState(account.clone())), - // AUTH METHODS - "account_constructs" => handle_account_constructs(data, &mut tx, account.unwrap()), - "account_instances" => handle_account_instances(data, &mut tx, account.unwrap()), + "account_constructs" => handle_account_constructs(data, &mut tx, account), + "account_instances" => handle_account_instances(data, &mut tx, account), - "construct_spawn" => handle_construct_spawn(data, &mut tx, account.unwrap()), - "construct_delete" => handle_construct_delete(data, &mut tx, account.unwrap()), + "construct_spawn" => handle_construct_spawn(data, &mut tx, account), + "construct_delete" => handle_construct_delete(data, &mut tx, account), - "game_state" => handle_game_state(data, &mut tx, account.unwrap()), - "game_skill" => handle_game_skill(data, &mut tx, account.unwrap()), - "game_ready" => handle_game_ready(data, &mut tx, account.unwrap()), + "game_state" => handle_game_state(data, &mut tx, account), + "game_skill" => handle_game_skill(data, &mut tx, account), + "game_ready" => handle_game_ready(data, &mut tx, account), - "instance_list" => handle_instance_list(data, &mut tx, account.unwrap()), - "instance_join" => handle_instance_join(data, &mut tx, account.unwrap()), - "instance_ready" => handle_instance_ready(data, &mut tx, account.unwrap()), - "instance_new" => handle_instance_new(data, &mut tx, account.unwrap()), - "instance_state" => handle_instance_state(data, &mut tx, account.unwrap()), + "instance_list" => handle_instance_list(data, &mut tx, account), + "instance_join" => handle_instance_join(data, &mut tx, account), + "instance_ready" => handle_instance_ready(data, &mut tx, account), + "instance_new" => handle_instance_new(data, &mut tx, account), + "instance_state" => handle_instance_state(data, &mut tx, account), - "vbox_accept" => handle_vbox_accept(data, &mut tx, account.unwrap()), - "vbox_apply" => handle_vbox_apply(data, &mut tx, account.unwrap()), - "vbox_combine" => handle_vbox_combine(data, &mut tx, account.unwrap()), - "vbox_discard" => handle_vbox_discard(data, &mut tx, account.unwrap()), - "vbox_reclaim" => handle_vbox_reclaim(data, &mut tx, account.unwrap()), - "vbox_unequip" => handle_vbox_unequip(data, &mut tx, account.unwrap()), + "vbox_accept" => handle_vbox_accept(data, &mut tx, account), + "vbox_apply" => handle_vbox_apply(data, &mut tx, account), + "vbox_combine" => handle_vbox_combine(data, &mut tx, account), + "vbox_discard" => handle_vbox_discard(data, &mut tx, account), + "vbox_reclaim" => handle_vbox_reclaim(data, &mut tx, account), + "vbox_unequip" => handle_vbox_unequip(data, &mut tx, account), _ => Err(format_err!("unknown method - {:?}", v.method)), }; @@ -99,12 +93,12 @@ pub fn receive(data: Vec, db: &Db, _client: &mut MnmlWs, begin: Instant) -> } } -fn handle_game_state(data: Vec, tx: &mut Transaction, account: Account) -> Result { +fn handle_game_state(data: Vec, tx: &mut Transaction, account: &Account) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; return Ok(RpcResult::GameState(game_state(msg.params, tx, &account)?)); } -// fn handle_game_pve(data: Vec, tx: &mut Transaction, account: Account) -> Result { +// fn handle_game_pve(data: Vec, tx: &mut Transaction, account: &Account) -> Result { // let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; // let game_response = RpcResponse { @@ -115,24 +109,24 @@ fn handle_game_state(data: Vec, tx: &mut Transaction, account: Account) -> R // return Ok(game_response); // } -fn handle_game_skill(data: Vec, tx: &mut Transaction, account: Account) -> Result { +fn handle_game_skill(data: Vec, tx: &mut Transaction, account: &Account) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; Ok(RpcResult::GameState(game_skill(msg.params, tx, &account)?)) } -fn handle_game_ready(data: Vec, tx: &mut Transaction, account: Account) -> Result { +fn handle_game_ready(data: Vec, tx: &mut Transaction, account: &Account) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; Ok(RpcResult::GameState(game_ready(msg.params, tx, &account)?)) } -fn handle_construct_spawn(data: Vec, tx: &mut Transaction, account: Account) -> Result { +fn handle_construct_spawn(data: Vec, tx: &mut Transaction, account: &Account) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; construct_spawn(msg.params, tx, &account)?; Ok(RpcResult::AccountConstructs(account_constructs(tx, &account)?)) } -fn handle_construct_delete(data: Vec, tx: &mut Transaction, account: Account) -> Result { +fn handle_construct_delete(data: Vec, tx: &mut Transaction, account: &Account) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; construct_delete(tx, msg.params.id, account.id)?; Ok(RpcResult::AccountConstructs(account_constructs(tx, &account)?)) @@ -150,35 +144,35 @@ fn handle_construct_delete(data: Vec, tx: &mut Transaction, account: Account // Ok(RpcResult::Account(account_login(msg.params, tx)?)) // } -fn handle_account_constructs(_data: Vec, tx: &mut Transaction, account: Account) -> Result { +fn handle_account_constructs(_data: Vec, tx: &mut Transaction, account: &Account) -> Result { Ok(RpcResult::AccountConstructs(account_constructs(tx, &account)?)) } -fn handle_account_instances(_data: Vec, tx: &mut Transaction, account: Account) -> Result { +fn handle_account_instances(_data: Vec, tx: &mut Transaction, account: &Account) -> Result { Ok(RpcResult::AccountInstances(account_instances(tx, &account)?)) } -fn handle_instance_new(data: Vec, tx: &mut Transaction, account: Account) -> Result { +fn handle_instance_new(data: Vec, tx: &mut Transaction, account: &Account) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; Ok(RpcResult::InstanceState(instance_new(msg.params, tx, &account)?)) } -fn handle_instance_ready(data: Vec, tx: &mut Transaction, account: Account) -> Result { +fn handle_instance_ready(data: Vec, tx: &mut Transaction, account: &Account) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; Ok(RpcResult::InstanceState(instance_ready(msg.params, tx, &account)?)) } -fn handle_instance_join(data: Vec, tx: &mut Transaction, account: Account) -> Result { +fn handle_instance_join(data: Vec, tx: &mut Transaction, account: &Account) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; Ok(RpcResult::InstanceState(instance_join(msg.params, tx, &account)?)) } -fn handle_instance_list(_data: Vec, tx: &mut Transaction, _account: Account) -> Result { +fn handle_instance_list(_data: Vec, tx: &mut Transaction, _account: &Account) -> Result { Ok(RpcResult::OpenInstances(instance_list(tx)?)) } -fn handle_instance_state(data: Vec, tx: &mut Transaction, account: Account) -> Result { +fn handle_instance_state(data: Vec, tx: &mut Transaction, account: &Account) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; match instance_state(msg.params, tx, &account)? { RpcResult::GameState(p) => Ok(RpcResult::GameState(p)), @@ -187,33 +181,33 @@ fn handle_instance_state(data: Vec, tx: &mut Transaction, account: Account) } } -fn handle_vbox_accept(data: Vec, tx: &mut Transaction, account: Account) -> Result { +fn handle_vbox_accept(data: Vec, tx: &mut Transaction, account: &Account) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; Ok(RpcResult::InstanceState(vbox_accept(msg.params, tx, &account)?)) } -fn handle_vbox_discard(data: Vec, tx: &mut Transaction, account: Account) -> Result { +fn handle_vbox_discard(data: Vec, tx: &mut Transaction, account: &Account) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; Ok(RpcResult::InstanceState(vbox_discard(msg.params, tx, &account)?)) } -fn handle_vbox_combine(data: Vec, tx: &mut Transaction, account: Account) -> Result { +fn handle_vbox_combine(data: Vec, tx: &mut Transaction, account: &Account) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; Ok(RpcResult::InstanceState(vbox_combine(msg.params, tx, &account)?)) } -fn handle_vbox_apply(data: Vec, tx: &mut Transaction, account: Account) -> Result { +fn handle_vbox_apply(data: Vec, tx: &mut Transaction, account: &Account) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; Ok(RpcResult::InstanceState(vbox_apply(msg.params, tx, &account)?)) } -fn handle_vbox_reclaim(data: Vec, tx: &mut Transaction, account: Account) -> Result { +fn handle_vbox_reclaim(data: Vec, tx: &mut Transaction, account: &Account) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; Ok(RpcResult::InstanceState(vbox_reclaim(msg.params, tx, &account)?)) } -fn handle_vbox_unequip(data: Vec, tx: &mut Transaction, account: Account) -> Result { +fn handle_vbox_unequip(data: Vec, tx: &mut Transaction, account: &Account) -> Result { let msg = from_slice::(&data).or(Err(err_msg("invalid params")))?; Ok(RpcResult::InstanceState(vbox_unequip(msg.params, tx, &account)?)) } @@ -225,7 +219,7 @@ pub struct RpcErrorResponse { #[derive(Debug,Clone,Serialize,Deserialize)] pub enum RpcResult { - Account(Account), + AccountState(Account), AccountConstructs(Vec), AccountInstances(Vec), GameState(Game),