104 lines
3.0 KiB
Rust
104 lines
3.0 KiB
Rust
use actix_web::web::{self, HttpResponse, Json};
|
|
use actix_web::{post, Responder};
|
|
use chrono::{Duration, Utc};
|
|
use jsonwebtoken::{encode, EncodingKey, Header};
|
|
use log::{debug, error};
|
|
|
|
use crate::{
|
|
data::{secret_key, Claims, CreateAccountRequest, LoginRequest, Token},
|
|
database::UserDao,
|
|
};
|
|
|
|
#[post("/register")]
|
|
async fn register(
|
|
user: Json<CreateAccountRequest>,
|
|
user_dao: web::Data<Box<dyn UserDao>>,
|
|
) -> impl Responder {
|
|
if !user.username.is_empty() && user.password.len() > 5 && user.password == user.confirmation {
|
|
if user_dao.user_exists(&user.username) {
|
|
HttpResponse::BadRequest()
|
|
} else if let Some(_user) = user_dao.create_user(&user.username, &user.password) {
|
|
HttpResponse::Ok()
|
|
} else {
|
|
HttpResponse::InternalServerError()
|
|
}
|
|
} else {
|
|
HttpResponse::BadRequest()
|
|
}
|
|
}
|
|
|
|
pub async fn login(
|
|
creds: Json<LoginRequest>,
|
|
user_dao: web::Data<Box<dyn UserDao>>,
|
|
) -> HttpResponse {
|
|
debug!("Logging in: {}", creds.username);
|
|
if let Some(user) = user_dao.get_user(&creds.username, &creds.password) {
|
|
let claims = Claims {
|
|
sub: user.id.to_string(),
|
|
exp: (Utc::now() + Duration::days(5)).timestamp(),
|
|
};
|
|
let token = encode(
|
|
&Header::default(),
|
|
&claims,
|
|
&EncodingKey::from_secret(secret_key().as_bytes()),
|
|
)
|
|
.unwrap();
|
|
HttpResponse::Ok().json(Token { token: &token })
|
|
} else {
|
|
error!("User not found during login: '{}'", creds.username);
|
|
HttpResponse::NotFound().finish()
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use crate::database::testhelpers::{BodyReader, TestUserDao};
|
|
|
|
#[actix_rt::test]
|
|
async fn test_login_reports_200_when_user_exists() {
|
|
let dao = TestUserDao::new();
|
|
dao.create_user("user", "pass");
|
|
|
|
let j = Json(LoginRequest {
|
|
username: "user".to_string(),
|
|
password: "pass".to_string(),
|
|
});
|
|
|
|
let response = login(j, web::Data::new(Box::new(dao))).await;
|
|
|
|
assert_eq!(response.status(), 200);
|
|
}
|
|
|
|
#[actix_rt::test]
|
|
async fn test_login_returns_token_on_success() {
|
|
let dao = TestUserDao::new();
|
|
dao.create_user("user", "password");
|
|
|
|
let j = Json(LoginRequest {
|
|
username: "user".to_string(),
|
|
password: "password".to_string(),
|
|
});
|
|
|
|
let response = login(j, web::Data::new(Box::new(dao))).await;
|
|
|
|
assert_eq!(response.status(), 200);
|
|
assert!(response.body().read_to_str().contains("\"token\""));
|
|
}
|
|
|
|
#[actix_rt::test]
|
|
async fn test_login_reports_400_when_user_does_not_exist() {
|
|
let dao = TestUserDao::new();
|
|
dao.create_user("user", "password");
|
|
|
|
let j = Json(LoginRequest {
|
|
username: "doesnotexist".to_string(),
|
|
password: "password".to_string(),
|
|
});
|
|
|
|
let response = login(j, web::Data::new(Box::new(dao))).await;
|
|
|
|
assert_eq!(response.status(), 404);
|
|
}
|
|
}
|