
Research
/Security News
9 Malicious NuGet Packages Deliver Time-Delayed Destructive Payloads
Socket researchers discovered nine malicious NuGet packages that use time-delayed payloads to crash applications and corrupt industrial control systems.
data-spec-validator
Advanced tools
def do_something(params):
val_a_must_int = params.get('a', 0)
val_b_must_be_non_empty_list = params.get('b', [])
# if key c presents, value c must be a date string between '2000-01-01' to '2020-01-01'
val_c_might_be_none = params.get('c', None)
# check type
if type(val_a_must_int) != int:
raise XXX
# check type & value
if type(val_b_must_list) != list or len(val_b_must_be_non_empty_list) == 0:
raise XXX
# if value exists, check its value
if val_c_might_be_none is not None:
date_c = datetime.strptime(val_c_might_be_present, '%Y-%m-%d')
date_20000101 = datetime.date(2000, 1, 1)
date_20200101 = datetime.date(2020, 1, 1)
if not (date_20000101 <= date_c <= date_20200101):
raise XXX
...
# do something actually
pip install data-spec-validator
dsv may depend on Django (support v3.0 or later) or djangorestframework.pip install data-spec-validator[decorator-dj] # Django Only
pip install data-spec-validator[decorator] # Django Rest Framework
validate_data_spec directly wherever you likefrom data_spec_validator.spec import INT, DIGIT_STR, ONE_OF, LIST_OF, Checker, CheckerOP, validate_data_spec
class SomeSpec:
field_a = Checker([INT])
field_b = Checker([DIGIT_STR], optional=True)
field_c = Checker([DIGIT_STR, INT], op=CheckerOP.ANY)
filed_d_array = Checker([LIST_OF], LIST_OF=int, alias='field_d[]', optional=True)
some_data = dict(field_a=4, field_b='3', field_c=1, field_dont_care=[5,6])
validate_data_spec(some_data, SomeSpec) # return True
some_data = dict(field_a=4, field_c='1')
validate_data_spec(some_data, SomeSpec) # return True
some_data = {
'field_a': 4,
'field_c': 1,
'field_d[]': [5, 6],
}
validate_data_spec(some_data, SomeSpec) # return True
some_data = dict(field_a='4', field_c='1')
validate_data_spec(some_data, SomeSpec) # raise Exception
some_data = dict(field_a='4', field_c='1')
validate_data_spec(some_data, SomeSpec, nothrow=True) # return False
class AnotherSpec:
field = Checker([ONE_OF], ONE_OF=[1, '2', [3, 4], {'5': 6}])
another_data = dict(field=[3, 4])
validate_data_spec(another_data, AnotherSpec) # return True
another_data = dict(field='4')
validate_data_spec(another_data, AnotherSpec) # raise Exception
from data_spec_validator.spec import INT, STR, Checker, validate_data_spec
class SingleSpec:
f_a = Checker([INT])
f_b = Checker([STR])
multirow_data = [dict(f_a=1, f_b='1'), dict(f_a=2, f_b='2'), dict(f_a=3, f_b='3')]
validate_data_spec(multirow_data, SingleSpec, multirow=True) # return True
test_spec.py/test_class_type_spec.py for more cases)int_field = Checker([INT]) or Checker[int]
float_field = Checker([FLOAT]) or Checker([float])
number_field = Checker([NUMBER])
str_field = Checker([STR]) or Checker([str])
digi_str_field = Checker([DIGIT_STR])
bool_field = Checker([BOOL]) or Checker([bool])
dict_field = Checker([DICT]) or Checker([dict])
list_field = Checker([LIST]) or Checker([list])
date_obj_field = Checker([DATE_OBJECT]) or Checker([datetime.date])
datetime_obj_field = Checker([DATETIME_OBJECT]) or Checker([datetime.datetime])
none_field = Checker([NONE]) or Checker([type(None)])
json_field = Checker([JSON])
json_bool_field = Checker([JSON_BOOL])
one_of_field = Checker([ONE_OF], ONE_OF=['a', 'b', 'c'])
spec_field = Checker([SPEC], SPEC=SomeSpecClass)
list_of_int_field = Checker([LIST_OF], LIST_OF=INT)
list_of_spec_field = Checker([LIST_OF], LIST_OF=SomeSpecClass)
length_field = Checker([LENGTH], LENGTH=dict(min=3, max=5))
amount_field = Checker([AMOUNT])
amount_range_field = Checker([AMOUNT_RANGE], AMOUNT_RANGE=dict(min=-2.1, max=3.8))
decimal_place_field = Checker([DECIMAL_PLACE], DECIMAL_PLACE=4)
date_field = Checker([DATE])
date_range_field = Checker([DATE_RANGE], DATE_RANGE=dict(min='2000-01-01', max='2010-12-31'))
email_field = Checker([EMAIL])
uuid_field = Checker([UUID]) or Checker([uuid.UUID])
re_field = Checker([REGEX], REGEX=dict(pattern=r'^The'))
re_field = Checker([REGEX], REGEX=dict(pattern=r'watch out', method='match'))
If a exists, c must not exist, if b exists, a must exist, if c exists, a must not exist.
Practically, optional=True will be configured in the most use cases, FMI, see test/test_spec.py
a = Checker([COND_EXIST], optional=True, COND_EXIST=dict(WITHOUT=['c']))
b = Checker([COND_EXIST], optional=True, COND_EXIST=dict(WITH=['a']))
c = Checker([COND_EXIST], optional=True, COND_EXIST=dict(WITHOUT=['a']))
class SomeClass:
pass
a = Checker([SomeClass])
dsv, the method must meet one of the following requirements.
django.core.handlers.wsgi.WSGIRequest) attribute.rest_framework.request.Request instance.rest_framework.decorators import api_view, the 1st argument is a rest_framework.request.Requestfrom rest_framework.decorators import api_view
from rest_framework.views import APIView
from data_spec_validator.decorator import dsv
from data_spec_validator.spec import UUID, EMAIL, Checker
class SomeViewSpec:
param_a = Checker([UUID])
param_b = Checker([EMAIL])
class SomeView(APIView):
@dsv(SomeViewSpec)
def get(self, request):
pass
@api_view(('POST',))
@dsv(SomeViewSpec)
def customer_create(request):
pass
@api_view(('POST',))
@dsv(SomeViewSpec, multirow=True) # For type(request.POST) is list
def customer_create(request):
pass
dsv_request_meta can help you validate the META in request header.gt_check in this case) and write custom Validator(GreaterThanValidator in this case)gt_check = 'gt_check'
from data_spec_validator.spec.defines import BaseValidator
class GreaterThanValidator(BaseValidator):
name = gt_check
@staticmethod
def validate(value, extra, data):
criteria = extra.get(GreaterThanValidator.name)
return value > criteria, ValueError(f'{value} is not greater than {criteria}')
from data_spec_validator.spec import custom_spec, Checker, validate_data_spec
custom_spec.register(dict(gt_check=GreaterThanValidator()))
class GreaterThanSpec:
key = Checker(['gt_check'], GT_CHECK=10)
ok_data = dict(key=11)
validate_data_spec(ok_data, GreaterThanSpec) # return True
nok_data = dict(key=9)
validate_data_spec(ok_data, GreaterThanSpec) # raise Exception
reset_msg_level(vague=True)# In default mode, any exception happens, there will be a reason in the message
"field: XXX, reason: '3' is not a integer"
# In vague mode, any exception happens, a general message is shown
"field: XXX not well-formatted"
dsv_feature(strict=True) detects unexpected key/value in datafrom data_spec_validator.spec import Checker, validate_data_spec, dsv_feature, BOOL
@dsv_feature(strict=True)
class StrictSpec:
a = Checker([BOOL])
ok_data = dict(a=True)
validate_data_spec(ok_data, StrictSpec) # return True
nok_data = dict(a=True, b=1)
validate_data_spec(nok_data, StrictSpec) # raise Exception
dsv_feature(any_keys_set={...}) means that at least one key among a keys tuple from the set must exist.from data_spec_validator.spec import Checker, validate_data_spec, dsv_feature, INT
@dsv_feature(any_keys_set={('a', 'b'), ('c', 'd')})
class _AnyKeysSetSpec:
a = Checker([INT], optional=True)
b = Checker([INT], optional=True)
c = Checker([INT], optional=True)
d = Checker([INT], optional=True)
validate_data_spec(dict(a=1, c=1, d=1), _AnyKeysSetSpec)
validate_data_spec(dict(a=1, c=1), _AnyKeysSetSpec)
validate_data_spec(dict(a=1, d=1), _AnyKeysSetSpec)
validate_data_spec(dict(b=1, c=1, d=1), _AnyKeysSetSpec)
validate_data_spec(dict(b=1, c=1), _AnyKeysSetSpec)
validate_data_spec(dict(b=1, d=1), _AnyKeysSetSpec)
validate_data_spec(dict(a=1, b=1, c=1), _AnyKeysSetSpec)
validate_data_spec(dict(a=1, b=1, d=1), _AnyKeysSetSpec)
validate_data_spec(dict(a=1, b=1, c=1, d=1), _AnyKeysSetSpec)
validate_data_spec(dict(a=1), _AnyKeysSetSpec) # raise exception
validate_data_spec(dict(b=1), _AnyKeysSetSpec) # raise exception
validate_data_spec(dict(c=1), _AnyKeysSetSpec) # raise exception
validate_data_spec(dict(d=1), _AnyKeysSetSpec) # raise exception
validate_data_spec(dict(e=1), _AnyKeysSetSpec) # raise exception
NOTE 1: ErrorMode.MSE stands for MOST-SIGNIFICANT-ERROR
NOTE 2: The validation results respect to the ErrorMode feature config on the OUTER-MOST spec. All nested specs
follow the OUTER-MOST spec configuration, for more reference, see test_spec.py:test_err_mode
from data_spec_validator.spec import Checker, validate_data_spec, dsv_feature, LENGTH, STR, AMOUNT, ErrorMode, INT, DIGIT_STR
@dsv_feature(err_mode=ErrorMode.ALL)
class _ErrModeAllSpec:
a = Checker([INT])
b = Checker([DIGIT_STR])
c = Checker([LENGTH, STR, AMOUNT], LENGTH=dict(min=3, max=5))
nok_data = dict(
a=True,
b='abc',
c='22',
)
validate_data_spec(nok_data, _ErrModeAllSpec) # raise DSVError
"""
A DSVError is raised with 3 errors in args.
(TypeError('field: _ErrModeAllSpec.a, reason: True is not an integer',),
TypeError("field: _ErrModeAllSpec.b, reason: 'abc' is not a digit str",),
ValueError("field: _ErrModeAllSpec.c, reason: Length of '22' must be between 3 and 5",))
"""
from data_spec_validator.spec import Checker, dsv_feature, validate_data_spec, INT
@dsv_feature(spec_name='CustomSpecName')
class _MySpec:
a = Checker([INT])
nok_data = dict(
a='abc',
)
validate_data_spec(nok_data, _MySpec)
"""
TypeError: field: CustomSpecName.a, reason: 'abc' is not an integer
"""
python -m unittest test/*.*
FAQs
Validation tool for API/Function parameters
We found that data-spec-validator demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
/Security News
Socket researchers discovered nine malicious NuGet packages that use time-delayed payloads to crash applications and corrupt industrial control systems.

Security News
Socket CTO Ahmad Nassri discusses why supply chain attacks now target developer machines and what AI means for the future of enterprise security.

Security News
Learn the essential steps every developer should take to stay secure on npm and reduce exposure to supply chain attacks.