version 2.13.1
This commit is contained in:
@@ -1,8 +1,18 @@
|
|||||||
## master
|
## 2.13.1
|
||||||
- Change .flash and .hidden to .w2p_flash and .w2p_hidden
|
|
||||||
- copy the static folder from the new welcome app when you update web2py
|
|
||||||
|
|
||||||
## 2.12.1
|
- added fabfile.py
|
||||||
|
- fixed oauth2 renew token, thanks dokime7
|
||||||
|
- fixed add_membership, del_membership, add_membership IntegrityError (when auth.enable_record_versioning)
|
||||||
|
- allow passing unicode to template render
|
||||||
|
- allow IS_NOT_IN_DB to work with custom primarykey, thanks timmyborg
|
||||||
|
- allow HttpOnly cookies
|
||||||
|
- french pluralizaiton rules, thanks Mathieu Clabaut
|
||||||
|
- fixed bug in redirect to cas service, thanks Fernando González
|
||||||
|
- allow deploying to pythonanywhere from the web2py admin that you're running locally, thanks Leonel
|
||||||
|
- better tests
|
||||||
|
- many more bug fixes
|
||||||
|
|
||||||
|
## 2.12.1-3
|
||||||
|
|
||||||
- security fix: Validate for open redirect everywhere, not just in login()
|
- security fix: Validate for open redirect everywhere, not just in login()
|
||||||
- allow to pack invidual apps and selected files as packed exe files
|
- allow to pack invidual apps and selected files as packed exe files
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ update:
|
|||||||
echo "remember that pymysql was tweaked"
|
echo "remember that pymysql was tweaked"
|
||||||
src:
|
src:
|
||||||
### Use semantic versioning
|
### Use semantic versioning
|
||||||
echo 'Version 2.12.3-stable+timestamp.'`date +%Y.%m.%d.%H.%M.%S` > VERSION
|
echo 'Version 2.13.1-stable+timestamp.'`date +%Y.%m.%d.%H.%M.%S` > VERSION
|
||||||
### rm -f all junk files
|
### rm -f all junk files
|
||||||
make clean
|
make clean
|
||||||
### clean up baisc apps
|
### clean up baisc apps
|
||||||
|
|||||||
+1
-1
@@ -120,7 +120,7 @@ def app_cleanup(app, request):
|
|||||||
r = False
|
r = False
|
||||||
|
|
||||||
# Remove cache files
|
# Remove cache files
|
||||||
path = apath('%s/cache/' % app, request)
|
path = apath('%s/cache/' % app, request)
|
||||||
if os.path.exists(path):
|
if os.path.exists(path):
|
||||||
CacheOnDisk(folder=path).clear()
|
CacheOnDisk(folder=path).clear()
|
||||||
for f in os.listdir(path):
|
for f in os.listdir(path):
|
||||||
|
|||||||
+2
-2
@@ -58,7 +58,7 @@ def remove_oldest_entries(storage, percentage=90):
|
|||||||
# compute current memory usage (%)
|
# compute current memory usage (%)
|
||||||
old_mem = psutil.virtual_memory().percent
|
old_mem = psutil.virtual_memory().percent
|
||||||
# if we have data in storage and utilization exceeds 90%
|
# if we have data in storage and utilization exceeds 90%
|
||||||
while storage and old_mem > percentage:
|
while storage and old_mem > percentage:
|
||||||
# removed oldest entry
|
# removed oldest entry
|
||||||
storage.popitem(last=False)
|
storage.popitem(last=False)
|
||||||
# garbage collect
|
# garbage collect
|
||||||
@@ -378,7 +378,7 @@ class CacheOnDisk(CacheAbstract):
|
|||||||
|
|
||||||
|
|
||||||
def safe_apply(self, key, function, default_value=None):
|
def safe_apply(self, key, function, default_value=None):
|
||||||
"""
|
"""
|
||||||
Safely apply a function to the value of a key in storage and set
|
Safely apply a function to the value of a key in storage and set
|
||||||
the return value of the function to it.
|
the return value of the function to it.
|
||||||
|
|
||||||
|
|||||||
+30
-30
@@ -470,21 +470,21 @@ def compile_views(folder, skip_failed_views=False):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
path = pjoin(folder, 'views')
|
path = pjoin(folder, 'views')
|
||||||
failed_views = []
|
failed_views = []
|
||||||
for fname in listdir(path, '^[\w/\-]+(\.\w+)*$'):
|
for fname in listdir(path, '^[\w/\-]+(\.\w+)*$'):
|
||||||
try:
|
try:
|
||||||
data = parse_template(fname, path)
|
data = parse_template(fname, path)
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
if skip_failed_views:
|
if skip_failed_views:
|
||||||
failed_views.append(file)
|
failed_views.append(file)
|
||||||
else:
|
else:
|
||||||
raise Exception("%s in %s" % (e, file))
|
raise Exception("%s in %s" % (e, file))
|
||||||
else:
|
else:
|
||||||
filename = ('views/%s.py' % file).replace('/', '_').replace('\\', '_')
|
filename = ('views/%s.py' % file).replace('/', '_').replace('\\', '_')
|
||||||
filename = pjoin(folder, 'compiled', filename)
|
filename = pjoin(folder, 'compiled', filename)
|
||||||
write_file(filename, data)
|
write_file(filename, data)
|
||||||
save_pyc(filename)
|
save_pyc(filename)
|
||||||
os.unlink(filename)
|
os.unlink(filename)
|
||||||
return failed_views if failed_views else None
|
return failed_views if failed_views else None
|
||||||
|
|
||||||
|
|
||||||
@@ -675,25 +675,25 @@ def run_view_in(environment):
|
|||||||
restricted(ccode, environment, 'file stream')
|
restricted(ccode, environment, 'file stream')
|
||||||
else:
|
else:
|
||||||
filename = pjoin(folder, 'views', view)
|
filename = pjoin(folder, 'views', view)
|
||||||
if os.path.exists(path): # compiled views
|
if os.path.exists(path): # compiled views
|
||||||
x = view.replace('/', '_')
|
x = view.replace('/', '_')
|
||||||
files = ['views_%s.pyc' % x]
|
files = ['views_%s.pyc' % x]
|
||||||
is_compiled = os.path.exists(pjoin(path, files[0]))
|
is_compiled = os.path.exists(pjoin(path, files[0]))
|
||||||
# Don't use a generic view if the non-compiled view exists.
|
# Don't use a generic view if the non-compiled view exists.
|
||||||
if is_compiled or (not is_compiled and not os.path.exists(filename)):
|
if is_compiled or (not is_compiled and not os.path.exists(filename)):
|
||||||
if allow_generic:
|
if allow_generic:
|
||||||
files.append('views_generic.%s.pyc' % request.extension)
|
files.append('views_generic.%s.pyc' % request.extension)
|
||||||
# for backward compatibility
|
# for backward compatibility
|
||||||
if request.extension == 'html':
|
if request.extension == 'html':
|
||||||
files.append('views_%s.pyc' % x[:-5])
|
files.append('views_%s.pyc' % x[:-5])
|
||||||
if allow_generic:
|
if allow_generic:
|
||||||
files.append('views_generic.pyc')
|
files.append('views_generic.pyc')
|
||||||
# end backward compatibility code
|
# end backward compatibility code
|
||||||
for f in files:
|
for f in files:
|
||||||
compiled = pjoin(path, f)
|
compiled = pjoin(path, f)
|
||||||
if os.path.exists(compiled):
|
if os.path.exists(compiled):
|
||||||
code = read_pyc(compiled)
|
code = read_pyc(compiled)
|
||||||
restricted(code, environment, layer=compiled)
|
restricted(code, environment, layer=compiled)
|
||||||
return
|
return
|
||||||
if not os.path.exists(filename) and allow_generic:
|
if not os.path.exists(filename) and allow_generic:
|
||||||
view = 'generic.' + request.extension
|
view = 'generic.' + request.extension
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class CustomImportException(ImportError):
|
|||||||
|
|
||||||
def custom_importer(name, globals=None, locals=None, fromlist=None, level=-1):
|
def custom_importer(name, globals=None, locals=None, fromlist=None, level=-1):
|
||||||
"""
|
"""
|
||||||
web2py's custom importer. It behaves like the standard Python importer but
|
web2py's custom importer. It behaves like the standard Python importer but
|
||||||
it tries to transform import statements as something like
|
it tries to transform import statements as something like
|
||||||
"import applications.app_name.modules.x".
|
"import applications.app_name.modules.x".
|
||||||
If the import fails, it falls back on naive_importer
|
If the import fails, it falls back on naive_importer
|
||||||
@@ -80,7 +80,7 @@ def custom_importer(name, globals=None, locals=None, fromlist=None, level=-1):
|
|||||||
if not fromlist:
|
if not fromlist:
|
||||||
# import like "import x" or "import x.y"
|
# import like "import x" or "import x.y"
|
||||||
result = None
|
result = None
|
||||||
for itemname in name.split("."):
|
for itemname in name.split("."):
|
||||||
new_mod = base_importer(
|
new_mod = base_importer(
|
||||||
modules_prefix, globals, locals, [itemname], level)
|
modules_prefix, globals, locals, [itemname], level)
|
||||||
try:
|
try:
|
||||||
|
|||||||
+1
-1
@@ -900,7 +900,7 @@ def render(content="hello world",
|
|||||||
|
|
||||||
if isinstance(content, unicode):
|
if isinstance(content, unicode):
|
||||||
content = content.encode('utf8')
|
content = content.encode('utf8')
|
||||||
|
|
||||||
# save current response class
|
# save current response class
|
||||||
if context and 'response' in context:
|
if context and 'response' in context:
|
||||||
old_response_body = context['response'].body
|
old_response_body = context['response'].body
|
||||||
|
|||||||
+13
-13
@@ -16,19 +16,19 @@ from gluon.globals import Request, Response, Session
|
|||||||
from gluon import URL
|
from gluon import URL
|
||||||
|
|
||||||
def setup_clean_session():
|
def setup_clean_session():
|
||||||
request = Request(env={})
|
request = Request(env={})
|
||||||
request.application = 'a'
|
request.application = 'a'
|
||||||
request.controller = 'c'
|
request.controller = 'c'
|
||||||
request.function = 'f'
|
request.function = 'f'
|
||||||
request.folder = 'applications/admin'
|
request.folder = 'applications/admin'
|
||||||
response = Response()
|
response = Response()
|
||||||
session = Session()
|
session = Session()
|
||||||
session.connect(request, response)
|
session.connect(request, response)
|
||||||
from gluon.globals import current
|
from gluon.globals import current
|
||||||
current.request = request
|
current.request = request
|
||||||
current.response = response
|
current.response = response
|
||||||
current.session = session
|
current.session = session
|
||||||
return current
|
return current
|
||||||
|
|
||||||
class testResponse(unittest.TestCase):
|
class testResponse(unittest.TestCase):
|
||||||
|
|
||||||
|
|||||||
@@ -309,7 +309,7 @@ class TestBareHelpers(unittest.TestCase):
|
|||||||
self.assertEqual(XML('<h1>Hello<a data-hello="world">World</a></h1>', sanitize=True),
|
self.assertEqual(XML('<h1>Hello<a data-hello="world">World</a></h1>', sanitize=True),
|
||||||
XML('<h1>HelloWorld</h1>'))
|
XML('<h1>HelloWorld</h1>'))
|
||||||
#bug check for the sanitizer for closing no-close tags
|
#bug check for the sanitizer for closing no-close tags
|
||||||
self.assertEqual(XML('<p>Test</p><br/><p>Test</p><br/>', sanitize=True),
|
self.assertEqual(XML('<p>Test</p><br/><p>Test</p><br/>', sanitize=True),
|
||||||
XML('<p>Test</p><br /><p>Test</p><br />'))
|
XML('<p>Test</p><br /><p>Test</p><br />'))
|
||||||
|
|
||||||
def testTAG(self):
|
def testTAG(self):
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ class TestList(unittest.TestCase):
|
|||||||
'something')
|
'something')
|
||||||
# except if default is especified
|
# except if default is especified
|
||||||
self.assertEqual(b(0, default=0, otherwise=lambda: 'something'), 0)
|
self.assertEqual(b(0, default=0, otherwise=lambda: 'something'), 0)
|
||||||
|
|
||||||
def test_listgetitem(self):
|
def test_listgetitem(self):
|
||||||
'''Mantains list behaviour.'''
|
'''Mantains list behaviour.'''
|
||||||
a = List((1, 2, 3))
|
a = List((1, 2, 3))
|
||||||
|
|||||||
+11
-11
@@ -24,42 +24,42 @@ class TestUtils(unittest.TestCase):
|
|||||||
|
|
||||||
data = md5_hash("web2py rocks")
|
data = md5_hash("web2py rocks")
|
||||||
self.assertEqual(data, '79509f3246a2824dee64635303e99204')
|
self.assertEqual(data, '79509f3246a2824dee64635303e99204')
|
||||||
|
|
||||||
def test_compare(self):
|
def test_compare(self):
|
||||||
""" Tests the compare funciton """
|
""" Tests the compare funciton """
|
||||||
|
|
||||||
a, b = 'test123', 'test123'
|
a, b = 'test123', 'test123'
|
||||||
compare_result_true = compare(a, b)
|
compare_result_true = compare(a, b)
|
||||||
self.assertTrue(compare_result_true)
|
self.assertTrue(compare_result_true)
|
||||||
|
|
||||||
a, b = 'test123', 'test456'
|
a, b = 'test123', 'test456'
|
||||||
compare_result_false = compare(a, b)
|
compare_result_false = compare(a, b)
|
||||||
self.assertFalse(compare_result_false)
|
self.assertFalse(compare_result_false)
|
||||||
|
|
||||||
def test_simple_hash(self):
|
def test_simple_hash(self):
|
||||||
""" Tests the simple_hash function """
|
""" Tests the simple_hash function """
|
||||||
|
|
||||||
# no key, no salt, md5
|
# no key, no salt, md5
|
||||||
data_md5 = simple_hash('web2py rocks!', key='', salt='', digest_alg='md5')
|
data_md5 = simple_hash('web2py rocks!', key='', salt='', digest_alg='md5')
|
||||||
self.assertEqual(data_md5, '37d95defba6c8834cb8cae86ee888568')
|
self.assertEqual(data_md5, '37d95defba6c8834cb8cae86ee888568')
|
||||||
|
|
||||||
# no key, no salt, sha1
|
# no key, no salt, sha1
|
||||||
data_sha1 = simple_hash('web2py rocks!', key='', salt='', digest_alg='sha1')
|
data_sha1 = simple_hash('web2py rocks!', key='', salt='', digest_alg='sha1')
|
||||||
self.assertEqual(data_sha1, '00489a46753d8db260c71542611cdef80652c4b7')
|
self.assertEqual(data_sha1, '00489a46753d8db260c71542611cdef80652c4b7')
|
||||||
|
|
||||||
# no key, no salt, sha224
|
# no key, no salt, sha224
|
||||||
data_sha224 = simple_hash('web2py rocks!', key='', salt='', digest_alg='sha224')
|
data_sha224 = simple_hash('web2py rocks!', key='', salt='', digest_alg='sha224')
|
||||||
self.assertEqual(data_sha224, '84d7054271842c2c17983baa2b1447e0289d101140a8c002d49d60da')
|
self.assertEqual(data_sha224, '84d7054271842c2c17983baa2b1447e0289d101140a8c002d49d60da')
|
||||||
|
|
||||||
# no key, no salt, sha256
|
# no key, no salt, sha256
|
||||||
data_sha256 = simple_hash('web2py rocks!', key='', salt='', digest_alg='sha256')
|
data_sha256 = simple_hash('web2py rocks!', key='', salt='', digest_alg='sha256')
|
||||||
self.assertEqual(data_sha256, '0849f224d8deb267e4598702aaec1bd749e6caec90832469891012a4be24af08')
|
self.assertEqual(data_sha256, '0849f224d8deb267e4598702aaec1bd749e6caec90832469891012a4be24af08')
|
||||||
|
|
||||||
# no key, no salt, sha384
|
# no key, no salt, sha384
|
||||||
data_sha384 = simple_hash('web2py rocks!', key='', salt='', digest_alg='sha384')
|
data_sha384 = simple_hash('web2py rocks!', key='', salt='', digest_alg='sha384')
|
||||||
self.assertEqual(data_sha384,
|
self.assertEqual(data_sha384,
|
||||||
'3cffaf39371adbe84eb10f588d2718207d8e965e9172a27a278321b86977351376ae79f92e91d8c58cad86c491282d5f')
|
'3cffaf39371adbe84eb10f588d2718207d8e965e9172a27a278321b86977351376ae79f92e91d8c58cad86c491282d5f')
|
||||||
|
|
||||||
# no key, no salt, sha512
|
# no key, no salt, sha512
|
||||||
data_sha512 = simple_hash('web2py rocks!', key='', salt='', digest_alg='sha512')
|
data_sha512 = simple_hash('web2py rocks!', key='', salt='', digest_alg='sha512')
|
||||||
self.assertEqual(data_sha512, 'fa3237f594743e1d7b6c800bb134b3255cf4a98ab8b01e2ec23256328c9f8059'
|
self.assertEqual(data_sha512, 'fa3237f594743e1d7b6c800bb134b3255cf4a98ab8b01e2ec23256328c9f8059'
|
||||||
|
|||||||
+20
-20
@@ -1426,7 +1426,7 @@ class Auth(object):
|
|||||||
csrf_prevention=True, propagate_extension=None,
|
csrf_prevention=True, propagate_extension=None,
|
||||||
url_index=None):
|
url_index=None):
|
||||||
|
|
||||||
## next two lines for backward compatibility
|
## next two lines for backward compatibility
|
||||||
if not db and environment and isinstance(environment, DAL):
|
if not db and environment and isinstance(environment, DAL):
|
||||||
db = environment
|
db = environment
|
||||||
self.db = db
|
self.db = db
|
||||||
@@ -1544,7 +1544,7 @@ class Auth(object):
|
|||||||
self.define_signature()
|
self.define_signature()
|
||||||
else:
|
else:
|
||||||
self.signature = None
|
self.signature = None
|
||||||
|
|
||||||
def get_vars_next(self):
|
def get_vars_next(self):
|
||||||
next = current.request.vars._next
|
next = current.request.vars._next
|
||||||
if isinstance(next, (list, tuple)):
|
if isinstance(next, (list, tuple)):
|
||||||
@@ -1554,7 +1554,7 @@ class Auth(object):
|
|||||||
# _next variable in the request.
|
# _next variable in the request.
|
||||||
items = next.split('/')
|
items = next.split('/')
|
||||||
if '//' in next and items[2] != current.request.env.http_host:
|
if '//' in next and items[2] != current.request.env.http_host:
|
||||||
next = None
|
next = None
|
||||||
return next
|
return next
|
||||||
|
|
||||||
def _get_user_id(self):
|
def _get_user_id(self):
|
||||||
@@ -1611,7 +1611,7 @@ class Auth(object):
|
|||||||
'retrieve_username', 'retrieve_password',
|
'retrieve_username', 'retrieve_password',
|
||||||
'reset_password', 'request_reset_password',
|
'reset_password', 'request_reset_password',
|
||||||
'change_password', 'profile', 'groups',
|
'change_password', 'profile', 'groups',
|
||||||
'impersonate', 'not_authorized', 'confirm_registration',
|
'impersonate', 'not_authorized', 'confirm_registration',
|
||||||
'bulk_register','manage_tokens'):
|
'bulk_register','manage_tokens'):
|
||||||
if len(request.args) >= 2 and args[0] == 'impersonate':
|
if len(request.args) >= 2 and args[0] == 'impersonate':
|
||||||
return getattr(self, args[0])(request.args[1])
|
return getattr(self, args[0])(request.args[1])
|
||||||
@@ -2373,7 +2373,7 @@ class Auth(object):
|
|||||||
and a raw password.
|
and a raw password.
|
||||||
"""
|
"""
|
||||||
settings = self._get_login_settings()
|
settings = self._get_login_settings()
|
||||||
# users can register_bare even if no password is provided,
|
# users can register_bare even if no password is provided,
|
||||||
# in this case they will have to reset their password to login
|
# in this case they will have to reset their password to login
|
||||||
if fields.get(settings.passfield):
|
if fields.get(settings.passfield):
|
||||||
fields[settings.passfield] = \
|
fields[settings.passfield] = \
|
||||||
@@ -2381,7 +2381,7 @@ class Auth(object):
|
|||||||
if not fields.get(settings.userfield):
|
if not fields.get(settings.userfield):
|
||||||
raise ValueError('register_bare: ' +
|
raise ValueError('register_bare: ' +
|
||||||
'userfield not provided or invalid')
|
'userfield not provided or invalid')
|
||||||
user = self.get_or_create_user(fields, login=False, get=False,
|
user = self.get_or_create_user(fields, login=False, get=False,
|
||||||
update_fields=self.settings.update_fields)
|
update_fields=self.settings.update_fields)
|
||||||
if not user:
|
if not user:
|
||||||
# get or create did not create a user (it ignores duplicate records)
|
# get or create did not create a user (it ignores duplicate records)
|
||||||
@@ -2732,7 +2732,7 @@ class Auth(object):
|
|||||||
# username and password at the first challenge).
|
# username and password at the first challenge).
|
||||||
# Check if this user is signed up for two-factor authentication
|
# Check if this user is signed up for two-factor authentication
|
||||||
# If auth.settings.auth_two_factor_enabled it will enable two factor
|
# If auth.settings.auth_two_factor_enabled it will enable two factor
|
||||||
# for all the app. Another way to anble two factor is that the user
|
# for all the app. Another way to anble two factor is that the user
|
||||||
# must be part of a group that is called auth.settings.two_factor_authentication_group
|
# must be part of a group that is called auth.settings.two_factor_authentication_group
|
||||||
if user and self.settings.auth_two_factor_enabled == True:
|
if user and self.settings.auth_two_factor_enabled == True:
|
||||||
session.auth_two_factor_enabled = True
|
session.auth_two_factor_enabled = True
|
||||||
@@ -2763,7 +2763,7 @@ class Auth(object):
|
|||||||
session.auth_two_factor_tries_left = self.settings.auth_two_factor_tries_left
|
session.auth_two_factor_tries_left = self.settings.auth_two_factor_tries_left
|
||||||
# Set the way we generate the code or we send the code. For example using SMS...
|
# Set the way we generate the code or we send the code. For example using SMS...
|
||||||
two_factor_methods = self.settings.two_factor_methods
|
two_factor_methods = self.settings.two_factor_methods
|
||||||
|
|
||||||
if two_factor_methods == []:
|
if two_factor_methods == []:
|
||||||
# TODO: Add some error checking to handle cases where email cannot be sent
|
# TODO: Add some error checking to handle cases where email cannot be sent
|
||||||
self.settings.mailer.send(
|
self.settings.mailer.send(
|
||||||
@@ -2780,19 +2780,19 @@ class Auth(object):
|
|||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
|
|
||||||
if form.accepts(request, session if self.csrf_prevention else None,
|
if form.accepts(request, session if self.csrf_prevention else None,
|
||||||
formname='login', dbio=False,
|
formname='login', dbio=False,
|
||||||
onvalidation=onvalidation,
|
onvalidation=onvalidation,
|
||||||
hideerror=settings.hideerror):
|
hideerror=settings.hideerror):
|
||||||
accepted_form = True
|
accepted_form = True
|
||||||
|
|
||||||
accepted_form = True
|
accepted_form = True
|
||||||
|
|
||||||
'''
|
'''
|
||||||
The lists is executed after form validation for each of the corresponding action.
|
The lists is executed after form validation for each of the corresponding action.
|
||||||
For example, in your model:
|
For example, in your model:
|
||||||
|
|
||||||
In your models copy and paste:
|
In your models copy and paste:
|
||||||
|
|
||||||
#Before define tables, we add some extra field to auth_user
|
#Before define tables, we add some extra field to auth_user
|
||||||
@@ -2802,7 +2802,7 @@ class Auth(object):
|
|||||||
|
|
||||||
OFFSET = 60 #Be sure is the same in your OTP Client
|
OFFSET = 60 #Be sure is the same in your OTP Client
|
||||||
|
|
||||||
#Set session.auth_two_factor to None. Because the code is generated by external app.
|
#Set session.auth_two_factor to None. Because the code is generated by external app.
|
||||||
# This will avoid to use the default setting and send a code by email.
|
# This will avoid to use the default setting and send a code by email.
|
||||||
def _set_two_factor(user, auth_two_factor):
|
def _set_two_factor(user, auth_two_factor):
|
||||||
return None
|
return None
|
||||||
@@ -2823,10 +2823,10 @@ class Auth(object):
|
|||||||
auth.messages.two_factor_comment = "Verify your OTP Client for the code."
|
auth.messages.two_factor_comment = "Verify your OTP Client for the code."
|
||||||
auth.settings.two_factor_methods = [lambda user, auth_two_factor: _set_two_factor(user, auth_two_factor)]
|
auth.settings.two_factor_methods = [lambda user, auth_two_factor: _set_two_factor(user, auth_two_factor)]
|
||||||
auth.settings.two_factor_onvalidation = [lambda user, otp: verify_otp(user, otp)]
|
auth.settings.two_factor_onvalidation = [lambda user, otp: verify_otp(user, otp)]
|
||||||
|
|
||||||
'''
|
'''
|
||||||
if self.settings.two_factor_onvalidation != []:
|
if self.settings.two_factor_onvalidation != []:
|
||||||
|
|
||||||
for two_factor_onvalidation in self.settings.two_factor_onvalidation:
|
for two_factor_onvalidation in self.settings.two_factor_onvalidation:
|
||||||
try:
|
try:
|
||||||
session.auth_two_factor = two_factor_onvalidation(session.auth_two_factor_user, form.vars['authentication_code'])
|
session.auth_two_factor = two_factor_onvalidation(session.auth_two_factor_user, form.vars['authentication_code'])
|
||||||
@@ -2834,7 +2834,7 @@ class Auth(object):
|
|||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
|
|
||||||
if form.vars['authentication_code'] == str(session.auth_two_factor):
|
if form.vars['authentication_code'] == str(session.auth_two_factor):
|
||||||
# Handle the case when the two-factor form has been successfully validated
|
# Handle the case when the two-factor form has been successfully validated
|
||||||
# and the user was previously stored (the current user should be None because
|
# and the user was previously stored (the current user should be None because
|
||||||
@@ -2994,7 +2994,7 @@ class Auth(object):
|
|||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if self.settings.register_verify_password:
|
if self.settings.register_verify_password:
|
||||||
if self.settings.register_fields is None:
|
if self.settings.register_fields is None:
|
||||||
self.settings.register_fields = [f.name for f in table_user if f.writable]
|
self.settings.register_fields = [f.name for f in table_user if f.writable]
|
||||||
k = self.settings.register_fields.index("password")
|
k = self.settings.register_fields.index("password")
|
||||||
@@ -3005,7 +3005,7 @@ class Auth(object):
|
|||||||
error_message=self.messages.mismatched_password),
|
error_message=self.messages.mismatched_password),
|
||||||
label=current.T("Confirm Password"))]
|
label=current.T("Confirm Password"))]
|
||||||
else:
|
else:
|
||||||
extra_fields = []
|
extra_fields = []
|
||||||
form = SQLFORM(table_user,
|
form = SQLFORM(table_user,
|
||||||
fields=self.settings.register_fields,
|
fields=self.settings.register_fields,
|
||||||
hidden=dict(_next=next),
|
hidden=dict(_next=next),
|
||||||
@@ -3382,7 +3382,7 @@ class Auth(object):
|
|||||||
|
|
||||||
if form.process().accepted:
|
if form.process().accepted:
|
||||||
emails = re.compile('[^\s\'"@<>,;:]+\@[^\s\'"@<>,;:]+').findall(form.vars.emails)
|
emails = re.compile('[^\s\'"@<>,;:]+\@[^\s\'"@<>,;:]+').findall(form.vars.emails)
|
||||||
# send the invitations
|
# send the invitations
|
||||||
emails_sent = []
|
emails_sent = []
|
||||||
emails_fail = []
|
emails_fail = []
|
||||||
emails_exist = []
|
emails_exist = []
|
||||||
@@ -3403,7 +3403,7 @@ class Auth(object):
|
|||||||
|
|
||||||
def manage_tokens(self):
|
def manage_tokens(self):
|
||||||
if not self.user:
|
if not self.user:
|
||||||
redirect(self.settings.login_url)
|
redirect(self.settings.login_url)
|
||||||
table_token =self.table_token()
|
table_token =self.table_token()
|
||||||
table_token.user_id.writable = False
|
table_token.user_id.writable = False
|
||||||
table_token.user_id.default = self.user.id
|
table_token.user_id.default = self.user.id
|
||||||
|
|||||||
+1
-1
@@ -3367,7 +3367,7 @@ class IS_IPV4(Validator):
|
|||||||
(number == self.localhost)):
|
(number == self.localhost)):
|
||||||
ok = False
|
ok = False
|
||||||
if not (self.is_private is None or self.is_private ==
|
if not (self.is_private is None or self.is_private ==
|
||||||
(sum([private_number[0] <= number <= private_number[1]
|
(sum([private_number[0] <= number <= private_number[1]
|
||||||
for private_number in self.private]) > 0)):
|
for private_number in self.private]) > 0)):
|
||||||
ok = False
|
ok = False
|
||||||
if not (self.is_automatic is None or self.is_automatic ==
|
if not (self.is_automatic is None or self.is_automatic ==
|
||||||
|
|||||||
Reference in New Issue
Block a user