From 99d822ecdbe8b00ac873dd3cb141631ce17882e2 Mon Sep 17 00:00:00 2001 From: Oliver Date: Thu, 13 Oct 2022 12:14:36 +1100 Subject: [PATCH] Check user permissions before linking or un-linking barcodes (#3772) * Check user permissions before linking or un-linking barcodse * Bump API version * Permission fixes for unit tests * Fix permission issues * Unit test fixes --- InvenTree/InvenTree/api_version.py | 5 +++- InvenTree/plugin/base/barcodes/api.py | 25 +++++++++++++++- .../plugin/base/barcodes/test_barcode.py | 2 ++ .../barcodes/test_inventree_barcode.py | 30 +++++++++++++++++++ 4 files changed, 60 insertions(+), 2 deletions(-) diff --git a/InvenTree/InvenTree/api_version.py b/InvenTree/InvenTree/api_version.py index 22c65f2417..c7a133c517 100644 --- a/InvenTree/InvenTree/api_version.py +++ b/InvenTree/InvenTree/api_version.py @@ -2,11 +2,14 @@ # InvenTree API version -INVENTREE_API_VERSION = 76 +INVENTREE_API_VERSION = 77 """ Increment this API version number whenever there is a significant change to the API that any clients need to know about +v77 -> 2022-10-12 : https://github.com/inventree/InvenTree/pull/3772 + - Adds model permission checks for barcode assignment actions + v76 -> 2022-09-10 : https://github.com/inventree/InvenTree/pull/3640 - Refactor of barcode data on the API - StockItem.uid renamed to StockItem.barcode_hash diff --git a/InvenTree/plugin/base/barcodes/api.py b/InvenTree/plugin/base/barcodes/api.py index 21a35a754a..15aeaa62fe 100644 --- a/InvenTree/plugin/base/barcodes/api.py +++ b/InvenTree/plugin/base/barcodes/api.py @@ -5,7 +5,7 @@ from django.urls import path, re_path from django.utils.translation import gettext_lazy as _ from rest_framework import permissions -from rest_framework.exceptions import ValidationError +from rest_framework.exceptions import PermissionDenied, ValidationError from rest_framework.response import Response from rest_framework.views import APIView @@ -13,6 +13,7 @@ from InvenTree.helpers import hash_barcode from plugin import registry from plugin.builtin.barcodes.inventree_barcode import ( InvenTreeExternalBarcodePlugin, InvenTreeInternalBarcodePlugin) +from users.models import RuleSet class BarcodeScan(APIView): @@ -139,6 +140,17 @@ class BarcodeAssign(APIView): try: instance = model.objects.get(pk=data[label]) + # Check that the user has the required permission + app_label = model._meta.app_label + model_name = model._meta.model_name + + table = f"{app_label}_{model_name}" + + if not RuleSet.check_table_permission(request.user, table, "change"): + raise PermissionDenied({ + "error": f"You do not have the required permissions for {table}" + }) + instance.assign_barcode( barcode_data=barcode_data, barcode_hash=barcode_hash, @@ -210,6 +222,17 @@ class BarcodeUnassign(APIView): label: _('No match found for provided value') }) + # Check that the user has the required permission + app_label = model._meta.app_label + model_name = model._meta.model_name + + table = f"{app_label}_{model_name}" + + if not RuleSet.check_table_permission(request.user, table, "change"): + raise PermissionDenied({ + "error": f"You do not have the required permissions for {table}" + }) + # Unassign the barcode data from the model instance instance.unassign_barcode() diff --git a/InvenTree/plugin/base/barcodes/test_barcode.py b/InvenTree/plugin/base/barcodes/test_barcode.py index c847d0f586..d3ca79bf4a 100644 --- a/InvenTree/plugin/base/barcodes/test_barcode.py +++ b/InvenTree/plugin/base/barcodes/test_barcode.py @@ -190,6 +190,8 @@ class BarcodeAPITest(InvenTreeAPITestCase): """Test that a barcode can be associated with a StockItem.""" item = StockItem.objects.get(pk=522) + self.assignRole('stock.change') + self.assertEqual(len(item.barcode_hash), 0) barcode_data = 'A-TEST-BARCODE-STRING' diff --git a/InvenTree/plugin/builtin/barcodes/test_inventree_barcode.py b/InvenTree/plugin/builtin/barcodes/test_inventree_barcode.py index 1230794625..6f2439de23 100644 --- a/InvenTree/plugin/builtin/barcodes/test_inventree_barcode.py +++ b/InvenTree/plugin/builtin/barcodes/test_inventree_barcode.py @@ -125,6 +125,19 @@ class TestInvenTreeBarcode(InvenTreeAPITestCase): self.assertIn('Missing data:', str(response.data)) + # Permission error check + response = self.assign( + { + 'barcode': 'abcdefg', + 'part': 1, + 'stockitem': 1, + }, + expected_code=403 + ) + + self.assignRole('part.change') + self.assignRole('stock.change') + # Provide too many fields response = self.assign( { @@ -188,6 +201,8 @@ class TestInvenTreeBarcode(InvenTreeAPITestCase): barcode = 'xyz-123' + self.assignRole('part.change') + # Test that an initial scan yields no results response = self.scan( { @@ -196,6 +211,8 @@ class TestInvenTreeBarcode(InvenTreeAPITestCase): expected_code=400 ) + self.assignRole('part.change') + # Attempt to assign to an invalid part ID response = self.assign( { @@ -247,6 +264,8 @@ class TestInvenTreeBarcode(InvenTreeAPITestCase): self.assertIn('Barcode matches existing item', str(response.data['error'])) + self.assignRole('part.change') + # Now test that we can unassign the barcode data also response = self.unassign( { @@ -265,6 +284,17 @@ class TestInvenTreeBarcode(InvenTreeAPITestCase): barcode = '555555555555555555555555' + # Assign random barcode data to a StockLocation instance + response = self.assign( + data={ + 'barcode': barcode, + 'stocklocation': 1, + }, + expected_code=403, + ) + + self.assignRole('stock_location.change') + # Assign random barcode data to a StockLocation instance response = self.assign( data={