Skip to content

Commit 5b5091b

Browse files
committed
issue2550921 - prevent usernames with characters ',' and '<', '>'
Can create login name with , in it. Confuses nosy list editing. Also can embed html tags. Updated userauditor.py to prevent this.
1 parent 416b284 commit 5b5091b

File tree

8 files changed

+70
-1
lines changed

8 files changed

+70
-1
lines changed

CHANGES.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@ Fixed:
2121
- issue2550996 - Give better error message when running with -c
2222
(install as windows service) and pywin32 is not importable. Could use
2323
better testing on a windows box. (John Rouillard)
24-
24+
- issue2550921 - Can create login name with , in it. Confuses nosy
25+
list editing. Also can embed html tags. Updated userauditor.py
26+
to prevent this. See updating.txt.
27+
2528
2019-10-23 2.0.0 alpha 0
2629

2730
Features:

doc/upgrading.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,19 @@ or::
112112

113113
if db.tx_Source in ['web', 'rest', 'xmlrpc', 'email-sig-openpgp', 'cli' ]:
114114

115+
Update userauditor.py to restrict usernames
116+
-------------------------------------------
117+
118+
A username can be created with embedded commas and &lt; and &gt;
119+
characters. Even though the &lt; and &gt; are usually escaped when
120+
displayed, the embedded comma makes it difficult to edit lists of
121+
users as they are comma separated.
122+
123+
If you have not modified your tracker's userauditor.py, you can just
124+
copy the userauditor.py from the classic template into your tracker's
125+
detectors directory. Otherwise merge the changes from the template
126+
userauditor.py. https://issues.roundup-tracker.org/issue2550921 may be
127+
helpful.
115128

116129
Migrating from 1.5.1 to 1.6.0
117130
=============================

share/roundup/templates/classic/detectors/userauditor.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
email_rfc = re.compile('^' + email_regexp[0] + '@' + email_regexp[1] + '$', re.IGNORECASE)
2828
email_local = re.compile('^' + email_regexp[0] + '$', re.IGNORECASE)
2929

30+
valid_username = re.compile('^[a-z0-9_@!%.+-]+$', re.IGNORECASE)
31+
3032
def valid_address(address):
3133
''' If we see an @-symbol in the address then check against the full
3234
RFC syntax. Otherwise it is a local-only address so only check
@@ -54,8 +56,13 @@ def audit_user_fields(db, cl, nodeid, newvalues):
5456
- email address is unique
5557
- roles specified exist
5658
- timezone is valid
59+
- username matches A-z0-9_-.@!+% (email symbols)
5760
'''
5861

62+
if 'username' in newvalues:
63+
if not valid_username.match(newvalues['username']):
64+
raise ValueError("Username/Login Name must consist only of the letters a-z (any case), digits 0-9 and the symbols: @._-!+%")
65+
5966
for address in get_addresses(newvalues):
6067
if not valid_address(address):
6168
raise ValueError('Email address syntax is invalid "%s"'%address)

share/roundup/templates/devel/detectors/userauditor.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
email_rfc = re.compile('^' + email_regexp[0] + '@' + email_regexp[1] + '$', re.IGNORECASE)
2828
email_local = re.compile('^' + email_regexp[0] + '$', re.IGNORECASE)
2929

30+
valid_username = re.compile('^[a-z0-9_@!%.+-]+$', re.IGNORECASE)
31+
3032
def valid_address(address):
3133
''' If we see an @-symbol in the address then check against the full
3234
RFC syntax. Otherwise it is a local-only address so only check
@@ -54,8 +56,13 @@ def audit_user_fields(db, cl, nodeid, newvalues):
5456
- email address is unique
5557
- roles specified exist
5658
- timezone is valid
59+
- username matches A-z0-9_-.@!+% (email symbols)
5760
'''
5861

62+
if 'username' in newvalues:
63+
if not valid_username.match(newvalues['username']):
64+
raise ValueError("Username/Login Name must consist only of the letters a-z (any case), digits 0-9 and the symbols: @._-!+%")
65+
5966
for address in get_addresses(newvalues):
6067
if not valid_address(address):
6168
raise ValueError('Email address syntax is invalid "%s"'%address)

share/roundup/templates/jinja2/detectors/userauditor.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
email_rfc = re.compile('^' + email_regexp[0] + '@' + email_regexp[1] + '$', re.IGNORECASE)
2828
email_local = re.compile('^' + email_regexp[0] + '$', re.IGNORECASE)
2929

30+
valid_username = re.compile('^[a-z0-9_@!%.+-]+$', re.IGNORECASE)
31+
3032
def valid_address(address):
3133
''' If we see an @-symbol in the address then check against the full
3234
RFC syntax. Otherwise it is a local-only address so only check
@@ -54,8 +56,13 @@ def audit_user_fields(db, cl, nodeid, newvalues):
5456
- email address is unique
5557
- roles specified exist
5658
- timezone is valid
59+
- username matches A-z0-9_-.@!+% (email symbols)
5760
'''
5861

62+
if 'username' in newvalues:
63+
if not valid_username.match(newvalues['username']):
64+
raise ValueError("Username/Login Name must consist only of the letters a-z (any case), digits 0-9 and the symbols: @._-!+%")
65+
5966
for address in get_addresses(newvalues):
6067
if not valid_address(address):
6168
raise ValueError('Email address syntax is invalid "%s"'%address)

share/roundup/templates/minimal/detectors/userauditor.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
email_rfc = re.compile('^' + email_regexp[0] + '@' + email_regexp[1] + '$', re.IGNORECASE)
2828
email_local = re.compile('^' + email_regexp[0] + '$', re.IGNORECASE)
2929

30+
valid_username = re.compile('^[a-z0-9_@!%.+-]+$', re.IGNORECASE)
31+
3032
def valid_address(address):
3133
''' If we see an @-symbol in the address then check against the full
3234
RFC syntax. Otherwise it is a local-only address so only check
@@ -54,8 +56,13 @@ def audit_user_fields(db, cl, nodeid, newvalues):
5456
- email address is unique
5557
- roles specified exist
5658
- timezone is valid
59+
- username matches A-z0-9_-.@!+% (email symbols)
5760
'''
5861

62+
if 'username' in newvalues:
63+
if not valid_username.match(newvalues['username']):
64+
raise ValueError("Username/Login Name must consist only of the letters a-z (any case), digits 0-9 and the symbols: @._-!+%")
65+
5966
for address in get_addresses(newvalues):
6067
if not valid_address(address):
6168
raise ValueError('Email address syntax is invalid "%s"'%address)

share/roundup/templates/responsive/detectors/userauditor.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
email_rfc = re.compile('^' + email_regexp[0] + '@' + email_regexp[1] + '$', re.IGNORECASE)
2828
email_local = re.compile('^' + email_regexp[0] + '$', re.IGNORECASE)
2929

30+
valid_username = re.compile('^[a-z0-9_@!%.+-]+$', re.IGNORECASE)
31+
3032
def valid_address(address):
3133
''' If we see an @-symbol in the address then check against the full
3234
RFC syntax. Otherwise it is a local-only address so only check
@@ -54,8 +56,13 @@ def audit_user_fields(db, cl, nodeid, newvalues):
5456
- email address is unique
5557
- roles specified exist
5658
- timezone is valid
59+
- username matches A-z0-9_-.@!+% (email symbols)
5760
'''
5861

62+
if 'username' in newvalues:
63+
if not valid_username.match(newvalues['username']):
64+
raise ValueError("Username/Login Name must consist only of the letters a-z (any case), digits 0-9 and the symbols: @._-!+%")
65+
5966
for address in get_addresses(newvalues):
6067
if not valid_address(address):
6168
raise ValueError('Email address syntax is invalid "%s"'%address)

test/test_userauditor.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,4 +102,22 @@ def testGoodRoles(self):
102102
# check for all-whitespace (treat as no role)
103103
self.db.user.set(userid, roles=' ')
104104

105+
def testBadUsernames(self):
106+
''' ky,le raises:
107+
ValueError: Username/Login Name must consist only of the letters a-z (any case), digits 0-9 and the symbols: @._-!+%
108+
'''
109+
110+
for name in [ "ky'le", "ky<br>le" ]:
111+
with self.assertRaises(ValueError) as ctx:
112+
self.db.user.create(username=name,
113+
address='[email protected]',
114+
realname='Kyle Broflovski', roles='User')
115+
self.assertEqual(str(ctx.exception), "Username/Login Name must "
116+
"consist only of the letters a-z (any case), "
117+
"digits 0-9 and the symbols: @._-!%")
118+
119+
self.db.user.create(username='[email protected]',
120+
address='[email protected]',
121+
realname='Kyle Broflovski', roles='User')
122+
105123
# vim: filetype=python sts=4 sw=4 et si

0 commit comments

Comments
 (0)