zulip/zerver/lib/thumbnail.py

80 lines
2.6 KiB
Python

# See https://zulip.readthedocs.io/en/latest/subsystems/thumbnailing.html
import base64
import os
import sys
import urllib
from urllib.parse import urljoin
from django.conf import settings
from django.utils.http import is_safe_url
from libthumbor import CryptoURL
ZULIP_PATH = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
sys.path.append(ZULIP_PATH)
from zerver.lib.camo import get_camo_url
from zthumbor.loaders.helpers import THUMBOR_EXTERNAL_TYPE, THUMBOR_LOCAL_FILE_TYPE, THUMBOR_S3_TYPE
def is_thumbor_enabled() -> bool:
return settings.THUMBOR_URL != ""
def user_uploads_or_external(url: str) -> bool:
return not is_safe_url(url, allowed_hosts=None) or url.startswith("/user_uploads/")
def get_source_type(url: str) -> str:
if not url.startswith("/user_uploads/"):
return THUMBOR_EXTERNAL_TYPE
local_uploads_dir = settings.LOCAL_UPLOADS_DIR
if local_uploads_dir:
return THUMBOR_LOCAL_FILE_TYPE
return THUMBOR_S3_TYPE
def generate_thumbnail_url(path: str, size: str = "0x0", is_camo_url: bool = False) -> str:
path = urljoin("/", path)
if not is_thumbor_enabled():
if is_safe_url(path, allowed_hosts=None):
return path
return get_camo_url(path)
if is_safe_url(path, allowed_hosts=None) and not path.startswith("/user_uploads/"):
return path
source_type = get_source_type(path)
safe_url = base64.urlsafe_b64encode(path.encode()).decode("utf-8")
image_url = f"{safe_url}/source_type/{source_type}"
width, height = map(int, size.split("x"))
crypto = CryptoURL(key=settings.THUMBOR_KEY)
smart_crop_enabled = True
apply_filters = ["no_upscale()"]
if is_camo_url:
smart_crop_enabled = False
apply_filters.append("quality(100)")
if size != "0x0":
apply_filters.append("sharpen(0.5,0.2,true)")
encrypted_url = crypto.generate(
width=width,
height=height,
smart=smart_crop_enabled,
filters=apply_filters,
image_url=image_url,
)
if settings.THUMBOR_URL == "http://127.0.0.1:9995":
# If THUMBOR_URL is the default then thumbor is hosted on same machine
# as the Zulip server and we should serve a relative URL.
# We add a /thumbor in front of the relative URL because we make
# use of a proxy pass to redirect request internally in Nginx to 9995
# port where thumbor is running.
thumbnail_url = "/thumbor" + encrypted_url
else:
thumbnail_url = urllib.parse.urljoin(settings.THUMBOR_URL, encrypted_url)
return thumbnail_url