Fix AVIF attachments (#26264)

This commit is contained in:
Christian Schmidt 2023-08-01 19:34:11 +02:00 committed by GitHub
parent 71fd70335a
commit f2257069b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 87 additions and 36 deletions

View File

@ -57,7 +57,7 @@ class MediaAttachment < ApplicationRecord
).freeze ).freeze
IMAGE_MIME_TYPES = %w(image/jpeg image/png image/gif image/heic image/heif image/webp image/avif).freeze IMAGE_MIME_TYPES = %w(image/jpeg image/png image/gif image/heic image/heif image/webp image/avif).freeze
IMAGE_CONVERTIBLE_MIME_TYPES = %w(image/heic image/heif).freeze IMAGE_CONVERTIBLE_MIME_TYPES = %w(image/heic image/heif image/avif).freeze
VIDEO_MIME_TYPES = %w(video/webm video/mp4 video/quicktime video/ogg).freeze VIDEO_MIME_TYPES = %w(video/webm video/mp4 video/quicktime video/ogg).freeze
VIDEO_CONVERTIBLE_MIME_TYPES = %w(video/webm video/quicktime).freeze VIDEO_CONVERTIBLE_MIME_TYPES = %w(video/webm video/quicktime).freeze
AUDIO_MIME_TYPES = %w(audio/wave audio/wav audio/x-wav audio/x-pn-wave audio/vnd.wave audio/ogg audio/vorbis audio/mpeg audio/mp3 audio/webm audio/flac audio/aac audio/m4a audio/x-m4a audio/mp4 audio/3gpp video/x-ms-asf).freeze AUDIO_MIME_TYPES = %w(audio/wave audio/wav audio/x-wav audio/x-pn-wave audio/vnd.wave audio/ogg audio/vorbis audio/mpeg audio/mp3 audio/webm audio/flac audio/aac audio/m4a audio/x-m4a audio/mp4 audio/3gpp video/x-ms-asf).freeze

View File

@ -22,6 +22,6 @@
<!-- Disallow any coder by default, and only enable ones required by Mastodon --> <!-- Disallow any coder by default, and only enable ones required by Mastodon -->
<policy domain="coder" rights="none" pattern="*" /> <policy domain="coder" rights="none" pattern="*" />
<policy domain="coder" rights="read | write" pattern="{PNG,JPEG,GIF,HEIC,WEBP}" /> <policy domain="coder" rights="read | write" pattern="{JPEG,PNG,GIF,WEBP,HEIC,AVIF}" />
<policy domain="coder" rights="write" pattern="{HISTOGRAM,RGB,INFO}" /> <policy domain="coder" rights="write" pattern="{HISTOGRAM,RGB,INFO}" />
</policymap> </policymap>

View File

@ -2,13 +2,15 @@
module Paperclip module Paperclip
module MediaTypeSpoofDetectorExtensions module MediaTypeSpoofDetectorExtensions
MARCEL_MIME_TYPES = %w(audio/mpeg image/avif).freeze
def calculated_content_type def calculated_content_type
return @calculated_content_type if defined?(@calculated_content_type) return @calculated_content_type if defined?(@calculated_content_type)
@calculated_content_type = type_from_file_command.chomp @calculated_content_type = type_from_file_command.chomp
# The `file` command fails to recognize some MP3 files as such # The `file` command fails to recognize some MP3 files as such
@calculated_content_type = type_from_marcel if @calculated_content_type == 'application/octet-stream' && type_from_marcel == 'audio/mpeg' @calculated_content_type = type_from_marcel if @calculated_content_type == 'application/octet-stream' && type_from_marcel.in?(MARCEL_MIME_TYPES)
@calculated_content_type @calculated_content_type
end end

BIN
spec/fixtures/files/600x400.avif vendored Normal file

Binary file not shown.

BIN
spec/fixtures/files/600x400.heic vendored Normal file

Binary file not shown.

BIN
spec/fixtures/files/600x400.jpeg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
spec/fixtures/files/600x400.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
spec/fixtures/files/600x400.webp vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

View File

@ -84,7 +84,87 @@ RSpec.describe MediaAttachment, paperclip_processing: true do
end end
end end
describe 'animated gif conversion' do shared_examples 'static 600x400 image' do |content_type, extension|
after do
media.destroy
end
it 'saves media attachment' do
expect(media.persisted?).to be true
expect(media.file).to_not be_nil
end
it 'completes processing' do
expect(media.processing_complete?).to be true
end
it 'sets type' do
expect(media.type).to eq 'image'
end
it 'sets content type' do
expect(media.file_content_type).to eq content_type
end
it 'sets file extension' do
expect(media.file_file_name).to end_with extension
end
it 'strips original file name' do
expect(media.file_file_name).to_not start_with '600x400'
end
it 'sets meta for original' do
expect(media.file.meta['original']['width']).to eq 600
expect(media.file.meta['original']['height']).to eq 400
expect(media.file.meta['original']['aspect']).to eq 1.5
end
it 'sets meta for thumbnail' do
expect(media.file.meta['small']['width']).to eq 588
expect(media.file.meta['small']['height']).to eq 392
expect(media.file.meta['small']['aspect']).to eq 1.5
end
end
describe 'jpeg' do
let(:media) { described_class.create(account: Fabricate(:account), file: attachment_fixture('600x400.jpeg')) }
it_behaves_like 'static 600x400 image', 'image/jpeg', '.jpeg'
end
describe 'png' do
let(:media) { described_class.create(account: Fabricate(:account), file: attachment_fixture('600x400.png')) }
it_behaves_like 'static 600x400 image', 'image/png', '.png'
end
describe 'webp' do
let(:media) { described_class.create(account: Fabricate(:account), file: attachment_fixture('600x400.webp')) }
it_behaves_like 'static 600x400 image', 'image/webp', '.webp'
end
describe 'avif' do
let(:media) { described_class.create(account: Fabricate(:account), file: attachment_fixture('600x400.avif')) }
it_behaves_like 'static 600x400 image', 'image/jpeg', '.jpeg'
end
describe 'heic' do
let(:media) { described_class.create(account: Fabricate(:account), file: attachment_fixture('600x400.heic')) }
it_behaves_like 'static 600x400 image', 'image/jpeg', '.jpeg'
end
describe 'base64-encoded image' do
let(:base64_attachment) { "data:image/jpeg;base64,#{Base64.encode64(attachment_fixture('600x400.jpeg').read)}" }
let(:media) { described_class.create(account: Fabricate(:account), file: base64_attachment) }
it_behaves_like 'static 600x400 image', 'image/jpeg', '.jpeg'
end
describe 'animated gif' do
let(:media) { described_class.create(account: Fabricate(:account), file: attachment_fixture('avatar.gif')) } let(:media) { described_class.create(account: Fabricate(:account), file: attachment_fixture('avatar.gif')) }
it 'sets type to gifv' do it 'sets type to gifv' do
@ -101,7 +181,7 @@ RSpec.describe MediaAttachment, paperclip_processing: true do
end end
end end
describe 'non-animated gif non-conversion' do describe 'static gif' do
fixtures = [ fixtures = [
{ filename: 'attachment.gif', width: 600, height: 400, aspect: 1.5 }, { filename: 'attachment.gif', width: 600, height: 400, aspect: 1.5 },
{ filename: 'mini-static.gif', width: 32, height: 32, aspect: 1.0 }, { filename: 'mini-static.gif', width: 32, height: 32, aspect: 1.0 },
@ -172,37 +252,6 @@ RSpec.describe MediaAttachment, paperclip_processing: true do
end end
end end
describe 'jpeg' do
let(:media) { described_class.create(account: Fabricate(:account), file: attachment_fixture('attachment.jpg')) }
it 'sets meta for different style' do
expect(media.file.meta['original']['width']).to eq 600
expect(media.file.meta['original']['height']).to eq 400
expect(media.file.meta['original']['aspect']).to eq 1.5
expect(media.file.meta['small']['width']).to eq 588
expect(media.file.meta['small']['height']).to eq 392
expect(media.file.meta['small']['aspect']).to eq 1.5
end
it 'gives the file a random name' do
expect(media.file_file_name).to_not eq 'attachment.jpg'
end
end
describe 'base64-encoded jpeg' do
let(:base64_attachment) { "data:image/jpeg;base64,#{Base64.encode64(attachment_fixture('attachment.jpg').read)}" }
let(:media) { described_class.create(account: Fabricate(:account), file: base64_attachment) }
it 'saves media attachment' do
expect(media.persisted?).to be true
expect(media.file).to_not be_nil
end
it 'gives the file a file name' do
expect(media.file_file_name).to_not be_blank
end
end
it 'is invalid without file' do it 'is invalid without file' do
media = described_class.new(account: Fabricate(:account)) media = described_class.new(account: Fabricate(:account))
expect(media.valid?).to be false expect(media.valid?).to be false