mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-10-30 20:55:42 +00:00 
			
		
		
		
	Url validation (#6045)
* Add new setting INVENTREE_STRICT_URLS - Enforce schema prefix to URL validation - Default = True * Implement new validation * Also implement for DRF serializers
This commit is contained in:
		| @@ -11,6 +11,7 @@ from djmoney.forms.fields import MoneyField | |||||||
| from djmoney.models.fields import MoneyField as ModelMoneyField | from djmoney.models.fields import MoneyField as ModelMoneyField | ||||||
| from djmoney.models.validators import MinMoneyValidator | from djmoney.models.validators import MinMoneyValidator | ||||||
| from rest_framework.fields import URLField as RestURLField | from rest_framework.fields import URLField as RestURLField | ||||||
|  | from rest_framework.fields import empty | ||||||
|  |  | ||||||
| import InvenTree.helpers | import InvenTree.helpers | ||||||
|  |  | ||||||
| @@ -29,6 +30,20 @@ class InvenTreeRestURLField(RestURLField): | |||||||
|         super().__init__(**kwargs) |         super().__init__(**kwargs) | ||||||
|         self.validators[-1].schemes = allowable_url_schemes() |         self.validators[-1].schemes = allowable_url_schemes() | ||||||
|  |  | ||||||
|  |     def run_validation(self, data=empty): | ||||||
|  |         """Override default validation behaviour for this field type""" | ||||||
|  |  | ||||||
|  |         import common.models | ||||||
|  |  | ||||||
|  |         strict_urls = common.models.InvenTreeSetting.get_setting('INVENTREE_STRICT_URLS', True, cache=False) | ||||||
|  |  | ||||||
|  |         if not strict_urls and data is not empty: | ||||||
|  |             if '://' not in data: | ||||||
|  |                 # Validate as if there were a schema provided | ||||||
|  |                 data = 'http://' + data | ||||||
|  |  | ||||||
|  |         return super().run_validation(data=data) | ||||||
|  |  | ||||||
|  |  | ||||||
| class InvenTreeURLField(models.URLField): | class InvenTreeURLField(models.URLField): | ||||||
|     """Custom URL field which has custom scheme validators.""" |     """Custom URL field which has custom scheme validators.""" | ||||||
|   | |||||||
| @@ -203,6 +203,37 @@ class ValidatorTest(TestCase): | |||||||
|         with self.assertRaises(django_exceptions.ValidationError): |         with self.assertRaises(django_exceptions.ValidationError): | ||||||
|             validate_overage("aaaa") |             validate_overage("aaaa") | ||||||
|  |  | ||||||
|  |     def test_url_validation(self): | ||||||
|  |         """Test for AllowedURLValidator""" | ||||||
|  |  | ||||||
|  |         from common.models import InvenTreeSetting | ||||||
|  |         from part.models import Part, PartCategory | ||||||
|  |  | ||||||
|  |         # Without strict URL validation | ||||||
|  |         InvenTreeSetting.set_setting('INVENTREE_STRICT_URLS', False, None) | ||||||
|  |  | ||||||
|  |         n = Part.objects.count() | ||||||
|  |         cat = PartCategory.objects.first() | ||||||
|  |  | ||||||
|  |         # Should pass, even without a schema | ||||||
|  |         Part.objects.create( | ||||||
|  |             name=f'Part {n}', | ||||||
|  |             description='Link without schema', | ||||||
|  |             category=cat, | ||||||
|  |             link='www.google.com', | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |         # With strict URL validation | ||||||
|  |         InvenTreeSetting.set_setting('INVENTREE_STRICT_URLS', True, None) | ||||||
|  |  | ||||||
|  |         with self.assertRaises(ValidationError): | ||||||
|  |             Part.objects.create( | ||||||
|  |                 name=f'Part {n + 1}', | ||||||
|  |                 description='Link without schema', | ||||||
|  |                 category=cat, | ||||||
|  |                 link='www.google.com', | ||||||
|  |             ) | ||||||
|  |  | ||||||
|  |  | ||||||
| class FormatTest(TestCase): | class FormatTest(TestCase): | ||||||
|     """Unit tests for custom string formatting functionality""" |     """Unit tests for custom string formatting functionality""" | ||||||
|   | |||||||
| @@ -60,9 +60,23 @@ def allowable_url_schemes(): | |||||||
|  |  | ||||||
| class AllowedURLValidator(validators.URLValidator): | class AllowedURLValidator(validators.URLValidator): | ||||||
|     """Custom URL validator to allow for custom schemes.""" |     """Custom URL validator to allow for custom schemes.""" | ||||||
|  |  | ||||||
|     def __call__(self, value): |     def __call__(self, value): | ||||||
|         """Validate the URL.""" |         """Validate the URL.""" | ||||||
|  |  | ||||||
|  |         import common.models | ||||||
|  |  | ||||||
|         self.schemes = allowable_url_schemes() |         self.schemes = allowable_url_schemes() | ||||||
|  |  | ||||||
|  |         # Determine if 'strict' URL validation is required (i.e. if the URL must have a schema prefix) | ||||||
|  |         strict_urls = common.models.InvenTreeSetting.get_setting('INVENTREE_STRICT_URLS', True, cache=False) | ||||||
|  |  | ||||||
|  |         if not strict_urls: | ||||||
|  |             # Allow URLs which do not have a provided schema | ||||||
|  |             if '://' not in value: | ||||||
|  |                 # Validate as if it were http | ||||||
|  |                 value = 'http://' + value | ||||||
|  |  | ||||||
|         super().__call__(value) |         super().__call__(value) | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1175,6 +1175,13 @@ class InvenTreeSetting(BaseInvenTreeSetting): | |||||||
|             'default': '', |             'default': '', | ||||||
|         }, |         }, | ||||||
|  |  | ||||||
|  |         'INVENTREE_STRICT_URLS': { | ||||||
|  |             'name': _('Strict URL Validation'), | ||||||
|  |             'description': _('Require schema specification when validating URLs'), | ||||||
|  |             'validator': bool, | ||||||
|  |             'default': True, | ||||||
|  |         }, | ||||||
|  |  | ||||||
|         'INVENTREE_REQUIRE_CONFIRM': { |         'INVENTREE_REQUIRE_CONFIRM': { | ||||||
|             'name': _('Require confirm'), |             'name': _('Require confirm'), | ||||||
|             'description': _('Require explicit user confirmation for certain action.'), |             'description': _('Require explicit user confirmation for certain action.'), | ||||||
|   | |||||||
| @@ -24,6 +24,7 @@ | |||||||
|         {% include "InvenTree/settings/setting.html" with key="INVENTREE_DOWNLOAD_IMAGE_MAX_SIZE" icon="fa-server" %} |         {% include "InvenTree/settings/setting.html" with key="INVENTREE_DOWNLOAD_IMAGE_MAX_SIZE" icon="fa-server" %} | ||||||
|         {% include "InvenTree/settings/setting.html" with key="INVENTREE_DOWNLOAD_FROM_URL_USER_AGENT" icon="fa-server" %} |         {% include "InvenTree/settings/setting.html" with key="INVENTREE_DOWNLOAD_FROM_URL_USER_AGENT" icon="fa-server" %} | ||||||
|         {% include "InvenTree/settings/setting.html" with key="INVENTREE_REQUIRE_CONFIRM" icon="fa-check" %} |         {% include "InvenTree/settings/setting.html" with key="INVENTREE_REQUIRE_CONFIRM" icon="fa-check" %} | ||||||
|  |         {% include "InvenTree/settings/setting.html" with key="INVENTREE_STRICT_URLS" icon="fa-link" %} | ||||||
|         {% include "InvenTree/settings/setting.html" with key="INVENTREE_TREE_DEPTH" icon="fa-sitemap" %} |         {% include "InvenTree/settings/setting.html" with key="INVENTREE_TREE_DEPTH" icon="fa-sitemap" %} | ||||||
|         {% include "InvenTree/settings/setting.html" with key="INVENTREE_BACKUP_ENABLE" icon="fa-hdd" %} |         {% include "InvenTree/settings/setting.html" with key="INVENTREE_BACKUP_ENABLE" icon="fa-hdd" %} | ||||||
|         {% include "InvenTree/settings/setting.html" with key="INVENTREE_BACKUP_DAYS" icon="fa-calendar-alt" %} |         {% include "InvenTree/settings/setting.html" with key="INVENTREE_BACKUP_DAYS" icon="fa-calendar-alt" %} | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user