111 lines
3.7 KiB
Rust
Executable File
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());
|
|
}
|
|
}
|