mirror of
https://github.com/inventree/InvenTree.git
synced 2026-05-17 14:58:36 +00:00
refactor(backend): various SAST fixes (#11952)
* optimize asserts * ensure redirect is safe * sanatize token in log
This commit is contained in:
@@ -1181,3 +1181,18 @@ def plugins_info(*args, **kwargs):
|
||||
return [
|
||||
{'name': plg.name, 'slug': plg.slug, 'version': plg.version} for plg in plugins
|
||||
]
|
||||
|
||||
|
||||
def sanitize_token(token_value: str, front=8, back=12) -> str:
|
||||
"""Sanitize a token by replacing the middle characters with asterisks.
|
||||
|
||||
Args:
|
||||
token_value: The token string to sanitize
|
||||
front: Number of characters to show at the start of the token (default = 8)
|
||||
back: Number of characters to show at the end of the token (default = 12)
|
||||
|
||||
Returns:
|
||||
The sanitized token string
|
||||
"""
|
||||
middle = len(token_value) - (front + back)
|
||||
return token_value[:front] + '*' * middle + token_value[-back:]
|
||||
|
||||
@@ -10,12 +10,13 @@ from django.http import HttpRequest, HttpResponse, JsonResponse
|
||||
from django.shortcuts import redirect, render
|
||||
from django.urls import resolve, reverse, reverse_lazy
|
||||
from django.utils.deprecation import MiddlewareMixin
|
||||
from django.utils.http import is_same_domain
|
||||
from django.utils.http import is_same_domain, url_has_allowed_host_and_scheme
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
import structlog
|
||||
from error_report.middleware import ExceptionProcessor
|
||||
|
||||
import InvenTree.helpers
|
||||
from common.settings import get_global_setting
|
||||
from InvenTree.cache import create_session_cache, delete_session_cache
|
||||
from InvenTree.config import CONFIG_LOOKUPS, inventreeInstaller
|
||||
@@ -126,7 +127,8 @@ class AuthRequiredMiddleware:
|
||||
return True
|
||||
except ApiToken.DoesNotExist: # pragma: no cover
|
||||
logger.warning(
|
||||
'Access denied for unknown token %s', token
|
||||
'Access denied for unknown token %s',
|
||||
InvenTree.helpers.sanitize_token(str(token)),
|
||||
) # pragma: no cover
|
||||
|
||||
return False
|
||||
@@ -163,9 +165,16 @@ class AuthRequiredMiddleware:
|
||||
if path not in urls and not any(
|
||||
path.startswith(p) for p in paths_ignore_handling
|
||||
):
|
||||
# Validate next url is safe to redirect to
|
||||
next_url = request.path
|
||||
if not url_has_allowed_host_and_scheme(
|
||||
url=next_url,
|
||||
allowed_hosts=settings.ALLOWED_HOSTS,
|
||||
require_https=request.is_secure(),
|
||||
):
|
||||
return redirect(str(reverse_lazy('account_login')))
|
||||
# Save the 'next' parameter to pass through to the login view
|
||||
|
||||
return redirect(f'{reverse_lazy("account_login")}?next={request.path}')
|
||||
return redirect(f'{reverse_lazy("account_login")}?next={next_url}')
|
||||
# Return a 401 (Unauthorized) response code for this request
|
||||
return HttpResponse('Unauthorized', status=401)
|
||||
|
||||
|
||||
@@ -299,7 +299,7 @@ class TestAddressMigration(MigratorTestCase):
|
||||
c1 = Company.objects.filter(name='Company 1').first()
|
||||
c2 = Company.objects.filter(name='Company 2').first()
|
||||
|
||||
self.assertEqual(len(Address.objects.all()), 2)
|
||||
self.assertEqual(Address.objects.count(), 2)
|
||||
|
||||
a1 = Address.objects.filter(company=c1.pk).first()
|
||||
a2 = Address.objects.filter(company=c2.pk).first()
|
||||
|
||||
@@ -147,7 +147,7 @@ class MachineAPITest(TestMachineRegistryMixin, InvenTreeAPITestCase):
|
||||
|
||||
def test_machine_detail(self):
|
||||
"""Test machine detail API endpoint."""
|
||||
self.assertFalse(len(MachineConfig.objects.all()), 0)
|
||||
self.assertFalse(MachineConfig.objects.count(), 0)
|
||||
self.get(
|
||||
reverse('api-machine-detail', kwargs={'pk': self.placeholder_uuid}),
|
||||
expected_code=404,
|
||||
@@ -185,7 +185,7 @@ class MachineAPITest(TestMachineRegistryMixin, InvenTreeAPITestCase):
|
||||
response = self.delete(
|
||||
reverse('api-machine-detail', kwargs={'pk': pk}), expected_code=204
|
||||
)
|
||||
self.assertFalse(len(MachineConfig.objects.all()), 0)
|
||||
self.assertFalse(MachineConfig.objects.count(), 0)
|
||||
|
||||
# Create machine where the driver does not exist
|
||||
machine_data['driver'] = 'non-existent-driver'
|
||||
|
||||
@@ -43,8 +43,8 @@ class CategoryTest(TestCase):
|
||||
self.assertTrue(self.electronics.has_children)
|
||||
self.assertTrue(self.mechanical.has_children)
|
||||
|
||||
self.assertEqual(len(self.electronics.children.all()), 3)
|
||||
self.assertEqual(len(self.mechanical.children.all()), 1)
|
||||
self.assertEqual(self.electronics.children.count(), 3)
|
||||
self.assertEqual(self.mechanical.children.count(), 1)
|
||||
|
||||
def test_unique_children(self):
|
||||
"""Test the 'unique_children' functionality."""
|
||||
|
||||
@@ -179,9 +179,7 @@ class ApiToken(AuthToken, InvenTree.models.MetadataMixin):
|
||||
if self.pk is None:
|
||||
return self.key # pragma: no cover
|
||||
|
||||
M = len(self.key) - 20
|
||||
|
||||
return self.key[:8] + '*' * M + self.key[-12:]
|
||||
return InvenTree.helpers.sanitize_token(self.key)
|
||||
|
||||
@property
|
||||
@admin.display(boolean=True, description=_('Expired'))
|
||||
|
||||
Reference in New Issue
Block a user