From d3965efd28e0cfcb882ed10126c20d2eca395cba Mon Sep 17 00:00:00 2001 From: Benjamin Sherriff Date: Wed, 18 Oct 2023 08:52:59 -0400 Subject: [PATCH] Temp updated --- service/Cargo.toml | 1 + service/src/db/users/model.rs | 54 +++++++++++++++++++++--------- service/src/db/users/routes.rs | 49 +++++++++++++-------------- service/src/main.rs | 9 ++--- ui/src/api/users.ts | 6 +++- ui/src/components/Topbar/index.tsx | 3 +- 6 files changed, 72 insertions(+), 50 deletions(-) diff --git a/service/Cargo.toml b/service/Cargo.toml index 0c0e6d3..bc5f973 100644 --- a/service/Cargo.toml +++ b/service/Cargo.toml @@ -28,6 +28,7 @@ r2d2 = "0.8.10" lazy_static = "1.4.0" uuid = { version = "1.4.1", features = ["serde", "v4"] } argon2 = "0.5.2" +jsonwebtoken = "9.0.0" [dependencies.tokio] version = "1.32.0" diff --git a/service/src/db/users/model.rs b/service/src/db/users/model.rs index 4159f48..72cb786 100644 --- a/service/src/db/users/model.rs +++ b/service/src/db/users/model.rs @@ -1,6 +1,6 @@ -use std::future::{ready, Ready}; +use std::{future::{ready, Ready, Future}, pin::Pin}; use actix_identity::Identity; -use actix_web::{FromRequest, Error as ActixError, HttpRequest, dev::Payload}; +use actix_web::{FromRequest, Error as ActixError, HttpRequest, dev::Payload, error::{ErrorUnauthorized, ErrorInternalServerError}}; use argon2::{password_hash::{rand_core::OsRng, PasswordHasher, PasswordVerifier, SaltString, Error as HashError}, Argon2, PasswordHash}; use diesel::prelude::*; use serde::{Serialize, Deserialize}; @@ -42,25 +42,47 @@ pub struct LoggedUser { impl FromRequest for LoggedUser { type Error = ActixError; - type Future = Ready>; + // type Future = Ready>; + // type Future = std::pin::Pin>>>; + type Future = Pin>>>; fn from_request(req: &HttpRequest, pl: &mut Payload) -> Self::Future { - if let Ok(identity) = Identity::from_request(req, pl).into_inner() { - if let Ok(user_json) = identity.id() { - if let Ok(user) = serde_json::from_str(&user_json) { - return ready(Ok(user)); - } - } - } - std::future::ready(Err( - ActixError::from(ServiceError { - status: 401, - message: "Unauthorized".to_string(), - }) - )) + // if let Ok(identity) = Identity::from_request(req, pl).into_inner() { + // if let Ok(user_json) = identity.id() { + // if let Ok(user) = serde_json::from_str(&user_json) { + // return ready(Ok(user)); + // } + // } + // } + // std::future::ready(Err( + // ActixError::from(ServiceError { + // status: 401, + // message: "Unauthorized".to_string(), + // }) + // )) + let identity = Identity::extract(req).into_inner(); + Box::pin(async move { + process_req_auth_data(identity).await + }) } } +async fn process_req_auth_data(identity: Result) -> Result { + let id = identity + .map_err(|_| ErrorUnauthorized("You are not logged in; 1"))? + .id() + .map_err(|_| ErrorUnauthorized("You are not logged in; 3"))?; + let logged_user = match serde_json::from_str::(&id) { + Ok(user) => user, + Err(err) => return Err(ErrorInternalServerError(err)) + }; + + let user = QueryUser::get_by_email(&logged_user.email) + .map_err(|_| ErrorUnauthorized("You are not logged in; 3"))?; + + Ok(LoggedUser { email: user.email }) +} + #[derive(Debug, Queryable, QueryableByName, Serialize, Deserialize)] #[diesel(table_name = users)] pub struct QueryUser { diff --git a/service/src/db/users/routes.rs b/service/src/db/users/routes.rs index 6937d3e..a3bcdb9 100644 --- a/service/src/db/users/routes.rs +++ b/service/src/db/users/routes.rs @@ -30,39 +30,38 @@ async fn register(user: web::Json) -> HttpResponse { async fn login(req: HttpRequest, auth: web::Json) -> HttpResponse { let email = auth.email.clone(); - match QueryUser::get_by_email(&email) { - Ok(query_user) => { - let hash = query_user.hash; - let password = auth.password.as_bytes(); - match verify(&hash, password) { - Ok(_) => { - let user = LoggedUser { - email: email.clone() - }; - let user_string = serde_json::to_string(&user).unwrap(); - match Identity::login(&req.extensions(), user_string) { - Ok(_) => HttpResponse::Ok().finish(), - Err(err) => return ResponseError::error_response(&err) - } - }, - Err(err) => ResponseError::error_response(&ServiceError { - status: 401, - message: err.to_string() - }) + let query_user = match QueryUser::get_by_email(&email) { + Ok(query_user) => query_user, + Err(err) => return ResponseError::error_response(&err) + }; + let hash = query_user.hash; + let password = auth.password.as_bytes(); + match verify(&hash, password) { + Ok(_) => { + let user = LoggedUser { + email: email.clone() + }; + let user_string = serde_json::to_string(&user).unwrap(); + match Identity::login(&req.extensions(), user_string) { + Ok(_) => HttpResponse::Ok().finish(), + Err(err) => return ResponseError::error_response(&err) } }, - Err(err) => ResponseError::error_response(&err) + Err(err) => ResponseError::error_response(&ServiceError { + status: 401, + message: err.to_string() + }) } } #[post("/logout")] -async fn logout(id: Identity) -> HttpResponse { - id.logout(); +async fn logout(identity: Identity) -> HttpResponse { + identity.logout(); HttpResponse::Ok().finish() } -#[get("/me")] -async fn me(user: LoggedUser) -> HttpResponse { +#[get("/ping")] +async fn ping(user: LoggedUser) -> HttpResponse { HttpResponse::Ok().json(user) } @@ -71,5 +70,5 @@ pub fn init_routes(config: &mut web::ServiceConfig) { .service(register) .service(login) .service(logout) - .service(me)); + .service(ping)); } \ No newline at end of file diff --git a/service/src/main.rs b/service/src/main.rs index ee08565..6bd9601 100644 --- a/service/src/main.rs +++ b/service/src/main.rs @@ -6,8 +6,7 @@ use std::env; use std::collections::HashSet; use std::sync::Arc; use actix_identity::IdentityMiddleware; -use actix_session::{SessionMiddleware, storage::{RedisActorSessionStore, CookieSessionStore}, config::{PersistentSession, BrowserSession, CookieContentSecurity}}; -// use db::users::validator; +use actix_session::{SessionMiddleware, storage::{RedisActorSessionStore, CookieSessionStore}, config::BrowserSession}; use log::{error, warn, info}; use serenity::client::Cache; use serenity::framework::StandardFramework; @@ -16,7 +15,7 @@ use serenity::prelude::*; use songbird::{SerenityInit, Songbird}; use actix_cors::Cors; -use actix_web::{HttpServer, App, web, cookie::{time::Duration, SameSite}}; +use actix_web::{HttpServer, App, web}; use crate::bot::{commands::oai::GPTModel, handler::Handler}; use dotenv::dotenv; @@ -114,7 +113,6 @@ async fn main() -> std::io::Result<()> { let port = env::var("SERVICE_PORT").unwrap_or("5000".to_string()); let server = match HttpServer::new(move || { - // let auth = HttpAuthentication::bearer(validator); let private_key = actix_web::cookie::Key::generate(); // let redis_host = env::var("REDIS_HOST").unwrap_or("localhost".to_string()); // let redis_port = env::var("REDIS_PORT").unwrap_or("6379".to_string()); @@ -127,7 +125,6 @@ async fn main() -> std::io::Result<()> { .cookie_name("auth".to_owned()) .cookie_secure(false) .cookie_http_only(false) - // .cookie_content_security(CookieContentSecurity::Private) .cookie_domain(Some("localhost".to_owned())) .cookie_path("/".to_owned()) .build(); @@ -137,9 +134,7 @@ async fn main() -> std::io::Result<()> { .allow_any_header() .supports_credentials() .max_age(3600); - // let cors = Cors::permissive(); App::new() - // .wrap(auth) .wrap(IdentityMiddleware::default()) .wrap(session) .wrap(cors) diff --git a/ui/src/api/users.ts b/ui/src/api/users.ts index b5cd5c0..eb2c6f5 100644 --- a/ui/src/api/users.ts +++ b/ui/src/api/users.ts @@ -1,4 +1,4 @@ -import { postRequest } from '.'; +import { getRequest, postRequest } from '.'; export async function login(email: string, password: string) { return await postRequest('users/login', { email, password }, { withCredentials: true }); @@ -7,3 +7,7 @@ export async function login(email: string, password: string) { export async function logout() { return await postRequest('users/logout', {}, { withCredentials: true }); } + +export async function ping() { + return await getRequest('users/ping', { withCredentials: true }); +} diff --git a/ui/src/components/Topbar/index.tsx b/ui/src/components/Topbar/index.tsx index c076f65..7ddcb3e 100644 --- a/ui/src/components/Topbar/index.tsx +++ b/ui/src/components/Topbar/index.tsx @@ -21,7 +21,7 @@ import { import Cookies from 'js-cookie'; import { useEffect, useState } from 'react'; import { useForm } from '@mantine/form'; -import { login, logout } from '@/api/users'; +import { login, logout, ping } from '@/api/users'; const headerItems = [ { @@ -107,6 +107,7 @@ export default function Topbar() { Logout )} + ping()}>Ping