summaryrefslogtreecommitdiff
path: root/app/controllers/concerns/send_file_upload.rb
diff options
context:
space:
mode:
Diffstat (limited to 'app/controllers/concerns/send_file_upload.rb')
-rw-r--r--app/controllers/concerns/send_file_upload.rb38
1 files changed, 32 insertions, 6 deletions
diff --git a/app/controllers/concerns/send_file_upload.rb b/app/controllers/concerns/send_file_upload.rb
index 7cb19fc7e58..2f06cd84ee5 100644
--- a/app/controllers/concerns/send_file_upload.rb
+++ b/app/controllers/concerns/send_file_upload.rb
@@ -2,6 +2,8 @@
module SendFileUpload
def send_upload(file_upload, send_params: {}, redirect_params: {}, attachment: nil, proxy: false, disposition: 'attachment')
+ content_type = content_type_for(attachment)
+
if attachment
response_disposition = ActionDispatch::Http::ContentDisposition.format(disposition: disposition, filename: attachment)
@@ -9,7 +11,7 @@ module SendFileUpload
# Google Cloud Storage, so the metadata needs to be cleared on GCS for
# this to work. However, this override works with AWS.
redirect_params[:query] = { "response-content-disposition" => response_disposition,
- "response-content-type" => guess_content_type(attachment) }
+ "response-content-type" => content_type }
# By default, Rails will send uploads with an extension of .js with a
# content-type of text/javascript, which will trigger Rails'
# cross-origin JavaScript protection.
@@ -20,7 +22,7 @@ module SendFileUpload
if image_scaling_request?(file_upload)
location = file_upload.file_storage? ? file_upload.path : file_upload.url
- headers.store(*Gitlab::Workhorse.send_scaled_image(location, params[:width].to_i))
+ headers.store(*Gitlab::Workhorse.send_scaled_image(location, params[:width].to_i, content_type))
head :ok
elsif file_upload.file_storage?
send_file file_upload.path, send_params
@@ -32,6 +34,12 @@ module SendFileUpload
end
end
+ def content_type_for(attachment)
+ return '' unless attachment
+
+ guess_content_type(attachment)
+ end
+
def guess_content_type(filename)
types = MIME::Types.type_for(filename)
@@ -45,15 +53,33 @@ module SendFileUpload
private
def image_scaling_request?(file_upload)
- avatar_image_upload?(file_upload) && valid_image_scaling_width? && current_user &&
- Feature.enabled?(:dynamic_image_resizing, current_user)
+ avatar_safe_for_scaling?(file_upload) &&
+ scaling_allowed_by_feature_flags?(file_upload) &&
+ valid_image_scaling_width?
end
- def avatar_image_upload?(file_upload)
- file_upload.try(:image?) && file_upload.try(:mounted_as)&.to_sym == :avatar
+ def avatar_safe_for_scaling?(file_upload)
+ file_upload.try(:image_safe_for_scaling?) && mounted_as_avatar?(file_upload)
+ end
+
+ def mounted_as_avatar?(file_upload)
+ file_upload.try(:mounted_as)&.to_sym == :avatar
end
def valid_image_scaling_width?
Avatarable::ALLOWED_IMAGE_SCALER_WIDTHS.include?(params[:width]&.to_i)
end
+
+ # We use two separate feature gates to allow image resizing.
+ # The first, `:dynamic_image_resizing_requester`, based on the content requester.
+ # Enabling it for the user would allow that user to send resizing requests for any avatar.
+ # The second, `:dynamic_image_resizing_owner`, based on the content owner.
+ # Enabling it for the user would allow anyone to send resizing requests against the mentioned user avatar only.
+ # This flag allows us to operate on trusted data only, more in https://gitlab.com/gitlab-org/gitlab/-/issues/241533.
+ # Because of this, you need to enable BOTH to serve resized image,
+ # as you would need at least one allowed requester and at least one allowed avatar.
+ def scaling_allowed_by_feature_flags?(file_upload)
+ Feature.enabled?(:dynamic_image_resizing_requester, current_user) &&
+ Feature.enabled?(:dynamic_image_resizing_owner, file_upload.model)
+ end
end