BryanDavis has uploaded a new change for review. https://gerrit.wikimedia.org/r/316205
Change subject: Update client side validation for username and shellname ...................................................................... Update client side validation for username and shellname * Add client side regex validation for shellname * Check username for invalid characters in ajax callback. This makes the error message a little more vague, but it improves feedback generally so I think it's ok. Change-Id: I312ae6ba3e33806778e1a95f0b7116262f274d22 --- M striker/register/forms.py M striker/register/utils.py M striker/register/views.py 3 files changed, 61 insertions(+), 27 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/labs/striker refs/changes/05/316205/1 diff --git a/striker/register/forms.py b/striker/register/forms.py index 8f62a9b..8781da9 100644 --- a/striker/register/forms.py +++ b/striker/register/forms.py @@ -35,7 +35,6 @@ @parsleyfy class LDAPUsername(forms.Form): - IN_USE = _('Username is already in use.') username = forms.CharField( label=_('Username'), widget=forms.TextInput( @@ -51,7 +50,8 @@ 'data-parsley-remote': mark_safe( '/register/api/username/{value}'), 'data-parsley-trigger': 'focusin focusout input', - 'data-parsley-remote-message': IN_USE, + 'data-parsley-remote-message': _( + 'Username is already in use or invalid.'), } ), max_length=255, @@ -68,19 +68,8 @@ regex='\S$', message=_('Must not end with whitespace') ), - # See MediaWikiTitleCodec::getTitleInvalidRegex() validators.RegexValidator( - regex=( - # Any char that is not in $wgLegalTitleChars - r'[^' - r''' %!"$&'()*,\-./0-9:;=?@A-Z\^_`a-z~''' - '\x80-\xFF' - r'+]' - # URL percent encoding sequences - r'|%[0-9A-Fa-f]{2}' - # XML/HTML entities - '|&([A-Za-z0-9\x80-\xff]+|#([0-9]+|x[0-9A-Fa-f]+));' - ), + regex=utils.get_username_invalid_regex(), inverse_match=True, message=_( 'Value contains illegal characters or character sequences.' @@ -97,7 +86,7 @@ username = self.cleaned_data['username'].strip() username = username[0].upper() + username[1:] if not utils.username_available(username): - raise forms.ValidationError(self.IN_USE) + raise forms.ValidationError(_('Username is already in use.')) # Check that it isn't banned by some abusefilter type rule user = utils.check_username_create(username) @@ -110,7 +99,14 @@ @parsleyfy class ShellUsername(forms.Form): - IN_USE = _('Shell username is already in use.') + # Unix username regex suggested by useradd(8). + # We don't allow a leading '_' or trailing '$' however. + RE_NAME = r'^[a-z][a-z0-9_-]{0,31}$' + NAME_ERR_MSG = _( + 'Must start with a-z, and can only contain ' + 'lowercase a-z, 0-9, _, and - characters.' + ) + shellname = forms.CharField( label=_('Shell username'), widget=forms.TextInput( @@ -126,19 +122,15 @@ 'data-parsley-remote': mark_safe( '/register/api/shellname/{value}'), 'data-parsley-trigger': 'focusin focusout input', - 'data-parsley-remote-message': IN_USE, + 'data-parsley-remote-message': _( + 'Shell username is already in use or invalid.'), + 'data-parsley-pattern': RE_NAME, + 'data-parsley-pattern-message': NAME_ERR_MSG, } ), max_length=32, validators=[ - validators.RegexValidator( - # Unix username regex suggested by useradd(8). - # We don't allow a leading '_' or trailing '$' however. - regex=r'^[a-z][a-z0-9_-]{0,31}$', - message=_( - 'Must start with a-z, and can only contain ' - 'lowercase a-z, 0-9, _, and - characters.') - ) + validators.RegexValidator(regex=RE_NAME, message=NAME_ERR_MSG), ] ) @@ -146,7 +138,7 @@ """Validate that shellname is available.""" shellname = self.cleaned_data['shellname'] if not utils.shellname_available(shellname): - raise forms.ValidationError(self.IN_USE) + raise forms.ValidationError(_('Shell username is already in use.')) # Check that it isn't banned by some abusefilter type rule user = utils.check_username_create(shellname) diff --git a/striker/register/utils.py b/striker/register/utils.py index 4c3aa27..cd411e2 100644 --- a/striker/register/utils.py +++ b/striker/register/utils.py @@ -18,7 +18,9 @@ # You should have received a copy of the GNU General Public License # along with Striker. If not, see <http://www.gnu.org/licenses/>. +import functools import logging +import re from django.utils import translation from django.utils.translation import ugettext_lazy as _ @@ -41,6 +43,44 @@ return False +@functools.lru_cache(maxsize=1) +def get_username_invalid_regex(): + """Regular expression that matches invalid usernames. + + The most definiative check is to actually pass a potential username to + a live MediaWiki instance, but this regular expression can be used to make + a quick check for obviously invalid names which contain illegal characters + and character sequences. + + See also: MediaWikiTitleCodec::getTitleInvalidRegex() + """ + return re.compile( + # Any char that is not in $wgLegalTitleChars + r'[^' + r''' %!"$&'()*,\-./0-9:;=?@A-Z\^_`a-z~''' + '\x80-\xFF' + r'+]' + # URL percent encoding sequences + r'|%[0-9A-Fa-f]{2}' + # XML/HTML entities + '|&([A-Za-z0-9\x80-\xff]+|#([0-9]+|x[0-9A-Fa-f]+));' + ) + + +def username_valid(name): + """Check a username to see if it is valid. + + Valid usernames are not necessarily available or even creatable. + """ + if re.search(r'^\s', name): + return False + if re.search(r'\s$', name): + return False + if get_username_invalid_regex().search(name): + return False + return True + + def username_available(name): try: Maintainer.objects.get(full_name=name) diff --git a/striker/register/views.py b/striker/register/views.py index 41f662d..8ea311d 100644 --- a/striker/register/views.py +++ b/striker/register/views.py @@ -116,7 +116,9 @@ available. This is to work with the limited choice of default response validators in parsley. """ - available = utils.username_available(name) + available = utils.username_valid(name) + if available: + available = utils.username_available(name) if available: available = utils.check_username_create(name)['ok'] status = 200 if available else 406 -- To view, visit https://gerrit.wikimedia.org/r/316205 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I312ae6ba3e33806778e1a95f0b7116262f274d22 Gerrit-PatchSet: 1 Gerrit-Project: labs/striker Gerrit-Branch: master Gerrit-Owner: BryanDavis <bda...@wikimedia.org> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits