rewriter.rb 2.0 KB
Newer Older
G
gfyoung 已提交
1 2
# frozen_string_literal: true

3 4 5 6
module Banzai
  module Filter
    class WikiLinkFilter < HTML::Pipeline::Filter
      class Rewriter
7 8
        UNSAFE_SLUG_REGEXES = [/\Ajavascript:/i].freeze

9 10 11 12 13 14 15
        def initialize(link_string, wiki:, slug:)
          @uri = Addressable::URI.parse(link_string)
          @wiki_base_path = wiki && wiki.wiki_base_path
          @slug = slug
        end

        def apply_rules
16
          # Special case: relative URLs beginning with `/uploads/` refer to
17 18 19 20 21 22 23 24 25
          # user-uploaded files will be handled elsewhere.
          return @uri.to_s if public_upload?

          # Special case: relative URLs beginning with Wikis::CreateAttachmentService::ATTACHMENT_PATH
          # refer to user-uploaded files to the wiki repository.
          unless repository_upload?
            apply_file_link_rules!
            apply_hierarchical_link_rules!
          end
26

27 28 29 30 31 32 33 34 35 36 37 38 39
          apply_relative_link_rules!
          @uri.to_s
        end

        private

        # Of the form 'file.md'
        def apply_file_link_rules!
          @uri = Addressable::URI.join(@slug, @uri) if @uri.extname.present?
        end

        # Of the form `./link`, `../link`, or similar
        def apply_hierarchical_link_rules!
40 41
          return if slug_considered_unsafe?

42 43 44 45 46 47 48
          @uri = Addressable::URI.join(@slug, @uri) if @uri.to_s[0] == '.'
        end

        # Any link _not_ of the form `http://example.com/`
        def apply_relative_link_rules!
          if @uri.relative? && @uri.path.present?
            link = ::File.join(@wiki_base_path, @uri.path)
Q
Qingping Hou 已提交
49
            link = "#{link}##{@uri.fragment}" if @uri.fragment
50 51 52
            @uri = Addressable::URI.parse(link)
          end
        end
53 54 55 56 57 58 59 60

        def public_upload?
          @uri.relative? && @uri.path.starts_with?('/uploads/')
        end

        def repository_upload?
          @uri.relative? && @uri.path.starts_with?(Wikis::CreateAttachmentService::ATTACHMENT_PATH)
        end
61 62 63 64

        def slug_considered_unsafe?
          UNSAFE_SLUG_REGEXES.any? { |r| r.match?(@slug) }
        end
65 66 67 68
      end
    end
  end
end