Skip to content

Commit

Permalink
Keys should not parse base64 encoded URLs (#2245)
Browse files Browse the repository at this point in the history
  • Loading branch information
facelessuser authored Nov 21, 2023
1 parent cf97b06 commit b336f93
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 6 deletions.
4 changes: 4 additions & 0 deletions docs/src/markdown/about/changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## 10.5

- **FIX**: Keys: Ensure that Keys does not parse base64 encoded URLs.

## 10.4

- **NEW**: Snippets: Allow PathLike objects for `base_path` to better support interactions with MkDocs.
Expand Down
28 changes: 22 additions & 6 deletions pymdownx/keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@
from . import keymap_db as keymap
import re

RE_KBD = r'''(?x)
RE_EARLY_KBD = r'''(?x)
(?:
# Escape
(?<!\\)(?P<escapes>(?:\\{2})+)(?=\+)|
Expand All @@ -105,6 +105,8 @@
)
'''

RE_KBD = r'\+{2}([\w\-]+(?:\+[\w\-]+)*?)\+{2}'

ESCAPE_RE = re.compile(r'''(?<!\\)(?:\\\\)*\\(.)''')
UNESCAPED_PLUS = re.compile(r'''(?<!\\)(?:\\\\)*(\+)''')
ESCAPED_BSLASH = '%s%s%s' % (md_util.STX, ord('\\'), md_util.ETX)
Expand All @@ -114,7 +116,7 @@
class KeysPattern(InlineProcessor):
"""Return kbd tag."""

def __init__(self, pattern, config, md):
def __init__(self, pattern, config, md, early=False):
"""Initialize."""

self.ksep = config['separator']
Expand All @@ -123,6 +125,7 @@ def __init__(self, pattern, config, md):
self.map = self.merge(keymap.keymap, config['key_map'])
self.aliases = keymap.aliases
self.camel = config['camel_case']
self.early = early
super().__init__(pattern, md)

def merge(self, x, y):
Expand Down Expand Up @@ -166,9 +169,21 @@ def process_key(self, key):
def handleMatch(self, m, data):
"""Handle kbd pattern matches."""

if m.group(1):
return m.group('escapes').replace(DOUBLE_BSLASH, ESCAPED_BSLASH), m.start(0), m.end(0)
content = [self.process_key(key) for key in UNESCAPED_PLUS.split(m.group(2)) if key != '+']
if self.early:
if m.group(1):
return m.group('escapes').replace(DOUBLE_BSLASH, ESCAPED_BSLASH), m.start(0), m.end(0)
quoted = 0
content = []
for key in UNESCAPED_PLUS.split(m.group(2)):
if key != '+':
if key.startswith(('"', "'")):
quoted += 1
content.append(self.process_key(key))
# Defer unquoted cases until later to avoid parsing URLs
if not quoted:
return None, None, None
else:
content = [self.process_key(key) for key in m.group(1).split('+')]

if None in content:
return None, None, None
Expand Down Expand Up @@ -215,7 +230,8 @@ def extendMarkdown(self, md):
"""Add support for keys."""

util.escape_chars(md, ['+'])
md.inlinePatterns.register(KeysPattern(RE_KBD, self.getConfigs(), md), "keys", 185)
md.inlinePatterns.register(KeysPattern(RE_EARLY_KBD, self.getConfigs(), md, early=True), "keys-custom", 185)
md.inlinePatterns.register(KeysPattern(RE_KBD, self.getConfigs(), md), "keys", 70)


def makeExtension(*args, **kwargs):
Expand Down
18 changes: 18 additions & 0 deletions tests/test_extensions/test_keys.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"""Test cases for Keys."""
from .. import util


class TestKeys(util.MdCase):
"""Tests for Keys."""

extension = [
'pymdownx.keys'
]

def test_avoid_base64(self):
"""Test complex case where `**text*text***` may be detected on accident."""

self.check_markdown(
"![](data:image/png;base64,aaaaa++a++aaaa) ++ctrl+a++ ++ctrl+'custom'++",
'<p><img alt="" src="data:image/png;base64,aaaaa++a++aaaa" /> <span class="keys"><kbd class="key-control">Ctrl</kbd><span>+</span><kbd class="key-a">A</kbd></span> <span class="keys"><kbd class="key-control">Ctrl</kbd><span>+</span><kbd>custom</kbd></span></p>' # noqa: E501
)

0 comments on commit b336f93

Please sign in to comment.