summaryrefslogtreecommitdiff
path: root/lib/gitlab/markdown/filter
diff options
context:
space:
mode:
Diffstat (limited to 'lib/gitlab/markdown/filter')
-rw-r--r--lib/gitlab/markdown/filter/autolink_filter.rb107
-rw-r--r--lib/gitlab/markdown/filter/commit_range_reference_filter.rb58
-rw-r--r--lib/gitlab/markdown/filter/commit_reference_filter.rb63
-rw-r--r--lib/gitlab/markdown/filter/emoji_filter.rb80
-rw-r--r--lib/gitlab/markdown/filter/external_issue_reference_filter.rb69
-rw-r--r--lib/gitlab/markdown/filter/external_link_filter.rb34
-rw-r--r--lib/gitlab/markdown/filter/issue_reference_filter.rb23
-rw-r--r--lib/gitlab/markdown/filter/label_reference_filter.rb96
-rw-r--r--lib/gitlab/markdown/filter/markdown_filter.rb39
-rw-r--r--lib/gitlab/markdown/filter/merge_request_reference_filter.rb41
-rw-r--r--lib/gitlab/markdown/filter/redactor_filter.rb43
-rw-r--r--lib/gitlab/markdown/filter/reference_gatherer_filter.rb63
-rw-r--r--lib/gitlab/markdown/filter/relative_link_filter.rb157
-rw-r--r--lib/gitlab/markdown/filter/sanitization_filter.rb99
-rw-r--r--lib/gitlab/markdown/filter/snippet_reference_filter.rb25
-rw-r--r--lib/gitlab/markdown/filter/syntax_highlight_filter.rb45
-rw-r--r--lib/gitlab/markdown/filter/table_of_contents_filter.rb63
-rw-r--r--lib/gitlab/markdown/filter/task_list_filter.rb24
-rw-r--r--lib/gitlab/markdown/filter/upload_link_filter.rb47
-rw-r--r--lib/gitlab/markdown/filter/user_reference_filter.rb129
20 files changed, 0 insertions, 1305 deletions
diff --git a/lib/gitlab/markdown/filter/autolink_filter.rb b/lib/gitlab/markdown/filter/autolink_filter.rb
deleted file mode 100644
index c37c3bc55bf..00000000000
--- a/lib/gitlab/markdown/filter/autolink_filter.rb
+++ /dev/null
@@ -1,107 +0,0 @@
-require 'gitlab/markdown'
-require 'html/pipeline/filter'
-require 'uri'
-
-module Gitlab
- module Markdown
- # HTML Filter for auto-linking URLs in HTML.
- #
- # Based on HTML::Pipeline::AutolinkFilter
- #
- # Context options:
- # :autolink - Boolean, skips all processing done by this filter when false
- # :link_attr - Hash of attributes for the generated links
- #
- class AutolinkFilter < HTML::Pipeline::Filter
- include ActionView::Helpers::TagHelper
-
- # Pattern to match text that should be autolinked.
- #
- # A URI scheme begins with a letter and may contain letters, numbers,
- # plus, period and hyphen. Schemes are case-insensitive but we're being
- # picky here and allowing only lowercase for autolinks.
- #
- # See http://en.wikipedia.org/wiki/URI_scheme
- #
- # The negative lookbehind ensures that users can paste a URL followed by a
- # period or comma for punctuation without those characters being included
- # in the generated link.
- #
- # Rubular: http://rubular.com/r/cxjPyZc7Sb
- LINK_PATTERN = %r{([a-z][a-z0-9\+\.-]+://\S+)(?<!,|\.)}
-
- # Text matching LINK_PATTERN inside these elements will not be linked
- IGNORE_PARENTS = %w(a code kbd pre script style).to_set
-
- def call
- return doc if context[:autolink] == false
-
- rinku_parse
- text_parse
- end
-
- private
-
- # Run the text through Rinku as a first pass
- #
- # This will quickly autolink http(s) and ftp links.
- #
- # `@doc` will be re-parsed with the HTML String from Rinku.
- def rinku_parse
- # Convert the options from a Hash to a String that Rinku expects
- options = tag_options(link_options)
-
- # NOTE: We don't parse email links because it will erroneously match
- # external Commit and CommitRange references.
- #
- # The final argument tells Rinku to link short URLs that don't include a
- # period (e.g., http://localhost:3000/)
- rinku = Rinku.auto_link(html, :urls, options, IGNORE_PARENTS.to_a, 1)
-
- # Rinku returns a String, so parse it back to a Nokogiri::XML::Document
- # for further processing.
- @doc = parse_html(rinku)
- end
-
- # Autolinks any text matching LINK_PATTERN that Rinku didn't already
- # replace
- def text_parse
- search_text_nodes(doc).each do |node|
- content = node.to_html
-
- next if has_ancestor?(node, IGNORE_PARENTS)
- next unless content.match(LINK_PATTERN)
-
- # If Rinku didn't link this, there's probably a good reason, so we'll
- # skip it too
- next if content.start_with?(*%w(http https ftp))
-
- html = autolink_filter(content)
-
- next if html == content
-
- node.replace(html)
- end
-
- doc
- end
-
- def autolink_filter(text)
- text.gsub(LINK_PATTERN) do |match|
- # Remove any trailing HTML entities and store them for appending
- # outside the link element. The entity must be marked HTML safe in
- # order to be output literally rather than escaped.
- match.gsub!(/((?:&[\w#]+;)+)\z/, '')
- dropped = ($1 || '').html_safe
-
- options = link_options.merge(href: match)
- content_tag(:a, match, options) + dropped
- end
- end
-
- def link_options
- @link_options ||= context[:link_attr] || {}
- end
- end
- end
-end
diff --git a/lib/gitlab/markdown/filter/commit_range_reference_filter.rb b/lib/gitlab/markdown/filter/commit_range_reference_filter.rb
deleted file mode 100644
index 36b3258ef76..00000000000
--- a/lib/gitlab/markdown/filter/commit_range_reference_filter.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-require 'gitlab/markdown'
-
-module Gitlab
- module Markdown
- # HTML filter that replaces commit range references with links.
- #
- # This filter supports cross-project references.
- class CommitRangeReferenceFilter < AbstractReferenceFilter
- def self.object_class
- CommitRange
- end
-
- def self.references_in(text, pattern = CommitRange.reference_pattern)
- text.gsub(pattern) do |match|
- yield match, $~[:commit_range], $~[:project], $~
- end
- end
-
- def self.referenced_by(node)
- project = Project.find(node.attr("data-project")) rescue nil
- return unless project
-
- id = node.attr("data-commit-range")
- range = find_object(project, id)
-
- return unless range
-
- { commit_range: range }
- end
-
- def initialize(*args)
- super
-
- @commit_map = {}
- end
-
- def self.find_object(project, id)
- range = CommitRange.new(id, project)
-
- range.valid_commits? ? range : nil
- end
-
- def find_object(*args)
- self.class.find_object(*args)
- end
-
- def url_for_object(range, project)
- h = Gitlab::Application.routes.url_helpers
- h.namespace_project_compare_url(project.namespace, project,
- range.to_param.merge(only_path: context[:only_path]))
- end
-
- def object_link_title(range)
- range.reference_title
- end
- end
- end
-end
diff --git a/lib/gitlab/markdown/filter/commit_reference_filter.rb b/lib/gitlab/markdown/filter/commit_reference_filter.rb
deleted file mode 100644
index e3066a89b04..00000000000
--- a/lib/gitlab/markdown/filter/commit_reference_filter.rb
+++ /dev/null
@@ -1,63 +0,0 @@
-require 'gitlab/markdown'
-
-module Gitlab
- module Markdown
- # HTML filter that replaces commit references with links.
- #
- # This filter supports cross-project references.
- class CommitReferenceFilter < AbstractReferenceFilter
- def self.object_class
- Commit
- end
-
- def self.references_in(text, pattern = Commit.reference_pattern)
- text.gsub(pattern) do |match|
- yield match, $~[:commit], $~[:project], $~
- end
- end
-
- def self.referenced_by(node)
- project = Project.find(node.attr("data-project")) rescue nil
- return unless project
-
- id = node.attr("data-commit")
- commit = find_object(project, id)
-
- return unless commit
-
- { commit: commit }
- end
-
- def self.find_object(project, id)
- if project && project.valid_repo?
- project.commit(id)
- end
- end
-
- def find_object(*args)
- self.class.find_object(*args)
- end
-
- def url_for_object(commit, project)
- h = Gitlab::Application.routes.url_helpers
- h.namespace_project_commit_url(project.namespace, project, commit,
- only_path: context[:only_path])
- end
-
- def object_link_title(commit)
- commit.link_title
- end
-
- def object_link_text_extras(object, matches)
- extras = super
-
- path = matches[:path] if matches.names.include?("path")
- if path == '/builds'
- extras.unshift "builds"
- end
-
- extras
- end
- end
- end
-end
diff --git a/lib/gitlab/markdown/filter/emoji_filter.rb b/lib/gitlab/markdown/filter/emoji_filter.rb
deleted file mode 100644
index da10e4d3760..00000000000
--- a/lib/gitlab/markdown/filter/emoji_filter.rb
+++ /dev/null
@@ -1,80 +0,0 @@
-require 'action_controller'
-require 'gitlab/markdown'
-require 'gitlab_emoji'
-require 'html/pipeline/filter'
-
-module Gitlab
- module Markdown
- # HTML filter that replaces :emoji: with images.
- #
- # Based on HTML::Pipeline::EmojiFilter
- #
- # Context options:
- # :asset_root
- # :asset_host
- class EmojiFilter < HTML::Pipeline::Filter
- IGNORED_ANCESTOR_TAGS = %w(pre code tt).to_set
-
- def call
- search_text_nodes(doc).each do |node|
- content = node.to_html
- next unless content.include?(':')
- next if has_ancestor?(node, IGNORED_ANCESTOR_TAGS)
-
- html = emoji_image_filter(content)
-
- next if html == content
-
- node.replace(html)
- end
-
- doc
- end
-
- # Replace :emoji: with corresponding images.
- #
- # text - String text to replace :emoji: in.
- #
- # Returns a String with :emoji: replaced with images.
- def emoji_image_filter(text)
- text.gsub(emoji_pattern) do |match|
- name = $1
- "<img class='emoji' title=':#{name}:' alt=':#{name}:' src='#{emoji_url(name)}' height='20' width='20' align='absmiddle' />"
- end
- end
-
- private
-
- def emoji_url(name)
- emoji_path = "emoji/#{emoji_filename(name)}"
- if context[:asset_host]
- # Asset host is specified.
- url_to_image(emoji_path)
- elsif context[:asset_root]
- # Gitlab url is specified
- File.join(context[:asset_root], url_to_image(emoji_path))
- else
- # All other cases
- url_to_image(emoji_path)
- end
- end
-
- def url_to_image(image)
- ActionController::Base.helpers.url_to_image(image)
- end
-
- # Build a regexp that matches all valid :emoji: names.
- def self.emoji_pattern
- @emoji_pattern ||= /:(#{Emoji.emojis_names.map { |name| Regexp.escape(name) }.join('|')}):/
- end
-
- def emoji_pattern
- self.class.emoji_pattern
- end
-
- def emoji_filename(name)
- "#{Emoji.emoji_filename(name)}.png"
- end
- end
- end
-end
diff --git a/lib/gitlab/markdown/filter/external_issue_reference_filter.rb b/lib/gitlab/markdown/filter/external_issue_reference_filter.rb
deleted file mode 100644
index 14bdf5521fc..00000000000
--- a/lib/gitlab/markdown/filter/external_issue_reference_filter.rb
+++ /dev/null
@@ -1,69 +0,0 @@
-require 'gitlab/markdown'
-
-module Gitlab
- module Markdown
- # HTML filter that replaces external issue tracker references with links.
- # References are ignored if the project doesn't use an external issue
- # tracker.
- class ExternalIssueReferenceFilter < ReferenceFilter
- # Public: Find `JIRA-123` issue references in text
- #
- # ExternalIssueReferenceFilter.references_in(text) do |match, issue|
- # "<a href=...>##{issue}</a>"
- # end
- #
- # text - String text to search.
- #
- # Yields the String match and the String issue reference.
- #
- # Returns a String replaced with the return of the block.
- def self.references_in(text)
- text.gsub(ExternalIssue.reference_pattern) do |match|
- yield match, $~[:issue]
- end
- end
-
- def call
- # Early return if the project isn't using an external tracker
- return doc if project.nil? || project.default_issues_tracker?
-
- replace_text_nodes_matching(ExternalIssue.reference_pattern) do |content|
- issue_link_filter(content)
- end
-
- replace_link_nodes_with_href(ExternalIssue.reference_pattern) do |link, text|
- issue_link_filter(link, link_text: text)
- end
- end
-
- # Replace `JIRA-123` issue references in text with links to the referenced
- # issue's details page.
- #
- # text - String text to replace references in.
- #
- # Returns a String with `JIRA-123` references replaced with links. All
- # links have `gfm` and `gfm-issue` class names attached for styling.
- def issue_link_filter(text, link_text: nil)
- project = context[:project]
-
- self.class.references_in(text) do |match, issue|
- url = url_for_issue(issue, project, only_path: context[:only_path])
-
- title = escape_once("Issue in #{project.external_issue_tracker.title}")
- klass = reference_class(:issue)
- data = data_attribute(project: project.id)
-
- text = link_text || match
-
- %(<a href="#{url}" #{data}
- title="#{title}"
- class="#{klass}">#{text}</a>)
- end
- end
-
- def url_for_issue(*args)
- IssuesHelper.url_for_issue(*args)
- end
- end
- end
-end
diff --git a/lib/gitlab/markdown/filter/external_link_filter.rb b/lib/gitlab/markdown/filter/external_link_filter.rb
deleted file mode 100644
index e09dfcb83c8..00000000000
--- a/lib/gitlab/markdown/filter/external_link_filter.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-require 'gitlab/markdown'
-require 'html/pipeline/filter'
-
-module Gitlab
- module Markdown
- # HTML Filter to add a `rel="nofollow"` attribute to external links
- #
- class ExternalLinkFilter < HTML::Pipeline::Filter
- def call
- doc.search('a').each do |node|
- link = node.attr('href')
-
- next unless link
-
- # Skip non-HTTP(S) links
- next unless link.start_with?('http')
-
- # Skip internal links
- next if link.start_with?(internal_url)
-
- node.set_attribute('rel', 'nofollow')
- end
-
- doc
- end
-
- private
-
- def internal_url
- @internal_url ||= Gitlab.config.gitlab.url
- end
- end
- end
-end
diff --git a/lib/gitlab/markdown/filter/issue_reference_filter.rb b/lib/gitlab/markdown/filter/issue_reference_filter.rb
deleted file mode 100644
index 1ed69e2f431..00000000000
--- a/lib/gitlab/markdown/filter/issue_reference_filter.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-require 'gitlab/markdown'
-
-module Gitlab
- module Markdown
- # HTML filter that replaces issue references with links. References to
- # issues that do not exist are ignored.
- #
- # This filter supports cross-project references.
- class IssueReferenceFilter < AbstractReferenceFilter
- def self.object_class
- Issue
- end
-
- def find_object(project, id)
- project.get_issue(id)
- end
-
- def url_for_object(issue, project)
- IssuesHelper.url_for_issue(issue.iid, project, only_path: context[:only_path])
- end
- end
- end
-end
diff --git a/lib/gitlab/markdown/filter/label_reference_filter.rb b/lib/gitlab/markdown/filter/label_reference_filter.rb
deleted file mode 100644
index a2026eecaeb..00000000000
--- a/lib/gitlab/markdown/filter/label_reference_filter.rb
+++ /dev/null
@@ -1,96 +0,0 @@
-require 'gitlab/markdown'
-
-module Gitlab
- module Markdown
- # HTML filter that replaces label references with links.
- class LabelReferenceFilter < ReferenceFilter
- # Public: Find label references in text
- #
- # LabelReferenceFilter.references_in(text) do |match, id, name|
- # "<a href=...>#{Label.find(id)}</a>"
- # end
- #
- # text - String text to search.
- #
- # Yields the String match, an optional Integer label ID, and an optional
- # String label name.
- #
- # Returns a String replaced with the return of the block.
- def self.references_in(text)
- text.gsub(Label.reference_pattern) do |match|
- yield match, $~[:label_id].to_i, $~[:label_name]
- end
- end
-
- def self.referenced_by(node)
- { label: LazyReference.new(Label, node.attr("data-label")) }
- end
-
- def call
- replace_text_nodes_matching(Label.reference_pattern) do |content|
- label_link_filter(content)
- end
-
- replace_link_nodes_with_href(Label.reference_pattern) do |link, text|
- label_link_filter(link, link_text: text)
- end
- end
-
- # Replace label references in text with links to the label specified.
- #
- # text - String text to replace references in.
- #
- # Returns a String with label references replaced with links. All links
- # have `gfm` and `gfm-label` class names attached for styling.
- def label_link_filter(text, link_text: nil)
- project = context[:project]
-
- self.class.references_in(text) do |match, id, name|
- params = label_params(id, name)
-
- if label = project.labels.find_by(params)
- url = url_for_label(project, label)
- klass = reference_class(:label)
- data = data_attribute(
- original: link_text || match,
- project: project.id,
- label: label.id
- )
-
- text = link_text || render_colored_label(label)
-
- %(<a href="#{url}" #{data}
- class="#{klass}">#{text}</a>)
- else
- match
- end
- end
- end
-
- def url_for_label(project, label)
- h = Gitlab::Application.routes.url_helpers
- h.namespace_project_issues_url( project.namespace, project, label_name: label.name,
- only_path: context[:only_path])
- end
-
- def render_colored_label(label)
- LabelsHelper.render_colored_label(label)
- end
-
- # Parameters to pass to `Label.find_by` based on the given arguments
- #
- # id - Integer ID to pass. If present, returns {id: id}
- # name - String name to pass. If `id` is absent, finds by name without
- # surrounding quotes.
- #
- # Returns a Hash.
- def label_params(id, name)
- if name
- { name: name.tr('"', '') }
- else
- { id: id }
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/markdown/filter/markdown_filter.rb b/lib/gitlab/markdown/filter/markdown_filter.rb
deleted file mode 100644
index 921e2a0794e..00000000000
--- a/lib/gitlab/markdown/filter/markdown_filter.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-module Gitlab
- module Markdown
- class MarkdownFilter < HTML::Pipeline::TextFilter
- def initialize(text, context = nil, result = nil)
- super text, context, result
- @text = @text.gsub "\r", ''
- end
-
- def call
- html = self.class.renderer.render(@text)
- html.rstrip!
- html
- end
-
- private
-
- def self.redcarpet_options
- # https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use
- @redcarpet_options ||= {
- fenced_code_blocks: true,
- footnotes: true,
- lax_spacing: true,
- no_intra_emphasis: true,
- space_after_headers: true,
- strikethrough: true,
- superscript: true,
- tables: true
- }.freeze
- end
-
- def self.renderer
- @renderer ||= begin
- renderer = Redcarpet::Render::HTML.new
- Redcarpet::Markdown.new(renderer, redcarpet_options)
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/markdown/filter/merge_request_reference_filter.rb b/lib/gitlab/markdown/filter/merge_request_reference_filter.rb
deleted file mode 100644
index 2eb77c46da7..00000000000
--- a/lib/gitlab/markdown/filter/merge_request_reference_filter.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-require 'gitlab/markdown'
-
-module Gitlab
- module Markdown
- # HTML filter that replaces merge request references with links. References
- # to merge requests that do not exist are ignored.
- #
- # This filter supports cross-project references.
- class MergeRequestReferenceFilter < AbstractReferenceFilter
- def self.object_class
- MergeRequest
- end
-
- def find_object(project, id)
- project.merge_requests.find_by(iid: id)
- end
-
- def url_for_object(mr, project)
- h = Gitlab::Application.routes.url_helpers
- h.namespace_project_merge_request_url(project.namespace, project, mr,
- only_path: context[:only_path])
- end
-
- def object_link_text_extras(object, matches)
- extras = super
-
- path = matches[:path] if matches.names.include?("path")
- case path
- when '/diffs'
- extras.unshift "diffs"
- when '/commits'
- extras.unshift "commits"
- when '/builds'
- extras.unshift "builds"
- end
-
- extras
- end
- end
- end
-end
diff --git a/lib/gitlab/markdown/filter/redactor_filter.rb b/lib/gitlab/markdown/filter/redactor_filter.rb
deleted file mode 100644
index 33ef7ce18b5..00000000000
--- a/lib/gitlab/markdown/filter/redactor_filter.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-require 'gitlab/markdown'
-require 'html/pipeline/filter'
-
-module Gitlab
- module Markdown
- # HTML filter that removes references to records that the current user does
- # not have permission to view.
- #
- # Expected to be run in its own post-processing pipeline.
- #
- class RedactorFilter < HTML::Pipeline::Filter
- def call
- doc.css('a.gfm').each do |node|
- unless user_can_reference?(node)
- # The reference should be replaced by the original text,
- # which is not always the same as the rendered text.
- text = node.attr('data-original') || node.text
- node.replace(text)
- end
- end
-
- doc
- end
-
- private
-
- def user_can_reference?(node)
- if node.has_attribute?('data-reference-filter')
- reference_type = node.attr('data-reference-filter')
- reference_filter = Gitlab::Markdown.const_get(reference_type)
-
- reference_filter.user_can_reference?(current_user, node, context)
- else
- true
- end
- end
-
- def current_user
- context[:current_user]
- end
- end
- end
-end
diff --git a/lib/gitlab/markdown/filter/reference_gatherer_filter.rb b/lib/gitlab/markdown/filter/reference_gatherer_filter.rb
deleted file mode 100644
index 62f241b4967..00000000000
--- a/lib/gitlab/markdown/filter/reference_gatherer_filter.rb
+++ /dev/null
@@ -1,63 +0,0 @@
-require 'gitlab/markdown'
-require 'html/pipeline/filter'
-
-module Gitlab
- module Markdown
- # HTML filter that gathers all referenced records that the current user has
- # permission to view.
- #
- # Expected to be run in its own post-processing pipeline.
- #
- class ReferenceGathererFilter < HTML::Pipeline::Filter
- def initialize(*)
- super
-
- result[:references] ||= Hash.new { |hash, type| hash[type] = [] }
- end
-
- def call
- doc.css('a.gfm').each do |node|
- gather_references(node)
- end
-
- load_lazy_references unless context[:load_lazy_references] == false
-
- doc
- end
-
- private
-
- def gather_references(node)
- return unless node.has_attribute?('data-reference-filter')
-
- reference_type = node.attr('data-reference-filter')
- reference_filter = Gitlab::Markdown.const_get(reference_type)
-
- return if context[:reference_filter] && reference_filter != context[:reference_filter]
-
- return unless reference_filter.user_can_reference?(current_user, node, context)
-
- references = reference_filter.referenced_by(node)
- return unless references
-
- references.each do |type, values|
- Array.wrap(values).each do |value|
- result[:references][type] << value
- end
- end
- end
-
- # Will load all references of one type using one query.
- def load_lazy_references
- refs = result[:references]
- refs.each do |type, values|
- refs[type] = ReferenceFilter::LazyReference.load(values)
- end
- end
-
- def current_user
- context[:current_user]
- end
- end
- end
-end
diff --git a/lib/gitlab/markdown/filter/relative_link_filter.rb b/lib/gitlab/markdown/filter/relative_link_filter.rb
deleted file mode 100644
index 81f60120fcd..00000000000
--- a/lib/gitlab/markdown/filter/relative_link_filter.rb
+++ /dev/null
@@ -1,157 +0,0 @@
-require 'gitlab/markdown'
-require 'html/pipeline/filter'
-require 'uri'
-
-module Gitlab
- module Markdown
- # HTML filter that "fixes" relative links to files in a repository.
- #
- # Context options:
- # :commit
- # :project
- # :project_wiki
- # :ref
- # :requested_path
- class RelativeLinkFilter < HTML::Pipeline::Filter
- def call
- return doc unless linkable_files?
-
- doc.search('a:not(.gfm)').each do |el|
- process_link_attr el.attribute('href')
- end
-
- doc.search('img').each do |el|
- process_link_attr el.attribute('src')
- end
-
- doc
- end
-
- protected
-
- def linkable_files?
- context[:project_wiki].nil? && repository.try(:exists?) && !repository.empty?
- end
-
- def process_link_attr(html_attr)
- return if html_attr.blank?
-
- uri = URI(html_attr.value)
- if uri.relative? && uri.path.present?
- html_attr.value = rebuild_relative_uri(uri).to_s
- end
- rescue URI::Error
- # noop
- end
-
- def rebuild_relative_uri(uri)
- file_path = relative_file_path(uri.path)
-
- uri.path = [
- relative_url_root,
- context[:project].path_with_namespace,
- path_type(file_path),
- ref || context[:project].default_branch, # if no ref exists, point to the default branch
- file_path
- ].compact.join('/').squeeze('/').chomp('/')
-
- uri
- end
-
- def relative_file_path(path)
- nested_path = build_relative_path(path, context[:requested_path])
- file_exists?(nested_path) ? nested_path : path
- end
-
- # Convert a relative path into its correct location based on the currently
- # requested path
- #
- # path - Relative path String
- # request_path - Currently-requested path String
- #
- # Examples:
- #
- # # File in the same directory as the current path
- # build_relative_path("users.md", "doc/api/README.md")
- # # => "doc/api/users.md"
- #
- # # File in the same directory, which is also the current path
- # build_relative_path("users.md", "doc/api")
- # # => "doc/api/users.md"
- #
- # # Going up one level to a different directory
- # build_relative_path("../update/7.14-to-8.0.md", "doc/api/README.md")
- # # => "doc/update/7.14-to-8.0.md"
- #
- # Returns a String
- def build_relative_path(path, request_path)
- return request_path if path.empty?
- return path unless request_path
-
- parts = request_path.split('/')
- parts.pop if path_type(request_path) != 'tree'
-
- while parts.length > 1 && path.start_with?('../')
- parts.pop
- path.sub!('../', '')
- end
-
- parts.push(path).join('/')
- end
-
- def file_exists?(path)
- return false if path.nil?
- repository.blob_at(current_sha, path).present? ||
- repository.tree(current_sha, path).entries.any?
- end
-
- # Get the type of the given path
- #
- # path - String path to check
- #
- # Examples:
- #
- # path_type('doc/README.md') # => 'blob'
- # path_type('doc/logo.png') # => 'raw'
- # path_type('doc/api') # => 'tree'
- #
- # Returns a String
- def path_type(path)
- unescaped_path = Addressable::URI.unescape(path)
-
- if tree?(unescaped_path)
- 'tree'
- elsif image?(unescaped_path)
- 'raw'
- else
- 'blob'
- end
- end
-
- def tree?(path)
- repository.tree(current_sha, path).entries.any?
- end
-
- def image?(path)
- repository.blob_at(current_sha, path).try(:image?)
- end
-
- def current_sha
- context[:commit].try(:id) ||
- ref ? repository.commit(ref).try(:sha) : repository.head_commit.sha
- end
-
- def relative_url_root
- Gitlab.config.gitlab.relative_url_root.presence || '/'
- end
-
- def ref
- context[:ref]
- end
-
- def repository
- context[:project].try(:repository)
- end
- end
- end
-end
diff --git a/lib/gitlab/markdown/filter/sanitization_filter.rb b/lib/gitlab/markdown/filter/sanitization_filter.rb
deleted file mode 100644
index cf153f30622..00000000000
--- a/lib/gitlab/markdown/filter/sanitization_filter.rb
+++ /dev/null
@@ -1,99 +0,0 @@
-require 'gitlab/markdown'
-require 'html/pipeline/filter'
-require 'html/pipeline/sanitization_filter'
-
-module Gitlab
- module Markdown
- # Sanitize HTML
- #
- # Extends HTML::Pipeline::SanitizationFilter with a custom whitelist.
- class SanitizationFilter < HTML::Pipeline::SanitizationFilter
- def whitelist
- # Descriptions are more heavily sanitized, allowing only a few elements.
- # See http://git.io/vkuAN
- if context[:inline_sanitization]
- whitelist = LIMITED
- whitelist[:elements] -= %w(pre code img ol ul li)
- else
- whitelist = super
- end
-
- customize_whitelist(whitelist)
-
- whitelist
- end
-
- private
-
- def customized?(transformers)
- transformers.last.source_location[0] == __FILE__
- end
-
- def customize_whitelist(whitelist)
- # Only push these customizations once
- return if customized?(whitelist[:transformers])
-
- # Allow code highlighting
- whitelist[:attributes]['pre'] = %w(class)
- whitelist[:attributes]['span'] = %w(class)
-
- # Allow table alignment
- whitelist[:attributes]['th'] = %w(style)
- whitelist[:attributes]['td'] = %w(style)
-
- # Allow span elements
- whitelist[:elements].push('span')
-
- # Allow any protocol in `a` elements...
- whitelist[:protocols].delete('a')
-
- # ...but then remove links with the `javascript` protocol
- whitelist[:transformers].push(remove_javascript_links)
-
- # Remove `rel` attribute from `a` elements
- whitelist[:transformers].push(remove_rel)
-
- # Remove `class` attribute from non-highlight spans
- whitelist[:transformers].push(clean_spans)
-
- whitelist
- end
-
- def remove_javascript_links
- lambda do |env|
- node = env[:node]
-
- return unless node.name == 'a'
- return unless node.has_attribute?('href')
-
- if node['href'].start_with?('javascript', ':javascript')
- node.remove_attribute('href')
- end
- end
- end
-
- def remove_rel
- lambda do |env|
- if env[:node_name] == 'a'
- env[:node].remove_attribute('rel')
- end
- end
- end
-
- def clean_spans
- lambda do |env|
- node = env[:node]
-
- return unless node.name == 'span'
- return unless node.has_attribute?('class')
-
- unless has_ancestor?(node, 'pre')
- node.remove_attribute('class')
- end
-
- { node_whitelist: [node] }
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/markdown/filter/snippet_reference_filter.rb b/lib/gitlab/markdown/filter/snippet_reference_filter.rb
deleted file mode 100644
index f7bd07c2a34..00000000000
--- a/lib/gitlab/markdown/filter/snippet_reference_filter.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-require 'gitlab/markdown'
-
-module Gitlab
- module Markdown
- # HTML filter that replaces snippet references with links. References to
- # snippets that do not exist are ignored.
- #
- # This filter supports cross-project references.
- class SnippetReferenceFilter < AbstractReferenceFilter
- def self.object_class
- Snippet
- end
-
- def find_object(project, id)
- project.snippets.find_by(id: id)
- end
-
- def url_for_object(snippet, project)
- h = Gitlab::Application.routes.url_helpers
- h.namespace_project_snippet_url(project.namespace, project, snippet,
- only_path: context[:only_path])
- end
- end
- end
-end
diff --git a/lib/gitlab/markdown/filter/syntax_highlight_filter.rb b/lib/gitlab/markdown/filter/syntax_highlight_filter.rb
deleted file mode 100644
index 8597e02f0de..00000000000
--- a/lib/gitlab/markdown/filter/syntax_highlight_filter.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-require 'gitlab/markdown'
-require 'html/pipeline/filter'
-require 'rouge/plugins/redcarpet'
-
-module Gitlab
- module Markdown
- # HTML Filter to highlight fenced code blocks
- #
- class SyntaxHighlightFilter < HTML::Pipeline::Filter
- include Rouge::Plugins::Redcarpet
-
- def call
- doc.search('pre > code').each do |node|
- highlight_node(node)
- end
-
- doc
- end
-
- def highlight_node(node)
- language = node.attr('class')
- code = node.text
-
- begin
- highlighted = block_code(code, language)
- rescue
- # Gracefully handle syntax highlighter bugs/errors to ensure
- # users can still access an issue/comment/etc.
- highlighted = "<pre>#{code}</pre>"
- end
-
- # Replace the parent `pre` element with the entire highlighted block
- node.parent.replace(highlighted)
- end
-
- private
-
- # Override Rouge::Plugins::Redcarpet#rouge_formatter
- def rouge_formatter(lexer)
- Rouge::Formatters::HTMLGitlab.new(
- cssclass: "code highlight js-syntax-highlight #{lexer.tag}")
- end
- end
- end
-end
diff --git a/lib/gitlab/markdown/filter/table_of_contents_filter.rb b/lib/gitlab/markdown/filter/table_of_contents_filter.rb
deleted file mode 100644
index bbb3bf7fc8b..00000000000
--- a/lib/gitlab/markdown/filter/table_of_contents_filter.rb
+++ /dev/null
@@ -1,63 +0,0 @@
-require 'gitlab/markdown'
-require 'html/pipeline/filter'
-
-module Gitlab
- module Markdown
- # HTML filter that adds an anchor child element to all Headers in a
- # document, so that they can be linked to.
- #
- # Generates the Table of Contents with links to each header. See Results.
- #
- # Based on HTML::Pipeline::TableOfContentsFilter.
- #
- # Context options:
- # :no_header_anchors - Skips all processing done by this filter.
- #
- # Results:
- # :toc - String containing Table of Contents data as a `ul` element with
- # `li` child elements.
- class TableOfContentsFilter < HTML::Pipeline::Filter
- PUNCTUATION_REGEXP = /[^\p{Word}\- ]/u
-
- def call
- return doc if context[:no_header_anchors]
-
- result[:toc] = ""
-
- headers = Hash.new(0)
-
- doc.css('h1, h2, h3, h4, h5, h6').each do |node|
- text = node.text
-
- id = text.downcase
- id.gsub!(PUNCTUATION_REGEXP, '') # remove punctuation
- id.gsub!(' ', '-') # replace spaces with dash
- id.squeeze!('-') # replace multiple dashes with one
-
- uniq = (headers[id] > 0) ? "-#{headers[id]}" : ''
- headers[id] += 1
-
- if header_content = node.children.first
- href = "#{id}#{uniq}"
- push_toc(href, text)
- header_content.add_previous_sibling(anchor_tag(href))
- end
- end
-
- result[:toc] = %Q{<ul class="section-nav">\n#{result[:toc]}</ul>} unless result[:toc].empty?
-
- doc
- end
-
- private
-
- def anchor_tag(href)
- %Q{<a id="#{href}" class="anchor" href="##{href}" aria-hidden="true"></a>}
- end
-
- def push_toc(href, text)
- result[:toc] << %Q{<li><a href="##{href}">#{text}</a></li>\n}
- end
- end
- end
-end
diff --git a/lib/gitlab/markdown/filter/task_list_filter.rb b/lib/gitlab/markdown/filter/task_list_filter.rb
deleted file mode 100644
index 2f133ae8500..00000000000
--- a/lib/gitlab/markdown/filter/task_list_filter.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require 'gitlab/markdown'
-require 'task_list/filter'
-
-module Gitlab
- module Markdown
- # Work around a bug in the default TaskList::Filter that adds a `task-list`
- # class to every list element, regardless of whether or not it contains a
- # task list.
- #
- # This is a (hopefully) temporary fix, pending a new release of the
- # task_list gem.
- #
- # See https://github.com/github/task_list/pull/60
- class TaskListFilter < TaskList::Filter
- def add_css_class(node, *new_class_names)
- if new_class_names.include?('task-list')
- super if node.children.any? { |c| c['class'] == 'task-list-item' }
- else
- super
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/markdown/filter/upload_link_filter.rb b/lib/gitlab/markdown/filter/upload_link_filter.rb
deleted file mode 100644
index fbada73ab86..00000000000
--- a/lib/gitlab/markdown/filter/upload_link_filter.rb
+++ /dev/null
@@ -1,47 +0,0 @@
-require 'gitlab/markdown'
-require 'html/pipeline/filter'
-require 'uri'
-
-module Gitlab
- module Markdown
- # HTML filter that "fixes" relative upload links to files.
- # Context options:
- # :project (required) - Current project
- #
- class UploadLinkFilter < HTML::Pipeline::Filter
- def call
- doc.search('a').each do |el|
- process_link_attr el.attribute('href')
- end
-
- doc.search('img').each do |el|
- process_link_attr el.attribute('src')
- end
-
- doc
- end
-
- protected
-
- def process_link_attr(html_attr)
- return if html_attr.blank?
-
- uri = html_attr.value
- if uri.starts_with?("/uploads/")
- html_attr.value = build_url(uri).to_s
- end
- end
-
- def build_url(uri)
- File.join(Gitlab.config.gitlab.url, context[:project].path_with_namespace, uri)
- end
-
- # Ensure that a :project key exists in context
- #
- # Note that while the key might exist, its value could be nil!
- def validate
- needs :project
- end
- end
- end
-end
diff --git a/lib/gitlab/markdown/filter/user_reference_filter.rb b/lib/gitlab/markdown/filter/user_reference_filter.rb
deleted file mode 100644
index 0a20d9c0347..00000000000
--- a/lib/gitlab/markdown/filter/user_reference_filter.rb
+++ /dev/null
@@ -1,129 +0,0 @@
-require 'gitlab/markdown'
-
-module Gitlab
- module Markdown
- # HTML filter that replaces user or group references with links.
- #
- # A special `@all` reference is also supported.
- class UserReferenceFilter < ReferenceFilter
- # Public: Find `@user` user references in text
- #
- # UserReferenceFilter.references_in(text) do |match, username|
- # "<a href=...>@#{user}</a>"
- # end
- #
- # text - String text to search.
- #
- # Yields the String match, and the String user name.
- #
- # Returns a String replaced with the return of the block.
- def self.references_in(text)
- text.gsub(User.reference_pattern) do |match|
- yield match, $~[:user]
- end
- end
-
- def self.referenced_by(node)
- if node.has_attribute?('data-group')
- group = Group.find(node.attr('data-group')) rescue nil
- return unless group
-
- { user: group.users }
- elsif node.has_attribute?('data-user')
- { user: LazyReference.new(User, node.attr('data-user')) }
- elsif node.has_attribute?('data-project')
- project = Project.find(node.attr('data-project')) rescue nil
- return unless project
-
- { user: project.team.members.flatten }
- end
- end
-
- def self.user_can_reference?(user, node, context)
- if node.has_attribute?('data-group')
- group = Group.find(node.attr('data-group')) rescue nil
- Ability.abilities.allowed?(user, :read_group, group)
- else
- super
- end
- end
-
- def call
- replace_text_nodes_matching(User.reference_pattern) do |content|
- user_link_filter(content)
- end
-
- replace_link_nodes_with_href(User.reference_pattern) do |link, text|
- user_link_filter(link, link_text: text)
- end
- end
-
- # Replace `@user` user references in text with links to the referenced
- # user's profile page.
- #
- # text - String text to replace references in.
- #
- # Returns a String with `@user` references replaced with links. All links
- # have `gfm` and `gfm-project_member` class names attached for styling.
- def user_link_filter(text, link_text: nil)
- self.class.references_in(text) do |match, username|
- if username == 'all'
- link_to_all(link_text: link_text)
- elsif namespace = Namespace.find_by(path: username)
- link_to_namespace(namespace, link_text: link_text) || match
- else
- match
- end
- end
- end
-
- private
-
- def urls
- Gitlab::Application.routes.url_helpers
- end
-
- def link_class
- reference_class(:project_member)
- end
-
- def link_to_all(link_text: nil)
- project = context[:project]
- url = urls.namespace_project_url(project.namespace, project,
- only_path: context[:only_path])
- data = data_attribute(project: project.id)
- text = link_text || User.reference_prefix + 'all'
-
- link_tag(url, data, text)
- end
-
- def link_to_namespace(namespace, link_text: nil)
- if namespace.is_a?(Group)
- link_to_group(namespace.path, namespace, link_text: link_text)
- else
- link_to_user(namespace.path, namespace, link_text: link_text)
- end
- end
-
- def link_to_group(group, namespace, link_text: nil)
- url = urls.group_url(group, only_path: context[:only_path])
- data = data_attribute(group: namespace.id)
- text = link_text || Group.reference_prefix + group
-
- link_tag(url, data, text)
- end
-
- def link_to_user(user, namespace, link_text: nil)
- url = urls.user_url(user, only_path: context[:only_path])
- data = data_attribute(user: namespace.owner_id)
- text = link_text || User.reference_prefix + user
-
- link_tag(url, data, text)
- end
-
- def link_tag(url, data, text)
- %(<a href="#{url}" #{data} class="#{link_class}">#{text}</a>)
- end
- end
- end
-end