diff --git a/ext/markdown2.py b/ext/markdown2.py index f34576e51b..5048413ce8 100644 --- a/ext/markdown2.py +++ b/ext/markdown2.py @@ -96,7 +96,7 @@ # not yet sure if there implications with this. Compare 'pydoc sre' # and 'perldoc perlre'. -__version_info__ = (2, 3, 8) +__version_info__ = (2, 3, 9) __version__ = '.'.join(map(str, __version_info__)) __author__ = "Trent Mick" @@ -200,7 +200,10 @@ class Markdown(object): titles = None html_blocks = None html_spans = None - html_removed_text = "[HTML_REMOVED]" # for compat with markdown.py + html_removed_text = "{(#HTML#)}" # placeholder removed text that does not trigger bold + html_removed_text_compat = "[HTML_REMOVED]" # for compat with markdown.py + + _toc = None # Used to track when we're inside an ordered or unordered list # (see _ProcessListItems() for details): @@ -217,6 +220,7 @@ def __init__(self, html4tags=False, tab_width=4, safe_mode=None, else: self.empty_element_suffix = " />" self.tab_width = tab_width + self.tab = tab_width * " " # For compatibility with earlier markdown2.py and with # markdown.py's safe_mode being a boolean, @@ -273,6 +277,7 @@ def reset(self): self._count_from_header_id = defaultdict(int) if "metadata" in self.extras: self.metadata = {} + self._toc = None # Per "rel" # should only be used in tags with an "href" attribute. @@ -384,6 +389,8 @@ def convert(self, text): if self.safe_mode: text = self._unhash_html_spans(text) + # return the removed text warning to its markdown.py compatible form + text = text.replace(self.html_removed_text, self.html_removed_text_compat) if "nofollow" in self.extras: text = self._a_nofollow.sub(r'<\1 rel="nofollow"\2', text) @@ -1070,23 +1077,43 @@ def _do_tables(self, text): def _wiki_table_sub(self, match): ttext = match.group(0).strip() - # print 'wiki table: %r' % match.group(0) + # print('wiki table: %r' % match.group(0)) rows = [] for line in ttext.splitlines(0): line = line.strip()[2:-2].strip() row = [c.strip() for c in re.split(r'(?' % self._html_class_str_from_tag('table'), ''] - for row in rows: - hrow = [''] - for cell in row: - hrow.append('') - hrow.append(self._run_span_gamut(cell)) - hrow.append('') - hrow.append('') - hlines.append(''.join(hrow)) - hlines += ['', ''] + hlines = [] + + def add_hline(line, indents=0): + hlines.append((self.tab * indents) + line) + + def format_cell(text): + return self._run_span_gamut(re.sub(r"^\s*~", "", cell).strip(" ")) + + add_hline('' % self._html_class_str_from_tag('table')) + # Check if first cell of first row is a header cell. If so, assume the whole row is a header row. + if rows and rows[0] and re.match(r"^\s*~", rows[0][0]): + add_hline('', 1) + add_hline('', 2) + for cell in rows[0]: + add_hline("{}".format(format_cell(cell)), 3) + add_hline('', 2) + add_hline('', 1) + # Only one header row allowed. + rows = rows[1:] + # If no more rows, don't create a tbody. + if rows: + add_hline('', 1) + for row in rows: + add_hline('', 2) + for cell in row: + add_hline('{}'.format(format_cell(cell)), 3) + add_hline('', 2) + add_hline('', 1) + add_hline('') return '\n'.join(hlines) + '\n' def _do_wiki_tables(self, text): @@ -1351,6 +1378,11 @@ def _do_links(self, text): continue link_text = text[start_idx+1:p] + # Fix for issue 341 - Injecting XSS into link text + if self.safe_mode: + link_text = self._hash_html_spans(link_text) + link_text = self._unhash_html_spans(link_text) + # Possibly a footnote ref? if "footnotes" in self.extras and link_text.startswith("^"): normed_id = re.sub(r'\W', '-', link_text[1:]) @@ -1509,7 +1541,6 @@ def header_id_from_text(self, text, prefix, n): return header_id - _toc = None def _toc_add_entry(self, level, id, name): if level > self._toc_depth: return @@ -2141,11 +2172,14 @@ def _encode_amps_and_angles(self, text): text = self._naked_gt_re.sub('>', text) return text - _incomplete_tags_re = re.compile("<(/?\w+[\s/]+?)") + _incomplete_tags_re = re.compile("<(/?\w+?(?!\w).+?[\s/]+?)") def _encode_incomplete_tags(self, text): if self.safe_mode not in ("replace", "escape"): return text + + if text.endswith(">"): + return text # this is not an incomplete tag, this is a link in the form return self._incomplete_tags_re.sub("<\\1", text) diff --git a/ext/readme.md b/ext/readme.md index 5e615cf1fd..11e1228ee9 100644 --- a/ext/readme.md +++ b/ext/readme.md @@ -37,7 +37,7 @@ ext | `imdbpie` | [5.6.4](https://pypi.org/project/imdbpie/5.6.4/) | **`medusa`* ext | `jsonrpclib-pelix` | [0.4.1](https://pypi.org/project/jsonrpclib-pelix/0.4.1/) | **`medusa`** | Module: `jsonrpclib` ext | `knowit` | [eea9ac1](https://github.com/ratoaq2/knowit/tree/eea9ac18e38c930230cf81b5dca4a9af9fb10d4e) | **`medusa`** | - ext | `Mako` | [1.1.2](https://pypi.org/project/Mako/1.1.2/) | **`medusa`** | Module: `mako` -ext | markdown2.py | [2.3.8](https://pypi.org/project/markdown2/2.3.8/) | **`medusa`** | - +ext | markdown2.py | [2.3.9](https://pypi.org/project/markdown2/2.3.9/) | **`medusa`** | - ext | `MarkupSafe` | [1.1.1](https://pypi.org/project/MarkupSafe/1.1.1/) | `Mako` | Module: `markupsafe` ext | `msgpack` | [0.5.6](https://pypi.org/project/msgpack/0.5.6/) | `CacheControl` | - ext | `oauthlib` | [3.0.0](https://pypi.org/project/oauthlib/3.0.0/) | `requests-oauthlib` | - diff --git a/requirements.txt b/requirements.txt index e7e3abf974..8e4887fc68 100644 --- a/requirements.txt +++ b/requirements.txt @@ -23,7 +23,7 @@ imdbpie==5.6.4 jsonrpclib-pelix==0.4.1 knowit @ https://codeload.github.com/ratoaq2/knowit/tar.gz/eea9ac18e38c930230cf81b5dca4a9af9fb10d4e#egg=knowit Mako==1.1.2 -markdown2==2.3.8 +markdown2==2.3.9 profilehooks==1.11.2 PyGithub==1.45 PyJWT==1.7.1