123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105 |
- # frozen_string_literal: true
- class Admin::SystemCheck::MediaPrivacyCheck < Admin::SystemCheck::BaseCheck
- include RoutingHelper
- def skip?
- !current_user.can?(:view_devops)
- end
- def pass?
- check_media_uploads!
- @failure_message.nil?
- end
- def message
- Admin::SystemCheck::Message.new(@failure_message, @failure_value, @failure_action, true)
- end
- private
- def check_media_uploads!
- if Rails.configuration.x.use_s3
- check_media_listing_inaccessible_s3!
- else
- check_media_listing_inaccessible!
- end
- end
- def check_media_listing_inaccessible!
- full_url = full_asset_url(media_attachment.file.url(:original, false))
- # Check if we can list the uploaded file. If true, that's an error
- directory_url = Addressable::URI.parse(full_url)
- directory_url.query = nil
- filename = directory_url.path.gsub(%r{.*/}, '')
- directory_url.path = directory_url.path.gsub(%r{/[^/]+\Z}, '/')
- Request.new(:get, directory_url, allow_local: true).perform do |res|
- if res.truncated_body&.include?(filename)
- @failure_message = use_storage? ? :upload_check_privacy_error_object_storage : :upload_check_privacy_error
- @failure_action = 'https://docs.joinmastodon.org/admin/optional/object-storage/#FS'
- end
- end
- rescue
- nil
- end
- def check_media_listing_inaccessible_s3!
- urls_to_check = []
- paperclip_options = Paperclip::Attachment.default_options
- s3_protocol = paperclip_options[:s3_protocol]
- s3_host_alias = paperclip_options[:s3_host_alias]
- s3_host_name = paperclip_options[:s3_host_name]
- bucket_name = paperclip_options.dig(:s3_credentials, :bucket)
- urls_to_check << "#{s3_protocol}://#{s3_host_alias}/" if s3_host_alias.present?
- urls_to_check << "#{s3_protocol}://#{s3_host_name}/#{bucket_name}/"
- urls_to_check.uniq.each do |full_url|
- check_s3_listing!(full_url)
- break if @failure_message.present?
- end
- rescue
- nil
- end
- def check_s3_listing!(full_url)
- bucket_url = Addressable::URI.parse(full_url)
- bucket_url.path = bucket_url.path.delete_suffix(media_attachment.file.path(:original))
- bucket_url.query = "max-keys=1&x-random=#{SecureRandom.hex(10)}"
- Request.new(:get, bucket_url, allow_local: true).perform do |res|
- if res.truncated_body&.include?('ListBucketResult')
- @failure_message = :upload_check_privacy_error_object_storage
- @failure_action = 'https://docs.joinmastodon.org/admin/optional/object-storage/#S3'
- end
- end
- end
- def media_attachment
- @media_attachment ||= begin
- attachment = Account.representative.media_attachments.first
- if attachment.present?
- attachment.touch # rubocop:disable Rails/SkipsModelValidations
- attachment
- else
- create_test_attachment!
- end
- end
- end
- def create_test_attachment!
- Tempfile.create(%w(test-upload .jpg), binmode: true) do |tmp_file|
- tmp_file.write(
- Base64.decode64(
- '/9j/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAYAAAA' \
- 'AAAD/2wCEAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBA' \
- 'QEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQE' \
- 'BAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAf/AABEIAAEAAgMBEQACEQEDEQH/x' \
- 'ABKAAEAAAAAAAAAAAAAAAAAAAALEAEAAAAAAAAAAAAAAAAAAAAAAQEAAAAAAAAAAAAAAAA' \
- 'AAAAAEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwA/8H//2Q=='
- )
- )
- tmp_file.flush
- Account.representative.media_attachments.create!(file: tmp_file)
- end
- end
- end
|