mirror of
https://github.com/dgtlmoon/changedetection.io.git
synced 2026-07-09 08:51:40 +00:00
5015bfa0cd
Build and push containers / metadata (push) Has been cancelled
Build and push containers / build-push-containers (push) Has been cancelled
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Build distribution 📦 (push) Has been cancelled
ChangeDetection.io App Test / lint-code (push) Has been cancelled
ChangeDetection.io App Test / lint-translations (push) Has been cancelled
ChangeDetection.io App Test / lint-template-i18n (push) Has been cancelled
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Test the built package works basically. (push) Has been cancelled
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Publish Python 🐍 distribution 📦 to PyPI (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-10 (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-11 (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-12 (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-13 (push) Has been cancelled
ChangeDetection.io App Test / test-application-3-14 (push) Has been cancelled
63 lines
2.6 KiB
Python
63 lines
2.6 KiB
Python
#!/usr/bin/env python3
|
|
|
|
# run from dir above changedetectionio/ dir
|
|
# python3 -m unittest changedetectionio.tests.unit.test_validate_url
|
|
|
|
import unittest
|
|
|
|
from changedetectionio.validate_url import is_safe_valid_url, normalize_url_encoding
|
|
|
|
|
|
class TestValidateUrl(unittest.TestCase):
|
|
|
|
def test_fragment_with_pipe_characters_is_valid(self):
|
|
"""https://github.com/dgtlmoon/changedetection.io/issues/4209
|
|
Browsers accept '|' in the fragment/anchor but RFC 3986 does not,
|
|
so it must be percent-encoded before validation instead of rejected."""
|
|
url = 'https://www.fnac.com/Pack-Tablette-Tactile-Samsung-Galaxy-Tab-S10-Lite-10-9-Wi-Fi-128-Go-Anthracite-Book-Cover/a21903823/w-4#int=S:PFreco|PF|48966|21903823|BL4|L1'
|
|
self.assertTrue(is_safe_valid_url(url), f"URL '{url}' with '|' in the fragment should be valid")
|
|
|
|
def test_fragment_pipe_is_percent_encoded(self):
|
|
normalized = normalize_url_encoding('https://example.com/page#a|b')
|
|
self.assertEqual(normalized, 'https://example.com/page#a%7Cb')
|
|
|
|
def test_already_encoded_fragment_is_not_double_encoded(self):
|
|
normalized = normalize_url_encoding('https://example.com/page#a%7Cb')
|
|
self.assertEqual(normalized, 'https://example.com/page#a%7Cb')
|
|
|
|
def test_fragment_normalization_is_idempotent(self):
|
|
url = 'https://example.com/page#int=S:PFreco|PF|48966'
|
|
once = normalize_url_encoding(url)
|
|
twice = normalize_url_encoding(once)
|
|
self.assertEqual(once, twice)
|
|
|
|
def test_rfc3986_fragment_characters_are_untouched(self):
|
|
# pchar / "/" / "?" are all legal in a fragment and must survive as-is
|
|
urls = [
|
|
'https://example.com/docs#section-2.1',
|
|
'https://example.com/app#/route/sub?tab=1',
|
|
"https://example.com/page#key=val&other=a:b@c!$&'()*+,;=",
|
|
]
|
|
for url in urls:
|
|
with self.subTest(url=url):
|
|
self.assertEqual(normalize_url_encoding(url), url)
|
|
self.assertTrue(is_safe_valid_url(url))
|
|
|
|
def test_unsafe_urls_are_still_rejected(self):
|
|
# The fragment fix must not loosen any of the existing security checks
|
|
unsafe = [
|
|
'javascript:alert(1)',
|
|
'source:javascript:alert(1)',
|
|
'https://example.com/page#<script>',
|
|
'http://INTERNAL:8888\\@PUBLIC/',
|
|
'',
|
|
None,
|
|
]
|
|
for url in unsafe:
|
|
with self.subTest(url=url):
|
|
self.assertFalse(is_safe_valid_url(url), f"URL '{url}' should be rejected")
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|