dialtone_axum 0.1.0

Dialtone Axum Back-end
Documentation
use axum::extract::Extension;
use axum::http::HeaderMap;
use axum::Json;
use chrono::Utc;
use jsonwebtoken::{encode, Header};
use sqlx::{Pool, Postgres};

use dialtone_common::rest::users::user_login::{AuthBody, UserCredential};
use dialtone_sqlx::control::user::authn::authn_user;

use crate::forwarded_for::get_forwarded;
use crate::response::response_error::ResponseError;
use crate::start_server::{Claims, KEYS};

pub async fn post_authenticate_handler(
    Json(login): Json<UserCredential>,
    headers: HeaderMap,
    Extension(pool): Extension<Pool<Postgres>>,
) -> Result<Json<AuthBody>, ResponseError> {
    // Check if the users sent the credentials
    if login.user_acct.is_empty() || login.password.is_empty() {
        return Err(ResponseError::MissingCredentials(None));
    }

    let forwarded_for = get_forwarded(&headers);
    tracing::debug!("forwarded_for = {:?}", forwarded_for);
    let auth_result = authn_user(
        &pool,
        &login.user_acct,
        &login.password,
        &forwarded_for,
        Utc::now(),
    )
    .await?;
    if !auth_result {
        return Err(ResponseError::WrongCredentials(Some(format!(
            "user {} failed to authenticate",
            login.user_acct
        ))));
    }

    let claims = Claims {
        sub: login.user_acct.to_owned(),
        // TODO make this configurable at some point
        exp: 2019331688,
    };
    // Create the authorization token
    let token = encode(&Header::default(), &claims, &KEYS.encoding).map_err(|err| {
        ResponseError::TokenCreation(Some(format!(
            "encode in post_authenticate_handler: {:?}",
            err
        )))
    })?;
    tracing::info!("user {} authenticated", login.user_acct);

    // Send the authorized token
    Ok(Json(AuthBody::new(token)))
}