merge
This commit is contained in:
+2
-1
@@ -4323,7 +4323,8 @@ class GoogleDatastoreAdapter(NoSQLAdapter):
|
||||
if first.type != 'id':
|
||||
return [GAEF(first.name,'!=',self.represent(second,first.type),lambda a,b:a!=b)]
|
||||
else:
|
||||
second = Key.from_path(first._tablename, long(second))
|
||||
if not second is None:
|
||||
second = Key.from_path(first._tablename, long(second))
|
||||
return [GAEF(first.name,'!=',second,lambda a,b:a!=b)]
|
||||
|
||||
def LT(self,first,second=None):
|
||||
|
||||
+2
-2
@@ -155,9 +155,9 @@ def read_possible_plural_rules():
|
||||
create list of all possible plural rules files
|
||||
result is cached in PLURAL_RULES dictionary to increase speed
|
||||
"""
|
||||
plurals = {}
|
||||
try:
|
||||
import gluon.contrib.plural_rules as package
|
||||
plurals = {}
|
||||
import contrib.plural_rules as package
|
||||
for importer, modname, ispkg in pkgutil.iter_modules(package.__path__):
|
||||
if len(modname)==2:
|
||||
module = __import__(package.__name__+'.'+modname,
|
||||
|
||||
@@ -192,6 +192,7 @@ def url_out(request, env, application, controller, function,
|
||||
port = ''
|
||||
else:
|
||||
port = ':%s' % port
|
||||
host = host.split(':')[0]
|
||||
url = '%s://%s%s%s' % (scheme, host, port, url)
|
||||
return url
|
||||
|
||||
|
||||
+7
-5
@@ -264,6 +264,7 @@ class Mail(object):
|
||||
cc=None,
|
||||
bcc=None,
|
||||
reply_to=None,
|
||||
sender='%(sender)s',
|
||||
encoding='utf-8',
|
||||
raw=False,
|
||||
headers={}
|
||||
@@ -606,7 +607,8 @@ class Mail(object):
|
||||
# no cryptography process as usual
|
||||
payload=payload_in
|
||||
|
||||
payload['From'] = encoded_or_raw(self.settings.sender.decode(encoding))
|
||||
sender = sender % dict(sender=self.settings.sender)
|
||||
payload['From'] = encoded_or_raw(sender.decode(encoding))
|
||||
origTo = to[:]
|
||||
if to:
|
||||
payload['To'] = encoded_or_raw(', '.join(to).decode(encoding))
|
||||
@@ -623,10 +625,10 @@ class Mail(object):
|
||||
for k,v in headers.iteritems():
|
||||
payload[k] = encoded_or_raw(v.decode(encoding))
|
||||
result = {}
|
||||
try:
|
||||
try:
|
||||
if self.settings.server == 'logging':
|
||||
logger.warn('email not sent\n%s\nFrom: %s\nTo: %s\nSubject: %s\n\n%s\n%s\n' % \
|
||||
('-'*40,self.settings.sender,
|
||||
('-'*40,sender,
|
||||
', '.join(to),subject,
|
||||
text or html,'-'*40))
|
||||
elif self.settings.server == 'gae':
|
||||
@@ -1195,7 +1197,7 @@ class Auth(object):
|
||||
'reset_password','request_reset_password',
|
||||
'change_password','profile','groups',
|
||||
'impersonate','not_authorized'):
|
||||
if len(request.args) >= 2:
|
||||
if len(request.args) >= 2 and args[0]=='impersonate':
|
||||
return getattr(self,args[0])(request.args[1])
|
||||
else:
|
||||
return getattr(self,args[0])()
|
||||
@@ -2443,7 +2445,7 @@ class Auth(object):
|
||||
session = current.session
|
||||
|
||||
if next is DEFAULT:
|
||||
next = self.settings.reset_password_next
|
||||
next = self.next or self.settings.reset_password_next
|
||||
try:
|
||||
key = request.vars.key or getarg(-1)
|
||||
t0 = int(key.split('-')[0])
|
||||
|
||||
+87
-10
@@ -2725,6 +2725,43 @@ class CRYPT(object):
|
||||
return ('', translate(self.error_message))
|
||||
return (LazyCrypt(self,value),None)
|
||||
|
||||
# entropy calculator for IS_STRONG
|
||||
#
|
||||
lowerset = frozenset(unicode('abcdefghijklmnopqrstuvwxyz'))
|
||||
upperset = frozenset(unicode('ABCDEFGHIJKLMNOPQRSTUVWXYZ'))
|
||||
numberset = frozenset(unicode('0123456789'))
|
||||
sym1set = frozenset(unicode('!@#$%^&*()'))
|
||||
sym2set = frozenset(unicode('~`-_=+[]{}\\|;:\'",.<>?/'))
|
||||
otherset = frozenset(unicode('0123456789abcdefghijklmnopqrstuvwxyz')) # anything else
|
||||
|
||||
def calc_entropy(string):
|
||||
" calculate a simple entropy for a given string "
|
||||
import math
|
||||
alphabet = 0 # alphabet size
|
||||
other = set()
|
||||
seen = set()
|
||||
lastset = None
|
||||
if isinstance(string, str):
|
||||
string = unicode(string, encoding='utf8')
|
||||
for c in string:
|
||||
# classify this character
|
||||
inset = otherset
|
||||
for cset in (lowerset, upperset, numberset, sym1set, sym2set):
|
||||
if c in cset:
|
||||
inset = cset
|
||||
break
|
||||
# calculate effect of character on alphabet size
|
||||
if inset not in seen:
|
||||
seen.add(inset)
|
||||
alphabet += len(inset) # credit for a new character set
|
||||
elif c not in other:
|
||||
alphabet += 1 # credit for unique characters
|
||||
other.add(c)
|
||||
if inset is not lastset:
|
||||
alphabet += 1 # credit for set transitions
|
||||
lastset = cset
|
||||
entropy = len(string) * math.log(alphabet) / 0.6931471805599453 # math.log(2)
|
||||
return round(entropy, 2)
|
||||
|
||||
class IS_STRONG(object):
|
||||
"""
|
||||
@@ -2734,23 +2771,61 @@ class IS_STRONG(object):
|
||||
requires=IS_STRONG(min=10, special=2, upper=2))
|
||||
|
||||
enforces complexity requirements on a field
|
||||
|
||||
>>> IS_STRONG(es=True)('Abcd1234')
|
||||
('Abcd1234', 'Must include at least 1 of the following: ~!@#$%^&*()_+-=?<>,.:;{}[]|')
|
||||
>>> IS_STRONG(es=True)('Abcd1234!')
|
||||
('Abcd1234!', None)
|
||||
>>> IS_STRONG(es=True, entropy=1)('a')
|
||||
('a', None)
|
||||
>>> IS_STRONG(es=True, entropy=1, min=2)('a')
|
||||
('a', 'Minimum length is 2')
|
||||
>>> IS_STRONG(es=True, entropy=100)('abc123')
|
||||
('abc123', 'Entropy (32.35) less than required (100)')
|
||||
>>> IS_STRONG(es=True, entropy=100)('and')
|
||||
('and', 'Entropy (14.57) less than required (100)')
|
||||
>>> IS_STRONG(es=True, entropy=100)('aaa')
|
||||
('aaa', 'Entropy (14.42) less than required (100)')
|
||||
>>> IS_STRONG(es=True, entropy=100)('a1d')
|
||||
('a1d', 'Entropy (15.97) less than required (100)')
|
||||
>>> IS_STRONG(es=True, entropy=100)('añd')
|
||||
('a\\xc3\\xb1d', 'Entropy (18.13) less than required (100)')
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, min=8, max=20, upper=1, lower=1, number=1,
|
||||
special=1, specials=r'~!@#$%^&*()_+-=?<>,.:;{}[]|',
|
||||
invalid=' "', error_message=None):
|
||||
self.min = min
|
||||
self.max = max
|
||||
self.upper = upper
|
||||
self.lower = lower
|
||||
self.number = number
|
||||
self.special = special
|
||||
def __init__(self, min=None, max=None, upper=None, lower=None, number=None,
|
||||
entropy=None,
|
||||
special=None, specials=r'~!@#$%^&*()_+-=?<>,.:;{}[]|',
|
||||
invalid=' "', error_message=None, es=False):
|
||||
self.entropy = entropy
|
||||
if entropy is None:
|
||||
# enforce default requirements
|
||||
self.min = 8 if min is None else min
|
||||
self.max = max # was 20, but that doesn't make sense
|
||||
self.upper = 1 if upper is None else upper
|
||||
self.lower = 1 if lower is None else lower
|
||||
self.number = 1 if number is None else number
|
||||
self.special = 1 if special is None else special
|
||||
else:
|
||||
# by default, an entropy spec is exclusive
|
||||
self.min = min
|
||||
self.max = max
|
||||
self.upper = upper
|
||||
self.lower = lower
|
||||
self.number = number
|
||||
self.special = special
|
||||
self.specials = specials
|
||||
self.invalid = invalid
|
||||
self.error_message = error_message
|
||||
self.estring = es # return error message as string (for doctest)
|
||||
|
||||
def __call__(self, value):
|
||||
failures = []
|
||||
if self.entropy is not None:
|
||||
entropy = calc_entropy(value)
|
||||
if entropy < self.entropy:
|
||||
failures.append(translate("Entropy (%(have)s) less than required (%(need)s)") \
|
||||
% dict(have=entropy, need=self.entropy))
|
||||
if type(self.min) == int and self.min > 0:
|
||||
if not len(value) >= self.min:
|
||||
failures.append(translate("Minimum length is %s") % self.min)
|
||||
@@ -2761,7 +2836,7 @@ class IS_STRONG(object):
|
||||
all_special = [ch in value for ch in self.specials]
|
||||
if self.special > 0:
|
||||
if not all_special.count(True) >= self.special:
|
||||
failures.append(translate("Must include at least %s of the following : %s") \
|
||||
failures.append(translate("Must include at least %s of the following: %s") \
|
||||
% (self.special, self.specials))
|
||||
if self.invalid:
|
||||
all_invalid = [ch in value for ch in self.invalid]
|
||||
@@ -2801,6 +2876,8 @@ class IS_STRONG(object):
|
||||
if len(failures) == 0:
|
||||
return (value, None)
|
||||
if not self.error_message:
|
||||
if self.estring:
|
||||
return (value, '|'.join(failures))
|
||||
from html import XML
|
||||
return (value, XML('<br />'.join(failures)))
|
||||
else:
|
||||
|
||||
Reference in New Issue
Block a user