Skip to content

Commit

Permalink
Ensure fenced code attributes are properly escaped.
Browse files Browse the repository at this point in the history
Fixes #1247.
  • Loading branch information
waylan committed May 4, 2022
1 parent ed417a1 commit ce73b27
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 15 deletions.
1 change: 1 addition & 0 deletions docs/change_log/index.md
Expand Up @@ -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).

Expand Down
25 changes: 10 additions & 15 deletions markdown/extensions/fenced_code.py
Expand Up @@ -22,6 +22,7 @@
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


Expand Down Expand Up @@ -120,30 +121,24 @@ def run(self, lines):
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")
Expand Down
18 changes: 18 additions & 0 deletions tests/test_syntax/extensions/test_fenced_code.py
Expand Up @@ -374,6 +374,24 @@ def testFencedLanguageAltPrefix(self):
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="&quot;foo"><code class="language-&quot;weird" bar="&quot;&gt;baz"># Some python code
</code></pre>
'''
),
extensions=['fenced_code', 'attr_list']
)


class TestFencedCodeWithCodehilite(TestCase):

Expand Down

0 comments on commit ce73b27

Please sign in to comment.