diff --git a/app/controllers/admin/base_controller.rb b/app/controllers/admin/base_controller.rb index 42965696da1..dcdc9afd7d1 100644 --- a/app/controllers/admin/base_controller.rb +++ b/app/controllers/admin/base_controller.rb @@ -5,6 +5,12 @@ module Admin include Authorization include AccountableConcern + content_security_policy do |p| + policy = ContentSecurityPolicy.new + p.img_src(*p.img_src, *policy.admin_media_hosts) + p.media_src(*p.media_src, *policy.admin_media_hosts) + end + layout 'admin' before_action :require_moderator_or_admin_permissions diff --git a/app/controllers/media_proxy_controller.rb b/app/controllers/media_proxy_controller.rb index 267107b6272..a885333b936 100644 --- a/app/controllers/media_proxy_controller.rb +++ b/app/controllers/media_proxy_controller.rb @@ -56,7 +56,7 @@ class MediaProxyController < ApplicationController end def media_attachment_file_path - if @media_attachment.discarded? + if @media_attachment.on_hold? expiring_asset_url(media_attachment_file, 10.minutes) else full_asset_url(media_attachment_file.url(attachment_style)) @@ -76,6 +76,6 @@ class MediaProxyController < ApplicationController end def requires_file_streaming? - Paperclip::Attachment.default_options[:storage] == :filesystem && @media_attachment.discarded? + Paperclip::Attachment.default_options[:storage] == :filesystem && @media_attachment.on_hold? end end diff --git a/app/lib/content_security_policy.rb b/app/lib/content_security_policy.rb index fc42e2d48b3..2fe0528013b 100644 --- a/app/lib/content_security_policy.rb +++ b/app/lib/content_security_policy.rb @@ -13,6 +13,11 @@ class ContentSecurityPolicy [assets_host, cdn_host_value, paperclip_root_url].concat(extra_media_hosts).compact end + # In the admin area we might need signed URLs that use this domain + def admin_media_hosts + [s3_endpoint_url].compact + end + def sso_host return unless ENV['ONE_CLICK_SSO_LOGIN'] == 'true' && ENV['OMNIAUTH_ONLY'] == 'true' && Devise.omniauth_providers.length == 1 @@ -76,6 +81,10 @@ class ContentSecurityPolicy host_to_url ENV.fetch('S3_HOSTNAME', nil) end + def s3_endpoint_url + ENV.fetch('S3_ENDPOINT', nil) + end + def swift_object_url url = ENV.fetch('SWIFT_OBJECT_URL', nil) return if url.blank? || !url.start_with?('https://') diff --git a/app/models/media_attachment.rb b/app/models/media_attachment.rb index 5ba5277d33d..4f8313e9a62 100644 --- a/app/models/media_attachment.rb +++ b/app/models/media_attachment.rb @@ -244,6 +244,10 @@ class MediaAttachment < ApplicationRecord status&.discarded? || (status_id.present? && status.nil?) end + def on_hold? + discarded? || account&.suspended? + end + def significantly_changed? description_previously_changed? || thumbnail_updated_at_previously_changed? || file_meta_previously_changed? end diff --git a/app/models/status_edit.rb b/app/models/status_edit.rb index cdd8dd79e64..8dfa05b92a8 100644 --- a/app/models/status_edit.rb +++ b/app/models/status_edit.rb @@ -28,7 +28,7 @@ class StatusEdit < ApplicationRecord :preview_remote_url, :text_url, :meta, :blurhash, :not_processed?, :needs_redownload?, :local?, :file, :thumbnail, :thumbnail_remote_url, - :shortcode, :video?, :audio?, :discarded?, to: :media_attachment + :shortcode, :video?, :audio?, :discarded?, :on_hold?, to: :media_attachment end rate_limit by: :account, family: :statuses diff --git a/app/policies/media_attachment_policy.rb b/app/policies/media_attachment_policy.rb index bf108ae0980..aff53157743 100644 --- a/app/policies/media_attachment_policy.rb +++ b/app/policies/media_attachment_policy.rb @@ -2,7 +2,7 @@ class MediaAttachmentPolicy < ApplicationPolicy def download? - (record.discarded? && role.can?(:manage_reports)) || show_status? + (record.on_hold? && role.can?(:manage_reports)) || show_status? end private diff --git a/app/serializers/rest/media_attachment_serializer.rb b/app/serializers/rest/media_attachment_serializer.rb index 28fa0205f3a..857e9841c71 100644 --- a/app/serializers/rest/media_attachment_serializer.rb +++ b/app/serializers/rest/media_attachment_serializer.rb @@ -16,7 +16,7 @@ class REST::MediaAttachmentSerializer < ActiveModel::Serializer def url if object.not_processed? nil - elsif object.needs_redownload? || object.discarded? + elsif object.needs_redownload? || object.on_hold? media_proxy_url(object.id, :original) else full_asset_url(object.file.url(:original)) @@ -28,7 +28,7 @@ class REST::MediaAttachmentSerializer < ActiveModel::Serializer end def preview_url - if object.needs_redownload? || object.discarded? + if object.needs_redownload? || object.on_hold? media_proxy_url(object.id, :small) elsif object.thumbnail.present? full_asset_url(object.thumbnail.url(:original)) diff --git a/app/views/statuses/_attachment_list.html.haml b/app/views/statuses/_attachment_list.html.haml index a150a3fae9d..d2a0318b8a3 100644 --- a/app/views/statuses/_attachment_list.html.haml +++ b/app/views/statuses/_attachment_list.html.haml @@ -4,5 +4,5 @@ %ul.attachment-list__list - attachments.each do |media| %li - - url = media.remote_url.presence || media.file.url + - url = media.remote_url.presence || media_proxy_url(media.id, :original) = link_to File.basename(url), url, title: media.description diff --git a/spec/helpers/media_component_helper_spec.rb b/spec/helpers/media_component_helper_spec.rb index 60c9f84da21..a625f5cd59b 100644 --- a/spec/helpers/media_component_helper_spec.rb +++ b/spec/helpers/media_component_helper_spec.rb @@ -5,7 +5,7 @@ require 'rails_helper' RSpec.describe MediaComponentHelper do before { helper.extend controller_helpers } - let(:media) { Fabricate.build(:media_attachment, type:, status: Fabricate.build(:status)) } + let(:media) { Fabricate.build(:media_attachment, type:, status: Fabricate.build(:status), id: 1234) } describe 'render_video_component' do let(:type) { :video } diff --git a/spec/requests/media_proxy_spec.rb b/spec/requests/media_proxy_spec.rb index fb4801ee67a..816af7d27e2 100644 --- a/spec/requests/media_proxy_spec.rb +++ b/spec/requests/media_proxy_spec.rb @@ -59,6 +59,22 @@ RSpec.describe 'Media Proxy' do end end + context 'when an admin wants to see a suspended attachment' do + before do + sign_in Fabricate(:admin_user) + end + + let(:account) { Fabricate(:account, suspended: true) } + let(:status) { Fabricate(:status, account:) } + let(:media_attachment) { Fabricate(:media_attachment, account:, status:, type: :image) } + + it 'returns the media' do + get "/media_proxy/#{media_attachment.id}" + + expect(response).to have_http_status(200) + end + end + def stub_attachment_request stub_request( :get,