2018-07-29 00:05:45 +02:00
|
|
|
import urllib
|
2018-10-27 16:37:29 +02:00
|
|
|
from typing import Any, Dict, List
|
2018-07-29 00:05:45 +02:00
|
|
|
|
2019-12-20 00:00:45 +01:00
|
|
|
from zerver.lib.pysa import mark_sanitized
|
2018-11-10 22:50:28 +01:00
|
|
|
from zerver.lib.topic import get_topic_from_message_info
|
2018-11-12 15:04:03 +01:00
|
|
|
from zerver.models import Realm, Stream, UserProfile
|
2018-07-29 00:05:45 +02:00
|
|
|
|
2020-06-11 00:54:34 +02:00
|
|
|
|
2018-07-29 00:05:45 +02:00
|
|
|
def hash_util_encode(string: str) -> str:
|
|
|
|
# Do the same encoding operation as hash_util.encodeHashComponent on the
|
|
|
|
# frontend.
|
|
|
|
# `safe` has a default value of "/", but we want those encoded, too.
|
|
|
|
return urllib.parse.quote(
|
|
|
|
string.encode("utf-8"), safe=b"").replace(".", "%2E").replace("%", ".")
|
|
|
|
|
|
|
|
def encode_stream(stream_id: int, stream_name: str) -> str:
|
|
|
|
# We encode streams for urls as something like 99-Verona.
|
|
|
|
stream_name = stream_name.replace(' ', '-')
|
|
|
|
return str(stream_id) + '-' + hash_util_encode(stream_name)
|
|
|
|
|
2018-11-12 15:04:03 +01:00
|
|
|
def personal_narrow_url(realm: Realm, sender: UserProfile) -> str:
|
2020-06-10 06:41:04 +02:00
|
|
|
base_url = f"{realm.uri}/#narrow/pm-with/"
|
2018-11-12 15:04:03 +01:00
|
|
|
email_user = sender.email.split('@')[0].lower()
|
|
|
|
pm_slug = str(sender.id) + '-' + hash_util_encode(email_user)
|
|
|
|
return base_url + pm_slug
|
|
|
|
|
2018-11-12 15:51:37 +01:00
|
|
|
def huddle_narrow_url(realm: Realm, other_user_ids: List[int]) -> str:
|
|
|
|
pm_slug = ','.join(str(user_id) for user_id in sorted(other_user_ids)) + '-group'
|
2020-06-10 06:41:04 +02:00
|
|
|
base_url = f"{realm.uri}/#narrow/pm-with/"
|
2018-11-12 15:51:37 +01:00
|
|
|
return base_url + pm_slug
|
2018-07-29 00:05:45 +02:00
|
|
|
|
|
|
|
def stream_narrow_url(realm: Realm, stream: Stream) -> str:
|
2020-06-10 06:41:04 +02:00
|
|
|
base_url = f"{realm.uri}/#narrow/stream/"
|
2018-07-29 00:05:45 +02:00
|
|
|
return base_url + encode_stream(stream.id, stream.name)
|
|
|
|
|
|
|
|
def topic_narrow_url(realm: Realm, stream: Stream, topic: str) -> str:
|
2020-06-10 06:41:04 +02:00
|
|
|
base_url = f"{realm.uri}/#narrow/stream/"
|
|
|
|
return f"{base_url}{encode_stream(stream.id, stream.name)}/topic/{hash_util_encode(topic)}"
|
2018-10-27 16:37:29 +02:00
|
|
|
|
|
|
|
def near_message_url(realm: Realm,
|
|
|
|
message: Dict[str, Any]) -> str:
|
|
|
|
|
|
|
|
if message['type'] == 'stream':
|
|
|
|
url = near_stream_message_url(
|
|
|
|
realm=realm,
|
|
|
|
message=message,
|
|
|
|
)
|
|
|
|
return url
|
|
|
|
|
|
|
|
url = near_pm_message_url(
|
|
|
|
realm=realm,
|
|
|
|
message=message,
|
|
|
|
)
|
|
|
|
return url
|
|
|
|
|
|
|
|
def near_stream_message_url(realm: Realm,
|
|
|
|
message: Dict[str, Any]) -> str:
|
|
|
|
message_id = str(message['id'])
|
|
|
|
stream_id = message['stream_id']
|
|
|
|
stream_name = message['display_recipient']
|
2018-11-10 22:50:28 +01:00
|
|
|
topic_name = get_topic_from_message_info(message)
|
2018-10-27 16:37:29 +02:00
|
|
|
encoded_topic = hash_util_encode(topic_name)
|
|
|
|
encoded_stream = encode_stream(stream_id=stream_id, stream_name=stream_name)
|
|
|
|
|
|
|
|
parts = [
|
|
|
|
realm.uri,
|
|
|
|
'#narrow',
|
|
|
|
'stream',
|
|
|
|
encoded_stream,
|
|
|
|
'topic',
|
|
|
|
encoded_topic,
|
|
|
|
'near',
|
|
|
|
message_id,
|
|
|
|
]
|
|
|
|
full_url = '/'.join(parts)
|
|
|
|
return full_url
|
|
|
|
|
|
|
|
def near_pm_message_url(realm: Realm,
|
|
|
|
message: Dict[str, Any]) -> str:
|
|
|
|
message_id = str(message['id'])
|
|
|
|
str_user_ids = [
|
|
|
|
str(recipient['id'])
|
|
|
|
for recipient in message['display_recipient']
|
|
|
|
]
|
|
|
|
|
|
|
|
# Use the "perma-link" format here that includes the sender's
|
|
|
|
# user_id, so they're easier to share between people.
|
|
|
|
pm_str = ','.join(str_user_ids) + '-pm'
|
|
|
|
|
|
|
|
parts = [
|
|
|
|
realm.uri,
|
|
|
|
'#narrow',
|
|
|
|
'pm-with',
|
|
|
|
pm_str,
|
|
|
|
'near',
|
|
|
|
message_id,
|
|
|
|
]
|
|
|
|
full_url = '/'.join(parts)
|
|
|
|
return full_url
|
2020-03-02 19:38:16 +01:00
|
|
|
|
|
|
|
def add_query_to_redirect_url(original_url: str, query: str) -> str:
|
2019-12-20 00:00:45 +01:00
|
|
|
# Using 'mark_sanitized' because user-controlled data after the '?' is
|
|
|
|
# not relevant for open redirects
|
|
|
|
return original_url + "?" + mark_sanitized(query)
|
2020-03-02 19:38:16 +01:00
|
|
|
|
|
|
|
def add_query_arg_to_redirect_url(original_url: str, query_arg: str) -> str:
|
|
|
|
assert '?' in original_url
|
2019-12-20 00:00:45 +01:00
|
|
|
# Using 'mark_sanitized' because user-controlled data after the '?' is
|
|
|
|
# not relevant for open redirects
|
|
|
|
return original_url + "&" + mark_sanitized(query_arg)
|