2018-07-23 09:32:32 +00:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2016-04-01 03:17:37 +00:00
|
|
|
module Banzai
|
|
|
|
module Filter
|
2016-06-08 04:59:20 +00:00
|
|
|
# HTML filter that "fixes" links to pages/files in a wiki.
|
|
|
|
# Rewrite rules are documented in the `WikiPipeline` spec.
|
2016-04-01 03:17:37 +00:00
|
|
|
#
|
|
|
|
# Context options:
|
2020-05-25 21:08:00 +00:00
|
|
|
# :wiki
|
2016-04-01 03:17:37 +00:00
|
|
|
class WikiLinkFilter < HTML::Pipeline::Filter
|
Extract SanitizeNodeLink and apply to WikiLinkFilter
The SanitizationFilter was running before the WikiFilter. Since
WikiFilter can modify links, we could see links that _should_ be stopped
by SanatizationFilter being rendered on the page. I (kerrizor) had
previously addressed the bug in: https://gitlab.com/gitlab-org/gitlab-ee/commit/7bc971915bbeadb950bb0e1f13510bf3038229a4
However, an additional exploit was discovered after that was merged.
Working through the issue, we couldn't simply shuffle the order of
filters, due to some implicit assumptions about the order of filters, so
instead we've extracted the logic that sanitizes a Nokogiri-generated
Node object, and applied it to the WikiLinkFilter as well.
On moving filters around:
Once we start moving around filters, we get cascading failures; fix one,
another one crops up. Many of the existing filters in the WikiPipeline
chain seem to assume that other filters have already done their work,
and thus operate on a "transform anything that's left" basis;
WikiFilter, for instance, assumes any link it finds in the markdown
should be prepended with the wiki_base_path.. but if it does that, it
also turns `href="@user"` into `href="/path/to/wiki/@user"`, which the
UserReferenceFilter doesn't see as a user reference it needs to
transform into a user profile link. This is true for all the reference
filters in the WikiPipeline.
2019-07-26 13:41:11 +00:00
|
|
|
include Gitlab::Utils::SanitizeNodeLink
|
|
|
|
|
2016-04-01 03:17:37 +00:00
|
|
|
def call
|
2020-05-25 21:08:00 +00:00
|
|
|
return doc unless wiki?
|
2016-04-01 03:17:37 +00:00
|
|
|
|
Extract SanitizeNodeLink and apply to WikiLinkFilter
The SanitizationFilter was running before the WikiFilter. Since
WikiFilter can modify links, we could see links that _should_ be stopped
by SanatizationFilter being rendered on the page. I (kerrizor) had
previously addressed the bug in: https://gitlab.com/gitlab-org/gitlab-ee/commit/7bc971915bbeadb950bb0e1f13510bf3038229a4
However, an additional exploit was discovered after that was merged.
Working through the issue, we couldn't simply shuffle the order of
filters, due to some implicit assumptions about the order of filters, so
instead we've extracted the logic that sanitizes a Nokogiri-generated
Node object, and applied it to the WikiLinkFilter as well.
On moving filters around:
Once we start moving around filters, we get cascading failures; fix one,
another one crops up. Many of the existing filters in the WikiPipeline
chain seem to assume that other filters have already done their work,
and thus operate on a "transform anything that's left" basis;
WikiFilter, for instance, assumes any link it finds in the markdown
should be prepended with the wiki_base_path.. but if it does that, it
also turns `href="@user"` into `href="/path/to/wiki/@user"`, which the
UserReferenceFilter doesn't see as a user reference it needs to
transform into a user profile link. This is true for all the reference
filters in the WikiPipeline.
2019-07-26 13:41:11 +00:00
|
|
|
doc.search('a:not(.gfm)').each { |el| process_link(el.attribute('href'), el) }
|
|
|
|
|
2019-10-09 12:06:13 +00:00
|
|
|
doc.search('video, audio').each { |el| process_link(el.attribute('src'), el) }
|
Extract SanitizeNodeLink and apply to WikiLinkFilter
The SanitizationFilter was running before the WikiFilter. Since
WikiFilter can modify links, we could see links that _should_ be stopped
by SanatizationFilter being rendered on the page. I (kerrizor) had
previously addressed the bug in: https://gitlab.com/gitlab-org/gitlab-ee/commit/7bc971915bbeadb950bb0e1f13510bf3038229a4
However, an additional exploit was discovered after that was merged.
Working through the issue, we couldn't simply shuffle the order of
filters, due to some implicit assumptions about the order of filters, so
instead we've extracted the logic that sanitizes a Nokogiri-generated
Node object, and applied it to the WikiLinkFilter as well.
On moving filters around:
Once we start moving around filters, we get cascading failures; fix one,
another one crops up. Many of the existing filters in the WikiPipeline
chain seem to assume that other filters have already done their work,
and thus operate on a "transform anything that's left" basis;
WikiFilter, for instance, assumes any link it finds in the markdown
should be prepended with the wiki_base_path.. but if it does that, it
also turns `href="@user"` into `href="/path/to/wiki/@user"`, which the
UserReferenceFilter doesn't see as a user reference it needs to
transform into a user profile link. This is true for all the reference
filters in the WikiPipeline.
2019-07-26 13:41:11 +00:00
|
|
|
|
2018-09-04 10:39:08 +00:00
|
|
|
doc.search('img').each do |el|
|
|
|
|
attr = el.attribute('data-src') || el.attribute('src')
|
|
|
|
|
Extract SanitizeNodeLink and apply to WikiLinkFilter
The SanitizationFilter was running before the WikiFilter. Since
WikiFilter can modify links, we could see links that _should_ be stopped
by SanatizationFilter being rendered on the page. I (kerrizor) had
previously addressed the bug in: https://gitlab.com/gitlab-org/gitlab-ee/commit/7bc971915bbeadb950bb0e1f13510bf3038229a4
However, an additional exploit was discovered after that was merged.
Working through the issue, we couldn't simply shuffle the order of
filters, due to some implicit assumptions about the order of filters, so
instead we've extracted the logic that sanitizes a Nokogiri-generated
Node object, and applied it to the WikiLinkFilter as well.
On moving filters around:
Once we start moving around filters, we get cascading failures; fix one,
another one crops up. Many of the existing filters in the WikiPipeline
chain seem to assume that other filters have already done their work,
and thus operate on a "transform anything that's left" basis;
WikiFilter, for instance, assumes any link it finds in the markdown
should be prepended with the wiki_base_path.. but if it does that, it
also turns `href="@user"` into `href="/path/to/wiki/@user"`, which the
UserReferenceFilter doesn't see as a user reference it needs to
transform into a user profile link. This is true for all the reference
filters in the WikiPipeline.
2019-07-26 13:41:11 +00:00
|
|
|
process_link(attr, el)
|
2016-04-01 03:17:37 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
doc
|
|
|
|
end
|
|
|
|
|
|
|
|
protected
|
|
|
|
|
Extract SanitizeNodeLink and apply to WikiLinkFilter
The SanitizationFilter was running before the WikiFilter. Since
WikiFilter can modify links, we could see links that _should_ be stopped
by SanatizationFilter being rendered on the page. I (kerrizor) had
previously addressed the bug in: https://gitlab.com/gitlab-org/gitlab-ee/commit/7bc971915bbeadb950bb0e1f13510bf3038229a4
However, an additional exploit was discovered after that was merged.
Working through the issue, we couldn't simply shuffle the order of
filters, due to some implicit assumptions about the order of filters, so
instead we've extracted the logic that sanitizes a Nokogiri-generated
Node object, and applied it to the WikiLinkFilter as well.
On moving filters around:
Once we start moving around filters, we get cascading failures; fix one,
another one crops up. Many of the existing filters in the WikiPipeline
chain seem to assume that other filters have already done their work,
and thus operate on a "transform anything that's left" basis;
WikiFilter, for instance, assumes any link it finds in the markdown
should be prepended with the wiki_base_path.. but if it does that, it
also turns `href="@user"` into `href="/path/to/wiki/@user"`, which the
UserReferenceFilter doesn't see as a user reference it needs to
transform into a user profile link. This is true for all the reference
filters in the WikiPipeline.
2019-07-26 13:41:11 +00:00
|
|
|
def process_link(link_attr, node)
|
|
|
|
process_link_attr(link_attr)
|
|
|
|
remove_unsafe_links({ node: node }, remove_invalid_links: false)
|
|
|
|
end
|
|
|
|
|
2020-05-25 21:08:00 +00:00
|
|
|
def wiki?
|
|
|
|
!context[:wiki].nil?
|
2016-04-01 03:17:37 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def process_link_attr(html_attr)
|
2016-06-08 04:59:20 +00:00
|
|
|
return if html_attr.blank?
|
2016-04-01 03:17:37 +00:00
|
|
|
|
2016-06-08 04:59:20 +00:00
|
|
|
html_attr.value = apply_rewrite_rules(html_attr.value)
|
2016-06-18 08:40:40 +00:00
|
|
|
rescue URI::Error, Addressable::URI::InvalidURIError
|
2016-04-01 03:17:37 +00:00
|
|
|
# noop
|
|
|
|
end
|
|
|
|
|
2016-06-08 04:59:20 +00:00
|
|
|
def apply_rewrite_rules(link_string)
|
2020-05-25 21:08:00 +00:00
|
|
|
Rewriter.new(link_string, wiki: context[:wiki], slug: context[:page_slug]).apply_rules
|
2016-04-01 03:17:37 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|