diff --git a/Cargo.toml b/Cargo.toml index a51decb..30704c5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,3 +34,4 @@ openssl = "0.10.64" alcoholic_jwt = "4091.0.0" utoipa = { version = "4.2.3", features = ["actix_extras", "chrono", "yaml", "uuid"] } utoipa-swagger-ui = { version = "7.0.1", features = ["actix-web"] } +futures-util = "0.3.30" diff --git a/migrations/2024-03-09-212028_create_user_table/up.sql b/migrations/2024-03-09-212028_create_user_table/up.sql index d114e7b..7fb0951 100644 --- a/migrations/2024-03-09-212028_create_user_table/up.sql +++ b/migrations/2024-03-09-212028_create_user_table/up.sql @@ -2,7 +2,6 @@ CREATE TABLE users ( id UUID PRIMARY KEY, username VARCHAR(255), email VARCHAR(255) NOT NULL, - password VARCHAR(255) NOT NULL, is_email_activate BOOLEAN DEFAULT FALSE, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP diff --git a/src/actors/handlers.rs b/src/actors/handlers.rs index b26f668..32f4f10 100644 --- a/src/actors/handlers.rs +++ b/src/actors/handlers.rs @@ -1,6 +1,6 @@ use crate::actors::messages::{ CheckIfRegisteredUser, CheckUser, CreateUser, DeleteUser, UpdateActivateEmail, UpdateEmail, - UpdatePassword, UpdateUsername, + UpdateUsername, }; use crate::db::postgres_db::DbService; use crate::db::tables::Users; @@ -19,7 +19,6 @@ impl Handler for DbService { id: msg.id, username: msg.username, email: msg.email, - password: msg.password, is_email_activate: false, created_at: chrono::Utc::now(), updated_at: None, @@ -83,27 +82,6 @@ impl Handler for DbService { } } -impl Handler for DbService { - type Result = AtomicResponse>; - - fn handle(&mut self, msg: UpdatePassword, _: &mut Self::Context) -> Self::Result { - let db = self.clone(); - let conn = async move { db.pool.get().await }; - let query = async move { - let _ = diesel::update(crate::db::schema::users::table) - .filter(crate::db::schema::users::id.eq(msg.user_id)) - .set(crate::db::schema::users::password.eq(msg.password)) - .execute(&mut conn.await?) - .await?; - Ok(()) - }; - log::info!("Updating user password {}", msg.user_id); - - let db = self.clone(); - AtomicResponse::new(Box::pin(query.into_actor(&db))) - } -} - impl Handler for DbService { type Result = AtomicResponse>; diff --git a/src/actors/messages.rs b/src/actors/messages.rs index 3f921a6..b33d71e 100644 --- a/src/actors/messages.rs +++ b/src/actors/messages.rs @@ -23,13 +23,6 @@ pub(crate) struct DeleteUser { pub user_id: Uuid, } -#[derive(Message)] -#[rtype(result = "crate::errors::Result<()>")] -pub(crate) struct UpdatePassword { - pub user_id: Uuid, - pub password: String, -} - #[derive(Message)] #[rtype(result = "crate::errors::Result<()>")] pub(crate) struct UpdateEmail { diff --git a/src/db/schema.rs b/src/db/schema.rs index 9ac6724..c3a9cdf 100644 --- a/src/db/schema.rs +++ b/src/db/schema.rs @@ -2,7 +2,6 @@ diesel::table!(users { id -> Uuid, username -> Varchar, email -> Varchar, - password -> Varchar, is_email_activate -> Bool, created_at -> Timestamptz, updated_at -> Nullable diff --git a/src/db/tables.rs b/src/db/tables.rs index 8bce338..88961bf 100644 --- a/src/db/tables.rs +++ b/src/db/tables.rs @@ -9,7 +9,6 @@ pub struct Users { pub id: Uuid, pub username: String, pub email: String, - pub password: String, pub is_email_activate: bool, pub created_at: DateTime, pub updated_at: Option>, diff --git a/src/main.rs b/src/main.rs index 48c0abc..0e753eb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,29 +2,31 @@ pub mod actors; pub mod consts; pub mod db; pub mod errors; +pub mod middleware; pub mod models; +pub mod services; pub mod user_flow; pub mod utils; use crate::db::postgres_db::DbService; use crate::errors::Result; -use crate::user_flow::requests::{check_token, login, register}; -use crate::utils::init_logging; +use crate::utils::{configure_data, configure_routes, init_logging}; use actix::Actor; -use actix_web::web::Data; -use utoipa_swagger_ui::SwaggerUi; +use crate::services::auth0::Auth0Service; use utoipa::OpenApi; #[derive(OpenApi)] #[openapi( paths( crate::user_flow::requests::login, - crate::user_flow::requests::register + crate::user_flow::requests::register, + crate::user_flow::requests::change_password ), components( schemas(crate::models::RegisteredUserData), - schemas(crate::models::UserData) + schemas(crate::models::UserData), + schemas(crate::models::UpdatePasswordData), ) )] struct ApiDoc; @@ -38,19 +40,23 @@ async fn main() -> Result<()> { let pool = db::utils::create_connection_pool(database_url).await?; let db = DbService::new(pool); let db = db.start(); - let openapi = ApiDoc::openapi(); - actix_web::HttpServer::new(move || { + + let client_id = dotenv::var("CLIENT_ID").unwrap_or_else(|_| "admin".to_string()); + let client = dotenv::var("CLIENT").unwrap_or_else(|_| "localhost:8080".to_string()); + let client_secret = dotenv::var("CLIENT_SECRET").unwrap_or_else(|_| "admin".to_string()); + let connection = dotenv::var("CONNECTION") + .unwrap_or_else(|_| "Username-Password-Authentication".to_string()); + let bind = dotenv::var("BIND").unwrap_or_else(|_| "localhost:8080".to_string()); + + let auth0_service = Auth0Service::new(client_id, client_secret, connection, client); + + let server = actix_web::HttpServer::new(move || { actix_web::App::new() - .route("/login", actix_web::web::post().to(login)) - .route("/register", actix_web::web::post().to(register)) - .route("/check_token", actix_web::web::get().to(check_token)) - .service( - SwaggerUi::new("/swagger-ui/{_:.*}").url("/api-docs/openapi.json", openapi.clone()), - ) - .app_data(Data::new(db.clone())) + .configure(configure_routes) + .configure(configure_data(db.clone(), auth0_service.clone())) }) - .bind("localhost:8080")? - .run() - .await?; + .bind(bind)?; + + server.run().await?; Ok(()) } diff --git a/src/middleware/auth.rs b/src/middleware/auth.rs new file mode 100644 index 0000000..6fc0046 --- /dev/null +++ b/src/middleware/auth.rs @@ -0,0 +1,107 @@ +use actix_web::body::BoxBody; +use actix_web::dev::{Service, ServiceRequest, ServiceResponse, Transform}; +use actix_web::{Error, HttpResponse}; +use futures_util::future::{ok, LocalBoxFuture, Ready}; +use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation}; +use serde::Deserialize; +use std::fs::File; +use std::io::Read; +use std::rc::Rc; +use std::sync::Arc; +use std::task::{Context, Poll}; +use tokio::sync::RwLock; + +#[derive(Debug, Deserialize)] +#[allow(dead_code)] +struct Claims { + sub: String, + exp: usize, +} + +pub struct AuthMiddleware; + +pub struct CheckAuthMiddleware { + service: Rc, + decoding_key: Arc>, +} + +impl Transform for AuthMiddleware +where + S: Service, Error = Error> + 'static, + S::Future: 'static, +{ + type Response = ServiceResponse; + type Error = Error; + type Transform = CheckAuthMiddleware; + type InitError = (); + type Future = Ready>; + + fn new_transform(&self, service: S) -> Self::Future { + let jwt_secret = std::env::var("JWT_SECRET").unwrap_or_else(|_| "secret".to_string()); + let decoding_key = AuthMiddleware::new_from_file(&jwt_secret).expect("Failed to load key"); + ok(CheckAuthMiddleware { + service: Rc::new(service), + decoding_key: Arc::new(RwLock::new(decoding_key)), + }) + } +} + +impl Service for CheckAuthMiddleware +where + S: Service, Error = Error> + 'static, + S::Future: 'static, +{ + type Response = ServiceResponse; + type Error = Error; + type Future = LocalBoxFuture<'static, Result>; + + fn poll_ready(&self, _: &mut Context<'_>) -> Poll> { + Poll::Ready(Ok(())) + } + + fn call(&self, req: ServiceRequest) -> Self::Future { + let service = Rc::clone(&self.service); + let decoding_key = self.decoding_key.clone(); + + Box::pin(async move { + let auth_header = req.headers().get("Authorization"); + + if req.path() == "/login" || req.path() == "/register" || req.path() == "/" { + return Ok(req.into_response(HttpResponse::Ok().finish())); + } + + if let Some(auth_header) = auth_header { + if let Ok(auth_token) = auth_header.to_str() { + if let Some(auth_str) = auth_token.strip_prefix("Bearer ") { + let token = &auth_str[7..]; + + let decoding_key = decoding_key.read().await; + + return match decode::( + token, + &decoding_key, + &Validation::new(Algorithm::HS256), + ) { + Ok(_) => service.call(req).await, + Err(_) => Ok(req.into_response(HttpResponse::Unauthorized().finish())), + }; + } + } + } + + Ok(req.into_response(HttpResponse::Unauthorized().finish())) + }) + } +} + +impl AuthMiddleware { + pub fn new_from_file(path: &str) -> Result { + let mut file = File::open(path)?; + let mut key_data = Vec::new(); + file.read_to_end(&mut key_data)?; + + let decoding_key = DecodingKey::from_secret(&key_data); + + Ok(decoding_key) + } +} diff --git a/src/middleware/mod.rs b/src/middleware/mod.rs new file mode 100644 index 0000000..0e4a05d --- /dev/null +++ b/src/middleware/mod.rs @@ -0,0 +1 @@ +pub mod auth; diff --git a/src/models.rs b/src/models.rs index 38ce67f..854e3bc 100644 --- a/src/models.rs +++ b/src/models.rs @@ -17,27 +17,8 @@ pub struct RegisteredUserData { pub password: String, } -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct ConnectToAuth0 { - pub client_id: String, - pub client_secret: String, - pub audience: String, - pub grant_type: String, - pub user_id: String, - pub connection: String, - #[serde(flatten)] - pub extra: T, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct RegistrationFlow { - pub username: String, - pub password: String, +#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] +pub struct UpdatePasswordData { + pub user_id: Uuid, pub email: String, } - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct LoginFlow { - pub username: String, - pub password: String, -} diff --git a/src/services/auth0.rs b/src/services/auth0.rs new file mode 100644 index 0000000..05d2841 --- /dev/null +++ b/src/services/auth0.rs @@ -0,0 +1,83 @@ +use crate::consts::{AUDIENCE, GRANT_TYPE_PASS}; +use crate::user_flow::auth0_models::{ChangePassFlow, ConnectToAuth0, LoginFlow, RegistrationFlow}; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct Auth0Service { + pub client_id: String, + pub client_secret: String, + pub connection: String, + pub client_url: String, +} + +impl Auth0Service { + pub fn new( + client_id: String, + client_secret: String, + connection: String, + client_url: String, + ) -> Self { + Auth0Service { + client_id, + client_secret, + connection, + client_url, + } + } + + pub fn generate_body_for_registration( + &self, + user_id: Uuid, + username: String, + password: String, + email: String, + ) -> ConnectToAuth0 { + ConnectToAuth0 { + client_id: self.client_id.clone(), + client_secret: self.client_secret.clone(), + audience: AUDIENCE.to_string(), + grant_type: GRANT_TYPE_PASS.to_string(), + user_id: user_id.to_string(), + connection: self.connection.clone(), + extra: RegistrationFlow { + username, + password, + email, + }, + } + } + + pub async fn generate_body_for_login( + &self, + user_id: Uuid, + username: String, + password: String, + ) -> ConnectToAuth0 { + ConnectToAuth0 { + client_id: self.client_id.clone(), + client_secret: self.client_secret.clone(), + audience: AUDIENCE.to_string(), + grant_type: GRANT_TYPE_PASS.to_string(), + user_id: user_id.to_string(), + connection: self.connection.clone(), + extra: LoginFlow { username, password }, + } + } + + pub async fn generate_body_for_change_password( + &self, + user_id: Uuid, + email: String, + ) -> ConnectToAuth0 { + ConnectToAuth0 { + client_id: self.client_id.clone(), + client_secret: self.client_secret.clone(), + audience: AUDIENCE.to_string(), + grant_type: GRANT_TYPE_PASS.to_string(), + user_id: user_id.to_string(), + connection: self.connection.clone(), + extra: ChangePassFlow { email }, + } + } +} diff --git a/src/services/mod.rs b/src/services/mod.rs new file mode 100644 index 0000000..0c86f1c --- /dev/null +++ b/src/services/mod.rs @@ -0,0 +1 @@ +pub mod auth0; diff --git a/src/user_flow/account_flow_methods.rs b/src/user_flow/account_flow_methods.rs new file mode 100644 index 0000000..e7aec88 --- /dev/null +++ b/src/user_flow/account_flow_methods.rs @@ -0,0 +1,31 @@ +use crate::consts::{APPLICATION_JSON, CONTENT_TYPE}; +use crate::errors::Result; +use crate::services::auth0::Auth0Service; +use crate::user_flow::consts::CHANGE_PASSWORD_URL; +use actix_web::web::Data; +use http::Method; +use reqwest::Client; +use uuid::Uuid; + +pub async fn send_request_to_change_pass( + user_id: Uuid, + email: String, + auth0_service: Data, +) -> Result<()> { + let client = Client::new(); + + let url = format!("{}{}", auth0_service.client_url, CHANGE_PASSWORD_URL); + + let body = auth0_service + .generate_body_for_change_password(user_id, email) + .await; + + client + .request(Method::POST, &url) + .header(CONTENT_TYPE, APPLICATION_JSON) + .json(&body) + .send() + .await?; + + Ok(()) +} diff --git a/src/user_flow/auth0.rs b/src/user_flow/auth0.rs index b2c7568..b55b66a 100644 --- a/src/user_flow/auth0.rs +++ b/src/user_flow/auth0.rs @@ -1,19 +1,29 @@ -use crate::consts::{ACCESS_TOKEN, APPLICATION_JSON, AUDIENCE, CONTENT_TYPE, GRANT_TYPE_PASS}; +use crate::consts::{ACCESS_TOKEN, APPLICATION_JSON, CONTENT_TYPE}; use crate::errors::Error; -use crate::models::{ConnectToAuth0, LoginFlow, RegisteredUserData, RegistrationFlow, UserData}; +use crate::models::{RegisteredUserData, UserData}; +use crate::services::auth0::Auth0Service; use crate::user_flow::consts::{LOGIN_URL, REGISTRATION_URL}; +use actix_web::web::Data; use http::Method; use reqwest::Client; use serde_json::Value; use uuid::Uuid; -pub async fn register_user(user: UserData, user_id: Uuid) -> crate::errors::Result<()> { +pub async fn register_user( + user: UserData, + user_id: Uuid, + auth0_service: Data, +) -> crate::errors::Result<()> { let client = Client::new(); - let client_url = dotenv::var("CLIENT").unwrap_or_else(|_| "localhost:8080".to_string()); - let url = format!("{}{}", client_url, REGISTRATION_URL); + let url = format!("{}{}", auth0_service.client_url, REGISTRATION_URL); - let body = generate_body_for_registration(user_id, user.username, user.password, user.email); + let body = auth0_service.generate_body_for_registration( + user_id, + user.username, + user.password, + user.email, + ); client .request(Method::POST, &url) @@ -24,13 +34,17 @@ pub async fn register_user(user: UserData, user_id: Uuid) -> crate::errors::Resu Ok(()) } -pub async fn get_jwt_user_token(user: RegisteredUserData) -> crate::errors::Result { +pub async fn get_jwt_user_token( + user: RegisteredUserData, + auth0_service: Data, +) -> crate::errors::Result { let client = Client::new(); - let client_url = dotenv::var("CLIENT").unwrap_or_else(|_| "localhost:8080".to_string()); - let url = format!("{}{}", client_url, LOGIN_URL); + let url = format!("{}{}", auth0_service.client_url, LOGIN_URL); - let body = generate_body_for_login(user.id, user.username, user.password).await; + let body = auth0_service + .generate_body_for_login(user.id, user.username, user.password) + .await; let response = client .request(Method::POST, &url) @@ -51,50 +65,3 @@ pub async fn get_jwt_user_token(user: RegisteredUserData) -> crate::errors::Resu } } } - -fn generate_body_for_registration( - user_id: Uuid, - username: String, - password: String, - email: String, -) -> ConnectToAuth0 { - let client_id = dotenv::var("CLIENT_ID").unwrap_or_else(|_| "admin".to_string()); - let client_secret = dotenv::var("CLIENT_SECRET").unwrap_or_else(|_| "admin".to_string()); - let connection = dotenv::var("CONNECTION") - .unwrap_or_else(|_| "Username-Password-Authentication".to_string()); - - ConnectToAuth0 { - client_id, - client_secret, - audience: AUDIENCE.to_string(), - grant_type: GRANT_TYPE_PASS.to_string(), - user_id: user_id.to_string(), - connection, - extra: RegistrationFlow { - username, - password, - email, - }, - } -} - -pub async fn generate_body_for_login( - user_id: Uuid, - username: String, - password: String, -) -> ConnectToAuth0 { - let client_id = dotenv::var("CLIENT_ID").unwrap_or_else(|_| "admin".to_string()); - let client_secret = dotenv::var("CLIENT_SECRET").unwrap_or_else(|_| "admin".to_string()); - let connection = dotenv::var("CONNECTION") - .unwrap_or_else(|_| "Username-Password-Authentication".to_string()); - - ConnectToAuth0 { - client_id, - client_secret, - audience: AUDIENCE.to_string(), - grant_type: GRANT_TYPE_PASS.to_string(), - user_id: user_id.to_string(), - connection, - extra: LoginFlow { username, password }, - } -} diff --git a/src/user_flow/auth0_models.rs b/src/user_flow/auth0_models.rs new file mode 100644 index 0000000..83a5cc8 --- /dev/null +++ b/src/user_flow/auth0_models.rs @@ -0,0 +1,31 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ConnectToAuth0 { + pub client_id: String, + pub client_secret: String, + pub audience: String, + pub grant_type: String, + pub user_id: String, + pub connection: String, + #[serde(flatten)] + pub extra: T, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct RegistrationFlow { + pub username: String, + pub password: String, + pub email: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct LoginFlow { + pub username: String, + pub password: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ChangePassFlow { + pub email: String, +} diff --git a/src/user_flow/consts.rs b/src/user_flow/consts.rs index b1796ff..0924c65 100644 --- a/src/user_flow/consts.rs +++ b/src/user_flow/consts.rs @@ -1,2 +1,3 @@ pub const REGISTRATION_URL: &str = "dbconnections/signup"; pub const LOGIN_URL: &str = "oauth/token"; +pub const CHANGE_PASSWORD_URL: &str = "dbconnections/change_password"; diff --git a/src/user_flow/mod.rs b/src/user_flow/mod.rs index af8d8dc..5f131e6 100644 --- a/src/user_flow/mod.rs +++ b/src/user_flow/mod.rs @@ -1,5 +1,6 @@ +pub mod account_flow_methods; pub mod auth0; +pub mod auth0_models; pub mod consts; mod models; pub mod requests; -pub mod utils; diff --git a/src/user_flow/requests.rs b/src/user_flow/requests.rs index 4f633fd..98219c7 100644 --- a/src/user_flow/requests.rs +++ b/src/user_flow/requests.rs @@ -1,12 +1,12 @@ use crate::actors::messages::{CheckIfRegisteredUser, CheckUser, CreateUser}; use crate::db::postgres_db::DbService; -use crate::models::{RegisteredUserData, UserData}; +use crate::models::{RegisteredUserData, UpdatePasswordData, UserData}; +use crate::services::auth0::Auth0Service; +use crate::user_flow::account_flow_methods::send_request_to_change_pass; use crate::user_flow::auth0::{get_jwt_user_token, register_user}; -use crate::user_flow::utils::fetch_jwks; use actix::Addr; use actix_web::web::{Data, Json}; -use actix_web::{HttpRequest, HttpResponse}; -use alcoholic_jwt::{token_kid, validate, Validation}; +use actix_web::HttpResponse; use uuid::Uuid; #[utoipa::path( @@ -19,10 +19,11 @@ use uuid::Uuid; )] pub async fn register( user: Json, + auth0_service: Data, db: Data>, ) -> crate::errors::Result { let user_id = Uuid::new_v4(); - register_user(user.clone(), user_id).await?; + register_user(user.clone(), user_id, auth0_service).await?; let if_user = CheckIfRegisteredUser { username: user.username.clone(), @@ -55,14 +56,15 @@ pub async fn register( ) )] pub async fn login( - db: Data>, user: Json, + auth0_service: Data, + db: Data>, ) -> crate::errors::Result { let if_user = CheckUser { id: user.id }; if db.send(if_user).await?? { log::info!("Getting request for login!"); - let token = get_jwt_user_token(user.0.clone()).await?; + let token = get_jwt_user_token(user.0.clone(), auth0_service).await?; let json = serde_json::json!({ "user": user, "token": token }); Ok(HttpResponse::Ok().body(json.to_string())) } else { @@ -72,30 +74,26 @@ pub async fn login( #[utoipa::path( post, - path = "/check_token", + path = "/change_password", responses( - (status = 200, description = "This is a right token"), - (status = BAD_REQUEST, description = "Not correct token") + (status = 200, description = "Successfully send email to change password"), + (status = BAD_REQUEST, description = "User not found") ) )] -pub async fn check_token(req: HttpRequest) -> crate::errors::Result { - log::info!("Getting request for checking token!"); - let token = req - .headers() - .get("Authorization") - .expect("Cannot find Auth header") - .to_str()?; - let authority = std::env::var("CLIENT").expect("AUTHORITY must be set"); - let uri = &format!("{}{}", authority.as_str(), ".well-known/jwks.json"); - log::info!("Fetching JWKS from: {}", uri); - let jwks = fetch_jwks(uri).await?; - let validations = vec![Validation::Issuer(authority), Validation::SubjectPresent]; - let kid = match token_kid(token) { - Ok(res) => res.expect("failed to decode kid"), - Err(e) => return Err(crate::errors::Error::AlcoholicJwtValidationError(e)), - }; - let jwk = jwks.find(&kid).expect("Specified key not found in set"); - let res = validate(token, jwk, validations)?; - log::info!("Token: {:?}", res.claims); - Ok(HttpResponse::Ok().finish()) +pub async fn change_password( + db: Data>, + user: Json, + auth0_service: Data, +) -> crate::errors::Result { + let if_user = CheckUser { id: user.user_id }; + + if db.send(if_user).await?? { + log::info!("Getting request for change password!"); + + send_request_to_change_pass(user.user_id, user.email.clone(), auth0_service).await?; + + Ok(HttpResponse::Ok().body("Sent email to change password!")) + } else { + Ok(HttpResponse::BadRequest().finish()) + } } diff --git a/src/user_flow/utils.rs b/src/user_flow/utils.rs deleted file mode 100644 index 475265a..0000000 --- a/src/user_flow/utils.rs +++ /dev/null @@ -1,17 +0,0 @@ -use crate::errors::Result; -use alcoholic_jwt::JWKS; -use std::fs::File; -use std::io::Read; - -pub fn load_pem_cert(file_path: &str) -> Result> { - let mut file = File::open(file_path)?; - let mut pem_cert = Vec::new(); - file.read_to_end(&mut pem_cert)?; - Ok(pem_cert) -} - -pub async fn fetch_jwks(uri: &str) -> Result { - let res = reqwest::get(uri).await?; - let val = res.json::().await?; - Ok(val) -} diff --git a/src/utils.rs b/src/utils.rs index b0fc224..711ed81 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,8 +1,18 @@ +use crate::db::postgres_db::DbService; +use crate::middleware::auth::AuthMiddleware; +use crate::services::auth0::Auth0Service; +use crate::user_flow::requests::{change_password, login, register}; +use crate::ApiDoc; +use actix::Addr; +use actix_web::web; +use actix_web::web::{Data, ServiceConfig}; use colored::Colorize; use log::{Level, LevelFilter}; use std::collections::HashMap; use std::str::FromStr; use std::thread::ThreadId; +use utoipa::OpenApi; +use utoipa_swagger_ui::SwaggerUi; pub fn init_logging() -> crate::errors::Result<()> { // Logging lib errors and all app logs @@ -61,3 +71,28 @@ fn parse_thread_id(id: &ThreadId) -> String { parsed.unwrap_or(id_str) } + +pub fn configure_routes(cfg: &mut web::ServiceConfig) { + let openapi = ApiDoc::openapi(); + + cfg.service( + web::scope("") + .service(web::resource("/login").route(web::post().to(login))) + .service(web::resource("/register").route(web::post().to(register))) + .service(SwaggerUi::new("/swagger-ui/{_:.*}").url("/api-docs/openapi.json", openapi)), + ) + .service( + web::scope("/user") + .wrap(AuthMiddleware) + .service(web::resource("/change_password").route(web::post().to(change_password))), + ); +} +pub fn configure_data( + db: Addr, + auth0_service: Auth0Service, +) -> Box { + Box::new(move |cfg: &mut ServiceConfig| { + cfg.app_data(Data::new(db)) + .app_data(Data::new(auth0_service)); + }) +}