0.9.3.4: Fix what I did yesterday
All checks were successful
File-uploader-crystal CI / build (push) Successful in 1m49s

This commit is contained in:
Fijxu 2024-11-21 13:30:19 -03:00
parent cb75b97520
commit bb9ecee67b
Signed by: Fijxu
GPG key ID: 32C1DDF333EDA6A4
4 changed files with 64 additions and 81 deletions

View file

@ -37,7 +37,7 @@ module Handling::Admin
failed_files << file failed_files << file
rescue ex rescue ex
LOGGER.error "Unknown error: #{ex.message}" LOGGER.error "Unknown error: #{ex.message}"
error500 "Unknown error: #{ex.message}" http_error 500,"Unknown error: #{ex.message}"
end end
end end
json = JSON.build do |j| json = JSON.build do |j|
@ -69,7 +69,7 @@ module Handling::Admin
failed << item failed << item
rescue ex rescue ex
LOGGER.error "Unknown error: #{ex.message}" LOGGER.error "Unknown error: #{ex.message}"
error500 "Unknown error: #{ex.message}" http_error 500, "Unknown error: #{ex.message}"
end end
end end
json = JSON.build do |j| json = JSON.build do |j|
@ -107,7 +107,7 @@ module Handling::Admin
failed << item failed << item
rescue ex rescue ex
LOGGER.error "Unknown error: #{ex.message}" LOGGER.error "Unknown error: #{ex.message}"
error500 "Unknown error: #{ex.message}" http_error 500,"Unknown error: #{ex.message}"
end end
end end
json = JSON.build do |j| json = JSON.build do |j|

View file

@ -18,7 +18,7 @@ module Handling
# which is inspecting the file directly (If I'm not wrong). # which is inspecting the file directly (If I'm not wrong).
if CONFIG.size_limit > 0 if CONFIG.size_limit > 0
if env.request.headers["Content-Length"].to_i > 1048576*CONFIG.size_limit if env.request.headers["Content-Length"].to_i > 1048576*CONFIG.size_limit
return error413("File is too big. The maximum size allowed is #{CONFIG.size_limit}MiB") return http_error 413, "File is too big. The maximum size allowed is #{CONFIG.size_limit}MiB"
end end
end end
filename = "" filename = ""
@ -33,13 +33,13 @@ module Handling
HTTP::FormData.parse(env.request) do |upload| HTTP::FormData.parse(env.request) do |upload|
if upload.filename.nil? || upload.filename.to_s.empty? if upload.filename.nil? || upload.filename.to_s.empty?
LOGGER.debug "No file provided by the user" LOGGER.debug "No file provided by the user"
return error403("No file provided") return http_error 403, "No file provided"
end end
# TODO: upload.body is emptied when is copied or read # TODO: upload.body is emptied when is copied or read
# Utils.check_duplicate(upload.dup) # Utils.check_duplicate(upload.dup)
extension = File.extname("#{upload.filename}") extension = File.extname("#{upload.filename}")
if CONFIG.blockedExtensions.includes?(extension.split(".")[1]) if CONFIG.blockedExtensions.includes?(extension.split(".")[1])
return error401("Extension '#{extension}' is not allowed") return http_error 401, "Extension '#{extension}' is not allowed"
end end
filename = Utils.generate_filename filename = Utils.generate_filename
file_path = "#{CONFIG.files}/#{filename}#{extension}" file_path = "#{CONFIG.files}/#{filename}#{extension}"
@ -70,7 +70,7 @@ module Handling
SQL.exec "UPDATE ips SET count = count + 1 WHERE ip = ('#{ip_address}')" SQL.exec "UPDATE ips SET count = count + 1 WHERE ip = ('#{ip_address}')"
rescue ex rescue ex
LOGGER.error "An error ocurred when trying to insert the data into the DB: #{ex.message}" LOGGER.error "An error ocurred when trying to insert the data into the DB: #{ex.message}"
return error500("An error ocurred when trying to insert the data into the DB") return http_error 500, "An error ocurred when trying to insert the data into the DB"
end end
json = JSON.build do |j| json = JSON.build do |j|
j.object do j.object do
@ -99,10 +99,10 @@ module Handling
files = env.params.json["files"].as((Array(JSON::Any))) files = env.params.json["files"].as((Array(JSON::Any)))
rescue ex : JSON::ParseException rescue ex : JSON::ParseException
LOGGER.error "Body malformed: #{ex.message}" LOGGER.error "Body malformed: #{ex.message}"
return error400 "Body malformed: #{ex.message}" return http_error 400, "Body malformed: #{ex.message}"
rescue ex rescue ex
LOGGER.error "Unknown error: #{ex.message}" LOGGER.error "Unknown error: #{ex.message}"
return error500 "Unknown error" return http_error 500, "Unknown error"
end end
successfull_files = [] of NamedTuple(filename: String, extension: String, original_filename: String, checksum: String, delete_key: String | Nil) successfull_files = [] of NamedTuple(filename: String, extension: String, original_filename: String, checksum: String, delete_key: String | Nil)
failed_files = [] of String failed_files = [] of String
@ -127,7 +127,7 @@ module Handling
end end
rescue ex rescue ex
LOGGER.debug "Failed to download file '#{url}': #{ex.message}" LOGGER.debug "Failed to download file '#{url}': #{ex.message}"
return error403("Failed to download file '#{url}'") return http_error 403, "Failed to download file '#{url}'"
failed_files << url failed_files << url
end end
end end
@ -158,7 +158,7 @@ module Handling
checksum: checksum} checksum: checksum}
rescue ex rescue ex
LOGGER.error "An error ocurred when trying to insert the data into the DB: #{ex.message}" LOGGER.error "An error ocurred when trying to insert the data into the DB: #{ex.message}"
return error500("An error ocurred when trying to insert the data into the DB") return http_error 500, "An error ocurred when trying to insert the data into the DB"
end end
end end
json = JSON.build do |j| json = JSON.build do |j|
@ -212,7 +212,7 @@ module Handling
end end
rescue ex rescue ex
LOGGER.debug "Failed to download file '#{url}': #{ex.message}" LOGGER.debug "Failed to download file '#{url}': #{ex.message}"
return error403("Failed to download file '#{url}': #{ex.message}") return http_error 403, "Failed to download file '#{url}': #{ex.message}"
failed_files << url failed_files << url
end end
end end
@ -241,7 +241,7 @@ module Handling
checksum: checksum} checksum: checksum}
rescue ex rescue ex
LOGGER.error "An error ocurred when trying to insert the data into the DB: #{ex.message}" LOGGER.error "An error ocurred when trying to insert the data into the DB: #{ex.message}"
return error500("An error ocurred when trying to insert the data into the DB") return http_error 500, "An error ocurred when trying to insert the data into the DB"
end end
json = JSON.build do |j| json = JSON.build do |j|
j.array do j.array do
@ -266,25 +266,30 @@ module Handling
end end
def retrieve_file(env) def retrieve_file(env)
protocol = Utils.protocol(env)
host = Utils.host(env)
begin begin
protocol = Utils.protocol(env)
host = Utils.host(env)
fileinfo = SQL.query_one?("SELECT filename, original_filename, uploaded_at, extension, checksum, thumbnail fileinfo = SQL.query_one?("SELECT filename, original_filename, uploaded_at, extension, checksum, thumbnail
FROM files FROM files
WHERE filename = ?", WHERE filename = ?",
env.params.url["filename"].split(".").first, env.params.url["filename"].split(".").first,
as: {filename: String, ofilename: String, up_at: String, ext: String, checksum: String, thumbnail: String | Nil}) as: {filename: String, ofilename: String, up_at: String, ext: String, checksum: String, thumbnail: String | Nil})
if fileinfo.nil? if fileinfo.nil?
return error404("File '#{env.params.url["filename"]}' does not exist") # TODO: Switch this to 404, if I use 404, it will use the kemal error page (ANOYING!)
return http_error 418, "File '#{env.params.url["filename"]}' does not exist"
end end
env.response.headers["Content-Disposition"] = "inline; filename*=UTF-8''#{fileinfo[:ofilename]}" rescue ex
# env.response.headers["Last-Modified"] = "#{fileinfo[:up_at]}" LOGGER.debug "Error when retrieving file '#{env.params.url["filename"]}': #{ex.message}"
env.response.headers["ETag"] = "#{fileinfo[:checksum]}" return http_error 500, "Error when retrieving file '#{env.params.url["filename"]}'"
end
env.response.headers["Content-Disposition"] = "inline; filename*=UTF-8''#{fileinfo[:ofilename]}"
# env.response.headers["Last-Modified"] = "#{fileinfo[:up_at]}"
env.response.headers["ETag"] = "#{fileinfo[:checksum]}"
CONFIG.opengraphUseragents.each do |useragent| CONFIG.opengraphUseragents.each do |useragent|
if env.request.headers.try &.["User-Agent"].includes?(useragent) if env.request.headers.try &.["User-Agent"].includes?(useragent)
env.response.content_type = "text/html" env.response.content_type = "text/html"
return %( return %(
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
@ -297,13 +302,9 @@ module Handling
</head> </head>
</html> </html>
) )
end
end end
send_file env, "#{CONFIG.files}/#{fileinfo[:filename]}#{fileinfo[:ext]}"
rescue ex
LOGGER.debug "Error when retrieving file '#{env.params.url["filename"]}': #{ex.message}"
return error500("Error when retrieving file '#{env.params.url["filename"]}'")
end end
send_file env, "#{CONFIG.files}/#{fileinfo[:filename]}#{fileinfo[:ext]}"
end end
def retrieve_thumbnail(env) def retrieve_thumbnail(env)
@ -311,7 +312,7 @@ module Handling
send_file env, "#{CONFIG.thumbnails}/#{env.params.url["thumbnail"]}" send_file env, "#{CONFIG.thumbnails}/#{env.params.url["thumbnail"]}"
rescue ex rescue ex
LOGGER.debug "Thumbnail '#{env.params.url["thumbnail"]}' does not exist: #{ex.message}" LOGGER.debug "Thumbnail '#{env.params.url["thumbnail"]}' does not exist: #{ex.message}"
return error403("Thumbnail '#{env.params.url["thumbnail"]}' does not exist") return http_error 403, "Thumbnail '#{env.params.url["thumbnail"]}' does not exist"
end end
end end
@ -333,7 +334,7 @@ module Handling
end end
rescue ex rescue ex
LOGGER.error "Unknown error: #{ex.message}" LOGGER.error "Unknown error: #{ex.message}"
return error500("Unknown error") return http_error 500, "Unknown error"
end end
json_data json_data
end end
@ -359,11 +360,11 @@ module Handling
return msg("File '#{fileinfo[:filename]}' deleted successfully") return msg("File '#{fileinfo[:filename]}' deleted successfully")
rescue ex rescue ex
LOGGER.error("Unknown error: #{ex.message}") LOGGER.error("Unknown error: #{ex.message}")
return error500("Unknown error") return http_error 500, "Unknown error"
end end
else else
LOGGER.debug "Key '#{env.params.query["key"]}' does not exist" LOGGER.debug "Key '#{env.params.query["key"]}' does not exist"
return error401("Delete key '#{env.params.query["key"]}' does not exist. No files were deleted") return http_error 401, "Delete key '#{env.params.query["key"]}' does not exist. No files were deleted"
end end
end end

View file

@ -1,34 +1,10 @@
macro http_error(status_code, message) macro http_error(status_code, message)
env.response.content_type = "application/json" env.response.content_type = "application/json"
env.response.status_code = {{status_code}} env.response.status_code = {{status_code}}
error_message = {"error" => {{message}}}.to_json error_message = {"error" => {{message}}}.to_json
error_message error_message
end end
macro error400(message)
http_error(400, {{message}})
end
macro error401(message)
http_error(401, {{message}})
end
macro error403(message)
http_error(403, {{message}})
end
macro error404(message)
http_error(404, {{message}})
end
macro error413(message)
http_error(413, {{message}})
end
macro error500(message)
http_error(500, {{message}})
end
macro msg(message) 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

View file

@ -12,7 +12,31 @@ module Routing
before_post "/api/admin/*" do |env| before_post "/api/admin/*" do |env|
if env.request.headers.try &.["X-Api-Key"]? != CONFIG.adminApiKey || nil if env.request.headers.try &.["X-Api-Key"]? != CONFIG.adminApiKey || nil
halt env, status_code: 401, response: error401("Wrong API Key") halt env, status_code: 401, response: http_error 401, "Wrong API Key"
end
end
before_post "/upload" do |env|
begin
ip_info = SQL.query_one?("SELECT ip, count, date FROM ips WHERE ip = ?", Utils.ip_address(env), as: {ip: String, count: Int32, date: Int32})
rescue ex
LOGGER.error "Error when trying to enforce rate limits: #{ex.message}"
next
end
if ip_info.nil?
next
end
time_since_first_upload = Time.utc.to_unix - ip_info[:date]
time_until_unban = ip_info[:date] - Time.utc.to_unix + CONFIG.rateLimitPeriod
if time_since_first_upload > CONFIG.rateLimitPeriod
SQL.exec "DELETE FROM ips WHERE ip = ?", ip_info[:ip]
end
if CONFIG.filesPerIP > 0
if ip_info[:count] >= CONFIG.filesPerIP && time_since_first_upload < CONFIG.rateLimitPeriod
halt env, status_code: 401, response: http_error 401, "Rate limited! Try again in #{time_until_unban} seconds"
end
end end
end end
@ -22,7 +46,7 @@ module Routing
next next
end end
if CONFIG.blockTorAddresses && @@exit_nodes.includes?(Utils.ip_address(env)) if CONFIG.blockTorAddresses && @@exit_nodes.includes?(Utils.ip_address(env))
halt env, status_code: 401, response: error401(CONFIG.torMessage) halt env, status_code: 401, response: http_error 401, CONFIG.torMessage
end end
end end
@ -40,28 +64,6 @@ module Routing
end end
post "/upload" do |env| post "/upload" do |env|
begin
ip_info = SQL.query_one?("SELECT ip, count, date FROM ips WHERE ip = ?", Utils.ip_address(env), as: {ip: String, count: Int32, date: Int32})
rescue ex
LOGGER.error "Error when trying to enforce rate limits: #{ex.message}"
next
end
if ip_info.nil?
next
end
time_since_first_upload = Time.utc.to_unix - ip_info[:date]
time_until_unban = ip_info[:date] - Time.utc.to_unix + CONFIG.rateLimitPeriod
if time_since_first_upload > CONFIG.rateLimitPeriod
SQL.exec "DELETE FROM ips WHERE ip = ?", ip_info[:ip]
end
if CONFIG.filesPerIP > 0
if ip_info[:count] >= CONFIG.filesPerIP && time_since_first_upload < CONFIG.rateLimitPeriod
halt env, status_code: 401, response: error401("Rate limited! Try again in #{time_until_unban} seconds")
end
end
Handling.upload(env) Handling.upload(env)
end end
@ -122,4 +124,8 @@ module Routing
get "/api/admin/torexitnodes" do |env| get "/api/admin/torexitnodes" do |env|
Handling::Admin.retrieve_tor_exit_nodes(env, @@exit_nodes) Handling::Admin.retrieve_tor_exit_nodes(env, @@exit_nodes)
end end
error 404 do
"File not found"
end
end end