From d6c761917bad2c9916ce125a29699548a855df79 Mon Sep 17 00:00:00 2001 From: appflowy Date: Mon, 23 Aug 2021 23:02:42 +0800 Subject: [PATCH] check params using flowy-user entities --- backend/src/entities/token.rs | 6 ++--- backend/src/routers/utils.rs | 6 ++--- backend/src/user_service/auth_service.rs | 23 +++++++++++------- backend/src/user_service/utils.rs | 6 ++--- rust-lib/flowy-net/src/config.rs | 1 + rust-lib/flowy-net/src/errors.rs | 19 ++++++++------- rust-lib/flowy-net/src/request/request.rs | 6 ++--- rust-lib/flowy-net/src/response/response.rs | 24 +++++++++---------- rust-lib/flowy-user/src/entities/mod.rs | 2 +- rust-lib/flowy-user/src/errors.rs | 5 ++++ .../src/services/user/user_server.rs | 13 +++------- 11 files changed, 60 insertions(+), 51 deletions(-) diff --git a/backend/src/entities/token.rs b/backend/src/entities/token.rs index 1c5411d4ec..cb795c4416 100644 --- a/backend/src/entities/token.rs +++ b/backend/src/entities/token.rs @@ -4,7 +4,7 @@ use crate::{ }; use chrono::{Duration, Local}; use derive_more::{From, Into}; -use flowy_net::errors::{Code, ServerError}; +use flowy_net::errors::{ErrorCode, ServerError}; use jsonwebtoken::{decode, encode, Algorithm, DecodingKey, EncodingKey, Header, Validation}; use serde::{Deserialize, Serialize}; @@ -51,7 +51,7 @@ impl Token { &EncodingKey::from_secret(jwt_secret().as_ref()), ) .map(Into::into) - .map_err(|err| ServerError::internal().with_msg(err)) + .map_err(|err| ServerError::internal().context(err)) } pub fn decode_token(token: &Self) -> Result { @@ -61,6 +61,6 @@ impl Token { &Validation::new(DEFAULT_ALGORITHM), ) .map(|data| Ok(data.claims)) - .map_err(|err| ServerError::unauthorized().with_msg(err))? + .map_err(|err| ServerError::unauthorized().context(err))? } } diff --git a/backend/src/routers/utils.rs b/backend/src/routers/utils.rs index 945e2fa41d..986e0047c7 100644 --- a/backend/src/routers/utils.rs +++ b/backend/src/routers/utils.rs @@ -1,7 +1,7 @@ use crate::config::MAX_PAYLOAD_SIZE; use actix_web::web; use flowy_net::{ - errors::{Code, ServerError}, + errors::{ErrorCode, ServerError}, response::*, }; use futures::StreamExt; @@ -23,11 +23,11 @@ pub fn parse_from_bytes(bytes: &[u8]) -> Result { pub async fn poll_payload(mut payload: web::Payload) -> Result { let mut body = web::BytesMut::new(); while let Some(chunk) = payload.next().await { - let chunk = chunk.map_err(|err| ServerError::internal().with_msg(err))?; + let chunk = chunk.map_err(|err| ServerError::internal().context(err))?; if (body.len() + chunk.len()) > MAX_PAYLOAD_SIZE { return Err(ServerError { - code: Code::PayloadOverflow, + code: ErrorCode::PayloadOverflow, msg: "Payload overflow".to_string(), }); } diff --git a/backend/src/user_service/auth_service.rs b/backend/src/user_service/auth_service.rs index f3679e7de1..73bbb39108 100644 --- a/backend/src/user_service/auth_service.rs +++ b/backend/src/user_service/auth_service.rs @@ -6,11 +6,12 @@ use actix_identity::Identity; use anyhow::Context; use chrono::Utc; use flowy_net::{ - errors::{Code, ServerError}, + errors::{ErrorCode, ServerError}, response::FlowyResponse, }; use flowy_user::{ entities::{SignInResponse, SignUpResponse}, + prelude::parser::{UserEmail, UserPassword}, protobuf::{SignInParams, SignUpParams}, }; use sqlx::{Error, PgPool, Postgres, Transaction}; @@ -21,17 +22,23 @@ pub async fn sign_in( params: SignInParams, id: Identity, ) -> Result { + let email = + UserEmail::parse(params.email).map_err(|e| ServerError::params_invalid().context(e))?; + let password = UserPassword::parse(params.password) + .map_err(|e| ServerError::params_invalid().context(e))?; + let mut transaction = pool .begin() .await .context("Failed to acquire a Postgres connection to sign in")?; - let user = read_user(&mut transaction, ¶ms.email).await?; + + let user = read_user(&mut transaction, &email.0).await?; transaction .commit() .await .context("Failed to commit SQL transaction to sign in.")?; - match verify_password(¶ms.password, &user.password) { + match verify_password(&password.0, &user.password) { Ok(true) => { let token = Token::create_token(&user)?; let data = SignInResponse { @@ -43,7 +50,7 @@ pub async fn sign_in( id.remember(data.token.clone()); FlowyResponse::success(data) }, - _ => Err(ServerError::passwordNotMatch()), + _ => Err(ServerError::password_not_match()), } } @@ -77,11 +84,11 @@ async fn is_email_exist( .bind(email) .fetch_optional(transaction) .await - .map_err(|err| ServerError::internal().with_msg(err))?; + .map_err(|err| ServerError::internal().context(err))?; match result { Some(_) => Err(ServerError { - code: Code::EmailAlreadyExists, + code: ErrorCode::EmailAlreadyExists, msg: format!("{} already exists", email), }), None => Ok(()), @@ -96,7 +103,7 @@ async fn read_user( .bind(email) .fetch_one(transaction) .await - .map_err(|err| ServerError::internal().with_msg(err))?; + .map_err(|err| ServerError::internal().context(err))?; Ok(user) } @@ -120,7 +127,7 @@ async fn insert_user( ) .execute(transaction) .await - .map_err(|e| ServerError::internal().with_msg(e))?; + .map_err(|e| ServerError::internal().context(e))?; let data = SignUpResponse { uid: uuid.to_string(), diff --git a/backend/src/user_service/utils.rs b/backend/src/user_service/utils.rs index 485963ae58..cde90518a9 100644 --- a/backend/src/user_service/utils.rs +++ b/backend/src/user_service/utils.rs @@ -1,5 +1,5 @@ use bcrypt::{hash, verify, BcryptError, DEFAULT_COST}; -use flowy_net::errors::{Code, ServerError}; +use flowy_net::errors::{ErrorCode, ServerError}; use jsonwebtoken::Algorithm; pub fn uuid() -> String { uuid::Uuid::new_v4().to_string() } @@ -10,14 +10,14 @@ pub fn hash_password(plain: &str) -> Result { .and_then(|c| c.parse().ok()) .unwrap_or(DEFAULT_COST); - hash(plain, hashing_cost).map_err(|e| ServerError::internal().with_msg(e)) + hash(plain, hashing_cost).map_err(|e| ServerError::internal().context(e)) } pub fn verify_password(source: &str, hash: &str) -> Result { match verify(source, hash) { Ok(true) => Ok(true), _ => Err(ServerError { - code: Code::PasswordNotMatch, + code: ErrorCode::PasswordNotMatch, msg: "Username and password don't match".to_string(), }), } diff --git a/rust-lib/flowy-net/src/config.rs b/rust-lib/flowy-net/src/config.rs index 70afa0ca34..15599b77e7 100644 --- a/rust-lib/flowy-net/src/config.rs +++ b/rust-lib/flowy-net/src/config.rs @@ -4,4 +4,5 @@ pub const HOST: &'static str = "http://localhost:8000"; lazy_static! { pub static ref SIGN_UP_URL: String = format!("{}/api/register", HOST); + pub static ref SIGN_IN_URL: String = format!("{}/api/auth", HOST); } diff --git a/rust-lib/flowy-net/src/errors.rs b/rust-lib/flowy-net/src/errors.rs index 383d6c914a..31986508b2 100644 --- a/rust-lib/flowy-net/src/errors.rs +++ b/rust-lib/flowy-net/src/errors.rs @@ -7,7 +7,7 @@ use crate::response::FlowyResponse; #[derive(thiserror::Error, Debug, Serialize, Deserialize, Clone)] pub struct ServerError { - pub code: Code, + pub code: ErrorCode, pub msg: String, } @@ -24,13 +24,14 @@ macro_rules! static_error { } impl ServerError { - static_error!(internal, Code::InternalError); - static_error!(http, Code::HttpError); - static_error!(payload_none, Code::PayloadUnexpectedNone); - static_error!(unauthorized, Code::Unauthorized); - static_error!(passwordNotMatch, Code::PasswordNotMatch); + static_error!(internal, ErrorCode::InternalError); + static_error!(http, ErrorCode::HttpError); + static_error!(payload_none, ErrorCode::PayloadUnexpectedNone); + static_error!(unauthorized, ErrorCode::Unauthorized); + static_error!(password_not_match, ErrorCode::PasswordNotMatch); + static_error!(params_invalid, ErrorCode::ParamsInvalid); - pub fn with_msg(mut self, error: T) -> Self { + pub fn context(mut self, error: T) -> Self { self.msg = format!("{:?}", error); self } @@ -54,7 +55,7 @@ impl std::convert::From<&ServerError> for FlowyResponse { #[derive(Serialize_repr, Deserialize_repr, PartialEq, Debug, Clone, derive_more::Display)] #[repr(u16)] -pub enum Code { +pub enum ErrorCode { #[display(fmt = "Token is invalid")] InvalidToken = 1, #[display(fmt = "Unauthorized")] @@ -65,6 +66,8 @@ pub enum Code { PayloadSerdeFail = 4, #[display(fmt = "Unexpected empty payload")] PayloadUnexpectedNone = 5, + #[display(fmt = "Params is invalid")] + ParamsInvalid = 6, #[display(fmt = "Protobuf serde error")] ProtobufError = 10, diff --git a/rust-lib/flowy-net/src/request/request.rs b/rust-lib/flowy-net/src/request/request.rs index 42e4bfd513..ffb0464fda 100644 --- a/rust-lib/flowy-net/src/request/request.rs +++ b/rust-lib/flowy-net/src/request/request.rs @@ -1,5 +1,5 @@ use crate::{ - errors::{Code, ServerError}, + errors::{ErrorCode, ServerError}, response::FlowyResponse, }; use bytes::Bytes; @@ -83,7 +83,7 @@ impl HttpRequestBuilder { match data { None => { let msg = format!("Request: {} receives unexpected empty body", self.url); - Err(ServerError::payload_none().with_msg(msg)) + Err(ServerError::payload_none().context(msg)) }, Some(data) => Ok(T2::try_from(data)?), } @@ -121,7 +121,7 @@ async fn get_response_data(original: Response) -> Result { Some(error) => Err(error), } } else { - Err(ServerError::http().with_msg(original)) + Err(ServerError::http().context(original)) } } diff --git a/rust-lib/flowy-net/src/response/response.rs b/rust-lib/flowy-net/src/response/response.rs index b2f4b321dc..a02bf9f731 100644 --- a/rust-lib/flowy-net/src/response/response.rs +++ b/rust-lib/flowy-net/src/response/response.rs @@ -1,4 +1,4 @@ -use crate::errors::{Code, ServerError}; +use crate::errors::{ErrorCode, ServerError}; use bytes::Bytes; use serde::{Deserialize, Serialize}; use std::{convert::TryInto, error::Error, fmt::Debug}; @@ -25,35 +25,35 @@ impl FlowyResponse { impl std::convert::From for ServerError { fn from(err: protobuf::ProtobufError) -> Self { ServerError { - code: Code::ProtobufError, + code: ErrorCode::ProtobufError, msg: format!("{}", err), } } } impl std::convert::From for ServerError { - fn from(error: RecvError) -> Self { ServerError::internal().with_msg(error) } + fn from(error: RecvError) -> Self { ServerError::internal().context(error) } } impl std::convert::From for ServerError { fn from(e: serde_json::Error) -> Self { let msg = format!("Serial error: {:?}", e); ServerError { - code: Code::SerdeError, + code: ErrorCode::SerdeError, msg, } } } impl std::convert::From for ServerError { - fn from(error: anyhow::Error) -> Self { ServerError::internal().with_msg(error) } + fn from(error: anyhow::Error) -> Self { ServerError::internal().context(error) } } impl std::convert::From for ServerError { fn from(error: reqwest::Error) -> Self { if error.is_timeout() { return ServerError { - code: Code::ConnectTimeout, + code: ErrorCode::ConnectTimeout, msg: format!("{}", error), }; } @@ -62,22 +62,22 @@ impl std::convert::From for ServerError { let hyper_error: Option<&hyper::Error> = error.source().unwrap().downcast_ref(); return match hyper_error { None => ServerError { - code: Code::ConnectRefused, + code: ErrorCode::ConnectRefused, msg: format!("{:?}", error), }, Some(hyper_error) => { - let mut code = Code::InternalError; + let mut code = ErrorCode::InternalError; let msg = format!("{}", error); if hyper_error.is_closed() { - code = Code::ConnectClose; + code = ErrorCode::ConnectClose; } if hyper_error.is_connect() { - code = Code::ConnectRefused; + code = ErrorCode::ConnectRefused; } if hyper_error.is_canceled() { - code = Code::ConnectCancel; + code = ErrorCode::ConnectCancel; } if hyper_error.is_timeout() {} @@ -89,7 +89,7 @@ impl std::convert::From for ServerError { let msg = format!("{:?}", error); ServerError { - code: Code::ProtobufError, + code: ErrorCode::ProtobufError, msg, } } diff --git a/rust-lib/flowy-user/src/entities/mod.rs b/rust-lib/flowy-user/src/entities/mod.rs index 002293747b..d444d896d1 100644 --- a/rust-lib/flowy-user/src/entities/mod.rs +++ b/rust-lib/flowy-user/src/entities/mod.rs @@ -2,7 +2,7 @@ pub use sign_in::*; pub use sign_up::*; pub use user_detail::*; pub use user_update::*; -mod parser; +pub mod parser; mod sign_in; pub mod sign_up; mod user_detail; diff --git a/rust-lib/flowy-user/src/errors.rs b/rust-lib/flowy-user/src/errors.rs index e5d8283b5b..32c57759ac 100644 --- a/rust-lib/flowy-user/src/errors.rs +++ b/rust-lib/flowy-user/src/errors.rs @@ -63,6 +63,7 @@ pub enum UserErrCode { fmt = "Password should contain a minimum of 6 characters with 1 special 1 letter and 1 numeric" )] PasswordFormatInvalid = 33, + #[display(fmt = "User name is too long")] UserNameTooLong = 40, #[display(fmt = "User name contain forbidden characters")] @@ -83,6 +84,10 @@ pub enum UserErrCode { NetworkError = 100, } +impl UserErrCode { + pub fn to_string(&self) -> String { format!("{}", self) } +} + impl std::default::Default for UserErrCode { fn default() -> Self { UserErrCode::Unknown } } diff --git a/rust-lib/flowy-user/src/services/user/user_server.rs b/rust-lib/flowy-user/src/services/user/user_server.rs index 01c3ac005a..0e6eb401f7 100644 --- a/rust-lib/flowy-user/src/services/user/user_server.rs +++ b/rust-lib/flowy-user/src/services/user/user_server.rs @@ -4,7 +4,7 @@ use crate::{ }; use flowy_net::{ - config::SIGN_UP_URL, + config::*, future::ResultFuture, request::{http_post, HttpRequestBuilder}, }; @@ -35,15 +35,8 @@ impl UserServer for UserServerImpl { ResultFuture::new(async move { user_sign_up(params, SIGN_UP_URL.as_ref()).await }) } - fn sign_in(&self, _params: SignInParams) -> ResultFuture { - // let user_id = params.email.clone(); - // Ok(UserTable::new( - // user_id, - // "".to_owned(), - // params.email, - // params.password, - // )) - unimplemented!() + fn sign_in(&self, params: SignInParams) -> ResultFuture { + ResultFuture::new(async move { user_sign_in(params, SIGN_IN_URL.as_ref()).await }) } fn sign_out(&self, _user_id: &str) -> ResultFuture<(), UserError> {