Skip to content

Commit

Permalink
Make context menu appear right next to the pointer
Browse files Browse the repository at this point in the history
Make custom error responses generic across the app
  • Loading branch information
dormant-user committed Mar 15, 2024
1 parent 820fcf5 commit 4279260
Show file tree
Hide file tree
Showing 10 changed files with 131 additions and 173 deletions.
4 changes: 2 additions & 2 deletions src/routes/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ pub async fn login(request: HttpRequest,
}

let mapped = verified.unwrap();
let (_host, _last_accessed) = squire::logger::log_connection(&request, &session);
let (_host, _last_accessed) = squire::custom::log_connection(&request, &session);

let payload = serde_json::to_string(&mapped).unwrap();
let encrypted_payload = fernet.encrypt(payload.as_bytes());
Expand Down Expand Up @@ -166,7 +166,7 @@ pub async fn home(request: HttpRequest,
if !auth_response.ok {
return failed_auth(auth_response, &config);
}
let (_host, _last_accessed) = squire::logger::log_connection(&request, &session);
let (_host, _last_accessed) = squire::custom::log_connection(&request, &session);
log::debug!("{}", auth_response.detail);

let listing_page = squire::content::get_all_stream_content(&config, &auth_response);
Expand Down
4 changes: 2 additions & 2 deletions src/routes/basics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ pub async fn root(request: HttpRequest,
session: web::Data<Arc<constant::Session>>,
metadata: web::Data<Arc<constant::MetaData>>,
template: web::Data<Arc<minijinja::Environment<'static>>>) -> HttpResponse {
let (_host, _last_accessed) = squire::logger::log_connection(&request, &session);
let (_host, _last_accessed) = squire::custom::log_connection(&request, &session);
let index = template.get_template("index").unwrap();
HttpResponse::build(StatusCode::OK)
.content_type("text/html; charset=utf-8")
Expand Down Expand Up @@ -70,7 +70,7 @@ pub async fn profile(request: HttpRequest,
if !auth_response.ok {
return routes::auth::failed_auth(auth_response, &config);
}
let (_host, last_accessed) = squire::logger::log_connection(&request, &session);
let (_host, last_accessed) = squire::custom::log_connection(&request, &session);
let index = template.get_template("profile").unwrap();
let mut access_map = HashMap::new();
if !last_accessed.is_empty() {
Expand Down
13 changes: 7 additions & 6 deletions src/routes/fileIO.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::path::{Path, PathBuf};
use std::sync::Arc;

use actix_web::{HttpRequest, HttpResponse, web};
use actix_web::http::StatusCode;
use fernet::Fernet;
use serde::Deserialize;

Expand Down Expand Up @@ -79,12 +80,10 @@ pub async fn edit(request: HttpRequest,
if !auth_response.ok {
return routes::auth::failed_auth(auth_response, &config);
}
let (_host, _last_accessed) = squire::logger::log_connection(&request, &session);
let (_host, _last_accessed) = squire::custom::log_connection(&request, &session);
log::debug!("{}", auth_response.detail);
let extracted = extract_media_path(payload, &config.media_source);
// todo: pop up doesn't always occur next to the mouse
// styling of the pop up is very basic
// make custom error responses generic
// todo: styling of the pop up is very basic
let media_path: PathBuf = match extracted {
Ok(path) => {
path
Expand All @@ -94,10 +93,12 @@ pub async fn edit(request: HttpRequest,
}
};
if !squire::authenticator::verify_secure_index(&PathBuf::from(&media_path), &auth_response.username) {
return squire::responses::restricted(
return squire::custom::error(
"RESTRICTED SECTION",
template.get_template("error").unwrap(),
&auth_response.username,
&metadata.pkg_version,
format!("This content is not accessible, as it does not belong to the user profile '{}'", auth_response.username),
StatusCode::FORBIDDEN
);
}
if let Some(edit_action) = request.headers().get("edit-action") {
Expand Down
58 changes: 36 additions & 22 deletions src/routes/media.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,15 @@ pub async fn track(request: HttpRequest,
return routes::auth::failed_auth(auth_response, &config);
}
if !squire::authenticator::verify_secure_index(&PathBuf::from(&info.file), &auth_response.username) {
return squire::responses::restricted(
return squire::custom::error(
"RESTRICTED SECTION",
template.get_template("error").unwrap(),
&auth_response.username,
&metadata.pkg_version
&metadata.pkg_version,
format!("This content is not accessible, as it does not belong to the user profile '{}'", auth_response.username),
StatusCode::FORBIDDEN
);
}
let (_host, _last_accessed) = squire::logger::log_connection(&request, &session);
let (_host, _last_accessed) = squire::custom::log_connection(&request, &session);
log::debug!("{}", auth_response.detail);
log::debug!("Track requested: {}", &info.file);
let filepath = Path::new(&config.media_source).join(&info.file);
Expand All @@ -111,9 +113,13 @@ pub async fn track(request: HttpRequest,
Ok(content) => HttpResponse::Ok()
.content_type("text/plain")
.body(content),
Err(_) => squire::responses::not_found(template.get_template("error").unwrap(),
&format!("'{}' was not found", &info.file),
&metadata.pkg_version)
Err(_) => squire::custom::error(
"CONTENT UNAVAILABLE",
template.get_template("error").unwrap(),
&metadata.pkg_version,
format!("'{}' was not found", &info.file),
StatusCode::NOT_FOUND
)
}
}

Expand Down Expand Up @@ -164,26 +170,30 @@ pub async fn stream(request: HttpRequest,
if !auth_response.ok {
return routes::auth::failed_auth(auth_response, &config);
}
let (_host, _last_accessed) = squire::logger::log_connection(&request, &session);
let (_host, _last_accessed) = squire::custom::log_connection(&request, &session);
log::debug!("{}", auth_response.detail);
let filepath = media_path.to_string();
if !squire::authenticator::verify_secure_index(&PathBuf::from(&filepath), &auth_response.username) {
return squire::responses::restricted(
return squire::custom::error(
"RESTRICTED SECTION",
template.get_template("error").unwrap(),
&auth_response.username,
&metadata.pkg_version
&metadata.pkg_version,
format!("This content is not accessible, as it does not belong to the user profile '{}'", auth_response.username),
StatusCode::FORBIDDEN
);
}
let secure_path = if filepath.contains(constant::SECURE_INDEX) { "true" } else { "false" };
let secure_flag = secure_path.to_string();
// True path of the media file
let __target = config.media_source.join(&filepath);
if !__target.exists() {
return squire::responses::not_found(
return squire::custom::error(
"CONTENT UNAVAILABLE",
template.get_template("error").unwrap(),
&format!("'{}' was not found", filepath),
&metadata.pkg_version
);
&metadata.pkg_version,
format!("'{}' was not found", filepath),
StatusCode::NOT_FOUND
)
}
// True path of the media file as a String
let __target_str = __target.to_string_lossy().to_string();
Expand Down Expand Up @@ -294,13 +304,15 @@ pub async fn streaming_endpoint(request: HttpRequest,
}
let media_path = config.media_source.join(&info.file);
if !squire::authenticator::verify_secure_index(&media_path, &auth_response.username) {
return squire::responses::restricted(
return squire::custom::error(
"RESTRICTED SECTION",
template.get_template("error").unwrap(),
&auth_response.username,
&metadata.pkg_version
&metadata.pkg_version,
format!("This content is not accessible, as it does not belong to the user profile '{}'", auth_response.username),
StatusCode::FORBIDDEN
);
}
let (host, _last_accessed) = squire::logger::log_connection(&request, &session);
let (host, _last_accessed) = squire::custom::log_connection(&request, &session);
if media_path.exists() {
let file = actix_files::NamedFile::open_async(media_path).await.unwrap();
// Check if the host is making a continued connection streaming the same file
Expand All @@ -313,9 +325,11 @@ pub async fn streaming_endpoint(request: HttpRequest,
}
let error = format!("File {:?} not found", media_path);
log::error!("{}", error);
squire::responses::not_found(
squire::custom::error(
"CONTENT UNAVAILABLE",
template.get_template("error").unwrap(),
&error,
&metadata.pkg_version
&metadata.pkg_version,
format!("'{}' was not found", &info.file),
StatusCode::NOT_FOUND
)
}
60 changes: 60 additions & 0 deletions src/squire/custom.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
use actix_web::{HttpRequest, HttpResponse};
use actix_web::http::StatusCode;
use minijinja::Template;

use crate::constant;

/// Logs connection information for an incoming HTTP request.
///
/// # Arguments
///
/// * `request` - A reference to the Actix web `HttpRequest` object.
/// * `session` - Session struct that holds the `session_mapping` and `session_tracker` to handle sessions.
///
/// This function logs the host and user agent information of the incoming connection.
///
/// # Returns
///
/// Returns a tuple of the host, and the last streamed file path.
pub fn log_connection(request: &HttpRequest, session: &constant::Session) -> (String, String) {
let host = request.connection_info().host().to_string();
let mut tracker = session.tracker.lock().unwrap();
if tracker.get(&host).is_none() {
tracker.insert(host.clone(), "".to_string());
log::info!("Connection received from {}", host);
if let Some(user_agent) = request.headers().get("user-agent") {
log::info!("User agent: {}", user_agent.to_str().unwrap())
}
}
return (host.clone(), tracker.get(&host).map_or("".to_string(), |s| s.to_string()));
}

/// Frames a custom response into an error page.
///
/// # Arguments
///
/// * `title` - Title to be displayed in the error page.
/// * `error` - Jinja template for the error page.
/// * `version` - Application's version in the title tag of the webpage.
/// * `description` - Description to be displayed in the error page.
/// * `status_code` - Status code of the response.
///
/// # Returns
///
/// Returns an HTTPResponse with the appropriate status code formatted as HTML.
pub fn error(title: &str,
error: Template,
version: &String,
description: String,
status_code: StatusCode) -> HttpResponse {
HttpResponse::build(status_code)
.content_type("text/html; charset=utf-8")
.body(error.render(minijinja::context!(
version => version,
title => title,
description => description,
help => r"Lost your way?\n\nHit the HOME button to navigate back to home page.",
button_text => "HOME", button_link => "/home",
block_navigation => true
)).unwrap())
}
29 changes: 0 additions & 29 deletions src/squire/logger.rs

This file was deleted.

6 changes: 2 additions & 4 deletions src/squire/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ pub mod settings;
pub mod startup;
/// Module for the functions that handle encryption/encoding and decryption/decoding.
pub mod secure;
/// Module for the function that logs the incoming connection information.
pub mod logger;
/// Module for custom functions that logs connection information and builds custom error responses.
pub mod custom;
/// Module for the functions that yield an ASCII art to print during startup.
pub mod ascii_art;
/// Module for the CORS middleware configuration.
Expand All @@ -18,5 +18,3 @@ pub mod content;
pub mod authenticator;
/// Module that handles parsing command line arguments.
pub mod parser;
/// Module that handles custom error responses to the user.
pub mod responses;
48 changes: 0 additions & 48 deletions src/squire/responses.rs

This file was deleted.

31 changes: 22 additions & 9 deletions src/templates/listing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,22 +253,31 @@ pub fn get_content() -> String {
// Set the global variable to the current file path
currentPath = path;
// Position the context menu beneath the clicked icon
// Calculate the appropriate coordinates for the context menu
var mouseX = event.clientX;
var mouseY = event.clientY;
var windowWidth = window.innerWidth;
var windowHeight = window.innerHeight;
var contextMenuWidth = contextMenu.offsetWidth;
var contextMenuHeight = contextMenu.offsetHeight;
var scrollX = window.scrollX || window.pageXOffset;
var scrollY = window.scrollY || window.pageYOffset;
// Adjust the coordinates considering the scroll position and moving 2 pixels away from the mouse pointer
var menuX = mouseX + scrollX + contextMenuWidth > windowWidth ? mouseX + scrollX - contextMenuWidth - 2 : mouseX + scrollX + 2;
var menuY = mouseY + scrollY + contextMenuHeight > windowHeight ? mouseY + scrollY - contextMenuHeight - 2 : mouseY + scrollY + 2;
// Position the context menu at the calculated coordinates
contextMenu.style.left = menuX + 'px';
contextMenu.style.top = menuY + 'px';
contextMenu.style.display = 'block';
contextMenu.style.left = event.clientX + 'px';
contextMenu.style.top = event.clientY + 'px';
}
function editAction(action, trueURL, relativePath) {
let http = new XMLHttpRequest();
http.open('POST', window.location.origin + `/edit`, true); // asynchronous session
http.setRequestHeader('Content-Type', 'application/json'); // Set content type to JSON
http.setRequestHeader('edit-action', action);
let data = {
url_locator: trueURL,
path_locator: relativePath
};
let jsonData = JSON.stringify(data);
http.onreadystatechange = function() {
if (http.readyState === XMLHttpRequest.DONE) {
if (http.status === 200) {
Expand All @@ -278,7 +287,11 @@ pub fn get_content() -> String {
}
}
};
http.send(jsonData);
let data = {
url_locator: trueURL,
path_locator: relativePath
};
http.send(JSON.stringify(data));
}
function getConfirmation(fileName, action) {
Expand Down
Loading

0 comments on commit 4279260

Please sign in to comment.