ontoref-code/crates/ontoref-daemon/src/ui/login.rs
Jesús Pérez 2d87d60bb5
Some checks failed
Rust CI / Security Audit (push) Has been cancelled
Rust CI / Check + Test + Lint (nightly) (push) Has been cancelled
Rust CI / Check + Test + Lint (stable) (push) Has been cancelled
chore: add src code
2026-03-13 00:18:14 +00:00

98 lines
2.8 KiB
Rust

use axum::{
extract::{Form, Path, State},
http::{header, StatusCode},
response::{Html, IntoResponse, Redirect, Response},
};
use serde::Deserialize;
use tera::Context;
use super::handlers::{render, UiError};
use crate::api::AppState;
use crate::session::{extract_cookie, COOKIE_NAME};
pub async fn login_page(
State(state): State<AppState>,
Path(slug): Path<String>,
) -> Result<Html<String>, UiError> {
let tera = state.tera.as_ref().ok_or(UiError::NotConfigured)?;
let mut ctx = Context::new();
ctx.insert("slug", &slug);
ctx.insert("error", &false);
ctx.insert("base_url", &format!("/ui/{slug}"));
render(tera, "pages/login.html", &ctx).await
}
#[derive(Deserialize)]
pub struct LoginForm {
pub key: String,
}
pub async fn login_submit(
State(state): State<AppState>,
Path(slug): Path<String>,
Form(form): Form<LoginForm>,
) -> Response {
let Some(ref registry) = state.registry else {
return Redirect::to("/ui/").into_response();
};
let Some(ctx) = registry.get(&slug) else {
return StatusCode::NOT_FOUND.into_response();
};
match ctx.verify_key(&form.key) {
Some(role) => {
let token = state.sessions.create(slug.clone(), role);
let cookie = format!(
"{}={}; Path=/ui/; HttpOnly; SameSite=Strict; Max-Age={}",
COOKIE_NAME,
token,
30 * 24 * 3600,
);
(
[(header::SET_COOKIE, cookie)],
Redirect::to(&format!("/ui/{slug}/")),
)
.into_response()
}
None => {
let tera = match state.tera.as_ref() {
Some(t) => t,
None => return StatusCode::INTERNAL_SERVER_ERROR.into_response(),
};
let mut tctx = Context::new();
tctx.insert("slug", &slug);
tctx.insert("error", &true);
tctx.insert("base_url", &format!("/ui/{slug}"));
match render(tera, "pages/login.html", &tctx).await {
Ok(html) => html.into_response(),
Err(_) => StatusCode::INTERNAL_SERVER_ERROR.into_response(),
}
}
}
}
pub async fn logout(
State(state): State<AppState>,
Path(slug): Path<String>,
request: axum::extract::Request,
) -> Response {
let cookie_str = request
.headers()
.get(header::COOKIE)
.and_then(|v| v.to_str().ok())
.unwrap_or("");
if let Some(token) = extract_cookie(cookie_str, COOKIE_NAME) {
state.sessions.revoke(&token);
}
let clear = format!(
"{}=; Path=/ui/; HttpOnly; SameSite=Strict; Max-Age=0",
COOKIE_NAME
);
(
[(header::SET_COOKIE, clear)],
Redirect::to(&format!("/ui/{slug}/login")),
)
.into_response()
}