2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-04-29 03:56:43 +00:00

Back porting of security patches (#3197)

* Merge pull request from GHSA-fr2w-mp56-g4xp

* Enforce file download for attachments table(s)

* Enforce file download for attachment in 'StockItemTestResult' table

(cherry picked from commit 76aa3a75f2e5b93877a229e29326b8b4ea815aea)

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

* Merge pull request from GHSA-rm89-9g65-4ffr

* Enable HTML escaping for all tables by default

* Enable HTML escaping for all tables by default

* Adds automatic escaping for bootstrap tables where custom formatter function is specified

- Intercept the row data *before* it is provided to the renderer function
- Adds a function for sanitizing nested data structure

* Sanitize form data before processing

(cherry picked from commit cd418d6948e6bf5f428cec5b4a7a1f0618a482a3)

* Increment version number for release

* Fix sanitization for array case - was missing a return value
This commit is contained in:
Oliver 2022-06-15 20:43:43 +10:00 committed by GitHub
parent f9c28eedaf
commit 26bf51c20a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 195 additions and 63 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

@ -13,6 +13,7 @@
inventreeDocReady, inventreeDocReady,
inventreeLoad, inventreeLoad,
inventreeSave, inventreeSave,
sanitizeData,
*/ */
function attachClipboard(selector, containerselector, textElement) { function attachClipboard(selector, containerselector, textElement) {
@ -273,6 +274,42 @@ function loadBrandIcon(element, name) {
} }
} }
/*
* Function to sanitize a (potentially nested) object.
* Iterates through all levels, and sanitizes each primitive string.
*
* Note that this function effectively provides a "deep copy" of the provided data,
* and the original data structure is unaltered.
*/
function sanitizeData(data) {
if (data == null) {
return null;
} else if (Array.isArray(data)) {
// Handle arrays
var arr = [];
data.forEach(function(val) {
arr.push(sanitizeData(val));
});
return arr;
} else if (typeof(data) === 'object') {
// Handle nested structures
var nested = {};
$.each(data, function(k, v) {
nested[k] = sanitizeData(v);
});
return nested;
} else if (typeof(data) === 'string') {
// Perform string replacement
return data.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#039;').replace(/`/g, '&#x60;');
} else {
return data;
}
}
// Convenience function to determine if an element exists // Convenience function to determine if an element exists
$.fn.exists = function() { $.fn.exists = function() {
return this.length !== 0; return this.length !== 0;

View File

@ -12,7 +12,7 @@ import common.models
from InvenTree.api_version import INVENTREE_API_VERSION from InvenTree.api_version import INVENTREE_API_VERSION
# InvenTree software version # InvenTree software version
INVENTREE_SW_VERSION = "0.7.1" INVENTREE_SW_VERSION = "0.7.2"
def inventreeInstanceName(): def inventreeInstanceName():

View File

@ -2,16 +2,15 @@ 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.
# TODO: 2022-05-12 - Need to investigate why this is the case! # TODO: 2022-05-12 - Need to investigate why this is the case!

View File

@ -3,8 +3,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,
@ -12,8 +12,8 @@ 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:
model = Company model = Company
@ -34,10 +34,8 @@ 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))
@ -70,10 +68,8 @@ 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))
@ -118,10 +114,8 @@ 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:
model = ManufacturerPartParameter model = ManufacturerPartParameter
@ -148,8 +142,8 @@ 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

@ -1,9 +1,12 @@
"""Admin functionality for the 'order' app"""
from django.contrib import admin 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,
@ -13,6 +16,7 @@ from .models import (PurchaseOrder, PurchaseOrderExtraLine,
# region general classes # region general classes
class GeneralExtraLineAdmin: class GeneralExtraLineAdmin:
"""Admin class template for the 'ExtraLineItem' models"""
list_display = ( list_display = (
'order', 'order',
'quantity', 'quantity',
@ -29,6 +33,7 @@ class GeneralExtraLineAdmin:
class GeneralExtraLineMeta: class GeneralExtraLineMeta:
"""Metaclass template for the 'ExtraLineItem' models"""
skip_unchanged = True skip_unchanged = True
report_skipped = False report_skipped = False
clean_model_instances = True clean_model_instances = True
@ -36,11 +41,13 @@ class GeneralExtraLineMeta:
class PurchaseOrderLineItemInlineAdmin(admin.StackedInline): class PurchaseOrderLineItemInlineAdmin(admin.StackedInline):
"""Inline admin class for the PurchaseOrderLineItem model"""
model = PurchaseOrderLineItem model = PurchaseOrderLineItem
extra = 0 extra = 0
class PurchaseOrderAdmin(ImportExportModelAdmin): class PurchaseOrderAdmin(ImportExportModelAdmin):
"""Admin class for the PurchaseOrder model"""
exclude = [ exclude = [
'reference_int', 'reference_int',
@ -68,6 +75,7 @@ class PurchaseOrderAdmin(ImportExportModelAdmin):
class SalesOrderAdmin(ImportExportModelAdmin): class SalesOrderAdmin(ImportExportModelAdmin):
"""Admin class for the SalesOrder model"""
exclude = [ exclude = [
'reference_int', 'reference_int',
@ -90,10 +98,8 @@ 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
line_items = Field(attribute='line_count', widget=widgets.IntegerWidget(), readonly=True) line_items = Field(attribute='line_count', widget=widgets.IntegerWidget(), readonly=True)
@ -102,6 +108,7 @@ class PurchaseOrderResource(ModelResource):
overdue = Field(attribute='is_overdue', widget=widgets.BooleanWidget(), readonly=True) overdue = Field(attribute='is_overdue', widget=widgets.BooleanWidget(), readonly=True)
class Meta: class Meta:
"""Metaclass"""
model = PurchaseOrder model = PurchaseOrder
skip_unchanged = True skip_unchanged = True
clean_model_instances = True clean_model_instances = True
@ -110,8 +117,8 @@ 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)
@ -122,23 +129,24 @@ class PurchaseOrderLineItemResource(ModelResource):
SKU = Field(attribute='part__SKU', readonly=True) SKU = Field(attribute='part__SKU', readonly=True)
class Meta: class Meta:
"""Metaclass"""
model = PurchaseOrderLineItem model = PurchaseOrderLineItem
skip_unchanged = True skip_unchanged = True
report_skipped = False report_skipped = False
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):
"""Metaclass options."""
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
line_items = Field(attribute='line_count', widget=widgets.IntegerWidget(), readonly=True) line_items = Field(attribute='line_count', widget=widgets.IntegerWidget(), readonly=True)
@ -147,6 +155,7 @@ class SalesOrderResource(ModelResource):
overdue = Field(attribute='is_overdue', widget=widgets.BooleanWidget(), readonly=True) overdue = Field(attribute='is_overdue', widget=widgets.BooleanWidget(), readonly=True)
class Meta: class Meta:
"""Metaclass options"""
model = SalesOrder model = SalesOrder
skip_unchanged = True skip_unchanged = True
clean_model_instances = True clean_model_instances = True
@ -155,10 +164,8 @@ 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)
@ -169,31 +176,34 @@ class SalesOrderLineItemResource(ModelResource):
fulfilled = Field(attribute='fulfilled_quantity', readonly=True) fulfilled = Field(attribute='fulfilled_quantity', readonly=True)
def dehydrate_sale_price(self, item): def dehydrate_sale_price(self, item):
""" """Return a string value of the 'sale_price' field, rather than the 'Money' object.
Return a string value of the 'sale_price' field, rather than the 'Money' object.
Ref: https://github.com/inventree/InvenTree/issues/2207 Ref: https://github.com/inventree/InvenTree/issues/2207
""" """
if item.sale_price: if item.sale_price:
return str(item.sale_price) return str(item.sale_price)
else: else:
return '' return ''
class Meta: class Meta:
"""Metaclass options"""
model = SalesOrderLineItem model = SalesOrderLineItem
skip_unchanged = True skip_unchanged = True
report_skipped = False report_skipped = False
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):
"""Metaclass options."""
model = SalesOrderExtraLine model = SalesOrderExtraLine
class PurchaseOrderLineItemAdmin(ImportExportModelAdmin): class PurchaseOrderLineItemAdmin(ImportExportModelAdmin):
"""Admin class for the PurchaseOrderLine model"""
resource_class = PurchaseOrderLineItemResource resource_class = PurchaseOrderLineItemResource
@ -210,11 +220,12 @@ class PurchaseOrderLineItemAdmin(ImportExportModelAdmin):
class PurchaseOrderExtraLineAdmin(GeneralExtraLineAdmin, ImportExportModelAdmin): class PurchaseOrderExtraLineAdmin(GeneralExtraLineAdmin, ImportExportModelAdmin):
"""Admin class for the PurchaseOrderExtraLine model"""
resource_class = PurchaseOrderExtraLineResource resource_class = PurchaseOrderExtraLineResource
class SalesOrderLineItemAdmin(ImportExportModelAdmin): class SalesOrderLineItemAdmin(ImportExportModelAdmin):
"""Admin class for the SalesOrderLine model"""
resource_class = SalesOrderLineItemResource resource_class = SalesOrderLineItemResource
@ -236,11 +247,12 @@ class SalesOrderLineItemAdmin(ImportExportModelAdmin):
class SalesOrderExtraLineAdmin(GeneralExtraLineAdmin, ImportExportModelAdmin): class SalesOrderExtraLineAdmin(GeneralExtraLineAdmin, ImportExportModelAdmin):
"""Admin class for the SalesOrderExtraLine model"""
resource_class = SalesOrderExtraLineResource resource_class = SalesOrderExtraLineResource
class SalesOrderShipmentAdmin(ImportExportModelAdmin): class SalesOrderShipmentAdmin(ImportExportModelAdmin):
"""Admin class for the SalesOrderShipment model"""
list_display = [ list_display = [
'order', 'order',
@ -258,6 +270,7 @@ class SalesOrderShipmentAdmin(ImportExportModelAdmin):
class SalesOrderAllocationAdmin(ImportExportModelAdmin): class SalesOrderAllocationAdmin(ImportExportModelAdmin):
"""Admin class for the SalesOrderAllocation model"""
list_display = ( list_display = (
'line', 'line',

View File

@ -3,15 +3,15 @@ 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
category = Field(attribute='category', widget=widgets.ForeignKeyWidget(models.PartCategory)) category = Field(attribute='category', widget=widgets.ForeignKeyWidget(models.PartCategory))
@ -81,8 +81,8 @@ 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,8 +157,8 @@ 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)
@ -269,8 +269,8 @@ 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

@ -3,10 +3,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
@ -14,8 +14,8 @@ 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))
@ -65,8 +65,8 @@ 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
part = Field(attribute='part', widget=widgets.ForeignKeyWidget(Part)) part = Field(attribute='part', widget=widgets.ForeignKeyWidget(Part))

View File

@ -149,7 +149,7 @@ function loadAttachmentTable(url, options) {
var html = `<span class='fas ${icon}'></span> ${filename}`; var html = `<span class='fas ${icon}'></span> ${filename}`;
return renderLink(html, value); return renderLink(html, value, {download: true});
} else if (row.link) { } else if (row.link) {
var html = `<span class='fas fa-link'></span> ${row.link}`; var html = `<span class='fas fa-link'></span> ${row.link}`;
return renderLink(html, row.link); return renderLink(html, row.link);

View File

@ -204,6 +204,9 @@ function constructChangeForm(fields, options) {
}, },
success: function(data) { success: function(data) {
// Ensure the data are fully sanitized before we operate on it
data = sanitizeData(data);
// An optional function can be provided to process the returned results, // An optional function can be provided to process the returned results,
// before they are rendered to the form // before they are rendered to the form
if (options.processResults) { if (options.processResults) {

View File

@ -1306,7 +1306,8 @@ function loadStockTestResultsTable(table, options) {
var html = value; var html = value;
if (row.attachment) { if (row.attachment) {
html += `<a href='${row.attachment}'><span class='fas fa-file-alt float-right'></span></a>`; var text = `<span class='fas fa-file-alt float-right'></span>`;
html += renderLink(text, row.attachment, {download: true});
} }
return html; return html;

View File

@ -92,6 +92,13 @@ function renderLink(text, url, options={}) {
var max_length = options.max_length || -1; var max_length = options.max_length || -1;
var extra = '';
if (options.download) {
var fn = url.split('/').at(-1);
extra += ` download='${fn}'`;
}
// Shorten the displayed length if required // Shorten the displayed length if required
if ((max_length > 0) && (text.length > max_length)) { if ((max_length > 0) && (text.length > max_length)) {
var slice_length = (max_length - 3) / 2; var slice_length = (max_length - 3) / 2;
@ -102,7 +109,7 @@ function renderLink(text, url, options={}) {
text = `${text_start}...${text_end}`; text = `${text_start}...${text_end}`;
} }
return '<a href="' + url + '">' + text + '</a>'; return `<a href='${url}'${extra}>${text}</a>`;
} }
@ -282,6 +289,8 @@ $.fn.inventreeTable = function(options) {
// Extract query params // Extract query params
var filters = options.queryParams || options.filters || {}; var filters = options.queryParams || options.filters || {};
options.escape = true;
// Store the total set of query params // Store the total set of query params
options.query_params = filters; options.query_params = filters;
@ -468,6 +477,49 @@ function customGroupSorter(sortName, sortOrder, sortData) {
$.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['en-US-custom']); $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['en-US-custom']);
// Enable HTML escaping by default
$.fn.bootstrapTable.escape = true;
// Override the 'calculateObjectValue' function at bootstrap-table.js:3525
// Allows us to escape any nasty HTML tags which are rendered to the DOM
$.fn.bootstrapTable.utils._calculateObjectValue = $.fn.bootstrapTable.utils.calculateObjectValue;
$.fn.bootstrapTable.utils.calculateObjectValue = function escapeCellValue(self, name, args, defaultValue) {
var args_list = [];
if (args) {
args_list.push(args[0]);
if (name && typeof(name) === 'function' && name.name == 'formatter') {
/* This is a custom "formatter" function for a particular cell,
* which may side-step regular HTML escaping, and inject malicious code into the DOM.
*
* Here we have access to the 'args' supplied to the custom 'formatter' function,
* which are in the order:
* args = [value, row, index, field]
*
* 'row' is the one we are interested in
*/
var row = Object.assign({}, args[1]);
args_list.push(sanitizeData(row));
} else {
args_list.push(args[1]);
}
for (var ii = 2; ii < args.length; ii++) {
args_list.push(args[ii]);
}
}
var value = $.fn.bootstrapTable.utils._calculateObjectValue(self, name, args_list, defaultValue);
return value;
};
})(jQuery); })(jQuery);
$.extend($.fn.treegrid.defaults, { $.extend($.fn.treegrid.defaults, {