From 405bc8dabff9d8e602b12e53a7855a815e425b95 Mon Sep 17 00:00:00 2001 From: Anders Kaseorg Date: Thu, 6 May 2021 15:38:24 -0700 Subject: [PATCH] requirements: Remove Thumbor. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thumbor and tc-aws have been dragging their feet on Python 3 support for years, and even the alphas and unofficial forks we’ve been running don’t seem to be maintained anymore. Depending on these projects is no longer viable for us. Signed-off-by: Anders Kaseorg --- .eslintignore | 1 - .github/workflows/production-suite.yml | 2 +- .github/workflows/zulip-ci.yml | 2 +- .gitignore | 2 - docs/development/setup-advanced.md | 1 - docs/overview/architecture-overview.md | 7 - docs/subsystems/index.rst | 1 - docs/subsystems/thumbnailing.md | 95 --- .../nginx/zulip-include-app.d/thumbor.conf | 7 - .../nginx/zulip-include-frontend/upstreams | 4 - .../files/supervisor/conf.d/thumbor.conf | 12 - puppet/zulip/manifests/profile/thumbor.pp | 25 - requirements/common.in | 4 - requirements/dev.txt | 5 - requirements/prod.txt | 5 - requirements/thumbor-dev.in | 2 - requirements/thumbor-dev.txt | 414 ----------- requirements/thumbor.in | 12 - requirements/thumbor.txt | 400 ---------- scripts/lib/clean_venv_cache.py | 1 - scripts/lib/create-thumbor-venv | 35 - scripts/lib/install | 1 - scripts/lib/setup_venv.py | 18 - scripts/lib/upgrade-zulip-stage-2 | 6 - scripts/restart-server | 2 - scripts/setup/generate_secrets.py | 1 - scripts/stop-server | 3 - static/js/lightbox.js | 1 - tools/lib/provision.py | 8 +- tools/run-dev.py | 24 +- tools/setup/setup_venvs.py | 2 - tools/update-locked-requirements | 6 +- version.py | 2 +- zerver/lib/test_helpers.py | 1 + zerver/lib/thumbnail.py | 62 +- zerver/tests/test_camo.py | 28 - zerver/tests/test_thumbnail.py | 342 +-------- zerver/views/{ => development}/camo.py | 9 +- zerver/views/thumbnail.py | 11 +- zproject/computed_settings.py | 2 - zproject/default_settings.py | 2 - zproject/dev_settings.py | 1 - zproject/dev_urls.py | 3 + zproject/prod_settings_template.py | 12 - zproject/test_extra_settings.py | 2 - zproject/urls.py | 13 +- zthumbor/__init__.py | 0 zthumbor/loaders/__init__.py | 0 zthumbor/loaders/helpers.py | 13 - zthumbor/loaders/zloader.py | 50 -- zthumbor/thumbor_settings.py | 700 ------------------ 51 files changed, 26 insertions(+), 2336 deletions(-) delete mode 100644 docs/subsystems/thumbnailing.md delete mode 100644 puppet/zulip/files/nginx/zulip-include-app.d/thumbor.conf delete mode 100644 puppet/zulip/files/supervisor/conf.d/thumbor.conf delete mode 100644 puppet/zulip/manifests/profile/thumbor.pp delete mode 100644 requirements/thumbor-dev.in delete mode 100644 requirements/thumbor-dev.txt delete mode 100644 requirements/thumbor.in delete mode 100644 requirements/thumbor.txt delete mode 100755 scripts/lib/create-thumbor-venv delete mode 100644 zerver/tests/test_camo.py rename zerver/views/{ => development}/camo.py (65%) delete mode 100644 zthumbor/__init__.py delete mode 100644 zthumbor/loaders/__init__.py delete mode 100644 zthumbor/loaders/helpers.py delete mode 100644 zthumbor/loaders/zloader.py delete mode 100644 zthumbor/thumbor_settings.py diff --git a/.eslintignore b/.eslintignore index 93d37c8953..0edb2533ec 100644 --- a/.eslintignore +++ b/.eslintignore @@ -12,4 +12,3 @@ !/var/puppeteer/test_credentials.d.ts /zulip-current-venv /zulip-py3-venv -/zulip-thumbor-venv diff --git a/.github/workflows/production-suite.yml b/.github/workflows/production-suite.yml index 73076073b3..bcff40068d 100644 --- a/.github/workflows/production-suite.yml +++ b/.github/workflows/production-suite.yml @@ -73,7 +73,7 @@ jobs: uses: actions/cache@v2 with: path: /srv/zulip-venv-cache - key: v1-venv-${{ github.job }}-${{ hashFiles('requirements/thumbor-dev.txt') }}-${{ hashFiles('requirements/dev.txt') }} + key: v1-venv-${{ github.job }}-${{ hashFiles('requirements/dev.txt') }} restore-keys: v1-venv-${{ github.job }} - name: Restore emoji cache diff --git a/.github/workflows/zulip-ci.yml b/.github/workflows/zulip-ci.yml index af1e2d44b9..d729414f79 100644 --- a/.github/workflows/zulip-ci.yml +++ b/.github/workflows/zulip-ci.yml @@ -91,7 +91,7 @@ jobs: uses: actions/cache@v2 with: path: /srv/zulip-venv-cache - key: v1-venv-${{ matrix.os }}-${{ hashFiles('requirements/thumbor-dev.txt') }}-${{ hashFiles('requirements/dev.txt') }} + key: v1-venv-${{ matrix.os }}-${{ hashFiles('requirements/dev.txt') }} restore-keys: v1-venv-${{ matrix.os }} - name: Restore emoji cache diff --git a/.gitignore b/.gitignore index f7645731f1..81008750bc 100644 --- a/.gitignore +++ b/.gitignore @@ -60,7 +60,6 @@ zulip-git-version /zproject/prod_settings.py /zulip-current-venv /zulip-py3-venv -/zulip-thumbor-venv ## Files left by various editors and local environments # (Ideally these should be in everyone's respective personal gitignore files.) @@ -85,5 +84,4 @@ core ## Miscellaneous # (Ideally this section is empty.) -zthumbor/thumbor_local_settings.py .transifexrc diff --git a/docs/development/setup-advanced.md b/docs/development/setup-advanced.md index 65173355dd..de0b96b336 100644 --- a/docs/development/setup-advanced.md +++ b/docs/development/setup-advanced.md @@ -242,7 +242,6 @@ expected. 9992: Django 9993: Tornado 9994: webpack - 9995: Thumbor ``` Visit the indicated URL in your web browser. diff --git a/docs/overview/architecture-overview.md b/docs/overview/architecture-overview.md index a5b8c73de7..534e9e1296 100644 --- a/docs/overview/architecture-overview.md +++ b/docs/overview/architecture-overview.md @@ -247,13 +247,6 @@ development PostgreSQL user. `tools/provision` also invokes `tools/rebuild-dev-database` to create the actual database with its schema. -### Thumbor and thumbnailing - -We use Thumbor, a popular open source thumbnailing server, to serve -images (both for inline URL previews and serving uploaded image -files). See [our thumbnailing docs](../subsystems/thumbnailing.md) -for more details on how this works. - ### Nagios Nagios is an optional component used for notifications to the system diff --git a/docs/subsystems/index.rst b/docs/subsystems/index.rst index b19797b703..0a8d172519 100644 --- a/docs/subsystems/index.rst +++ b/docs/subsystems/index.rst @@ -32,7 +32,6 @@ Subsystems documentation release-checklist api-release-checklist input-pills - thumbnailing presence unread_messages billing diff --git a/docs/subsystems/thumbnailing.md b/docs/subsystems/thumbnailing.md deleted file mode 100644 index aa599cc4f4..0000000000 --- a/docs/subsystems/thumbnailing.md +++ /dev/null @@ -1,95 +0,0 @@ -# Thumbnailing - -Note: Thumbnailing is an experimental feature. While it is -implemented in Zulip, due to issues with the upstream Thumbor project -being almost unmaintained, it is not recommended for production use. -This is the design document for how thumbnailing will work in Zulip, -assuming Thumbor recovers as a project or we replace it with a similar -alternative. - -There are two key places one would naturally want to thumbnail images -in a team chat application like Zulip: - -* On the server-side, when serving inline image and URL previews in - the bodies of messages. This is very important for Zulip's network - performance of low-bandwidth networks. -* In mobile apps, to avoid uploading full-size images on a mobile - network (which Zulip does not yet implement), - -Our server-side thumbnailing system is powered by [thumbor][], a -popular open source server for serving images and thumbnailing them. - -Thumbor is responsible for a few things in Zulip: - -* Serving all image content over HTTPS, even if the original/upstream - image was hosted on HTTP (this was previously done by `camo` in - older versions of Zulip; the `THUMBOR_SERVES_CAMO` setting controls - whether Thumbor will serve the old-style Camo URLs that might be - present in old messages). This is important to avoid mixed-content - warnings from browsers (which look very bad), and does have some - real security benefit in protecting our users from malicious - content. -* Minimizing potentially unnecessary bandwidth that might be used in - communication between the Zulip server and clients. Before we - introduced this feature, uploading large photos could result in a - bad experience for users with a slow network connection. - -Thumbor handles a lot of details for us, varying from signing of -thumbnailing URLs, to caching for DoS prevention. - -It is configured via the `THUMBOR_URL` and `THUMBNAIL_IMAGES` settings in -`/etc/zulip/settings.py`; you can host Thumbor on the same machine as -the Zulip server, or a remote server (which is better for isolation, -since security bugs in image-processing libraries have in the past -been a common attack vector). - -The thumbnailing system is used for any images that appear in the -bodies of Zulip messages (i.e. both images linked to by users, as well -as uploaded image files.). We exclude a few special image sources -(e.g. youtube stills) only because they are already thumbnailed. - -For uploaded image files, we enforce the same security policy on -thumbnail URLs that we do for the uploaded files themselves. - -A correct client implementation interacting with the thumbnailing -system should do the following: - -* For serving the thumbnailed to 100px height version of images, - nothing special is required; the client just needs to display the - `src=` value in the `` tag in the rendered message HTML. -* For displaying a "full-size" version of an image (e.g. to use in a - lightbox), the client can access the `data-fullsize-src` attribute - on the `` tag; this will contain the URL for a full-size - version. -* Ideally, when clicking on an image to switch from the thumbnail to - the full-size / lightbox size, the client should immediately display - the thumbnailed (low resolution) version and in parallel fetch the - full-size version in the background, transparently swapping it into - place once the full size version is available. This provides a - slick user experience where the user doesn't see a loading state, - and instead just sees the image focus a few hundred milliseconds - after clicking the image. - -## URL design - -The raw Thumbor URLs are ugly, and regardless, have the property that -we might want to change them over time (a classic case is if one moves -the thumbor installation to be hosted by a different server). In -order to avoid encoding these into Zulip messages, we encode in the -[HTML rendered message content](../subsystems/markdown.md) URLs of -the form -`/thumbnail/?url=https://example.com/image.png&size=thumbnail` as the -`src` in our image tags, and that URL serves a -(configuration-dependent) redirect to the actual image hosted on -thumbor. - - -## Avatars, realm icons, and custom emoji - -Currently, these user-uploaded content are thumbnailed by Zulip's -internal file-upload code, in part because they change rarely and -don't have the same throughput/performance requirements as -user-uploaded files. We may later convert them to use thumbor as -well. - -[thumbor]: https://github.com/thumbor/thumbor diff --git a/puppet/zulip/files/nginx/zulip-include-app.d/thumbor.conf b/puppet/zulip/files/nginx/zulip-include-app.d/thumbor.conf deleted file mode 100644 index c80ad4f078..0000000000 --- a/puppet/zulip/files/nginx/zulip-include-app.d/thumbor.conf +++ /dev/null @@ -1,7 +0,0 @@ -# This configuration proxies requests to /thumbor to a copy of the -# thumbor service installed locally on the Zulip server. -location /thumbor { - rewrite /thumbor/(.*) /$1 break; - proxy_pass http://thumbor; - include /etc/nginx/zulip-include/proxy; -} diff --git a/puppet/zulip/files/nginx/zulip-include-frontend/upstreams b/puppet/zulip/files/nginx/zulip-include-frontend/upstreams index 1275cb6988..1f49875103 100644 --- a/puppet/zulip/files/nginx/zulip-include-frontend/upstreams +++ b/puppet/zulip/files/nginx/zulip-include-frontend/upstreams @@ -11,7 +11,3 @@ upstream localhost_sso { upstream camo { server 127.0.0.1:9292; } - -upstream thumbor { - server localhost:9995; -} diff --git a/puppet/zulip/files/supervisor/conf.d/thumbor.conf b/puppet/zulip/files/supervisor/conf.d/thumbor.conf deleted file mode 100644 index d6b1706c66..0000000000 --- a/puppet/zulip/files/supervisor/conf.d/thumbor.conf +++ /dev/null @@ -1,12 +0,0 @@ -[program:zulip-thumbor] -command=/home/zulip/deployments/current/zulip-thumbor-venv/bin/thumbor --port=9995 --conf=/home/zulip/deployments/current/zthumbor/thumbor_settings.py -user=zulip -directory=/home/zulip/deployments/current/ -autostart=true -autorestart=true -startretries=3 -stopsignal=TERM -redirect_stderr=true -stdout_logfile=/var/log/zulip/thumbor.log -stdout_logfile_maxbytes=20MB -stdout_logfile_backups=3 diff --git a/puppet/zulip/manifests/profile/thumbor.pp b/puppet/zulip/manifests/profile/thumbor.pp deleted file mode 100644 index 8598cb8696..0000000000 --- a/puppet/zulip/manifests/profile/thumbor.pp +++ /dev/null @@ -1,25 +0,0 @@ -class zulip::profile::thumbor { - include zulip::profile::base - include zulip::nginx - include zulip::supervisor - - file { "${zulip::common::supervisor_conf_dir}/thumbor.conf": - ensure => file, - require => Package[supervisor], - owner => 'root', - group => 'root', - mode => '0644', - source => 'puppet:///modules/zulip/supervisor/conf.d/thumbor.conf', - notify => Service[$zulip::common::supervisor_service], - } - - file { '/etc/nginx/zulip-include/app.d/thumbor.conf': - ensure => file, - require => Package[$zulip::common::nginx], - owner => 'root', - group => 'root', - mode => '0644', - notify => Service['nginx'], - source => 'puppet:///modules/zulip/nginx/zulip-include-app.d/thumbor.conf', - } -} diff --git a/requirements/common.in b/requirements/common.in index b18b3cb597..73475a519a 100644 --- a/requirements/common.in +++ b/requirements/common.in @@ -156,10 +156,6 @@ disposable-email-domains # Needed for parsing YAML with JSON references from the REST API spec files jsonref -# Needed for signing thumbnail requests so that they can be authenticated on the -# other end. -libthumbor - # Needed for string matching in AlertWordProcessor pyahocorasick diff --git a/requirements/dev.txt b/requirements/dev.txt index e04e1b279d..862aaaa6d6 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -627,10 +627,6 @@ libcst==0.3.18 \ --hash=sha256:30154cd0aaede8f3adfc4bdead23fe022a57e88898b9993cc3fea3bfbaf780d2 \ --hash=sha256:da89cc1a37702caa6fe7207b1257fad58f0d4643597279733106ca902b4fdbad # via pyre-check -libthumbor==2.0.1 \ - --hash=sha256:3c4e1a59c019d22f868d225315c06f97fad30fb5e78112d6a230b978e7d24e38 \ - --hash=sha256:ed4fe5f27f8f90e7285b7e6dce99c1b67d43a140bf370e989080b43d80ce25f0 - # via -r requirements/common.in line-profiler==3.1.0 \ --hash=sha256:23b074497f196d7dd7bc74386cbba47766162f187ebd78bfbc96238f1ce1202d \ --hash=sha256:2b937d8b207cee753d175cc65907901bd9ccadfe20ff2038df9aeae2eafcba6b \ @@ -1352,7 +1348,6 @@ six==1.15.0 \ # html5lib # isodate # jsonschema - # libthumbor # moto # openapi-core # openapi-schema-validator diff --git a/requirements/prod.txt b/requirements/prod.txt index daea305c04..cd8668472f 100644 --- a/requirements/prod.txt +++ b/requirements/prod.txt @@ -431,10 +431,6 @@ lazy-object-proxy==1.6.0 \ --hash=sha256:ed361bb83436f117f9917d282a456f9e5009ea12fd6de8742d1a4752c3017e93 \ --hash=sha256:f5144c75445ae3ca2057faac03fda5a902eff196702b0a24daf1d6ce0650514b # via openapi-core -libthumbor==2.0.1 \ - --hash=sha256:3c4e1a59c019d22f868d225315c06f97fad30fb5e78112d6a230b978e7d24e38 \ - --hash=sha256:ed4fe5f27f8f90e7285b7e6dce99c1b67d43a140bf370e989080b43d80ce25f0 - # via -r requirements/common.in lxml==4.6.3 \ --hash=sha256:079f3ae844f38982d156efce585bc540c16a926d4436712cf4baee0cce487a3d \ --hash=sha256:0fbcf5565ac01dff87cbfc0ff323515c823081c5777a9fc7703ff58388c258c3 \ @@ -900,7 +896,6 @@ six==1.15.0 \ # html5lib # isodate # jsonschema - # libthumbor # openapi-core # openapi-schema-validator # openapi-spec-validator diff --git a/requirements/thumbor-dev.in b/requirements/thumbor-dev.in deleted file mode 100644 index 9ae833e440..0000000000 --- a/requirements/thumbor-dev.in +++ /dev/null @@ -1,2 +0,0 @@ --r pip.in --r thumbor.in diff --git a/requirements/thumbor-dev.txt b/requirements/thumbor-dev.txt deleted file mode 100644 index 2ee26b29bb..0000000000 --- a/requirements/thumbor-dev.txt +++ /dev/null @@ -1,414 +0,0 @@ -# -# This file is GENERATED. Don't edit directly. -# -# To update, edit the non-"lock" files in requirements/*.in, then: -# -# tools/update-locked-requirements -# -# For details, see requirements/README.md . -# -aiobotocore==1.3.0 \ - --hash=sha256:81890d270b1f948ffd218e8bab11e235bea272840ea8b1b9e0aef1954c6cec9e - # via tc-aws -aiohttp==3.7.4.post0 \ - --hash=sha256:02f46fc0e3c5ac58b80d4d56eb0a7c7d97fcef69ace9326289fb9f1955e65cfe \ - --hash=sha256:0563c1b3826945eecd62186f3f5c7d31abb7391fedc893b7e2b26303b5a9f3fe \ - --hash=sha256:114b281e4d68302a324dd33abb04778e8557d88947875cbf4e842c2c01a030c5 \ - --hash=sha256:14762875b22d0055f05d12abc7f7d61d5fd4fe4642ce1a249abdf8c700bf1fd8 \ - --hash=sha256:15492a6368d985b76a2a5fdd2166cddfea5d24e69eefed4630cbaae5c81d89bd \ - --hash=sha256:17c073de315745a1510393a96e680d20af8e67e324f70b42accbd4cb3315c9fb \ - --hash=sha256:209b4a8ee987eccc91e2bd3ac36adee0e53a5970b8ac52c273f7f8fd4872c94c \ - --hash=sha256:230a8f7e24298dea47659251abc0fd8b3c4e38a664c59d4b89cca7f6c09c9e87 \ - --hash=sha256:2e19413bf84934d651344783c9f5e22dee452e251cfd220ebadbed2d9931dbf0 \ - --hash=sha256:393f389841e8f2dfc86f774ad22f00923fdee66d238af89b70ea314c4aefd290 \ - --hash=sha256:3cf75f7cdc2397ed4442594b935a11ed5569961333d49b7539ea741be2cc79d5 \ - --hash=sha256:3d78619672183be860b96ed96f533046ec97ca067fd46ac1f6a09cd9b7484287 \ - --hash=sha256:40eced07f07a9e60e825554a31f923e8d3997cfc7fb31dbc1328c70826e04cde \ - --hash=sha256:493d3299ebe5f5a7c66b9819eacdcfbbaaf1a8e84911ddffcdc48888497afecf \ - --hash=sha256:4b302b45040890cea949ad092479e01ba25911a15e648429c7c5aae9650c67a8 \ - --hash=sha256:515dfef7f869a0feb2afee66b957cc7bbe9ad0cdee45aec7fdc623f4ecd4fb16 \ - --hash=sha256:547da6cacac20666422d4882cfcd51298d45f7ccb60a04ec27424d2f36ba3eaf \ - --hash=sha256:5df68496d19f849921f05f14f31bd6ef53ad4b00245da3195048c69934521809 \ - --hash=sha256:64322071e046020e8797117b3658b9c2f80e3267daec409b350b6a7a05041213 \ - --hash=sha256:7615dab56bb07bff74bc865307aeb89a8bfd9941d2ef9d817b9436da3a0ea54f \ - --hash=sha256:79ebfc238612123a713a457d92afb4096e2148be17df6c50fb9bf7a81c2f8013 \ - --hash=sha256:7b18b97cf8ee5452fa5f4e3af95d01d84d86d32c5e2bfa260cf041749d66360b \ - --hash=sha256:932bb1ea39a54e9ea27fc9232163059a0b8855256f4052e776357ad9add6f1c9 \ - --hash=sha256:a00bb73540af068ca7390e636c01cbc4f644961896fa9363154ff43fd37af2f5 \ - --hash=sha256:a5ca29ee66f8343ed336816c553e82d6cade48a3ad702b9ffa6125d187e2dedb \ - --hash=sha256:af9aa9ef5ba1fd5b8c948bb11f44891968ab30356d65fd0cc6707d989cd521df \ - --hash=sha256:bb437315738aa441251214dad17428cafda9cdc9729499f1d6001748e1d432f4 \ - --hash=sha256:bdb230b4943891321e06fc7def63c7aace16095be7d9cf3b1e01be2f10fba439 \ - --hash=sha256:c6e9dcb4cb338d91a73f178d866d051efe7c62a7166653a91e7d9fb18274058f \ - --hash=sha256:cffe3ab27871bc3ea47df5d8f7013945712c46a3cc5a95b6bee15887f1675c22 \ - --hash=sha256:d012ad7911653a906425d8473a1465caa9f8dea7fcf07b6d870397b774ea7c0f \ - --hash=sha256:d9e13b33afd39ddeb377eff2c1c4f00544e191e1d1dee5b6c51ddee8ea6f0cf5 \ - --hash=sha256:e4b2b334e68b18ac9817d828ba44d8fcb391f6acb398bcc5062b14b2cbeac970 \ - --hash=sha256:e54962802d4b8b18b6207d4a927032826af39395a3bd9196a5af43fc4e60b009 \ - --hash=sha256:f705e12750171c0ab4ef2a3c76b9a4024a62c4103e3a55dd6f99265b9bc6fcfc \ - --hash=sha256:f881853d2643a29e643609da57b96d5f9c9b93f62429dcc1cbb413c7d07f0e1a \ - --hash=sha256:fe60131d21b31fd1a14bd43e6bb88256f69dfc3188b3a89d736d6c71ed43ec95 - # via aiobotocore -aioitertools==0.7.1 \ - --hash=sha256:54a56c7cf3b5290d1cb5e8974353c9f52c677612b5d69a859369a020c53414a3 \ - --hash=sha256:8972308474c41ed5e0636819f948ebff32f2318e70f7e7d23cd208c4357cc773 - # via aiobotocore -asgiref==3.3.4 \ - --hash=sha256:92906c611ce6c967347bbfea733f13d6313901d54dcca88195eaeb52b2a8e8ee \ - --hash=sha256:d1216dfbdfb63826470995d31caed36225dcaf34f182e0fa257a4dd9e86f1b78 - # via django -async-timeout==3.0.1 \ - --hash=sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f \ - --hash=sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3 - # via aiohttp -attrs==20.3.0 \ - --hash=sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6 \ - --hash=sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700 - # via aiohttp -botocore==1.20.49 \ - --hash=sha256:6a672ba41dd00e5c1c1824ca8143d180d88de8736d78c0b1f96b8d3cb0466561 \ - --hash=sha256:f7f103fa0651c69dd360c7d0ecd874854303de5cc0869e0cbc2818a52baacc69 - # via aiobotocore -chardet==4.0.0 \ - --hash=sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa \ - --hash=sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5 - # via aiohttp -colorful==0.5.4 \ - --hash=sha256:86848ad4e2eda60cd2519d8698945d22f6f6551e23e95f3f14dfbb60997807ea \ - --hash=sha256:8d264b52a39aae4c0ba3e2a46afbaec81b0559a99be0d2cfe2aba4cf94531348 - # via thumbor -derpconf==0.8.3 \ - --hash=sha256:1bb152d8a1cf5c2a6d629bf29acd4af0c00811339642fc0a56172b0a83b31a15 - # via thumbor -django-auth-ldap==2.4.0 \ - --hash=sha256:2d869955da8a0c9a4448671bd9826b9f87458f6a9fc20278e84de8a81200a2be \ - --hash=sha256:60fcbfc3141c99c3c49d3ccd7311a3992a231c319d94b6d2c143968f63676676 - # via -r requirements/thumbor.in -django==3.1.8 \ - --hash=sha256:c348b3ddc452bf4b62361f0752f71a339140c777ebea3cdaaaa8fdb7f417a862 \ - --hash=sha256:f8393103e15ec2d2d313ccbb95a3f1da092f9f58d74ac1c61ca2ac0436ae1eac - # via - # -r requirements/thumbor.in - # django-auth-ldap -idna-ssl==1.1.0 \ - --hash=sha256:a933e3bb13da54383f9e8f35dc4f9cb9eb9b3b78c6b36f311254d6d0d92c6c7c - # via aiohttp -idna==3.1 \ - --hash=sha256:5205d03e7bcbb919cc9c19885f9920d622ca52448306f2377daede5cf3faac16 \ - --hash=sha256:c5b02147e01ea9920e6b0a3f1f7bb833612d507592c837a6c49552768f4054e1 - # via - # idna-ssl - # yarl -jmespath==0.10.0 \ - --hash=sha256:b85d0567b8666149a93172712e68920734333c0ce7e89b78b3e987f71e5ed4f9 \ - --hash=sha256:cdf6525904cc597730141d61b36f2e4b8ecc257c420fa2f4549bac2c2d0cb72f - # via botocore -libthumbor==2.0.1 \ - --hash=sha256:3c4e1a59c019d22f868d225315c06f97fad30fb5e78112d6a230b978e7d24e38 \ - --hash=sha256:ed4fe5f27f8f90e7285b7e6dce99c1b67d43a140bf370e989080b43d80ce25f0 - # via thumbor -multidict==5.1.0 \ - --hash=sha256:018132dbd8688c7a69ad89c4a3f39ea2f9f33302ebe567a879da8f4ca73f0d0a \ - --hash=sha256:051012ccee979b2b06be928a6150d237aec75dd6bf2d1eeeb190baf2b05abc93 \ - --hash=sha256:05c20b68e512166fddba59a918773ba002fdd77800cad9f55b59790030bab632 \ - --hash=sha256:07b42215124aedecc6083f1ce6b7e5ec5b50047afa701f3442054373a6deb656 \ - --hash=sha256:0e3c84e6c67eba89c2dbcee08504ba8644ab4284863452450520dad8f1e89b79 \ - --hash=sha256:0e929169f9c090dae0646a011c8b058e5e5fb391466016b39d21745b48817fd7 \ - --hash=sha256:1ab820665e67373de5802acae069a6a05567ae234ddb129f31d290fc3d1aa56d \ - --hash=sha256:25b4e5f22d3a37ddf3effc0710ba692cfc792c2b9edfb9c05aefe823256e84d5 \ - --hash=sha256:2e68965192c4ea61fff1b81c14ff712fc7dc15d2bd120602e4a3494ea6584224 \ - --hash=sha256:2f1a132f1c88724674271d636e6b7351477c27722f2ed789f719f9e3545a3d26 \ - --hash=sha256:37e5438e1c78931df5d3c0c78ae049092877e5e9c02dd1ff5abb9cf27a5914ea \ - --hash=sha256:3a041b76d13706b7fff23b9fc83117c7b8fe8d5fe9e6be45eee72b9baa75f348 \ - --hash=sha256:3a4f32116f8f72ecf2a29dabfb27b23ab7cdc0ba807e8459e59a93a9be9506f6 \ - --hash=sha256:46c73e09ad374a6d876c599f2328161bcd95e280f84d2060cf57991dec5cfe76 \ - --hash=sha256:46dd362c2f045095c920162e9307de5ffd0a1bfbba0a6e990b344366f55a30c1 \ - --hash=sha256:4b186eb7d6ae7c06eb4392411189469e6a820da81447f46c0072a41c748ab73f \ - --hash=sha256:54fd1e83a184e19c598d5e70ba508196fd0bbdd676ce159feb412a4a6664f952 \ - --hash=sha256:585fd452dd7782130d112f7ddf3473ffdd521414674c33876187e101b588738a \ - --hash=sha256:5cf3443199b83ed9e955f511b5b241fd3ae004e3cb81c58ec10f4fe47c7dce37 \ - --hash=sha256:6a4d5ce640e37b0efcc8441caeea8f43a06addace2335bd11151bc02d2ee31f9 \ - --hash=sha256:7df80d07818b385f3129180369079bd6934cf70469f99daaebfac89dca288359 \ - --hash=sha256:806068d4f86cb06af37cd65821554f98240a19ce646d3cd24e1c33587f313eb8 \ - --hash=sha256:830f57206cc96ed0ccf68304141fec9481a096c4d2e2831f311bde1c404401da \ - --hash=sha256:929006d3c2d923788ba153ad0de8ed2e5ed39fdbe8e7be21e2f22ed06c6783d3 \ - --hash=sha256:9436dc58c123f07b230383083855593550c4d301d2532045a17ccf6eca505f6d \ - --hash=sha256:9dd6e9b1a913d096ac95d0399bd737e00f2af1e1594a787e00f7975778c8b2bf \ - --hash=sha256:ace010325c787c378afd7f7c1ac66b26313b3344628652eacd149bdd23c68841 \ - --hash=sha256:b47a43177a5e65b771b80db71e7be76c0ba23cc8aa73eeeb089ed5219cdbe27d \ - --hash=sha256:b797515be8743b771aa868f83563f789bbd4b236659ba52243b735d80b29ed93 \ - --hash=sha256:b7993704f1a4b204e71debe6095150d43b2ee6150fa4f44d6d966ec356a8d61f \ - --hash=sha256:d5c65bdf4484872c4af3150aeebe101ba560dcfb34488d9a8ff8dbcd21079647 \ - --hash=sha256:d81eddcb12d608cc08081fa88d046c78afb1bf8107e6feab5d43503fea74a635 \ - --hash=sha256:dc862056f76443a0db4509116c5cd480fe1b6a2d45512a653f9a855cc0517456 \ - --hash=sha256:ecc771ab628ea281517e24fd2c52e8f31c41e66652d07599ad8818abaad38cda \ - --hash=sha256:f200755768dc19c6f4e2b672421e0ebb3dd54c38d5a4f262b872d8cfcc9e93b5 \ - --hash=sha256:f21756997ad8ef815d8ef3d34edd98804ab5ea337feedcd62fb52d22bf531281 \ - --hash=sha256:fc13a9524bc18b6fb6e0dbec3533ba0496bbed167c56d0aabefd965584557d80 - # via - # aiohttp - # yarl -numpy==1.19.5 \ - --hash=sha256:012426a41bc9ab63bb158635aecccc7610e3eff5d31d1eb43bc099debc979d94 \ - --hash=sha256:06fab248a088e439402141ea04f0fffb203723148f6ee791e9c75b3e9e82f080 \ - --hash=sha256:0eef32ca3132a48e43f6a0f5a82cb508f22ce5a3d6f67a8329c81c8e226d3f6e \ - --hash=sha256:1ded4fce9cfaaf24e7a0ab51b7a87be9038ea1ace7f34b841fe3b6894c721d1c \ - --hash=sha256:2e55195bc1c6b705bfd8ad6f288b38b11b1af32f3c8289d6c50d47f950c12e76 \ - --hash=sha256:2ea52bd92ab9f768cc64a4c3ef8f4b2580a17af0a5436f6126b08efbd1838371 \ - --hash=sha256:36674959eed6957e61f11c912f71e78857a8d0604171dfd9ce9ad5cbf41c511c \ - --hash=sha256:384ec0463d1c2671170901994aeb6dce126de0a95ccc3976c43b0038a37329c2 \ - --hash=sha256:39b70c19ec771805081578cc936bbe95336798b7edf4732ed102e7a43ec5c07a \ - --hash=sha256:400580cbd3cff6ffa6293df2278c75aef2d58d8d93d3c5614cd67981dae68ceb \ - --hash=sha256:43d4c81d5ffdff6bae58d66a3cd7f54a7acd9a0e7b18d97abb255defc09e3140 \ - --hash=sha256:50a4a0ad0111cc1b71fa32dedd05fa239f7fb5a43a40663269bb5dc7877cfd28 \ - --hash=sha256:603aa0706be710eea8884af807b1b3bc9fb2e49b9f4da439e76000f3b3c6ff0f \ - --hash=sha256:6149a185cece5ee78d1d196938b2a8f9d09f5a5ebfbba66969302a778d5ddd1d \ - --hash=sha256:759e4095edc3c1b3ac031f34d9459fa781777a93ccc633a472a5468587a190ff \ - --hash=sha256:7fb43004bce0ca31d8f13a6eb5e943fa73371381e53f7074ed21a4cb786c32f8 \ - --hash=sha256:811daee36a58dc79cf3d8bdd4a490e4277d0e4b7d103a001a4e73ddb48e7e6aa \ - --hash=sha256:8b5e972b43c8fc27d56550b4120fe6257fdc15f9301914380b27f74856299fea \ - --hash=sha256:99abf4f353c3d1a0c7a5f27699482c987cf663b1eac20db59b8c7b061eabd7fc \ - --hash=sha256:a0d53e51a6cb6f0d9082decb7a4cb6dfb33055308c4c44f53103c073f649af73 \ - --hash=sha256:a12ff4c8ddfee61f90a1633a4c4afd3f7bcb32b11c52026c92a12e1325922d0d \ - --hash=sha256:a4646724fba402aa7504cd48b4b50e783296b5e10a524c7a6da62e4a8ac9698d \ - --hash=sha256:a76f502430dd98d7546e1ea2250a7360c065a5fdea52b2dffe8ae7180909b6f4 \ - --hash=sha256:a9d17f2be3b427fbb2bce61e596cf555d6f8a56c222bd2ca148baeeb5e5c783c \ - --hash=sha256:ab83f24d5c52d60dbc8cd0528759532736b56db58adaa7b5f1f76ad551416a1e \ - --hash=sha256:aeb9ed923be74e659984e321f609b9ba54a48354bfd168d21a2b072ed1e833ea \ - --hash=sha256:c843b3f50d1ab7361ca4f0b3639bf691569493a56808a0b0c54a051d260b7dbd \ - --hash=sha256:cae865b1cae1ec2663d8ea56ef6ff185bad091a5e33ebbadd98de2cfa3fa668f \ - --hash=sha256:cc6bd4fd593cb261332568485e20a0712883cf631f6f5e8e86a52caa8b2b50ff \ - --hash=sha256:cf2402002d3d9f91c8b01e66fbb436a4ed01c6498fffed0e4c7566da1d40ee1e \ - --hash=sha256:d051ec1c64b85ecc69531e1137bb9751c6830772ee5c1c426dbcfe98ef5788d7 \ - --hash=sha256:d6631f2e867676b13026e2846180e2c13c1e11289d67da08d71cacb2cd93d4aa \ - --hash=sha256:dbd18bcf4889b720ba13a27ec2f2aac1981bd41203b3a3b27ba7a33f88ae4827 \ - --hash=sha256:df609c82f18c5b9f6cb97271f03315ff0dbe481a2a02e56aeb1b1a985ce38e60 - # via opencv-python-headless -opencv-python-headless==4.5.1.48 \ - --hash=sha256:0e02809db2968e54f3c23340be6ff9a1428b3f03f5dca7cd5aceda66e319ce86 \ - --hash=sha256:1f7c14f5d4e5af4dc4669fc6b4a983b36072a934c439ac11266b930496da8255 \ - --hash=sha256:243aea91cc1e36a47c46da4cc408071af39444a48df1fe1539ea8d7990500fd2 \ - --hash=sha256:2560dcf3c1158226b066302f777bfe0f65282410b8d90871dd872306c967d1f1 \ - --hash=sha256:2e6a9a88617a0ef7219cff24ba78a58416670a77e6ac63975f9009af3319ab63 \ - --hash=sha256:372149d007e20bf556b7687591d22b58b56b3c225f492da051d81587e5dc7411 \ - --hash=sha256:522f12dd994e064a30562adfd63b9439099bd7c80819f5261c37ebe593283c9e \ - --hash=sha256:526b9e19cf6300f0891d8f427eac1048091912332bb781eb4957a4994bfbe608 \ - --hash=sha256:5f0c7d34fa9953706c2a1a6d2760a91dc5a68cab3df16af61609894c6c8586f1 \ - --hash=sha256:657cdd9fbbbbb7e898ae3d9b0649b367d0e440d429c714104d069c5612d578bb \ - --hash=sha256:65c9ea57be5ebcaed009b3fee14fe59f3b6aa1e573fe08c5039ff057ad593c53 \ - --hash=sha256:777fb596e04331f73ef5b0c1faa4d33348f29ca58216d9286355c16f5489c939 \ - --hash=sha256:7c75680ffdf32d7044415a215d1fc60dbec14a7f2f0b59a85f0f74ef5efcb6ad \ - --hash=sha256:924aa4c34ead0b817309f42291dc526b2a7755476afe3009d1e275fc3090d92d \ - --hash=sha256:96d1da6ad061d8f3509668d398d14dd8265e529d6407f87eb26e7f4ddf043cc0 \ - --hash=sha256:9aa04a491c534531029fbac61da961fae0bf4abb1786eed9c91befde4ca7bd81 \ - --hash=sha256:a322d4df14c3a5f19701a023b3da91e9b8af8653b0d2ee0c50b0b341212f7343 \ - --hash=sha256:aa562c520f46283423ba8fac29099458e42deab697a9abd0491622e421c5c454 \ - --hash=sha256:ba2f0bd46e9534f29969e39f7895cbea9764173102b0c04b7818b8a9910d66e4 \ - --hash=sha256:d16825755e7b5a6d8737f93e116670229e1510199e0af9213004e187ae0dbcc5 \ - --hash=sha256:e3027e0d1b71b68b5cfe1ea9c627e323dff71112c854ba19805258d8fc6c630e \ - --hash=sha256:f2011ecb3980bbed283d17d43e0f1221bac88c0cac1a6fb59a056544de2df2f7 \ - --hash=sha256:f5e40a06116460ef2fd2d1c24be3b65f8bfb5fcdfe433f3fc01bcb4c2eb485bf \ - --hash=sha256:f7f8e4f7c63c8e95eb210f4cba88d0069a0a964d6335d7a35b07f0d0baa13558 \ - --hash=sha256:fe02a943b1a28b505e954fbce24e867119a3eb4351f93adad55c6cfe81a70484 - # via thumbor -pillow==7.2.0 \ - --hash=sha256:0295442429645fa16d05bd567ef5cff178482439c9aad0411d3f0ce9b88b3a6f \ - --hash=sha256:06aba4169e78c439d528fdeb34762c3b61a70813527a2c57f0540541e9f433a8 \ - --hash=sha256:09d7f9e64289cb40c2c8d7ad674b2ed6105f55dc3b09aa8e4918e20a0311e7ad \ - --hash=sha256:0a80dd307a5d8440b0a08bd7b81617e04d870e40a3e46a32d9c246e54705e86f \ - --hash=sha256:1ca594126d3c4def54babee699c055a913efb01e106c309fa6b04405d474d5ae \ - --hash=sha256:25930fadde8019f374400f7986e8404c8b781ce519da27792cbe46eabec00c4d \ - --hash=sha256:431b15cffbf949e89df2f7b48528be18b78bfa5177cb3036284a5508159492b5 \ - --hash=sha256:52125833b070791fcb5710fabc640fc1df07d087fc0c0f02d3661f76c23c5b8b \ - --hash=sha256:5e51ee2b8114def244384eda1c82b10e307ad9778dac5c83fb0943775a653cd8 \ - --hash=sha256:612cfda94e9c8346f239bf1a4b082fdd5c8143cf82d685ba2dba76e7adeeb233 \ - --hash=sha256:6d7741e65835716ceea0fd13a7d0192961212fd59e741a46bbed7a473c634ed6 \ - --hash=sha256:6edb5446f44d901e8683ffb25ebdfc26988ee813da3bf91e12252b57ac163727 \ - --hash=sha256:725aa6cfc66ce2857d585f06e9519a1cc0ef6d13f186ff3447ab6dff0a09bc7f \ - --hash=sha256:8dad18b69f710bf3a001d2bf3afab7c432785d94fcf819c16b5207b1cfd17d38 \ - --hash=sha256:94cf49723928eb6070a892cb39d6c156f7b5a2db4e8971cb958f7b6b104fb4c4 \ - --hash=sha256:97f9e7953a77d5a70f49b9a48da7776dc51e9b738151b22dacf101641594a626 \ - --hash=sha256:9ad7f865eebde135d526bb3163d0b23ffff365cf87e767c649550964ad72785d \ - --hash=sha256:9c87ef410a58dd54b92424ffd7e28fd2ec65d2f7fc02b76f5e9b2067e355ebf6 \ - --hash=sha256:a060cf8aa332052df2158e5a119303965be92c3da6f2d93b6878f0ebca80b2f6 \ - --hash=sha256:c79f9c5fb846285f943aafeafda3358992d64f0ef58566e23484132ecd8d7d63 \ - --hash=sha256:c92302a33138409e8f1ad16731568c55c9053eee71bb05b6b744067e1b62380f \ - --hash=sha256:d08b23fdb388c0715990cbc06866db554e1822c4bdcf6d4166cf30ac82df8c41 \ - --hash=sha256:d350f0f2c2421e65fbc62690f26b59b0bcda1b614beb318c81e38647e0f673a1 \ - --hash=sha256:e901964262a56d9ea3c2693df68bc9860b8bdda2b04768821e4c44ae797de117 \ - --hash=sha256:ec29604081f10f16a7aea809ad42e27764188fc258b02259a03a8ff7ded3808d \ - --hash=sha256:edf31f1150778abd4322444c393ab9c7bd2af271dd4dafb4208fb613b1f3cdc9 \ - --hash=sha256:f7e30c27477dffc3e85c2463b3e649f751789e0f6c8456099eea7ddd53be4a8a \ - --hash=sha256:ffe538682dc19cc542ae7c3e504fdf54ca7f86fb8a135e59dd6bc8627eae6cce - # via thumbor -pyasn1-modules==0.2.8 \ - --hash=sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e \ - --hash=sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74 - # via python-ldap -pyasn1==0.4.8 \ - --hash=sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d \ - --hash=sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba - # via - # pyasn1-modules - # python-ldap -pycurl==7.43.0.6 \ - --hash=sha256:8301518689daefa53726b59ded6b48f33751c383cf987b0ccfbbc4ed40281325 - # via -r requirements/thumbor.in -python-dateutil==2.8.1 \ - --hash=sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c \ - --hash=sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a - # via - # botocore - # tc-aws -python-ldap==3.3.1 \ - --hash=sha256:4711cacf013e298754abd70058ccc995758177fb425f1c2d30e71adfc1d00aa5 - # via django-auth-ldap -pytz==2019.3 \ - --hash=sha256:1c557d7d0e871de1f5ccd5833f60fb2550652da6be2693c1e02300743d21500d \ - --hash=sha256:b02c06db6cf09c12dd25137e563b31700d3b80fcc4ad23abb7a315f2789819be - # via - # django - # thumbor -six==1.15.0 \ - --hash=sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259 \ - --hash=sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced - # via - # derpconf - # libthumbor - # python-dateutil -sqlparse==0.4.1 \ - --hash=sha256:017cde379adbd6a1f15a61873f43e8274179378e95ef3fede90b5aa64d304ed0 \ - --hash=sha256:0f91fd2e829c44362cbcfab3e9ae12e22badaa8a29ad5ff599f9ec109f0454e8 - # via django -statsd==3.3.0 \ - --hash=sha256:c610fb80347fca0ef62666d241bce64184bd7cc1efe582f9690e045c25535eaa \ - --hash=sha256:e3e6db4c246f7c59003e51c9720a51a7f39a396541cb9b147ff4b14d15b5dd1f - # via thumbor -https://github.com/kkopachev/aws/archive/b5058e6b9fec7354629acc6d5df423e0310bb0cd.zip#egg=tc_aws==6.3 \ - --hash=sha256:8a28437b0dfab88c89f280a2d6ec55a6abfa3e26d495dc15e1b3f38744e27f0c - # via -r requirements/thumbor.in -thumbor==7.0.0a5 \ - --hash=sha256:5042c9c8facf0da028a22f1aee717f856d213ec037835ca0edaa0282217654bb - # via - # -r requirements/thumbor.in - # tc-aws -tornado==6.1 \ - --hash=sha256:0a00ff4561e2929a2c37ce706cb8233b7907e0cdc22eab98888aca5dd3775feb \ - --hash=sha256:0d321a39c36e5f2c4ff12b4ed58d41390460f798422c4504e09eb5678e09998c \ - --hash=sha256:1e8225a1070cd8eec59a996c43229fe8f95689cb16e552d130b9793cb570a288 \ - --hash=sha256:20241b3cb4f425e971cb0a8e4ffc9b0a861530ae3c52f2b0434e6c1b57e9fd95 \ - --hash=sha256:25ad220258349a12ae87ede08a7b04aca51237721f63b1808d39bdb4b2164558 \ - --hash=sha256:33892118b165401f291070100d6d09359ca74addda679b60390b09f8ef325ffe \ - --hash=sha256:33c6e81d7bd55b468d2e793517c909b139960b6c790a60b7991b9b6b76fb9791 \ - --hash=sha256:3447475585bae2e77ecb832fc0300c3695516a47d46cefa0528181a34c5b9d3d \ - --hash=sha256:34ca2dac9e4d7afb0bed4677512e36a52f09caa6fded70b4e3e1c89dbd92c326 \ - --hash=sha256:3e63498f680547ed24d2c71e6497f24bca791aca2fe116dbc2bd0ac7f191691b \ - --hash=sha256:548430be2740e327b3fe0201abe471f314741efcb0067ec4f2d7dcfb4825f3e4 \ - --hash=sha256:6196a5c39286cc37c024cd78834fb9345e464525d8991c21e908cc046d1cc02c \ - --hash=sha256:61b32d06ae8a036a6607805e6720ef00a3c98207038444ba7fd3d169cd998910 \ - --hash=sha256:6286efab1ed6e74b7028327365cf7346b1d777d63ab30e21a0f4d5b275fc17d5 \ - --hash=sha256:65d98939f1a2e74b58839f8c4dab3b6b3c1ce84972ae712be02845e65391ac7c \ - --hash=sha256:66324e4e1beede9ac79e60f88de548da58b1f8ab4b2f1354d8375774f997e6c0 \ - --hash=sha256:6c77c9937962577a6a76917845d06af6ab9197702a42e1346d8ae2e76b5e3675 \ - --hash=sha256:70dec29e8ac485dbf57481baee40781c63e381bebea080991893cd297742b8fd \ - --hash=sha256:7250a3fa399f08ec9cb3f7b1b987955d17e044f1ade821b32e5f435130250d7f \ - --hash=sha256:748290bf9112b581c525e6e6d3820621ff020ed95af6f17fedef416b27ed564c \ - --hash=sha256:7da13da6f985aab7f6f28debab00c67ff9cbacd588e8477034c0652ac141feea \ - --hash=sha256:8f959b26f2634a091bb42241c3ed8d3cedb506e7c27b8dd5c7b9f745318ddbb6 \ - --hash=sha256:9de9e5188a782be6b1ce866e8a51bc76a0fbaa0e16613823fc38e4fc2556ad05 \ - --hash=sha256:a48900ecea1cbb71b8c71c620dee15b62f85f7c14189bdeee54966fbd9a0c5bd \ - --hash=sha256:b87936fd2c317b6ee08a5741ea06b9d11a6074ef4cc42e031bc6403f82a32575 \ - --hash=sha256:c77da1263aa361938476f04c4b6c8916001b90b2c2fdd92d8d535e1af48fba5a \ - --hash=sha256:cb5ec8eead331e3bb4ce8066cf06d2dfef1bfb1b2a73082dfe8a161301b76e37 \ - --hash=sha256:cc0ee35043162abbf717b7df924597ade8e5395e7b66d18270116f8745ceb795 \ - --hash=sha256:d14d30e7f46a0476efb0deb5b61343b1526f73ebb5ed84f23dc794bdb88f9d9f \ - --hash=sha256:d371e811d6b156d82aa5f9a4e08b58debf97c302a35714f6f45e35139c332e32 \ - --hash=sha256:d3d20ea5782ba63ed13bc2b8c291a053c8d807a8fa927d941bd718468f7b950c \ - --hash=sha256:d3f7594930c423fd9f5d1a76bee85a2c36fd8b4b16921cae7e965f22575e9c01 \ - --hash=sha256:dcef026f608f678c118779cd6591c8af6e9b4155c44e0d1bc0c87c036fb8c8c4 \ - --hash=sha256:e0791ac58d91ac58f694d8d2957884df8e4e2f6687cdf367ef7eb7497f79eaa2 \ - --hash=sha256:e385b637ac3acaae8022e7e47dfa7b83d3620e432e3ecb9a3f7f58f150e50921 \ - --hash=sha256:e519d64089b0876c7b467274468709dadf11e41d65f63bba207e04217f47c085 \ - --hash=sha256:e7229e60ac41a1202444497ddde70a48d33909e484f96eb0da9baf8dc68541df \ - --hash=sha256:ed3ad863b1b40cd1d4bd21e7498329ccaece75db5a5bf58cd3c9f130843e7102 \ - --hash=sha256:f0ba29bafd8e7e22920567ce0d232c26d4d47c8b5cf4ed7b562b5db39fa199c5 \ - --hash=sha256:fa2ba70284fa42c2a5ecb35e322e68823288a4251f9ba9cc77be04ae15eada68 \ - --hash=sha256:fba85b6cd9c39be262fcd23865652920832b61583de2a2ca907dbd8e8a8c81e5 - # via thumbor -typing-extensions==3.7.4.3 \ - --hash=sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918 \ - --hash=sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c \ - --hash=sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f - # via - # aiohttp - # aioitertools - # asgiref - # yarl -urllib3==1.26.4 \ - --hash=sha256:2f4da4594db7e1e110a944bb1b551fdf4e6c136ad42e4234131391e21eb5b0df \ - --hash=sha256:e7b021f7241115872f92f43c6508082facffbd1c048e3c6e2bb9c2a157e28937 - # via botocore -virtualenv-clone==0.5.4 \ - --hash=sha256:07e74418b7cc64f4fda987bf5bc71ebd59af27a7bc9e8a8ee9fd54b1f2390a27 \ - --hash=sha256:665e48dd54c84b98b71a657acb49104c54e7652bce9c1c4f6c6976ed4c827a29 - # via -r requirements/thumbor.in -webcolors==1.11.1 \ - --hash=sha256:76f360636957d1c976db7466bc71dcb713bb95ac8911944dffc55c01cb516de6 \ - --hash=sha256:b8cd5d865a25c51ff1218f0c90d0c0781fc64312a49b746b320cf50de1648f6e - # via thumbor -wheel==0.36.2 \ - --hash=sha256:78b5b185f0e5763c26ca1e324373aadd49182ca90e825f7853f4b2509215dc0e \ - --hash=sha256:e11eefd162658ea59a60a0f6c7d493a7190ea4b9a85e335b33489d9f17e0245e - # via -r requirements/pip.in -wrapt==1.12.1 \ - --hash=sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7 - # via aiobotocore -yarl==1.6.3 \ - --hash=sha256:00d7ad91b6583602eb9c1d085a2cf281ada267e9a197e8b7cae487dadbfa293e \ - --hash=sha256:0355a701b3998dcd832d0dc47cc5dedf3874f966ac7f870e0f3a6788d802d434 \ - --hash=sha256:15263c3b0b47968c1d90daa89f21fcc889bb4b1aac5555580d74565de6836366 \ - --hash=sha256:2ce4c621d21326a4a5500c25031e102af589edb50c09b321049e388b3934eec3 \ - --hash=sha256:31ede6e8c4329fb81c86706ba8f6bf661a924b53ba191b27aa5fcee5714d18ec \ - --hash=sha256:324ba3d3c6fee56e2e0b0d09bf5c73824b9f08234339d2b788af65e60040c959 \ - --hash=sha256:329412812ecfc94a57cd37c9d547579510a9e83c516bc069470db5f75684629e \ - --hash=sha256:4736eaee5626db8d9cda9eb5282028cc834e2aeb194e0d8b50217d707e98bb5c \ - --hash=sha256:4953fb0b4fdb7e08b2f3b3be80a00d28c5c8a2056bb066169de00e6501b986b6 \ - --hash=sha256:4c5bcfc3ed226bf6419f7a33982fb4b8ec2e45785a0561eb99274ebbf09fdd6a \ - --hash=sha256:547f7665ad50fa8563150ed079f8e805e63dd85def6674c97efd78eed6c224a6 \ - --hash=sha256:5b883e458058f8d6099e4420f0cc2567989032b5f34b271c0827de9f1079a424 \ - --hash=sha256:63f90b20ca654b3ecc7a8d62c03ffa46999595f0167d6450fa8383bab252987e \ - --hash=sha256:68dc568889b1c13f1e4745c96b931cc94fdd0defe92a72c2b8ce01091b22e35f \ - --hash=sha256:69ee97c71fee1f63d04c945f56d5d726483c4762845400a6795a3b75d56b6c50 \ - --hash=sha256:6d6283d8e0631b617edf0fd726353cb76630b83a089a40933043894e7f6721e2 \ - --hash=sha256:72a660bdd24497e3e84f5519e57a9ee9220b6f3ac4d45056961bf22838ce20cc \ - --hash=sha256:73494d5b71099ae8cb8754f1df131c11d433b387efab7b51849e7e1e851f07a4 \ - --hash=sha256:7356644cbed76119d0b6bd32ffba704d30d747e0c217109d7979a7bc36c4d970 \ - --hash=sha256:8a9066529240171b68893d60dca86a763eae2139dd42f42106b03cf4b426bf10 \ - --hash=sha256:8aa3decd5e0e852dc68335abf5478a518b41bf2ab2f330fe44916399efedfae0 \ - --hash=sha256:97b5bdc450d63c3ba30a127d018b866ea94e65655efaf889ebeabc20f7d12406 \ - --hash=sha256:9ede61b0854e267fd565e7527e2f2eb3ef8858b301319be0604177690e1a3896 \ - --hash=sha256:b2e9a456c121e26d13c29251f8267541bd75e6a1ccf9e859179701c36a078643 \ - --hash=sha256:b5dfc9a40c198334f4f3f55880ecf910adebdcb2a0b9a9c23c9345faa9185721 \ - --hash=sha256:bafb450deef6861815ed579c7a6113a879a6ef58aed4c3a4be54400ae8871478 \ - --hash=sha256:c49ff66d479d38ab863c50f7bb27dee97c6627c5fe60697de15529da9c3de724 \ - --hash=sha256:ce3beb46a72d9f2190f9e1027886bfc513702d748047b548b05dab7dfb584d2e \ - --hash=sha256:d26608cf178efb8faa5ff0f2d2e77c208f471c5a3709e577a7b3fd0445703ac8 \ - --hash=sha256:d597767fcd2c3dc49d6eea360c458b65643d1e4dbed91361cf5e36e53c1f8c96 \ - --hash=sha256:d5c32c82990e4ac4d8150fd7652b972216b204de4e83a122546dce571c1bdf25 \ - --hash=sha256:d8d07d102f17b68966e2de0e07bfd6e139c7c02ef06d3a0f8d2f0f055e13bb76 \ - --hash=sha256:e46fba844f4895b36f4c398c5af062a9808d1f26b2999c58909517384d5deda2 \ - --hash=sha256:e6b5460dc5ad42ad2b36cca524491dfcaffbfd9c8df50508bddc354e787b8dc2 \ - --hash=sha256:f040bcc6725c821a4c0665f3aa96a4d0805a7aaf2caf266d256b8ed71b9f041c \ - --hash=sha256:f0b059678fd549c66b89bed03efcabb009075bd131c248ecdf087bdb6faba24a \ - --hash=sha256:fcbb48a93e8699eae920f8d92f7160c03567b421bc17362a9ffbbd706a816f71 - # via aiohttp - -# The following packages are considered to be unsafe in a requirements file: -pip==20.2.4 \ - --hash=sha256:51f1c7514530bd5c145d8f13ed936ad6b8bfcb8cf74e10403d0890bc986f0033 \ - --hash=sha256:85c99a857ea0fb0aedf23833d9be5c40cf253fe24443f0829c7b472e23c364a1 - # via -r requirements/pip.in -setuptools==56.0.0 \ - --hash=sha256:08a1c0f99455307c48690f00d5c2ac2c1ccfab04df00454fef854ec145b81302 \ - --hash=sha256:7430499900e443375ba9449a9cc5d78506b801e929fef4a186496012f93683b5 - # via -r requirements/pip.in diff --git a/requirements/thumbor.in b/requirements/thumbor.in deleted file mode 100644 index 8a830454ea..0000000000 --- a/requirements/thumbor.in +++ /dev/null @@ -1,12 +0,0 @@ -https://github.com/kkopachev/aws/archive/b5058e6b9fec7354629acc6d5df423e0310bb0cd.zip#egg=tc_aws==6.3 -thumbor>=7.dev - -# Not required by Thumbor, but recommended -pycurl - -# Required for just importing settings from our main django app. -django-auth-ldap -Django==3.1.* - -# Needed for cloning virtual environments -virtualenv-clone diff --git a/requirements/thumbor.txt b/requirements/thumbor.txt deleted file mode 100644 index 1864dfd3ca..0000000000 --- a/requirements/thumbor.txt +++ /dev/null @@ -1,400 +0,0 @@ -# -# This file is GENERATED. Don't edit directly. -# -# To update, edit the non-"lock" files in requirements/*.in, then: -# -# tools/update-locked-requirements -# -# For details, see requirements/README.md . -# -aiobotocore==1.3.0 \ - --hash=sha256:81890d270b1f948ffd218e8bab11e235bea272840ea8b1b9e0aef1954c6cec9e - # via tc-aws -aiohttp==3.7.4.post0 \ - --hash=sha256:02f46fc0e3c5ac58b80d4d56eb0a7c7d97fcef69ace9326289fb9f1955e65cfe \ - --hash=sha256:0563c1b3826945eecd62186f3f5c7d31abb7391fedc893b7e2b26303b5a9f3fe \ - --hash=sha256:114b281e4d68302a324dd33abb04778e8557d88947875cbf4e842c2c01a030c5 \ - --hash=sha256:14762875b22d0055f05d12abc7f7d61d5fd4fe4642ce1a249abdf8c700bf1fd8 \ - --hash=sha256:15492a6368d985b76a2a5fdd2166cddfea5d24e69eefed4630cbaae5c81d89bd \ - --hash=sha256:17c073de315745a1510393a96e680d20af8e67e324f70b42accbd4cb3315c9fb \ - --hash=sha256:209b4a8ee987eccc91e2bd3ac36adee0e53a5970b8ac52c273f7f8fd4872c94c \ - --hash=sha256:230a8f7e24298dea47659251abc0fd8b3c4e38a664c59d4b89cca7f6c09c9e87 \ - --hash=sha256:2e19413bf84934d651344783c9f5e22dee452e251cfd220ebadbed2d9931dbf0 \ - --hash=sha256:393f389841e8f2dfc86f774ad22f00923fdee66d238af89b70ea314c4aefd290 \ - --hash=sha256:3cf75f7cdc2397ed4442594b935a11ed5569961333d49b7539ea741be2cc79d5 \ - --hash=sha256:3d78619672183be860b96ed96f533046ec97ca067fd46ac1f6a09cd9b7484287 \ - --hash=sha256:40eced07f07a9e60e825554a31f923e8d3997cfc7fb31dbc1328c70826e04cde \ - --hash=sha256:493d3299ebe5f5a7c66b9819eacdcfbbaaf1a8e84911ddffcdc48888497afecf \ - --hash=sha256:4b302b45040890cea949ad092479e01ba25911a15e648429c7c5aae9650c67a8 \ - --hash=sha256:515dfef7f869a0feb2afee66b957cc7bbe9ad0cdee45aec7fdc623f4ecd4fb16 \ - --hash=sha256:547da6cacac20666422d4882cfcd51298d45f7ccb60a04ec27424d2f36ba3eaf \ - --hash=sha256:5df68496d19f849921f05f14f31bd6ef53ad4b00245da3195048c69934521809 \ - --hash=sha256:64322071e046020e8797117b3658b9c2f80e3267daec409b350b6a7a05041213 \ - --hash=sha256:7615dab56bb07bff74bc865307aeb89a8bfd9941d2ef9d817b9436da3a0ea54f \ - --hash=sha256:79ebfc238612123a713a457d92afb4096e2148be17df6c50fb9bf7a81c2f8013 \ - --hash=sha256:7b18b97cf8ee5452fa5f4e3af95d01d84d86d32c5e2bfa260cf041749d66360b \ - --hash=sha256:932bb1ea39a54e9ea27fc9232163059a0b8855256f4052e776357ad9add6f1c9 \ - --hash=sha256:a00bb73540af068ca7390e636c01cbc4f644961896fa9363154ff43fd37af2f5 \ - --hash=sha256:a5ca29ee66f8343ed336816c553e82d6cade48a3ad702b9ffa6125d187e2dedb \ - --hash=sha256:af9aa9ef5ba1fd5b8c948bb11f44891968ab30356d65fd0cc6707d989cd521df \ - --hash=sha256:bb437315738aa441251214dad17428cafda9cdc9729499f1d6001748e1d432f4 \ - --hash=sha256:bdb230b4943891321e06fc7def63c7aace16095be7d9cf3b1e01be2f10fba439 \ - --hash=sha256:c6e9dcb4cb338d91a73f178d866d051efe7c62a7166653a91e7d9fb18274058f \ - --hash=sha256:cffe3ab27871bc3ea47df5d8f7013945712c46a3cc5a95b6bee15887f1675c22 \ - --hash=sha256:d012ad7911653a906425d8473a1465caa9f8dea7fcf07b6d870397b774ea7c0f \ - --hash=sha256:d9e13b33afd39ddeb377eff2c1c4f00544e191e1d1dee5b6c51ddee8ea6f0cf5 \ - --hash=sha256:e4b2b334e68b18ac9817d828ba44d8fcb391f6acb398bcc5062b14b2cbeac970 \ - --hash=sha256:e54962802d4b8b18b6207d4a927032826af39395a3bd9196a5af43fc4e60b009 \ - --hash=sha256:f705e12750171c0ab4ef2a3c76b9a4024a62c4103e3a55dd6f99265b9bc6fcfc \ - --hash=sha256:f881853d2643a29e643609da57b96d5f9c9b93f62429dcc1cbb413c7d07f0e1a \ - --hash=sha256:fe60131d21b31fd1a14bd43e6bb88256f69dfc3188b3a89d736d6c71ed43ec95 - # via aiobotocore -aioitertools==0.7.1 \ - --hash=sha256:54a56c7cf3b5290d1cb5e8974353c9f52c677612b5d69a859369a020c53414a3 \ - --hash=sha256:8972308474c41ed5e0636819f948ebff32f2318e70f7e7d23cd208c4357cc773 - # via aiobotocore -asgiref==3.3.4 \ - --hash=sha256:92906c611ce6c967347bbfea733f13d6313901d54dcca88195eaeb52b2a8e8ee \ - --hash=sha256:d1216dfbdfb63826470995d31caed36225dcaf34f182e0fa257a4dd9e86f1b78 - # via django -async-timeout==3.0.1 \ - --hash=sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f \ - --hash=sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3 - # via aiohttp -attrs==20.3.0 \ - --hash=sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6 \ - --hash=sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700 - # via aiohttp -botocore==1.20.49 \ - --hash=sha256:6a672ba41dd00e5c1c1824ca8143d180d88de8736d78c0b1f96b8d3cb0466561 \ - --hash=sha256:f7f103fa0651c69dd360c7d0ecd874854303de5cc0869e0cbc2818a52baacc69 - # via aiobotocore -chardet==4.0.0 \ - --hash=sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa \ - --hash=sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5 - # via aiohttp -colorful==0.5.4 \ - --hash=sha256:86848ad4e2eda60cd2519d8698945d22f6f6551e23e95f3f14dfbb60997807ea \ - --hash=sha256:8d264b52a39aae4c0ba3e2a46afbaec81b0559a99be0d2cfe2aba4cf94531348 - # via thumbor -derpconf==0.8.3 \ - --hash=sha256:1bb152d8a1cf5c2a6d629bf29acd4af0c00811339642fc0a56172b0a83b31a15 - # via thumbor -django-auth-ldap==2.4.0 \ - --hash=sha256:2d869955da8a0c9a4448671bd9826b9f87458f6a9fc20278e84de8a81200a2be \ - --hash=sha256:60fcbfc3141c99c3c49d3ccd7311a3992a231c319d94b6d2c143968f63676676 - # via -r requirements/thumbor.in -django==3.1.8 \ - --hash=sha256:c348b3ddc452bf4b62361f0752f71a339140c777ebea3cdaaaa8fdb7f417a862 \ - --hash=sha256:f8393103e15ec2d2d313ccbb95a3f1da092f9f58d74ac1c61ca2ac0436ae1eac - # via - # -r requirements/thumbor.in - # django-auth-ldap -idna-ssl==1.1.0 \ - --hash=sha256:a933e3bb13da54383f9e8f35dc4f9cb9eb9b3b78c6b36f311254d6d0d92c6c7c - # via aiohttp -idna==3.1 \ - --hash=sha256:5205d03e7bcbb919cc9c19885f9920d622ca52448306f2377daede5cf3faac16 \ - --hash=sha256:c5b02147e01ea9920e6b0a3f1f7bb833612d507592c837a6c49552768f4054e1 - # via - # idna-ssl - # yarl -jmespath==0.10.0 \ - --hash=sha256:b85d0567b8666149a93172712e68920734333c0ce7e89b78b3e987f71e5ed4f9 \ - --hash=sha256:cdf6525904cc597730141d61b36f2e4b8ecc257c420fa2f4549bac2c2d0cb72f - # via botocore -libthumbor==2.0.1 \ - --hash=sha256:3c4e1a59c019d22f868d225315c06f97fad30fb5e78112d6a230b978e7d24e38 \ - --hash=sha256:ed4fe5f27f8f90e7285b7e6dce99c1b67d43a140bf370e989080b43d80ce25f0 - # via thumbor -multidict==5.1.0 \ - --hash=sha256:018132dbd8688c7a69ad89c4a3f39ea2f9f33302ebe567a879da8f4ca73f0d0a \ - --hash=sha256:051012ccee979b2b06be928a6150d237aec75dd6bf2d1eeeb190baf2b05abc93 \ - --hash=sha256:05c20b68e512166fddba59a918773ba002fdd77800cad9f55b59790030bab632 \ - --hash=sha256:07b42215124aedecc6083f1ce6b7e5ec5b50047afa701f3442054373a6deb656 \ - --hash=sha256:0e3c84e6c67eba89c2dbcee08504ba8644ab4284863452450520dad8f1e89b79 \ - --hash=sha256:0e929169f9c090dae0646a011c8b058e5e5fb391466016b39d21745b48817fd7 \ - --hash=sha256:1ab820665e67373de5802acae069a6a05567ae234ddb129f31d290fc3d1aa56d \ - --hash=sha256:25b4e5f22d3a37ddf3effc0710ba692cfc792c2b9edfb9c05aefe823256e84d5 \ - --hash=sha256:2e68965192c4ea61fff1b81c14ff712fc7dc15d2bd120602e4a3494ea6584224 \ - --hash=sha256:2f1a132f1c88724674271d636e6b7351477c27722f2ed789f719f9e3545a3d26 \ - --hash=sha256:37e5438e1c78931df5d3c0c78ae049092877e5e9c02dd1ff5abb9cf27a5914ea \ - --hash=sha256:3a041b76d13706b7fff23b9fc83117c7b8fe8d5fe9e6be45eee72b9baa75f348 \ - --hash=sha256:3a4f32116f8f72ecf2a29dabfb27b23ab7cdc0ba807e8459e59a93a9be9506f6 \ - --hash=sha256:46c73e09ad374a6d876c599f2328161bcd95e280f84d2060cf57991dec5cfe76 \ - --hash=sha256:46dd362c2f045095c920162e9307de5ffd0a1bfbba0a6e990b344366f55a30c1 \ - --hash=sha256:4b186eb7d6ae7c06eb4392411189469e6a820da81447f46c0072a41c748ab73f \ - --hash=sha256:54fd1e83a184e19c598d5e70ba508196fd0bbdd676ce159feb412a4a6664f952 \ - --hash=sha256:585fd452dd7782130d112f7ddf3473ffdd521414674c33876187e101b588738a \ - --hash=sha256:5cf3443199b83ed9e955f511b5b241fd3ae004e3cb81c58ec10f4fe47c7dce37 \ - --hash=sha256:6a4d5ce640e37b0efcc8441caeea8f43a06addace2335bd11151bc02d2ee31f9 \ - --hash=sha256:7df80d07818b385f3129180369079bd6934cf70469f99daaebfac89dca288359 \ - --hash=sha256:806068d4f86cb06af37cd65821554f98240a19ce646d3cd24e1c33587f313eb8 \ - --hash=sha256:830f57206cc96ed0ccf68304141fec9481a096c4d2e2831f311bde1c404401da \ - --hash=sha256:929006d3c2d923788ba153ad0de8ed2e5ed39fdbe8e7be21e2f22ed06c6783d3 \ - --hash=sha256:9436dc58c123f07b230383083855593550c4d301d2532045a17ccf6eca505f6d \ - --hash=sha256:9dd6e9b1a913d096ac95d0399bd737e00f2af1e1594a787e00f7975778c8b2bf \ - --hash=sha256:ace010325c787c378afd7f7c1ac66b26313b3344628652eacd149bdd23c68841 \ - --hash=sha256:b47a43177a5e65b771b80db71e7be76c0ba23cc8aa73eeeb089ed5219cdbe27d \ - --hash=sha256:b797515be8743b771aa868f83563f789bbd4b236659ba52243b735d80b29ed93 \ - --hash=sha256:b7993704f1a4b204e71debe6095150d43b2ee6150fa4f44d6d966ec356a8d61f \ - --hash=sha256:d5c65bdf4484872c4af3150aeebe101ba560dcfb34488d9a8ff8dbcd21079647 \ - --hash=sha256:d81eddcb12d608cc08081fa88d046c78afb1bf8107e6feab5d43503fea74a635 \ - --hash=sha256:dc862056f76443a0db4509116c5cd480fe1b6a2d45512a653f9a855cc0517456 \ - --hash=sha256:ecc771ab628ea281517e24fd2c52e8f31c41e66652d07599ad8818abaad38cda \ - --hash=sha256:f200755768dc19c6f4e2b672421e0ebb3dd54c38d5a4f262b872d8cfcc9e93b5 \ - --hash=sha256:f21756997ad8ef815d8ef3d34edd98804ab5ea337feedcd62fb52d22bf531281 \ - --hash=sha256:fc13a9524bc18b6fb6e0dbec3533ba0496bbed167c56d0aabefd965584557d80 - # via - # aiohttp - # yarl -numpy==1.19.5 \ - --hash=sha256:012426a41bc9ab63bb158635aecccc7610e3eff5d31d1eb43bc099debc979d94 \ - --hash=sha256:06fab248a088e439402141ea04f0fffb203723148f6ee791e9c75b3e9e82f080 \ - --hash=sha256:0eef32ca3132a48e43f6a0f5a82cb508f22ce5a3d6f67a8329c81c8e226d3f6e \ - --hash=sha256:1ded4fce9cfaaf24e7a0ab51b7a87be9038ea1ace7f34b841fe3b6894c721d1c \ - --hash=sha256:2e55195bc1c6b705bfd8ad6f288b38b11b1af32f3c8289d6c50d47f950c12e76 \ - --hash=sha256:2ea52bd92ab9f768cc64a4c3ef8f4b2580a17af0a5436f6126b08efbd1838371 \ - --hash=sha256:36674959eed6957e61f11c912f71e78857a8d0604171dfd9ce9ad5cbf41c511c \ - --hash=sha256:384ec0463d1c2671170901994aeb6dce126de0a95ccc3976c43b0038a37329c2 \ - --hash=sha256:39b70c19ec771805081578cc936bbe95336798b7edf4732ed102e7a43ec5c07a \ - --hash=sha256:400580cbd3cff6ffa6293df2278c75aef2d58d8d93d3c5614cd67981dae68ceb \ - --hash=sha256:43d4c81d5ffdff6bae58d66a3cd7f54a7acd9a0e7b18d97abb255defc09e3140 \ - --hash=sha256:50a4a0ad0111cc1b71fa32dedd05fa239f7fb5a43a40663269bb5dc7877cfd28 \ - --hash=sha256:603aa0706be710eea8884af807b1b3bc9fb2e49b9f4da439e76000f3b3c6ff0f \ - --hash=sha256:6149a185cece5ee78d1d196938b2a8f9d09f5a5ebfbba66969302a778d5ddd1d \ - --hash=sha256:759e4095edc3c1b3ac031f34d9459fa781777a93ccc633a472a5468587a190ff \ - --hash=sha256:7fb43004bce0ca31d8f13a6eb5e943fa73371381e53f7074ed21a4cb786c32f8 \ - --hash=sha256:811daee36a58dc79cf3d8bdd4a490e4277d0e4b7d103a001a4e73ddb48e7e6aa \ - --hash=sha256:8b5e972b43c8fc27d56550b4120fe6257fdc15f9301914380b27f74856299fea \ - --hash=sha256:99abf4f353c3d1a0c7a5f27699482c987cf663b1eac20db59b8c7b061eabd7fc \ - --hash=sha256:a0d53e51a6cb6f0d9082decb7a4cb6dfb33055308c4c44f53103c073f649af73 \ - --hash=sha256:a12ff4c8ddfee61f90a1633a4c4afd3f7bcb32b11c52026c92a12e1325922d0d \ - --hash=sha256:a4646724fba402aa7504cd48b4b50e783296b5e10a524c7a6da62e4a8ac9698d \ - --hash=sha256:a76f502430dd98d7546e1ea2250a7360c065a5fdea52b2dffe8ae7180909b6f4 \ - --hash=sha256:a9d17f2be3b427fbb2bce61e596cf555d6f8a56c222bd2ca148baeeb5e5c783c \ - --hash=sha256:ab83f24d5c52d60dbc8cd0528759532736b56db58adaa7b5f1f76ad551416a1e \ - --hash=sha256:aeb9ed923be74e659984e321f609b9ba54a48354bfd168d21a2b072ed1e833ea \ - --hash=sha256:c843b3f50d1ab7361ca4f0b3639bf691569493a56808a0b0c54a051d260b7dbd \ - --hash=sha256:cae865b1cae1ec2663d8ea56ef6ff185bad091a5e33ebbadd98de2cfa3fa668f \ - --hash=sha256:cc6bd4fd593cb261332568485e20a0712883cf631f6f5e8e86a52caa8b2b50ff \ - --hash=sha256:cf2402002d3d9f91c8b01e66fbb436a4ed01c6498fffed0e4c7566da1d40ee1e \ - --hash=sha256:d051ec1c64b85ecc69531e1137bb9751c6830772ee5c1c426dbcfe98ef5788d7 \ - --hash=sha256:d6631f2e867676b13026e2846180e2c13c1e11289d67da08d71cacb2cd93d4aa \ - --hash=sha256:dbd18bcf4889b720ba13a27ec2f2aac1981bd41203b3a3b27ba7a33f88ae4827 \ - --hash=sha256:df609c82f18c5b9f6cb97271f03315ff0dbe481a2a02e56aeb1b1a985ce38e60 - # via opencv-python-headless -opencv-python-headless==4.5.1.48 \ - --hash=sha256:0e02809db2968e54f3c23340be6ff9a1428b3f03f5dca7cd5aceda66e319ce86 \ - --hash=sha256:1f7c14f5d4e5af4dc4669fc6b4a983b36072a934c439ac11266b930496da8255 \ - --hash=sha256:243aea91cc1e36a47c46da4cc408071af39444a48df1fe1539ea8d7990500fd2 \ - --hash=sha256:2560dcf3c1158226b066302f777bfe0f65282410b8d90871dd872306c967d1f1 \ - --hash=sha256:2e6a9a88617a0ef7219cff24ba78a58416670a77e6ac63975f9009af3319ab63 \ - --hash=sha256:372149d007e20bf556b7687591d22b58b56b3c225f492da051d81587e5dc7411 \ - --hash=sha256:522f12dd994e064a30562adfd63b9439099bd7c80819f5261c37ebe593283c9e \ - --hash=sha256:526b9e19cf6300f0891d8f427eac1048091912332bb781eb4957a4994bfbe608 \ - --hash=sha256:5f0c7d34fa9953706c2a1a6d2760a91dc5a68cab3df16af61609894c6c8586f1 \ - --hash=sha256:657cdd9fbbbbb7e898ae3d9b0649b367d0e440d429c714104d069c5612d578bb \ - --hash=sha256:65c9ea57be5ebcaed009b3fee14fe59f3b6aa1e573fe08c5039ff057ad593c53 \ - --hash=sha256:777fb596e04331f73ef5b0c1faa4d33348f29ca58216d9286355c16f5489c939 \ - --hash=sha256:7c75680ffdf32d7044415a215d1fc60dbec14a7f2f0b59a85f0f74ef5efcb6ad \ - --hash=sha256:924aa4c34ead0b817309f42291dc526b2a7755476afe3009d1e275fc3090d92d \ - --hash=sha256:96d1da6ad061d8f3509668d398d14dd8265e529d6407f87eb26e7f4ddf043cc0 \ - --hash=sha256:9aa04a491c534531029fbac61da961fae0bf4abb1786eed9c91befde4ca7bd81 \ - --hash=sha256:a322d4df14c3a5f19701a023b3da91e9b8af8653b0d2ee0c50b0b341212f7343 \ - --hash=sha256:aa562c520f46283423ba8fac29099458e42deab697a9abd0491622e421c5c454 \ - --hash=sha256:ba2f0bd46e9534f29969e39f7895cbea9764173102b0c04b7818b8a9910d66e4 \ - --hash=sha256:d16825755e7b5a6d8737f93e116670229e1510199e0af9213004e187ae0dbcc5 \ - --hash=sha256:e3027e0d1b71b68b5cfe1ea9c627e323dff71112c854ba19805258d8fc6c630e \ - --hash=sha256:f2011ecb3980bbed283d17d43e0f1221bac88c0cac1a6fb59a056544de2df2f7 \ - --hash=sha256:f5e40a06116460ef2fd2d1c24be3b65f8bfb5fcdfe433f3fc01bcb4c2eb485bf \ - --hash=sha256:f7f8e4f7c63c8e95eb210f4cba88d0069a0a964d6335d7a35b07f0d0baa13558 \ - --hash=sha256:fe02a943b1a28b505e954fbce24e867119a3eb4351f93adad55c6cfe81a70484 - # via thumbor -pillow==7.2.0 \ - --hash=sha256:0295442429645fa16d05bd567ef5cff178482439c9aad0411d3f0ce9b88b3a6f \ - --hash=sha256:06aba4169e78c439d528fdeb34762c3b61a70813527a2c57f0540541e9f433a8 \ - --hash=sha256:09d7f9e64289cb40c2c8d7ad674b2ed6105f55dc3b09aa8e4918e20a0311e7ad \ - --hash=sha256:0a80dd307a5d8440b0a08bd7b81617e04d870e40a3e46a32d9c246e54705e86f \ - --hash=sha256:1ca594126d3c4def54babee699c055a913efb01e106c309fa6b04405d474d5ae \ - --hash=sha256:25930fadde8019f374400f7986e8404c8b781ce519da27792cbe46eabec00c4d \ - --hash=sha256:431b15cffbf949e89df2f7b48528be18b78bfa5177cb3036284a5508159492b5 \ - --hash=sha256:52125833b070791fcb5710fabc640fc1df07d087fc0c0f02d3661f76c23c5b8b \ - --hash=sha256:5e51ee2b8114def244384eda1c82b10e307ad9778dac5c83fb0943775a653cd8 \ - --hash=sha256:612cfda94e9c8346f239bf1a4b082fdd5c8143cf82d685ba2dba76e7adeeb233 \ - --hash=sha256:6d7741e65835716ceea0fd13a7d0192961212fd59e741a46bbed7a473c634ed6 \ - --hash=sha256:6edb5446f44d901e8683ffb25ebdfc26988ee813da3bf91e12252b57ac163727 \ - --hash=sha256:725aa6cfc66ce2857d585f06e9519a1cc0ef6d13f186ff3447ab6dff0a09bc7f \ - --hash=sha256:8dad18b69f710bf3a001d2bf3afab7c432785d94fcf819c16b5207b1cfd17d38 \ - --hash=sha256:94cf49723928eb6070a892cb39d6c156f7b5a2db4e8971cb958f7b6b104fb4c4 \ - --hash=sha256:97f9e7953a77d5a70f49b9a48da7776dc51e9b738151b22dacf101641594a626 \ - --hash=sha256:9ad7f865eebde135d526bb3163d0b23ffff365cf87e767c649550964ad72785d \ - --hash=sha256:9c87ef410a58dd54b92424ffd7e28fd2ec65d2f7fc02b76f5e9b2067e355ebf6 \ - --hash=sha256:a060cf8aa332052df2158e5a119303965be92c3da6f2d93b6878f0ebca80b2f6 \ - --hash=sha256:c79f9c5fb846285f943aafeafda3358992d64f0ef58566e23484132ecd8d7d63 \ - --hash=sha256:c92302a33138409e8f1ad16731568c55c9053eee71bb05b6b744067e1b62380f \ - --hash=sha256:d08b23fdb388c0715990cbc06866db554e1822c4bdcf6d4166cf30ac82df8c41 \ - --hash=sha256:d350f0f2c2421e65fbc62690f26b59b0bcda1b614beb318c81e38647e0f673a1 \ - --hash=sha256:e901964262a56d9ea3c2693df68bc9860b8bdda2b04768821e4c44ae797de117 \ - --hash=sha256:ec29604081f10f16a7aea809ad42e27764188fc258b02259a03a8ff7ded3808d \ - --hash=sha256:edf31f1150778abd4322444c393ab9c7bd2af271dd4dafb4208fb613b1f3cdc9 \ - --hash=sha256:f7e30c27477dffc3e85c2463b3e649f751789e0f6c8456099eea7ddd53be4a8a \ - --hash=sha256:ffe538682dc19cc542ae7c3e504fdf54ca7f86fb8a135e59dd6bc8627eae6cce - # via thumbor -pyasn1-modules==0.2.8 \ - --hash=sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e \ - --hash=sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74 - # via python-ldap -pyasn1==0.4.8 \ - --hash=sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d \ - --hash=sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba - # via - # pyasn1-modules - # python-ldap -pycurl==7.43.0.6 \ - --hash=sha256:8301518689daefa53726b59ded6b48f33751c383cf987b0ccfbbc4ed40281325 - # via -r requirements/thumbor.in -python-dateutil==2.8.1 \ - --hash=sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c \ - --hash=sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a - # via - # botocore - # tc-aws -python-ldap==3.3.1 \ - --hash=sha256:4711cacf013e298754abd70058ccc995758177fb425f1c2d30e71adfc1d00aa5 - # via django-auth-ldap -pytz==2019.3 \ - --hash=sha256:1c557d7d0e871de1f5ccd5833f60fb2550652da6be2693c1e02300743d21500d \ - --hash=sha256:b02c06db6cf09c12dd25137e563b31700d3b80fcc4ad23abb7a315f2789819be - # via - # django - # thumbor -six==1.15.0 \ - --hash=sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259 \ - --hash=sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced - # via - # derpconf - # libthumbor - # python-dateutil -sqlparse==0.4.1 \ - --hash=sha256:017cde379adbd6a1f15a61873f43e8274179378e95ef3fede90b5aa64d304ed0 \ - --hash=sha256:0f91fd2e829c44362cbcfab3e9ae12e22badaa8a29ad5ff599f9ec109f0454e8 - # via django -statsd==3.3.0 \ - --hash=sha256:c610fb80347fca0ef62666d241bce64184bd7cc1efe582f9690e045c25535eaa \ - --hash=sha256:e3e6db4c246f7c59003e51c9720a51a7f39a396541cb9b147ff4b14d15b5dd1f - # via thumbor -https://github.com/kkopachev/aws/archive/b5058e6b9fec7354629acc6d5df423e0310bb0cd.zip#egg=tc_aws==6.3 \ - --hash=sha256:8a28437b0dfab88c89f280a2d6ec55a6abfa3e26d495dc15e1b3f38744e27f0c - # via -r requirements/thumbor.in -thumbor==7.0.0a5 \ - --hash=sha256:5042c9c8facf0da028a22f1aee717f856d213ec037835ca0edaa0282217654bb - # via - # -r requirements/thumbor.in - # tc-aws -tornado==6.1 \ - --hash=sha256:0a00ff4561e2929a2c37ce706cb8233b7907e0cdc22eab98888aca5dd3775feb \ - --hash=sha256:0d321a39c36e5f2c4ff12b4ed58d41390460f798422c4504e09eb5678e09998c \ - --hash=sha256:1e8225a1070cd8eec59a996c43229fe8f95689cb16e552d130b9793cb570a288 \ - --hash=sha256:20241b3cb4f425e971cb0a8e4ffc9b0a861530ae3c52f2b0434e6c1b57e9fd95 \ - --hash=sha256:25ad220258349a12ae87ede08a7b04aca51237721f63b1808d39bdb4b2164558 \ - --hash=sha256:33892118b165401f291070100d6d09359ca74addda679b60390b09f8ef325ffe \ - --hash=sha256:33c6e81d7bd55b468d2e793517c909b139960b6c790a60b7991b9b6b76fb9791 \ - --hash=sha256:3447475585bae2e77ecb832fc0300c3695516a47d46cefa0528181a34c5b9d3d \ - --hash=sha256:34ca2dac9e4d7afb0bed4677512e36a52f09caa6fded70b4e3e1c89dbd92c326 \ - --hash=sha256:3e63498f680547ed24d2c71e6497f24bca791aca2fe116dbc2bd0ac7f191691b \ - --hash=sha256:548430be2740e327b3fe0201abe471f314741efcb0067ec4f2d7dcfb4825f3e4 \ - --hash=sha256:6196a5c39286cc37c024cd78834fb9345e464525d8991c21e908cc046d1cc02c \ - --hash=sha256:61b32d06ae8a036a6607805e6720ef00a3c98207038444ba7fd3d169cd998910 \ - --hash=sha256:6286efab1ed6e74b7028327365cf7346b1d777d63ab30e21a0f4d5b275fc17d5 \ - --hash=sha256:65d98939f1a2e74b58839f8c4dab3b6b3c1ce84972ae712be02845e65391ac7c \ - --hash=sha256:66324e4e1beede9ac79e60f88de548da58b1f8ab4b2f1354d8375774f997e6c0 \ - --hash=sha256:6c77c9937962577a6a76917845d06af6ab9197702a42e1346d8ae2e76b5e3675 \ - --hash=sha256:70dec29e8ac485dbf57481baee40781c63e381bebea080991893cd297742b8fd \ - --hash=sha256:7250a3fa399f08ec9cb3f7b1b987955d17e044f1ade821b32e5f435130250d7f \ - --hash=sha256:748290bf9112b581c525e6e6d3820621ff020ed95af6f17fedef416b27ed564c \ - --hash=sha256:7da13da6f985aab7f6f28debab00c67ff9cbacd588e8477034c0652ac141feea \ - --hash=sha256:8f959b26f2634a091bb42241c3ed8d3cedb506e7c27b8dd5c7b9f745318ddbb6 \ - --hash=sha256:9de9e5188a782be6b1ce866e8a51bc76a0fbaa0e16613823fc38e4fc2556ad05 \ - --hash=sha256:a48900ecea1cbb71b8c71c620dee15b62f85f7c14189bdeee54966fbd9a0c5bd \ - --hash=sha256:b87936fd2c317b6ee08a5741ea06b9d11a6074ef4cc42e031bc6403f82a32575 \ - --hash=sha256:c77da1263aa361938476f04c4b6c8916001b90b2c2fdd92d8d535e1af48fba5a \ - --hash=sha256:cb5ec8eead331e3bb4ce8066cf06d2dfef1bfb1b2a73082dfe8a161301b76e37 \ - --hash=sha256:cc0ee35043162abbf717b7df924597ade8e5395e7b66d18270116f8745ceb795 \ - --hash=sha256:d14d30e7f46a0476efb0deb5b61343b1526f73ebb5ed84f23dc794bdb88f9d9f \ - --hash=sha256:d371e811d6b156d82aa5f9a4e08b58debf97c302a35714f6f45e35139c332e32 \ - --hash=sha256:d3d20ea5782ba63ed13bc2b8c291a053c8d807a8fa927d941bd718468f7b950c \ - --hash=sha256:d3f7594930c423fd9f5d1a76bee85a2c36fd8b4b16921cae7e965f22575e9c01 \ - --hash=sha256:dcef026f608f678c118779cd6591c8af6e9b4155c44e0d1bc0c87c036fb8c8c4 \ - --hash=sha256:e0791ac58d91ac58f694d8d2957884df8e4e2f6687cdf367ef7eb7497f79eaa2 \ - --hash=sha256:e385b637ac3acaae8022e7e47dfa7b83d3620e432e3ecb9a3f7f58f150e50921 \ - --hash=sha256:e519d64089b0876c7b467274468709dadf11e41d65f63bba207e04217f47c085 \ - --hash=sha256:e7229e60ac41a1202444497ddde70a48d33909e484f96eb0da9baf8dc68541df \ - --hash=sha256:ed3ad863b1b40cd1d4bd21e7498329ccaece75db5a5bf58cd3c9f130843e7102 \ - --hash=sha256:f0ba29bafd8e7e22920567ce0d232c26d4d47c8b5cf4ed7b562b5db39fa199c5 \ - --hash=sha256:fa2ba70284fa42c2a5ecb35e322e68823288a4251f9ba9cc77be04ae15eada68 \ - --hash=sha256:fba85b6cd9c39be262fcd23865652920832b61583de2a2ca907dbd8e8a8c81e5 - # via thumbor -typing-extensions==3.7.4.3 \ - --hash=sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918 \ - --hash=sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c \ - --hash=sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f - # via - # aiohttp - # aioitertools - # asgiref - # yarl -urllib3==1.26.4 \ - --hash=sha256:2f4da4594db7e1e110a944bb1b551fdf4e6c136ad42e4234131391e21eb5b0df \ - --hash=sha256:e7b021f7241115872f92f43c6508082facffbd1c048e3c6e2bb9c2a157e28937 - # via botocore -virtualenv-clone==0.5.4 \ - --hash=sha256:07e74418b7cc64f4fda987bf5bc71ebd59af27a7bc9e8a8ee9fd54b1f2390a27 \ - --hash=sha256:665e48dd54c84b98b71a657acb49104c54e7652bce9c1c4f6c6976ed4c827a29 - # via -r requirements/thumbor.in -webcolors==1.11.1 \ - --hash=sha256:76f360636957d1c976db7466bc71dcb713bb95ac8911944dffc55c01cb516de6 \ - --hash=sha256:b8cd5d865a25c51ff1218f0c90d0c0781fc64312a49b746b320cf50de1648f6e - # via thumbor -wrapt==1.12.1 \ - --hash=sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7 - # via aiobotocore -yarl==1.6.3 \ - --hash=sha256:00d7ad91b6583602eb9c1d085a2cf281ada267e9a197e8b7cae487dadbfa293e \ - --hash=sha256:0355a701b3998dcd832d0dc47cc5dedf3874f966ac7f870e0f3a6788d802d434 \ - --hash=sha256:15263c3b0b47968c1d90daa89f21fcc889bb4b1aac5555580d74565de6836366 \ - --hash=sha256:2ce4c621d21326a4a5500c25031e102af589edb50c09b321049e388b3934eec3 \ - --hash=sha256:31ede6e8c4329fb81c86706ba8f6bf661a924b53ba191b27aa5fcee5714d18ec \ - --hash=sha256:324ba3d3c6fee56e2e0b0d09bf5c73824b9f08234339d2b788af65e60040c959 \ - --hash=sha256:329412812ecfc94a57cd37c9d547579510a9e83c516bc069470db5f75684629e \ - --hash=sha256:4736eaee5626db8d9cda9eb5282028cc834e2aeb194e0d8b50217d707e98bb5c \ - --hash=sha256:4953fb0b4fdb7e08b2f3b3be80a00d28c5c8a2056bb066169de00e6501b986b6 \ - --hash=sha256:4c5bcfc3ed226bf6419f7a33982fb4b8ec2e45785a0561eb99274ebbf09fdd6a \ - --hash=sha256:547f7665ad50fa8563150ed079f8e805e63dd85def6674c97efd78eed6c224a6 \ - --hash=sha256:5b883e458058f8d6099e4420f0cc2567989032b5f34b271c0827de9f1079a424 \ - --hash=sha256:63f90b20ca654b3ecc7a8d62c03ffa46999595f0167d6450fa8383bab252987e \ - --hash=sha256:68dc568889b1c13f1e4745c96b931cc94fdd0defe92a72c2b8ce01091b22e35f \ - --hash=sha256:69ee97c71fee1f63d04c945f56d5d726483c4762845400a6795a3b75d56b6c50 \ - --hash=sha256:6d6283d8e0631b617edf0fd726353cb76630b83a089a40933043894e7f6721e2 \ - --hash=sha256:72a660bdd24497e3e84f5519e57a9ee9220b6f3ac4d45056961bf22838ce20cc \ - --hash=sha256:73494d5b71099ae8cb8754f1df131c11d433b387efab7b51849e7e1e851f07a4 \ - --hash=sha256:7356644cbed76119d0b6bd32ffba704d30d747e0c217109d7979a7bc36c4d970 \ - --hash=sha256:8a9066529240171b68893d60dca86a763eae2139dd42f42106b03cf4b426bf10 \ - --hash=sha256:8aa3decd5e0e852dc68335abf5478a518b41bf2ab2f330fe44916399efedfae0 \ - --hash=sha256:97b5bdc450d63c3ba30a127d018b866ea94e65655efaf889ebeabc20f7d12406 \ - --hash=sha256:9ede61b0854e267fd565e7527e2f2eb3ef8858b301319be0604177690e1a3896 \ - --hash=sha256:b2e9a456c121e26d13c29251f8267541bd75e6a1ccf9e859179701c36a078643 \ - --hash=sha256:b5dfc9a40c198334f4f3f55880ecf910adebdcb2a0b9a9c23c9345faa9185721 \ - --hash=sha256:bafb450deef6861815ed579c7a6113a879a6ef58aed4c3a4be54400ae8871478 \ - --hash=sha256:c49ff66d479d38ab863c50f7bb27dee97c6627c5fe60697de15529da9c3de724 \ - --hash=sha256:ce3beb46a72d9f2190f9e1027886bfc513702d748047b548b05dab7dfb584d2e \ - --hash=sha256:d26608cf178efb8faa5ff0f2d2e77c208f471c5a3709e577a7b3fd0445703ac8 \ - --hash=sha256:d597767fcd2c3dc49d6eea360c458b65643d1e4dbed91361cf5e36e53c1f8c96 \ - --hash=sha256:d5c32c82990e4ac4d8150fd7652b972216b204de4e83a122546dce571c1bdf25 \ - --hash=sha256:d8d07d102f17b68966e2de0e07bfd6e139c7c02ef06d3a0f8d2f0f055e13bb76 \ - --hash=sha256:e46fba844f4895b36f4c398c5af062a9808d1f26b2999c58909517384d5deda2 \ - --hash=sha256:e6b5460dc5ad42ad2b36cca524491dfcaffbfd9c8df50508bddc354e787b8dc2 \ - --hash=sha256:f040bcc6725c821a4c0665f3aa96a4d0805a7aaf2caf266d256b8ed71b9f041c \ - --hash=sha256:f0b059678fd549c66b89bed03efcabb009075bd131c248ecdf087bdb6faba24a \ - --hash=sha256:fcbb48a93e8699eae920f8d92f7160c03567b421bc17362a9ffbbd706a816f71 - # via aiohttp diff --git a/scripts/lib/clean_venv_cache.py b/scripts/lib/clean_venv_cache.py index 816161bbd2..2698d9e2e8 100755 --- a/scripts/lib/clean_venv_cache.py +++ b/scripts/lib/clean_venv_cache.py @@ -32,7 +32,6 @@ def get_caches_in_use(threshold_days: int) -> Set[str]: setups_to_check |= get_recent_deployments(threshold_days) if ENV == "dev": add_current_venv_cache("zulip-py3-venv") - add_current_venv_cache("zulip-thumbor-venv") for path in setups_to_check: reqs_dir = os.path.join(path, "requirements") diff --git a/scripts/lib/create-thumbor-venv b/scripts/lib/create-thumbor-venv deleted file mode 100755 index 84b0d2c5b2..0000000000 --- a/scripts/lib/create-thumbor-venv +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env python3 -import argparse -import os -import sys - -ZULIP_PATH = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) -if ZULIP_PATH not in sys.path: - sys.path.append(ZULIP_PATH) - -from scripts.lib.setup_venv import ( - THUMBOR_VENV_DEPENDENCIES, - YUM_THUMBOR_VENV_DEPENDENCIES, - setup_virtualenv, -) -from scripts.lib.zulip_tools import os_families, parse_os_release, run - -parser = argparse.ArgumentParser(description="Create a thumbor virtualenv with caching") -parser.add_argument("deploy_path") -args = parser.parse_args() - -# install dependencies for setting up the virtualenv -distro_info = parse_os_release() -if "debian" in os_families(): - run(["apt-get", "-y", "install", *THUMBOR_VENV_DEPENDENCIES]) -elif "fedora" in os_families(): - run(["yum", "-y", "install", *YUM_THUMBOR_VENV_DEPENDENCIES]) -else: - print("Unsupported platform: {}".format(distro_info["ID"])) - sys.exit(1) - -venv_name = "zulip-thumbor-venv" -cached_venv_path = setup_virtualenv( - os.path.join(args.deploy_path, venv_name), - os.path.join(ZULIP_PATH, "requirements", "thumbor.txt"), -) diff --git a/scripts/lib/install b/scripts/lib/install index 4bb77e2b85..73bbdf0555 100755 --- a/scripts/lib/install +++ b/scripts/lib/install @@ -365,7 +365,6 @@ fi # Create and activate a virtualenv if [ "$VIRTUALENV_NEEDED" = "yes" ]; then "$ZULIP_PATH"/scripts/lib/create-production-venv "$ZULIP_PATH" - "$ZULIP_PATH"/scripts/lib/create-thumbor-venv "$ZULIP_PATH" fi "$ZULIP_PATH"/scripts/lib/install-node diff --git a/scripts/lib/setup_venv.py b/scripts/lib/setup_venv.py index a37cb8c276..01b5b96229 100644 --- a/scripts/lib/setup_venv.py +++ b/scripts/lib/setup_venv.py @@ -69,24 +69,6 @@ FEDORA_VENV_DEPENDENCIES = [ "virtualenv", # see https://unix.stackexchange.com/questions/27877/install-virtualenv-on-fedora-16 ] -THUMBOR_VENV_DEPENDENCIES = [ - "libcurl4-openssl-dev", - "libjpeg-dev", - "zlib1g-dev", - "libfreetype6-dev", - "libpng-dev", - "gifsicle", -] - -YUM_THUMBOR_VENV_DEPENDENCIES = [ - "libcurl-devel", - "libjpeg-turbo-devel", - "zlib-devel", - "freetype-devel", - "libpng-devel", - "gifsicle", -] - def get_venv_dependencies(vendor: str, os_version: str) -> List[str]: if "debian" in os_families(): diff --git a/scripts/lib/upgrade-zulip-stage-2 b/scripts/lib/upgrade-zulip-stage-2 index 668d2334b6..7969e54852 100755 --- a/scripts/lib/upgrade-zulip-stage-2 +++ b/scripts/lib/upgrade-zulip-stage-2 @@ -169,11 +169,6 @@ subprocess.check_call( [os.path.join(deploy_path, "scripts", "lib", "create-production-venv"), deploy_path] ) -# Set up the thumbor venv -subprocess.check_call( - [os.path.join(deploy_path, "scripts", "lib", "create-thumbor-venv"), deploy_path] -) - # Make sure the right version of node is installed subprocess.check_call([os.path.join(deploy_path, "scripts", "lib", "install-node"), deploy_path]) @@ -279,7 +274,6 @@ class_renames = { "zulip::postgres_appdb_tuned": "zulip::profile::postgresql", "zulip::postgres_backups": "zulip::postgresql_backups", "zulip::rabbit": "zulip::profile::rabbitmq", - "zulip::thumbor": "zulip::profile::thumbor", "zulip::voyager": "zulip::profile::standalone", } classes = re.split(r"\s*,\s*", get_config(config_file, "machine", "puppet_classes")) diff --git a/scripts/restart-server b/scripts/restart-server index d35eeefcf1..fcefe81907 100755 --- a/scripts/restart-server +++ b/scripts/restart-server @@ -87,8 +87,6 @@ else: worker_status.check_returncode() workers = [status_line.split()[0] for status_line in worker_status.stdout.splitlines()] -if os.path.exists("/etc/supervisor/conf.d/zulip/thumbor.conf"): - workers.append("zulip-thumbor") if os.path.exists("/etc/supervisor/conf.d/zulip/zulip_db.conf"): workers.append("process-fts-updates") diff --git a/scripts/setup/generate_secrets.py b/scripts/setup/generate_secrets.py index 08e606f262..ac4f6ec4bc 100755 --- a/scripts/setup/generate_secrets.py +++ b/scripts/setup/generate_secrets.py @@ -23,7 +23,6 @@ AUTOGENERATED_SETTINGS = [ "avatar_salt", "rabbitmq_password", "shared_secret", - "thumbor_key", ] diff --git a/scripts/stop-server b/scripts/stop-server index accc150f06..3a8c9eb9f0 100755 --- a/scripts/stop-server +++ b/scripts/stop-server @@ -25,9 +25,6 @@ services = [] if os.path.exists("/etc/supervisor/conf.d/zulip/zulip_db.conf"): services.append("process-fts-updates") -if os.path.exists("/etc/supervisor/conf.d/zulip/thumbor.conf"): - services.append("zulip-thumbor") - # Contrary to the order in (re)start-server, we stop django before the # workers, to increase the chance that we finish processing any work # that may have been enqueued by the Django, leaving the final state diff --git a/static/js/lightbox.js b/static/js/lightbox.js index c02b715b52..2036e3cced 100644 --- a/static/js/lightbox.js +++ b/static/js/lightbox.js @@ -234,7 +234,6 @@ export function parse_image_data(image) { $source = $parent.attr("data-id"); } else { $type = "image"; - // thumbor supplies the src as thumbnail, data-src-fullsize as full-sized. if ($image.attr("data-src-fullsize")) { $source = $image.attr("data-src-fullsize"); } else { diff --git a/tools/lib/provision.py b/tools/lib/provision.py index 4ab703ff96..1df135110b 100755 --- a/tools/lib/provision.py +++ b/tools/lib/provision.py @@ -15,11 +15,7 @@ sys.path.append(ZULIP_PATH) from typing import TYPE_CHECKING, List from scripts.lib.node_cache import NODE_MODULES_CACHE_PATH, setup_node_modules -from scripts.lib.setup_venv import ( - THUMBOR_VENV_DEPENDENCIES, - YUM_THUMBOR_VENV_DEPENDENCIES, - get_venv_dependencies, -) +from scripts.lib.setup_venv import get_venv_dependencies from scripts.lib.zulip_tools import ( ENDC, FAIL, @@ -159,7 +155,6 @@ UBUNTU_COMMON_APT_DEPENDENCIES = [ "libxss1", "xvfb", # Puppeteer dependencies end here. - *THUMBOR_VENV_DEPENDENCIES, ] COMMON_YUM_DEPENDENCIES = [ @@ -179,7 +174,6 @@ COMMON_YUM_DEPENDENCIES = [ "mesa-libgbm", "xorg-x11-server-Xvfb", # Puppeteer dependencies end here. - *YUM_THUMBOR_VENV_DEPENDENCIES, ] BUILD_PGROONGA_FROM_SOURCE = False diff --git a/tools/run-dev.py b/tools/run-dev.py index e98d605948..9b06e9d31d 100755 --- a/tools/run-dev.py +++ b/tools/run-dev.py @@ -50,7 +50,7 @@ parser.add_argument( dest="clear_memcached", help="Do not clear memcached on startup", ) -parser.add_argument("--streamlined", action="store_true", help="Avoid thumbor, etc.") +parser.add_argument("--streamlined", action="store_true", help="Avoid process_queue, etc.") parser.add_argument( "--enable-tornado-logging", action="store_true", @@ -98,7 +98,6 @@ proxy_port = base_port django_port = base_port + 1 tornado_port = base_port + 2 webpack_port = base_port + 3 -thumbor_port = base_port + 4 os.chdir(os.path.join(os.path.dirname(__file__), "..")) @@ -149,7 +148,7 @@ def server_processes() -> List[List[str]]: if options.streamlined: # The streamlined operation allows us to do many - # things, but search/thumbor/etc. features won't work. + # things, but search/etc. features won't work. return main_cmds other_cmds = [ @@ -161,11 +160,6 @@ def server_processes() -> List[List[str]]: "--quiet", ], ["./manage.py", "deliver_scheduled_messages"], - [ - "/srv/zulip-thumbor-venv/bin/thumbor", - "--conf=./zthumbor/thumbor_settings.py", - f"--port={thumbor_port}", - ], ] # NORMAL (but slower) operation: @@ -200,8 +194,6 @@ def transform_url(protocol: str, path: str, query: str, target_port: int, target host = ":".join((target_host, str(target_port))) # Here we are going to rewrite the path a bit so that it is in parity with # what we will have for production - if path.startswith("/thumbor"): - path = path[len("/thumbor") :] newpath = urlunparse((protocol, host, path, "", query, "")) return newpath @@ -320,10 +312,6 @@ class TornadoHandler(BaseHandler): target_port = tornado_port -class ThumborHandler(BaseHandler): - target_port = thumbor_port - - class ErrorHandler(BaseHandler): @web.asynchronous def prepare(self) -> None: @@ -333,17 +321,12 @@ class ErrorHandler(BaseHandler): self.finish() -def using_thumbor() -> bool: - return not options.streamlined - - class Application(web.Application): def __init__(self, enable_logging: bool = False) -> None: handlers = [ (r"/json/events.*", TornadoHandler), (r"/api/v1/events.*", TornadoHandler), (r"/webpack.*", WebPackHandler), - (r"/thumbor.*", ThumborHandler if using_thumbor() else ErrorHandler), (r"/.*", DjangoHandler), ] super().__init__(handlers, enable_logging=enable_logging) @@ -387,9 +370,6 @@ def print_listeners() -> None: if not options.test: ports.append((webpack_port, "webpack")) - if using_thumbor(): - ports.append((thumbor_port, "Thumbor")) - for port, label in ports: print(f" {port}: {label}") print() diff --git a/tools/setup/setup_venvs.py b/tools/setup/setup_venvs.py index 7682a6a0d1..5b8d9acf8a 100755 --- a/tools/setup/setup_venvs.py +++ b/tools/setup/setup_venvs.py @@ -13,11 +13,9 @@ from scripts.lib.zulip_tools import overwrite_symlink VENV_PATH = "/srv/zulip-py3-venv" DEV_REQS_FILE = os.path.join(ZULIP_PATH, "requirements", "dev.txt") -THUMBOR_REQS_FILE = os.path.join(ZULIP_PATH, "requirements", "thumbor-dev.txt") def main() -> None: - setup_virtualenv("/srv/zulip-thumbor-venv", THUMBOR_REQS_FILE, patch_activate_script=True) cached_venv_path = setup_virtualenv(VENV_PATH, DEV_REQS_FILE, patch_activate_script=True) overwrite_symlink(cached_venv_path, os.path.join(ZULIP_PATH, "zulip-py3-venv")) diff --git a/tools/update-locked-requirements b/tools/update-locked-requirements index 1e8072bd1c..2d89ce3b9d 100755 --- a/tools/update-locked-requirements +++ b/tools/update-locked-requirements @@ -2,7 +2,7 @@ set -e # Make sure the Zulip dev virtualenv exists, and operate within it. -if [ ! -d /srv/zulip-py3-venv ] || [ ! -d /srv/zulip-thumbor-venv ]; then +if [ ! -d /srv/zulip-py3-venv ]; then ./tools/setup/setup_venvs.py fi @@ -54,7 +54,3 @@ for name in pip prod mypy docs; do cp "$OUTPUT_BASE_DIR/dev.txt" "$OUTPUT_BASE_DIR/$name.txt" compile_requirements "requirements/$name.in" "$OUTPUT_BASE_DIR/$name.txt" done - -compile_requirements requirements/thumbor-dev.in "$OUTPUT_BASE_DIR/thumbor-dev.txt" -cp "$OUTPUT_BASE_DIR/thumbor-dev.txt" "$OUTPUT_BASE_DIR/thumbor.txt" -compile_requirements "requirements/thumbor.in" "$OUTPUT_BASE_DIR/thumbor.txt" diff --git a/version.py b/version.py index 9ffa0d10a8..c345d177f8 100644 --- a/version.py +++ b/version.py @@ -45,4 +45,4 @@ API_FEATURE_LEVEL = 62 # historical commits sharing the same major version, in which case a # minor version bump suffices. -PROVISION_VERSION = "142.0" +PROVISION_VERSION = "143.0" diff --git a/zerver/lib/test_helpers.py b/zerver/lib/test_helpers.py index d7200ed9db..4a577ecd5e 100644 --- a/zerver/lib/test_helpers.py +++ b/zerver/lib/test_helpers.py @@ -507,6 +507,7 @@ def write_instrumentation_reports(full_suite: bool, include_webhooks: bool) -> N "casper/(?P.+)", "static/(?P.+)", "flush_caches", + "external_content/(?P[^/]+)/(?P[^/]+)", *(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