FEATURE: Add support for secure media (#7888)

This PR introduces a new secure media setting. When enabled, it prevent unathorized access to media uploads (files of type image, video and audio). When the `login_required` setting is enabled, then all media uploads will be protected from unauthorized (anonymous) access. When `login_required`is disabled, only media in private messages will be protected from unauthorized access. 

A few notes: 

- the `prevent_anons_from_downloading_files` setting no longer applies to audio and video uploads
- the `secure_media` setting can only be enabled if S3 uploads are already enabled and configured
- upload records have a new column, `secure`, which is a boolean `true/false` of the upload's secure status
- when creating a public post with an upload that has already been uploaded and is marked as secure, the post creator will raise an error
- when enabling or disabling the setting on a site with existing uploads, the rake task `uploads:ensure_correct_acl` should be used to update all uploads' secure status and their ACL on S3
This commit is contained in:
Penar Musaraj
2019-11-17 20:25:42 -05:00
committed by Martin Brennan
parent 56b19ba740
commit 102909edb3
40 changed files with 1157 additions and 153 deletions

View File

@ -288,6 +288,84 @@ describe Upload do
end
end
describe '.update_secure_status' do
it 'marks a local upload as not secure with default settings' do
upload.update!(secure: true)
expect { upload.update_secure_status }
.to change { upload.secure }
expect(upload.secure).to eq(false)
end
it 'marks a local attachment as secure if prevent_anons_from_downloading_files is enabled' do
SiteSetting.prevent_anons_from_downloading_files = true
SiteSetting.authorized_extensions = "pdf"
upload.update!(original_filename: "small.pdf", extension: "pdf")
expect { upload.update_secure_status }
.to change { upload.secure }
expect(upload.secure).to eq(true)
end
it 'marks a local attachment as not secure if prevent_anons_from_downloading_files is disabled' do
SiteSetting.prevent_anons_from_downloading_files = false
SiteSetting.authorized_extensions = "pdf"
upload.update!(original_filename: "small.pdf", extension: "pdf", secure: true)
expect { upload.update_secure_status }
.to change { upload.secure }
expect(upload.secure).to eq(false)
end
it 'does not change secure status of a non-attachment when prevent_anons_from_downloading_files is enabled' do
SiteSetting.prevent_anons_from_downloading_files = true
SiteSetting.authorized_extensions = "mp4"
upload.update!(original_filename: "small.mp4", extension: "mp4")
expect { upload.update_secure_status }
.not_to change { upload.secure }
expect(upload.secure).to eq(false)
end
context "secure media enabled" do
before do
SiteSetting.enable_s3_uploads = true
SiteSetting.s3_upload_bucket = "s3-upload-bucket"
SiteSetting.s3_access_key_id = "some key"
SiteSetting.s3_secret_access_key = "some secret key"
SiteSetting.secure_media = true
stub_request(:head, "https://#{SiteSetting.s3_upload_bucket}.s3.amazonaws.com/")
stub_request(
:put,
"https://#{SiteSetting.s3_upload_bucket}.s3.amazonaws.com/original/1X/#{upload.sha1}.#{upload.extension}?acl"
)
end
it 'marks an image upload as not secure when not associated with a post' do
upload.update!(secure: true)
expect { upload.update_secure_status }
.to change { upload.secure }
expect(upload.secure).to eq(false)
end
it 'marks an image upload as secure if login_required is enabled' do
SiteSetting.login_required = true
upload.update!(secure: false)
expect { upload.update_secure_status }
.to change { upload.secure }
expect(upload.secure).to eq(true)
end
end
end
describe '.reset_unknown_extensions!' do
it 'should reset the extension of uploads when it is "unknown"' do
upload1 = Fabricate(:upload, extension: "unknown")