use backend::rocket_builder; use backend::repo::mock::{MockUserRepo, MockTokenRepo}; use backend::repo::message_repo::MessageRepository; use backend::svc::chat_svc::ChatService; use backend::repo::user_repo::UserRepository; use backend::repo::{Repo, AccessTokenRepoTrait}; use rocket::local::asynchronous::Client; use rocket::http::{Status, ContentType}; use serde_json::json; use std::sync::{Arc, Mutex}; use sqlx::PgPool; use chrono::Utc; use backend::svc::llm_service::LlmService; async fn test_rocket() -> rocket::Rocket { let users = Arc::new(MockUserRepo { users: Mutex::new(vec![]) }); let tokens = Arc::new(MockTokenRepo { tokens: Mutex::new(vec![]) }); let pool = PgPool::connect_lazy("postgres://localhost/unused").unwrap(); let messages = MessageRepository::new(pool.clone()); let user_repo = Arc::new(UserRepository::new(pool)); let llm_service = LlmService::new(); let chat_service = ChatService::new(32, messages, user_repo, llm_service); rocket_builder(users, tokens, chat_service) } #[rocket::async_test] async fn test_unauthorized_access() { let client = Client::tracked(test_rocket().await).await.expect("valid rocket instance"); // Attempt to access a protected endpoint without authentication let response = client.patch("/api/settings/display_name").dispatch().await; assert_eq!(response.status(), Status::Unauthorized); let response = client.post("/api/settings/password").dispatch().await; assert_eq!(response.status(), Status::Unauthorized); let response = client.delete("/api/settings").dispatch().await; assert_eq!(response.status(), Status::Unauthorized); } #[rocket::async_test] async fn test_signup_invalid_token() { let client = Client::tracked(test_rocket().await).await.expect("valid rocket instance"); let signup_data = json!({ "email": "test@example.com", "username": "testuser", "password": "password123", "access_token": "invalid-token" }); let response = client.post("/api/signup") .header(ContentType::JSON) .body(signup_data.to_string()) .dispatch() .await; assert_eq!(response.status(), Status::Unauthorized); } #[rocket::async_test] async fn test_login_invalid_credentials() { let client = Client::tracked(test_rocket().await).await.expect("valid rocket instance"); let login_data = json!({ "username": "nonexistent", "password": "wrongpassword" }); let response = client.post("/api/login") .header(ContentType::JSON) .body(login_data.to_string()) .dispatch() .await; assert_eq!(response.status(), Status::Unauthorized); } #[rocket::async_test] async fn test_full_auth_flow() { let users = Arc::new(MockUserRepo { users: Mutex::new(vec![]) }); let tokens = Arc::new(MockTokenRepo { tokens: Mutex::new(vec![]) }); let pool = PgPool::connect_lazy("postgres://localhost/unused").unwrap(); let messages = MessageRepository::new(pool.clone()); let user_repo = Arc::new(UserRepository::new(pool)); let llm_service = LlmService::new(); let chat_service = ChatService::new(32, messages, user_repo, llm_service); let token_code = "valid-token"; tokens.create_new(1, "test", token_code, 1, Utc::now(), Utc::now()).await.unwrap(); let client = Client::tracked(rocket_builder(users, tokens, chat_service)).await.expect("valid rocket instance"); // 1. Signup let signup_data = json!({ "email": "test@example.com", "username": "testuser", "password": "password123", "access_token": token_code }); let response = client.post("/api/signup") .header(ContentType::JSON) .body(signup_data.to_string()) .dispatch() .await; assert_eq!(response.status(), Status::Ok); let body = response.into_string().await.unwrap(); assert!(body.contains("token")); // 2. Login let login_data = json!({ "username": "testuser", "password": "password123" }); let response = client.post("/api/login") .header(ContentType::JSON) .body(login_data.to_string()) .dispatch() .await; assert_eq!(response.status(), Status::Ok); let body = response.into_string().await.unwrap(); assert!(body.contains("token")); } #[rocket::async_test] async fn test_delete_account_security() { let users = Arc::new(MockUserRepo { users: Mutex::new(vec![]) }); let tokens = Arc::new(MockTokenRepo { tokens: Mutex::new(vec![]) }); let pool = PgPool::connect_lazy("postgres://localhost/unused").unwrap(); let messages = MessageRepository::new(pool.clone()); let user_repo = Arc::new(UserRepository::new(pool)); let llm_service = LlmService::new(); let chat_service = ChatService::new(32, messages, user_repo, llm_service); let client = Client::tracked(rocket_builder(users.clone(), tokens.clone(), chat_service)).await.expect("valid rocket instance"); let token_code = "valid-token"; tokens.create_new(1, "test", token_code, 1, Utc::now(), Utc::now()).await.unwrap(); client.post("/api/signup") .header(ContentType::JSON) .body(json!({ "email": "test@example.com", "username": "testuser", "password": "password123", "access_token": token_code }).to_string()) .dispatch() .await; // Login to get JWT let login_res = client.post("/api/login") .header(ContentType::JSON) .body(json!({ "username": "testuser", "password": "password123" }).to_string()) .dispatch() .await; let auth_resp: serde_json::Value = serde_json::from_str(&login_res.into_string().await.unwrap()).unwrap(); let jwt = auth_resp["token"].as_str().unwrap(); // 1. Delete with WRONG password let response = client.delete("/api/settings") .header(ContentType::JSON) .header(rocket::http::Header::new("Authorization", format!("Bearer {}", jwt))) .body(json!({ "password": "wrongpassword", "totp_code": null }).to_string()) .dispatch() .await; assert_eq!(response.status(), Status::Unauthorized); // 2. Delete with CORRECT password let response = client.delete("/api/settings") .header(ContentType::JSON) .header(rocket::http::Header::new("Authorization", format!("Bearer {}", jwt))) .body(json!({ "password": "password123", "totp_code": null }).to_string()) .dispatch() .await; assert_eq!(response.status(), Status::Ok); // Verify user is gone assert!(users.users.lock().unwrap().is_empty()); }