0.5.1: return a proper error message if the file doesn't exist. Return proper HTTP error codes.

This commit is contained in:
Fijxu 2024-08-04 15:13:45 -04:00
parent b2395b3dea
commit 839bd717b3
Signed by: Fijxu
GPG key ID: 32C1DDF333EDA6A4
8 changed files with 62 additions and 23 deletions

BIN
public/favicon.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

View file

@ -17,9 +17,9 @@ p, h1, h2, h3, h4, h5 {
max-width: 700px; max-width: 700px;
margin: auto; margin: auto;
/* background: white; */ /* background: white; */
padding: 20px; /*! padding: 20px; */
border-radius: 0px; border-radius: 0px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); /*! box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); */
} }
#drop-area { #drop-area {
@ -86,9 +86,9 @@ nav a, nav > ul
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
border: 2px solid #f40101; /* Optional styling for the status box */ border: 2px solid #eee; /* Optional styling for the status box */
padding: 10px; /* Optional padding */ padding: 5px; /* Optional padding */
border-radius: 6px; /* Optional rounded corners */ /*! border-radius: 6px; */ /* Optional rounded corners */
/*! background-color: #f9f9f9; */ /* Optional background color */ /*! background-color: #f9f9f9; */ /* Optional background color */
} }

View file

@ -13,8 +13,8 @@ class Config
property unix_socket : String? property unix_socket : String?
property delete_files_after : Int32 = 7 property delete_files_after : Int32 = 7
# How often should the check of old files be performed? (in seconds) # How often should the check of old files be performed? (in seconds)
property delete_files_after_check_seconds : Int32 = 60 property delete_files_after_check_seconds : Int32 = 1800
property delete_key_lenght : Int8 = 8 property delete_key_lenght : Int8 = 4
# Blocked extensions that are not allowed to be uploaded to the server # Blocked extensions that are not allowed to be uploaded to the server
property blocked_extensions : Array(String) = [] of String property blocked_extensions : Array(String) = [] of String
property siteInfo : String = "xd" property siteInfo : String = "xd"

View file

@ -23,6 +23,7 @@ Utils.create_db
Utils.create_files_dir Utils.create_files_dir
get "/" do |env| get "/" do |env|
files_hosted = SQL.query_one "SELECT COUNT (filename) FROM files", as: Int32
host = env.request.headers["Host"] host = env.request.headers["Host"]
render "src/views/index.ecr" render "src/views/index.ecr"
end end

View file

@ -1,6 +1,13 @@
module Handling module Handling
extend self extend self
private macro error401(message)
env.response.content_type = "application/json"
env.response.status_code = 401
error_message = {"error" => {{message}}}.to_json
return error_message
end
private macro error403(message) private macro error403(message)
env.response.content_type = "application/json" env.response.content_type = "application/json"
env.response.status_code = 403 env.response.status_code = 403
@ -8,6 +15,27 @@ module Handling
return error_message return error_message
end end
private macro error404(message)
env.response.content_type = "application/json"
env.response.status_code = 404
error_message = {"error" => {{message}}}.to_json
return error_message
end
private macro error413(message)
env.response.content_type = "application/json"
env.response.status_code = 413
error_message = {"error" => {{message}}}.to_json
return error_message
end
private macro error500(message)
env.response.content_type = "application/json"
env.response.status_code = 500
error_message = {"error" => {{message}}}.to_json
return error_message
end
private macro msg(message) private macro msg(message)
env.response.content_type = "application/json" env.response.content_type = "application/json"
msg = {"message" => {{message}}}.to_json msg = {"message" => {{message}}}.to_json
@ -18,7 +46,7 @@ end
env.response.content_type = "application/json" env.response.content_type = "application/json"
# You can modify this if you want to allow files smaller than 1MiB # You can modify this if you want to allow files smaller than 1MiB
if env.request.headers["Content-Length"].to_i > 1048576*CONFIG.size_limit if env.request.headers["Content-Length"].to_i > 1048576*CONFIG.size_limit
error403("File is too big. The maximum size allowed is #{CONFIG.size_limit}MiB") error413("File is too big. The maximum size allowed is #{CONFIG.size_limit}MiB")
end end
filename = "" filename = ""
extension = "" extension = ""
@ -32,13 +60,13 @@ end
next if upload.filename.nil? || upload.filename.to_s.empty? next if upload.filename.nil? || upload.filename.to_s.empty?
extension = File.extname("#{upload.filename}") extension = File.extname("#{upload.filename}")
if CONFIG.blocked_extensions.includes?(extension.split(".")[1]) if CONFIG.blocked_extensions.includes?(extension.split(".")[1])
error403("Extension '#{extension}' is not allowed") error401("Extension '#{extension}' is not allowed")
end end
# TODO: Check if random string is already taken by some file (This will likely # TODO: Check if random string is already taken by some file (This will likely
# never happen but it is better to design it that way) # never happen but it is better to design it that way)
filename = Random.base58(CONFIG.filename_lenght) filename = Random.base58(CONFIG.filename_lenght)
if !filename.is_a?(String) if !filename.is_a?(String)
return "This doesn't look like a file" error403("This doesn't look like a file")
else else
file_path = ::File.join ["#{CONFIG.files}", filename + extension] file_path = ::File.join ["#{CONFIG.files}", filename + extension]
File.open(file_path, "w") do |file| File.open(file_path, "w") do |file|
@ -73,26 +101,30 @@ end
def retrieve_file(env) def retrieve_file(env)
puts env.params.url puts env.params.url
filename = SQL.query_one "SELECT filename FROM files WHERE filename = ?", env.params.url["filename"].to_s.split(".").first, as: String begin
extension = SQL.query_one "SELECT extension FROM files WHERE filename = ?", filename, as: String filename = SQL.query_one "SELECT filename FROM files WHERE filename = ?", env.params.url["filename"].to_s.split(".").first, as: String
send_file env, "#{CONFIG.files}/#{filename}#{extension}" extension = SQL.query_one "SELECT extension FROM files WHERE filename = ?", filename, as: String
send_file env, "#{CONFIG.files}/#{filename}#{extension}"
rescue
error404("This file does not exist")
end
end end
def stats(env) def stats(env)
env.response.content_type = "application/json" env.response.content_type = "application/json"
json_data = JSON.build do |json| begin
json.object do json_data = JSON.build do |json|
json.field "stats" do json.object do
json.object do json.field "stats" do
begin json.object do
json.field "filesHosted", SQL.query_one "SELECT COUNT (filename) FROM files", as: Int32 json.field "filesHosted", SQL.query_one "SELECT COUNT (filename) FROM files", as: Int32
json.field "maxUploadSize", CONFIG.size_limit json.field "maxUploadSize", CONFIG.size_limit
rescue
json.field "error", "Unknown error"
end end
end end
end end
end end
rescue ex
error500("Unknown error: #{ex.message}")
end end
json_data json_data
end end
@ -106,10 +138,10 @@ end
SQL.exec "DELETE FROM files WHERE delete_key = ?", env.params.query["key"] SQL.exec "DELETE FROM files WHERE delete_key = ?", env.params.query["key"]
msg("File '#{file_to_delete}' deleted successfully") msg("File '#{file_to_delete}' deleted successfully")
rescue ex rescue ex
error403("Unknown error: #{ex.message}") error500("Unknown error: #{ex.message}")
end end
else else
error403("Huh? This delete key doesn't exist") error401("Huh? This delete key doesn't exist")
end end
end end
end end

3
src/log.cr Normal file
View file

@ -0,0 +1,3 @@
module LOGGER
end

View file

@ -14,6 +14,7 @@ module Utils
def create_files_dir def create_files_dir
if !Dir.exists?("#{CONFIG.files}") if !Dir.exists?("#{CONFIG.files}")
puts "INFO: Creatin files folder under '#{CONFIG.files}'"
begin begin
Dir.mkdir("#{CONFIG.files}") Dir.mkdir("#{CONFIG.files}")
rescue ex rescue ex

View file

@ -30,13 +30,14 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title> <%= host %> </title> <title> <%= host %> </title>
<link rel="stylesheet" href="styles.css"> <link rel="stylesheet" href="styles.css">
<link rel="icon" href="./favicon.gif" type="image/gif" />
</head> </head>
<body> <body>
<div class="container"> <div class="container">
<h1 style="font-size: 72px; text-align: center; margin: 20px;"> <%= host %> </h1> <h1 style="font-size: 72px; text-align: center; margin: 20px;"> <%= host %> </h1>
<p style="text-align: center; font-size: 22px;"> <%= CONFIG.siteInfo %> </p> <p style="text-align: center; font-size: 22px;"> <%= CONFIG.siteInfo %> </p>
<div id="drop-area"> <div id="drop-area">
<p style='padding: 0;margin: 0; color: #123718bf;'>Drop or Choose file(s)</p> <p style='padding: 0;margin: 0; color: #123718bf;'>Arrastra, Pega o Selecciona archivos.</p>
<input type="file" id="fileElem" accept="*/*" style="display: none;"> <input type="file" id="fileElem" accept="*/*" style="display: none;">
<!-- <label for="fileElem" class="button">Select File</label> --> <!-- <label for="fileElem" class="button">Select File</label> -->
</div> </div>
@ -47,6 +48,7 @@
<p> <a href='./chatterino.png'>Chatterino Config</a> </p> <p> <a href='./chatterino.png'>Chatterino Config</a> </p>
<p> <a href='./sharex.sxcu'>ShareX Config</a> </p> <p> <a href='./sharex.sxcu'>ShareX Config</a> </p>
<p> <a href='https://codeberg.org/Fijxu/file-uploader-crystal'>file-uploader-crystal (BETA <%= CURRENT_VERSION %>-<%= CURRENT_COMMIT %> @ <%= CURRENT_BRANCH %>)</a> </p> <p> <a href='https://codeberg.org/Fijxu/file-uploader-crystal'>file-uploader-crystal (BETA <%= CURRENT_VERSION %>-<%= CURRENT_COMMIT %> @ <%= CURRENT_BRANCH %>)</a> </p>
<p>Archivos alojados: <%= files_hosted %></p>
</div> </div>
<script src="script.js"></script> <script src="script.js"></script>
</body> </body>