accounts are back

This commit is contained in:
ntr 2019-06-16 14:24:05 +10:00
parent 66462ac670
commit 2b06c83ea0
4 changed files with 103 additions and 86 deletions

View File

@ -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,

View File

@ -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<Account
let entry = Account {
id: returned.get(0),
name: returned.get(1),
token: returned.get(2),
};
return Ok(entry);

View File

@ -1,26 +1,23 @@
use std::time::{Instant, Duration};
use std::env;
use chrono::Duration as ChronoDuration;
use failure::err_msg;
use serde_cbor::{to_vec};
use actix::prelude::*;
use actix_web::{middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer};
use actix_web::{middleware, web, App, Error, HttpMessage, HttpRequest, HttpResponse, HttpServer};
use actix_web::middleware::cors::Cors;
use actix_web::error::ResponseError;
use actix_web::http::{StatusCode, Cookie};
use actix_web::cookie::{SameSite};
use actix_web_actors::ws;
use r2d2::{Pool};
use r2d2::{PooledConnection};
use r2d2_postgres::{TlsMode, PostgresConnectionManager};
use rpc::{receive, RpcErrorResponse, AccountLoginParams, AccountCreateParams};
use rpc::{receive, RpcResult, RpcErrorResponse, AccountLoginParams, AccountCreateParams};
use warden::{warden};
use account::{Account, account_login, account_create};
use account::{Account, account_login, account_create, account_from_token};
pub type Db = PooledConnection<PostgresConnectionManager>;
type PgPool = Pool<PostgresConnectionManager>;
@ -36,6 +33,7 @@ pub struct MnmlSocket {
/// otherwise we drop connection.
hb: Instant,
pool: PgPool,
account: Option<Account>,
}
impl Actor for MnmlSocket {
@ -50,10 +48,22 @@ impl Actor for MnmlSocket {
/// Handler for `ws::Message`
impl StreamHandler<ws::Message, ws::ProtocolError> 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<ws::Message, ws::ProtocolError> 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<ws::Message, ws::ProtocolError> for MnmlSocket {
}
impl MnmlSocket {
fn new(state: web::Data<State>) -> MnmlSocket {
fn new(state: web::Data<State>, account: Option<Account>) -> 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<State>, stream: web::Payload) -> Result<HttpResponse, Error> {
ws::start(MnmlSocket::new(state), &r, stream)
fn connect(r: HttpRequest, state: web::Data<State>, stream: web::Payload) -> Result<HttpResponse, Error> {
let account: Option<Account> = 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<State>, params: web::Json::<AccountLoginParams>) -> Result<HttpResponse, MnmlError> {
@ -148,14 +186,7 @@ fn login(state: web::Data<State>, params: web::Json::<AccountLoginParams>) -> Re
match account_login(&params.name, &params.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<State>, params: web::Json::<AccountCreateParams>) -
match account_create(&params.name, &params.password, &params.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<PostgresConnectionManager> {
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"),
}

View File

@ -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<MnmlSocket>;
pub fn receive(data: Vec<u8>, db: &Db, _client: &mut MnmlWs, begin: Instant) -> Result<RpcResult, Error> {
pub fn receive(data: Vec<u8>, db: &Db, _client: &mut MnmlWs, begin: Instant, account: Option<&Account>) -> Result<RpcResult, Error> {
// cast the msg to this type to receive method name
match from_slice::<RpcMessage>(&data) {
Ok(v) => {
@ -29,11 +29,6 @@ pub fn receive(data: Vec<u8>, db: &Db, _client: &mut MnmlWs, begin: Instant) ->
let mut tx = db.transaction()?;
let account: Option<Account> = 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<u8>, 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<u8>, db: &Db, _client: &mut MnmlWs, begin: Instant) ->
}
}
fn handle_game_state(data: Vec<u8>, tx: &mut Transaction, account: Account) -> Result<RpcResult, Error> {
fn handle_game_state(data: Vec<u8>, tx: &mut Transaction, account: &Account) -> Result<RpcResult, Error> {
let msg = from_slice::<GameStateMsg>(&data).or(Err(err_msg("invalid params")))?;
return Ok(RpcResult::GameState(game_state(msg.params, tx, &account)?));
}
// fn handle_game_pve(data: Vec<u8>, tx: &mut Transaction, account: Account) -> Result<RpcResult, Error> {
// fn handle_game_pve(data: Vec<u8>, tx: &mut Transaction, account: &Account) -> Result<RpcResult, Error> {
// let msg = from_slice::<GamePveMsg>(&data).or(Err(err_msg("invalid params")))?;
// let game_response = RpcResponse {
@ -115,24 +109,24 @@ fn handle_game_state(data: Vec<u8>, tx: &mut Transaction, account: Account) -> R
// return Ok(game_response);
// }
fn handle_game_skill(data: Vec<u8>, tx: &mut Transaction, account: Account) -> Result<RpcResult, Error> {
fn handle_game_skill(data: Vec<u8>, tx: &mut Transaction, account: &Account) -> Result<RpcResult, Error> {
let msg = from_slice::<GameSkillMsg>(&data).or(Err(err_msg("invalid params")))?;
Ok(RpcResult::GameState(game_skill(msg.params, tx, &account)?))
}
fn handle_game_ready(data: Vec<u8>, tx: &mut Transaction, account: Account) -> Result<RpcResult, Error> {
fn handle_game_ready(data: Vec<u8>, tx: &mut Transaction, account: &Account) -> Result<RpcResult, Error> {
let msg = from_slice::<GameStateMsg>(&data).or(Err(err_msg("invalid params")))?;
Ok(RpcResult::GameState(game_ready(msg.params, tx, &account)?))
}
fn handle_construct_spawn(data: Vec<u8>, tx: &mut Transaction, account: Account) -> Result<RpcResult, Error> {
fn handle_construct_spawn(data: Vec<u8>, tx: &mut Transaction, account: &Account) -> Result<RpcResult, Error> {
let msg = from_slice::<ConstructSpawnMsg>(&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<u8>, tx: &mut Transaction, account: Account) -> Result<RpcResult, Error> {
fn handle_construct_delete(data: Vec<u8>, tx: &mut Transaction, account: &Account) -> Result<RpcResult, Error> {
let msg = from_slice::<ConstructDeleteMsg>(&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<u8>, tx: &mut Transaction, account: Account
// Ok(RpcResult::Account(account_login(msg.params, tx)?))
// }
fn handle_account_constructs(_data: Vec<u8>, tx: &mut Transaction, account: Account) -> Result<RpcResult, Error> {
fn handle_account_constructs(_data: Vec<u8>, tx: &mut Transaction, account: &Account) -> Result<RpcResult, Error> {
Ok(RpcResult::AccountConstructs(account_constructs(tx, &account)?))
}
fn handle_account_instances(_data: Vec<u8>, tx: &mut Transaction, account: Account) -> Result<RpcResult, Error> {
fn handle_account_instances(_data: Vec<u8>, tx: &mut Transaction, account: &Account) -> Result<RpcResult, Error> {
Ok(RpcResult::AccountInstances(account_instances(tx, &account)?))
}
fn handle_instance_new(data: Vec<u8>, tx: &mut Transaction, account: Account) -> Result<RpcResult, Error> {
fn handle_instance_new(data: Vec<u8>, tx: &mut Transaction, account: &Account) -> Result<RpcResult, Error> {
let msg = from_slice::<InstanceLobbyMsg>(&data).or(Err(err_msg("invalid params")))?;
Ok(RpcResult::InstanceState(instance_new(msg.params, tx, &account)?))
}
fn handle_instance_ready(data: Vec<u8>, tx: &mut Transaction, account: Account) -> Result<RpcResult, Error> {
fn handle_instance_ready(data: Vec<u8>, tx: &mut Transaction, account: &Account) -> Result<RpcResult, Error> {
let msg = from_slice::<InstanceReadyMsg>(&data).or(Err(err_msg("invalid params")))?;
Ok(RpcResult::InstanceState(instance_ready(msg.params, tx, &account)?))
}
fn handle_instance_join(data: Vec<u8>, tx: &mut Transaction, account: Account) -> Result<RpcResult, Error> {
fn handle_instance_join(data: Vec<u8>, tx: &mut Transaction, account: &Account) -> Result<RpcResult, Error> {
let msg = from_slice::<InstanceJoinMsg>(&data).or(Err(err_msg("invalid params")))?;
Ok(RpcResult::InstanceState(instance_join(msg.params, tx, &account)?))
}
fn handle_instance_list(_data: Vec<u8>, tx: &mut Transaction, _account: Account) -> Result<RpcResult, Error> {
fn handle_instance_list(_data: Vec<u8>, tx: &mut Transaction, _account: &Account) -> Result<RpcResult, Error> {
Ok(RpcResult::OpenInstances(instance_list(tx)?))
}
fn handle_instance_state(data: Vec<u8>, tx: &mut Transaction, account: Account) -> Result<RpcResult, Error> {
fn handle_instance_state(data: Vec<u8>, tx: &mut Transaction, account: &Account) -> Result<RpcResult, Error> {
let msg = from_slice::<InstanceStateMsg>(&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<u8>, tx: &mut Transaction, account: Account)
}
}
fn handle_vbox_accept(data: Vec<u8>, tx: &mut Transaction, account: Account) -> Result<RpcResult, Error> {
fn handle_vbox_accept(data: Vec<u8>, tx: &mut Transaction, account: &Account) -> Result<RpcResult, Error> {
let msg = from_slice::<VboxAcceptMsg>(&data).or(Err(err_msg("invalid params")))?;
Ok(RpcResult::InstanceState(vbox_accept(msg.params, tx, &account)?))
}
fn handle_vbox_discard(data: Vec<u8>, tx: &mut Transaction, account: Account) -> Result<RpcResult, Error> {
fn handle_vbox_discard(data: Vec<u8>, tx: &mut Transaction, account: &Account) -> Result<RpcResult, Error> {
let msg = from_slice::<VboxDiscardMsg>(&data).or(Err(err_msg("invalid params")))?;
Ok(RpcResult::InstanceState(vbox_discard(msg.params, tx, &account)?))
}
fn handle_vbox_combine(data: Vec<u8>, tx: &mut Transaction, account: Account) -> Result<RpcResult, Error> {
fn handle_vbox_combine(data: Vec<u8>, tx: &mut Transaction, account: &Account) -> Result<RpcResult, Error> {
let msg = from_slice::<VboxCombineMsg>(&data).or(Err(err_msg("invalid params")))?;
Ok(RpcResult::InstanceState(vbox_combine(msg.params, tx, &account)?))
}
fn handle_vbox_apply(data: Vec<u8>, tx: &mut Transaction, account: Account) -> Result<RpcResult, Error> {
fn handle_vbox_apply(data: Vec<u8>, tx: &mut Transaction, account: &Account) -> Result<RpcResult, Error> {
let msg = from_slice::<VboxApplyMsg>(&data).or(Err(err_msg("invalid params")))?;
Ok(RpcResult::InstanceState(vbox_apply(msg.params, tx, &account)?))
}
fn handle_vbox_reclaim(data: Vec<u8>, tx: &mut Transaction, account: Account) -> Result<RpcResult, Error> {
fn handle_vbox_reclaim(data: Vec<u8>, tx: &mut Transaction, account: &Account) -> Result<RpcResult, Error> {
let msg = from_slice::<VboxReclaimMsg>(&data).or(Err(err_msg("invalid params")))?;
Ok(RpcResult::InstanceState(vbox_reclaim(msg.params, tx, &account)?))
}
fn handle_vbox_unequip(data: Vec<u8>, tx: &mut Transaction, account: Account) -> Result<RpcResult, Error> {
fn handle_vbox_unequip(data: Vec<u8>, tx: &mut Transaction, account: &Account) -> Result<RpcResult, Error> {
let msg = from_slice::<VboxUnequipMsg>(&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<Construct>),
AccountInstances(Vec<Instance>),
GameState(Game),