diff --git a/src/services/identity/service.rs b/src/services/identity/service.rs index 979f9ec..7237c78 100644 --- a/src/services/identity/service.rs +++ b/src/services/identity/service.rs @@ -64,6 +64,7 @@ impl Service<'_> { self.check_nickname_for_duplication(), self.captcha(), self.signin(), + self.signin_without_security_code(), ) .map(|_| ()) } @@ -678,4 +679,212 @@ impl Service<'_> { Ok(()) } + + async fn signin_without_security_code(&self) -> Result<(), Box> { + let s = self + .connection_broker + .queue_subscribe( + bpr::ss::identity::SUBJECT_SIGNIN_WITHOUT_SECURITY_CODE, + self.queue_broker.as_str(), + ) + .await?; + + while let Some(message) = s.next().await { + if let Err(e) = async { + let req = + bpr::ss::identity::SigninWithoutSecurityCodeRequest::decode(message.data.as_slice()) + .map_err(|e| { + bcr::error::rpc::Error::InvalidRequest(bcr::error::rpc::InvalidRequest { + message: format!("invalid request: {}", e), + }) + })?; + + let client = match req.client { + Some(c) => c, + None => { + return Err(bcr::error::rpc::Error::InvalidParams( + bcr::error::rpc::InvalidParams { + message: "invalid client information".to_string(), + detail: bcr::error::rpc::InvalidParamsDetail { + location: "request".to_string(), + param: "client".to_string(), + value: "".to_string(), + error_type: bcr::error::rpc::InvalidParamsType::Required, + message: "".to_string(), + }, + }, + )); + } + }; + let request = match req.request { + Some(r) => r, + None => { + return Err(bcr::error::rpc::Error::InvalidParams( + bcr::error::rpc::InvalidParams { + message: "invalid request information".to_string(), + detail: bcr::error::rpc::InvalidParamsDetail { + location: "request".to_string(), + param: "request".to_string(), + value: "".to_string(), + error_type: bcr::error::rpc::InvalidParamsType::Required, + message: "".to_string(), + }, + }, + )); + } + }; + let conn = self.pool.get().map_err(|e| { + bcr::error::rpc::Error::Server(bcr::error::rpc::Server { + code: bpr::protobuf::rpc::Error::SERVER_00, + message: format!("server {}", e), + data: None, + }) + })?; + + let username = request.username; + let password = request.password; + + let m = match self + .member_repository + .select_by_username(&conn, &username) + .map_err(|e| { + bcr::error::rpc::Error::Server(bcr::error::rpc::Server { + code: bpr::protobuf::rpc::Error::SERVER_00, + message: format!("server {}", e), + data: None, + }) + })? { + Some(m) => m, + None => { + return Err(bcr::error::rpc::Error::InvalidParams( + bcr::error::rpc::InvalidParams { + message: "invalid username".to_string(), + detail: bcr::error::rpc::InvalidParamsDetail { + location: "request".to_string(), + param: "username".to_string(), + value: username, + error_type: bcr::error::rpc::InvalidParamsType::None, + message: "".to_string(), + }, + }, + )); + } + }; + + if !(argon2::verify_encoded(&m.password, password.as_bytes()).map_err(|e| { + bcr::error::rpc::Error::InvalidParams(bcr::error::rpc::InvalidParams { + message: "invalid password".to_string(), + detail: bcr::error::rpc::InvalidParamsDetail { + location: "request".to_string(), + param: "password".to_string(), + value: password.clone(), + error_type: bcr::error::rpc::InvalidParamsType::None, + message: e.to_string(), + }, + }) + })?) { + return Err(bcr::error::rpc::Error::InvalidParams( + bcr::error::rpc::InvalidParams { + message: "invalid password".to_string(), + detail: bcr::error::rpc::InvalidParamsDetail { + location: "request".to_string(), + param: "password".to_string(), + value: password.clone(), + error_type: bcr::error::rpc::InvalidParamsType::EqualsTo, + message: "".to_string(), + }, + }, + )); + } + + let _s = self.check_site(&conn, client.site_url.clone(), m.site_id)?; + + let expires_at = (chrono::Utc::now() + chrono::Duration::minutes(30)).timestamp(); + let session = self + .member_session_repository + .insert( + &conn, + &repositories::member_session::models::NewMemberSession { + member_id: m.id, + ip: client.client_ip.clone(), + expires_at, + }, + ) + .map_err(|e| { + bcr::error::rpc::Error::Server(bcr::error::rpc::Server { + code: bpr::protobuf::rpc::Error::SERVER_00, + message: format!("server {}", e), + data: None, + }) + })?; + + let access_token = self + .identity_composition + .get_token("Beteran".to_string(), session.id.to_string()) + .map_err(|e| { + bcr::error::rpc::Error::Server(bcr::error::rpc::Server { + code: bpr::protobuf::rpc::Error::SERVER_00, + message: format!("server {}", e), + data: None, + }) + })?; + + self + .connection_broker + .publish( + bpr::ss::identity::EVENT_SUBJECT_AFTER_SIGNIN, + bpr::ss::identity::AfterSigninEvent { + client: Some(client), + event: Some(bpr::ss::identity::after_signin_event::Event { + member: Some(bpr::models::member::Member::from(&m)), + }), + } + .encode_to_vec(), + ) + .await + .map_err(|e| { + bcr::error::rpc::Error::Server(bcr::error::rpc::Server { + code: bpr::protobuf::rpc::Error::SERVER_00, + message: format!("server {}", e), + data: None, + }) + })?; + + message + .respond( + bpr::ss::identity::SigninWithoutSecurityCodeResponse { + error: None, + result: Some( + bpr::ss::identity::signin_without_security_code_response::Result { access_token }, + ), + } + .encode_to_vec(), + ) + .await + .map_err(|e| { + bcr::error::rpc::Error::Server(bcr::error::rpc::Server { + code: bpr::protobuf::rpc::Error::SERVER_00, + message: format!("server {}", e), + data: None, + }) + })?; + + Ok::<(), bcr::error::rpc::Error>(()) + } + .await + { + message + .respond( + bpr::ss::identity::SigninWithoutSecurityCodeResponse { + error: Some(bpr::protobuf::rpc::Error::from(e)), + result: None, + } + .encode_to_vec(), + ) + .await?; + } + } + + Ok(()) + } }