1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
use actix_web::{post, web, HttpResponse, Responder};
use de_lobby_model::{Token, UserWithPassword, UsernameAndPassword};
use log::{error, info, warn};

use super::{
    db::{RegistrationError, Users},
    token::{Claims, Tokens},
};

/// Registers all authentication endpoints.
pub(super) fn configure(cfg: &mut web::ServiceConfig) {
    cfg.service(web::scope("/auth").service(sign_up).service(sign_in));
}

#[post("/sign-up")]
async fn sign_up(
    tokens: web::Data<Tokens>,
    users: web::Data<Users>,
    user: web::Json<UserWithPassword>,
) -> impl Responder {
    if let Err(error) = user.validate() {
        warn!("Invalid sing-up request: {}", error);
        return HttpResponse::BadRequest().json(error.to_string());
    }

    match users.register(&user.0).await {
        Ok(_) => {
            let token = match tokens.encode(&Claims::standard(user.0.user().username())) {
                Ok(token) => token,
                Err(error) => {
                    error!("Token encoding error: {:?}", error);
                    return HttpResponse::InternalServerError().finish();
                }
            };
            info!(
                "Registration of user {} was successful.",
                user.user().username()
            );
            HttpResponse::Ok().json(Token::new(token))
        }
        Err(RegistrationError::UsernameTaken) => {
            warn!("Username {} is already taken.", user.user().username());
            HttpResponse::Conflict().json("The username is already taken.")
        }
        Err(error) => {
            error!("Registration error: {:?}", error);
            HttpResponse::InternalServerError().finish()
        }
    }
}

#[post("/sign-in")]
async fn sign_in(
    tokens: web::Data<Tokens>,
    users: web::Data<Users>,
    user: web::Json<UsernameAndPassword>,
) -> impl Responder {
    match users.login(&user.0).await {
        Ok(false) => {
            warn!("Signing in of user {} was unsuccessful.", user.username());
            HttpResponse::Unauthorized().finish()
        }
        Ok(true) => {
            let token = match tokens.encode(&Claims::standard(user.0.username())) {
                Ok(token) => token,
                Err(error) => {
                    error!("Token encoding error: {:?}", error);
                    return HttpResponse::InternalServerError().finish();
                }
            };
            info!("Signing in of user {} was successful.", user.username());
            HttpResponse::Ok().json(Token::new(token))
        }
        Err(error) => {
            error!("Sign-in error: {:?}", error);
            HttpResponse::InternalServerError().finish()
        }
    }
}