Merge branch 'fix_arbitrary_code_execution' into develop

This commit is contained in:
Jakob Ketterl
2021-01-24 22:47:08 +01:00
15 changed files with 389 additions and 17 deletions

View File

@ -1,4 +1,5 @@
from abc import ABC, abstractmethod
from owrx.property.validators import Validator
import logging
logger = logging.getLogger(__name__)
@ -154,6 +155,50 @@ class PropertyFilter(PropertyManager):
return [k for k in self.pm.keys() if k in self.props]
class PropertyValidationError(Exception):
def __init__(self, key, value):
super().__init__('Invalid value for property "{key}": "{value}"'.format(key=key, value=str(value)))
class PropertyValidator(PropertyManager):
def __init__(self, pm: PropertyManager, validators=None):
self.pm = pm
self.pm.wire(self._fireCallbacks)
if validators is None:
self.validators = {}
else:
self.validators = {k: Validator.of(v) for k, v in validators.items()}
super().__init__()
def validate(self, key, value):
if key not in self.validators:
return
if not self.validators[key].isValid(value):
raise PropertyValidationError(key, value)
def setValidator(self, key, validator):
self.validators[key] = Validator.of(validator)
def __getitem__(self, item):
return self.pm.__getitem__(item)
def __setitem__(self, key, value):
self.validate(key, value)
return self.pm.__setitem__(key, value)
def __contains__(self, item):
return self.pm.__contains__(item)
def __dict__(self):
return self.pm.__dict__()
def __delitem__(self, key):
return self.pm.__delitem__(key)
def keys(self):
return self.pm.keys()
class PropertyStack(PropertyManager):
def __init__(self):
super().__init__()

View File

@ -0,0 +1,98 @@
from abc import ABC, abstractmethod
from functools import reduce
from operator import or_
import re
class ValidatorException(Exception):
pass
class Validator(ABC):
@staticmethod
def of(x):
if isinstance(x, Validator):
return x
if callable(x):
return LambdaValidator(x)
if x in validator_types:
return validator_types[x]()
raise ValidatorException("Cannot create validator")
@abstractmethod
def isValid(self, value):
pass
class LambdaValidator(Validator):
def __init__(self, c):
self.callable = c
def isValid(self, value):
return self.callable(value)
class TypeValidator(Validator):
def __init__(self, type):
self.type = type
super().__init__()
def isValid(self, value):
return isinstance(value, self.type)
class IntegerValidator(TypeValidator):
def __init__(self):
super().__init__(int)
class FloatValidator(TypeValidator):
def __init__(self):
super().__init__(float)
class StringValidator(TypeValidator):
def __init__(self):
super().__init__(str)
class BoolValidator(TypeValidator):
def __init__(self):
super().__init__(bool)
class OrValidator(Validator):
def __init__(self, *validators):
self.validators = validators
super().__init__()
def isValid(self, value):
return reduce(
or_,
[v.isValid(value) for v in self.validators],
False
)
class NumberValidator(OrValidator):
def __init__(self):
super().__init__(IntegerValidator(), FloatValidator())
class RegexValidator(StringValidator):
def __init__(self, regex: re.Pattern):
self.regex = regex
super().__init__()
def isValid(self, value):
return super().isValid(value) and self.regex.match(value) is not None
validator_types = {
"string": StringValidator,
"str": StringValidator,
"integer": IntegerValidator,
"int": IntegerValidator,
"number": NumberValidator,
"num": NumberValidator,
}