[^/]+)",
*(webhook.url for webhook in WEBHOOK_INTEGRATIONS if not include_webhooks),
}
diff --git a/zerver/lib/thumbnail.py b/zerver/lib/thumbnail.py
index 02304f12a4..34401c893e 100644
--- a/zerver/lib/thumbnail.py
+++ b/zerver/lib/thumbnail.py
@@ -1,23 +1,14 @@
# 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 url_has_allowed_host_and_scheme
-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:
@@ -26,58 +17,9 @@ def user_uploads_or_external(url: str) -> bool:
)
-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 url_has_allowed_host_and_scheme(path, allowed_hosts=None):
- return path
- return get_camo_url(path)
-
- if url_has_allowed_host_and_scheme(path, allowed_hosts=None) and not path.startswith(
- "/user_uploads/"
- ):
+ if url_has_allowed_host_and_scheme(path, allowed_hosts=None):
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
+ return get_camo_url(path)
diff --git a/zerver/tests/test_camo.py b/zerver/tests/test_camo.py
deleted file mode 100644
index b9ac718fa4..0000000000
--- a/zerver/tests/test_camo.py
+++ /dev/null
@@ -1,28 +0,0 @@
-from zerver.lib.test_classes import ZulipTestCase
-
-
-class CamoURLTest(ZulipTestCase):
- def test_legacy_camo_url(self) -> None:
- # Test with valid hex and URL pair
- result = self.client_get(
- "/external_content/0f50f0bda30b6e65e9442c83ddb4076c74e75f96/687474703a2f2f7777772e72616e646f6d2e736974652f696d616765732f666f6f6261722e6a706567"
- )
- self.assertEqual(result.status_code, 302, result)
- self.assertIn(
- "/filters:no_upscale():quality(100)/aHR0cDovL3d3dy5yYW5kb20uc2l0ZS9pbWFnZXMvZm9vYmFyLmpwZWc=/source_type/external",
- result.url,
- )
-
- # Test with invalid hex and URL pair
- result = self.client_get(
- "/external_content/074c5e6c9c6d4ce97db1c740d79dc561cf7eb379/687474703a2f2f7777772e72616e646f6d2e736974652f696d616765732f666f6f6261722e6a706567"
- )
- self.assertEqual(result.status_code, 403, result)
- self.assert_in_response("Not a valid URL.", result)
-
- def test_with_thumbor_disabled(self) -> None:
- with self.settings(THUMBOR_SERVES_CAMO=False):
- result = self.client_get(
- "/external_content/074c5e6c9c6d4ce97db1c740d79dc561cf7eb379/687474703a2f2f7777772e72616e646f6d2e736974652f696d616765732f666f6f6261722e6a706567"
- )
- self.assertEqual(result.status_code, 404, result)
diff --git a/zerver/tests/test_thumbnail.py b/zerver/tests/test_thumbnail.py
index 8c467e7e8c..26bfab67dd 100644
--- a/zerver/tests/test_thumbnail.py
+++ b/zerver/tests/test_thumbnail.py
@@ -1,180 +1,12 @@
-import base64
from io import StringIO
import orjson
-from django.conf import settings
from zerver.lib.test_classes import ZulipTestCase
-from zerver.lib.test_helpers import (
- create_s3_buckets,
- get_test_image_file,
- override_settings,
- use_s3_backend,
-)
-from zerver.lib.upload import upload_backend, upload_emoji_image
-from zerver.lib.users import get_api_key
class ThumbnailTest(ZulipTestCase):
- @use_s3_backend
- def test_s3_source_type(self) -> None:
- def get_file_path_urlpart(uri: str, size: str = "") -> str:
- url_in_result = "smart/filters:no_upscale()%s/%s/source_type/s3"
- sharpen_filter = ""
- if size:
- url_in_result = f"/{size}/{url_in_result}"
- sharpen_filter = ":sharpen(0.5,0.2,true)"
- hex_uri = base64.urlsafe_b64encode(uri.encode()).decode("utf-8")
- return url_in_result % (sharpen_filter, hex_uri)
-
- create_s3_buckets(settings.S3_AUTH_UPLOADS_BUCKET, settings.S3_AVATAR_BUCKET)
-
- hamlet = self.example_user("hamlet")
- self.login_user(hamlet)
- fp = StringIO("zulip!")
- fp.name = "zulip.jpeg"
-
- result = self.client_post("/json/user_uploads", {"file": fp})
- self.assert_json_success(result)
- json = orjson.loads(result.content)
- self.assertIn("uri", json)
- uri = json["uri"]
- base = "/user_uploads/"
- self.assertEqual(base, uri[: len(base)])
-
- # Test full size image.
- result = self.client_get("/thumbnail", {"url": uri[1:], "size": "full"})
- self.assertEqual(result.status_code, 302, result)
- expected_part_url = get_file_path_urlpart(uri)
- self.assertIn(expected_part_url, result.url)
-
- # Test thumbnail size.
- result = self.client_get("/thumbnail", {"url": uri[1:], "size": "thumbnail"})
- self.assertEqual(result.status_code, 302, result)
- expected_part_url = get_file_path_urlpart(uri, "0x300")
- self.assertIn(expected_part_url, result.url)
-
- # Test custom emoji URLs in Zulip messages.
- user_profile = self.example_user("hamlet")
- file_name = "emoji.png"
-
- with get_test_image_file("img.png") as image_file:
- upload_emoji_image(image_file, file_name, user_profile)
- custom_emoji_url = upload_backend.get_emoji_url(file_name, user_profile.realm_id)
- emoji_url_base = "/user_avatars/"
- self.assertEqual(emoji_url_base, custom_emoji_url[: len(emoji_url_base)])
-
- # Test full size custom emoji image (for emoji link in messages case).
- result = self.client_get("/thumbnail", {"url": custom_emoji_url[1:], "size": "full"})
- self.assertEqual(result.status_code, 302, result)
- self.assertIn(custom_emoji_url, result.url)
-
- # Tests the /api/v1/thumbnail API endpoint with standard API auth
- self.logout()
- result = self.api_get(hamlet, "/thumbnail", {"url": uri[1:], "size": "full"})
- self.assertEqual(result.status_code, 302, result)
- expected_part_url = get_file_path_urlpart(uri)
- self.assertIn(expected_part_url, result.url)
-
- # Test with another user trying to access image using thumbor.
- self.login("iago")
- result = self.client_get("/thumbnail", {"url": uri[1:], "size": "full"})
- self.assertEqual(result.status_code, 403, result)
- self.assert_in_response("You are not authorized to view this file.", result)
-
- def test_external_source_type(self) -> None:
- def run_test_with_image_url(image_url: str) -> None:
- # Test full size image.
- self.login("hamlet")
- encoded_url = base64.urlsafe_b64encode(image_url.encode()).decode("utf-8")
- result = self.client_get("/thumbnail", {"url": image_url, "size": "full"})
- self.assertEqual(result.status_code, 302, result)
- expected_part_url = (
- "/smart/filters:no_upscale()/" + encoded_url + "/source_type/external"
- )
- self.assertIn(expected_part_url, result.url)
-
- # Test thumbnail size.
- result = self.client_get("/thumbnail", {"url": image_url, "size": "thumbnail"})
- self.assertEqual(result.status_code, 302, result)
- expected_part_url = (
- "/0x300/smart/filters:no_upscale():sharpen(0.5,0.2,true)/"
- + encoded_url
- + "/source_type/external"
- )
- self.assertIn(expected_part_url, result.url)
-
- # Test API endpoint with standard API authentication.
- self.logout()
- user_profile = self.example_user("hamlet")
- result = self.api_get(
- user_profile, "/thumbnail", {"url": image_url, "size": "thumbnail"}
- )
- self.assertEqual(result.status_code, 302, result)
- expected_part_url = (
- "/0x300/smart/filters:no_upscale():sharpen(0.5,0.2,true)/"
- + encoded_url
- + "/source_type/external"
- )
- self.assertIn(expected_part_url, result.url)
-
- # Test API endpoint with legacy API authentication.
- user_profile = self.example_user("hamlet")
- result = self.client_get(
- "/thumbnail",
- {"url": image_url, "size": "thumbnail", "api_key": get_api_key(user_profile)},
- )
- self.assertEqual(result.status_code, 302, result)
- expected_part_url = (
- "/0x300/smart/filters:no_upscale():sharpen(0.5,0.2,true)/"
- + encoded_url
- + "/source_type/external"
- )
- self.assertIn(expected_part_url, result.url)
-
- # Test a second logged-in user; they should also be able to access it
- user_profile = self.example_user("iago")
- result = self.client_get(
- "/thumbnail",
- {"url": image_url, "size": "thumbnail", "api_key": get_api_key(user_profile)},
- )
- self.assertEqual(result.status_code, 302, result)
- expected_part_url = (
- "/0x300/smart/filters:no_upscale():sharpen(0.5,0.2,true)/"
- + encoded_url
- + "/source_type/external"
- )
- self.assertIn(expected_part_url, result.url)
-
- # Test with another user trying to access image using thumbor.
- # File should be always accessible to user in case of external source
- self.login("iago")
- result = self.client_get("/thumbnail", {"url": image_url, "size": "full"})
- self.assertEqual(result.status_code, 302, result)
- expected_part_url = (
- "/smart/filters:no_upscale()/" + encoded_url + "/source_type/external"
- )
- self.assertIn(expected_part_url, result.url)
-
- image_url = "https://images.foobar.com/12345"
- run_test_with_image_url(image_url)
-
- image_url = "http://images.foobar.com/12345"
- run_test_with_image_url(image_url)
-
- image_url = "//images.foobar.com/12345"
- run_test_with_image_url(image_url)
-
- def test_local_file_type(self) -> None:
- def get_file_path_urlpart(uri: str, size: str = "") -> str:
- url_in_result = "smart/filters:no_upscale()%s/%s/source_type/local_file"
- sharpen_filter = ""
- if size:
- url_in_result = f"/{size}/{url_in_result}"
- sharpen_filter = ":sharpen(0.5,0.2,true)"
- hex_uri = base64.urlsafe_b64encode(uri.encode()).decode("utf-8")
- return url_in_result % (sharpen_filter, hex_uri)
-
+ def test_thumbnail_redirect(self) -> None:
self.login("hamlet")
fp = StringIO("zulip!")
fp.name = "zulip.jpeg"
@@ -187,187 +19,29 @@ class ThumbnailTest(ZulipTestCase):
base = "/user_uploads/"
self.assertEqual(base, uri[: len(base)])
- # Test full size image.
- # We remove the forward slash infront of the `/user_uploads/` to match
- # Markdown behaviour.
- result = self.client_get("/thumbnail", {"url": uri[1:], "size": "full"})
- self.assertEqual(result.status_code, 302, result)
- expected_part_url = get_file_path_urlpart(uri)
- self.assertIn(expected_part_url, result.url)
-
- # Test thumbnail size.
- result = self.client_get("/thumbnail", {"url": uri[1:], "size": "thumbnail"})
- self.assertEqual(result.status_code, 302, result)
- expected_part_url = get_file_path_urlpart(uri, "0x300")
- self.assertIn(expected_part_url, result.url)
-
- # Test with a Unicode filename.
- fp = StringIO("zulip!")
- fp.name = "μένει.jpg"
-
- result = self.client_post("/json/user_uploads", {"file": fp})
- self.assert_json_success(result)
- json = orjson.loads(result.content)
- self.assertIn("uri", json)
- uri = json["uri"]
-
- # We remove the forward slash infront of the `/user_uploads/` to match
- # Markdown behaviour.
- result = self.client_get("/thumbnail", {"url": uri[1:], "size": "full"})
- self.assertEqual(result.status_code, 302, result)
- expected_part_url = get_file_path_urlpart(uri)
- self.assertIn(expected_part_url, result.url)
-
- # Test custom emoji urls in Zulip messages.
- user_profile = self.example_user("hamlet")
- file_name = "emoji.png"
-
- with get_test_image_file("img.png") as image_file:
- upload_emoji_image(image_file, file_name, user_profile)
- custom_emoji_url = upload_backend.get_emoji_url(file_name, user_profile.realm_id)
- emoji_url_base = "/user_avatars/"
- self.assertEqual(emoji_url_base, custom_emoji_url[: len(emoji_url_base)])
-
- # Test full size custom emoji image (for emoji link in messages case).
- result = self.client_get("/thumbnail", {"url": custom_emoji_url[1:], "size": "full"})
- self.assertEqual(result.status_code, 302, result)
- self.assertIn(custom_emoji_url, result.url)
-
- # Tests the /api/v1/thumbnail API endpoint with HTTP basic auth.
- self.logout()
- user_profile = self.example_user("hamlet")
- result = self.api_get(user_profile, "/thumbnail", {"url": uri[1:], "size": "full"})
- self.assertEqual(result.status_code, 302, result)
- expected_part_url = get_file_path_urlpart(uri)
- self.assertIn(expected_part_url, result.url)
-
- # Tests the /api/v1/thumbnail API endpoint with ?api_key
- # auth.
- user_profile = self.example_user("hamlet")
- result = self.client_get(
- "/thumbnail", {"url": uri[1:], "size": "full", "api_key": get_api_key(user_profile)}
- )
- self.assertEqual(result.status_code, 302, result)
- expected_part_url = get_file_path_urlpart(uri)
- self.assertIn(expected_part_url, result.url)
-
- # Test with another user trying to access image using thumbor.
- self.login("iago")
- result = self.client_get("/thumbnail", {"url": uri[1:], "size": "full"})
- self.assertEqual(result.status_code, 403, result)
- self.assert_in_response("You are not authorized to view this file.", result)
-
- @override_settings(THUMBOR_URL="127.0.0.1:9995")
- def test_with_static_files(self) -> None:
- self.login("hamlet")
- uri = "/static/images/cute/turtle.png"
result = self.client_get("/thumbnail", {"url": uri[1:], "size": "full"})
self.assertEqual(result.status_code, 302, result)
self.assertEqual(uri, result.url)
- def test_with_thumbor_disabled(self) -> None:
- self.login("hamlet")
- fp = StringIO("zulip!")
- fp.name = "zulip.jpeg"
-
- result = self.client_post("/json/user_uploads", {"file": fp})
- self.assert_json_success(result)
- json = orjson.loads(result.content)
- self.assertIn("uri", json)
- uri = json["uri"]
- base = "/user_uploads/"
- self.assertEqual(base, uri[: len(base)])
-
- with self.settings(THUMBOR_URL=""):
- result = self.client_get("/thumbnail", {"url": uri[1:], "size": "full"})
- self.assertEqual(result.status_code, 302, result)
- self.assertEqual(uri, result.url)
+ self.login("iago")
+ result = self.client_get("/thumbnail", {"url": uri[1:], "size": "full"})
+ self.assertEqual(result.status_code, 403, result)
+ self.assert_in_response("You are not authorized to view this file.", result)
uri = "https://www.google.com/images/srpr/logo4w.png"
- with self.settings(THUMBOR_URL=""):
- result = self.client_get("/thumbnail", {"url": uri, "size": "full"})
+ result = self.client_get("/thumbnail", {"url": uri, "size": "full"})
self.assertEqual(result.status_code, 302, result)
base = "https://external-content.zulipcdn.net/external_content/56c362a24201593891955ff526b3b412c0f9fcd2/68747470733a2f2f7777772e676f6f676c652e636f6d2f696d616765732f737270722f6c6f676f34772e706e67"
self.assertEqual(base, result.url)
uri = "http://www.google.com/images/srpr/logo4w.png"
- with self.settings(THUMBOR_URL=""):
- result = self.client_get("/thumbnail", {"url": uri, "size": "full"})
+ result = self.client_get("/thumbnail", {"url": uri, "size": "full"})
self.assertEqual(result.status_code, 302, result)
base = "https://external-content.zulipcdn.net/external_content/7b6552b60c635e41e8f6daeb36d88afc4eabde79/687474703a2f2f7777772e676f6f676c652e636f6d2f696d616765732f737270722f6c6f676f34772e706e67"
self.assertEqual(base, result.url)
uri = "//www.google.com/images/srpr/logo4w.png"
- with self.settings(THUMBOR_URL=""):
- result = self.client_get("/thumbnail", {"url": uri, "size": "full"})
+ result = self.client_get("/thumbnail", {"url": uri, "size": "full"})
self.assertEqual(result.status_code, 302, result)
base = "https://external-content.zulipcdn.net/external_content/676530cf4b101d56f56cc4a37c6ef4d4fd9b0c03/2f2f7777772e676f6f676c652e636f6d2f696d616765732f737270722f6c6f676f34772e706e67"
self.assertEqual(base, result.url)
-
- def test_with_different_THUMBOR_URL(self) -> None:
- self.login("hamlet")
- fp = StringIO("zulip!")
- fp.name = "zulip.jpeg"
-
- result = self.client_post("/json/user_uploads", {"file": fp})
- self.assert_json_success(result)
- json = orjson.loads(result.content)
- self.assertIn("uri", json)
- uri = json["uri"]
- base = "/user_uploads/"
- self.assertEqual(base, uri[: len(base)])
-
- hex_uri = base64.urlsafe_b64encode(uri.encode()).decode("utf-8")
- with self.settings(THUMBOR_URL="http://test-thumborhost.com"):
- result = self.client_get("/thumbnail", {"url": uri[1:], "size": "full"})
- self.assertEqual(result.status_code, 302, result)
- base = "http://test-thumborhost.com/"
- self.assertEqual(base, result.url[: len(base)])
- expected_part_url = "/smart/filters:no_upscale()/" + hex_uri + "/source_type/local_file"
- self.assertIn(expected_part_url, result.url)
-
- def test_with_different_sizes(self) -> None:
- def get_file_path_urlpart(uri: str, size: str = "") -> str:
- url_in_result = "smart/filters:no_upscale()%s/%s/source_type/local_file"
- sharpen_filter = ""
- if size:
- url_in_result = f"/{size}/{url_in_result}"
- sharpen_filter = ":sharpen(0.5,0.2,true)"
- hex_uri = base64.urlsafe_b64encode(uri.encode()).decode("utf-8")
- return url_in_result % (sharpen_filter, hex_uri)
-
- self.login("hamlet")
- fp = StringIO("zulip!")
- fp.name = "zulip.jpeg"
-
- result = self.client_post("/json/user_uploads", {"file": fp})
- self.assert_json_success(result)
- json = orjson.loads(result.content)
- self.assertIn("uri", json)
- uri = json["uri"]
- base = "/user_uploads/"
- self.assertEqual(base, uri[: len(base)])
-
- # Test with size supplied as a query parameter.
- # size=thumbnail should return a 0x300 sized image.
- # size=full should return the original resolution image.
- result = self.client_get("/thumbnail", {"url": uri[1:], "size": "thumbnail"})
- self.assertEqual(result.status_code, 302, result)
- expected_part_url = get_file_path_urlpart(uri, "0x300")
- self.assertIn(expected_part_url, result.url)
-
- result = self.client_get("/thumbnail", {"url": uri[1:], "size": "full"})
- self.assertEqual(result.status_code, 302, result)
- expected_part_url = get_file_path_urlpart(uri)
- self.assertIn(expected_part_url, result.url)
-
- # Test with size supplied as a query parameter where size is anything
- # else than 'full' or 'thumbnail'. Result should be an error message.
- result = self.client_get("/thumbnail", {"url": uri[1:], "size": "480x360"})
- self.assertEqual(result.status_code, 403, result)
- self.assert_in_response("Invalid size.", result)
-
- # Test with no size param supplied. In this case as well we show an
- # error message.
- result = self.client_get("/thumbnail", {"url": uri[1:]})
- self.assertEqual(result.status_code, 400, "Missing 'size' argument")
diff --git a/zerver/views/camo.py b/zerver/views/development/camo.py
similarity index 65%
rename from zerver/views/camo.py
rename to zerver/views/development/camo.py
index 9739a3da4f..c1bc7a5b38 100644
--- a/zerver/views/camo.py
+++ b/zerver/views/development/camo.py
@@ -1,18 +1,13 @@
-from django.conf import settings
-from django.http import HttpRequest, HttpResponse, HttpResponseForbidden, HttpResponseNotFound
+from django.http import HttpRequest, HttpResponse, HttpResponseForbidden
from django.shortcuts import redirect
-from django.utils.translation import gettext as _
from zerver.lib.camo import is_camo_url_valid
from zerver.lib.thumbnail import generate_thumbnail_url
def handle_camo_url(request: HttpRequest, digest: str, received_url: str) -> HttpResponse:
- if not settings.THUMBOR_SERVES_CAMO:
- return HttpResponseNotFound()
-
original_url = bytes.fromhex(received_url).decode()
if is_camo_url_valid(digest, original_url):
return redirect(generate_thumbnail_url(original_url, is_camo_url=True))
else:
- return HttpResponseForbidden(_("Not a valid URL.
"))
+ return HttpResponseForbidden("Not a valid URL.
")
diff --git a/zerver/views/thumbnail.py b/zerver/views/thumbnail.py
index bb9b474ddd..8ad30bc845 100644
--- a/zerver/views/thumbnail.py
+++ b/zerver/views/thumbnail.py
@@ -31,14 +31,5 @@ def backend_serve_thumbnail(
if not validate_thumbnail_request(user_profile, url):
return HttpResponseForbidden(_("You are not authorized to view this file.
"))
- size = None
- if size_requested == "thumbnail":
- size = "0x300"
- elif size_requested == "full":
- size = "0x0"
-
- if size is None:
- return HttpResponseForbidden(_("Invalid size.
"))
-
- thumbnail_url = generate_thumbnail_url(url, size)
+ thumbnail_url = generate_thumbnail_url(url)
return redirect(thumbnail_url)
diff --git a/zproject/computed_settings.py b/zproject/computed_settings.py
index d860911cb0..96164546f0 100644
--- a/zproject/computed_settings.py
+++ b/zproject/computed_settings.py
@@ -1160,8 +1160,6 @@ CROSS_REALM_BOT_EMAILS = {
"emailgateway@zulip.com",
}
-THUMBOR_KEY = get_secret("thumbor_key")
-
TWO_FACTOR_PATCH_ADMIN = False
# Allow the environment to override the default DSN
diff --git a/zproject/default_settings.py b/zproject/default_settings.py
index 3e7eeb3091..c78a8181c1 100644
--- a/zproject/default_settings.py
+++ b/zproject/default_settings.py
@@ -158,8 +158,6 @@ REDIS_PORT = 6379
REMOTE_POSTGRES_HOST = ""
REMOTE_POSTGRES_PORT = ""
REMOTE_POSTGRES_SSLMODE = ""
-THUMBOR_URL = ""
-THUMBOR_SERVES_CAMO = False
THUMBNAIL_IMAGES = False
SENDFILE_BACKEND: Optional[str] = None
diff --git a/zproject/dev_settings.py b/zproject/dev_settings.py
index 5683fc3e3b..fb489030d8 100644
--- a/zproject/dev_settings.py
+++ b/zproject/dev_settings.py
@@ -157,7 +157,6 @@ if FAKE_LDAP_MODE:
}
AUTHENTICATION_BACKENDS += ("zproject.backends.ZulipLDAPAuthBackend",)
-THUMBOR_URL = "http://127.0.0.1:9995"
THUMBNAIL_IMAGES = True
SEARCH_PILLS_ENABLED = bool(os.getenv("SEARCH_PILLS_ENABLED", False))
diff --git a/zproject/dev_urls.py b/zproject/dev_urls.py
index db208190e1..8aec120e15 100644
--- a/zproject/dev_urls.py
+++ b/zproject/dev_urls.py
@@ -11,6 +11,7 @@ from django.views.static import serve
from zerver.views.auth import config_error, login_page
from zerver.views.development.cache import remove_caches
+from zerver.views.development.camo import handle_camo_url
from zerver.views.development.dev_login import (
api_dev_fetch_api_key,
api_dev_list_users,
@@ -86,6 +87,8 @@ urls = [
path("config-error/remoteuser/", config_error),
# Special endpoint to remove all the server-side caches.
path("flush_caches", remove_caches),
+ # Redirect camo URLs for development
+ path("external_content//", handle_camo_url),
]
v1_api_mobile_patterns = [
diff --git a/zproject/prod_settings_template.py b/zproject/prod_settings_template.py
index 91db5f4708..3d4398d94d 100644
--- a/zproject/prod_settings_template.py
+++ b/zproject/prod_settings_template.py
@@ -523,18 +523,6 @@ SOCIAL_AUTH_SAML_SUPPORT_CONTACT = {
## can also be disabled in a realm's organization settings.
# INLINE_URL_EMBED_PREVIEW = True
-## By default, Zulip connects to the thumbor (the thumbnailing software
-## we use) service running locally on the machine. If you're running
-## thumbor on a different server, you can configure that by setting
-## THUMBOR_URL here. Setting THUMBOR_URL='' will let Zulip server know that
-## thumbor is not running or configured.
-# THUMBOR_URL = 'http://127.0.0.1:9995'
-##
-## This setting controls whether images shown in Zulip's inline image
-## previews should be thumbnailed by thumbor, which saves bandwidth but
-## can modify the image's appearance.
-# THUMBNAIL_IMAGES = True
-
########
## Twitter previews.
##
diff --git a/zproject/test_extra_settings.py b/zproject/test_extra_settings.py
index 34b43ccd3b..fe76a6ef09 100644
--- a/zproject/test_extra_settings.py
+++ b/zproject/test_extra_settings.py
@@ -204,9 +204,7 @@ BIG_BLUE_BUTTON_URL = "https://bbb.example.com/bigbluebutton/"
TWO_FACTOR_AUTHENTICATION_ENABLED = False
PUSH_NOTIFICATION_BOUNCER_URL = None
-THUMBOR_URL = "http://127.0.0.1:9995"
THUMBNAIL_IMAGES = True
-THUMBOR_SERVES_CAMO = True
# Logging the emails while running the tests adds them
# to /emails page.
diff --git a/zproject/urls.py b/zproject/urls.py
index b40057a96a..a2064d337e 100644
--- a/zproject/urls.py
+++ b/zproject/urls.py
@@ -36,7 +36,6 @@ from zerver.views.auth import (
start_social_login,
start_social_signup,
)
-from zerver.views.camo import handle_camo_url
from zerver.views.compatibility import check_global_compatibility
from zerver.views.custom_profile_fields import (
create_realm_custom_profile_field,
@@ -666,8 +665,8 @@ urls += [
"user_uploads//",
GET=(serve_file_backend, {"override_api_url_scheme"}),
),
- # This endpoint serves thumbnailed versions of images using thumbor;
- # it requires an exception for the same reason.
+ # This endpoint redirects to camo; it requires an exception for the
+ # same reason.
rest_path("thumbnail", GET=(backend_serve_thumbnail, {"override_api_url_scheme"})),
# Avatars have the same constraint because their URLs are included
# in API data structures used by both the mobile and web clients.
@@ -683,14 +682,6 @@ urls += [
path("report/csp_violations", report_csp_violations),
]
-# This URL serves as a way to provide backward compatibility to messages
-# rendered at the time Zulip used camo for doing http -> https conversion for
-# such links with images previews. Now thumbor can be used for serving such
-# images.
-urls += [
- path("external_content//", handle_camo_url),
-]
-
# Incoming webhook URLs
# We don't create URLs for particular Git integrations here
# because of generic one below
diff --git a/zthumbor/__init__.py b/zthumbor/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/zthumbor/loaders/__init__.py b/zthumbor/loaders/__init__.py
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/zthumbor/loaders/helpers.py b/zthumbor/loaders/helpers.py
deleted file mode 100644
index a7c38ea953..0000000000
--- a/zthumbor/loaders/helpers.py
+++ /dev/null
@@ -1,13 +0,0 @@
-import re
-from typing import Tuple
-
-THUMBOR_EXTERNAL_TYPE = "external"
-THUMBOR_S3_TYPE = "s3"
-THUMBOR_LOCAL_FILE_TYPE = "local_file"
-
-
-def separate_url_and_source_type(url: str) -> Tuple[str, str]:
- THUMBNAIL_URL_PATT = re.compile("^(?P.+)/source_type/(?P.+)")
- matches = THUMBNAIL_URL_PATT.match(url)
- assert matches is not None
- return (matches.group("source_type"), matches.group("actual_url"))
diff --git a/zthumbor/loaders/zloader.py b/zthumbor/loaders/zloader.py
deleted file mode 100644
index 8cbc8bcc87..0000000000
--- a/zthumbor/loaders/zloader.py
+++ /dev/null
@@ -1,50 +0,0 @@
-# See https://zulip.readthedocs.io/en/latest/subsystems/thumbnailing.html
-
-import base64
-import logging
-import urllib.parse
-
-from tc_aws.loaders import s3_loader
-from thumbor.context import Context
-from thumbor.loaders import LoaderResult, file_loader, https_loader
-
-from .helpers import (
- THUMBOR_EXTERNAL_TYPE,
- THUMBOR_LOCAL_FILE_TYPE,
- THUMBOR_S3_TYPE,
- separate_url_and_source_type,
-)
-
-
-def get_not_found_result() -> LoaderResult:
- result = LoaderResult()
- result.error = LoaderResult.ERROR_NOT_FOUND
- result.successful = False
- return result
-
-
-async def load(context: Context, url: str) -> LoaderResult:
- source_type, encoded_url = separate_url_and_source_type(url)
- actual_url = base64.urlsafe_b64decode(urllib.parse.unquote(encoded_url)).decode("utf-8")
-
- if source_type == THUMBOR_S3_TYPE:
- if actual_url.startswith("/user_uploads/"):
- actual_url = actual_url[len("/user_uploads/") :]
- else:
- raise AssertionError("Unexpected s3 file.")
-
- return await s3_loader.load(context, actual_url)
- elif source_type == THUMBOR_LOCAL_FILE_TYPE:
- if actual_url.startswith("/user_uploads/"):
- actual_url = actual_url[len("/user_uploads/") :]
- local_file_path_prefix = "files/"
- else:
- raise AssertionError("Unexpected local file.")
-
- patched_local_url = local_file_path_prefix + actual_url
- return await file_loader.load(context, patched_local_url)
- elif source_type == THUMBOR_EXTERNAL_TYPE:
- return await https_loader.load(context, actual_url)
- else:
- logging.warning("INVALID SOURCE TYPE: " + source_type)
- return get_not_found_result()
diff --git a/zthumbor/thumbor_settings.py b/zthumbor/thumbor_settings.py
deleted file mode 100644
index 22d10c68c0..0000000000
--- a/zthumbor/thumbor_settings.py
+++ /dev/null
@@ -1,700 +0,0 @@
-import configparser
-import os
-import sys
-
-ZULIP_PATH = os.getcwd() # Thumbor doesn’t set __file__ when loading this
-sys.path.append(ZULIP_PATH)
-
-from zproject.config import get_secret
-
-os.environ["AWS_ACCESS_KEY_ID"] = get_secret("s3_key", "")
-os.environ["AWS_SECRET_ACCESS_KEY"] = get_secret("s3_secret_key", "")
-
-config_file = configparser.RawConfigParser()
-config_file.read("/etc/zulip/zulip.conf")
-
-# Whether this instance of Zulip is running in a production environment.
-PRODUCTION = config_file.has_option("machine", "deploy_type")
-if PRODUCTION:
- try:
- from zproject.prod_settings import LOCAL_UPLOADS_DIR
- except ImportError:
- LOCAL_UPLOADS_DIR = None
-else:
- from zproject.dev_settings import LOCAL_UPLOADS_DIR
-
-IS_LOCAL_STORAGE = bool(LOCAL_UPLOADS_DIR)
-
-################################# File Loader ##################################
-
-## The root path where the File Loader will try to find images
-if IS_LOCAL_STORAGE:
- if os.path.isabs(LOCAL_UPLOADS_DIR):
- FILE_LOADER_ROOT_PATH = LOCAL_UPLOADS_DIR
- else:
- FILE_LOADER_ROOT_PATH = os.path.join(ZULIP_PATH, LOCAL_UPLOADS_DIR)
-
-################################### Logging ####################################
-
-## Logging configuration as json
-## Defaults to: None
-# THUMBOR_LOG_CONFIG = None
-
-## Log Format to be used by thumbor when writing log messages.
-## Defaults to: '%(asctime)s %(name)s:%(levelname)s %(message)s'
-# THUMBOR_LOG_FORMAT = '%(asctime)s %(name)s:%(levelname)s %(message)s'
-
-## Date Format to be used by thumbor when writing log messages.
-## Defaults to: '%Y-%m-%d %H:%M:%S'
-# THUMBOR_LOG_DATE_FORMAT = '%Y-%m-%d %H:%M:%S'
-
-################################################################################
-
-
-################################### Imaging ####################################
-
-## Max width in pixels for images read or generated by thumbor
-## Defaults to: 0
-# MAX_WIDTH = 0
-
-## Max height in pixels for images read or generated by thumbor
-## Defaults to: 0
-# MAX_HEIGHT = 0
-
-## Max pixel count for images read by thumbor
-## Defaults to: 75000000.0
-# MAX_PIXELS = 75000000.0
-
-## Min width in pixels for images read or generated by thumbor
-## Defaults to: 1
-# MIN_WIDTH = 1
-
-## Min width in pixels for images read or generated by thumbor
-## Defaults to: 1
-# MIN_HEIGHT = 1
-
-## Allowed domains for the http loader to download. These are regular
-## expressions.
-## Defaults to: # [
-# ]
-
-# ALLOWED_SOURCES = # [
-# ]
-
-
-## Quality index used for generated JPEG images
-## Defaults to: 80
-# QUALITY = 80
-
-## Exports JPEG images with the `progressive` flag set.
-## Defaults to: True
-# PROGRESSIVE_JPEG = True
-
-## Specify subsampling behavior for Pillow (see `subsampling` in
-## http://pillow.readthedocs.org/en/latest/handbook/image-file-
-## formats.html#jpeg).Be careful to use int for 0,1,2 and string for "4:4:4"
-## notation. Will ignore `quality`. Using `keep` will copy the original file's
-## subsampling.
-## Defaults to: None
-# PILLOW_JPEG_SUBSAMPLING = None
-
-## Specify quantization tables for Pillow (see `qtables` in
-## http://pillow.readthedocs.org/en/latest/handbook/image-file-
-## formats.html#jpeg). Will ignore `quality`. Using `keep` will copy the
-## original file's qtables.
-## Defaults to: None
-# PILLOW_JPEG_QTABLES = None
-
-## Quality index used for generated WebP images. If not set (None) the same level
-## of JPEG quality will be used.
-## Defaults to: None
-# WEBP_QUALITY = None
-
-## Specifies whether WebP format should be used automatically if the request
-## accepts it (via Accept header)
-## Defaults to: False
-# AUTO_WEBP = False
-
-## Specify the ratio between 1in and 1px for SVG images. This is only used
-## whenrasterizing SVG images having their size units in cm or inches.
-## Defaults to: 150
-# SVG_DPI = 150
-
-## Max AGE sent as a header for the image served by thumbor in seconds
-## Defaults to: 86400
-# MAX_AGE = 86400
-
-## Indicates the Max AGE header in seconds for temporary images (images with
-## failed smart detection)
-## Defaults to: 0
-# MAX_AGE_TEMP_IMAGE = 0
-
-## Indicates whether thumbor should rotate images that have an Orientation EXIF
-## header
-## Defaults to: False
-# RESPECT_ORIENTATION = False
-
-## Ignore errors during smart detections and return image as a temp image (not
-## saved in result storage and with MAX_AGE_TEMP_IMAGE age)
-## Defaults to: False
-# IGNORE_SMART_ERRORS = False
-
-## Sends If-Modified-Since & Last-Modified headers; requires support from result
-## storage
-## Defaults to: False
-# SEND_IF_MODIFIED_LAST_MODIFIED_HEADERS = False
-
-## Preserves exif information in generated images. Increases image size in
-## kbytes, use with caution.
-## Defaults to: False
-# PRESERVE_EXIF_INFO = False
-
-## Indicates whether thumbor should enable the EXPERIMENTAL support for animated
-## gifs.
-## Defaults to: True
-# ALLOW_ANIMATED_GIFS = True
-
-## Indicates whether thumbor should use gifsicle engine. Please note that smart
-## cropping and filters are not supported for gifs using gifsicle (but won't
-## give an error).
-## Defaults to: False
-USE_GIFSICLE_ENGINE = True
-
-## Indicates whether thumbor should enable blacklist functionality to prevent
-## processing certain images.
-## Defaults to: False
-# USE_BLACKLIST = False
-
-## Size of the thread pool used for image transformations. The default value is
-## 0 (don't use a threadpoool. Increase this if you are seeing your IOLoop
-## getting blocked (often indicated by your upstream HTTP requests timing out)
-## Defaults to: 0
-# ENGINE_THREADPOOL_SIZE = 0
-
-################################################################################
-
-
-################################ Extensibility #################################
-
-## The metrics backend thumbor should use to measure internal actions. This must
-## be the full name of a python module (python must be able to import it)
-## Defaults to: 'thumbor.metrics.logger_metrics'
-# METRICS = 'thumbor.metrics.logger_metrics'
-
-## The loader thumbor should use to load the original image. This must be the
-## full name of a python module (python must be able to import it)
-## Defaults to: 'thumbor.loaders.http_loader'
-LOADER = "zthumbor.loaders.zloader"
-
-## The file storage thumbor should use to store original images. This must be the
-## full name of a python module (python must be able to import it)
-## Defaults to: 'thumbor.storages.file_storage'
-if IS_LOCAL_STORAGE:
- STORAGE = "thumbor.storages.file_storage"
-else:
- STORAGE = "tc_aws.storages.s3_storage"
-
-## The result storage thumbor should use to store generated images. This must be
-## the full name of a python module (python must be able to import it)
-## Defaults to: None
-if IS_LOCAL_STORAGE:
- RESULT_STORAGE = "thumbor.result_storages.file_storage"
-else:
- RESULT_STORAGE = "tc_aws.result_storages.s3_storage"
-
-## The imaging engine thumbor should use to perform image operations. This must
-## be the full name of a python module (python must be able to import it)
-## Defaults to: 'thumbor.engines.pil'
-# ENGINE = 'thumbor.engines.pil'
-
-## The gif engine thumbor should use to perform image operations. This must be
-## the full name of a python module (python must be able to import it)
-## Defaults to: 'thumbor.engines.gif'
-# GIF_ENGINE = 'thumbor.engines.gif'
-
-## The url signer thumbor should use to verify url signatures.This must be the
-## full name of a python module (python must be able to import it)
-## Defaults to: 'thumbor.url_signers.base64_hmac_sha1'
-# URL_SIGNER = 'thumbor.url_signers.base64_hmac_sha1'
-
-################################################################################
-
-
-################################### Security ###################################
-
-## The security key thumbor uses to sign image URLs
-## Defaults to: 'MY_SECURE_KEY'
-SECURITY_KEY = get_secret("thumbor_key")
-
-## Indicates if the /unsafe URL should be available
-## Defaults to: True
-ALLOW_UNSAFE_URL = False
-
-## Indicates if encrypted (old style) URLs should be allowed
-## Defaults to: True
-ALLOW_OLD_URLS = False
-
-################################################################################
-
-
-##################################### HTTP #####################################
-
-## Enables automatically generated etags
-## Defaults to: True
-# ENABLE_ETAGS = True
-
-################################################################################
-
-
-################################### Storage ####################################
-
-## Set maximum id length for images when stored
-## Defaults to: 32
-# MAX_ID_LENGTH = 32
-
-################################################################################
-
-
-################################### Metrics ####################################
-
-## Host to send statsd instrumentation to
-## Defaults to: None
-# STATSD_HOST = None
-
-## Port to send statsd instrumentation to
-## Defaults to: 8125
-# STATSD_PORT = 8125
-
-## Prefix for statsd
-## Defaults to: None
-# STATSD_PREFIX = None
-
-################################################################################
-
-################################# HTTP Loader ##################################
-
-## The maximum number of seconds libcurl can take to connect to an image being
-## loaded
-## Defaults to: 5
-# HTTP_LOADER_CONNECT_TIMEOUT = 5
-
-## The maximum number of seconds libcurl can take to download an image
-## Defaults to: 20
-# HTTP_LOADER_REQUEST_TIMEOUT = 20
-
-## Indicates whether libcurl should follow redirects when downloading an image
-## Defaults to: True
-# HTTP_LOADER_FOLLOW_REDIRECTS = True
-
-## Indicates the number of redirects libcurl should follow when downloading an
-## image
-## Defaults to: 5
-# HTTP_LOADER_MAX_REDIRECTS = 5
-
-## The maximum number of simultaneous HTTP connections the loader can make before
-## queuing
-## Defaults to: 10
-# HTTP_LOADER_MAX_CLIENTS = 10
-
-## Indicates whether thumbor should forward the user agent of the requesting user
-## Defaults to: False
-# HTTP_LOADER_FORWARD_USER_AGENT = False
-
-## Default user agent for thumbor http loader requests
-## Defaults to: 'Thumbor/6.1.5'
-# HTTP_LOADER_DEFAULT_USER_AGENT = 'Thumbor/6.1.5'
-
-
-if config_file.has_option("http_proxy", "host") and config_file.has_option("http_proxy", "port"):
- ## The proxy host needed to load images through
- ## Defaults to: None
- HTTP_LOADER_PROXY_HOST = config_file.get("http_proxy", "host")
-
- ## The proxy port for the proxy host
- ## Defaults to: None
- HTTP_LOADER_PROXY_PORT = int(config_file.get("http_proxy", "port"))
-
-## The proxy username for the proxy host
-## Defaults to: None
-# HTTP_LOADER_PROXY_USERNAME = None
-
-## The proxy password for the proxy host
-## Defaults to: None
-# HTTP_LOADER_PROXY_PASSWORD = None
-
-## The filename of CA certificates in PEM format
-## Defaults to: None
-# HTTP_LOADER_CA_CERTS = None
-
-## The filename for client SSL key
-## Defaults to: None
-# HTTP_LOADER_CLIENT_KEY = None
-
-## The filename for client SSL certificate
-## Defaults to: None
-# HTTP_LOADER_CLIENT_CERT = None
-
-## If the CurlAsyncHTTPClient should be used
-## Defaults to: False
-# HTTP_LOADER_CURL_ASYNC_HTTP_CLIENT = False
-
-################################################################################
-
-
-################################# File Storage #################################
-
-## Expiration in seconds for the images in the File Storage. Defaults to one
-## month
-## Defaults to: 2592000
-# STORAGE_EXPIRATION_SECONDS = 2592000
-
-## Indicates whether thumbor should store the signing key for each image in the
-## file storage. This allows the key to be changed and old images to still be
-## properly found
-## Defaults to: False
-# STORES_CRYPTO_KEY_FOR_EACH_IMAGE = False
-
-## The root path where the File Storage will try to find images
-## Defaults to: '/tmp/thumbor/storage'
-# FILE_STORAGE_ROOT_PATH = '/tmp/thumbor/storage'
-
-################################################################################
-
-
-#################################### Upload ####################################
-
-## Max size in Kb for images uploaded to thumbor
-## Aliases: MAX_SIZE
-## Defaults to: 0
-# UPLOAD_MAX_SIZE = 0
-
-## Indicates whether thumbor should enable File uploads
-## Aliases: ENABLE_ORIGINAL_PHOTO_UPLOAD
-## Defaults to: False
-# UPLOAD_ENABLED = False
-
-## The type of storage to store uploaded images with
-## Aliases: ORIGINAL_PHOTO_STORAGE
-## Defaults to: 'thumbor.storages.file_storage'
-# UPLOAD_PHOTO_STORAGE = 'thumbor.storages.file_storage'
-
-## Indicates whether image deletion should be allowed
-## Aliases: ALLOW_ORIGINAL_PHOTO_DELETION
-## Defaults to: False
-# UPLOAD_DELETE_ALLOWED = False
-
-## Indicates whether image overwrite should be allowed
-## Aliases: ALLOW_ORIGINAL_PHOTO_PUTTING
-## Defaults to: False
-# UPLOAD_PUT_ALLOWED = False
-
-## Default filename for image uploaded
-## Defaults to: 'image'
-# UPLOAD_DEFAULT_FILENAME = 'image'
-
-################################################################################
-
-
-############################### Memcache Storage ###############################
-
-## List of Memcache storage server hosts
-## Defaults to: # [
-# 'localhost:11211',
-# ]
-
-# MEMCACHE_STORAGE_SERVERS = # [
-# 'localhost:11211',
-# ]
-
-
-################################################################################
-
-
-################################ Mixed Storage #################################
-
-## Mixed Storage file storage. This must be the full name of a python module
-## (python must be able to import it)
-## Defaults to: 'thumbor.storages.no_storage'
-# MIXED_STORAGE_FILE_STORAGE = 'thumbor.storages.no_storage'
-
-## Mixed Storage signing key storage. This must be the full name of a python
-## module (python must be able to import it)
-## Defaults to: 'thumbor.storages.no_storage'
-# MIXED_STORAGE_CRYPTO_STORAGE = 'thumbor.storages.no_storage'
-
-## Mixed Storage detector information storage. This must be the full name of a
-## python module (python must be able to import it)
-## Defaults to: 'thumbor.storages.no_storage'
-# MIXED_STORAGE_DETECTOR_STORAGE = 'thumbor.storages.no_storage'
-
-################################################################################
-
-
-##################################### Meta #####################################
-
-## The callback function name that should be used by the META route for JSONP
-## access
-## Defaults to: None
-# META_CALLBACK_NAME = None
-
-################################################################################
-
-
-################################## Detection ###################################
-
-## List of detectors that thumbor should use to find faces and/or features. All
-## of them must be full names of python modules (python must be able to import
-## it)
-## Defaults to: # [
-# ]
-
-# DETECTORS = # [
-# ]
-
-
-## The cascade file that opencv will use to detect faces.
-## Defaults to: 'haarcascade_frontalface_alt.xml'
-# FACE_DETECTOR_CASCADE_FILE = 'haarcascade_frontalface_alt.xml'
-
-## The cascade file that opencv will use to detect glasses.
-## Defaults to: 'haarcascade_eye_tree_eyeglasses.xml'
-# GLASSES_DETECTOR_CASCADE_FILE = 'haarcascade_eye_tree_eyeglasses.xml'
-
-## The cascade file that opencv will use to detect profile faces.
-## Defaults to: 'haarcascade_profileface.xml'
-# PROFILE_DETECTOR_CASCADE_FILE = 'haarcascade_profileface.xml'
-
-################################################################################
-
-
-################################## Optimizers ##################################
-
-## List of optimizers that thumbor will use to optimize images
-## Defaults to: # [
-# ]
-
-# OPTIMIZERS = # [
-# ]
-
-
-## Path for the jpegtran binary
-## Defaults to: '/usr/bin/jpegtran'
-# JPEGTRAN_PATH = '/usr/bin/jpegtran'
-
-## Path for the ffmpeg binary used to generate gifv(h.264)
-## Defaults to: '/usr/local/bin/ffmpeg'
-# FFMPEG_PATH = '/usr/local/bin/ffmpeg'
-
-################################################################################
-
-
-################################### Filters ####################################
-
-## List of filters that thumbor will allow to be used in generated images. All of
-## them must be full names of python modules (python must be able to import
-## it)
-## Defaults to: # [
-# 'thumbor.filters.brightness',
-# 'thumbor.filters.colorize',
-# 'thumbor.filters.contrast',
-# 'thumbor.filters.rgb',
-# 'thumbor.filters.round_corner',
-# 'thumbor.filters.quality',
-# 'thumbor.filters.noise',
-# 'thumbor.filters.watermark',
-# 'thumbor.filters.equalize',
-# 'thumbor.filters.fill',
-# 'thumbor.filters.sharpen',
-# 'thumbor.filters.strip_icc',
-# 'thumbor.filters.frame',
-# 'thumbor.filters.grayscale',
-# 'thumbor.filters.rotate',
-# 'thumbor.filters.format',
-# 'thumbor.filters.max_bytes',
-# 'thumbor.filters.convolution',
-# 'thumbor.filters.blur',
-# 'thumbor.filters.extract_focal',
-# 'thumbor.filters.focal',
-# 'thumbor.filters.no_upscale',
-# 'thumbor.filters.saturation',
-# 'thumbor.filters.max_age',
-# 'thumbor.filters.curve',
-# ]
-
-# FILTERS = # [
-# 'thumbor.filters.brightness',
-# 'thumbor.filters.colorize',
-# 'thumbor.filters.contrast',
-# 'thumbor.filters.rgb',
-# 'thumbor.filters.round_corner',
-# 'thumbor.filters.quality',
-# 'thumbor.filters.noise',
-# 'thumbor.filters.watermark',
-# 'thumbor.filters.equalize',
-# 'thumbor.filters.fill',
-# 'thumbor.filters.sharpen',
-# 'thumbor.filters.strip_icc',
-# 'thumbor.filters.frame',
-# 'thumbor.filters.grayscale',
-# 'thumbor.filters.rotate',
-# 'thumbor.filters.format',
-# 'thumbor.filters.max_bytes',
-# 'thumbor.filters.convolution',
-# 'thumbor.filters.blur',
-# 'thumbor.filters.extract_focal',
-# 'thumbor.filters.focal',
-# 'thumbor.filters.no_upscale',
-# 'thumbor.filters.saturation',
-# 'thumbor.filters.max_age',
-# 'thumbor.filters.curve',
-# ]
-
-
-################################################################################
-
-
-################################ Result Storage ################################
-
-## Expiration in seconds of generated images in the result storage
-## Defaults to: 0
-# RESULT_STORAGE_EXPIRATION_SECONDS = 0
-
-## Path where the Result storage will store generated images
-## Defaults to: '/tmp/thumbor/result_storage'
-if IS_LOCAL_STORAGE:
- RESULT_STORAGE_FILE_STORAGE_ROOT_PATH = os.path.join(FILE_LOADER_ROOT_PATH, "thumbnails")
-
-## Indicates whether unsafe requests should also be stored in the Result Storage
-## Defaults to: False
-RESULT_STORAGE_STORES_UNSAFE = True
-
-################################################################################
-
-
-############################ Queued Redis Detector #############################
-
-## Server host for the queued redis detector
-## Defaults to: 'localhost'
-# REDIS_QUEUE_SERVER_HOST = 'localhost'
-
-## Server port for the queued redis detector
-## Defaults to: 6379
-# REDIS_QUEUE_SERVER_PORT = 6379
-
-## Server database index for the queued redis detector
-## Defaults to: 0
-# REDIS_QUEUE_SERVER_DB = 0
-
-## Server password for the queued redis detector
-## Defaults to: None
-# REDIS_QUEUE_SERVER_PASSWORD = None
-
-################################################################################
-
-
-############################# Queued SQS Detector ##############################
-
-## AWS key id
-## Defaults to: None
-# SQS_QUEUE_KEY_ID = None
-
-## AWS key secret
-## Defaults to: None
-# SQS_QUEUE_KEY_SECRET = None
-
-## AWS SQS region
-## Defaults to: 'us-east-1'
-# SQS_QUEUE_REGION = 'us-east-1'
-
-################################################################################
-
-
-#################################### Errors ####################################
-
-## This configuration indicates whether thumbor should use a custom error
-## handler.
-## Defaults to: False
-# USE_CUSTOM_ERROR_HANDLING = False
-
-## Error reporting module. Needs to contain a class called ErrorHandler with a
-## handle_error(context, handler, exception) method.
-## Defaults to: 'thumbor.error_handlers.sentry'
-# ERROR_HANDLER_MODULE = 'thumbor.error_handlers.sentry'
-
-## File of error log as json
-## Defaults to: None
-# ERROR_FILE_LOGGER = None
-
-## File of error log name is parametrized with context attribute
-## Defaults to: False
-# ERROR_FILE_NAME_USE_CONTEXT = False
-
-################################################################################
-
-
-############################### Errors - Sentry ################################
-
-## Sentry thumbor project dsn. i.e.: http://5a63d58ae7b94f1dab3dee740b301d6a:73ee
-## a45d3e8649239a973087e8f21f98@localhost:9000/2
-## Defaults to: ''
-# SENTRY_DSN_URL = ''
-
-################################################################################
-
-
-################################### General ####################################
-
-## Custom app class to override ThumborServiceApp. This config value is
-## overridden by the -a command-line parameter.
-## Defaults to: 'thumbor.app.ThumborServiceApp'
-# APP_CLASS = 'thumbor.app.ThumborServiceApp'
-
-################################################################################
-
-
-################################### AWS S3 settings ############################
-
-if not IS_LOCAL_STORAGE:
- from zproject.configured_settings import S3_AUTH_UPLOADS_BUCKET, S3_ENDPOINT_URL, S3_REGION
-
- TC_AWS_REGION = S3_REGION # AWS Region
- TC_AWS_ENDPOINT = S3_ENDPOINT_URL
-
- TC_AWS_STORAGE_BUCKET = S3_AUTH_UPLOADS_BUCKET # S3 bucket for Storage
- TC_AWS_STORAGE_ROOT_PATH = "thumbnails" # S3 path prefix for Storage bucket
-
- TC_AWS_LOADER_BUCKET = S3_AUTH_UPLOADS_BUCKET # S3 bucket for loader
- TC_AWS_LOADER_ROOT_PATH = "" # S3 path prefix for Loader bucket
-
- TC_AWS_RESULT_STORAGE_BUCKET = S3_AUTH_UPLOADS_BUCKET # S3 bucket for result Storage
- TC_AWS_RESULT_STORAGE_ROOT_PATH = "thumbnails" # S3 path prefix for Result storage bucket
-
-TC_AWS_MAX_RETRY = 0 # Max retries for get image from S3 Bucket. Default is 0
-
-# put data into S3 using the Server Side Encryption functionality to
-# encrypt data at rest in S3
-# https://aws.amazon.com/about-aws/whats-new/2011/10/04/amazon-s3-announces-server-side-encryption-support/
-TC_AWS_STORAGE_SSE = False
-
-# put data into S3 with Reduced Redundancy
-# https://aws.amazon.com/about-aws/whats-new/2010/05/19/announcing-amazon-s3-reduced-redundancy-storage/
-TC_AWS_STORAGE_RRS = False
-
-
-# Enable HTTP Loader as well?
-# This would allow you to load watermarks in over your images dynamically through a URI
-# E.g.
-# http://your-thumbor.com/unsafe/filters:watermark(http://example.com/watermark.png,0,0,50)/s3_bucket/photo.jpg
-TC_AWS_ENABLE_HTTP_LOADER = False
-
-TC_AWS_ALLOWED_BUCKETS = False # List of allowed bucket to be requested
-TC_AWS_STORE_METADATA = False # Store result with metadata (for instance content-type)
-
-################################################################################
-
-
-# You can override settings in zthumbor/thumbor_local_settings.py
-try:
- from zthumbor.thumbor_local_settings import *
-except ImportError:
- pass