Files
rss-reader/src/views/auth/login.rs
T
2026-06-12 19:22:07 +02:00

111 lines
3.7 KiB
Rust
Executable File

use crate::database::establish_connection;
use crate::diesel;
use crate::error::AppError;
use crate::json_serialization::login::Login;
use crate::models::user::rss_user::User;
use crate::schema::users;
use crate::{auth::jwt::JwtToken, schema::users::username};
use actix_web::{web, HttpResponse};
use diesel::prelude::*;
pub async fn login(credentials: web::Json<Login>) -> Result<HttpResponse, AppError> {
let username_cred: String = credentials.username.clone();
let password: String = credentials.password.clone();
let mut connection = establish_connection();
let users: Vec<User> = users::table
.filter(username.eq(username_cred.as_str()))
.load::<User>(&mut connection)?;
if users.is_empty() {
return Ok(HttpResponse::NotFound().finish());
} else if users.len() > 1 {
log::error!(
"multiple user have the usernam: {}",
credentials.username.clone()
);
return Ok(HttpResponse::Conflict().finish());
}
let user: &User = &users[0];
match user.clone().verify(password)? {
true => {
log::info!("verified password successfully for user {}", user.id);
let token: String = JwtToken::encode(user.id, user.token_version);
Ok(HttpResponse::Ok()
.insert_header(("token", token))
.insert_header(("user_id", user.id))
.finish())
}
false => Ok(HttpResponse::Unauthorized().finish()),
}
}
#[cfg(test)]
mod tests {
use actix_web::http::StatusCode;
use actix_web::{test, web, App};
use super::login;
use crate::database::establish_connection;
use crate::test_helpers::{delete_user, insert_user, unique_suffix};
#[actix_web::test]
async fn login_succeeds_with_correct_credentials() {
let mut connection = establish_connection();
let user = insert_user(&mut connection, "correct-password");
let app = test::init_service(App::new().route("/login", web::post().to(login))).await;
let req = test::TestRequest::post()
.uri("/login")
.set_json(serde_json::json!({
"username": user.username,
"password": "correct-password"
}))
.to_request();
let resp = test::call_service(&app, req).await;
assert_eq!(StatusCode::OK, resp.status());
assert!(resp.headers().contains_key("token"));
delete_user(&mut connection, user.id);
}
#[actix_web::test]
async fn login_fails_with_wrong_password() {
let mut connection = establish_connection();
let user = insert_user(&mut connection, "correct-password");
let app = test::init_service(App::new().route("/login", web::post().to(login))).await;
let req = test::TestRequest::post()
.uri("/login")
.set_json(serde_json::json!({
"username": user.username,
"password": "wrong-password"
}))
.to_request();
let resp = test::call_service(&app, req).await;
assert_eq!(StatusCode::UNAUTHORIZED, resp.status());
delete_user(&mut connection, user.id);
}
#[actix_web::test]
async fn login_fails_for_unknown_user() {
let app = test::init_service(App::new().route("/login", web::post().to(login))).await;
let req = test::TestRequest::post()
.uri("/login")
.set_json(serde_json::json!({
"username": format!("does-not-exist-{}", unique_suffix()),
"password": "whatever"
}))
.to_request();
let resp = test::call_service(&app, req).await;
assert_eq!(StatusCode::NOT_FOUND, resp.status());
}
}