0.8.9: Better frontend and idk what more

This commit is contained in:
Fijxu 2024-08-22 18:59:08 -04:00
parent 69fe5a3c58
commit 7ee5956970
Signed by: Fijxu
GPG key ID: 32C1DDF333EDA6A4
6 changed files with 382 additions and 278 deletions

View file

@ -1,140 +1,169 @@
// By chatgpt becuase I hate frontend and javascript kill me
document.addEventListener("DOMContentLoaded", () => {
const dropArea = document.getElementById("drop-area");
const fileInput = document.getElementById("fileElem");
const uploadStatus = document.getElementById("upload-status");
const dropArea = document.getElementById("drop-area");
const fileInput = document.getElementById("fileElem");
const uploadStatus = document.getElementById("upload-status");
// Prevent default drag behaviors
["dragenter", "dragover", "dragleave", "drop"].forEach(eventName => {
dropArea.addEventListener(eventName, preventDefaults, false);
document.body.addEventListener(eventName, preventDefaults, false);
// Prevent default drag behaviors
["dragenter", "dragover", "dragleave", "drop"].forEach((eventName) => {
dropArea.addEventListener(eventName, preventDefaults, false);
document.body.addEventListener(eventName, preventDefaults, false);
});
// Highlight drop area when item is dragged over
["dragenter", "dragover"].forEach((eventName) => {
dropArea.addEventListener(eventName, highlight, false);
});
["dragleave", "drop"].forEach((eventName) => {
dropArea.addEventListener(eventName, unhighlight, false);
});
// Handle dropped files
dropArea.addEventListener("drop", handleDrop, false);
dropArea.addEventListener("click", () => fileInput.click());
// Handle file selection
fileInput.addEventListener(
"change",
() => {
const files = fileInput.files;
handleFiles(files);
},
false
);
// Handle pasted files
document.addEventListener("paste", handlePaste, false);
function preventDefaults(e) {
e.preventDefault();
e.stopPropagation();
}
function highlight() {
dropArea.classList.add("highlight");
}
function unhighlight() {
dropArea.classList.remove("highlight");
}
function handleDrop(e) {
const dt = e.dataTransfer;
const files = dt.files;
handleFiles(files);
}
function handlePaste(e) {
const items = e.clipboardData.items;
for (let i = 0; i < items.length; i++) {
const item = items[i];
if (item.kind === "file") {
const file = item.getAsFile();
handleFiles([file]);
}
}
}
function handleFiles(files) {
if (files.length > 0) {
for (const file of files) {
uploadFile(file);
}
}
}
function uploadFile(file) {
const url = "upload"; // Replace with your upload URL
const xhr = new XMLHttpRequest();
// Create a new upload status container and link elements
const uploadContainer = document.createElement("div");
const statusLink = document.createElement("div");
const uploadText = document.createElement("span");
const buttons = document.createElement("div");
const copyButton = document.createElement("button");
const deleteButton = document.createElement("button");
uploadContainer.className = "upload-status"; // Use the existing CSS class for styling
uploadContainer.appendChild(uploadText);
uploadContainer.appendChild(statusLink);
buttons.appendChild(copyButton)
buttons.appendChild(deleteButton)
uploadContainer.appendChild(buttons)
uploadStatus.appendChild(uploadContainer);
// Update upload text
uploadText.innerHTML = "0%";
uploadText.className = "percent";
statusLink.className = "status";
copyButton.className = "copy-button"; // Add class for styling
copyButton.innerHTML = "Copiar"; // Set button text
deleteButton.className = "delete-button";
deleteButton.innerHTML = "Borrar";
copyButton.style.display = "none";
deleteButton.style.display = "none";
// Update progress text
xhr.upload.addEventListener("progress", (e) => {
if (e.lengthComputable) {
const percentComplete = Math.round((e.loaded / e.total) * 100);
uploadText.innerHTML = `${percentComplete}%`; // Update the text with the percentage
}
});
// Highlight drop area when item is dragged over
["dragenter", "dragover"].forEach(eventName => {
dropArea.addEventListener(eventName, highlight, false);
});
xhr.onerror = () => {
console.error("Error:", xhr.status, xhr.statusText, xhr.responseText);
statusLink.textContent = "Error desconocido";
};
["dragleave", "drop"].forEach(eventName => {
dropArea.addEventListener(eventName, unhighlight, false);
});
// Handle dropped files
dropArea.addEventListener("drop", handleDrop, false);
dropArea.addEventListener("click", () => fileInput.click());
// Handle file selection
fileInput.addEventListener("change", () => {
const files = fileInput.files;
handleFiles(files);
}, false);
// Handle pasted files
document.addEventListener("paste", handlePaste, false);
function preventDefaults(e) {
e.preventDefault();
e.stopPropagation();
}
function highlight() {
dropArea.classList.add("highlight");
}
function unhighlight() {
dropArea.classList.remove("highlight");
}
function handleDrop(e) {
const dt = e.dataTransfer;
const files = dt.files;
handleFiles(files);
}
function handlePaste(e) {
const items = e.clipboardData.items;
for (let i = 0; i < items.length; i++) {
const item = items[i];
if (item.kind === "file") {
const file = item.getAsFile();
handleFiles([file]);
}
xhr.onload = () => {
// console.log("Response Status:", xhr.status);
// console.log("Response Text:", xhr.responseText);
if (xhr.status === 200) {
try {
const response = JSON.parse(xhr.responseText);
const fileLink = response.link;
statusLink.innerHTML = `<a href="${fileLink}" target="_blank">${fileLink}</a>`;
copyButton.style.display = "inline";
copyButton.onclick = () => copyToClipboard(fileLink);
deleteButton.style.display = "inline";
deleteButton.onclick = () => {
window.open(response.deleteLink, "_blank");
};
} catch (error) {
statusLink.textContent =
"Error desconocido, habla con el administrador";
}
}
function handleFiles(files) {
if (files.length > 0) {
for (const file of files) {
uploadFile(file);
}
} else if (xhr.status >= 400 && xhr.status < 500) {
try {
const errorResponse = JSON.parse(xhr.responseText);
statusLink.textContent = errorResponse.error || "Error del cliente.";
} catch (e) {
statusLink.textContent = "Error del cliente.";
}
}
} else {
statusLink.textContent = "Error del servidor.";
}
};
function uploadFile(file) {
const url = "upload"; // Replace with your upload URL
const xhr = new XMLHttpRequest();
// Send file
const formData = new FormData();
formData.append("file", file);
xhr.open("POST", url, true);
xhr.send(formData);
}
// Create a new upload status container and link elements
const uploadContainer = document.createElement("div");
const statusLink = document.createElement("div");
const uploadText = document.createElement("span");
const copyButton = document.createElement("button");
uploadContainer.className = "upload-status"; // Use the existing CSS class for styling
uploadContainer.appendChild(uploadText);
uploadContainer.appendChild(statusLink);
uploadContainer.appendChild(copyButton);
uploadStatus.appendChild(uploadContainer); // Append to the main upload status container
// Update upload text
uploadText.innerHTML = "0%";
uploadText.className = "percent"
copyButton.className = "copy-button"; // Add class for styling
copyButton.innerHTML = "Copiar"; // Set button text
copyButton.style.display = "none"; // Hide initially
// Update progress text
xhr.upload.addEventListener("progress", (e) => {
if (e.lengthComputable) {
const percentComplete = Math.round((e.loaded / e.total) * 100);
uploadText.innerHTML = `${percentComplete}%`; // Update the text with the percentage
}
});
// Handle response
xhr.onload = () => {
if (xhr.status === 200) {
try {
const response = JSON.parse(xhr.responseText);
const fileLink = response.link; // Assuming the response contains a key 'link'
statusLink.innerHTML = `<a href="${fileLink}" target="_blank">${fileLink}</a>`;
copyButton.style.display = "inline"; // Show the copy button
copyButton.onclick = () => copyToClipboard(fileLink); // Set the copy action
} catch (error) {
statusLink.textContent = "File uploaded but failed to parse response.";
}
} else {
statusLink.textContent = "File upload failed.";
}
};
// Handle errors
xhr.onerror = () => {
statusLink.textContent = "An error occurred during the file upload.";
};
// Send file
const formData = new FormData();
formData.append("file", file);
xhr.open("POST", url, true);
xhr.send(formData);
}
// Function to copy the link to the clipboard
function copyToClipboard(text) {
navigator.clipboard.writeText(text).then(() => {
// alert("Link copied to clipboard!"); // Notify the user
}).catch(err => {
console.error("Failed to copy: ", err);
});
}
// Function to copy the link to the clipboard
function copyToClipboard(text) {
navigator.clipboard
.writeText(text)
.then(() => {
// alert("Link copied to clipboard!"); // Notify the user
})
.catch((err) => {
console.error("Failed to copy: ", err);
});
}
});

View file

@ -1,172 +1,228 @@
@font-face {
font-family: "FG";
font-weight: 500;
src: url('framd.ttf');
font-family: "FG";
font-weight: 500;
src: url('framd.ttf');
}
@font-face {
font-family: "FG";
font-weight: 900;
src: url('frahv.ttf');
font-family: "FG";
font-weight: 900;
src: url('frahv.ttf');
}
@font-face {
font-family: "XFG";
font-weight: 900;
src: url('frahvmod.ttf');
font-family: "XFG";
font-weight: 900;
src: url('frahvmod.ttf');
}
html {
font-family: "FG";
background-image: linear-gradient(to bottom,
rgba(11, 11, 11, 0.92),
rgba(11, 11, 11, 0.92)),
url(./bliss-small.avif);
background-attachment: fixed;
font-family: "FG";
background-image: linear-gradient(to bottom,
rgba(11, 11, 11, 0.92),
rgba(11, 11, 11, 0.92)),
url(./bliss-small.avif);
background-attachment: fixed;
background-repeat: no-repeat;
background-size: cover;
}
body {
/* font-family: Arial, sans-serif; */
/* background-color: #111; */
margin: 0;
padding: 20px;
/* font-family: Arial, sans-serif; */
/* background-color: #111; */
margin: 0;
padding: 20px;
}
p, h1, h2, h3, h4, h5 {
color: aliceblue
p,
h1,
h2,
h3,
h4,
h5 {
color: aliceblue
}
h1 {
font-family: "FG";
font-weight: 200;
max-width: 100%;
overflow-wrap: break-word;
font-family: "FG";
font-weight: 200;
max-width: 100%;
overflow-wrap: break-word;
}
a {
text-decoration: none;
text-decoration: none;
}
.bottom {
font-size: 0.9em;
/* margin-top: 1ch;*/
flex: 1;
text-align: center;
font-size: 0.9em;
/* margin-top: 1ch;*/
flex: 1;
text-align: center;
}
.bottom > p {
margin: 10px 0px;
.bottom>p {
margin: 10px 0px;
}
.percent {
color: aliceblue
color: aliceblue
}
.container {
max-width: 700px;
margin: auto;
/* background: white; */
/*! padding: 20px; */
border-radius: 0px;
/*! box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); */
max-width: 800px;
margin: auto;
/* background: white; */
/*! padding: 20px; */
border-radius: 0px;
/*! box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); */
}
#drop-area {
/*! border: 2px solid #00ff00; */
/*! border-radius: 6px; */
/*! padding-left: 10px; */
/*! padding-right: 10px; */
text-align: center;
position: relative;
width: fit-content;
margin: 0 auto; /* Center the element */
display: block; /* Ensure it behaves as a block-level element */
background: rgba(202,230,190,.75);
border: 1px solid #b7d1a0;
border-radius: 4px;
color: #468847;
cursor: pointer;
/*! display: inline-block; */
font-size: 24px;
padding: 28px 48px;
text-shadow: 0 1px hsla(0,0%,100%,.5);
transition: background-color .25s,width .5s,height .5s;
/*! border: 2px solid #00ff00; */
/*! border-radius: 6px; */
/*! padding-left: 10px; */
/*! padding-right: 10px; */
text-align: center;
position: relative;
width: fit-content;
margin: 0 auto;
/* Center the element */
display: block;
/* Ensure it behaves as a block-level element */
background: rgba(202, 230, 190, .75);
border: 1px solid #b7d1a0;
border-radius: 4px;
color: #468847;
cursor: pointer;
/*! display: inline-block; */
font-size: 24px;
padding: 28px 48px;
text-shadow: 0 1px hsla(0, 0%, 100%, .5);
transition: background-color .25s, width .5s, height .5s;
}
.button {
display: inline-block;
padding: 10px 20px;
/* background: #; */
color: white;
border-radius: 5px;
cursor: pointer;
/* margin-top: 10px; */
display: inline-block;
padding: 10px 20px;
/* background: #; */
color: white;
border-radius: 5px;
cursor: pointer;
/* margin-top: 10px; */
}
.upload-status {
margin-top: 10px;
margin-top: 10px;
}
nav a, nav > ul
{
list-style: none;
margin: 0;
padding: 0;
text-align: center;
nav a,
nav>ul {
list-style: none;
margin: 0;
padding: 0;
text-align: center;
}
#upload-status {
margin: 20px; /* Adjust as needed */
margin: 20px;
/* Adjust as needed */
}
.upload-status {
display: flex;
align-items: center;
justify-content: space-between;
border: 2px solid #999; /* Optional styling for the status box */
padding: 5px; /* Optional padding */
/*! border-radius: 6px; */ /* Optional rounded corners */
/*! background-color: #f9f9f9; */ /* Optional background color */
display: flex;
align-items: center;
justify-content: space-between;
border: 2px solid #999;
/* Optional styling for the status box */
padding: 5px;
/* Optional padding */
/*! border-radius: 6px; */
/* Optional rounded corners */
/*! background-color: #f9f9f9; */
/* Optional background color */
}
.link-container {
display: flex;
align-items: center;
margin-left: auto; /* Pushes the link and button to the right */
display: flex;
align-items: center;
margin-left: auto;
/* Pushes the link and button to the right */
}
.link {
color: #ffb6c1;
text-decoration: none; /* Remove underline from link */
margin-right: 5px; /* Space between link and button */
color: #ffb6c1;
text-decoration: none;
/* Remove underline from link */
margin-right: 5px;
/* Space between link and button */
}
.link:hover {
text-decoration: underline; /* Optional: underline on hover */
text-decoration: underline;
/* Optional: underline on hover */
}
.copy-button {
display: inline;
background-color: #5e5e5e; /* Button background color */
color: white; /* Button text color */
border: none; /* Remove border */
border-radius: 3px; /* Rounded corners for the button */
padding: 5px 10px; /* Button padding */
cursor: pointer; /* Pointer cursor on hover */
display: inline;
background-color: #7a6fff;
/* Button background color */
color: white;
/* Button text color */
border: none;
/* Remove border */
border-radius: 3px;
/* Rounded corners for the button */
padding: 5px 10px;
/* Button padding */
cursor: pointer;
/* Pointer cursor on hover */
font-weight: bold;
}
.delete-button {
display: inline;
background-color: #ff6f6f;
/* Button background color */
color: white;
/* Button text color */
border: none;
/* Remove border */
border-radius: 3px;
/* Rounded corners for the button */
padding: 5px 10px;
/* Button padding */
cursor: pointer;
/* Pointer cursor on hover */
margin-left: 6px;
font-weight: bold;
}
.copy-button:hover {
background-color: #404040; /* Darker shade on hover */
background-color: #6057ce;
/* Darker shade on hover */
}
.delete-button:hover {
background-color: #ce5757;
/* Darker shade on hover */
}
.status {
color: rgb(255, 132, 0);
}
a:link {
color: #ffb6c1
color: #ffb6c1
}
a:visited {
color: #ffb6c1
color: #ffb6c1
}
a:hover {
color: #ffb6c1
color: #ffb6c1
}

View file

@ -56,7 +56,7 @@ module Handling::Admin
# Delete entry from db
SQL.exec "DELETE FROM #{CONFIG.ipTableName} WHERE ip = ?", ip
LOGGER.debug "Rate limit for '#{ip}' was deleted"
successfull_ips << ip
successfull_ips << ip
rescue ex : DB::NoResultsError
LOGGER.error("Rate limit for '#{ip}' doesn't exist or is not registered in the database: #{ex.message}")
failed_ips << ip

View file

@ -20,6 +20,8 @@ module Jobs
spawn do
loop do
Utils.retrieve_tor_exit_nodes
# Updates the @@exit_nodes array instantly
Routing.reload_exit_nodes
sleep CONFIG.torExitNodesCheck
end
end
@ -28,9 +30,7 @@ module Jobs
def self.kemal
spawn do
if !CONFIG.unix_socket.nil?
Kemal.run do |config|
config.server.not_nil!.bind_unix "#{CONFIG.unix_socket}"
end
Kemal.run &.server.not_nil!.bind_unix "#{CONFIG.unix_socket}"
else
Kemal.run
end

View file

@ -3,19 +3,10 @@ require "./http-errors"
module Routing
extend self
@@exit_nodes = Array(String).new
if CONFIG.blockTorAddresses
spawn do
# Wait a little for Utils.retrieve_tor_exit_nodes to execute first
# or it will load an old exit node list
# I think this can be replaced by channels which makes me able to
# receive data from fibers
sleep 5
loop do
LOGGER.debug "Updating Tor exit nodes array"
@@exit_nodes = Utils.load_tor_exit_nodes
sleep CONFIG.torExitNodesCheck + 5
end
end
def reload_exit_nodes
LOGGER.debug "Updating Tor exit nodes array"
@@exit_nodes = Utils.load_tor_exit_nodes
end
before_post "/api/admin/*" do |env|
@ -86,20 +77,21 @@ module Routing
Handling.sharex_config(env)
end
self.register_admin
if CONFIG.adminEnabled
self.register_admin
end
end
def register_admin
if CONFIG.adminEnabled
# post "/api/admin/upload" do |env|
# Handling::Admin.delete_ip_limit(env)
# end
post "/api/admin/delete" do |env|
Handling::Admin.delete_file(env)
end
end
post "/api/admin/deleteiplimit" do |env|
Handling::Admin.delete_ip_limit(env)
# post "/api/admin/upload" do |env|
# Handling::Admin.delete_ip_limit(env)
# end
post "/api/admin/delete" do |env|
Handling::Admin.delete_file(env)
end
end
post "/api/admin/deleteiplimit" do |env|
Handling::Admin.delete_ip_limit(env)
end
end

View file

@ -135,7 +135,8 @@ module Utils
end
end
# Delete socket if the server has not been previously cleaned by the server (Due to unclean exits, crashes, etc.)
# Delete socket if the server has not been previously cleaned by the server
# (Due to unclean exits, crashes, etc.)
def delete_socket
if File.exists?("#{CONFIG.unix_socket}")
LOGGER.info "Deleting old unix socket"
@ -167,21 +168,43 @@ module Utils
msg("File '#{fileinfo[:filename]}' deleted successfully")
end
MAGIC_BYTES = {
# Images
".png" => "89504e470d0a1a0a",
".heic" => "6674797068656963",
".jpg" => "ffd8ff",
".gif" => "474946383",
# Videos
".mp4" => "66747970",
".webm" => "1a45dfa3",
".mov" => "6d6f6f76",
".wmv" => "󠀀3026b2758e66cf11",
".flv" => "󠀀464c5601",
".mpeg" => "000001bx",
# Audio
".mp3" => "󠀀494433",
".aac" => "󠀀fff1",
".wav" => "󠀀57415645666d7420",
".flac" => "󠀀664c614300000022",
".ogg" => "󠀀4f67675300020000000000000000",
".wma" => "󠀀3026b2758e66cf11a6d900aa0062ce6c",
".aiff" => "󠀀464f524d00",
# Whatever
".7z" => "377abcaf271c",
".gz" => "1f8b",
".iso" => "󠀀4344303031",
# Documents
"pdf" => "󠀀25504446",
"html" => "<!DOCTYPE html>",
}
def detect_extension(file) : String
magic_bytes = {
".png" => "89504e470d0a1a0a",
".jpg" => "ffd8ff",
".webm" => "1a45dfa3",
".mp4" => "66747970",
".gif" => "474946383",
".7z" => "377abcaf271c",
".gz" => "1f8b",
}
file = File.open(file)
slice = Bytes.new(8)
slice = Bytes.new(16)
hex = IO::Hexdump.new(file)
# Reads the first 16 bytes of the file in Heap
hex.read(slice)
magic_bytes.each do |ext, mb|
MAGIC_BYTES.each do |ext, mb|
if slice.hexstring.includes?(mb)
return ext
end
@ -191,17 +214,21 @@ module Utils
def retrieve_tor_exit_nodes
LOGGER.debug "Retrieving Tor exit nodes list"
resp = HTTP::Client.get(CONFIG.torExitNodesUrl) do |res|
if res.success? && res.status_code == 200
begin
File.open(CONFIG.torExitNodesFile, "w") do |output|
IO.copy(res.body_io, output)
HTTP::Client.get(CONFIG.torExitNodesUrl) do |res|
begin
if res.success? && res.status_code == 200
begin
File.open(CONFIG.torExitNodesFile, "w") { |output| IO.copy(res.body_io, output) }
rescue ex
LOGGER.error "Failed to write to file: #{ex.message}"
end
rescue ex
LOGGER.error "Failed to write to file: #{ex.message}"
else
LOGGER.error "Failed to retrieve exit nodes list. Status Code: #{res.status_code}"
end
else
LOGGER.error "Failed to retrieve exit nodes list. Status Code: #{res.status_code}"
rescue ex : Socket::ConnectError
LOGGER.error "Failed to connect to #{CONFIG.torExitNodesUrl}: #{ex.message}"
rescue ex
LOGGER.error "Unknown error: #{ex.message}"
end
end
end
@ -227,7 +254,7 @@ module Utils
end
def host(env) : String
begin
begin
return env.request.headers.try &.["X-Forwarded-Host"]
rescue
return env.request.headers["Host"]