Skip to main content

webdav_server/api/auth/
login.rs

1use crate::error::Result;
2use crate::logger::Module;
3use crate::model::session::Session;
4use crate::model::user::User;
5use crate::{
6    api::Error::{BadRequest, Unauthorized},
7    app::State as AppState,
8};
9use crate::{info, warn};
10use axum::Json;
11use axum::extract::State;
12use serde::{Deserialize, Serialize};
13
14/// The JSON body returned on a successful login.
15#[derive(Debug, Serialize)]
16pub struct LoginResponse {
17    /// The raw opaque session token.
18    ///
19    /// This is a UUID v4 string generated by the server. The client stores it
20    /// and passes it as `Authorization: Bearer <token>` on every subsequent request.
21    pub token: String,
22}
23
24/// The JSON body expected by the login endpoint.
25#[derive(Deserialize)]
26pub struct LoginRequest {
27    /// A hex-encoded BLAKE3 hash of the user's public identity.
28    identity_hash: String,
29    /// The authentication verifier derived from the user's credentials on the client side.
30    auth_verifier: String,
31}
32
33/// Authenticates a user and generates a new session token.
34///
35/// This endpoint verifies the provided identity hash and auth verifier against
36/// the database. If successful, it creates a new session and returns the token.
37///
38/// # Errors
39/// - Returns a `BadRequest` if the identity hash cannot be decoded from hex.
40/// - Returns an `Unauthorized` if the credentials do not match any existing user.
41/// - Returns an internal error if a database query fails.
42pub async fn login(
43    State(state): State<AppState>,
44    Json(request): Json<LoginRequest>,
45) -> Result<Json<LoginResponse>> {
46    let Ok(identity_hash) = hex::decode(&request.identity_hash) else {
47        Err(BadRequest("identity_hash failed to decode".into()))?
48    };
49
50    let user_id = User::verify(&state.db, identity_hash, request.auth_verifier)
51        .await?
52        .ok_or_else(|| {
53            warn!(
54                Module::Api,
55                "Failed login attempt with id : ''",
56                // hex::encode(identity_hash)
57            );
58            Unauthorized("Invalid Credentials".into())
59        })?;
60
61    let token = Session::create(&state.db, user_id).await?;
62
63    info!(Module::Api, "User {user_id} successfully logged in");
64    Ok(Json(LoginResponse { token }))
65}