use std::sync::Arc;
use actix_web::{HttpRequest, HttpResponse, web};
use actix_web::cookie::Cookie;
use actix_web::cookie::time::{Duration, OffsetDateTime};
use actix_web::http::StatusCode;
use itertools::Itertools;
use minijinja::context;
use serde::Serialize;
use crate::{constant, routes, squire, template};
#[derive(Serialize)]
struct RedirectResponse {
redirect_url: String,
}
#[derive(Serialize)]
pub struct DetailError {
pub detail: String,
}
#[post("/login")]
pub async fn login(config: web::Data<Arc<squire::settings::Config>>,
request: HttpRequest) -> HttpResponse {
let verified = routes::authenticator::verify_login(&request, &config);
if verified.is_err() {
let err = verified.err().unwrap().to_string();
log::warn!("Error response::{}", err);
return HttpResponse::Unauthorized().json(DetailError {
detail: err
});
}
let mapped = verified.unwrap();
squire::logger::log_connection(&request);
let payload = serde_json::to_string(&mapped).unwrap();
let mut cookie = Cookie::build("session_token", constant::FERNET.encrypt(payload.as_bytes()))
.http_only(true)
.finish();
let mut expiration = OffsetDateTime::now_utc();
expiration += Duration::seconds(config.session_duration as i64);
cookie.set_expires(expiration);
log::info!("Session for '{}' will be valid until {}", mapped.get("username").unwrap(), expiration);
let mut response = HttpResponse::Ok().json(RedirectResponse {
redirect_url: "/home".to_string(),
});
response.add_cookie(&cookie).unwrap();
response
}
#[get("/logout")]
pub async fn logout(config: web::Data<Arc<squire::settings::Config>>,
request: HttpRequest) -> HttpResponse {
let host = request.connection_info().host().to_owned();
let template = constant::ENV.lock().unwrap();
let logout_template = template.get_template("logout").unwrap();
let mut response = HttpResponse::build(StatusCode::OK);
response.content_type("text/html; charset=utf-8");
let rendered;
let auth_response = routes::authenticator::verify_token(&request, &config);
log::debug!("Session Validation Response: {}", auth_response.detail);
if auth_response.username != "NA" {
log::info!("{} from {} attempted to logged out", auth_response.username, host);
}
if auth_response.ok {
let mut tracker = constant::HOST_SERVE.lock().unwrap();
if tracker.get(&host).is_some() {
tracker.remove(&host);
} else {
log::warn!("Session information for {} was not stored or no video was played", host);
}
rendered = logout_template.render(context!(detail => "You have been logged out successfully.")).unwrap();
let age = Duration::new(0, 1);
let cookie = Cookie::build("session_token", "boo")
.http_only(true).max_age(age).finish();
response.cookie(cookie);
} else {
log::debug!("No stored session found for {}", host);
rendered = logout_template.render(
context!(detail => "You are not logged in. Please click the button below to proceed.",
show_login => true)
).unwrap();
}
response.body(rendered)
}
#[get("/home")]
pub async fn home(config: web::Data<Arc<squire::settings::Config>>,
request: HttpRequest) -> HttpResponse {
let auth_response = routes::authenticator::verify_token(&request, &config);
if !auth_response.ok {
let mut response = HttpResponse::Found();
let age = Duration::new(0, 1);
let cookie = Cookie::build("detail", auth_response.detail)
.http_only(true).max_age(age).finish();
response.cookie(cookie);
response.append_header(("Location", "/error"));
return response.finish();
}
squire::logger::log_connection(&request);
log::debug!("{}", auth_response.detail);
let file_format = config.file_formats.iter().collect_tuple().unwrap();
let args = (config.video_source.to_string_lossy().to_string(), file_format);
let listing_page = squire::fileio::get_all_stream_content(args);
let template = constant::ENV.lock().unwrap();
let listing = template.get_template("listing").unwrap();
return HttpResponse::build(StatusCode::OK)
.content_type("text/html; charset=utf-8")
.body(listing.render(context!(
files => listing_page.files, directories => listing_page.directories)).unwrap()
);
}
#[get("/error")]
pub async fn error(request: HttpRequest) -> HttpResponse {
if let Some(detail) = request.cookie("detail") {
let template = constant::ENV.lock().unwrap();
let session = template.get_template("session").unwrap();
return HttpResponse::build(StatusCode::OK)
.content_type("text/html; charset=utf-8")
.body(session.render(context!(reason => detail.value())).unwrap());
}
return HttpResponse::build(StatusCode::OK)
.content_type("text/html; charset=utf-8")
.body(template::UNAUTHORIZED);
}