Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Escape application names for GMarkup #51

Merged
merged 1 commit into from
Dec 10, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Escape application names for GMarkup
GLib provides a parser called GMarkup, which implements a subset of XML.
Application names may contain XML metacharacters, such as "<" and "&".
These must be escaped to prevent XML injection, but the app menu didn't
do that.

The GMarkup documentation explicitly states that GMarkup must not be
used to parse untrusted input [1].  Therefore, parsing malicious markup
may have undefined results.  Fortunately, there is no security problem
because the only allowed character with special meaning in XML is "&"
and ";" is not allowed.  Therefore, there is no way to create a valid
XML entity or inject tags.  The worst that can happen is the creation of
ill-formed markup that that GLib rejects.

This patch also addresses a URL construction bug: filenames need to be
URL-encoded in file:// URLs.

[1]: https://github.com/GNOME/glib/blob/3304a517d9a7bdbb52d60394fdae6f9903f0f4f3/glib/gmarkup.c#L50-L51
  • Loading branch information
DemiMarie committed Nov 27, 2024
commit b2e036c70dfee99275765f86f7ecd22337d2055a
4 changes: 3 additions & 1 deletion qubes_menu/app_widgets.py
Original file line number Diff line number Diff line change
@@ -22,6 +22,7 @@
"""
import subprocess
import logging
import urllib.parse
from typing import Optional, List
from functools import reduce

@@ -74,7 +75,8 @@
self.connect("drag-data-get", self._on_drag_data_get)

def _on_drag_data_get(self, _widget, _drag_context, data, _info, _time):
data.set_uris(['file://' + str(self.app_info.file_path)])
data.set_uris(['file://' +
urllib.parse.quote(str(self.app_info.file_path))])

Check warning on line 79 in qubes_menu/app_widgets.py

Codecov / codecov/patch

qubes_menu/app_widgets.py#L79

Added line #L79 was not covered by tests

def show_menu(self, _widget, event):
"""
24 changes: 14 additions & 10 deletions qubes_menu/utils.py
Original file line number Diff line number Diff line change
@@ -55,15 +55,14 @@
pixbuf.fill(0x000)
return pixbuf


def show_error(title, text):
"""
Helper function to display error messages.
"""
dialog = Gtk.MessageDialog(
None, 0, Gtk.MessageType.ERROR, Gtk.ButtonsType.OK)
dialog.set_title(title)
dialog.set_markup(text)
dialog.set_markup(GLib.markup_escape_text(text))

Check warning on line 65 in qubes_menu/utils.py

Codecov / codecov/patch

qubes_menu/utils.py#L65

Added line #L65 was not covered by tests
dialog.connect("response", lambda *x: dialog.destroy())
dialog.show()

@@ -91,7 +90,7 @@


def highlight_words(labels: List[Gtk.Label], search_words: List[str],
hl_tag: Optional[str] = None):
hl_tag: Optional[str] = None) -> None:
"""Highlight provided search_words in the provided labels."""
if not labels:
return
@@ -110,7 +109,7 @@
for label in labels:
text = label.get_text()
# remove existing highlighting
label.set_markup(text)
label.set_markup(GLib.markup_escape_text(text))
search_text = text.lower()
found_intervals = []
for word in search_words:
@@ -131,12 +130,17 @@
else:
result_intervals.append(interval)

for interval in reversed(result_intervals):
start, end = interval
text = text[:start] + hl_tag + \
text[start:end] + '</span>' + text[end:]

label.set_markup(text)
markup_list = []
last_start = 0

Check warning on line 134 in qubes_menu/utils.py

Codecov / codecov/patch

qubes_menu/utils.py#L134

Added line #L134 was not covered by tests
for start, end in reversed(result_intervals):
markup_list.append(GLib.markup_escape_text(text[last_start:start]))
markup_list.append(hl_tag)
markup_list.append(GLib.markup_escape_text(text[start:end]))
markup_list.append('</span>')
last_start = end
markup_list.append(GLib.markup_escape_text(text[last_start:]))

label.set_markup("".join(markup_list))


def get_visible_child(widget: Gtk.Container, reverse=False):