diff --git a/VERSION b/VERSION index 7b4aa452..119bb72c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.6.0-development+timestamp.2013.07.17.07.36.50 +Version 2.6.0-development+timestamp.2013.07.17.17.18.40 diff --git a/applications/admin/static/css/bootstrap_essentials.css b/applications/admin/static/css/bootstrap_essentials.css index 905cbe62..b5035b62 100644 --- a/applications/admin/static/css/bootstrap_essentials.css +++ b/applications/admin/static/css/bootstrap_essentials.css @@ -327,6 +327,89 @@ font-style: italic; color: #ccc; } +/*============================================================= +EDIT PAGE SLIDING FILES MENU +==============================================================*/ +@media (max-width: 979px) { + body.edit div#header {position:relative; z-index: 1030 !important;} +} + +#editor_area, #edit_placeholder { + margin: 0; + padding: 0; +} + +#editor_area { + position: relative; + box-sizing: border-box; +} + +#files { + width: auto; + height: 100%; + margin: 0; + padding: 0; + position: fixed; + top: 0px; + left: 0px; + z-index: 1029; + border-right: 3px solid #000; + /* animation (it doesn't work in IE<10) */ + -moz-transition: all 0.4s; + -webkit-transition: all 0.4s; + -o-transition: all 0.4s; + transition: all 0.4s; +} + +#files:hover, #files:focus { + left: 0px !important; +} + +#files, .files-toggle { + background: #1b1b1b; + opacity: 0.98; +} + +.files-toggle { + width: 18px; + height: 86px; + border-radius: 0px 4px 4px 0px; + color: #999; + position: absolute; + top: 60px; + right: -18px; + cursor: default; +} + +.arrow { + display: block; + position: absolute; + top: 8px; + width: 18px; + height: 70px; + background: url(../images/files_toggle.png) no-repeat; +} + +.files-menu { + height: 100%; + overflow: auto; +} + +#filelist { + position: relative; + top: 60px; + padding-bottom: 60px; +} + +#filelist li { + padding-right: 8px; + width: 100%; +} + +#filelist li>a { + text-shadow: none; +} + /*============================================================= MEDIA QUERIES ==============================================================*/ diff --git a/applications/admin/static/images/files_toggle.png b/applications/admin/static/images/files_toggle.png new file mode 100644 index 00000000..098e02a8 Binary files /dev/null and b/applications/admin/static/images/files_toggle.png differ diff --git a/applications/admin/views/default/edit.html b/applications/admin/views/default/edit.html index 2f6e2804..6700bf9b 100644 --- a/applications/admin/views/default/edit.html +++ b/applications/admin/views/default/edit.html @@ -121,7 +121,7 @@ jQuery(document).on('click', 'a.font_button', function (e) { case 'decr': new_incr = -2; break; case 'default': new_incr = 0; break; } - jQuery('textarea[name="data"]') .each(function(id, ta) { + jQuery('textarea[name="data"]').each(function(id, ta) { editor = jQuery(ta).data('editor'); set_font(editor, new_incr); }); @@ -163,9 +163,6 @@ jQuery(document).on('click', 'a.font_button', function (e) {
-
-
- +
+
+
+ +
-
+
+ diff --git a/gluon/contrib/pbkdf2.py b/gluon/contrib/pbkdf2.py index a67bf94e..b311c53f 100644 --- a/gluon/contrib/pbkdf2.py +++ b/gluon/contrib/pbkdf2.py @@ -40,19 +40,12 @@ :copyright: (c) Copyright 2011 by Armin Ronacher. :license: BSD, see LICENSE for more details. """ -#import hmac -#import hashlib +import hmac try: - # Use PyCrypto (if available). - from Crypto.Hash import HMAC as hmac, SHA as sha1 + from hashlib import sha1 except ImportError: - # PyCrypto not available. Use the Python standard library. - import hmac - try: - from hashlib import sha1 - except ImportError: - # hashlib not available. Use the old sha module. - import sha as sha1 + # hashlib not available. Use the old sha module. + import sha as sha1 from struct import Struct from operator import xor @@ -121,9 +114,8 @@ def test(): check('pass\x00word', 'sa\x00lt', 4096, 16, '56fa6aa75548099dcc37d7f03425e0c3') # This one is from the RFC but it just takes for ages - ##check('password', 'salt', 16777216, 20, - ## 'eefe3d61cd4da4e4e9945b3d6ba2158c2634e984') - + check('password', 'salt', 16777216, 20, + 'eefe3d61cd4da4e4e9945b3d6ba2158c2634e984') # From Crypt-PBKDF2 check('password', 'ATHENA.MIT.EDUraeburn', 1, 16, 'cdedb5281bb2f801565a1122b2563515') diff --git a/gluon/contrib/redis_session.py b/gluon/contrib/redis_session.py index 14ce094c..ce8fb167 100644 --- a/gluon/contrib/redis_session.py +++ b/gluon/contrib/redis_session.py @@ -143,7 +143,6 @@ class MockTable(object): release_lock(self.r_server, key_lock, newid) return newid - class MockQuery(object): """a fake Query object that supports querying by id and listing all keys. No other operation is supported diff --git a/gluon/globals.py b/gluon/globals.py index bb10b89a..39117a22 100644 --- a/gluon/globals.py +++ b/gluon/globals.py @@ -498,7 +498,6 @@ class Session(Storage): masterapp=None, clear_session=False ): - if request is None: request = current.request if response is None: @@ -576,13 +575,14 @@ class Session(Storage): if record_id == '0': raise Exception('record_id == 0') # Select from database - row = db(table.id == record_id).select().first() + row = db(table.id == record_id).select() + row = row and row[0] or None # Make sure the session data exists in the database if not row or row.unique_key != unique_key: raise Exception('No record') unique_key = web2py_uuid() - row.update_record(unique_key=unique_key) + db(table.id == record_id).update(unique_key=unique_key) response.session_id = '%s:%s' % (record_id, unique_key) response.session_db_table = table response.session_db_record_id = record_id diff --git a/gluon/tools.py b/gluon/tools.py index 3c27a0be..eb6d6e50 100644 --- a/gluon/tools.py +++ b/gluon/tools.py @@ -1794,7 +1794,7 @@ class Auth(object): guess = keys.get('email', 'anonymous').split('@')[0] keys['first_name'] = keys.get('username', guess) user_id = table_user.insert(**table_user._filter_fields(keys)) - user = table_user[user_id] + user = table_user[user_id] print user if self.settings.create_user_groups: group_id = self.add_group( @@ -1856,11 +1856,14 @@ class Auth(object): delattr(user,'password') else: user = Row(user) - for key,value in user.items(): + for key, value in user.items(): if callable(value) or key=='password': delattr(user,key) + sessdb = current.response.session_db_table and current.response.session_db_table._db or None current.session.renew( - clear_session=not self.settings.keep_session_onlogin, db=self.db) + clear_session=not self.settings.keep_session_onlogin, + db=sessdb + ) current.session.auth = Storage( user = user, last_visit=current.request.now, @@ -2247,8 +2250,10 @@ class Auth(object): current.session.auth = None current.session.flash = self.messages.logged_out + sessdb = current.response.session_db_table and current.response.session_db_table._db or None current.session.renew( - clear_session=not self.settings.keep_session_onlogout, db=self.db) + clear_session=not self.settings.keep_session_onlogout, + db=sessdb) if not next is None: redirect(next) @@ -4913,7 +4918,7 @@ class Expose(object): def __init__(self, base=None, basename=None, extensions=None, allow_download=True): """ Usage: - + def static(): return dict(files=Expose()) @@ -4995,7 +5000,7 @@ class Expose(object): return '' def xml(self): - return DIV( + return DIV( H2(self.breadcrumbs(self.basename)), self.paragraph or '', self.table_folders(), @@ -5154,7 +5159,7 @@ class Wiki(object): db.wiki_tag.insert(name=tag, wiki_page=page.id) db.wiki_page._after_insert.append(update_tags_insert) db.wiki_page._after_update.append(update_tags_update) - + if (auth.user and check_credentials(current.request, gae_login=False) and not 'wiki_editor' in auth.user_groups.values()): diff --git a/gluon/utils.py b/gluon/utils.py index 9f7c3c89..e8f1d294 100644 --- a/gluon/utils.py +++ b/gluon/utils.py @@ -11,8 +11,8 @@ This file specifically includes utilities for security. import threading import struct -import hashlib -import hmac +#import hashlib +#import hmac import uuid import random import time @@ -23,6 +23,7 @@ import logging import socket import base64 import zlib +from types import ModuleType _struct_2_long_long = struct.Struct('=QQ') @@ -33,21 +34,15 @@ if python_version == 2: else: import pickle -try: - from Crypto.Hash import MD5 as md5, \ - SHA as sha1, \ - SHA224 as sha224, \ - SHA256 as sha256, \ - SHA384 as sha384, \ - SHA512 as sha512 -except ImportError: - from hashlib import md5, sha1, sha224, sha256, sha384, sha512 +from hashlib import md5, sha1, sha224, sha256, sha384, sha512 try: from Crypto.Cipher import AES except ImportError: import contrib.aes as AES +import hmac + try: from contrib.pbkdf2 import pbkdf2_hex HAVE_PBKDF2 = True @@ -80,8 +75,7 @@ def compare(a, b): def md5_hash(text): """ Generate a md5 hash with the given text """ - return md5.new(text).hexdigest() - + return md5(text).hexdigest() def simple_hash(text, key='', salt='', digest_alg='md5'): """ @@ -100,7 +94,7 @@ def simple_hash(text, key='', salt='', digest_alg='md5'): digest_alg = get_digest(digest_alg) h = hmac.new(key + salt, text, digest_alg) else: # compatible with third party systems - h = hashlib.new(digest_alg) + h = get_digest(digest_alg)() h.update(text + salt) return h.hexdigest() @@ -143,7 +137,7 @@ def pad(s, n=32, padchar=' '): def secure_dumps(data, encryption_key, hash_key=None, compression_level=None): if not hash_key: - hash_key = hashlib.sha1(encryption_key).hexdigest() + hash_key = sha1(encryption_key).hexdigest() dump = pickle.dumps(data) if compression_level: dump = zlib.compress(dump, compression_level) @@ -158,7 +152,7 @@ def secure_loads(data, encryption_key, hash_key=None, compression_level=None): if not ':' in data: return None if not hash_key: - hash_key = hashlib.sha1(encryption_key).hexdigest() + hash_key = sha1(encryption_key).hexdigest() signature, encrypted_data = data.split(':', 1) actual_signature = hmac.new(hash_key, encrypted_data).hexdigest() if not compare(signature, actual_signature):