improve validation of hostname and username fields

not sure hostname validation makes perfect sense but at least it is a bit
more transparent now
This commit is contained in:
Michael Hudson-Doyle 2017-10-05 22:14:44 +13:00
parent f4eaea1d6d
commit b06d1a78c4
2 changed files with 23 additions and 1 deletions

View File

@ -14,19 +14,20 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging import logging
import re
from urwid import connect_signal from urwid import connect_signal
from subiquitycore.ui.interactive import ( from subiquitycore.ui.interactive import (
PasswordEditor, PasswordEditor,
StringEditor, StringEditor,
UsernameEditor,
) )
from subiquitycore.ui.form import ( from subiquitycore.ui.form import (
simple_field, simple_field,
Form, Form,
FormField, FormField,
StringField, StringField,
WantsToKnowFromField,
) )
from subiquitycore.ui.container import ListBox from subiquitycore.ui.container import ListBox
from subiquitycore.ui.utils import button_pile, Padding from subiquitycore.ui.utils import button_pile, Padding
@ -56,6 +57,16 @@ class RealnameField(FormField):
def _make_widget(self, form): def _make_widget(self, form):
return RealnameEditor(form) return RealnameEditor(form)
class UsernameEditor(StringEditor, WantsToKnowFromField):
def valid_char(self, ch):
if len(ch) == 1 and not re.match('[a-z0-9_-]', ch):
self.bff.in_error = True
self.bff.show_extra(("info_error", "The only characters permitted in this field are a-z, 0-9, _ and -"))
return False
else:
return super().valid_char(ch)
UsernameField = simple_field(UsernameEditor) UsernameField = simple_field(UsernameEditor)
PasswordField = simple_field(PasswordEditor) PasswordField = simple_field(PasswordEditor)
@ -87,6 +98,9 @@ class IdentityForm(Form):
if len(self.hostname.value) > HOSTNAME_MAXLEN: if len(self.hostname.value) > HOSTNAME_MAXLEN:
return _("Server name too long, must be < ") + str(HOSTNAME_MAXLEN) return _("Server name too long, must be < ") + str(HOSTNAME_MAXLEN)
if not re.match(r'[a-z_][a-z0-9_-]*', self.username.value):
return _("Hostname must match NAME_REGEX, i.e. [a-z_][a-z0-9_-]*")
def validate_username(self): def validate_username(self):
if len(self.username.value) < 1: if len(self.username.value) < 1:
return _("Username missing") return _("Username missing")
@ -94,6 +108,9 @@ class IdentityForm(Form):
if len(self.username.value) > USERNAME_MAXLEN: if len(self.username.value) > USERNAME_MAXLEN:
return _("Username too long, must be < ") + str(USERNAME_MAXLEN) return _("Username too long, must be < ") + str(USERNAME_MAXLEN)
if not re.match(r'[a-z_][a-z0-9_-]*', self.username.value):
return _("Username must match NAME_REGEX, i.e. [a-z_][a-z0-9_-]*")
def validate_password(self): def validate_password(self):
# XXX we should not require a password if an ssh identity is provided # XXX we should not require a password if an ssh identity is provided
# Form doesn't support form-wide validation yet though, oops. # Form doesn't support form-wide validation yet though, oops.

View File

@ -91,6 +91,9 @@ class FormField(object):
return BoundFormField(self, form, widget) return BoundFormField(self, form, widget)
class WantsToKnowFromField(object):
"""A marker class."""
class BoundFormField(object): class BoundFormField(object):
def __init__(self, field, form, widget): def __init__(self, field, form, widget):
@ -105,6 +108,8 @@ class BoundFormField(object):
self.widget = widget self.widget = widget
if 'change' in getattr(widget, 'signals', []): if 'change' in getattr(widget, 'signals', []):
connect_signal(widget, 'change', self._change) connect_signal(widget, 'change', self._change)
if isinstance(widget, WantsToKnowFromField):
widget.bff = self
def clean(self, value): def clean(self, value):
cleaner = getattr(self.form, "clean_" + self.field.name, None) cleaner = getattr(self.form, "clean_" + self.field.name, None)