mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-10-30 03:56:23 -05:00 
			
		
		
		
	Fix: use PAPERLESS_URL if set for pw reset emails (#5902)
This commit is contained in:
		| @@ -7,4 +7,5 @@ def settings(request): | ||||
|         or django_settings.EMAIL_HOST_USER != "", | ||||
|         "DISABLE_REGULAR_LOGIN": django_settings.DISABLE_REGULAR_LOGIN, | ||||
|         "ACCOUNT_ALLOW_SIGNUPS": django_settings.ACCOUNT_ALLOW_SIGNUPS, | ||||
|         "domain": getattr(django_settings, "PAPERLESS_URL", request.get_host()), | ||||
|     } | ||||
|   | ||||
							
								
								
									
										7
									
								
								src/documents/templates/account/email/base_message.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/documents/templates/account/email/base_message.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| {% load i18n %}{% autoescape off %}{% blocktrans with site_name="Paperless-ngx" %}Hello from {{ site_name }}!{% endblocktrans %} | ||||
|  | ||||
| {% block content %}{% endblock content %} | ||||
|  | ||||
| {% blocktrans with site_name="Paperless-ngx" site_domain=settings.domain %}Thank you for using {{ site_name }}! | ||||
| {{ site_domain }}{% endblocktrans %} | ||||
| {% endautoescape %} | ||||
| @@ -2,7 +2,7 @@ msgid "" | ||||
| msgstr "" | ||||
| "Project-Id-Version: paperless-ngx\n" | ||||
| "Report-Msgid-Bugs-To: \n" | ||||
| "POT-Creation-Date: 2024-02-26 00:10-0800\n" | ||||
| "POT-Creation-Date: 2024-02-26 13:34-0800\n" | ||||
| "PO-Revision-Date: 2022-02-17 04:17\n" | ||||
| "Last-Translator: \n" | ||||
| "Language-Team: English\n" | ||||
| @@ -786,6 +786,18 @@ msgstr "" | ||||
| msgid "Invalid variable detected." | ||||
| msgstr "" | ||||
|  | ||||
| #: documents/templates/account/email/base_message.txt:1 | ||||
| #, python-format | ||||
| msgid "Hello from %(site_name)s!" | ||||
| msgstr "" | ||||
|  | ||||
| #: documents/templates/account/email/base_message.txt:5 | ||||
| #, python-format | ||||
| msgid "" | ||||
| "Thank you for using %(site_name)s!\n" | ||||
| "%(site_domain)s" | ||||
| msgstr "" | ||||
|  | ||||
| #: documents/templates/account/login.html:5 | ||||
| msgid "Paperless-ngx sign in" | ||||
| msgstr "" | ||||
| @@ -1138,131 +1150,131 @@ msgstr "" | ||||
| msgid "paperless application settings" | ||||
| msgstr "" | ||||
|  | ||||
| #: paperless/settings.py:644 | ||||
| #: paperless/settings.py:656 | ||||
| msgid "English (US)" | ||||
| msgstr "" | ||||
|  | ||||
| #: paperless/settings.py:645 | ||||
| #: paperless/settings.py:657 | ||||
| msgid "Arabic" | ||||
| msgstr "" | ||||
|  | ||||
| #: paperless/settings.py:646 | ||||
| #: paperless/settings.py:658 | ||||
| msgid "Afrikaans" | ||||
| msgstr "" | ||||
|  | ||||
| #: paperless/settings.py:647 | ||||
| #: paperless/settings.py:659 | ||||
| msgid "Belarusian" | ||||
| msgstr "" | ||||
|  | ||||
| #: paperless/settings.py:648 | ||||
| #: paperless/settings.py:660 | ||||
| msgid "Bulgarian" | ||||
| msgstr "" | ||||
|  | ||||
| #: paperless/settings.py:649 | ||||
| #: paperless/settings.py:661 | ||||
| msgid "Catalan" | ||||
| msgstr "" | ||||
|  | ||||
| #: paperless/settings.py:650 | ||||
| #: paperless/settings.py:662 | ||||
| msgid "Czech" | ||||
| msgstr "" | ||||
|  | ||||
| #: paperless/settings.py:651 | ||||
| #: paperless/settings.py:663 | ||||
| msgid "Danish" | ||||
| msgstr "" | ||||
|  | ||||
| #: paperless/settings.py:652 | ||||
| #: paperless/settings.py:664 | ||||
| msgid "German" | ||||
| msgstr "" | ||||
|  | ||||
| #: paperless/settings.py:653 | ||||
| #: paperless/settings.py:665 | ||||
| msgid "Greek" | ||||
| msgstr "" | ||||
|  | ||||
| #: paperless/settings.py:654 | ||||
| #: paperless/settings.py:666 | ||||
| msgid "English (GB)" | ||||
| msgstr "" | ||||
|  | ||||
| #: paperless/settings.py:655 | ||||
| #: paperless/settings.py:667 | ||||
| msgid "Spanish" | ||||
| msgstr "" | ||||
|  | ||||
| #: paperless/settings.py:656 | ||||
| #: paperless/settings.py:668 | ||||
| msgid "Finnish" | ||||
| msgstr "" | ||||
|  | ||||
| #: paperless/settings.py:657 | ||||
| #: paperless/settings.py:669 | ||||
| msgid "French" | ||||
| msgstr "" | ||||
|  | ||||
| #: paperless/settings.py:658 | ||||
| #: paperless/settings.py:670 | ||||
| msgid "Hungarian" | ||||
| msgstr "" | ||||
|  | ||||
| #: paperless/settings.py:659 | ||||
| #: paperless/settings.py:671 | ||||
| msgid "Italian" | ||||
| msgstr "" | ||||
|  | ||||
| #: paperless/settings.py:660 | ||||
| #: paperless/settings.py:672 | ||||
| msgid "Japanese" | ||||
| msgstr "" | ||||
|  | ||||
| #: paperless/settings.py:661 | ||||
| #: paperless/settings.py:673 | ||||
| msgid "Luxembourgish" | ||||
| msgstr "" | ||||
|  | ||||
| #: paperless/settings.py:662 | ||||
| #: paperless/settings.py:674 | ||||
| msgid "Norwegian" | ||||
| msgstr "" | ||||
|  | ||||
| #: paperless/settings.py:663 | ||||
| #: paperless/settings.py:675 | ||||
| msgid "Dutch" | ||||
| msgstr "" | ||||
|  | ||||
| #: paperless/settings.py:664 | ||||
| #: paperless/settings.py:676 | ||||
| msgid "Polish" | ||||
| msgstr "" | ||||
|  | ||||
| #: paperless/settings.py:665 | ||||
| #: paperless/settings.py:677 | ||||
| msgid "Portuguese (Brazil)" | ||||
| msgstr "" | ||||
|  | ||||
| #: paperless/settings.py:666 | ||||
| #: paperless/settings.py:678 | ||||
| msgid "Portuguese" | ||||
| msgstr "" | ||||
|  | ||||
| #: paperless/settings.py:667 | ||||
| #: paperless/settings.py:679 | ||||
| msgid "Romanian" | ||||
| msgstr "" | ||||
|  | ||||
| #: paperless/settings.py:668 | ||||
| #: paperless/settings.py:680 | ||||
| msgid "Russian" | ||||
| msgstr "" | ||||
|  | ||||
| #: paperless/settings.py:669 | ||||
| #: paperless/settings.py:681 | ||||
| msgid "Slovak" | ||||
| msgstr "" | ||||
|  | ||||
| #: paperless/settings.py:670 | ||||
| #: paperless/settings.py:682 | ||||
| msgid "Slovenian" | ||||
| msgstr "" | ||||
|  | ||||
| #: paperless/settings.py:671 | ||||
| #: paperless/settings.py:683 | ||||
| msgid "Serbian" | ||||
| msgstr "" | ||||
|  | ||||
| #: paperless/settings.py:672 | ||||
| #: paperless/settings.py:684 | ||||
| msgid "Swedish" | ||||
| msgstr "" | ||||
|  | ||||
| #: paperless/settings.py:673 | ||||
| #: paperless/settings.py:685 | ||||
| msgid "Turkish" | ||||
| msgstr "" | ||||
|  | ||||
| #: paperless/settings.py:674 | ||||
| #: paperless/settings.py:686 | ||||
| msgid "Ukrainian" | ||||
| msgstr "" | ||||
|  | ||||
| #: paperless/settings.py:675 | ||||
| #: paperless/settings.py:687 | ||||
| msgid "Chinese Simplified" | ||||
| msgstr "" | ||||
|  | ||||
|   | ||||
| @@ -1,3 +1,5 @@ | ||||
| from urllib.parse import quote | ||||
|  | ||||
| from allauth.account.adapter import DefaultAccountAdapter | ||||
| from allauth.core import context | ||||
| from allauth.socialaccount.adapter import DefaultSocialAccountAdapter | ||||
| @@ -45,6 +47,20 @@ class CustomAccountAdapter(DefaultAccountAdapter): | ||||
|  | ||||
|         return url_has_allowed_host_and_scheme(url, allowed_hosts=allowed_hosts) | ||||
|  | ||||
|     def get_reset_password_from_key_url(self, key): | ||||
|         """ | ||||
|         Return the URL to reset a password e.g. in reset email. | ||||
|         """ | ||||
|         if settings.PAPERLESS_URL is None: | ||||
|             return super().get_reset_password_from_key_url(key) | ||||
|         else: | ||||
|             path = reverse( | ||||
|                 "account_reset_password_from_key", | ||||
|                 kwargs={"uidb36": "UID", "key": "KEY"}, | ||||
|             ) | ||||
|             path = path.replace("UID-KEY", quote(key)) | ||||
|             return settings.PAPERLESS_URL + path | ||||
|  | ||||
|  | ||||
| class CustomSocialAccountAdapter(DefaultSocialAccountAdapter): | ||||
|     def is_open_for_signup(self, request, sociallogin): | ||||
|   | ||||
| @@ -437,6 +437,8 @@ SOCIALACCOUNT_PROVIDERS = json.loads( | ||||
|     os.getenv("PAPERLESS_SOCIALACCOUNT_PROVIDERS", "{}"), | ||||
| ) | ||||
|  | ||||
| ACCOUNT_EMAIL_SUBJECT_PREFIX = "[Paperless-ngx] " | ||||
|  | ||||
| DISABLE_REGULAR_LOGIN = __get_boolean("PAPERLESS_DISABLE_REGULAR_LOGIN") | ||||
|  | ||||
| AUTO_LOGIN_USERNAME = os.getenv("PAPERLESS_AUTO_LOGIN_USERNAME") | ||||
| @@ -498,18 +500,23 @@ if DEBUG: | ||||
|     CORS_ALLOWED_ORIGINS.append("http://localhost:4200") | ||||
|  | ||||
| ALLOWED_HOSTS = __get_list("PAPERLESS_ALLOWED_HOSTS", ["*"]) | ||||
|  | ||||
| _paperless_url = os.getenv("PAPERLESS_URL") | ||||
| if _paperless_url: | ||||
|     _paperless_uri = urlparse(_paperless_url) | ||||
|     CSRF_TRUSTED_ORIGINS.append(_paperless_url) | ||||
|     CORS_ALLOWED_ORIGINS.append(_paperless_url) | ||||
|  | ||||
| if ["*"] != ALLOWED_HOSTS: | ||||
|     # always allow localhost. Necessary e.g. for healthcheck in docker. | ||||
|     ALLOWED_HOSTS.append("localhost") | ||||
|     if _paperless_url: | ||||
|         ALLOWED_HOSTS.append(_paperless_uri.hostname) | ||||
|  | ||||
|  | ||||
| def _parse_paperless_url(): | ||||
|     global CSRF_TRUSTED_ORIGINS, CORS_ALLOWED_ORIGINS, ALLOWED_HOSTS | ||||
|     url = os.getenv("PAPERLESS_URL") | ||||
|     if url: | ||||
|         CSRF_TRUSTED_ORIGINS.append(url) | ||||
|         CORS_ALLOWED_ORIGINS.append(url) | ||||
|         ALLOWED_HOSTS.append(urlparse(url).hostname) | ||||
|  | ||||
|     return url | ||||
|  | ||||
|  | ||||
| PAPERLESS_URL = _parse_paperless_url() | ||||
|  | ||||
| # For use with trusted proxies | ||||
| TRUSTED_PROXIES = __get_list("PAPERLESS_TRUSTED_PROXIES") | ||||
| @@ -1126,3 +1133,6 @@ DEFAULT_FROM_EMAIL: Final[str] = os.getenv("PAPERLESS_EMAIL_FROM", EMAIL_HOST_US | ||||
| EMAIL_USE_TLS: Final[bool] = __get_boolean("PAPERLESS_EMAIL_USE_TLS") | ||||
| EMAIL_USE_SSL: Final[bool] = __get_boolean("PAPERLESS_EMAIL_USE_SSL") | ||||
| EMAIL_SUBJECT_PREFIX: Final[str] = "[Paperless-ngx] " | ||||
| if DEBUG:  # pragma: no cover | ||||
|     EMAIL_BACKEND = "django.core.mail.backends.filebased.EmailBackend" | ||||
|     EMAIL_FILE_PATH = BASE_DIR / "sent_emails" | ||||
|   | ||||
| @@ -61,6 +61,27 @@ class TestCustomAccountAdapter(TestCase): | ||||
|         with self.assertRaises(ValidationError): | ||||
|             adapter.pre_authenticate(request) | ||||
|  | ||||
|     def test_get_reset_password_from_key_url(self): | ||||
|         request = HttpRequest() | ||||
|         request.get_host = mock.Mock(return_value="foo.org") | ||||
|         with context.request_context(request): | ||||
|             adapter = get_adapter() | ||||
|  | ||||
|             # Test when PAPERLESS_URL is None | ||||
|             expected_url = f"https://foo.org{reverse('account_reset_password_from_key', kwargs={'uidb36': 'UID', 'key': 'KEY'})}" | ||||
|             self.assertEqual( | ||||
|                 adapter.get_reset_password_from_key_url("UID-KEY"), | ||||
|                 expected_url, | ||||
|             ) | ||||
|  | ||||
|             # Test when PAPERLESS_URL is not None | ||||
|             with override_settings(PAPERLESS_URL="https://bar.com"): | ||||
|                 expected_url = f"https://bar.com{reverse('account_reset_password_from_key', kwargs={'uidb36': 'UID', 'key': 'KEY'})}" | ||||
|                 self.assertEqual( | ||||
|                     adapter.get_reset_password_from_key_url("UID-KEY"), | ||||
|                     expected_url, | ||||
|                 ) | ||||
|  | ||||
|  | ||||
| class TestCustomSocialAccountAdapter(TestCase): | ||||
|     def test_is_open_for_signup(self): | ||||
|   | ||||
| @@ -8,6 +8,7 @@ from celery.schedules import crontab | ||||
| from paperless.settings import _parse_beat_schedule | ||||
| from paperless.settings import _parse_db_settings | ||||
| from paperless.settings import _parse_ignore_dates | ||||
| from paperless.settings import _parse_paperless_url | ||||
| from paperless.settings import _parse_redis_url | ||||
| from paperless.settings import default_threads_per_worker | ||||
|  | ||||
| @@ -349,3 +350,27 @@ class TestDBSettings(TestCase): | ||||
|                 }, | ||||
|                 databases["sqlite"]["OPTIONS"], | ||||
|             ) | ||||
|  | ||||
|  | ||||
| class TestPaperlessURLSettings(TestCase): | ||||
|     def test_paperless_url(self): | ||||
|         """ | ||||
|         GIVEN: | ||||
|             - PAPERLESS_URL is set | ||||
|         WHEN: | ||||
|             - The URL is parsed | ||||
|         THEN: | ||||
|             - The URL is returned and present in related settings | ||||
|         """ | ||||
|         with mock.patch.dict( | ||||
|             os.environ, | ||||
|             { | ||||
|                 "PAPERLESS_URL": "https://example.com", | ||||
|             }, | ||||
|         ): | ||||
|             url = _parse_paperless_url() | ||||
|             self.assertEqual("https://example.com", url) | ||||
|             from django.conf import settings | ||||
|  | ||||
|             self.assertIn(url, settings.CSRF_TRUSTED_ORIGINS) | ||||
|             self.assertIn(url, settings.CORS_ALLOWED_ORIGINS) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 shamoon
					shamoon