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

Reply via email to