From 4803700cab92dc7a54bee4090dc2e92eb70ade7f Mon Sep 17 00:00:00 2001 From: Fijxu Date: Wed, 11 Sep 2024 01:50:17 -0300 Subject: [PATCH] 0.9.1: Upload file from URL with GET request --- README.md | 4 +- src/file-uploader-crystal.cr | 1 + src/handling/handling.cr | 89 +++++++++++++++++++++++++++++++++++- src/routing.cr | 8 +++- 4 files changed, 97 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 1f826ef..76b35b3 100644 --- a/README.md +++ b/README.md @@ -83,4 +83,6 @@ WantedBy=default.target - Dockerfile and Docker image (Crystal doesn't has dependency hell like other languages so is not really necessary to do, but useful for people that want instant deploy) - Custom file expiration using headers (Like rustypaste) - Small CLI to upload files (like `rpaste` from rustypaste) -- Add more endpoints to Admin API \ No newline at end of file +- Add more endpoints to Admin API + +- diff --git a/src/file-uploader-crystal.cr b/src/file-uploader-crystal.cr index d775fb6..6a293b1 100644 --- a/src/file-uploader-crystal.cr +++ b/src/file-uploader-crystal.cr @@ -32,6 +32,7 @@ CURRENT_TAG = {{ "#{`git describe --long --abbrev=7 --tags | sed 's/([^-]*)- Utils.check_dependencies Utils.create_db Utils.create_files_dir +Utils.create_thumbnails_dir Routing.register_all Utils.delete_socket diff --git a/src/handling/handling.cr b/src/handling/handling.cr index 13260d5..0ddd0ce 100644 --- a/src/handling/handling.cr +++ b/src/handling/handling.cr @@ -83,8 +83,7 @@ module Handling end # The most unoptimized and unstable feature lol - # TODO: Support batch upload via JSON array - def upload_url(env) + def upload_url_bulk(env) env.response.content_type = "application/json" ip_address = Utils.ip_address(env) protocol = Utils.protocol(env) @@ -169,6 +168,92 @@ module Handling json end + # TODO: Add delete url, same for upload_url_bulk + def upload_url(env) + env.response.content_type = "application/json" + ip_address = Utils.ip_address(env) + protocol = Utils.protocol(env) + host = Utils.host(env) + url = env.params.query["url"] + successfull_files = [] of NamedTuple(filename: String, extension: String, original_filename: String, checksum: String, delete_key: String | Nil) + failed_files = [] of String + # X-Forwarded-For if behind a reverse proxy and the header is set in the reverse + # proxy configuration. + if url.empty? + end + # files.each do |url| + url = url.to_s + filename = Utils.generate_filename + original_filename = "" + extension = "" + checksum = "" + uploaded_at = Time.utc + extension = File.extname(URI.parse(url).path) + delete_key = nil + file_path = ::File.join ["#{CONFIG.files}", filename + extension] + File.open(file_path, "w") do |output| + begin + HTTP::Client.get(url) do |res| + IO.copy(res.body_io, output) + end + rescue ex + LOGGER.debug "Failed to download file '#{url}': #{ex.message}" + return error403("Failed to download file '#{url}'") + failed_files << url + end + end + # successfull_files << url + # end + if extension.empty? + extension = Utils.detect_extension(file_path) + File.rename(file_path, file_path + extension) + file_path = ::File.join ["#{CONFIG.files}", filename + extension] + end + # The second one is faster and it uses less memory + # original_filename = URI.parse("https://ayaya.beauty/PqC").path.split("/").last + original_filename = url.split("/").last + checksum = Utils.hash_file(file_path) + begin + spawn { Utils.generate_thumbnail(filename, extension) } + rescue ex + LOGGER.error "An error ocurred when trying to generate a thumbnail: #{ex.message}" + end + begin + # Insert SQL data just before returning the upload information + SQL.exec("INSERT INTO #{CONFIG.dbTableName} VALUES (?, ?, ?, ?, ?, ?, ?, ?)", + original_filename, filename, extension, uploaded_at, checksum, ip_address, delete_key, nil) + successfull_files << {filename: filename, + original_filename: original_filename, + extension: extension, + delete_key: delete_key, + checksum: checksum} + rescue ex + 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") + end + # end + json = JSON.build do |j| + j.array do + successfull_files.each do |fileinfo| + j.object do + j.field "link", "#{protocol}://#{host}/#{fileinfo[:filename]}" + j.field "linkExt", "#{protocol}://#{host}/#{fileinfo[:filename]}#{fileinfo[:extension]}" + j.field "id", fileinfo[:filename] + j.field "ext", fileinfo[:extension] + j.field "name", fileinfo[:original_filename] + j.field "checksum", fileinfo[:checksum] + if CONFIG.deleteKeyLength > 0 + delete_key = Random.base58(CONFIG.deleteKeyLength) + j.field "deleteKey", fileinfo[:delete_key] + j.field "deleteLink", "#{protocol}://#{host}/delete?key=#{fileinfo[:delete_key]}" + end + end + end + end + end + json + end + def retrieve_file(env) begin protocol = Utils.protocol(env) diff --git a/src/routing.cr b/src/routing.cr index 384d350..b458819 100644 --- a/src/routing.cr +++ b/src/routing.cr @@ -54,10 +54,14 @@ module Routing Handling.upload(env) end - post "/api/uploadurl" do |env| + get "/upload" do |env| Handling.upload_url(env) end + post "/api/uploadurl" do |env| + Handling.upload_url_bulk(env) + end + get "/:filename" do |env| Handling.retrieve_file(env) end @@ -100,7 +104,7 @@ module Routing Handling::Admin.retrieve_file_info(env) end - get "/api/admin/torexitnodes" do |env| + get "/api/admin/torexitnodes" do |env| Handling::Admin.retrieve_tor_exit_nodes(env, @@exit_nodes) end end