Module: StillActive::MarkdownEscape
Overview
Escaping for untrusted metadata (gem names, licences, versions, repo URLs, advisory ids) rendered into GitHub-Flavored Markdown. These values come from registry/repo metadata, a Gemfile/lockfile, a –baseline file, or –gems input, so they can contain markdown-structural characters. Centralised so the table renderer (MarkdownHelper) and the diff renderer (DiffMarkdownHelper) can’t drift apart on what’s safe.
Instance Method Summary collapse
-
#cell(text) ⇒ Object
Table cell: a literal “|” or newline would forge columns or break the row.
-
#code_span(text) ⇒ Object
Wrap arbitrary text in an inline code span safely.
-
#inline(text) ⇒ Object
Inline (non-table) free text in a bullet list: neutralise newlines (which would break the list) and brackets/backslash (which could forge a link).
-
#link_text(text) ⇒ Object
Link text additionally must not contain “[” or “]”, which could forge or truncate the link.
-
#url(value) ⇒ Object
Link destination: percent-encode the characters that would break out of a “(…)” destination or the table row.
Instance Method Details
#cell(text) ⇒ Object
Table cell: a literal “|” or newline would forge columns or break the row. Backslash is escaped first so it can’t escape a following delimiter.
15 16 17 18 19 |
# File 'lib/helpers/markdown_escape.rb', line 15 def cell(text) return text if text.nil? text.to_s.gsub(/[\\|\r\n]/, "\\" => "\\\\", "|" => "\\|", "\r" => " ", "\n" => " ") end |
#code_span(text) ⇒ Object
Wrap arbitrary text in an inline code span safely. A backtick in the text would otherwise close the span early, so use a backtick fence longer than the longest run in the content (and pad when it starts/ends with one), per the GFM code-span rules. Newlines collapse to spaces.
49 50 51 52 53 54 55 56 |
# File 'lib/helpers/markdown_escape.rb', line 49 def code_span(text) content = text.to_s.tr("\r\n", " ") return "`#{content}`" unless content.include?("`") fence = "`" * (content.scan(/`+/).map(&:length).max + 1) pad = content.start_with?("`") || content.end_with?("`") ? " " : "" "#{fence}#{pad}#{content}#{pad}#{fence}" end |
#inline(text) ⇒ Object
Inline (non-table) free text in a bullet list: neutralise newlines (which would break the list) and brackets/backslash (which could forge a link).
39 40 41 42 43 |
# File 'lib/helpers/markdown_escape.rb', line 39 def inline(text) return text if text.nil? text.to_s.gsub(/[\\\[\]\r\n]/, "\\" => "\\\\", "[" => "\\[", "]" => "\\]", "\r" => " ", "\n" => " ") end |
#link_text(text) ⇒ Object
Link text additionally must not contain “[” or “]”, which could forge or truncate the link.
23 24 25 26 27 |
# File 'lib/helpers/markdown_escape.rb', line 23 def link_text(text) return text if text.nil? cell(text).gsub(/[\[\]]/, "[" => "\\[", "]" => "\\]") end |
#url(value) ⇒ Object
Link destination: percent-encode the characters that would break out of a “(…)” destination or the table row. Lossless for legitimate http(s) URLs.
31 32 33 34 35 |
# File 'lib/helpers/markdown_escape.rb', line 31 def url(value) return value if value.nil? value.to_s.gsub(/[|() \t\r\n]/, "|" => "%7C", "(" => "%28", ")" => "%29", " " => "%20", "\t" => "%09", "\r" => "%0D", "\n" => "%0A") end |