diff --git a/CHANGES.md b/CHANGES.md index cabaeb1f..2c528404 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -22,6 +22,7 @@ - [pull #734] Fix empty list items being parsed as nested lists (#167) - [pull #735] Fix `smarty-pants` extra converting quotes inside inline HTML tags and comments (#150) - [pull #737] Fix XSS from code spans that the span gamut doesn't treat as code spans in safe mode (#726) +- [pull #738] Fix `<` in code blocks being escaped twice in safe mode (#240) ## python-markdown2 2.5.5 diff --git a/lib/markdown2.py b/lib/markdown2.py index 18419ef0..aa767426 100755 --- a/lib/markdown2.py +++ b/lib/markdown2.py @@ -1677,7 +1677,7 @@ def header_id_from_text(self, None to not have an id attribute and to exclude this header from the TOC (if the "toc" extra is specified). """ - header_id = _slugify(html.unescape(text)) + header_id = _slugify(html.unescape(self._unescape_special_chars(text))) if prefix and isinstance(prefix, str): header_id = prefix + '-' + header_id @@ -2335,10 +2335,13 @@ def _encode_incomplete_tags(self, text: str) -> str: def incomplete_tags_sub(match): text = match.group() + # hash the `<` so that code blocks don't escape it a second time + lt_hash = self._hash_span('<') + self._code_table['<'] = lt_hash # ensure that we handle escaped incomplete tags properly by consuming and replacing the escapes if not self._is_unescaped_re.match(text): - text = text.replace('\\<', '<') - return text.replace('<', '<') + text = text.replace('\\<', lt_hash) + return text.replace('<', lt_hash) text = self._incomplete_tags_re.sub(incomplete_tags_sub, text) diff --git a/test/tm-cases/safe_mode_incomplete_tags_in_code_blocks.html b/test/tm-cases/safe_mode_incomplete_tags_in_code_blocks.html new file mode 100644 index 00000000..ac0e08aa --- /dev/null +++ b/test/tm-cases/safe_mode_incomplete_tags_in_code_blocks.html @@ -0,0 +1,27 @@ +
Start of test.
+ +for (i=0; i<3; i++) {
+ printf("Hello, world.");
+}
+
+
+++ +This is a quote
+
if (a<b && b<c) {}
+
+
+list item
+ +x<y
+These are still escaped: a<b and <c
+ +Literal entity: <div
+
diff --git a/test/tm-cases/safe_mode_incomplete_tags_in_code_blocks.opts b/test/tm-cases/safe_mode_incomplete_tags_in_code_blocks.opts
new file mode 100644
index 00000000..998d391b
--- /dev/null
+++ b/test/tm-cases/safe_mode_incomplete_tags_in_code_blocks.opts
@@ -0,0 +1 @@
+{'safe_mode': 'escape', 'extras': ['fenced-code-blocks', 'header-ids']}
\ No newline at end of file
diff --git a/test/tm-cases/safe_mode_incomplete_tags_in_code_blocks.text b/test/tm-cases/safe_mode_incomplete_tags_in_code_blocks.text
new file mode 100644
index 00000000..1f26a623
--- /dev/null
+++ b/test/tm-cases/safe_mode_incomplete_tags_in_code_blocks.text
@@ -0,0 +1,21 @@
+# Comparing a This is a quote
+
+```
+if (a