Sanitize notifications ids as they are retransmitted over the TTY
This commit is contained in:
parent
c455fea729
commit
f05783e64d
@ -56,6 +56,10 @@ Detailed list of changes
|
|||||||
|
|
||||||
- Wayland: Fix remembering window size not accurate when client side decorations are present
|
- Wayland: Fix remembering window size not accurate when client side decorations are present
|
||||||
|
|
||||||
|
- Fix an issue where notification identifiers were not sanitized leading to
|
||||||
|
code execution if the user clicked on a notification popup from a malicious
|
||||||
|
source. Thanks to Carter Sande for discovering this vulnerability.
|
||||||
|
|
||||||
0.26.1 [2022-08-30]
|
0.26.1 [2022-08-30]
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|||||||
@ -1,13 +1,15 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# License: GPLv3 Copyright: 2019, Kovid Goyal <kovid at kovidgoyal.net>
|
# License: GPLv3 Copyright: 2019, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
|
|
||||||
|
import re
|
||||||
from base64 import standard_b64decode
|
from base64 import standard_b64decode
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from itertools import count
|
from itertools import count
|
||||||
from typing import Dict, Optional, Callable
|
from typing import Callable, Dict, Optional
|
||||||
|
|
||||||
from .constants import is_macos, logo_png_file
|
from .constants import is_macos, logo_png_file
|
||||||
from .fast_data_types import get_boss
|
from .fast_data_types import get_boss
|
||||||
|
from .types import run_once
|
||||||
from .utils import log_error
|
from .utils import log_error
|
||||||
|
|
||||||
NotifyImplementation = Callable[[str, str, str], None]
|
NotifyImplementation = Callable[[str, str, str], None]
|
||||||
@ -92,6 +94,11 @@ def parse_osc_777(raw: str) -> NotificationCommand:
|
|||||||
return ans
|
return ans
|
||||||
|
|
||||||
|
|
||||||
|
@run_once
|
||||||
|
def sanitize_identifier_pat() -> 're.Pattern[str]':
|
||||||
|
return re.compile(r'[^a-zA-Z0-9-_+.]+')
|
||||||
|
|
||||||
|
|
||||||
def parse_osc_99(raw: str) -> NotificationCommand:
|
def parse_osc_99(raw: str) -> NotificationCommand:
|
||||||
cmd = NotificationCommand()
|
cmd = NotificationCommand()
|
||||||
metadata, payload = raw.partition(';')[::2]
|
metadata, payload = raw.partition(';')[::2]
|
||||||
@ -107,7 +114,7 @@ def parse_osc_99(raw: str) -> NotificationCommand:
|
|||||||
if k == 'p':
|
if k == 'p':
|
||||||
payload_type = v
|
payload_type = v
|
||||||
elif k == 'i':
|
elif k == 'i':
|
||||||
cmd.identifier = v
|
cmd.identifier = sanitize_identifier_pat().sub('', v)
|
||||||
elif k == 'e':
|
elif k == 'e':
|
||||||
payload_is_encoded = v == '1'
|
payload_is_encoded = v == '1'
|
||||||
elif k == 'd':
|
elif k == 'd':
|
||||||
|
|||||||
@ -41,7 +41,7 @@ from .fast_data_types import (
|
|||||||
update_window_title, update_window_visibility, wakeup_main_loop
|
update_window_title, update_window_visibility, wakeup_main_loop
|
||||||
)
|
)
|
||||||
from .keys import keyboard_mode_name, mod_mask
|
from .keys import keyboard_mode_name, mod_mask
|
||||||
from .notify import NotificationCommand, handle_notification_cmd
|
from .notify import NotificationCommand, handle_notification_cmd, sanitize_identifier_pat
|
||||||
from .options.types import Options
|
from .options.types import Options
|
||||||
from .rgb import to_color
|
from .rgb import to_color
|
||||||
from .terminfo import get_capabilities
|
from .terminfo import get_capabilities
|
||||||
@ -1001,6 +1001,7 @@ class Window:
|
|||||||
self.screen.send_escape_code_to_child(OSC, f'{code};rgb:{r:04x}/{g:04x}/{b:04x}')
|
self.screen.send_escape_code_to_child(OSC, f'{code};rgb:{r:04x}/{g:04x}/{b:04x}')
|
||||||
|
|
||||||
def report_notification_activated(self, identifier: str) -> None:
|
def report_notification_activated(self, identifier: str) -> None:
|
||||||
|
identifier = sanitize_identifier_pat().sub('', identifier)
|
||||||
self.screen.send_escape_code_to_child(OSC, f'99;i={identifier};')
|
self.screen.send_escape_code_to_child(OSC, f'99;i={identifier};')
|
||||||
|
|
||||||
def set_dynamic_color(self, code: int, value: Union[str, bytes]) -> None:
|
def set_dynamic_color(self, code: int, value: Union[str, bytes]) -> None:
|
||||||
|
|||||||
@ -555,3 +555,7 @@ class TestDataTypes(BaseTest):
|
|||||||
self.assertEqual(hash(SingleKey(key=1)), hash(SingleKey(key=1)))
|
self.assertEqual(hash(SingleKey(key=1)), hash(SingleKey(key=1)))
|
||||||
self.assertNotEqual(hash(SingleKey(key=1, mods=2)), hash(SingleKey(key=1)))
|
self.assertNotEqual(hash(SingleKey(key=1, mods=2)), hash(SingleKey(key=1)))
|
||||||
self.assertNotEqual(SingleKey(key=1, mods=2), SingleKey(key=1))
|
self.assertNotEqual(SingleKey(key=1, mods=2), SingleKey(key=1))
|
||||||
|
|
||||||
|
def test_notify_identifier_sanitization(self):
|
||||||
|
from kitty.notify import sanitize_identifier_pat
|
||||||
|
self.ae(sanitize_identifier_pat().sub('', '\x1b\nabc\n[*'), 'abc')
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user