diff --git a/lib/volumen/admin_routes.rb b/lib/volumen/admin_routes.rb index 5d1708e..59a555c 100644 --- a/lib/volumen/admin_routes.rb +++ b/lib/volumen/admin_routes.rb @@ -92,6 +92,12 @@ module Volumen halt(413, json("error" => "file_too_large", "max_bytes" => Server::MAX_UPLOAD_BYTES)) end + content_type_str = upload[:type].to_s.split(";").first.to_s.strip.downcase + unless Server::ALLOWED_UPLOAD_TYPES.include?(content_type_str) + halt(415, json("error" => "unsupported_media_type", + "allowed" => Server::ALLOWED_UPLOAD_TYPES)) + end + json("url" => store.store_upload(upload[:filename], upload[:tempfile])) end diff --git a/lib/volumen/server.rb b/lib/volumen/server.rb index 8d252dd..d9d4c0b 100644 --- a/lib/volumen/server.rb +++ b/lib/volumen/server.rb @@ -18,6 +18,9 @@ module Volumen MAX_LOGIN_ATTEMPTS = 10 LOGIN_WINDOW = 60 # seconds MAX_UPLOAD_BYTES = 10 * 1024 * 1024 # 10 MB + ALLOWED_UPLOAD_TYPES = %w[ + image/jpeg image/png image/gif image/webp image/avif image/svg+xml + ].freeze SLUG_REGEX = /\A[a-z0-9](?:[a-z0-9._-]*[a-z0-9])?\z/ register ApiRoutes diff --git a/test/admin_test.rb b/test/admin_test.rb index 9fe2c2e..f342129 100644 --- a/test/admin_test.rb +++ b/test/admin_test.rb @@ -124,6 +124,19 @@ class AdminTest < Minitest::Test assert_equal 403, last_response.status end + def test_upload_rejects_unsupported_media_type + login + get "/admin/posts/new" + token = csrf(last_response.body) + txt_path = File.join(@dir, "readme.txt") + File.binwrite(txt_path, "hello") + post "/admin/uploads", + "_csrf" => token, + "file" => Rack::Test::UploadedFile.new(txt_path, "text/plain") + assert_equal 415, last_response.status + assert_equal "unsupported_media_type", JSON.parse(last_response.body)["error"] + end + def test_upload_rejects_file_too_large login get "/admin/posts/new"