class Dependabot::PullRequestCreator::MessageBuilder::LinkAndMentionSanitizer
def build_mention_link_text_nodes(text)
def build_mention_link_text_nodes(text) code_node = CommonMarker::Node.new(:code) code_node.string_content = insert_zero_width_space_in_mention(text) [code_node] end
def build_mention_nodes(text)
def build_mention_nodes(text) nodes = T.let([], T::Array[CommonMarker::Node]) scan = StringScanner.new(text) until scan.eos? line = scan.scan_until(MENTION_REGEX) || scan.scan_until(EOS_REGEX) line_match = T.must(line).match(MENTION_REGEX) mention = line_match&.to_s text_node = CommonMarker::Node.new(:text) if mention && !mention.end_with?("/") text_node.string_content = line_match.pre_match nodes << text_node nodes << create_link_node( "https://github.com/#{mention.tr('@', '')}", mention.to_s ) else text_node.string_content = line nodes << text_node end end nodes end
def build_nwo_text_node(text)
def build_nwo_text_node(text) code_node = CommonMarker::Node.new(:code) code_node.string_content = text code_node end
def build_team_mention_nodes(text)
def build_team_mention_nodes(text) nodes = T.let([], T::Array[CommonMarker::Node]) scan = StringScanner.new(text) until scan.eos? line = scan.scan_until(TEAM_MENTION_REGEX) || scan.scan_until(EOS_REGEX) line_match = T.must(line).match(TEAM_MENTION_REGEX) mention = line_match&.to_s text_node = CommonMarker::Node.new(:text) if mention text_node.string_content = line_match.pre_match nodes << text_node nodes += build_mention_link_text_nodes(mention.to_s) else text_node.string_content = line nodes << text_node end end nodes end
def create_link_node(url, text)
def create_link_node(url, text) link_node = CommonMarker::Node.new(:link) code_node = CommonMarker::Node.new(:code) link_node.url = url code_node.string_content = insert_zero_width_space_in_mention(text) link_node.append_child(code_node) link_node end
def initialize(github_redirection_service:)
def initialize(github_redirection_service:) @github_redirection_service = github_redirection_service end
def insert_zero_width_space_in_mention(mention)
def insert_zero_width_space_in_mention(mention) mention.sub("@", "@\u200B").encode("utf-8") end
def parent_node_link?(node)
def parent_node_link?(node) node.type == :link || (!node.parent.nil? && parent_node_link?(T.must(node.parent))) end
def replace_github_host(text)
def replace_github_host(text) return text if !github_redirection_service.nil? && text.include?(T.must(github_redirection_service)) text.gsub( /(www\.)?github.com/, github_redirection_service || "github.com" ) end
def replace_nwo_node(node)
def replace_nwo_node(node) match = T.must(node.string_content.match(GITHUB_NWO_REGEX)) repo = match.named_captures.fetch("repo") number = match.named_captures.fetch("number") new_node = build_nwo_text_node("#{repo}##{number}") node.insert_before(new_node) node.delete end
def sanitize_links(doc)
def sanitize_links(doc) doc.walk do |node| if node.type == :link && node.url.match?(GITHUB_REF_REGEX) node.each do |subnode| unless subnode.type == :text && subnode.string_content.match?(GITHUB_REF_REGEX) next end last_match = T.must(subnode.string_content.match(GITHUB_REF_REGEX)) number = last_match.named_captures.fetch("number") repo = last_match.named_captures.fetch("repo") subnode.string_content = "#{repo}##{number}" end node.url = replace_github_host(node.url) elsif node.type == :text && node.string_content.match?(GITHUB_REF_REGEX) node.string_content = replace_github_host(node.string_content) end end end
def sanitize_links_and_mentions(text:, unsafe: false, format_html: true)
def sanitize_links_and_mentions(text:, unsafe: false, format_html: true) doc = CommonMarker.render_doc( text, :LIBERAL_HTML_TAG, COMMONMARKER_EXTENSIONS ) sanitize_team_mentions(doc) sanitize_mentions(doc) sanitize_links(doc) sanitize_nwo_text(doc) render_options = if text.match?(MARKDOWN_REGEX) COMMONMARKER_OPTIONS else COMMONMARKER_OPTIONS + [:HARDBREAKS] end mode = unsafe ? :UNSAFE : :DEFAULT return doc.to_commonmark([mode] + render_options) unless format_html doc.to_html(([mode] + render_options), COMMONMARKER_EXTENSIONS) end
def sanitize_mentions(doc)
def sanitize_mentions(doc) doc.walk do |node| if node.type == :text && node.string_content.match?(MENTION_REGEX) nodes = if parent_node_link?(node) build_mention_link_text_nodes(node.string_content) else build_mention_nodes(node.string_content) end nodes.each do |n| node.insert_before(n) end node.delete end end end
def sanitize_nwo_text(doc)
def sanitize_nwo_text(doc) doc.walk do |node| if node.type == :text && node.string_content.match?(GITHUB_NWO_REGEX) && !parent_node_link?(node) replace_nwo_node(node) end end end
def sanitize_team_mentions(doc)
def sanitize_team_mentions(doc) doc.walk do |node| if node.type == :text && node.string_content.match?(TEAM_MENTION_REGEX) nodes = build_team_mention_nodes(node.string_content) nodes.each do |n| node.insert_before(n) end node.delete end end end