2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-04-29 20:16:44 +00:00

Merge pull request from GHSA-7rq4-qcpw-74gq

* Create custom ModelResource subclass

- Strips illegal starting characters from string cells
- Prevents formula injection

* Update all existing ModelResource classes to base off InvenTreeResource

* Handle more complex case where an illegal char is hidden behind another one
This commit is contained in:
Oliver 2022-06-15 18:32:35 +10:00 committed by GitHub
parent 76aa3a75f2
commit 57563f6b7a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 57 additions and 24 deletions

View File

@ -0,0 +1,33 @@
"""Admin classes"""
from import_export.resources import ModelResource
class InvenTreeResource(ModelResource):
"""Custom subclass of the ModelResource class provided by django-import-export"
Ensures that exported data are escaped to prevent malicious formula injection.
Ref: https://owasp.org/www-community/attacks/CSV_Injection
"""
def export_resource(self, obj):
"""Custom function to override default row export behaviour.
Specifically, strip illegal leading characters to prevent formula injection
"""
row = super().export_resource(obj)
illegal_start_vals = ['@', '=', '+', '-', '@', '\t', '\r', '\n']
for idx, val in enumerate(row):
if type(val) is str:
val = val.strip()
# If the value starts with certain 'suspicious' values, remove it!
while len(val) > 0 and val[0] in illegal_start_vals:
# Remove the first character
val = val[1:]
row[idx] = val
return row

View File

@ -4,15 +4,14 @@ from django.contrib import admin
from import_export.admin import ImportExportModelAdmin from import_export.admin import ImportExportModelAdmin
from import_export.fields import Field from import_export.fields import Field
from import_export.resources import ModelResource
import import_export.widgets as widgets import import_export.widgets as widgets
from build.models import Build, BuildItem from build.models import Build, BuildItem
from InvenTree.admin import InvenTreeResource
import part.models import part.models
class BuildResource(ModelResource): class BuildResource(InvenTreeResource):
"""Class for managing import/export of Build data.""" """Class for managing import/export of Build data."""
# For some reason, we need to specify the fields individually for this ModelResource, # For some reason, we need to specify the fields individually for this ModelResource,
# but we don't for other ones. # but we don't for other ones.

View File

@ -5,8 +5,8 @@ from django.contrib import admin
import import_export.widgets as widgets import import_export.widgets as widgets
from import_export.admin import ImportExportModelAdmin from import_export.admin import ImportExportModelAdmin
from import_export.fields import Field from import_export.fields import Field
from import_export.resources import ModelResource
from InvenTree.admin import InvenTreeResource
from part.models import Part from part.models import Part
from .models import (Company, ManufacturerPart, ManufacturerPartAttachment, from .models import (Company, ManufacturerPart, ManufacturerPartAttachment,
@ -14,7 +14,7 @@ from .models import (Company, ManufacturerPart, ManufacturerPartAttachment,
SupplierPriceBreak) SupplierPriceBreak)
class CompanyResource(ModelResource): class CompanyResource(InvenTreeResource):
"""Class for managing Company data import/export.""" """Class for managing Company data import/export."""
class Meta: class Meta:
@ -38,7 +38,7 @@ class CompanyAdmin(ImportExportModelAdmin):
] ]
class SupplierPartResource(ModelResource): class SupplierPartResource(InvenTreeResource):
"""Class for managing SupplierPart data import/export.""" """Class for managing SupplierPart data import/export."""
part = Field(attribute='part', widget=widgets.ForeignKeyWidget(Part)) part = Field(attribute='part', widget=widgets.ForeignKeyWidget(Part))
@ -74,7 +74,7 @@ class SupplierPartAdmin(ImportExportModelAdmin):
autocomplete_fields = ('part', 'supplier', 'manufacturer_part',) autocomplete_fields = ('part', 'supplier', 'manufacturer_part',)
class ManufacturerPartResource(ModelResource): class ManufacturerPartResource(InvenTreeResource):
"""Class for managing ManufacturerPart data import/export.""" """Class for managing ManufacturerPart data import/export."""
part = Field(attribute='part', widget=widgets.ForeignKeyWidget(Part)) part = Field(attribute='part', widget=widgets.ForeignKeyWidget(Part))
@ -117,7 +117,7 @@ class ManufacturerPartAttachmentAdmin(ImportExportModelAdmin):
autocomplete_fields = ('manufacturer_part',) autocomplete_fields = ('manufacturer_part',)
class ManufacturerPartParameterResource(ModelResource): class ManufacturerPartParameterResource(InvenTreeResource):
"""Class for managing ManufacturerPartParameter data import/export.""" """Class for managing ManufacturerPartParameter data import/export."""
class Meta: class Meta:
@ -144,7 +144,7 @@ class ManufacturerPartParameterAdmin(ImportExportModelAdmin):
autocomplete_fields = ('manufacturer_part',) autocomplete_fields = ('manufacturer_part',)
class SupplierPriceBreakResource(ModelResource): class SupplierPriceBreakResource(InvenTreeResource):
"""Class for managing SupplierPriceBreak data import/export.""" """Class for managing SupplierPriceBreak data import/export."""
part = Field(attribute='part', widget=widgets.ForeignKeyWidget(SupplierPart)) part = Field(attribute='part', widget=widgets.ForeignKeyWidget(SupplierPart))

View File

@ -5,7 +5,8 @@ from django.contrib import admin
import import_export.widgets as widgets import import_export.widgets as widgets
from import_export.admin import ImportExportModelAdmin from import_export.admin import ImportExportModelAdmin
from import_export.fields import Field from import_export.fields import Field
from import_export.resources import ModelResource
from InvenTree.admin import InvenTreeResource
from .models import (PurchaseOrder, PurchaseOrderExtraLine, from .models import (PurchaseOrder, PurchaseOrderExtraLine,
PurchaseOrderLineItem, SalesOrder, SalesOrderAllocation, PurchaseOrderLineItem, SalesOrder, SalesOrderAllocation,
@ -97,7 +98,7 @@ class SalesOrderAdmin(ImportExportModelAdmin):
autocomplete_fields = ('customer',) autocomplete_fields = ('customer',)
class PurchaseOrderResource(ModelResource): class PurchaseOrderResource(InvenTreeResource):
"""Class for managing import / export of PurchaseOrder data.""" """Class for managing import / export of PurchaseOrder data."""
# Add number of line items # Add number of line items
@ -116,7 +117,7 @@ class PurchaseOrderResource(ModelResource):
] ]
class PurchaseOrderLineItemResource(ModelResource): class PurchaseOrderLineItemResource(InvenTreeResource):
"""Class for managing import / export of PurchaseOrderLineItem data.""" """Class for managing import / export of PurchaseOrderLineItem data."""
part_name = Field(attribute='part__part__name', readonly=True) part_name = Field(attribute='part__part__name', readonly=True)
@ -135,7 +136,7 @@ class PurchaseOrderLineItemResource(ModelResource):
clean_model_instances = True clean_model_instances = True
class PurchaseOrderExtraLineResource(ModelResource): class PurchaseOrderExtraLineResource(InvenTreeResource):
"""Class for managing import / export of PurchaseOrderExtraLine data.""" """Class for managing import / export of PurchaseOrderExtraLine data."""
class Meta(GeneralExtraLineMeta): class Meta(GeneralExtraLineMeta):
@ -144,7 +145,7 @@ class PurchaseOrderExtraLineResource(ModelResource):
model = PurchaseOrderExtraLine model = PurchaseOrderExtraLine
class SalesOrderResource(ModelResource): class SalesOrderResource(InvenTreeResource):
"""Class for managing import / export of SalesOrder data.""" """Class for managing import / export of SalesOrder data."""
# Add number of line items # Add number of line items
@ -163,7 +164,7 @@ class SalesOrderResource(ModelResource):
] ]
class SalesOrderLineItemResource(ModelResource): class SalesOrderLineItemResource(InvenTreeResource):
"""Class for managing import / export of SalesOrderLineItem data.""" """Class for managing import / export of SalesOrderLineItem data."""
part_name = Field(attribute='part__name', readonly=True) part_name = Field(attribute='part__name', readonly=True)
@ -192,7 +193,7 @@ class SalesOrderLineItemResource(ModelResource):
clean_model_instances = True clean_model_instances = True
class SalesOrderExtraLineResource(ModelResource): class SalesOrderExtraLineResource(InvenTreeResource):
"""Class for managing import / export of SalesOrderExtraLine data.""" """Class for managing import / export of SalesOrderExtraLine data."""
class Meta(GeneralExtraLineMeta): class Meta(GeneralExtraLineMeta):

View File

@ -5,14 +5,14 @@ from django.contrib import admin
import import_export.widgets as widgets import import_export.widgets as widgets
from import_export.admin import ImportExportModelAdmin from import_export.admin import ImportExportModelAdmin
from import_export.fields import Field from import_export.fields import Field
from import_export.resources import ModelResource
import part.models as models import part.models as models
from company.models import SupplierPart from company.models import SupplierPart
from InvenTree.admin import InvenTreeResource
from stock.models import StockLocation from stock.models import StockLocation
class PartResource(ModelResource): class PartResource(InvenTreeResource):
"""Class for managing Part data import/export.""" """Class for managing Part data import/export."""
# ForeignKey fields # ForeignKey fields
@ -92,7 +92,7 @@ class PartAdmin(ImportExportModelAdmin):
] ]
class PartCategoryResource(ModelResource): class PartCategoryResource(InvenTreeResource):
"""Class for managing PartCategory data import/export.""" """Class for managing PartCategory data import/export."""
parent = Field(attribute='parent', widget=widgets.ForeignKeyWidget(models.PartCategory)) parent = Field(attribute='parent', widget=widgets.ForeignKeyWidget(models.PartCategory))
@ -157,7 +157,7 @@ class PartTestTemplateAdmin(admin.ModelAdmin):
autocomplete_fields = ('part',) autocomplete_fields = ('part',)
class BomItemResource(ModelResource): class BomItemResource(InvenTreeResource):
"""Class for managing BomItem data import/export.""" """Class for managing BomItem data import/export."""
level = Field(attribute='level', readonly=True) level = Field(attribute='level', readonly=True)
@ -266,7 +266,7 @@ class ParameterTemplateAdmin(ImportExportModelAdmin):
search_fields = ('name', 'units') search_fields = ('name', 'units')
class ParameterResource(ModelResource): class ParameterResource(InvenTreeResource):
"""Class for managing PartParameter data import/export.""" """Class for managing PartParameter data import/export."""
part = Field(attribute='part', widget=widgets.ForeignKeyWidget(models.Part)) part = Field(attribute='part', widget=widgets.ForeignKeyWidget(models.Part))

View File

@ -5,10 +5,10 @@ from django.contrib import admin
import import_export.widgets as widgets import import_export.widgets as widgets
from import_export.admin import ImportExportModelAdmin from import_export.admin import ImportExportModelAdmin
from import_export.fields import Field from import_export.fields import Field
from import_export.resources import ModelResource
from build.models import Build from build.models import Build
from company.models import Company, SupplierPart from company.models import Company, SupplierPart
from InvenTree.admin import InvenTreeResource
from order.models import PurchaseOrder, SalesOrder from order.models import PurchaseOrder, SalesOrder
from part.models import Part from part.models import Part
@ -16,7 +16,7 @@ from .models import (StockItem, StockItemAttachment, StockItemTestResult,
StockItemTracking, StockLocation) StockItemTracking, StockLocation)
class LocationResource(ModelResource): class LocationResource(InvenTreeResource):
"""Class for managing StockLocation data import/export.""" """Class for managing StockLocation data import/export."""
parent = Field(attribute='parent', widget=widgets.ForeignKeyWidget(StockLocation)) parent = Field(attribute='parent', widget=widgets.ForeignKeyWidget(StockLocation))
@ -68,7 +68,7 @@ class LocationAdmin(ImportExportModelAdmin):
] ]
class StockItemResource(ModelResource): class StockItemResource(InvenTreeResource):
"""Class for managing StockItem data import/export.""" """Class for managing StockItem data import/export."""
# Custom managers for ForeignKey fields # Custom managers for ForeignKey fields