summaryrefslogtreecommitdiffstats
path: root/src/auth/credentials.rs
blob: 88253b33f1ecffb44bfd7fbc3172f1d406b9b628 (plain)
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
use argon2::{
    password_hash::{rand_core::OsRng, SaltString},
    Argon2, PasswordHasher,
};
use axum::{
    extract::{Path, State},
    http::StatusCode,
    Json,
};
use axum_extra::routing::Resource;
use serde::{Deserialize, Serialize};
use uuid::Uuid;

use crate::state::AppState;

use super::{error::Error, AccessClaims, RefreshClaims};

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Credential {
    pub password: String,
}

pub fn router() -> Resource<AppState> {
    Resource::named("credentials")
        .create(create)
        .destroy(destroy)
}

pub async fn create(
    State(state): State<AppState>,
    Json(Credential { password }): Json<Credential>,
) -> Result<(StatusCode, (AccessClaims, RefreshClaims)), Error> {
    let salt = SaltString::generate(&mut OsRng);
    let password_hash = Argon2::default().hash_password(password.as_bytes(), &salt)?;

    let uuid = sqlx::query!(
        "INSERT INTO credential (password_hash) VALUES ($1) RETURNING id",
        password_hash.to_string()
    )
    .fetch_optional(&state.pool)
    .await?
    .ok_or(Error::Registration)?
    .id;

    let refresh = RefreshClaims::issue(uuid);
    let access = refresh.refresh();

    Ok((StatusCode::CREATED, (access, refresh)))
}

pub async fn destroy(State(state): State<AppState>, Path(uuid): Path<Uuid>) -> Result<(), Error> {
    let mut tx = state.pool.begin().await?;
    let rows = sqlx::query!("DELETE FROM credential WHERE id = $1", uuid)
        .execute(&mut *tx)
        .await?
        .rows_affected();

    if rows == 0 {
        return Err(Error::UserNotFound);
    } else if rows > 1 {
        tracing::warn!("DELETE query affected {rows} rows. This should not happen.");
    }

    tx.commit().await?;
    Ok(())
}