enigmatick 0.4.1

Enigmatick is a social media platform that integrates with servers that implement the ActivityPub protocol (e.g., Mastodon)
Documentation
use crate::{
    admin,
    models::{
        actors::{update_password_by_username, Actor},
        profiles::Profile,
    },
    server::{extractors::AxumSigned, AppState},
};
use axum::{
    extract::{rejection::JsonRejection, Path, State},
    http::StatusCode,
    response::Json,
};
use serde::Deserialize;

use super::ActivityJson;

#[derive(Deserialize, Debug, Clone)]
pub struct AuthenticationData {
    pub username: String,
    pub password: String,
}

#[derive(Deserialize, Debug, Clone)]
pub struct UpdatePassword {
    pub current: String,
    pub updated: String,
    pub encrypted_client_private_key: String,
    pub encrypted_olm_pickled_account: String,
    pub olm_pickled_account_hash: String,
}

pub async fn authenticate_user(
    State(state): State<AppState>,
    user: Result<Json<AuthenticationData>, JsonRejection>,
) -> Result<ActivityJson<Profile>, StatusCode> {
    log::debug!("AXUM AUTHENTICATING");

    let user = match user {
        Ok(json) => json.0,
        Err(e) => {
            log::error!("FAILED TO DECODE user: {e:#?}");
            return Err(StatusCode::UNAUTHORIZED);
        }
    };

    let conn = match state.db_pool.get().await {
        Ok(conn) => conn,
        Err(e) => {
            log::error!("Failed to get DB connection: {e}");
            return Err(StatusCode::INTERNAL_SERVER_ERROR);
        }
    };

    match admin::authenticate(&conn, user.username.clone(), user.password.clone()).await {
        Some(profile) => Ok(ActivityJson(profile)),
        None => Err(StatusCode::UNAUTHORIZED),
    }
}

pub async fn change_password(
    signed: AxumSigned,
    State(state): State<AppState>,
    Path(username): Path<String>,
    password: Result<Json<UpdatePassword>, JsonRejection>,
) -> Result<ActivityJson<Actor>, StatusCode> {
    if signed.local() {
        let password = match password {
            Ok(json) => json.0,
            Err(e) => {
                log::error!("FAILED TO DECODE password: {e:#?}");
                return Err(StatusCode::UNAUTHORIZED);
            }
        };

        let conn = match state.db_pool.get().await {
            Ok(conn) => conn,
            Err(e) => {
                log::error!("Failed to get DB connection: {e}");
                return Err(StatusCode::INTERNAL_SERVER_ERROR);
            }
        };

        let password_hash = match admin::verify_and_generate_password(
            &conn,
            username.clone(),
            password.current.clone(),
            password.updated.clone(),
        )
        .await
        {
            Some(hash) => hash,
            None => return Err(StatusCode::UNAUTHORIZED),
        };

        let client_private_key = password.encrypted_client_private_key.clone();
        let olm_pickled_account = password.encrypted_olm_pickled_account.clone();
        let olm_pickled_account_hash = password.olm_pickled_account_hash.clone();

        let updated_actor = update_password_by_username(
            &conn,
            username,
            password_hash,
            client_private_key,
            olm_pickled_account,
            olm_pickled_account_hash,
        )
        .await
        .unwrap_or_default();

        Ok(ActivityJson(updated_actor))
    } else {
        Err(StatusCode::UNAUTHORIZED)
    }
}