Improved webapps directive validation
This commit is contained in:
parent
c119ef9bc0
commit
ae0968f58f
3
TODO.md
3
TODO.md
|
@ -426,3 +426,6 @@ Case
|
||||||
|
|
||||||
# Discount prepaid metric should be more optimal https://orchestra.pangea.org/admin/orders/order/40/
|
# Discount prepaid metric should be more optimal https://orchestra.pangea.org/admin/orders/order/40/
|
||||||
# -> order.billed_metric besides billed_until
|
# -> order.billed_metric besides billed_until
|
||||||
|
|
||||||
|
|
||||||
|
# websites directives: redirect strip() and allow empty URL_path
|
||||||
|
|
|
@ -34,13 +34,11 @@ class ListSerializer(AccountSerializerMixin, SetPasswordHyperlinkedSerializer):
|
||||||
fields = ('url', 'id', 'name', 'password', 'address_name', 'address_domain', 'admin_email')
|
fields = ('url', 'id', 'name', 'password', 'address_name', 'address_domain', 'admin_email')
|
||||||
postonly_fields = ('name', 'password')
|
postonly_fields = ('name', 'password')
|
||||||
|
|
||||||
def validate_address_domain(self, attrs, source):
|
def validate_address_domain(self, address_name):
|
||||||
address_domain = attrs.get(source)
|
|
||||||
address_name = attrs.get('address_name')
|
|
||||||
if self.instance:
|
if self.instance:
|
||||||
address_domain = address_domain or self.instance.address_domain
|
address_domain = address_domain or self.instance.address_domain
|
||||||
address_name = address_name or self.instance.address_name
|
address_name = address_name or self.instance.address_name
|
||||||
if address_name and not address_domain:
|
if address_name and not address_domain:
|
||||||
raise serializers.ValidationError(
|
raise serializers.ValidationError(
|
||||||
_("address_domains should should be provided when providing an addres_name"))
|
_("address_domains should should be provided when providing an addres_name"))
|
||||||
return attrs
|
return address_name
|
||||||
|
|
|
@ -11,13 +11,15 @@ class PaymentSourceSerializer(AccountSerializerMixin, serializers.HyperlinkedMod
|
||||||
model = PaymentSource
|
model = PaymentSource
|
||||||
fields = ('url', 'id', 'method', 'data', 'is_active')
|
fields = ('url', 'id', 'method', 'data', 'is_active')
|
||||||
|
|
||||||
def validate_data(self, attrs, source):
|
def validate(self, data):
|
||||||
plugin = PaymentMethod.get(attrs['method'])
|
""" validate data according to method """
|
||||||
|
data = super(PaymentSourceSerializer, self).validate(data)
|
||||||
|
plugin = PaymentMethod.get(data['method'])
|
||||||
serializer_class = plugin().get_serializer()
|
serializer_class = plugin().get_serializer()
|
||||||
serializer = serializer_class(data=attrs[source])
|
serializer = serializer_class(data=data['data'])
|
||||||
if not serializer.is_valid():
|
if not serializer.is_valid():
|
||||||
raise serializers.ValidationError(serializer.errors)
|
raise serializers.ValidationError(serializer.errors)
|
||||||
return attrs
|
return data
|
||||||
|
|
||||||
def transform_data(self, obj, value):
|
def transform_data(self, obj, value):
|
||||||
if not obj:
|
if not obj:
|
||||||
|
|
|
@ -48,9 +48,8 @@ def insert_resource_serializers():
|
||||||
except KeyError:
|
except KeyError:
|
||||||
continue
|
continue
|
||||||
# TODO this is a fucking workaround, reimplement this on the proper place
|
# TODO this is a fucking workaround, reimplement this on the proper place
|
||||||
def validate_resources(self, attrs, source, _resources=resources):
|
def validate_resources(self, posted, _resources=resources):
|
||||||
""" Creates missing resources """
|
""" Creates missing resources """
|
||||||
posted = attrs.get(source, [])
|
|
||||||
result = []
|
result = []
|
||||||
resources = list(_resources)
|
resources = list(_resources)
|
||||||
for data in posted:
|
for data in posted:
|
||||||
|
@ -67,8 +66,7 @@ def insert_resource_serializers():
|
||||||
if not resource.on_demand:
|
if not resource.on_demand:
|
||||||
data.allocated = resource.default_allocation
|
data.allocated = resource.default_allocation
|
||||||
result.append(data)
|
result.append(data)
|
||||||
attrs[source] = result
|
return result
|
||||||
return attrs
|
|
||||||
viewset = router.get_viewset(model)
|
viewset = router.get_viewset(model)
|
||||||
viewset.serializer_class.validate_resources = validate_resources
|
viewset.serializer_class.validate_resources = validate_resources
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,10 @@ class SystemUserFormMixin(object):
|
||||||
};""" % username
|
};""" % username
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def clean_directory(self):
|
||||||
|
directory = self.cleaned_data['directory']
|
||||||
|
return directory.lstrip('/')
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
super(SystemUserFormMixin, self).clean()
|
super(SystemUserFormMixin, self).clean()
|
||||||
cleaned_data = self.cleaned_data
|
cleaned_data = self.cleaned_data
|
||||||
|
@ -113,6 +117,10 @@ class PermissionForm(forms.Form):
|
||||||
(user.get_base_home(), user.get_base_home()) for user in related_users
|
(user.get_base_home(), user.get_base_home()) for user in related_users
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def clean_home_extension(self):
|
||||||
|
home_extension = self.cleaned_data['home_extension']
|
||||||
|
return home_extension.lstrip('/')
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
cleaned_data = super(PermissionForm, self).clean()
|
cleaned_data = super(PermissionForm, self).clean()
|
||||||
path = os.path.join(cleaned_data['base_home'], cleaned_data['home_extension'])
|
path = os.path.join(cleaned_data['base_home'], cleaned_data['home_extension'])
|
||||||
|
|
|
@ -96,6 +96,7 @@ class SystemUser(models.Model):
|
||||||
super(SystemUser, self).save(*args, **kwargs)
|
super(SystemUser, self).save(*args, **kwargs)
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
|
self.directory = self.directory.lstrip('/')
|
||||||
if self.home:
|
if self.home:
|
||||||
self.home = os.path.normpath(self.home)
|
self.home = os.path.normpath(self.home)
|
||||||
if self.directory:
|
if self.directory:
|
||||||
|
|
|
@ -24,20 +24,20 @@ class SystemUserSerializer(AccountSerializerMixin, SetPasswordHyperlinkedSeriali
|
||||||
)
|
)
|
||||||
postonly_fields = ('username', 'password')
|
postonly_fields = ('username', 'password')
|
||||||
|
|
||||||
def validate(self, attrs):
|
def validate_directory(self, directory):
|
||||||
attrs = super(SystemUserSerializer, self).validate(attrs)
|
return directory.lstrip('/')
|
||||||
user = SystemUser(
|
|
||||||
username=attrs.get('username') or self.instance.username,
|
|
||||||
shell=attrs.get('shell') or self.instance.shell,
|
|
||||||
)
|
|
||||||
validate_home(user, attrs, self.get_account())
|
|
||||||
return attrs
|
|
||||||
|
|
||||||
def validate_groups(self, attrs, source):
|
def validate(self, data):
|
||||||
groups = attrs.get(source)
|
data = super(SystemUserSerializer, self).validate(data)
|
||||||
|
user = SystemUser(
|
||||||
|
username=data.get('username') or self.instance.username,
|
||||||
|
shell=data.get('shell') or self.instance.shell,
|
||||||
|
)
|
||||||
|
validate_home(user, data, self.get_account())
|
||||||
|
groups = data.get('groups')
|
||||||
if groups:
|
if groups:
|
||||||
for group in groups:
|
for group in groups:
|
||||||
if group.username == attrs['username']:
|
if group.username == data['username']:
|
||||||
raise serializers.ValidationError(
|
raise serializers.ValidationError(
|
||||||
_("Do not make the user member of its group"))
|
_("Do not make the user member of its group"))
|
||||||
return attrs
|
return data
|
||||||
|
|
|
@ -6,7 +6,7 @@ from django.utils.translation import ugettext_lazy as _
|
||||||
from orchestra.contrib.orchestration import Operation
|
from orchestra.contrib.orchestration import Operation
|
||||||
|
|
||||||
|
|
||||||
def validate_path_exists(user, path, ):
|
def validate_path_exists(user, path):
|
||||||
user.path_to_validate = path
|
user.path_to_validate = path
|
||||||
log = Operation.execute_action(user, 'validate_path_exists')[0]
|
log = Operation.execute_action(user, 'validate_path_exists')[0]
|
||||||
if 'path does not exists' in log.stderr:
|
if 'path does not exists' in log.stderr:
|
||||||
|
|
|
@ -84,12 +84,13 @@ class SiteDirective(Plugin):
|
||||||
if errors:
|
if errors:
|
||||||
raise ValidationError(errors)
|
raise ValidationError(errors)
|
||||||
|
|
||||||
def validate(self, website):
|
def validate(self, directive):
|
||||||
if self.regex and not re.match(self.regex, website.value):
|
directive.value = directive.value.strip()
|
||||||
|
if self.regex and not re.match(self.regex, directive.value):
|
||||||
raise ValidationError({
|
raise ValidationError({
|
||||||
'value': ValidationError(_("'%(value)s' does not match %(regex)s."),
|
'value': ValidationError(_("'%(value)s' does not match %(regex)s."),
|
||||||
params={
|
params={
|
||||||
'value': website.value,
|
'value': directive.value,
|
||||||
'regex': self.regex
|
'regex': self.regex
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
@ -99,20 +100,25 @@ class Redirect(SiteDirective):
|
||||||
name = 'redirect'
|
name = 'redirect'
|
||||||
verbose_name = _("Redirection")
|
verbose_name = _("Redirection")
|
||||||
help_text = _("<tt><website path> <destination URL></tt>")
|
help_text = _("<tt><website path> <destination URL></tt>")
|
||||||
regex = r'^[^ ]+\s[^ ]+$'
|
regex = r'^[^ ]*\s[^ ]+$'
|
||||||
group = SiteDirective.HTTPD
|
group = SiteDirective.HTTPD
|
||||||
unique_value = True
|
unique_value = True
|
||||||
unique_location = True
|
unique_location = True
|
||||||
|
|
||||||
|
def validate(self, directive):
|
||||||
|
""" inserts default url path if not provided """
|
||||||
|
values = directive.value.strip().split()
|
||||||
|
if len(values) == 1:
|
||||||
|
values.insert(0, '/')
|
||||||
|
directive.value = ' '.join(values)
|
||||||
|
super(Redirect, self).validate(directive)
|
||||||
|
|
||||||
class Proxy(SiteDirective):
|
|
||||||
|
class Proxy(Redirect):
|
||||||
name = 'proxy'
|
name = 'proxy'
|
||||||
verbose_name = _("Proxy")
|
verbose_name = _("Proxy")
|
||||||
help_text = _("<tt><website path> <target URL></tt>")
|
help_text = _("<tt><website path> <target URL></tt>")
|
||||||
regex = r'^[^ ]+\shttp[^ ]+(timeout=[0-9]{1,3}|retry=[0-9]|\s)*$'
|
regex = r'^[^ ]+\shttp[^ ]+(timeout=[0-9]{1,3}|retry=[0-9]|\s)*$'
|
||||||
group = SiteDirective.HTTPD
|
|
||||||
unique_value = True
|
|
||||||
unique_location = True
|
|
||||||
|
|
||||||
|
|
||||||
class ErrorDocument(SiteDirective):
|
class ErrorDocument(SiteDirective):
|
||||||
|
@ -132,27 +138,21 @@ class SSLCA(SiteDirective):
|
||||||
name = 'ssl-ca'
|
name = 'ssl-ca'
|
||||||
verbose_name = _("SSL CA")
|
verbose_name = _("SSL CA")
|
||||||
help_text = _("Filesystem path of the CA certificate file.")
|
help_text = _("Filesystem path of the CA certificate file.")
|
||||||
regex = r'^[^ ]+$'
|
regex = r'^/[^ ]+$'
|
||||||
group = SiteDirective.SSL
|
group = SiteDirective.SSL
|
||||||
unique_name = True
|
unique_name = True
|
||||||
|
|
||||||
|
|
||||||
class SSLCert(SiteDirective):
|
class SSLCert(SSLCA):
|
||||||
name = 'ssl-cert'
|
name = 'ssl-cert'
|
||||||
verbose_name = _("SSL cert")
|
verbose_name = _("SSL cert")
|
||||||
help_text = _("Filesystem path of the certificate file.")
|
help_text = _("Filesystem path of the certificate file.")
|
||||||
regex = r'^[^ ]+$'
|
|
||||||
group = SiteDirective.SSL
|
|
||||||
unique_name = True
|
|
||||||
|
|
||||||
|
|
||||||
class SSLKey(SiteDirective):
|
class SSLKey(SSLCA):
|
||||||
name = 'ssl-key'
|
name = 'ssl-key'
|
||||||
verbose_name = _("SSL key")
|
verbose_name = _("SSL key")
|
||||||
help_text = _("Filesystem path of the key file.")
|
help_text = _("Filesystem path of the key file.")
|
||||||
regex = r'^[^ ]+$'
|
|
||||||
group = SiteDirective.SSL
|
|
||||||
unique_name = True
|
|
||||||
|
|
||||||
|
|
||||||
class SecRuleRemove(SiteDirective):
|
class SecRuleRemove(SiteDirective):
|
||||||
|
@ -164,13 +164,11 @@ class SecRuleRemove(SiteDirective):
|
||||||
unique_location = True
|
unique_location = True
|
||||||
|
|
||||||
|
|
||||||
class SecEngine(SiteDirective):
|
class SecEngine(SecRuleRemove):
|
||||||
name = 'sec-engine'
|
name = 'sec-engine'
|
||||||
verbose_name = _("SecRuleEngine Off")
|
verbose_name = _("SecRuleEngine Off")
|
||||||
help_text = _("URL path with disabled modsecurity engine.")
|
help_text = _("URL path with disabled modsecurity engine.")
|
||||||
regex = r'^/[^ ]*$'
|
regex = r'^/[^ ]*$'
|
||||||
group = SiteDirective.SEC
|
|
||||||
unique_value = True
|
|
||||||
|
|
||||||
|
|
||||||
class WordPressSaaS(SiteDirective):
|
class WordPressSaaS(SiteDirective):
|
||||||
|
@ -183,21 +181,13 @@ class WordPressSaaS(SiteDirective):
|
||||||
unique_location = True
|
unique_location = True
|
||||||
|
|
||||||
|
|
||||||
class DokuWikiSaaS(SiteDirective):
|
class DokuWikiSaaS(WordPressSaaS):
|
||||||
name = 'dokuwiki-saas'
|
name = 'dokuwiki-saas'
|
||||||
verbose_name = "DokuWiki SaaS"
|
verbose_name = "DokuWiki SaaS"
|
||||||
help_text = _("URL path for mounting wordpress multisite.")
|
help_text = _("URL path for mounting wordpress multisite.")
|
||||||
group = SiteDirective.SAAS
|
|
||||||
regex = r'^/[^ ]*$'
|
|
||||||
unique_value = True
|
|
||||||
unique_location = True
|
|
||||||
|
|
||||||
|
|
||||||
class DrupalSaaS(SiteDirective):
|
class DrupalSaaS(WordPressSaaS):
|
||||||
name = 'drupal-saas'
|
name = 'drupal-saas'
|
||||||
verbose_name = "Drupdal SaaS"
|
verbose_name = "Drupdal SaaS"
|
||||||
help_text = _("URL path for mounting wordpress multisite.")
|
help_text = _("URL path for mounting wordpress multisite.")
|
||||||
group = SiteDirective.SAAS
|
|
||||||
regex = r'^/[^ ]*$'
|
|
||||||
unique_value = True
|
|
||||||
unique_location = True
|
|
||||||
|
|
Loading…
Reference in a new issue