From 51d3c7646079bf490f1731b1f7e9cc29128bf437 Mon Sep 17 00:00:00 2001 From: Mashy Date: Fri, 19 Jul 2019 19:19:29 +1000 Subject: [PATCH 1/6] wip --- client/src/components/login.jsx | 8 +++----- server/src/net.rs | 24 +++++++++++++++++++++++- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/client/src/components/login.jsx b/client/src/components/login.jsx index 5e8c6876..5136031f 100644 --- a/client/src/components/login.jsx +++ b/client/src/components/login.jsx @@ -12,11 +12,9 @@ const addState = connect( } = state; function submitLogin(name, password) { postData('/login', { name, password }) - .then(res => { - if (!res.ok) return errorToast(res); - res.text() - }) - .then(res => { + .then(res => res.json()) + .then(data => { + if (!data.success) return errorToast(data.error_message); ws.connect(); }) .catch(error => errorToast(error)); diff --git a/server/src/net.rs b/server/src/net.rs index 12eb66d7..4e0ae64b 100644 --- a/server/src/net.rs +++ b/server/src/net.rs @@ -5,9 +5,11 @@ use iron::headers::{Cookie as CookieHdr, SetCookie}; use iron::prelude::*; use iron::status; use iron::typemap::Key; +use iron::mime::Mime; use iron::{typemap, BeforeMiddleware,AfterMiddleware}; use persistent::Read; use router::Router; +use serde::{Serialize, Deserialize}; // use warden::{warden}; // use pubsub::{pg_listen}; @@ -37,6 +39,23 @@ pub enum MnmlHttpError { InvalidCode, } +#[derive(Serialize, Deserialize)] +struct JsonResponse { + response: String, + success: bool, + error_message: String +} + +impl JsonResponse { + fn success(response: String) -> Self { + JsonResponse { response: response, success: true, error_message: "".to_string() } + } + + fn error(msg: String) -> Self { + JsonResponse { response: "".to_string(), success: false, error_message: msg } + } +} + impl From for IronError { fn from(m_err: MnmlHttpError) -> Self { let (err, res) = match m_err { @@ -48,8 +67,11 @@ impl From for IronError { MnmlHttpError::PasswordUnacceptable => (m_err.compat(), status::BadRequest), MnmlHttpError::InvalidCode => (m_err.compat(), status::Unauthorized), }; + let err_msg = JsonResponse::error("grep".to_string()); + let err_out = serde_json::to_string(&err_msg).expect("Failed to encode response"); + let content_type = "application/json".parse::().expect("Failed to parse content type"); - IronError::new(err, res) + IronError::new(err, (content_type, res, err_out)) } } From 9c45a3fb7a3898a89f64644073023db0a1b122e0 Mon Sep 17 00:00:00 2001 From: Mashy Date: Fri, 19 Jul 2019 19:46:54 +1000 Subject: [PATCH 2/6] getting somewhere --- client/src/components/login.jsx | 1 + server/src/net.rs | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/client/src/components/login.jsx b/client/src/components/login.jsx index 5136031f..22fbdaff 100644 --- a/client/src/components/login.jsx +++ b/client/src/components/login.jsx @@ -15,6 +15,7 @@ const addState = connect( .then(res => res.json()) .then(data => { if (!data.success) return errorToast(data.error_message); + console.log(data.response); ws.connect(); }) .catch(error => errorToast(error)); diff --git a/server/src/net.rs b/server/src/net.rs index 4e0ae64b..80766191 100644 --- a/server/src/net.rs +++ b/server/src/net.rs @@ -20,7 +20,7 @@ use payments::{stripe}; pub const TOKEN_HEADER: &str = "x-auth-token"; -#[derive(Fail, Debug, Serialize, Deserialize)] +#[derive(Clone, Copy, Fail, Debug, Serialize, Deserialize)] pub enum MnmlHttpError { // User Facing Errors #[fail(display="internal server error")] @@ -67,7 +67,7 @@ impl From for IronError { MnmlHttpError::PasswordUnacceptable => (m_err.compat(), status::BadRequest), MnmlHttpError::InvalidCode => (m_err.compat(), status::Unauthorized), }; - let err_msg = JsonResponse::error("grep".to_string()); + let err_msg = JsonResponse::error(m_err.to_string()); let err_out = serde_json::to_string(&err_msg).expect("Failed to encode response"); let content_type = "application/json".parse::().expect("Failed to parse content type"); @@ -132,8 +132,16 @@ fn token_res(token: String) -> Response { .max_age(Duration::weeks(1)) // 1 week aligns with db set .finish(); - let mut res = Response::with(status::Ok); - res.headers.set(SetCookie(vec![v.to_string()])); + let content_type = "application/json".parse::().expect("Failed to parse content type"); + let msg = JsonResponse { + response: "success666".to_string(), + success: true, + error_message: "".to_string() + }; + let msg_out = serde_json::to_string(&msg).expect("Failed to encode response"); + + let mut res = Response::with((content_type, status::Ok, msg_out)); + res.headers.set(SetCookie(vec![v.to_string()])); return res; } From b289ed92deb3104eb6a3c6fe79f440a173b80bf0 Mon Sep 17 00:00:00 2001 From: Mashy Date: Fri, 19 Jul 2019 21:01:12 +1000 Subject: [PATCH 3/6] tidying fns --- server/src/net.rs | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/server/src/net.rs b/server/src/net.rs index 80766191..b7d1ffc6 100644 --- a/server/src/net.rs +++ b/server/src/net.rs @@ -41,21 +41,31 @@ pub enum MnmlHttpError { #[derive(Serialize, Deserialize)] struct JsonResponse { - response: String, + response: Option, success: bool, - error_message: String + error_message: Option } impl JsonResponse { fn success(response: String) -> Self { - JsonResponse { response: response, success: true, error_message: "".to_string() } + JsonResponse { response: Some(response), success: true, error_message: None } } fn error(msg: String) -> Self { - JsonResponse { response: "".to_string(), success: false, error_message: msg } + JsonResponse { response: None, success: false, error_message: Some(msg) } } } +fn iron_response (status: status::Status, message: String) -> Response { + let content_type = "application/json".parse::().unwrap(); + let msg = match status { + status::Ok => JsonResponse::success(message), + _ => JsonResponse::error(message) + }; + let msg_out = serde_json::to_string(&msg).unwrap(); + return Response::with((content_type, status, msg_out)); +} + impl From for IronError { fn from(m_err: MnmlHttpError) -> Self { let (err, res) = match m_err { @@ -67,11 +77,7 @@ impl From for IronError { MnmlHttpError::PasswordUnacceptable => (m_err.compat(), status::BadRequest), MnmlHttpError::InvalidCode => (m_err.compat(), status::Unauthorized), }; - let err_msg = JsonResponse::error(m_err.to_string()); - let err_out = serde_json::to_string(&err_msg).expect("Failed to encode response"); - let content_type = "application/json".parse::().expect("Failed to parse content type"); - - IronError::new(err, (content_type, res, err_out)) + IronError { error: Box::new(err), response: iron_response(res, m_err.to_string()) } } } @@ -132,15 +138,7 @@ fn token_res(token: String) -> Response { .max_age(Duration::weeks(1)) // 1 week aligns with db set .finish(); - let content_type = "application/json".parse::().expect("Failed to parse content type"); - let msg = JsonResponse { - response: "success666".to_string(), - success: true, - error_message: "".to_string() - }; - let msg_out = serde_json::to_string(&msg).expect("Failed to encode response"); - - let mut res = Response::with((content_type, status::Ok, msg_out)); + let mut res = iron_response(status::Ok, "token_res".to_string()); res.headers.set(SetCookie(vec![v.to_string()])); return res; @@ -216,7 +214,7 @@ fn logout(req: &mut Request) -> IronResult { tx.commit().or(Err(MnmlHttpError::ServerError))?; - let mut res = Response::with(status::Ok); + let mut res = iron_response(status::Ok, "token_res".to_string()); res.headers.set(SetCookie(vec![AUTH_CLEAR.to_string()])); Ok(res) From c44cd44933d5d5a2d45a01f5ed0b7e1a57eb99df Mon Sep 17 00:00:00 2001 From: Mashy Date: Sat, 20 Jul 2019 01:04:02 +1000 Subject: [PATCH 4/6] register account proper err handling --- client/src/components/login.jsx | 9 ++++----- server/src/account.rs | 11 ++++++----- server/src/net.rs | 23 ++++++++++++++++++++++- 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/client/src/components/login.jsx b/client/src/components/login.jsx index 22fbdaff..4d822807 100644 --- a/client/src/components/login.jsx +++ b/client/src/components/login.jsx @@ -23,11 +23,10 @@ const addState = connect( function submitRegister(name, password, code) { postData('/register', { name, password, code }) - .then(res => { - if (!res.ok) return errorToast(res); - res.text() - }) - .then(res => { + .then(res => res.json()) + .then(data => { + if (!data.success) return errorToast(data.error_message); + console.log(data.response); ws.connect(); }) .catch(error => errorToast(error)); diff --git a/server/src/account.rs b/server/src/account.rs index 7232351a..3f2358af 100644 --- a/server/src/account.rs +++ b/server/src/account.rs @@ -8,6 +8,7 @@ use serde_cbor::{from_slice}; use postgres::transaction::Transaction; +use net::MnmlHttpError; use names::{name as generate_name}; use construct::{Construct, construct_recover, construct_spawn}; use instance::{Instance, instance_delete}; @@ -212,17 +213,17 @@ pub fn set_subscribed(tx: &mut Transaction, id: Uuid, subscribed: bool) -> Resul Ok(name) } -pub fn create(name: &String, password: &String, code: &String, tx: &mut Transaction) -> Result { +pub fn create(name: &String, password: &String, code: &String, tx: &mut Transaction) -> Result { if password.len() < PASSWORD_MIN_LEN { - return Err(err_msg("password must be at least 12 characters")); + return Err(MnmlHttpError::PasswordUnacceptable); } if code.to_lowercase() != "grep842" { - return Err(err_msg("https://discord.gg/YJJgurM")); + return Err(MnmlHttpError::InvalidCode); } if name.len() == 0 { - return Err(err_msg("account name not supplied")); + return Err(MnmlHttpError::AccountNameNotProvided); } let id = Uuid::new_v4(); @@ -246,7 +247,7 @@ pub fn create(name: &String, password: &String, code: &String, tx: &mut Transact match result.iter().next() { Some(row) => row, - None => return Err(err_msg("account not created")), + None => return Err(MnmlHttpError::DbError), }; // 3 constructs for a team and 1 to swap diff --git a/server/src/net.rs b/server/src/net.rs index b7d1ffc6..f030a896 100644 --- a/server/src/net.rs +++ b/server/src/net.rs @@ -32,6 +32,8 @@ pub enum MnmlHttpError { #[fail(display="bad request")] BadRequest, #[fail(display="account name taken or invalid")] + AccountNameNotProvided, + #[fail(display="account name not provided")] AccountNameTaken, #[fail(display="password unacceptable. must be > 11 characters")] PasswordUnacceptable, @@ -39,6 +41,24 @@ pub enum MnmlHttpError { InvalidCode, } +impl From for MnmlHttpError { + fn from(_err: bcrypt::BcryptError) -> Self { + MnmlHttpError::ServerError + } +} + +impl From for MnmlHttpError { + fn from(_err: postgres::Error) -> Self { + MnmlHttpError::DbError + } +} + +impl From for MnmlHttpError { + fn from(_err: failure::Error) -> Self { + MnmlHttpError::ServerError + } +} + #[derive(Serialize, Deserialize)] struct JsonResponse { response: Option, @@ -73,6 +93,7 @@ impl From for IronError { MnmlHttpError::DbError => (m_err.compat(), status::InternalServerError), MnmlHttpError::Unauthorized => (m_err.compat(), status::Unauthorized), MnmlHttpError::BadRequest => (m_err.compat(), status::BadRequest), + MnmlHttpError::AccountNameNotProvided => (m_err.compat(), status::BadRequest), MnmlHttpError::AccountNameTaken => (m_err.compat(), status::BadRequest), MnmlHttpError::PasswordUnacceptable => (m_err.compat(), status::BadRequest), MnmlHttpError::InvalidCode => (m_err.compat(), status::Unauthorized), @@ -169,7 +190,7 @@ fn register(req: &mut Request) -> IronResult { }, Err(e) => { warn!("{:?}", e); - Err(IronError::from(MnmlHttpError::BadRequest)) + Err(IronError::from(e)) } } } From 4db44e0b59b16a19bc294b17bb9f7d37349cca26 Mon Sep 17 00:00:00 2001 From: Mashy Date: Sat, 20 Jul 2019 11:15:47 +1000 Subject: [PATCH 5/6] great victory --- server/src/account.rs | 6 +++--- server/src/net.rs | 27 +++++++++++++++++++-------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/server/src/account.rs b/server/src/account.rs index 3f2358af..402b62b6 100644 --- a/server/src/account.rs +++ b/server/src/account.rs @@ -76,7 +76,7 @@ pub fn from_token(db: &Db, token: String) -> Result { Ok(Account { id, name, balance, subscribed }) } -pub fn login(tx: &mut Transaction, name: &String, password: &String) -> Result { +pub fn login(tx: &mut Transaction, name: &String, password: &String) -> Result { let query = " SELECT id, password, name, balance, subscribed FROM accounts @@ -97,7 +97,7 @@ pub fn login(tx: &mut Transaction, name: &String, password: &String) -> Result Result Response { impl From for IronError { fn from(m_err: MnmlHttpError) -> Self { let (err, res) = match m_err { - MnmlHttpError::ServerError => (m_err.compat(), status::InternalServerError), + MnmlHttpError::ServerError | MnmlHttpError::DbError => (m_err.compat(), status::InternalServerError), - MnmlHttpError::Unauthorized => (m_err.compat(), status::Unauthorized), - MnmlHttpError::BadRequest => (m_err.compat(), status::BadRequest), - MnmlHttpError::AccountNameNotProvided => (m_err.compat(), status::BadRequest), - MnmlHttpError::AccountNameTaken => (m_err.compat(), status::BadRequest), + + MnmlHttpError::AccountNameNotProvided | + MnmlHttpError::AccountNameTaken | + MnmlHttpError::AccountNameNotFound | + MnmlHttpError::BadRequest | MnmlHttpError::PasswordUnacceptable => (m_err.compat(), status::BadRequest), - MnmlHttpError::InvalidCode => (m_err.compat(), status::Unauthorized), + + MnmlHttpError::PasswordNotMatch | + MnmlHttpError::InvalidCode | + MnmlHttpError::TokenDoesNotMatch | + MnmlHttpError::Unauthorized => (m_err.compat(), status::Unauthorized), }; IronError { error: Box::new(err), response: iron_response(res, m_err.to_string()) } } @@ -119,7 +130,7 @@ impl BeforeMiddleware for AuthMiddleware { if cookie.name() == TOKEN_HEADER { match account::from_token(&db, cookie.value().to_string()) { Ok(a) => req.extensions.insert::(a), - Err(_) => return Err(IronError::from(MnmlHttpError::Unauthorized)), + Err(_) => return Err(IronError::from(MnmlHttpError::TokenDoesNotMatch)), }; } } @@ -219,7 +230,7 @@ fn login(req: &mut Request) -> IronResult { }, Err(e) => { warn!("{:?}", e); - Err(IronError::from(MnmlHttpError::Unauthorized)) + Err(IronError::from(e)) } } } From 938d53048eee304d3e22839715b817d18349a8a6 Mon Sep 17 00:00:00 2001 From: Mashy Date: Sat, 20 Jul 2019 11:18:25 +1000 Subject: [PATCH 6/6] misc --- server/src/account.rs | 2 +- server/src/net.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/server/src/account.rs b/server/src/account.rs index 402b62b6..29acc8e4 100644 --- a/server/src/account.rs +++ b/server/src/account.rs @@ -97,7 +97,7 @@ pub fn login(tx: &mut Transaction, name: &String, password: &String) -> Result for IronError { MnmlHttpError::AccountNameNotProvided | MnmlHttpError::AccountNameTaken | - MnmlHttpError::AccountNameNotFound | + MnmlHttpError::AccountNotFound | MnmlHttpError::BadRequest | MnmlHttpError::PasswordUnacceptable => (m_err.compat(), status::BadRequest),