mirror of
https://github.com/yt-dlp/yt-dlp.git
synced 2026-07-06 10:18:57 +00:00
Validate and escape values in --write-link output
See https://github.com/yt-dlp/yt-dlp/security/advisories/GHSA-6v4j-43gg-vj32 Authored by: bashonly
This commit is contained in:
parent
bed3d58c5c
commit
b6590aaa1e
@ -134,7 +134,10 @@ from yt_dlp.utils import (
|
|||||||
xpath_text,
|
xpath_text,
|
||||||
xpath_with_ns,
|
xpath_with_ns,
|
||||||
)
|
)
|
||||||
from yt_dlp.utils._utils import _UnsafeExtensionError
|
from yt_dlp.utils._utils import (
|
||||||
|
_UnsafeExtensionError,
|
||||||
|
_desktop_entry_localestring,
|
||||||
|
)
|
||||||
from yt_dlp.utils.networking import (
|
from yt_dlp.utils.networking import (
|
||||||
HTTPHeaderDict,
|
HTTPHeaderDict,
|
||||||
escape_rfc3986,
|
escape_rfc3986,
|
||||||
@ -1948,6 +1951,27 @@ Line 1
|
|||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
iri_to_uri('http://导航.中国/'),
|
iri_to_uri('http://导航.中国/'),
|
||||||
'http://xn--fet810g.xn--fiqs8s/')
|
'http://xn--fet810g.xn--fiqs8s/')
|
||||||
|
self.assertEqual(
|
||||||
|
iri_to_uri('file://example.org/run.exe', allowed_schemes=('file',)),
|
||||||
|
'file://example.org/run.exe')
|
||||||
|
self.assertRaises(ValueError, iri_to_uri, 'file://example.org/run.exe')
|
||||||
|
|
||||||
|
def test_desktop_entry_localestring(self):
|
||||||
|
self.assertEqual(
|
||||||
|
_desktop_entry_localestring('A B'),
|
||||||
|
'A\\sB')
|
||||||
|
self.assertEqual(
|
||||||
|
_desktop_entry_localestring('A\nB'),
|
||||||
|
'A\\nB')
|
||||||
|
self.assertEqual(
|
||||||
|
_desktop_entry_localestring('A\tB'),
|
||||||
|
'A\\tB')
|
||||||
|
self.assertEqual(
|
||||||
|
_desktop_entry_localestring('A\rB'),
|
||||||
|
'A\\rB')
|
||||||
|
self.assertEqual(
|
||||||
|
_desktop_entry_localestring('A\\B'),
|
||||||
|
'A\\\\B')
|
||||||
|
|
||||||
def test_clean_podcast_url(self):
|
def test_clean_podcast_url(self):
|
||||||
self.assertEqual(clean_podcast_url('https://www.podtrac.com/pts/redirect.mp3/chtbl.com/track/5899E/traffic.megaphone.fm/HSW7835899191.mp3'), 'https://traffic.megaphone.fm/HSW7835899191.mp3')
|
self.assertEqual(clean_podcast_url('https://www.podtrac.com/pts/redirect.mp3/chtbl.com/track/5899E/traffic.megaphone.fm/HSW7835899191.mp3'), 'https://traffic.megaphone.fm/HSW7835899191.mp3')
|
||||||
|
|||||||
@ -170,7 +170,12 @@ from .utils import (
|
|||||||
write_json_file,
|
write_json_file,
|
||||||
write_string,
|
write_string,
|
||||||
)
|
)
|
||||||
from .utils._utils import _UnsafeExtensionError, _YDLLogger, _ProgressState
|
from .utils._utils import (
|
||||||
|
_UnsafeExtensionError,
|
||||||
|
_YDLLogger,
|
||||||
|
_ProgressState,
|
||||||
|
_desktop_entry_localestring,
|
||||||
|
)
|
||||||
from .utils.networking import (
|
from .utils.networking import (
|
||||||
HTTPHeaderDict,
|
HTTPHeaderDict,
|
||||||
clean_headers,
|
clean_headers,
|
||||||
@ -3406,10 +3411,13 @@ class YoutubeDL:
|
|||||||
|
|
||||||
# Write internet shortcut files
|
# Write internet shortcut files
|
||||||
def _write_link_file(link_type):
|
def _write_link_file(link_type):
|
||||||
|
# iri_to_uri converts to ascii, percent-escapes unsafe characters & validates scheme
|
||||||
|
# See https://github.com/yt-dlp/yt-dlp/security/advisories/GHSA-6v4j-43gg-vj32
|
||||||
url = try_get(info_dict['webpage_url'], iri_to_uri)
|
url = try_get(info_dict['webpage_url'], iri_to_uri)
|
||||||
if not url:
|
if not url:
|
||||||
self.report_warning(
|
self.report_warning(
|
||||||
f'Cannot write internet shortcut file because the actual URL of "{info_dict["webpage_url"]}" is unknown')
|
f'Cannot write internet shortcut file because the actual URL '
|
||||||
|
f'of "{info_dict["webpage_url"]}" is unknown or disallowed')
|
||||||
return True
|
return True
|
||||||
linkfn = replace_extension(
|
linkfn = replace_extension(
|
||||||
self.prepare_filename(info_dict, 'link'), link_type,
|
self.prepare_filename(info_dict, 'link'), link_type,
|
||||||
@ -3425,7 +3433,8 @@ class YoutubeDL:
|
|||||||
newline='\r\n' if link_type == 'url' else '\n') as linkfile:
|
newline='\r\n' if link_type == 'url' else '\n') as linkfile:
|
||||||
template_vars = {'url': url}
|
template_vars = {'url': url}
|
||||||
if link_type == 'desktop':
|
if link_type == 'desktop':
|
||||||
template_vars['filename'] = linkfn[:-(len(link_type) + 1)]
|
# See https://github.com/yt-dlp/yt-dlp/security/advisories/GHSA-6v4j-43gg-vj32
|
||||||
|
template_vars['filename'] = _desktop_entry_localestring(linkfn[:-(len(link_type) + 1)])
|
||||||
linkfile.write(LINK_TEMPLATES[link_type] % template_vars)
|
linkfile.write(LINK_TEMPLATES[link_type] % template_vars)
|
||||||
except OSError:
|
except OSError:
|
||||||
self.report_error(f'Cannot write internet shortcut {linkfn}')
|
self.report_error(f'Cannot write internet shortcut {linkfn}')
|
||||||
|
|||||||
@ -4631,8 +4631,21 @@ LINK_TEMPLATES = {
|
|||||||
'webloc': DOT_WEBLOC_LINK_TEMPLATE,
|
'webloc': DOT_WEBLOC_LINK_TEMPLATE,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Ref: https://specifications.freedesktop.org/desktop-entry/latest/value-types.html
|
||||||
|
_DESKTOP_ENTRY_TRANS = str.maketrans({
|
||||||
|
' ': R'\s',
|
||||||
|
'\n': R'\n',
|
||||||
|
'\t': R'\t',
|
||||||
|
'\r': R'\r',
|
||||||
|
'\\': R'\\',
|
||||||
|
})
|
||||||
|
|
||||||
def iri_to_uri(iri):
|
|
||||||
|
def _desktop_entry_localestring(s):
|
||||||
|
return s.translate(_DESKTOP_ENTRY_TRANS)
|
||||||
|
|
||||||
|
|
||||||
|
def iri_to_uri(iri, *, allowed_schemes=('http', 'https')):
|
||||||
"""
|
"""
|
||||||
Converts an IRI (Internationalized Resource Identifier, allowing Unicode characters) to a URI (Uniform Resource Identifier, ASCII-only).
|
Converts an IRI (Internationalized Resource Identifier, allowing Unicode characters) to a URI (Uniform Resource Identifier, ASCII-only).
|
||||||
|
|
||||||
@ -4641,6 +4654,9 @@ def iri_to_uri(iri):
|
|||||||
|
|
||||||
iri_parts = urllib.parse.urlparse(iri)
|
iri_parts = urllib.parse.urlparse(iri)
|
||||||
|
|
||||||
|
if iri_parts.scheme not in allowed_schemes:
|
||||||
|
raise ValueError(f'"{iri_parts.scheme}" is not in allowed_schemes: {", ".join(allowed_schemes)}')
|
||||||
|
|
||||||
if '[' in iri_parts.netloc:
|
if '[' in iri_parts.netloc:
|
||||||
raise ValueError('IPv6 URIs are not, yet, supported.')
|
raise ValueError('IPv6 URIs are not, yet, supported.')
|
||||||
# Querying `.netloc`, when there's only one bracket, also raises a ValueError.
|
# Querying `.netloc`, when there's only one bracket, also raises a ValueError.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user