Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix AVIF attachments #26264

Merged
merged 2 commits into from
Aug 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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