0.4.0: Support for blocked extensions and filesize limit

This commit is contained in:
Fijxu 2024-08-03 15:55:31 -04:00
parent 17f1efa214
commit e096ed5215
Signed by: Fijxu
GPG key ID: 32C1DDF333EDA6A4
3 changed files with 42 additions and 45 deletions

View file

@ -0,0 +1,2 @@
blocked_extensions:
- "exe"

View file

@ -6,12 +6,16 @@ class Config
property files : String = "./files" property files : String = "./files"
property db : String = "./db.sqlite3" property db : String = "./db.sqlite3"
property filename_lenght : Int8 = 3 property filename_lenght : Int8 = 3
# In MiB
property size_limit : Int16 = 512
property port : UInt16 = 8080 property port : UInt16 = 8080
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 = 60
property delete_key_lenght : Int8 = 8 property delete_key_lenght : Int8 = 8
# Blocked extensions that are not allowed to be uploaded to the server
property blocked_extensions : Array(String) = [] of String
def self.load def self.load
config_file = "config/config.yml" config_file = "config/config.yml"

View file

@ -1,7 +1,25 @@
module Handling module Handling
extend self extend self
private macro error403(message)
env.response.content_type = "application/json"
env.response.status_code = 403
error_message = {"error" => {{message}}}.to_json
return error_message
end
private macro msg(message)
env.response.content_type = "application/json"
msg = {"message" => {{message}}}.to_json
return msg
end
def upload(env) def upload(env)
env.response.content_type = "application/json"
# 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
error403("File is too big. The maximum size allowed is #{CONFIG.size_limit}MiB")
end
filename = "" filename = ""
extension = "" extension = ""
original_filename = "" original_filename = ""
@ -13,6 +31,11 @@ module Handling
HTTP::FormData.parse(env.request) do |upload| HTTP::FormData.parse(env.request) do |upload|
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])
error403("Extension '#{extension}' is not allowed")
end
# 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)
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" return "This doesn't look like a file"
@ -25,12 +48,11 @@ module Handling
original_filename = upload.filename original_filename = upload.filename
uploaded_at = Time.utc uploaded_at = Time.utc
file_hash = Utils.hash_file(file_path) file_hash = Utils.hash_file(file_path)
ip_address = env.request.not_nil!.remote_address.to_s.split(":").first ip_address = env.request.remote_address.to_s.split(":").first
SQL.exec "INSERT INTO FILES VALUES (?, ?, ?, ?, ?, ?, ?)", SQL.exec "INSERT INTO FILES VALUES (?, ?, ?, ?, ?, ?, ?)",
original_filename, filename, extension, uploaded_at, file_hash, ip_address, delete_key original_filename, filename, extension, uploaded_at, file_hash, ip_address, delete_key
end end
end end
env.response.content_type = "application/json"
if !filename.empty? if !filename.empty?
JSON.build do |j| JSON.build do |j|
j.object do j.object do
@ -44,57 +66,32 @@ module Handling
end end
end end
else else
env.response.content_type = "application/json" error403("No file")
env.response.status_code = 403
error_message = {"error" => "No file"}.to_json
error_message
end end
end end
def retrieve_file(env) def retrieve_file(env)
begin filename = SQL.query_one "SELECT filename FROM files WHERE filename = ?", env.params.url["filename"].to_s.split(".").first, as: String
if !File.extname(env.params.url["filename"]).empty? extension = SQL.query_one "SELECT extension FROM files WHERE filename = ?", filename, as: String
send_file env, "#{CONFIG.files}/#{env.params.url["filename"]}" send_file env, "#{CONFIG.files}/#{filename}#{extension}"
# next
end
dir = Dir.new("#{CONFIG.files}")
dir.each do |filename|
if filename.starts_with?("#{env.params.url["filename"]}")
send_file env, "#{CONFIG.files}/#{env.params.url["filename"]}" + File.extname(filename)
end
end
raise ""
rescue
env.response.content_type = "text/plain"
env.response.status_code = 403
return "File does not exist"
end
end end
def stats(env) def stats(env)
begin env.response.content_type = "application/json"
dir = Dir.new("#{CONFIG.files}")
rescue
env.response.content_type = "text/plain"
env.response.status_code = 403
return "Unknown error"
end
json_data = JSON.build do |json| json_data = JSON.build do |json|
json.object do json.object do
json.field "stats" do json.field "stats" do
json.object do json.object do
begin begin
json.field "filesHosted", dir.children.size json.field "filesHosted", SQL.query_one "SELECT COUNT (filename) FROM files", as: Int32
json.field "maxUploadSize", CONFIG.size_limit
rescue rescue
json.field "filesHosted", 0 json.field "error", "Unknown error"
end end
end end
end end
end end
end end
dir.close
env.response.content_type = "application/json"
json_data json_data
end end
@ -105,18 +102,12 @@ module Handling
file_extension = SQL.query_one "SELECT extension FROM files WHERE delete_key = ?", env.params.query["key"], as: String file_extension = SQL.query_one "SELECT extension FROM files WHERE delete_key = ?", env.params.query["key"], as: String
File.delete("#{CONFIG.files}/#{file_to_delete}#{file_extension}") File.delete("#{CONFIG.files}/#{file_to_delete}#{file_extension}")
SQL.exec "DELETE FROM files WHERE delete_key = ?", env.params.query["key"] SQL.exec "DELETE FROM files WHERE delete_key = ?", env.params.query["key"]
env.response.content_type = "application/json" msg("File deleted successfully")
error_message = {"message" => "File deleted successfully"}.to_json rescue ex
error_message error403("Unknown error: #{ex.message}")
rescue
env.response.content_type = "application/json"
env.response.status_code = 403
end end
else else
env.response.content_type = "application/json" error403("Huh? This delete key doesn't exist")
env.response.status_code = 403
error_message = {"error" => "Huh? This delete key doesn't exist"}.to_json
error_message
end end
end end
end end