Skip to content

Commit

Permalink
Fix AVIF attachments (#26264)
Browse files Browse the repository at this point in the history
  • Loading branch information
c960657 committed Aug 1, 2023
1 parent 71fd703 commit f225706
Show file tree
Hide file tree
Showing 9 changed files with 87 additions and 36 deletions.
2 changes: 1 addition & 1 deletion app/models/media_attachment.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class MediaAttachment < ApplicationRecord
).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_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
Expand Down
2 changes: 1 addition & 1 deletion config/imagemagick/policy.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@

<!-- Disallow any coder by default, and only enable ones required by Mastodon -->
<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}" />
</policymap>
4 changes: 3 additions & 1 deletion lib/paperclip/media_type_spoof_detector_extensions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

module Paperclip
module MediaTypeSpoofDetectorExtensions
MARCEL_MIME_TYPES = %w(audio/mpeg image/avif).freeze

def calculated_content_type
return @calculated_content_type if defined?(@calculated_content_type)

@calculated_content_type = type_from_file_command.chomp

# 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
end

Expand Down
Binary file added spec/fixtures/files/600x400.avif
Binary file not shown.
Binary file added spec/fixtures/files/600x400.heic
Binary file not shown.
Binary file added spec/fixtures/files/600x400.jpeg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added spec/fixtures/files/600x400.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added spec/fixtures/files/600x400.webp
Binary file not shown.
115 changes: 82 additions & 33 deletions spec/models/media_attachment_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,87 @@
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')) }

it 'sets type to gifv' do
Expand All @@ -101,7 +181,7 @@
end
end

describe 'non-animated gif non-conversion' do
describe 'static gif' do
fixtures = [
{ filename: 'attachment.gif', width: 600, height: 400, aspect: 1.5 },
{ filename: 'mini-static.gif', width: 32, height: 32, aspect: 1.0 },
Expand Down Expand Up @@ -172,37 +252,6 @@
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
media = described_class.new(account: Fabricate(:account))
expect(media.valid?).to be false
Expand Down

0 comments on commit f225706

Please sign in to comment.