Compare commits

..

3 commits

Author SHA1 Message Date
7cc2ad9117
chore: use Database::Files.file_count to get the files hosted count
All checks were successful
File-uploader-crystal CI / build (push) Successful in 2m40s
2025-04-28 18:01:41 -04:00
44d7afddfc
fix: select all fields on a row for old_files 2025-04-28 18:01:00 -04:00
c0f73bab0a
chore: change the name of properties inside the config class 2025-04-28 17:59:37 -04:00
10 changed files with 65 additions and 62 deletions

View file

@ -7,32 +7,32 @@ thumbnails: "./thumbnails"
db: "./db.sqlite3"
# Tor
blockTorAddresses: true
torExitNodesCheck: 1600
torExitNodesUrl: "https://check.torproject.org/exit-addresses"
torMessage: "TOR IS BLOCKED!"
block_tor_addresses: true
tor_exit_nodes_check: 1600
tor_exit_nodes_url: "https://check.torproject.org/exit-addresses"
tor_message: "TOR IS BLOCKED!"
generate_thumbnails: true
adminEnabled: true
adminApiKey: "asd"
admin_enabled: true
admin_api_key: "asd"
size_limit: 512
enable_checksums: false
port: 8080
filesPerIP: 2
rateLimitPeriod: 20
rateLimitMessage: ""
files_per_ip: 2
rate_limit_period: 20
rate_limit_message: ""
filename_length: 3
deleteFilesAfter: 7
deleteFilesCheck: 1800
deleteKeyLength: 4
delete_files_after: 7
delete_files_check: 1800
delete_key_length: 4
siteInfo: "Whatever you want to put here"
siteWarning: "WARNING!"
site_info: "Whatever you want to put here"
site_warning: "WARNING!"
blockedExtensions:
blocked_extensions:
- "exe"
opengraphUseragents:
opengraph_useragents:
- "chatterino-api-cache/"
- "FFZBot/"
- "Twitterbot/"

View file

@ -23,10 +23,10 @@ class Config
property db : String = "./db.sqlite3"
# Enable or disable the admin API
property adminEnabled : Bool = false
property admin_enabled : Bool = false
# The API key for admin routes. It's passed as a "X-Api-Key" header to the
# request
property adminApiKey : String? = nil
property admin_api_key : String? = nil
# Not implemented
property incrementalfilename_length : Bool = true
@ -42,43 +42,43 @@ class Config
# True if you want this program to block IP addresses coming from the Tor
# network
property blockTorAddresses : Bool = false
property block_tor_addresses : Bool = false
# How often (in seconds) should this program download the exit nodes list
property torExitNodesCheck : Int32 = 3600
property tor_exit_nodes_check : Int32 = 3600
# Only https://check.torproject.org/exit-addresses is supported
property torExitNodesUrl : String = "https://check.torproject.org/exit-addresses"
property tor_exit_nodes_url : String = "https://check.torproject.org/exit-addresses"
# Message that will be displayed to the Tor user.
# It will be shown on the Frontend and shown in the error 401 when a user
# tries to upload a file using curl or any other tool
property torMessage : String? = "Tor is blocked!"
property tor_message : String? = "Tor is blocked!"
# How many files an IP address can upload to the server. Setting this to 0
# disables rate limits
property filesPerIP : Int32 = 32
# disables rate limits in the rate limit period
property files_per_ip : Int32 = 32
# How often is the file limit per IP reset? (in seconds)
property rateLimitPeriod : Int32 = 600
property rate_limit_period : Int32 = 600
# TODO: UNUSED CONSTANT
property rateLimitMessage : String = ""
property rate_limit_message : String = ""
# Delete the files after how many days?
property deleteFilesAfter : Int32 = 14
property delete_files_after : Int32 = 14
# How often should the check of old files be performed? (in seconds)
property deleteFilesCheck : Int32 = 1800
property delete_files_check : Int32 = 1800
# The lenght of the delete key
property deleteKeyLength : Int32 = 6
property delete_key_length : Int32 = 6
property siteInfo : String = "xd"
property site_info : String = "xd"
# TODO: UNUSED CONSTANT
property siteWarning : String? = ""
property site_warning : String? = ""
# Blocked extensions that are not allowed to be uploaded to the server
property blockedExtensions : Array(String) = [] of String
property blocked_extensions : Array(String) = [] of String
# A list of OpenGraph user agents. If the request contains one of those User
# agents when trying to retrieve a file from the server; the server will
# reply with an HTML with OpenGraph tags, pointing to the media thumbnail
# (if it was generated successfully) and the name of the file as title
property opengraphUseragents : Array(String) = [] of String
property opengraph_useragents : Array(String) = [] of String
# Since this program detects the Host header of the client it can be used
# with multiple domains. You can display the domains in the frontend

View file

@ -64,9 +64,9 @@ module Database::Files
def old_files : Array(UFile)
request = <<-SQL
SELECT filename, extension, thumbnail
SELECT *
FROM files
WHERE uploaded_at < strftime('%s', 'now') - #{CONFIG.deleteFilesAfter * 3600}
WHERE uploaded_at < strftime('%s', 'now') - #{CONFIG.delete_files_after * 3600}
SQL
SQL.query_all(request, as: UFile)

View file

@ -1,27 +1,27 @@
# Pretty cool way to write background jobs! :)
module Jobs
def self.check_old_files
if CONFIG.deleteFilesCheck <= 0
if CONFIG.delete_files_check <= 0
LOGGER.info "File deletion is disabled"
return
end
spawn do
loop do
Utils.check_old_files
sleep CONFIG.deleteFilesCheck.seconds
sleep CONFIG.delete_files_check.seconds
end
end
end
def self.retrieve_tor_exit_nodes
if !CONFIG.blockTorAddresses
if !CONFIG.block_tor_addresses
return
end
LOGGER.info("Blocking Tor exit nodes")
spawn do
loop do
Utils::Tor.refresh_exit_nodes
sleep CONFIG.torExitNodesCheck.seconds
sleep CONFIG.tor_exit_nodes_check.seconds
end
end
end

View file

@ -18,7 +18,7 @@ module Routing::Misc
property alternative_domains : Array(String)
def initialize
@files_hosted = SQL.query_one("SELECT COUNT (filename) FROM files", as: Int32)
@files_hosted = Database::Files.file_count
@max_upload_size = CONFIG.size_limit.to_s
@thumbnail_generation = CONFIG.generate_thumbnails
@filename_length = CONFIG.filename_length

View file

@ -20,21 +20,19 @@ module Routes::Retrieve
env.response.headers["Content-Disposition"] = "inline; filename*=UTF-8''#{file.original_filename}"
env.response.headers["ETag"] = "#{file.checksum}"
CONFIG.opengraphUseragents.each do |useragent|
CONFIG.opengraph_useragents.each do |useragent|
env.response.content_type = "text/html"
if env.request.headers["User-Agent"]?.try &.includes?(useragent)
return %(
<!DOCTYPE html>
return %(<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta property="og:title" content="#{file.filename}">
<meta property="og:title" content="#{file.original_filename}">
<meta property="og:url" content="#{scheme}://#{host}/#{file.filename}">
#{%(<meta property="og:image" content="#{scheme}://#{host}/thumbnail/#{file.filename}.jpg">) if file.thumbnail}
</head>
</html>
)
</html>)
end
end
send_file env, "#{CONFIG.files}/#{file.filename}#{file.extension}"

View file

@ -58,12 +58,17 @@ module Routes::Upload
ee 403, "No file provided"
end
file.extension = File.extname("#{upload.filename}")
file.filename = Utils.generate_filename
if file.original_filename == "control_v.png"
file.original_filename = file.filename
end
file.extension = File.extname("#{upload.filename}")
full_filename = file.filename + file.extension
file_path = "#{CONFIG.files}/#{full_filename}"
if CONFIG.blockedExtensions.includes?(file.extension.split(".")[1])
if CONFIG.blocked_extensions.includes?(file.extension.split(".")[1])
ee 401, "Extension '#{file.extension}' is not allowed"
end
@ -82,8 +87,8 @@ module Routes::Upload
ip.ip = file.ip
ip.date = file.uploaded_at
if CONFIG.deleteKeyLength > 0
file.delete_key = Random.base58(CONFIG.deleteKeyLength)
if CONFIG.delete_key_length > 0
file.delete_key = Random.base58(CONFIG.delete_key_length)
end
begin

View file

@ -21,7 +21,7 @@ module Routing
# before_post "/api/admin/*" do |env|
# env.response.content_type = "application/json"
# if env.request.headers.try &.["X-Api-Key"]? != CONFIG.adminApiKey || nil
# if env.request.headers.try &.["X-Api-Key"]? != CONFIG.admin_api_key || nil
# halt env, status_code: 401, response: "Wrong API Key"
# end
# end
@ -31,12 +31,12 @@ module Routing
api_key = env.request.headers["X-Api-Key"]?
# Skips Tor blocking and Rate limits if the API key matches
if api_key == CONFIG.adminApiKey
if api_key == CONFIG.admin_api_key
next
end
if CONFIG.blockTorAddresses && tor_exit_nodes.includes?(Headers.ip_addr)
halt env, status_code: 401, response: CONFIG.torMessage
if CONFIG.block_tor_addresses && tor_exit_nodes.includes?(Headers.ip_addr)
halt env, status_code: 401, response: CONFIG.tor_message
end
end
@ -52,15 +52,15 @@ module Routing
next
end
if CONFIG.filesPerIP > 0
if CONFIG.files_per_ip > 0
time_since_first_upload = Time.utc.to_unix - ip_info.date
time_until_unban = ip_info.date - Time.utc.to_unix + CONFIG.rateLimitPeriod
time_until_unban = ip_info.date - Time.utc.to_unix + CONFIG.rate_limit_period
if time_since_first_upload > CONFIG.rateLimitPeriod
if time_since_first_upload > CONFIG.rate_limit_period
Database::IP.delete(ip_info.ip)
end
if ip_info.count >= CONFIG.filesPerIP && time_since_first_upload < CONFIG.rateLimitPeriod
if ip_info.count >= CONFIG.files_per_ip && time_since_first_upload < CONFIG.rate_limit_period
halt env, status_code: 401, response: "Rate limited! Try again in #{time_until_unban} seconds"
end
end
@ -81,7 +81,7 @@ module Routing
get "/info/sharex.sxcu", Routing::Misc, :sharex_config
get "/info/chatterinoconfig", Routing::Misc, :chatterino_config
# if CONFIG.adminEnabled
# if CONFIG.admin_enabled
# self.register_admin
# end
end

View file

@ -12,7 +12,7 @@ module Utils::Tor
LOGGER.debug "retrieve_tor_exit_nodes: Retrieving Tor exit nodes list"
ips = [] of String
HTTP::Client.get(CONFIG.torExitNodesUrl) do |res|
HTTP::Client.get(CONFIG.tor_exit_nodes_url) do |res|
begin
if res.success? && res.status_code == 200
res.body_io.each_line do |line|
@ -25,7 +25,7 @@ module Utils::Tor
LOGGER.error "retrieve_tor_exit_nodes: Failed to retrieve exit nodes list. Status Code: #{res.status_code}"
end
rescue ex : Socket::ConnectError
LOGGER.error "retrieve_tor_exit_nodes: Failed to connect to #{CONFIG.torExitNodesUrl}: #{ex.message}"
LOGGER.error "retrieve_tor_exit_nodes: Failed to connect to #{CONFIG.tor_exit_nodes_url}: #{ex.message}"
rescue ex
LOGGER.error "retrieve_tor_exit_nodes: Unknown error: #{ex.message}"
end

View file

@ -11,7 +11,7 @@
<body>
<div class="container">
<h1 style="font-size: 68px; 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.site_info %></p>
<div id="drop-area">
<p style='padding: 0;margin: 0; color: #123718bf;'>Arrastra, Pega o Selecciona archivos.</p>
<input type="file" id="fileElem" accept="*/*" style="display: none;">