1
0
Fork 0
forked from alemi/upub

feat: login tells you who you are

This commit is contained in:
əlemi 2024-04-15 22:29:55 +02:00
parent 2dabd308cc
commit 3cf401467e
Signed by: alemi
GPG key ID: A4895B84D311642C

View file

@ -2,7 +2,7 @@ use axum::{http::StatusCode, extract::State, Json};
use rand::Rng; use rand::Rng;
use sea_orm::{ColumnTrait, Condition, EntityTrait, QueryFilter}; use sea_orm::{ColumnTrait, Condition, EntityTrait, QueryFilter};
use crate::{model, server::Context}; use crate::{errors::UpubError, model, server::Context};
#[derive(Debug, Clone, serde::Deserialize)] #[derive(Debug, Clone, serde::Deserialize)]
@ -11,7 +11,14 @@ pub struct LoginForm {
password: String, password: String,
} }
pub async fn login(State(ctx): State<Context>, Json(login): Json<LoginForm>) -> Result<Json<serde_json::Value>, StatusCode> { #[derive(Debug, Clone, serde::Serialize)]
pub struct AuthSuccess {
token: String,
user: String,
expires: chrono::DateTime<chrono::Utc>,
}
pub async fn login(State(ctx): State<Context>, Json(login): Json<LoginForm>) -> crate::Result<Json<AuthSuccess>> {
// TODO salt the pwd // TODO salt the pwd
match model::credential::Entity::find() match model::credential::Entity::find()
.filter(Condition::all() .filter(Condition::all()
@ -19,30 +26,30 @@ pub async fn login(State(ctx): State<Context>, Json(login): Json<LoginForm>) ->
.add(model::credential::Column::Password.eq(sha256::digest(login.password))) .add(model::credential::Column::Password.eq(sha256::digest(login.password)))
) )
.one(ctx.db()) .one(ctx.db())
.await .await?
{ {
Ok(Some(x)) => { Some(x) => {
// TODO should probably use crypto-safe rng // TODO should probably use crypto-safe rng
let token : String = rand::thread_rng() let token : String = rand::thread_rng()
.sample_iter(&rand::distributions::Alphanumeric) .sample_iter(&rand::distributions::Alphanumeric)
.take(128) .take(128)
.map(char::from) .map(char::from)
.collect(); .collect();
let expires = chrono::Utc::now() + std::time::Duration::from_secs(3600 * 6);
model::session::Entity::insert( model::session::Entity::insert(
model::session::ActiveModel { model::session::ActiveModel {
id: sea_orm::ActiveValue::Set(token.clone()), id: sea_orm::ActiveValue::Set(token.clone()),
actor: sea_orm::ActiveValue::Set(x.id), actor: sea_orm::ActiveValue::Set(x.id.clone()),
expires: sea_orm::ActiveValue::Set(chrono::Utc::now() + std::time::Duration::from_secs(3600 * 6)), expires: sea_orm::ActiveValue::Set(expires),
} }
) )
.exec(ctx.db()) .exec(ctx.db())
.await.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; .await.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
Ok(Json(serde_json::Value::String(token))) Ok(Json(AuthSuccess {
token, expires,
user: x.id
}))
}, },
Ok(None) => Err(StatusCode::UNAUTHORIZED), None => Err(UpubError::unauthorized()),
Err(e) => {
tracing::error!("error querying db for user credentials: {e}");
Err(StatusCode::INTERNAL_SERVER_ERROR)
}
} }
} }