Fix AVIF attachments (#26264)
This commit is contained in:
parent
71fd70335a
commit
f2257069b2
9 changed files with 87 additions and 36 deletions
|
@ -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
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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
BIN
spec/fixtures/files/600x400.avif
vendored
Normal file
Binary file not shown.
BIN
spec/fixtures/files/600x400.heic
vendored
Normal file
BIN
spec/fixtures/files/600x400.heic
vendored
Normal file
Binary file not shown.
BIN
spec/fixtures/files/600x400.jpeg
vendored
Normal file
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
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
BIN
spec/fixtures/files/600x400.webp
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.8 KiB |
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue