diff options
author | Waylan Limberg <waylan.limberg@icloud.com> | 2022-05-04 14:13:56 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-05-04 14:13:56 -0400 |
commit | ce73b2754fb754c29d719c9980ae2f4aa4912f4d (patch) | |
tree | 6e11d57b842b72db7f3ae0784c05ee2f1342cd34 | |
parent | ed417a1a555bf2206ceea84ba29ce37322ca8261 (diff) | |
download | python-markdown-ce73b2754fb754c29d719c9980ae2f4aa4912f4d.tar.gz |
Ensure fenced code attributes are properly escaped.
Fixes #1247.
-rw-r--r-- | docs/change_log/index.md | 1 | ||||
-rw-r--r-- | markdown/extensions/fenced_code.py | 25 | ||||
-rw-r--r-- | tests/test_syntax/extensions/test_fenced_code.py | 18 |
3 files changed, 29 insertions, 15 deletions
diff --git a/docs/change_log/index.md b/docs/change_log/index.md index 5320fc7..b9fa97b 100644 --- a/docs/change_log/index.md +++ b/docs/change_log/index.md @@ -7,6 +7,7 @@ Python-Markdown Change Log * Disallow square brackets in reference link ids (#1209). * Retain configured `pygments_style` after first code block (#1240). +* Ensure fenced code attributes are properly escaped (#1247). Nov 17, 2021: version 3.3.6 (a bug-fix release). diff --git a/markdown/extensions/fenced_code.py b/markdown/extensions/fenced_code.py index 9be0ca0..409166a 100644 --- a/markdown/extensions/fenced_code.py +++ b/markdown/extensions/fenced_code.py @@ -22,6 +22,7 @@ from ..preprocessors import Preprocessor from .codehilite import CodeHilite, CodeHiliteExtension, parse_hl_lines from .attr_list import get_attrs, AttrListExtension from ..util import parseBoolValue +from ..serializers import _escape_attrib_html import re @@ -120,30 +121,24 @@ class FencedBlockPreprocessor(Preprocessor): else: id_attr = lang_attr = class_attr = kv_pairs = '' if lang: - lang_attr = ' class="{}{}"'.format(self.config.get('lang_prefix', 'language-'), lang) + prefix = self.config.get('lang_prefix', 'language-') + lang_attr = f' class="{prefix}{_escape_attrib_html(lang)}"' if classes: - class_attr = ' class="{}"'.format(' '.join(classes)) + class_attr = f' class="{_escape_attrib_html(" ".join(classes))}"' if id: - id_attr = ' id="{}"'.format(id) + id_attr = f' id="{_escape_attrib_html(id)}"' if self.use_attr_list and config and not config.get('use_pygments', False): # Only assign key/value pairs to code element if attr_list ext is enabled, key/value pairs # were defined on the code block, and the `use_pygments` key was not set to True. The # `use_pygments` key could be either set to False or not defined. It is omitted from output. - kv_pairs = ' ' + ' '.join( - '{k}="{v}"'.format(k=k, v=v) for k, v in config.items() if k != 'use_pygments' + kv_pairs = ''.join( + f' {k}="{_escape_attrib_html(v)}"' for k, v in config.items() if k != 'use_pygments' ) - code = '<pre{id}{cls}><code{lang}{kv}>{code}</code></pre>'.format( - id=id_attr, - cls=class_attr, - lang=lang_attr, - kv=kv_pairs, - code=self._escape(m.group('code')) - ) + code = self._escape(m.group('code')) + code = f'<pre{id_attr}{class_attr}><code{lang_attr}{kv_pairs}>{code}</code></pre>' placeholder = self.md.htmlStash.store(code) - text = '{}\n{}\n{}'.format(text[:m.start()], - placeholder, - text[m.end():]) + text = f'{text[:m.start()]}\n{placeholder}\n{text[m.end():]}' else: break return text.split("\n") diff --git a/tests/test_syntax/extensions/test_fenced_code.py b/tests/test_syntax/extensions/test_fenced_code.py index 76c8769..2cdde98 100644 --- a/tests/test_syntax/extensions/test_fenced_code.py +++ b/tests/test_syntax/extensions/test_fenced_code.py @@ -374,6 +374,24 @@ class TestFencedCode(TestCase): extensions=[markdown.extensions.fenced_code.FencedCodeExtension(lang_prefix='lang-')] ) + def testFencedCodeEscapedAttrs(self): + self.assertMarkdownRenders( + self.dedent( + ''' + ``` { ."weird #"foo bar=">baz } + # Some python code + ``` + ''' + ), + self.dedent( + ''' + <pre id=""foo"><code class="language-"weird" bar="">baz"># Some python code + </code></pre> + ''' + ), + extensions=['fenced_code', 'attr_list'] + ) + class TestFencedCodeWithCodehilite(TestCase): |