use crate::web_client::types::{AppState, CreateClientIdResponse, LoginRequest, LoginResponse};
use crate::web_client::utils::{get_mime_type, parse_cookies};
use axum::{
extract::{Path as AxumPath, Request, State},
http::{header, StatusCode},
response::{Html, IntoResponse},
Json,
};
use axum_extra::extract::cookie::{Cookie, SameSite};
use include_dir;
use uuid::Uuid;
use zellij_utils::{consts::VERSION, web_authentication_tokens::create_session_token};
const WEB_CLIENT_PAGE: &str = include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/",
"assets/index.html"
));
const ASSETS_DIR: include_dir::Dir<'_> = include_dir::include_dir!("$CARGO_MANIFEST_DIR/assets");
pub async fn serve_html(request: Request) -> Html<String> {
let cookies = parse_cookies(&request);
let is_authenticated = cookies.get("session_token").is_some();
let auth_value = if is_authenticated { "true" } else { "false" };
let html = Html(WEB_CLIENT_PAGE.replace("IS_AUTHENTICATED", &format!("{}", auth_value)));
html
}
pub async fn login_handler(Json(login_request): Json<LoginRequest>) -> impl IntoResponse {
match create_session_token(
&login_request.auth_token,
login_request.remember_me.unwrap_or(false),
) {
Ok(session_token) => {
let cookie = if login_request.remember_me.unwrap_or(false) {
Cookie::build(("session_token", session_token))
.http_only(true)
.secure(true)
.same_site(SameSite::Strict)
.path("/")
.max_age(time::Duration::weeks(4))
.build()
} else {
Cookie::build(("session_token", session_token))
.http_only(true)
.secure(true)
.same_site(SameSite::Strict)
.path("/")
.build()
};
let mut response = Json(LoginResponse {
success: true,
message: "Login successful".to_string(),
})
.into_response();
if let Ok(cookie_header) = axum::http::HeaderValue::from_str(&cookie.to_string()) {
response.headers_mut().insert("set-cookie", cookie_header);
}
response
},
Err(_) => (
StatusCode::UNAUTHORIZED,
Json(LoginResponse {
success: false,
message: "Invalid authentication token".to_string(),
}),
)
.into_response(),
}
}
pub async fn create_new_client(
State(state): State<AppState>,
) -> Result<Json<CreateClientIdResponse>, (StatusCode, impl IntoResponse)> {
let web_client_id = String::from(Uuid::new_v4());
let os_input = state
.client_os_api_factory
.create_client_os_api()
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, Json(e.to_string())))?;
state
.connection_table
.lock()
.unwrap()
.add_new_client(web_client_id.to_owned(), os_input);
Ok(Json(CreateClientIdResponse { web_client_id }))
}
pub async fn get_static_asset(AxumPath(path): AxumPath<String>) -> impl IntoResponse {
let path = path.trim_start_matches('/');
match ASSETS_DIR.get_file(path) {
None => (
[(header::CONTENT_TYPE, "text/html")],
"Not Found".as_bytes(),
),
Some(file) => {
let ext = file.path().extension().and_then(|ext| ext.to_str());
let mime_type = get_mime_type(ext);
([(header::CONTENT_TYPE, mime_type)], file.contents())
},
}
}
pub async fn version_handler() -> &'static str {
VERSION
}