summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/banzai/filter/audio_link_filter.rb66
-rw-r--r--lib/banzai/filter/relative_link_filter.rb4
-rw-r--r--lib/banzai/filter/wiki_link_filter.rb2
-rw-r--r--lib/banzai/pipeline/gfm_pipeline.rb1
-rw-r--r--lib/gitlab/database/migration_helpers.rb2
-rw-r--r--lib/gitlab/file_markdown_link_builder.rb4
-rw-r--r--lib/gitlab/file_type_detection.rb18
-rw-r--r--lib/gitlab/profiler.rb3
8 files changed, 88 insertions, 12 deletions
diff --git a/lib/banzai/filter/audio_link_filter.rb b/lib/banzai/filter/audio_link_filter.rb
new file mode 100644
index 00000000000..83aa520dc4b
--- /dev/null
+++ b/lib/banzai/filter/audio_link_filter.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+# Generated HTML is transformed back to GFM by app/assets/javascripts/behaviors/markdown/nodes/audio.js
+module Banzai
+ module Filter
+ # Find every image that isn't already wrapped in an `a` tag, and that has
+ # a `src` attribute ending with an audio extension, add a new audio node and
+ # a "Download" link in the case the audio cannot be played.
+ class AudioLinkFilter < HTML::Pipeline::Filter
+ def call
+ doc.xpath('descendant-or-self::img[not(ancestor::a)]').each do |el|
+ el.replace(audio_node(doc, el)) if has_audio_extension?(el)
+ end
+
+ doc
+ end
+
+ private
+
+ def has_audio_extension?(element)
+ src = element.attr('data-canonical-src').presence || element.attr('src')
+
+ return unless src.present?
+
+ src_ext = File.extname(src).sub('.', '').downcase
+ Gitlab::FileTypeDetection::SAFE_AUDIO_EXT.include?(src_ext)
+ end
+
+ def audio_node(doc, element)
+ container = doc.document.create_element(
+ 'div',
+ class: 'audio-container'
+ )
+
+ audio = doc.document.create_element(
+ 'audio',
+ src: element['src'],
+ controls: true,
+ 'data-setup' => '{}',
+ 'data-title' => element['title'] || element['alt'])
+
+ link = doc.document.create_element(
+ 'a',
+ element['title'] || element['alt'],
+ href: element['src'],
+ target: '_blank',
+ rel: 'noopener noreferrer',
+ title: "Download '#{element['title'] || element['alt']}'")
+
+ # make sure the original non-proxied src carries over
+ if element['data-canonical-src']
+ audio['data-canonical-src'] = element['data-canonical-src']
+ link['data-canonical-src'] = element['data-canonical-src']
+ end
+
+ download_paragraph = doc.document.create_element('p')
+ download_paragraph.children = link
+
+ container.add_child(audio)
+ container.add_child(download_paragraph)
+
+ container
+ end
+ end
+ end
+end
diff --git a/lib/banzai/filter/relative_link_filter.rb b/lib/banzai/filter/relative_link_filter.rb
index df181406591..c7589e69262 100644
--- a/lib/banzai/filter/relative_link_filter.rb
+++ b/lib/banzai/filter/relative_link_filter.rb
@@ -65,7 +65,7 @@ module Banzai
el.attribute('href')
end
- attrs += doc.search('img, video').flat_map do |el|
+ attrs += doc.search('img, video, audio').flat_map do |el|
[el.attribute('src'), el.attribute('data-src')]
end
@@ -83,7 +83,7 @@ module Banzai
get_blob_types(paths).each do |name, type|
if type == :blob
blob = ::Blob.decorate(Gitlab::Git::Blob.new(name: name), project)
- uri_types[name] = blob.image? || blob.video? ? :raw : :blob
+ uri_types[name] = blob.image? || blob.video? || blob.audio? ? :raw : :blob
else
uri_types[name] = type
end
diff --git a/lib/banzai/filter/wiki_link_filter.rb b/lib/banzai/filter/wiki_link_filter.rb
index 18947679b69..205f777bc90 100644
--- a/lib/banzai/filter/wiki_link_filter.rb
+++ b/lib/banzai/filter/wiki_link_filter.rb
@@ -15,7 +15,7 @@ module Banzai
doc.search('a:not(.gfm)').each { |el| process_link(el.attribute('href'), el) }
- doc.search('video').each { |el| process_link(el.attribute('src'), el) }
+ doc.search('video, audio').each { |el| process_link(el.attribute('src'), el) }
doc.search('img').each do |el|
attr = el.attribute('data-src') || el.attribute('src')
diff --git a/lib/banzai/pipeline/gfm_pipeline.rb b/lib/banzai/pipeline/gfm_pipeline.rb
index bb0d1eaa1e1..08e27257fdf 100644
--- a/lib/banzai/pipeline/gfm_pipeline.rb
+++ b/lib/banzai/pipeline/gfm_pipeline.rb
@@ -26,6 +26,7 @@ module Banzai
Filter::ColorFilter,
Filter::MermaidFilter,
Filter::VideoLinkFilter,
+ Filter::AudioLinkFilter,
Filter::ImageLazyLoadFilter,
Filter::ImageLinkFilter,
Filter::InlineMetricsFilter,
diff --git a/lib/gitlab/database/migration_helpers.rb b/lib/gitlab/database/migration_helpers.rb
index 5a42952796c..ae29546cdac 100644
--- a/lib/gitlab/database/migration_helpers.rb
+++ b/lib/gitlab/database/migration_helpers.rb
@@ -1018,7 +1018,7 @@ into similar problems in the future (e.g. when new tables are created).
end
model_class.each_batch(of: batch_size) do |relation, index|
- start_id, end_id = relation.pluck('MIN(id), MAX(id)').first
+ start_id, end_id = relation.pluck(Arel.sql('MIN(id), MAX(id)')).first
# `BackgroundMigrationWorker.bulk_perform_in` schedules all jobs for
# the same time, which is not helpful in most cases where we wish to
diff --git a/lib/gitlab/file_markdown_link_builder.rb b/lib/gitlab/file_markdown_link_builder.rb
index e9e5172e6f8..09d799b859d 100644
--- a/lib/gitlab/file_markdown_link_builder.rb
+++ b/lib/gitlab/file_markdown_link_builder.rb
@@ -10,14 +10,14 @@ module Gitlab
return unless name = markdown_name
markdown = "[#{name.gsub(']', '\\]')}](#{secure_url})"
- markdown = "!#{markdown}" if image_or_video? || dangerous_image_or_video?
+ markdown = "!#{markdown}" if embeddable? || dangerous_embeddable?
markdown
end
def markdown_name
return unless filename.present?
- image_or_video? ? File.basename(filename, File.extname(filename)) : filename
+ embeddable? ? File.basename(filename, File.extname(filename)) : filename
end
end
end
diff --git a/lib/gitlab/file_type_detection.rb b/lib/gitlab/file_type_detection.rb
index 7137720f204..ca78d49f99b 100644
--- a/lib/gitlab/file_type_detection.rb
+++ b/lib/gitlab/file_type_detection.rb
@@ -26,11 +26,13 @@ module Gitlab
# on IE >= 9.
# http://archive.sublimevideo.info/20150912/docs.sublimevideo.net/troubleshooting.html
SAFE_VIDEO_EXT = %w[mp4 m4v mov webm ogv].freeze
+ SAFE_AUDIO_EXT = %w[mp3 oga ogg spx wav].freeze
# These extension types can contain dangerous code and should only be embedded inline with
# proper filtering. They should always be tagged as "Content-Disposition: attachment", not "inline".
DANGEROUS_IMAGE_EXT = %w[svg].freeze
DANGEROUS_VIDEO_EXT = [].freeze # None, yet
+ DANGEROUS_AUDIO_EXT = [].freeze # None, yet
def image?
extension_match?(SAFE_IMAGE_EXT)
@@ -40,8 +42,12 @@ module Gitlab
extension_match?(SAFE_VIDEO_EXT)
end
- def image_or_video?
- image? || video?
+ def audio?
+ extension_match?(SAFE_AUDIO_EXT)
+ end
+
+ def embeddable?
+ image? || video? || audio?
end
def dangerous_image?
@@ -52,8 +58,12 @@ module Gitlab
extension_match?(DANGEROUS_VIDEO_EXT)
end
- def dangerous_image_or_video?
- dangerous_image? || dangerous_video?
+ def dangerous_audio?
+ extension_match?(DANGEROUS_AUDIO_EXT)
+ end
+
+ def dangerous_embeddable?
+ dangerous_image? || dangerous_video? || dangerous_audio?
end
private
diff --git a/lib/gitlab/profiler.rb b/lib/gitlab/profiler.rb
index 275151f7fc1..560618bb486 100644
--- a/lib/gitlab/profiler.rb
+++ b/lib/gitlab/profiler.rb
@@ -37,8 +37,7 @@ module Gitlab
# - post_data: a string of raw POST data to use. Changes the HTTP verb to
# POST.
#
- # - user: a user to authenticate as. Only works if the user has a valid
- # personal access token.
+ # - user: a user to authenticate as.
#
# - private_token: instead of providing a user instance, the token can be
# given as a string. Takes precedence over the user option.