mirror of https://github.com/zulip/zulip.git
python: Use urlsplit instead of urlparse.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
parent
3853fa875a
commit
223b626256
|
@ -2,7 +2,7 @@ from contextlib import suppress
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from typing import Any, Dict, Iterable, List, Optional, Union
|
from typing import Any, Dict, Iterable, List, Optional, Union
|
||||||
from urllib.parse import urlencode, urlparse
|
from urllib.parse import urlencode, urlsplit
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
|
@ -272,7 +272,7 @@ def support(
|
||||||
for key_word in key_words:
|
for key_word in key_words:
|
||||||
try:
|
try:
|
||||||
URLValidator()(key_word)
|
URLValidator()(key_word)
|
||||||
parse_result = urlparse(key_word)
|
parse_result = urlsplit(key_word)
|
||||||
hostname = parse_result.hostname
|
hostname = parse_result.hostname
|
||||||
assert hostname is not None
|
assert hostname is not None
|
||||||
if parse_result.port:
|
if parse_result.port:
|
||||||
|
|
|
@ -50,7 +50,7 @@ import sys
|
||||||
from configparser import RawConfigParser
|
from configparser import RawConfigParser
|
||||||
from typing import NoReturn
|
from typing import NoReturn
|
||||||
from urllib.error import HTTPError
|
from urllib.error import HTTPError
|
||||||
from urllib.parse import urlencode, urljoin, urlparse
|
from urllib.parse import urlencode, urljoin, urlsplit
|
||||||
from urllib.request import Request, urlopen
|
from urllib.request import Request, urlopen
|
||||||
|
|
||||||
sys.path.append(os.path.join(os.path.dirname(__file__), "..", ".."))
|
sys.path.append(os.path.join(os.path.dirname(__file__), "..", ".."))
|
||||||
|
@ -131,7 +131,7 @@ def send_email_mirror(
|
||||||
if test:
|
if test:
|
||||||
return
|
return
|
||||||
|
|
||||||
if not urlparse(host).scheme:
|
if not urlsplit(host).scheme:
|
||||||
config_file = get_config_file()
|
config_file = get_config_file()
|
||||||
http_only_config = get_config(config_file, "application_server", "http_only", "")
|
http_only_config = get_config(config_file, "application_server", "http_only", "")
|
||||||
http_only = http_only_config == "true"
|
http_only = http_only_config == "true"
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import os
|
import os
|
||||||
from posixpath import basename
|
from posixpath import basename
|
||||||
from typing import Any, List, Set
|
from typing import Any, List, Set
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlsplit
|
||||||
|
|
||||||
from typing_extensions import override
|
from typing_extensions import override
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ class UnusedImagesLinterSpider(BaseDocumentationSpider):
|
||||||
def _is_external_url(self, url: str) -> bool:
|
def _is_external_url(self, url: str) -> bool:
|
||||||
is_external = url.startswith("http") and self.start_urls[0] not in url
|
is_external = url.startswith("http") and self.start_urls[0] not in url
|
||||||
if self._has_extension(url) and f"localhost:9981/{self.images_path}" in url:
|
if self._has_extension(url) and f"localhost:9981/{self.images_path}" in url:
|
||||||
self.static_images.add(basename(urlparse(url).path))
|
self.static_images.add(basename(urlsplit(url).path))
|
||||||
return is_external or self._has_extension(url)
|
return is_external or self._has_extension(url)
|
||||||
|
|
||||||
def closed(self, *args: Any, **kwargs: Any) -> None:
|
def closed(self, *args: Any, **kwargs: Any) -> None:
|
||||||
|
|
|
@ -2,7 +2,7 @@ import json
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
from typing import Callable, Iterator, List, Optional, Union
|
from typing import Callable, Iterator, List, Optional, Union
|
||||||
from urllib.parse import urlparse, urlsplit
|
from urllib.parse import urlsplit
|
||||||
|
|
||||||
import scrapy
|
import scrapy
|
||||||
from scrapy.http import Request, Response
|
from scrapy.http import Request, Response
|
||||||
|
@ -233,7 +233,7 @@ class BaseDocumentationSpider(scrapy.Spider):
|
||||||
response = failure.value.response
|
response = failure.value.response
|
||||||
# Hack: The filtering above does not catch this URL,
|
# Hack: The filtering above does not catch this URL,
|
||||||
# likely due to a redirect.
|
# likely due to a redirect.
|
||||||
if urlparse(response.url).netloc == "idmsa.apple.com":
|
if urlsplit(response.url).netloc == "idmsa.apple.com":
|
||||||
return None
|
return None
|
||||||
if response.status == 405 and response.request.method == "HEAD":
|
if response.status == 405 and response.request.method == "HEAD":
|
||||||
# Method 'HEAD' not allowed, repeat request with 'GET'
|
# Method 'HEAD' not allowed, repeat request with 'GET'
|
||||||
|
|
|
@ -8,7 +8,7 @@ import signal
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
from typing import List, Sequence
|
from typing import List, Sequence
|
||||||
from urllib.parse import urlunparse
|
from urllib.parse import urlunsplit
|
||||||
|
|
||||||
TOOLS_DIR = os.path.dirname(os.path.abspath(__file__))
|
TOOLS_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||||
sys.path.insert(0, os.path.dirname(TOOLS_DIR))
|
sys.path.insert(0, os.path.dirname(TOOLS_DIR))
|
||||||
|
@ -204,7 +204,7 @@ def transform_url(protocol: str, path: str, query: str, target_port: int, target
|
||||||
host = ":".join((target_host, str(target_port)))
|
host = ":".join((target_host, str(target_port)))
|
||||||
# Here we are going to rewrite the path a bit so that it is in parity with
|
# Here we are going to rewrite the path a bit so that it is in parity with
|
||||||
# what we will have for production
|
# what we will have for production
|
||||||
newpath = urlunparse((protocol, host, path, "", query, ""))
|
newpath = urlunsplit((protocol, host, path, query, ""))
|
||||||
return newpath
|
return newpath
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -295,3 +295,12 @@ rules:
|
||||||
fix: time_machine.travel($TIME, tick=False)
|
fix: time_machine.travel($TIME, tick=False)
|
||||||
severity: ERROR
|
severity: ERROR
|
||||||
message: "Use the time_machine package, rather than mocking timezone_now"
|
message: "Use the time_machine package, rather than mocking timezone_now"
|
||||||
|
|
||||||
|
- id: urlparse
|
||||||
|
languages: [python]
|
||||||
|
pattern-either:
|
||||||
|
- pattern: urllib.parse.urlparse
|
||||||
|
- pattern: urllib.parse.urlunparse
|
||||||
|
- pattern: urllib.parse.ParseResult
|
||||||
|
severity: ERROR
|
||||||
|
message: "Use urlsplit rather than urlparse"
|
||||||
|
|
|
@ -15,7 +15,7 @@ from typing import (
|
||||||
cast,
|
cast,
|
||||||
overload,
|
overload,
|
||||||
)
|
)
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlsplit
|
||||||
|
|
||||||
import django_otp
|
import django_otp
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
@ -393,8 +393,8 @@ def zulip_redirect_to_login(
|
||||||
resolved_login_url = resolve_url(login_url or settings.LOGIN_URL)
|
resolved_login_url = resolve_url(login_url or settings.LOGIN_URL)
|
||||||
# If the login URL is the same scheme and net location then just
|
# If the login URL is the same scheme and net location then just
|
||||||
# use the path as the "next" url.
|
# use the path as the "next" url.
|
||||||
login_scheme, login_netloc = urlparse(resolved_login_url)[:2]
|
login_scheme, login_netloc = urlsplit(resolved_login_url)[:2]
|
||||||
current_scheme, current_netloc = urlparse(path)[:2]
|
current_scheme, current_netloc = urlsplit(path)[:2]
|
||||||
if (not login_scheme or login_scheme == current_scheme) and (
|
if (not login_scheme or login_scheme == current_scheme) and (
|
||||||
not login_netloc or login_netloc == current_netloc
|
not login_netloc or login_netloc == current_netloc
|
||||||
):
|
):
|
||||||
|
|
|
@ -26,7 +26,7 @@ from typing import (
|
||||||
Union,
|
Union,
|
||||||
cast,
|
cast,
|
||||||
)
|
)
|
||||||
from urllib.parse import parse_qs, quote, urlencode, urljoin, urlparse, urlsplit, urlunparse
|
from urllib.parse import parse_qs, quote, urlencode, urljoin, urlsplit, urlunsplit
|
||||||
from xml.etree.ElementTree import Element, SubElement
|
from xml.etree.ElementTree import Element, SubElement
|
||||||
|
|
||||||
import ahocorasick
|
import ahocorasick
|
||||||
|
@ -486,7 +486,7 @@ def fetch_open_graph_image(url: str) -> Optional[Dict[str, Any]]:
|
||||||
|
|
||||||
|
|
||||||
def get_tweet_id(url: str) -> Optional[str]:
|
def get_tweet_id(url: str) -> Optional[str]:
|
||||||
parsed_url = urlparse(url)
|
parsed_url = urlsplit(url)
|
||||||
if not (parsed_url.netloc == "twitter.com" or parsed_url.netloc.endswith(".twitter.com")):
|
if not (parsed_url.netloc == "twitter.com" or parsed_url.netloc.endswith(".twitter.com")):
|
||||||
return None
|
return None
|
||||||
to_match = parsed_url.path
|
to_match = parsed_url.path
|
||||||
|
@ -715,7 +715,7 @@ class InlineInterestingLinkProcessor(markdown.treeprocessors.Treeprocessor):
|
||||||
def get_actual_image_url(self, url: str) -> str:
|
def get_actual_image_url(self, url: str) -> str:
|
||||||
# Add specific per-site cases to convert image-preview URLs to image URLs.
|
# Add specific per-site cases to convert image-preview URLs to image URLs.
|
||||||
# See https://github.com/zulip/zulip/issues/4658 for more information
|
# See https://github.com/zulip/zulip/issues/4658 for more information
|
||||||
parsed_url = urlparse(url)
|
parsed_url = urlsplit(url)
|
||||||
if parsed_url.netloc == "github.com" or parsed_url.netloc.endswith(".github.com"):
|
if parsed_url.netloc == "github.com" or parsed_url.netloc.endswith(".github.com"):
|
||||||
# https://github.com/zulip/zulip/blob/main/static/images/logo/zulip-icon-128x128.png ->
|
# https://github.com/zulip/zulip/blob/main/static/images/logo/zulip-icon-128x128.png ->
|
||||||
# https://raw.githubusercontent.com/zulip/zulip/main/static/images/logo/zulip-icon-128x128.png
|
# https://raw.githubusercontent.com/zulip/zulip/main/static/images/logo/zulip-icon-128x128.png
|
||||||
|
@ -730,7 +730,7 @@ class InlineInterestingLinkProcessor(markdown.treeprocessors.Treeprocessor):
|
||||||
def is_image(self, url: str) -> bool:
|
def is_image(self, url: str) -> bool:
|
||||||
if not self.zmd.image_preview_enabled:
|
if not self.zmd.image_preview_enabled:
|
||||||
return False
|
return False
|
||||||
parsed_url = urlparse(url)
|
parsed_url = urlsplit(url)
|
||||||
# remove HTML URLs which end with image extensions that cannot be shorted
|
# remove HTML URLs which end with image extensions that cannot be shorted
|
||||||
if parsed_url.netloc == "pasteboard.co":
|
if parsed_url.netloc == "pasteboard.co":
|
||||||
return False
|
return False
|
||||||
|
@ -742,7 +742,7 @@ class InlineInterestingLinkProcessor(markdown.treeprocessors.Treeprocessor):
|
||||||
# wikipedia.org to point to the actual image URL. It's
|
# wikipedia.org to point to the actual image URL. It's
|
||||||
# structurally very similar to dropbox_image, and possibly
|
# structurally very similar to dropbox_image, and possibly
|
||||||
# should be rewritten to use open graph, but has some value.
|
# should be rewritten to use open graph, but has some value.
|
||||||
parsed_url = urlparse(url)
|
parsed_url = urlsplit(url)
|
||||||
if parsed_url.netloc.lower().endswith(".wikipedia.org") and parsed_url.path.startswith(
|
if parsed_url.netloc.lower().endswith(".wikipedia.org") and parsed_url.path.startswith(
|
||||||
"/wiki/File:"
|
"/wiki/File:"
|
||||||
):
|
):
|
||||||
|
@ -757,7 +757,7 @@ class InlineInterestingLinkProcessor(markdown.treeprocessors.Treeprocessor):
|
||||||
|
|
||||||
def dropbox_image(self, url: str) -> Optional[Dict[str, Any]]:
|
def dropbox_image(self, url: str) -> Optional[Dict[str, Any]]:
|
||||||
# TODO: The returned Dict could possibly be a TypedDict in future.
|
# TODO: The returned Dict could possibly be a TypedDict in future.
|
||||||
parsed_url = urlparse(url)
|
parsed_url = urlsplit(url)
|
||||||
if parsed_url.netloc == "dropbox.com" or parsed_url.netloc.endswith(".dropbox.com"):
|
if parsed_url.netloc == "dropbox.com" or parsed_url.netloc.endswith(".dropbox.com"):
|
||||||
is_album = parsed_url.path.startswith("/sc/") or parsed_url.path.startswith("/photos/")
|
is_album = parsed_url.path.startswith("/sc/") or parsed_url.path.startswith("/photos/")
|
||||||
# Only allow preview Dropbox shared links
|
# Only allow preview Dropbox shared links
|
||||||
|
@ -1566,8 +1566,8 @@ def sanitize_url(url: str) -> Optional[str]:
|
||||||
See the docstring on markdown.inlinepatterns.LinkPattern.sanitize_url.
|
See the docstring on markdown.inlinepatterns.LinkPattern.sanitize_url.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
parts = urlparse(url.replace(" ", "%20"))
|
parts = urlsplit(url.replace(" ", "%20"))
|
||||||
scheme, netloc, path, params, query, fragment = parts
|
scheme, netloc, path, query, fragment = parts
|
||||||
except ValueError:
|
except ValueError:
|
||||||
# Bad URL - so bad it couldn't be parsed.
|
# Bad URL - so bad it couldn't be parsed.
|
||||||
return ""
|
return ""
|
||||||
|
@ -1578,10 +1578,10 @@ def sanitize_url(url: str) -> Optional[str]:
|
||||||
scheme = "mailto"
|
scheme = "mailto"
|
||||||
elif scheme == "" and netloc == "" and len(path) > 0 and path[0] == "/":
|
elif scheme == "" and netloc == "" and len(path) > 0 and path[0] == "/":
|
||||||
# Allow domain-relative links
|
# Allow domain-relative links
|
||||||
return urlunparse(("", "", path, params, query, fragment))
|
return urlunsplit(("", "", path, query, fragment))
|
||||||
elif (scheme, netloc, path, params, query) == ("", "", "", "", "") and len(fragment) > 0:
|
elif (scheme, netloc, path, query) == ("", "", "", "") and len(fragment) > 0:
|
||||||
# Allow fragment links
|
# Allow fragment links
|
||||||
return urlunparse(("", "", "", "", "", fragment))
|
return urlunsplit(("", "", "", "", fragment))
|
||||||
|
|
||||||
# Zulip modification: If scheme is not specified, assume http://
|
# Zulip modification: If scheme is not specified, assume http://
|
||||||
# We re-enter sanitize_url because netloc etc. need to be re-parsed.
|
# We re-enter sanitize_url because netloc etc. need to be re-parsed.
|
||||||
|
@ -1606,7 +1606,7 @@ def sanitize_url(url: str) -> Optional[str]:
|
||||||
# the colon check, which would also forbid a lot of legitimate URLs.
|
# the colon check, which would also forbid a lot of legitimate URLs.
|
||||||
|
|
||||||
# URL passes all tests. Return URL as-is.
|
# URL passes all tests. Return URL as-is.
|
||||||
return urlunparse((scheme, netloc, path, params, query, fragment))
|
return urlunsplit((scheme, netloc, path, query, fragment))
|
||||||
|
|
||||||
|
|
||||||
def url_to_a(
|
def url_to_a(
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlsplit
|
||||||
|
|
||||||
from bs4.element import Tag
|
from bs4.element import Tag
|
||||||
from typing_extensions import override
|
from typing_extensions import override
|
||||||
|
@ -53,9 +53,9 @@ class GenericParser(BaseParser):
|
||||||
if isinstance(first_image, Tag) and first_image["src"] != "":
|
if isinstance(first_image, Tag) and first_image["src"] != "":
|
||||||
assert isinstance(first_image["src"], str)
|
assert isinstance(first_image["src"], str)
|
||||||
try:
|
try:
|
||||||
# We use urlparse and not URLValidator because we
|
# We use urlsplit and not URLValidator because we
|
||||||
# need to support relative URLs.
|
# need to support relative URLs.
|
||||||
urlparse(first_image["src"])
|
urlsplit(first_image["src"])
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return None
|
return None
|
||||||
return first_image["src"]
|
return first_image["src"]
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlsplit
|
||||||
|
|
||||||
from typing_extensions import override
|
from typing_extensions import override
|
||||||
|
|
||||||
|
@ -26,9 +26,9 @@ class OpenGraphParser(BaseParser):
|
||||||
data.description = tag["content"]
|
data.description = tag["content"]
|
||||||
elif tag["property"] == "og:image":
|
elif tag["property"] == "og:image":
|
||||||
try:
|
try:
|
||||||
# We use urlparse and not URLValidator because we
|
# We use urlsplit and not URLValidator because we
|
||||||
# need to support relative URLs.
|
# need to support relative URLs.
|
||||||
urlparse(tag["content"])
|
urlsplit(tag["content"])
|
||||||
except ValueError:
|
except ValueError:
|
||||||
continue
|
continue
|
||||||
data.image = tag["content"]
|
data.image = tag["content"]
|
||||||
|
|
|
@ -24,7 +24,7 @@ from typing import (
|
||||||
Type,
|
Type,
|
||||||
)
|
)
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
from urllib.parse import parse_qs, urlencode, urlparse
|
from urllib.parse import parse_qs, urlencode, urlsplit
|
||||||
|
|
||||||
import jwt
|
import jwt
|
||||||
import ldap
|
import ldap
|
||||||
|
@ -977,7 +977,7 @@ class SocialAuthBase(DesktopFlowTestingLib, ZulipTestCase, ABC):
|
||||||
headers: Any,
|
headers: Any,
|
||||||
**extra_data: Any,
|
**extra_data: Any,
|
||||||
) -> "TestHttpResponse":
|
) -> "TestHttpResponse":
|
||||||
parsed_url = urlparse(result["Location"])
|
parsed_url = urlsplit(result["Location"])
|
||||||
csrf_state = parse_qs(parsed_url.query)["state"]
|
csrf_state = parse_qs(parsed_url.query)["state"]
|
||||||
result = self.client_get(self.AUTH_FINISH_URL, dict(state=csrf_state), **headers)
|
result = self.client_get(self.AUTH_FINISH_URL, dict(state=csrf_state), **headers)
|
||||||
return result
|
return result
|
||||||
|
@ -1157,7 +1157,7 @@ class SocialAuthBase(DesktopFlowTestingLib, ZulipTestCase, ABC):
|
||||||
self.assertEqual(data["subdomain"], "zulip")
|
self.assertEqual(data["subdomain"], "zulip")
|
||||||
self.assertEqual(data["redirect_to"], "/user_uploads/image")
|
self.assertEqual(data["redirect_to"], "/user_uploads/image")
|
||||||
self.assertEqual(result.status_code, 302)
|
self.assertEqual(result.status_code, 302)
|
||||||
parsed_url = urlparse(result["Location"])
|
parsed_url = urlsplit(result["Location"])
|
||||||
url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}"
|
url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}"
|
||||||
self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/"))
|
self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/"))
|
||||||
|
|
||||||
|
@ -1181,7 +1181,7 @@ class SocialAuthBase(DesktopFlowTestingLib, ZulipTestCase, ABC):
|
||||||
self.assertEqual(data["subdomain"], "zulip")
|
self.assertEqual(data["subdomain"], "zulip")
|
||||||
self.assertEqual(data["redirect_to"], "/user_uploads/image")
|
self.assertEqual(data["redirect_to"], "/user_uploads/image")
|
||||||
self.assertEqual(result.status_code, 302)
|
self.assertEqual(result.status_code, 302)
|
||||||
parsed_url = urlparse(result["Location"])
|
parsed_url = urlsplit(result["Location"])
|
||||||
url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}"
|
url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}"
|
||||||
self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/"))
|
self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/"))
|
||||||
|
|
||||||
|
@ -1307,7 +1307,7 @@ class SocialAuthBase(DesktopFlowTestingLib, ZulipTestCase, ABC):
|
||||||
)
|
)
|
||||||
self.assertEqual(result.status_code, 302)
|
self.assertEqual(result.status_code, 302)
|
||||||
redirect_url = result["Location"]
|
redirect_url = result["Location"]
|
||||||
parsed_url = urlparse(redirect_url)
|
parsed_url = urlsplit(redirect_url)
|
||||||
query_params = parse_qs(parsed_url.query)
|
query_params = parse_qs(parsed_url.query)
|
||||||
self.assertEqual(parsed_url.scheme, "zulip")
|
self.assertEqual(parsed_url.scheme, "zulip")
|
||||||
self.assertEqual(query_params["realm"], ["http://zulip.testserver"])
|
self.assertEqual(query_params["realm"], ["http://zulip.testserver"])
|
||||||
|
@ -1403,7 +1403,7 @@ class SocialAuthBase(DesktopFlowTestingLib, ZulipTestCase, ABC):
|
||||||
self.assertEqual(data["full_name"], self.example_user("hamlet").full_name)
|
self.assertEqual(data["full_name"], self.example_user("hamlet").full_name)
|
||||||
self.assertEqual(data["subdomain"], "zulip")
|
self.assertEqual(data["subdomain"], "zulip")
|
||||||
self.assertEqual(result.status_code, 302)
|
self.assertEqual(result.status_code, 302)
|
||||||
parsed_url = urlparse(result["Location"])
|
parsed_url = urlsplit(result["Location"])
|
||||||
url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}"
|
url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}"
|
||||||
self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/"))
|
self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/"))
|
||||||
hamlet = self.example_user("hamlet")
|
hamlet = self.example_user("hamlet")
|
||||||
|
@ -1429,7 +1429,7 @@ class SocialAuthBase(DesktopFlowTestingLib, ZulipTestCase, ABC):
|
||||||
self.assertEqual(data["full_name"], name)
|
self.assertEqual(data["full_name"], name)
|
||||||
self.assertEqual(data["subdomain"], "zulip")
|
self.assertEqual(data["subdomain"], "zulip")
|
||||||
self.assertEqual(result.status_code, 302)
|
self.assertEqual(result.status_code, 302)
|
||||||
parsed_url = urlparse(result["Location"])
|
parsed_url = urlsplit(result["Location"])
|
||||||
url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}"
|
url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}"
|
||||||
self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/"))
|
self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/"))
|
||||||
|
|
||||||
|
@ -1472,7 +1472,7 @@ class SocialAuthBase(DesktopFlowTestingLib, ZulipTestCase, ABC):
|
||||||
if mobile_flow_otp:
|
if mobile_flow_otp:
|
||||||
self.assertEqual(result.status_code, 302)
|
self.assertEqual(result.status_code, 302)
|
||||||
redirect_url = result["Location"]
|
redirect_url = result["Location"]
|
||||||
parsed_url = urlparse(redirect_url)
|
parsed_url = urlsplit(redirect_url)
|
||||||
query_params = parse_qs(parsed_url.query)
|
query_params = parse_qs(parsed_url.query)
|
||||||
self.assertEqual(parsed_url.scheme, "zulip")
|
self.assertEqual(parsed_url.scheme, "zulip")
|
||||||
self.assertEqual(query_params["realm"], ["http://zulip.testserver"])
|
self.assertEqual(query_params["realm"], ["http://zulip.testserver"])
|
||||||
|
@ -1715,7 +1715,7 @@ class SocialAuthBase(DesktopFlowTestingLib, ZulipTestCase, ABC):
|
||||||
self.assertEqual(data["full_name"], name)
|
self.assertEqual(data["full_name"], name)
|
||||||
self.assertEqual(data["subdomain"], "zulip")
|
self.assertEqual(data["subdomain"], "zulip")
|
||||||
self.assertEqual(result.status_code, 302)
|
self.assertEqual(result.status_code, 302)
|
||||||
parsed_url = urlparse(result["Location"])
|
parsed_url = urlsplit(result["Location"])
|
||||||
url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}"
|
url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}"
|
||||||
self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/"))
|
self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/"))
|
||||||
|
|
||||||
|
@ -1739,7 +1739,7 @@ class SocialAuthBase(DesktopFlowTestingLib, ZulipTestCase, ABC):
|
||||||
self.assertEqual(data["full_name"], name)
|
self.assertEqual(data["full_name"], name)
|
||||||
self.assertEqual(data["subdomain"], "zulip")
|
self.assertEqual(data["subdomain"], "zulip")
|
||||||
self.assertEqual(result.status_code, 302)
|
self.assertEqual(result.status_code, 302)
|
||||||
parsed_url = urlparse(result["Location"])
|
parsed_url = urlsplit(result["Location"])
|
||||||
url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}"
|
url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}"
|
||||||
self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/"))
|
self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/"))
|
||||||
|
|
||||||
|
@ -1995,7 +1995,7 @@ class SAMLAuthBackendTest(SocialAuthBase):
|
||||||
assert "samlrequest" in result["Location"].lower()
|
assert "samlrequest" in result["Location"].lower()
|
||||||
|
|
||||||
self.client.cookies = result.cookies
|
self.client.cookies = result.cookies
|
||||||
parsed_url = urlparse(result["Location"])
|
parsed_url = urlsplit(result["Location"])
|
||||||
relay_state = parse_qs(parsed_url.query)["RelayState"][0]
|
relay_state = parse_qs(parsed_url.query)["RelayState"][0]
|
||||||
# Make sure params are getting encoded into RelayState:
|
# Make sure params are getting encoded into RelayState:
|
||||||
data = SAMLAuthBackend.get_data_from_redis(orjson.loads(relay_state)["state_token"])
|
data = SAMLAuthBackend.get_data_from_redis(orjson.loads(relay_state)["state_token"])
|
||||||
|
@ -2148,7 +2148,7 @@ class SAMLAuthBackendTest(SocialAuthBase):
|
||||||
|
|
||||||
# Verify the redirect has the correct form - a LogoutRequest for hamlet
|
# Verify the redirect has the correct form - a LogoutRequest for hamlet
|
||||||
# is delivered to the IdP in the SAMLRequest param.
|
# is delivered to the IdP in the SAMLRequest param.
|
||||||
query_dict = parse_qs(urlparse(result["Location"]).query)
|
query_dict = parse_qs(urlsplit(result["Location"]).query)
|
||||||
saml_request_encoded = query_dict["SAMLRequest"][0]
|
saml_request_encoded = query_dict["SAMLRequest"][0]
|
||||||
saml_request = OneLogin_Saml2_Utils.decode_base64_and_inflate(saml_request_encoded).decode()
|
saml_request = OneLogin_Saml2_Utils.decode_base64_and_inflate(saml_request_encoded).decode()
|
||||||
self.assertIn("<samlp:LogoutRequest", saml_request)
|
self.assertIn("<samlp:LogoutRequest", saml_request)
|
||||||
|
@ -2330,7 +2330,7 @@ class SAMLAuthBackendTest(SocialAuthBase):
|
||||||
redirect_to = result["Location"]
|
redirect_to = result["Location"]
|
||||||
self.assertIn(settings.SOCIAL_AUTH_SAML_ENABLED_IDPS["test_idp"]["slo_url"], redirect_to)
|
self.assertIn(settings.SOCIAL_AUTH_SAML_ENABLED_IDPS["test_idp"]["slo_url"], redirect_to)
|
||||||
|
|
||||||
parsed = urlparse(redirect_to)
|
parsed = urlsplit(redirect_to)
|
||||||
query_dict = parse_qs(parsed.query)
|
query_dict = parse_qs(parsed.query)
|
||||||
|
|
||||||
self.assertIn("SAMLResponse", query_dict)
|
self.assertIn("SAMLResponse", query_dict)
|
||||||
|
@ -3014,7 +3014,7 @@ class SAMLAuthBackendTest(SocialAuthBase):
|
||||||
self.assertEqual(data["full_name"], self.name)
|
self.assertEqual(data["full_name"], self.name)
|
||||||
self.assertEqual(data["subdomain"], "zulip")
|
self.assertEqual(data["subdomain"], "zulip")
|
||||||
self.assertEqual(result.status_code, 302)
|
self.assertEqual(result.status_code, 302)
|
||||||
parsed_url = urlparse(result["Location"])
|
parsed_url = urlsplit(result["Location"])
|
||||||
url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}"
|
url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}"
|
||||||
self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/"))
|
self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/"))
|
||||||
|
|
||||||
|
@ -3049,7 +3049,7 @@ class SAMLAuthBackendTest(SocialAuthBase):
|
||||||
self.assertEqual(data["full_name"], self.name)
|
self.assertEqual(data["full_name"], self.name)
|
||||||
self.assertEqual(data["subdomain"], "zulip")
|
self.assertEqual(data["subdomain"], "zulip")
|
||||||
self.assertEqual(result.status_code, 302)
|
self.assertEqual(result.status_code, 302)
|
||||||
parsed_url = urlparse(result["Location"])
|
parsed_url = urlsplit(result["Location"])
|
||||||
url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}"
|
url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}"
|
||||||
self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/"))
|
self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/"))
|
||||||
|
|
||||||
|
@ -3070,7 +3070,7 @@ class SAMLAuthBackendTest(SocialAuthBase):
|
||||||
self.assertEqual(data["full_name"], self.name)
|
self.assertEqual(data["full_name"], self.name)
|
||||||
self.assertEqual(data["subdomain"], "zulip")
|
self.assertEqual(data["subdomain"], "zulip")
|
||||||
self.assertEqual(result.status_code, 302)
|
self.assertEqual(result.status_code, 302)
|
||||||
parsed_url = urlparse(result["Location"])
|
parsed_url = urlsplit(result["Location"])
|
||||||
url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}"
|
url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}"
|
||||||
self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/"))
|
self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/"))
|
||||||
|
|
||||||
|
@ -3344,7 +3344,7 @@ class AppleIdAuthBackendTest(AppleAuthMixin, SocialAuthBase):
|
||||||
headers: Any,
|
headers: Any,
|
||||||
**extra_data: Any,
|
**extra_data: Any,
|
||||||
) -> "TestHttpResponse":
|
) -> "TestHttpResponse":
|
||||||
parsed_url = urlparse(result["Location"])
|
parsed_url = urlsplit(result["Location"])
|
||||||
state = parse_qs(parsed_url.query)["state"]
|
state = parse_qs(parsed_url.query)["state"]
|
||||||
user_param = json.dumps(account_data_dict)
|
user_param = json.dumps(account_data_dict)
|
||||||
self.client.session.flush()
|
self.client.session.flush()
|
||||||
|
@ -3923,7 +3923,7 @@ class GitHubAuthBackendTest(SocialAuthBase):
|
||||||
expect_noreply_email_allowed: bool = False,
|
expect_noreply_email_allowed: bool = False,
|
||||||
**extra_data: Any,
|
**extra_data: Any,
|
||||||
) -> "TestHttpResponse":
|
) -> "TestHttpResponse":
|
||||||
parsed_url = urlparse(result["Location"])
|
parsed_url = urlsplit(result["Location"])
|
||||||
csrf_state = parse_qs(parsed_url.query)["state"]
|
csrf_state = parse_qs(parsed_url.query)["state"]
|
||||||
result = self.client_get(self.AUTH_FINISH_URL, dict(state=csrf_state), **headers)
|
result = self.client_get(self.AUTH_FINISH_URL, dict(state=csrf_state), **headers)
|
||||||
|
|
||||||
|
@ -4120,7 +4120,7 @@ class GitHubAuthBackendTest(SocialAuthBase):
|
||||||
self.assertEqual(data["subdomain"], "zulip")
|
self.assertEqual(data["subdomain"], "zulip")
|
||||||
self.assertEqual(data["redirect_to"], "/user_uploads/image")
|
self.assertEqual(data["redirect_to"], "/user_uploads/image")
|
||||||
self.assertEqual(result.status_code, 302)
|
self.assertEqual(result.status_code, 302)
|
||||||
parsed_url = urlparse(result["Location"])
|
parsed_url = urlsplit(result["Location"])
|
||||||
url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}"
|
url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}"
|
||||||
self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/"))
|
self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/"))
|
||||||
|
|
||||||
|
@ -4145,7 +4145,7 @@ class GitHubAuthBackendTest(SocialAuthBase):
|
||||||
self.assertEqual(data["subdomain"], "zulip")
|
self.assertEqual(data["subdomain"], "zulip")
|
||||||
self.assertEqual(data["redirect_to"], "/user_uploads/image")
|
self.assertEqual(data["redirect_to"], "/user_uploads/image")
|
||||||
self.assertEqual(result.status_code, 302)
|
self.assertEqual(result.status_code, 302)
|
||||||
parsed_url = urlparse(result["Location"])
|
parsed_url = urlsplit(result["Location"])
|
||||||
url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}"
|
url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}"
|
||||||
self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/"))
|
self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/"))
|
||||||
|
|
||||||
|
@ -4174,7 +4174,7 @@ class GitHubAuthBackendTest(SocialAuthBase):
|
||||||
self.assertEqual(data["subdomain"], "zulip")
|
self.assertEqual(data["subdomain"], "zulip")
|
||||||
self.assertEqual(data["redirect_to"], "/user_uploads/image")
|
self.assertEqual(data["redirect_to"], "/user_uploads/image")
|
||||||
self.assertEqual(result.status_code, 302)
|
self.assertEqual(result.status_code, 302)
|
||||||
parsed_url = urlparse(result["Location"])
|
parsed_url = urlsplit(result["Location"])
|
||||||
url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}"
|
url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}"
|
||||||
self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/"))
|
self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/"))
|
||||||
|
|
||||||
|
@ -4203,7 +4203,7 @@ class GitHubAuthBackendTest(SocialAuthBase):
|
||||||
self.assertEqual(data["subdomain"], "zulip")
|
self.assertEqual(data["subdomain"], "zulip")
|
||||||
self.assertEqual(data["redirect_to"], "/user_uploads/image")
|
self.assertEqual(data["redirect_to"], "/user_uploads/image")
|
||||||
self.assertEqual(result.status_code, 302)
|
self.assertEqual(result.status_code, 302)
|
||||||
parsed_url = urlparse(result["Location"])
|
parsed_url = urlsplit(result["Location"])
|
||||||
url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}"
|
url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}"
|
||||||
self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/"))
|
self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/"))
|
||||||
|
|
||||||
|
@ -4264,7 +4264,7 @@ class GitHubAuthBackendTest(SocialAuthBase):
|
||||||
self.assertEqual(data["subdomain"], "zulip")
|
self.assertEqual(data["subdomain"], "zulip")
|
||||||
self.assertEqual(data["redirect_to"], "/user_uploads/image")
|
self.assertEqual(data["redirect_to"], "/user_uploads/image")
|
||||||
self.assertEqual(result.status_code, 302)
|
self.assertEqual(result.status_code, 302)
|
||||||
parsed_url = urlparse(result["Location"])
|
parsed_url = urlsplit(result["Location"])
|
||||||
url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}"
|
url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}"
|
||||||
self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/"))
|
self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/"))
|
||||||
|
|
||||||
|
@ -4347,7 +4347,7 @@ class GitHubAuthBackendTest(SocialAuthBase):
|
||||||
self.assertEqual(data["full_name"], account_data_dict["name"])
|
self.assertEqual(data["full_name"], account_data_dict["name"])
|
||||||
self.assertEqual(data["subdomain"], "zulip")
|
self.assertEqual(data["subdomain"], "zulip")
|
||||||
self.assertEqual(result.status_code, 302)
|
self.assertEqual(result.status_code, 302)
|
||||||
parsed_url = urlparse(result["Location"])
|
parsed_url = urlsplit(result["Location"])
|
||||||
url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}"
|
url = f"{parsed_url.scheme}://{parsed_url.netloc}{parsed_url.path}"
|
||||||
self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/"))
|
self.assertTrue(url.startswith("http://zulip.testserver/accounts/login/subdomain/"))
|
||||||
|
|
||||||
|
@ -4486,7 +4486,7 @@ class GoogleAuthBackendTest(SocialAuthBase):
|
||||||
|
|
||||||
self.assertEqual(result.status_code, 302)
|
self.assertEqual(result.status_code, 302)
|
||||||
redirect_url = result["Location"]
|
redirect_url = result["Location"]
|
||||||
parsed_url = urlparse(redirect_url)
|
parsed_url = urlsplit(redirect_url)
|
||||||
query_params = parse_qs(parsed_url.query)
|
query_params = parse_qs(parsed_url.query)
|
||||||
self.assertEqual(parsed_url.scheme, "zulip")
|
self.assertEqual(parsed_url.scheme, "zulip")
|
||||||
self.assertEqual(query_params["realm"], ["http://zulip-mobile.testserver"])
|
self.assertEqual(query_params["realm"], ["http://zulip-mobile.testserver"])
|
||||||
|
@ -4531,7 +4531,7 @@ class GoogleAuthBackendTest(SocialAuthBase):
|
||||||
)
|
)
|
||||||
self.assertEqual(result.status_code, 302)
|
self.assertEqual(result.status_code, 302)
|
||||||
redirect_url = result["Location"]
|
redirect_url = result["Location"]
|
||||||
parsed_url = urlparse(redirect_url)
|
parsed_url = urlsplit(redirect_url)
|
||||||
query_params = parse_qs(parsed_url.query)
|
query_params = parse_qs(parsed_url.query)
|
||||||
self.assertEqual(parsed_url.scheme, "zulip")
|
self.assertEqual(parsed_url.scheme, "zulip")
|
||||||
self.assertEqual(query_params["realm"], ["http://zulip.testserver"])
|
self.assertEqual(query_params["realm"], ["http://zulip.testserver"])
|
||||||
|
@ -5529,7 +5529,7 @@ class TestZulipRemoteUserBackend(DesktopFlowTestingLib, ZulipTestCase):
|
||||||
self.assertEqual(result.status_code, 302)
|
self.assertEqual(result.status_code, 302)
|
||||||
|
|
||||||
url = result["Location"]
|
url = result["Location"]
|
||||||
parsed_url = urlparse(url)
|
parsed_url = urlsplit(url)
|
||||||
self.assertEqual(parsed_url.path, "/accounts/login/sso/")
|
self.assertEqual(parsed_url.path, "/accounts/login/sso/")
|
||||||
self.assertEqual(parsed_url.query, "param1=value1¶ms=value2")
|
self.assertEqual(parsed_url.query, "param1=value1¶ms=value2")
|
||||||
|
|
||||||
|
@ -5673,7 +5673,7 @@ class TestZulipRemoteUserBackend(DesktopFlowTestingLib, ZulipTestCase):
|
||||||
)
|
)
|
||||||
self.assertEqual(result.status_code, 302)
|
self.assertEqual(result.status_code, 302)
|
||||||
redirect_url = result["Location"]
|
redirect_url = result["Location"]
|
||||||
parsed_url = urlparse(redirect_url)
|
parsed_url = urlsplit(redirect_url)
|
||||||
query_params = parse_qs(parsed_url.query)
|
query_params = parse_qs(parsed_url.query)
|
||||||
self.assertEqual(parsed_url.scheme, "zulip")
|
self.assertEqual(parsed_url.scheme, "zulip")
|
||||||
self.assertEqual(query_params["realm"], ["http://zulip.testserver"])
|
self.assertEqual(query_params["realm"], ["http://zulip.testserver"])
|
||||||
|
@ -5722,7 +5722,7 @@ class TestZulipRemoteUserBackend(DesktopFlowTestingLib, ZulipTestCase):
|
||||||
)
|
)
|
||||||
self.assertEqual(result.status_code, 302)
|
self.assertEqual(result.status_code, 302)
|
||||||
redirect_url = result["Location"]
|
redirect_url = result["Location"]
|
||||||
parsed_url = urlparse(redirect_url)
|
parsed_url = urlsplit(redirect_url)
|
||||||
query_params = parse_qs(parsed_url.query)
|
query_params = parse_qs(parsed_url.query)
|
||||||
self.assertEqual(parsed_url.scheme, "zulip")
|
self.assertEqual(parsed_url.scheme, "zulip")
|
||||||
self.assertEqual(query_params["realm"], ["http://zulip.testserver"])
|
self.assertEqual(query_params["realm"], ["http://zulip.testserver"])
|
||||||
|
|
|
@ -2,7 +2,7 @@ import calendar
|
||||||
from datetime import timedelta, timezone
|
from datetime import timedelta, timezone
|
||||||
from typing import TYPE_CHECKING, Any, Dict
|
from typing import TYPE_CHECKING, Any, Dict
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlsplit
|
||||||
|
|
||||||
import orjson
|
import orjson
|
||||||
import time_machine
|
import time_machine
|
||||||
|
@ -1011,7 +1011,7 @@ class HomeTest(ZulipTestCase):
|
||||||
self.assertTrue(result["Location"].endswith("/desktop_home/"))
|
self.assertTrue(result["Location"].endswith("/desktop_home/"))
|
||||||
result = self.client_get("/desktop_home/")
|
result = self.client_get("/desktop_home/")
|
||||||
self.assertEqual(result.status_code, 302)
|
self.assertEqual(result.status_code, 302)
|
||||||
path = urlparse(result["Location"]).path
|
path = urlsplit(result["Location"]).path
|
||||||
self.assertEqual(path, "/")
|
self.assertEqual(path, "/")
|
||||||
|
|
||||||
@override_settings(SERVER_UPGRADE_NAG_DEADLINE_DAYS=365)
|
@override_settings(SERVER_UPGRADE_NAG_DEADLINE_DAYS=365)
|
||||||
|
|
|
@ -3,7 +3,7 @@ import time
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from typing import TYPE_CHECKING, Any, Dict, Optional, Sequence, Union
|
from typing import TYPE_CHECKING, Any, Dict, Optional, Sequence, Union
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock, patch
|
||||||
from urllib.parse import quote, quote_plus, urlencode, urlparse
|
from urllib.parse import quote, quote_plus, urlencode, urlsplit
|
||||||
|
|
||||||
import orjson
|
import orjson
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
@ -1095,7 +1095,7 @@ class EmailUnsubscribeTests(ZulipTestCase):
|
||||||
# An unknown message type "fake" produces an error.
|
# An unknown message type "fake" produces an error.
|
||||||
user_profile = self.example_user("hamlet")
|
user_profile = self.example_user("hamlet")
|
||||||
unsubscribe_link = one_click_unsubscribe_link(user_profile, "fake")
|
unsubscribe_link = one_click_unsubscribe_link(user_profile, "fake")
|
||||||
result = self.client_get(urlparse(unsubscribe_link).path)
|
result = self.client_get(urlsplit(unsubscribe_link).path)
|
||||||
self.assert_in_response("Unknown email unsubscribe request", result)
|
self.assert_in_response("Unknown email unsubscribe request", result)
|
||||||
|
|
||||||
def test_message_notification_emails_unsubscribe(self) -> None:
|
def test_message_notification_emails_unsubscribe(self) -> None:
|
||||||
|
@ -1109,7 +1109,7 @@ class EmailUnsubscribeTests(ZulipTestCase):
|
||||||
user_profile.save()
|
user_profile.save()
|
||||||
|
|
||||||
unsubscribe_link = one_click_unsubscribe_link(user_profile, "missed_messages")
|
unsubscribe_link = one_click_unsubscribe_link(user_profile, "missed_messages")
|
||||||
result = self.client_get(urlparse(unsubscribe_link).path)
|
result = self.client_get(urlsplit(unsubscribe_link).path)
|
||||||
|
|
||||||
self.assertEqual(result.status_code, 200)
|
self.assertEqual(result.status_code, 200)
|
||||||
|
|
||||||
|
@ -1128,7 +1128,7 @@ class EmailUnsubscribeTests(ZulipTestCase):
|
||||||
|
|
||||||
# Simulate unsubscribing from the welcome e-mails.
|
# Simulate unsubscribing from the welcome e-mails.
|
||||||
unsubscribe_link = one_click_unsubscribe_link(user_profile, "welcome")
|
unsubscribe_link = one_click_unsubscribe_link(user_profile, "welcome")
|
||||||
result = self.client_get(urlparse(unsubscribe_link).path)
|
result = self.client_get(urlsplit(unsubscribe_link).path)
|
||||||
|
|
||||||
# The welcome email jobs are no longer scheduled.
|
# The welcome email jobs are no longer scheduled.
|
||||||
self.assertEqual(result.status_code, 200)
|
self.assertEqual(result.status_code, 200)
|
||||||
|
@ -1166,7 +1166,7 @@ class EmailUnsubscribeTests(ZulipTestCase):
|
||||||
|
|
||||||
# Simulate unsubscribing from digest e-mails.
|
# Simulate unsubscribing from digest e-mails.
|
||||||
unsubscribe_link = one_click_unsubscribe_link(user_profile, "digest")
|
unsubscribe_link = one_click_unsubscribe_link(user_profile, "digest")
|
||||||
result = self.client_get(urlparse(unsubscribe_link).path)
|
result = self.client_get(urlsplit(unsubscribe_link).path)
|
||||||
|
|
||||||
# The setting is toggled off, and scheduled jobs have been removed.
|
# The setting is toggled off, and scheduled jobs have been removed.
|
||||||
self.assertEqual(result.status_code, 200)
|
self.assertEqual(result.status_code, 200)
|
||||||
|
@ -1187,7 +1187,7 @@ class EmailUnsubscribeTests(ZulipTestCase):
|
||||||
user_profile.save()
|
user_profile.save()
|
||||||
|
|
||||||
unsubscribe_link = one_click_unsubscribe_link(user_profile, "login")
|
unsubscribe_link = one_click_unsubscribe_link(user_profile, "login")
|
||||||
result = self.client_get(urlparse(unsubscribe_link).path)
|
result = self.client_get(urlsplit(unsubscribe_link).path)
|
||||||
|
|
||||||
self.assertEqual(result.status_code, 200)
|
self.assertEqual(result.status_code, 200)
|
||||||
|
|
||||||
|
@ -1204,7 +1204,7 @@ class EmailUnsubscribeTests(ZulipTestCase):
|
||||||
|
|
||||||
# Simulate unsubscribing from marketing e-mails.
|
# Simulate unsubscribing from marketing e-mails.
|
||||||
unsubscribe_link = one_click_unsubscribe_link(user_profile, "marketing")
|
unsubscribe_link = one_click_unsubscribe_link(user_profile, "marketing")
|
||||||
result = self.client_get(urlparse(unsubscribe_link).path)
|
result = self.client_get(urlsplit(unsubscribe_link).path)
|
||||||
self.assertEqual(result.status_code, 200)
|
self.assertEqual(result.status_code, 200)
|
||||||
|
|
||||||
# Circumvent user_profile caching.
|
# Circumvent user_profile caching.
|
||||||
|
@ -1223,7 +1223,7 @@ class EmailUnsubscribeTests(ZulipTestCase):
|
||||||
# Simulate unsubscribing from marketing e-mails.
|
# Simulate unsubscribing from marketing e-mails.
|
||||||
unsubscribe_link = one_click_unsubscribe_link(user_profile, "marketing")
|
unsubscribe_link = one_click_unsubscribe_link(user_profile, "marketing")
|
||||||
client = Client(enforce_csrf_checks=True)
|
client = Client(enforce_csrf_checks=True)
|
||||||
result = client.post(urlparse(unsubscribe_link).path, {"List-Unsubscribe": "One-Click"})
|
result = client.post(urlsplit(unsubscribe_link).path, {"List-Unsubscribe": "One-Click"})
|
||||||
self.assertEqual(result.status_code, 200)
|
self.assertEqual(result.status_code, 200)
|
||||||
|
|
||||||
# Circumvent user_profile caching.
|
# Circumvent user_profile caching.
|
||||||
|
|
|
@ -4,7 +4,7 @@ from io import BytesIO
|
||||||
from typing import Any, Dict, Iterator, List, Set, Tuple
|
from typing import Any, Dict, Iterator, List, Set, Tuple
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
from unittest.mock import ANY
|
from unittest.mock import ANY
|
||||||
from urllib.parse import parse_qs, urlparse
|
from urllib.parse import parse_qs, urlsplit
|
||||||
|
|
||||||
import orjson
|
import orjson
|
||||||
import responses
|
import responses
|
||||||
|
@ -76,7 +76,7 @@ def request_callback(request: PreparedRequest) -> Tuple[int, Dict[str, str], byt
|
||||||
if request.url == "https://slack.com/api/users.list":
|
if request.url == "https://slack.com/api/users.list":
|
||||||
return (200, {}, orjson.dumps({"ok": True, "members": "user_data"}))
|
return (200, {}, orjson.dumps({"ok": True, "members": "user_data"}))
|
||||||
|
|
||||||
query_from_url = str(urlparse(request.url).query)
|
query_from_url = str(urlsplit(request.url).query)
|
||||||
qs = parse_qs(query_from_url)
|
qs = parse_qs(query_from_url)
|
||||||
if request.url and "https://slack.com/api/users.info" in request.url:
|
if request.url and "https://slack.com/api/users.info" in request.url:
|
||||||
user2team_dict = {
|
user2team_dict = {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
from io import BytesIO, StringIO
|
from io import BytesIO, StringIO
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlsplit
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
@ -143,7 +143,7 @@ class LocalStorageTest(UploadSerializeMixin, ZulipTestCase):
|
||||||
# on-disk content, which nginx serves
|
# on-disk content, which nginx serves
|
||||||
result = self.client_get(url)
|
result = self.client_get(url)
|
||||||
self.assertEqual(result.status_code, 200)
|
self.assertEqual(result.status_code, 200)
|
||||||
internal_redirect_path = urlparse(url).path.replace(
|
internal_redirect_path = urlsplit(url).path.replace(
|
||||||
"/user_avatars/", "/internal/local/user_avatars/"
|
"/user_avatars/", "/internal/local/user_avatars/"
|
||||||
)
|
)
|
||||||
self.assertEqual(result["X-Accel-Redirect"], internal_redirect_path)
|
self.assertEqual(result["X-Accel-Redirect"], internal_redirect_path)
|
||||||
|
@ -257,5 +257,5 @@ class LocalStorageTest(UploadSerializeMixin, ZulipTestCase):
|
||||||
warn_log.output,
|
warn_log.output,
|
||||||
["WARNING:root:not_a_file does not exist. Its entry in the database will be removed."],
|
["WARNING:root:not_a_file does not exist. Its entry in the database will be removed."],
|
||||||
)
|
)
|
||||||
path_id = urlparse(url).path
|
path_id = urlsplit(url).path
|
||||||
self.assertEqual(delete_export_tarball(path_id), path_id)
|
self.assertEqual(delete_export_tarball(path_id), path_id)
|
||||||
|
|
|
@ -3,7 +3,7 @@ import os
|
||||||
import re
|
import re
|
||||||
from io import BytesIO, StringIO
|
from io import BytesIO, StringIO
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlsplit
|
||||||
|
|
||||||
import botocore.exceptions
|
import botocore.exceptions
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
@ -191,7 +191,7 @@ class S3Test(ZulipTestCase):
|
||||||
# In development, this is just a redirect
|
# In development, this is just a redirect
|
||||||
response = self.client_get(url)
|
response = self.client_get(url)
|
||||||
redirect_url = response["Location"]
|
redirect_url = response["Location"]
|
||||||
path = urlparse(redirect_url).path
|
path = urlsplit(redirect_url).path
|
||||||
assert path.startswith("/")
|
assert path.startswith("/")
|
||||||
key = path[len("/") :]
|
key = path[len("/") :]
|
||||||
self.assertEqual(b"zulip!", bucket.Object(key).get()["Body"].read())
|
self.assertEqual(b"zulip!", bucket.Object(key).get()["Body"].read())
|
||||||
|
@ -200,7 +200,7 @@ class S3Test(ZulipTestCase):
|
||||||
with self.settings(DEVELOPMENT=False):
|
with self.settings(DEVELOPMENT=False):
|
||||||
response = self.client_get(url)
|
response = self.client_get(url)
|
||||||
redirect_url = response["X-Accel-Redirect"]
|
redirect_url = response["X-Accel-Redirect"]
|
||||||
path = urlparse(redirect_url).path
|
path = urlsplit(redirect_url).path
|
||||||
assert path.startswith(prefix)
|
assert path.startswith(prefix)
|
||||||
key = path[len(prefix) :]
|
key = path[len(prefix) :]
|
||||||
self.assertEqual(b"zulip!", bucket.Object(key).get()["Body"].read())
|
self.assertEqual(b"zulip!", bucket.Object(key).get()["Body"].read())
|
||||||
|
@ -210,7 +210,7 @@ class S3Test(ZulipTestCase):
|
||||||
with self.settings(DEVELOPMENT=False):
|
with self.settings(DEVELOPMENT=False):
|
||||||
response = self.client_get(download_url)
|
response = self.client_get(download_url)
|
||||||
redirect_url = response["X-Accel-Redirect"]
|
redirect_url = response["X-Accel-Redirect"]
|
||||||
path = urlparse(redirect_url).path
|
path = urlsplit(redirect_url).path
|
||||||
assert path.startswith(prefix)
|
assert path.startswith(prefix)
|
||||||
key = path[len(prefix) :]
|
key = path[len(prefix) :]
|
||||||
self.assertEqual(b"zulip!", bucket.Object(key).get()["Body"].read())
|
self.assertEqual(b"zulip!", bucket.Object(key).get()["Body"].read())
|
||||||
|
@ -230,7 +230,7 @@ class S3Test(ZulipTestCase):
|
||||||
with self.settings(DEVELOPMENT=False):
|
with self.settings(DEVELOPMENT=False):
|
||||||
self.client_get(url_only_url)
|
self.client_get(url_only_url)
|
||||||
redirect_url = response["X-Accel-Redirect"]
|
redirect_url = response["X-Accel-Redirect"]
|
||||||
path = urlparse(redirect_url).path
|
path = urlsplit(redirect_url).path
|
||||||
assert path.startswith(prefix)
|
assert path.startswith(prefix)
|
||||||
key = path[len(prefix) :]
|
key = path[len(prefix) :]
|
||||||
self.assertEqual(b"zulip!", bucket.Object(key).get()["Body"].read())
|
self.assertEqual(b"zulip!", bucket.Object(key).get()["Body"].read())
|
||||||
|
@ -532,5 +532,5 @@ class S3Test(ZulipTestCase):
|
||||||
warn_log.output,
|
warn_log.output,
|
||||||
["WARNING:root:not_a_file does not exist. Its entry in the database will be removed."],
|
["WARNING:root:not_a_file does not exist. Its entry in the database will be removed."],
|
||||||
)
|
)
|
||||||
path_id = urlparse(url).path
|
path_id = urlsplit(url).path
|
||||||
self.assertEqual(delete_export_tarball(path_id), path_id)
|
self.assertEqual(delete_export_tarball(path_id), path_id)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
from typing import Any, Dict, Iterable, List, Mapping, Optional, Sequence, Tuple, Union
|
from typing import Any, Dict, Iterable, List, Mapping, Optional, Sequence, Tuple, Union
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlsplit
|
||||||
|
|
||||||
import orjson
|
import orjson
|
||||||
import requests
|
import requests
|
||||||
|
@ -50,7 +50,7 @@ class TornadoAdapter(HTTPAdapter):
|
||||||
request, stream=stream, timeout=timeout, verify=verify, cert=cert, proxies=proxies
|
request, stream=stream, timeout=timeout, verify=verify, cert=cert, proxies=proxies
|
||||||
)
|
)
|
||||||
except ConnectionError:
|
except ConnectionError:
|
||||||
parsed_url = urlparse(request.url)
|
parsed_url = urlsplit(request.url)
|
||||||
logfile = (
|
logfile = (
|
||||||
f"tornado-{parsed_url.port}.log"
|
f"tornado-{parsed_url.port}.log"
|
||||||
if settings.TORNADO_PROCESSES > 1
|
if settings.TORNADO_PROCESSES > 1
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import logging
|
import logging
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
from typing import Type
|
from typing import Type
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlsplit
|
||||||
|
|
||||||
import orjson
|
import orjson
|
||||||
from circuitbreaker import CircuitBreakerError, circuit
|
from circuitbreaker import CircuitBreakerError, circuit
|
||||||
|
@ -34,7 +34,7 @@ def sentry_tunnel(
|
||||||
try:
|
try:
|
||||||
envelope_header_line, envelope_items = request.body.split(b"\n", 1)
|
envelope_header_line, envelope_items = request.body.split(b"\n", 1)
|
||||||
envelope_header = to_wild_value("envelope_header", envelope_header_line.decode("utf-8"))
|
envelope_header = to_wild_value("envelope_header", envelope_header_line.decode("utf-8"))
|
||||||
dsn = urlparse(envelope_header["dsn"].tame(check_url))
|
dsn = urlsplit(envelope_header["dsn"].tame(check_url))
|
||||||
except Exception:
|
except Exception:
|
||||||
raise JsonableError(_("Invalid request format"))
|
raise JsonableError(_("Invalid request format"))
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import os
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from mimetypes import guess_type
|
from mimetypes import guess_type
|
||||||
from typing import List, Optional, Union
|
from typing import List, Optional, Union
|
||||||
from urllib.parse import quote, urlparse
|
from urllib.parse import quote, urlsplit
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.models import AnonymousUser
|
from django.contrib.auth.models import AnonymousUser
|
||||||
|
@ -41,7 +41,7 @@ from zerver.models import UserProfile, validate_attachment_request
|
||||||
|
|
||||||
|
|
||||||
def patch_disposition_header(response: HttpResponse, url: str, is_attachment: bool) -> None:
|
def patch_disposition_header(response: HttpResponse, url: str, is_attachment: bool) -> None:
|
||||||
filename = os.path.basename(urlparse(url).path)
|
filename = os.path.basename(urlsplit(url).path)
|
||||||
content_disposition = content_disposition_header(is_attachment, filename)
|
content_disposition = content_disposition_header(is_attachment, filename)
|
||||||
|
|
||||||
if content_disposition is not None:
|
if content_disposition is not None:
|
||||||
|
@ -84,7 +84,7 @@ def serve_s3(request: HttpRequest, path_id: str, force_download: bool = False) -
|
||||||
|
|
||||||
# We over-escape the path, to work around it being impossible to
|
# We over-escape the path, to work around it being impossible to
|
||||||
# get the _unescaped_ new internal request URI in nginx.
|
# get the _unescaped_ new internal request URI in nginx.
|
||||||
parsed_url = urlparse(url)
|
parsed_url = urlsplit(url)
|
||||||
assert parsed_url.hostname is not None
|
assert parsed_url.hostname is not None
|
||||||
assert parsed_url.path is not None
|
assert parsed_url.path is not None
|
||||||
assert parsed_url.query is not None
|
assert parsed_url.query is not None
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Webhooks for external integrations.
|
# Webhooks for external integrations.
|
||||||
from typing import Optional, Tuple
|
from typing import Optional, Tuple
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlsplit
|
||||||
|
|
||||||
from django.http import HttpRequest, HttpResponse
|
from django.http import HttpRequest, HttpResponse
|
||||||
|
|
||||||
|
@ -224,7 +224,7 @@ def semaphore_2(payload: WildValue) -> Tuple[str, str, Optional[str], str]:
|
||||||
|
|
||||||
|
|
||||||
def is_github_repo(repo_url: str) -> bool:
|
def is_github_repo(repo_url: str) -> bool:
|
||||||
return urlparse(repo_url).hostname == "github.com"
|
return urlsplit(repo_url).hostname == "github.com"
|
||||||
|
|
||||||
|
|
||||||
def summary_line(message: str) -> str:
|
def summary_line(message: str) -> str:
|
||||||
|
|
|
@ -30,7 +30,7 @@ from typing import (
|
||||||
Type,
|
Type,
|
||||||
TypeVar,
|
TypeVar,
|
||||||
)
|
)
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlsplit
|
||||||
|
|
||||||
import orjson
|
import orjson
|
||||||
import sentry_sdk
|
import sentry_sdk
|
||||||
|
@ -1132,7 +1132,7 @@ class DeferredWorker(QueueProcessingWorker):
|
||||||
assert public_url is not None
|
assert public_url is not None
|
||||||
|
|
||||||
# Update the extra_data field now that the export is complete.
|
# Update the extra_data field now that the export is complete.
|
||||||
extra_data["export_path"] = urlparse(public_url).path
|
extra_data["export_path"] = urlsplit(public_url).path
|
||||||
export_event.extra_data = extra_data
|
export_event.extra_data = extra_data
|
||||||
export_event.save(update_fields=["extra_data"])
|
export_event.save(update_fields=["extra_data"])
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue