Mercurial > p > roundup > code
diff templates/classic/detectors/userauditor.py @ 3902:21420ba64b0d
fuller email validition (request [SF#216291])
Checks email syntax more rigorously.
Perform address checks against "address" and any "alternate_addresses".
Changed all of the unit tests to have addresses that pass this new check.
| author | Justus Pendleton <jpend@users.sourceforge.net> |
|---|---|
| date | Wed, 12 Sep 2007 21:11:14 +0000 |
| parents | fa611c224895 |
| children |
line wrap: on
line diff
--- a/templates/classic/detectors/userauditor.py Wed Sep 12 17:57:27 2007 +0000 +++ b/templates/classic/detectors/userauditor.py Wed Sep 12 21:11:14 2007 +0000 @@ -18,44 +18,73 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. # -#$Id: userauditor.py,v 1.8 2007-09-11 21:28:29 jpend Exp $ +#$Id: userauditor.py,v 1.9 2007-09-12 21:11:13 jpend Exp $ + +import re + +# regular expression thanks to: http://www.regular-expressions.info/email.html +# this is the "99.99% solution for syntax only". +email_regexp = (r"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*", r"(localhost|(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9]))") +email_rfc = re.compile('^' + email_regexp[0] + '@' + email_regexp[1] + '$', re.IGNORECASE) +email_local = re.compile('^' + email_regexp[0] + '$', re.IGNORECASE) + +def valid_address(address): + ''' If we see an @-symbol in the address then check against the full + RFC syntax. Otherwise it is a local-only address so only check + the local part of the RFC syntax. + ''' + if '@' in address: + return email_rfc.match(address) + else: + return email_local.match(address) + +def get_addresses(user): + ''' iterate over all known addresses in a newvalues dict + this takes of the address/alterate_addresses handling + ''' + if user.has_key('address'): + yield user['address'] + if user.get('alternate_addresses', None): + for address in user['alternate_addresses'].split('\n'): + yield address def audit_user_fields(db, cl, nodeid, newvalues): ''' Make sure user properties are valid. - - email address has no spaces in it + - email address is syntactically valid - email address is unique - roles specified exist - timezone is valid ''' - if newvalues.has_key('address'): - address = newvalues['address'] - if address: - if ' ' in address: - raise ValueError, 'Email address must not contain spaces' - user = db.user.stringFind(address=address) - if len(user): - raise ValueError, 'Email address already in use' + + for address in get_addresses(newvalues): + if not valid_address(address): + raise ValueError, 'Email address syntax is invalid' + + check_main = db.user.stringFind(address=address) + # make sure none of the alts are owned by anyone other than us (x!=nodeid) + check_alts = [x for x in db.user.filter(None, {'alternate_addresses' : address}) if x != nodeid] + if check_main or check_alts: + raise ValueError, 'Email address %s already in use' % address for rolename in [r.lower().strip() for r in newvalues.get('roles', '').split(',')]: if rolename and not db.security.role.has_key(rolename): raise ValueError, 'Role "%s" does not exist'%rolename - if newvalues.has_key('timezone'): - tz = newvalues['timezone'] - if tz: - # if they set a new timezone validate the timezone by attempting to - # use it before we store it to the db. - import roundup.date - import datetime - try: - TZ = roundup.date.get_timezone(tz) - dt = datetime.datetime.now() - local = TZ.localize(dt).utctimetuple() - except IOError: - raise ValueError, 'Timezone "%s" does not exist' % tz - except ValueError: - raise ValueError, 'Timezone "%s" exceeds valid range [-23...23]' % tz + tz = newvalues.get('timezone', None) + if tz: + # if they set a new timezone validate the timezone by attempting to + # use it before we store it to the db. + import roundup.date + import datetime + try: + TZ = roundup.date.get_timezone(tz) + dt = datetime.datetime.now() + local = TZ.localize(dt).utctimetuple() + except IOError: + raise ValueError, 'Timezone "%s" does not exist' % tz + except ValueError: + raise ValueError, 'Timezone "%s" exceeds valid range [-23...23]' % tz def init(db): # fire before changes are made
