From 81ac84043b456449c664fb81db452f0417534c94 Mon Sep 17 00:00:00 2001 From: PARK BYUNG JUN Date: Sat, 6 Aug 2022 04:20:17 +0000 Subject: [PATCH] captcha repository is removed --- .vscode/launch.json | 4 + Cargo.toml | 4 +- migrations/202206201300_captcha/down.sql | 3 - migrations/202206201300_captcha/up.sql | 12 -- src/main.rs | 11 ++ src/repositories/captcha/mod.rs | 9 - src/repositories/captcha/models.rs | 37 ----- src/repositories/captcha/repository.rs | 135 --------------- src/repositories/captcha/schema.rs | 16 -- src/repositories/mod.rs | 1 - src/services/identity/service.rs | 203 ++++++++++------------- 11 files changed, 102 insertions(+), 333 deletions(-) delete mode 100644 migrations/202206201300_captcha/down.sql delete mode 100644 migrations/202206201300_captcha/up.sql delete mode 100644 src/repositories/captcha/mod.rs delete mode 100644 src/repositories/captcha/models.rs delete mode 100644 src/repositories/captcha/repository.rs delete mode 100644 src/repositories/captcha/schema.rs diff --git a/.vscode/launch.json b/.vscode/launch.json index fe6a34b..1751753 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -23,6 +23,8 @@ "URL_DATABASE": "postgresql://beteran:qwer5795QWER@192.168.50.200:25432/beteran", "URL_BROKER": "nats://192.168.50.200:4222", "QUEUE_BROKER": "bet.beteran", + "CAPTCHA_SALT": "qwer5795QWER", + "PASSWORD_SALT": "qwer5795QWER", }, "args": [], "cwd": "${workspaceFolder}" @@ -47,6 +49,8 @@ "URL_DATABASE": "postgresql://beteran:qwer5795QWER@192.168.50.200:25432/beteran", "URL_BROKER": "nats://192.168.50.200:4222", "QUEUE_BROKER": "bet.beteran", + "CAPTCHA_SALT": "qwer5795QWER", + "PASSWORD_SALT": "qwer5795QWER", }, "args": [], "cwd": "${workspaceFolder}" diff --git a/Cargo.toml b/Cargo.toml index ecad178..2b36b75 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ tokio = { version = "1", features = ["macros", "rt-multi-thread"] } tokio-cron-scheduler = { version = "0" } uuid = { version = "0", features = ["serde", "v4", "v5"] } -beteran-protobuf-rust = { git = "https://gitlab.loafle.net/bet/beteran-protobuf-rust.git", tag = "v0.1.22-snapshot" } -beteran-common-rust = { git = "https://gitlab.loafle.net/bet/beteran-common-rust.git", tag = "v0.1.2-snapshot" } +beteran-protobuf-rust = { git = "https://gitlab.loafle.net/bet/beteran-protobuf-rust.git", tag = "v0.1.23-snapshot" } +beteran-common-rust = { git = "https://gitlab.loafle.net/bet/beteran-common-rust.git", tag = "v0.1.3-snapshot" } [build-dependencies] diff --git a/migrations/202206201300_captcha/down.sql b/migrations/202206201300_captcha/down.sql deleted file mode 100644 index 215fed9..0000000 --- a/migrations/202206201300_captcha/down.sql +++ /dev/null @@ -1,3 +0,0 @@ -DROP UNIQUE INDEX uidx_captchas_token; -DROP TABLE captchas; - diff --git a/migrations/202206201300_captcha/up.sql b/migrations/202206201300_captcha/up.sql deleted file mode 100644 index f78ed05..0000000 --- a/migrations/202206201300_captcha/up.sql +++ /dev/null @@ -1,12 +0,0 @@ -CREATE TABLE IF NOT EXISTS captchas ( - id UUID DEFAULT uuid_generate_v4(), - token TEXT NOT NULL, - security_code TEXT NOT NULL, - expires_at BIGINT NOT NULL DEFAULT (extract(epoch from now()) * 1000), - created_at BIGINT NOT NULL DEFAULT (extract(epoch from now()) * 1000), - - PRIMARY KEY (id) -); - --- index -CREATE UNIQUE INDEX uidx_captchas_token ON captchas (token); diff --git a/src/main.rs b/src/main.rs index 3e656f3..e71899f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -34,6 +34,15 @@ async fn main() -> Result<(), Box> { None => "".to_string(), }; + let captcha_salt = match env::var_os("CAPTCHA_SALT") { + Some(v) => v.into_string().unwrap(), + None => "".to_string(), + }; + let password_salt = match env::var_os("PASSWORD_SALT") { + Some(v) => v.into_string().unwrap(), + None => "".to_string(), + }; + let manager = ConnectionManager::::new(url_db); let pool = Pool::builder() .max_size(4) @@ -50,6 +59,8 @@ async fn main() -> Result<(), Box> { connection_server_broker.clone(), queue_server_broker.clone(), pool.clone(), + captcha_salt.clone(), + password_salt.clone(), ); println!("Server service [beteran-server-service] is started"); diff --git a/src/repositories/captcha/mod.rs b/src/repositories/captcha/mod.rs deleted file mode 100644 index bef7c9e..0000000 --- a/src/repositories/captcha/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -//! -//! - -/// -pub mod models; -/// -pub mod repository; -/// -pub mod schema; diff --git a/src/repositories/captcha/models.rs b/src/repositories/captcha/models.rs deleted file mode 100644 index 78fd65f..0000000 --- a/src/repositories/captcha/models.rs +++ /dev/null @@ -1,37 +0,0 @@ -use super::schema::captchas; -use beteran_common_rust as bcr; - -/// -#[derive(Eq, Hash, Identifiable, Queryable, PartialEq, Debug, Clone)] -#[table_name = "captchas"] -pub struct Captcha { - /// - pub id: uuid::Uuid, - /// - pub security_code: String, - /// - pub expires_at: i64, - /// - pub created_at: i64, -} - -/// -#[derive(Insertable, Debug, Clone)] -#[table_name = "captchas"] -pub struct NewCaptcha { - /// - pub security_code: String, - /// - pub expires_at: i64, -} - -/// -#[derive(Debug, Clone)] -pub struct FindAll { - /// - pub expires_at: Option, - /// - pub pagination: Option, - /// - pub sorts: Option>, -} diff --git a/src/repositories/captcha/repository.rs b/src/repositories/captcha/repository.rs deleted file mode 100644 index efacfd4..0000000 --- a/src/repositories/captcha/repository.rs +++ /dev/null @@ -1,135 +0,0 @@ -//! -//! -use super::{models, schema::captchas}; -use beteran_common_rust as bcr; -use diesel::prelude::*; -use diesel::result::Error; - -/// -pub struct Repository {} - -impl std::fmt::Debug for Repository { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - f.debug_struct("Repository of captchas").finish() - } -} - -impl Default for Repository { - fn default() -> Self { - Self::new() - } -} - -impl Repository { - /// - pub fn new() -> Repository { - Repository {} - } - - /// - pub fn insert( - &self, - conn: &diesel::PgConnection, - new_captcha: &models::NewCaptcha, - ) -> Result { - let captcha = diesel::insert_into(captchas::table) - .values(new_captcha) - .get_result::(conn)?; - - Ok(captcha) - } - - /// - pub fn select( - &self, - conn: &diesel::PgConnection, - id: uuid::Uuid, - ) -> Result, Error> { - match captchas::table.find(id).first::(conn) { - Ok(m) => Ok(Some(m)), - Err(e) => match e { - diesel::result::Error::NotFound => Ok(None), - _ => Err(e), - }, - } - } - - /// - pub fn select_all_count( - &self, - conn: &diesel::PgConnection, - find_all: models::FindAll, - ) -> Result { - use captchas::dsl; - - let mut q = captchas::table.into_boxed(); - - if let Some(sp) = find_all.expires_at { - q = q.filter(dsl::expires_at.lt(sp)); - } - - q.count().get_result(conn) - } - - /// - pub fn select_all( - &self, - conn: &diesel::PgConnection, - find_all: models::FindAll, - ) -> Result, Error> { - use captchas::dsl; - - let mut q = captchas::table.into_boxed(); - - if let Some(sp) = find_all.expires_at { - q = q.filter(dsl::expires_at.lt(sp)); - } - - if let Some(p) = find_all.pagination { - let page = p.page.unwrap_or(1); - - if let Some(page_size) = p.page_size { - q = q.offset(((page - 1) * page_size) as i64); - q = q.limit(page_size as i64); - } - } - if let Some(orderbys) = find_all.sorts { - for s in orderbys { - match s { - bcr::models::pagination::Sort::ASC(property) => match property.as_str() { - "expires_at" => { - q = q.order_by(dsl::expires_at.asc()); - } - "created_at" => { - q = q.order_by(dsl::created_at.asc()); - } - - _ => {} - }, - bcr::models::pagination::Sort::DESC(property) => match property.as_str() { - "expires_at" => { - q = q.order_by(dsl::expires_at.desc()); - } - "created_at" => { - q = q.order_by(dsl::created_at.desc()); - } - _ => {} - }, - }; - } - } - - q.load::(conn) - } - - /// - pub fn delete_expired(&self, conn: &diesel::PgConnection) -> Result { - use captchas::dsl; - - let now = chrono::Utc::now().timestamp(); - - diesel::delete(dsl::captchas.filter(dsl::expires_at.le(now))) - .execute(conn) - .map(|c| c as u64) - } -} diff --git a/src/repositories/captcha/schema.rs b/src/repositories/captcha/schema.rs deleted file mode 100644 index 0e81576..0000000 --- a/src/repositories/captcha/schema.rs +++ /dev/null @@ -1,16 +0,0 @@ -//! -//! - -table! { - /// - captchas(id) { - /// - id -> Uuid, - /// - security_code -> Text, - /// - expires_at -> BigInt, - /// - created_at -> BigInt, - } -} diff --git a/src/repositories/mod.rs b/src/repositories/mod.rs index b498a5d..90f5fbe 100644 --- a/src/repositories/mod.rs +++ b/src/repositories/mod.rs @@ -1,4 +1,3 @@ -pub mod captcha; pub mod member; pub mod member_class; pub mod member_level; diff --git a/src/services/identity/service.rs b/src/services/identity/service.rs index 58f6989..5e6fc7b 100644 --- a/src/services/identity/service.rs +++ b/src/services/identity/service.rs @@ -1,8 +1,6 @@ //! //! -use std::str::FromStr; - use super::super::super::repositories; use beteran_common_rust as bcr; use beteran_protobuf_rust as bpr; @@ -13,30 +11,34 @@ use diesel::{ use prost::Message; /// -pub struct Service { +pub struct Service<'a> { connection_broker: nats::asynk::Connection, queue_broker: String, pool: Pool>, member_repository: repositories::member::repository::Repository, member_site_repository: repositories::member_site::repository::Repository, member_session_repository: repositories::member_session::repository::Repository, - captcha_repository: repositories::captcha::repository::Repository, + argon2_config: argon2::Config<'a>, + captcha_salt: String, + password_salt: String, } -impl std::fmt::Debug for Service { +impl std::fmt::Debug for Service<'_> { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { f.debug_struct("Service of service.member.service.identity") .finish() } } -impl Service { +impl Service<'_> { /// pub fn new( connection_broker: nats::asynk::Connection, queue_broker: String, pool: Pool>, - ) -> Service { + captcha_salt: String, + password_salt: String, + ) -> Service<'static> { Service { connection_broker, queue_broker, @@ -44,7 +46,19 @@ impl Service { member_repository: repositories::member::repository::Repository::new(), member_site_repository: repositories::member_site::repository::Repository::new(), member_session_repository: repositories::member_session::repository::Repository::new(), - captcha_repository: repositories::captcha::repository::Repository::new(), + argon2_config: argon2::Config { + variant: argon2::Variant::Argon2i, + version: argon2::Version::Version13, + mem_cost: 65536, + time_cost: 10, + lanes: 4, + thread_mode: argon2::ThreadMode::Parallel, + secret: &[], + ad: &[], + hash_length: 32, + }, + captcha_salt, + password_salt, } } @@ -288,23 +302,23 @@ impl Service { } }; - let site_url = match client.site_url { - Some(site_url) => site_url, - None => { - return Err(bcr::error::rpc::Error::InvalidParams( - bcr::error::rpc::InvalidParams { - message: "invalid site_url information".to_string(), - detail: bcr::error::rpc::InvalidParamsDetail { - location: "request".to_string(), - param: "client.site_url".to_string(), - value: "".to_string(), - error_type: bcr::error::rpc::InvalidParamsType::Required, - message: "".to_string(), - }, - }, - )); - } - }; + // let site_url = match client.site_url { + // Some(site_url) => site_url, + // None => { + // return Err(bcr::error::rpc::Error::InvalidParams( + // bcr::error::rpc::InvalidParams { + // message: "invalid site_url information".to_string(), + // detail: bcr::error::rpc::InvalidParamsDetail { + // location: "request".to_string(), + // param: "client.site_url".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 { @@ -314,36 +328,37 @@ impl Service { }) })?; - match self - .member_site_repository - .select_by_url(&conn, &site_url) - .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(ms) => ms, - None => { - return Err(bcr::error::rpc::Error::InvalidParams( - bcr::error::rpc::InvalidParams { - message: "invalid site_url information".to_string(), - detail: bcr::error::rpc::InvalidParamsDetail { - location: "request".to_string(), - param: "client.site_url".to_string(), - value: "".to_string(), - error_type: bcr::error::rpc::InvalidParamsType::None, - message: "".to_string(), - }, - }, - )); - } - }; + // match self + // .member_site_repository + // .select_by_url(&conn, &site_url) + // .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(ms) => ms, + // None => { + // return Err(bcr::error::rpc::Error::InvalidParams( + // bcr::error::rpc::InvalidParams { + // message: "invalid site_url information".to_string(), + // detail: bcr::error::rpc::InvalidParamsDetail { + // location: "request".to_string(), + // param: "client.site_url".to_string(), + // value: "".to_string(), + // error_type: bcr::error::rpc::InvalidParamsType::None, + // message: "".to_string(), + // }, + // }, + // )); + // } + // }; let mut c = captcha::Captcha::new(); let c = c + .add_chars(5) .apply_filter(captcha::filters::Noise::new(0.1)) .view(220, 120); @@ -359,30 +374,19 @@ impl Service { }; let security_code = c.chars_as_string(); - let expires_at = (chrono::Utc::now() + chrono::Duration::hours(2)).timestamp(); - - let new_captcha = repositories::captcha::models::NewCaptcha { - security_code, - expires_at, - }; - - let inserted_captcha = self - .captcha_repository - .insert(&conn, &new_captcha) - .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 security_code_hash = argon2::hash_encoded( + security_code.as_bytes(), + self.captcha_salt.as_bytes(), + &self.argon2_config, + ) + .unwrap(); message .respond( bpr::ss::member::identity::CaptchaResponse { error: None, result: Some(bpr::ss::member::identity::captcha_response::Result { - token: inserted_captcha.id.to_string(), + security_code_hash, image: image_as_base64, }), } @@ -487,65 +491,28 @@ impl Service { } }; - let captcha_id = uuid::Uuid::from_str(req.token.as_str()).map_err(|e| { - bcr::error::rpc::Error::InvalidParams(bcr::error::rpc::InvalidParams { - message: "invalid captcha token".to_string(), - detail: bcr::error::rpc::InvalidParamsDetail { - location: "request".to_string(), - param: "token".to_string(), - value: "".to_string(), - error_type: bcr::error::rpc::InvalidParamsType::None, - message: e.to_string(), - }, - }) - })?; + let security_code_hash = req.security_code_hash; let security_code = req.security_code; let username = req.username; let password = req.password; - let captcha = match self - .captcha_repository - .select(&conn, captcha_id) - .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(c) => c, - None => { - return Err(bcr::error::rpc::Error::InvalidParams( - bcr::error::rpc::InvalidParams { - message: "invalid captcha token".to_string(), + let security_code_matches = + argon2::verify_encoded(security_code_hash.as_str(), security_code.as_bytes()).map_err( + |e| { + bcr::error::rpc::Error::InvalidParams(bcr::error::rpc::InvalidParams { + message: "invalid security_code".to_string(), detail: bcr::error::rpc::InvalidParamsDetail { location: "request".to_string(), - param: "token".to_string(), - value: "".to_string(), + param: "security_code".to_string(), + value: security_code.clone(), error_type: bcr::error::rpc::InvalidParamsType::None, - message: "".to_string(), + message: e.to_string(), }, - }, - )); - } - }; - - if !captcha.expires_at < chrono::Utc::now().timestamp() { - return Err(bcr::error::rpc::Error::InvalidParams( - bcr::error::rpc::InvalidParams { - message: "invalid captcha token".to_string(), - detail: bcr::error::rpc::InvalidParamsDetail { - location: "request".to_string(), - param: "token".to_string(), - value: "".to_string(), - error_type: bcr::error::rpc::InvalidParamsType::None, - message: "captcha token is expired".to_string(), - }, + }) }, - )); - } + )?; - if !captcha.security_code.eq(&security_code) { + if !security_code_matches { return Err(bcr::error::rpc::Error::InvalidParams( bcr::error::rpc::InvalidParams { message: "invalid security_code".to_string(),