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

@ -170,7 +170,7 @@ RSpec.describe UploadCreator do
end
end
describe 'private uploads' do
describe 'secure attachments' do
let(:filename) { "small.pdf" }
let(:file) { file_from_fixtures(filename, "pdf") }
@ -179,31 +179,31 @@ RSpec.describe UploadCreator do
SiteSetting.authorized_extensions = 'pdf|svg|jpg'
end
it 'should mark uploads as private' do
it 'should mark attachments as secure' do
upload = UploadCreator.new(file, filename).create_for(user.id)
stored_upload = Upload.last
expect(stored_upload.private?).to eq(true)
expect(stored_upload.secure?).to eq(true)
end
it 'should not mark theme uploads as private' do
it 'should not mark theme uploads as secure' do
fname = "custom-theme-icon-sprite.svg"
upload = UploadCreator.new(file_from_fixtures(fname), fname, for_theme: true).create_for(-1)
expect(upload.private?).to eq(false)
expect(upload.secure?).to eq(false)
end
it 'should not mark image uploads as private' do
it 'should not apply prevent_anons_from_downloading_files to image uploads' do
fname = "logo.jpg"
upload = UploadCreator.new(file_from_fixtures(fname), fname).create_for(user.id)
stored_upload = Upload.last
expect(stored_upload.original_filename).to eq(fname)
expect(stored_upload.private?).to eq(false)
expect(stored_upload.secure?).to eq(false)
end
end
describe 'uploading to s3' do
context 'uploading to s3' do
let(:filename) { "should_be_jpeg.png" }
let(:file) { file_from_fixtures(filename) }
let(:pdf_filename) { "small.pdf" }
@ -233,7 +233,7 @@ RSpec.describe UploadCreator do
expect(upload.etag).to eq('ETag')
end
it 'should return signed URL for private uploads in S3' do
it 'should return signed URL for secure attachments in S3' do
SiteSetting.prevent_anons_from_downloading_files = true
SiteSetting.authorized_extensions = 'pdf'
@ -241,7 +241,7 @@ RSpec.describe UploadCreator do
stored_upload = Upload.last
signed_url = Discourse.store.url_for(stored_upload)
expect(stored_upload.private?).to eq(true)
expect(stored_upload.secure?).to eq(true)
expect(stored_upload.url).not_to eq(signed_url)
expect(signed_url).to match(/Amz-Credential/)
end