diff --git a/migrations/20210310122154_mcaptcha_users.sql b/migrations/20210310122154_mcaptcha_users.sql index 28a9c24f..09a59c35 100644 --- a/migrations/20210310122154_mcaptcha_users.sql +++ b/migrations/20210310122154_mcaptcha_users.sql @@ -1,6 +1,7 @@ CREATE TABLE IF NOT EXISTS mcaptcha_users ( name VARCHAR(100) NOT NULL UNIQUE, email VARCHAR(100) NOT NULL UNIQUE, + secret varchar(50) NOT NULL UNIQUE, password TEXT NOT NULL, ID SERIAL PRIMARY KEY NOT NULL ); diff --git a/src/api/v1/auth.rs b/src/api/v1/auth.rs index 4ca818d4..39cc8656 100644 --- a/src/api/v1/auth.rs +++ b/src/api/v1/auth.rs @@ -14,12 +14,14 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ +use std::borrow::Cow; use actix_identity::Identity; use actix_web::{post, web, HttpResponse, Responder}; use log::debug; use serde::{Deserialize, Serialize}; +use super::mcaptcha::get_random; use crate::errors::*; use crate::Data; @@ -49,19 +51,53 @@ pub async fn signup( let username = data.creds.username(&payload.username)?; let hash = data.creds.password(&payload.password)?; data.creds.email(Some(&payload.email))?; - let res = sqlx::query!( - "INSERT INTO mcaptcha_users (name , password, email) VALUES ($1, $2, $3)", + + let mut secret; + + loop { + secret = get_random(32); + let res = add_user_helper(&username, &hash, &payload.email, &secret, &data).await; + if res.is_ok() { + break; + } else { + if let Err(sqlx::Error::Database(err)) = res { + if err.code() == Some(Cow::from("23505")) { + let msg = err.message(); + if msg.contains("mcaptcha_users_name_key") { + Err(ServiceError::UsernameTaken)?; + } else if msg.contains("mcaptcha_users_secret_key") { + continue; + } else { + Err(ServiceError::InternalServerError)?; + } + } else { + Err(sqlx::Error::Database(err))?; + } + }; + } + } + Ok(HttpResponse::Ok()) +} + +pub async fn add_user_helper( + username: &str, + hash: &str, + email: &str, + secret: &str, + data: &Data, +) -> Result<(), sqlx::Error> { + sqlx::query!( + "INSERT INTO mcaptcha_users + (name , password, email, secret) VALUES ($1, $2, $3, $4)", username, hash, - &payload.email + email, + //get_random(32), + secret, ) .execute(&data.db) - .await; - - match res { - Err(e) => Err(dup_error(e, ServiceError::UsernameTaken)), - Ok(_) => Ok(HttpResponse::Ok()), - } + .await?; + Ok(()) } #[post("/api/v1/signin")] diff --git a/src/errors.rs b/src/errors.rs index e573334c..bb061b04 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -204,7 +204,9 @@ impl From for ServiceError { pub fn dup_error(e: sqlx::Error, dup_error: ServiceError) -> ServiceError { use sqlx::error::Error; use std::borrow::Cow; + // println!("sqlx:Error: {:#?}", &e); if let Error::Database(err) = e { + // println!("Database Error: {:#?}", &err); if err.code() == Some(Cow::from("23505")) { dup_error } else {