Skip to content

Commit 23834ba

Browse files
committed
Version 1.1.0
Signed-off-by: Chris Warrick <[email protected]>
1 parent eae642f commit 23834ba

11 files changed

+68
-23
lines changed

CHANGELOG.rst

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22
Appendix A. Changelog
33
=====================
44

5-
master
5+
v1.1.0
66
------
77

8+
* Changed hashing mechanism to sha256 + bcrypt.
9+
Hashes will be fixed automatically on first login of each user.
10+
* Added ``passlib`` dependency.
811
* rqworker queue is now named ``coil`` (was ``default``)
912
* add trailing slashes to all URLs
1013
* use ``url_for()``

coil/__init__.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# -*- coding: utf-8 -*-
22

3-
# Coil CMS v1.0.0
3+
# Coil CMS v1.1.0
44
# Copyright © 2014-2015 Chris Warrick, Roberto Alsina, Henry Hirsch et al.
55

66
# Permission is hereby granted, free of charge, to any
@@ -29,4 +29,4 @@
2929

3030
__all__ = ['__version__']
3131

32-
__version__ = '1.0.0'
32+
__version__ = '1.1.0'

coil/__main__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# -*- coding: utf-8 -*-
22

3-
# Coil CMS v1.0.0
3+
# Coil CMS v1.1.0
44
# Copyright © 2014-2015 Chris Warrick, Roberto Alsina, Henry Hirsch et al.
55

66
# Permission is hereby granted, free of charge, to any

coil/forms.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# -*- coding: utf-8 -*-
22

3-
# Coil CMS v1.0.0
3+
# Coil CMS v1.1.0
44
# Copyright © 2014-2015 Chris Warrick, Roberto Alsina, Henry Hirsch et al.
55

66
# Permission is hereby granted, free of charge, to any

coil/init.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# -*- coding: utf-8 -*-
22

3-
# Coil CMS v1.0.0
3+
# Coil CMS v1.1.0
44
# Copyright © 2014-2015 Chris Warrick, Roberto Alsina, Henry Hirsch et al.
55

66
# Permission is hereby granted, free of charge, to any
@@ -44,8 +44,10 @@ def write_users(dburl):
4444
data = {
4545
'username': 'admin',
4646
'realname': 'Website Administrator',
47+
'email': '[email protected]',
4748
'password':
48-
'$2a$12$.qMCcA2uOo0BKkDtEF/bueYtHjcdPBmfEdpxtktRwRTgsR7ZVTWmW',
49+
r'$bcrypt-sha256$2a,12$NNtd2TC9mZO6.EvLwEwlLO$axojD34/iE8x'
50+
r'QitQnCCOGPhofgmjNdq',
4951
}
5052

5153
for p in PERMISSIONS:

coil/tasks.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# -*- coding: utf-8 -*-
22

3-
# Coil CMS v1.0.0
3+
# Coil CMS v1.1.0
44
# Copyright © 2014-2015 Chris Warrick, Roberto Alsina, Henry Hirsch et al.
55

66
# Permission is hereby granted, free of charge, to any

coil/utils.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# -*- coding: utf-8 -*-
22

3-
# Coil CMS v1.0.0
3+
# Coil CMS v1.1.0
44
# Copyright © 2014-2015 Chris Warrick, Roberto Alsina, Henry Hirsch et al.
55

66
# Permission is hereby granted, free of charge, to any

coil/web.py

+50-11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# -*- coding: utf-8 -*-
22

3-
# Coil CMS v1.0.0
3+
# Coil CMS v1.1.0
44
# Copyright © 2014-2015 Chris Warrick, Roberto Alsina, Henry Hirsch et al.
55

66
# Permission is hereby granted, free of charge, to any
@@ -43,7 +43,7 @@
4343
url_for)
4444
from flask.ext.login import (LoginManager, login_required, login_user,
4545
logout_user, current_user, make_secure_token)
46-
from flask.ext.bcrypt import Bcrypt
46+
from passlib.hash import bcrypt_sha256
4747
from coil.utils import USER_FIELDS, PERMISSIONS, PERMISSIONS_E, SiteProxy
4848
from coil.forms import (LoginForm, NewPostForm, NewPageForm, DeleteForm,
4949
UserDeleteForm, UserEditForm, AccountForm,
@@ -78,7 +78,6 @@ def configure_site():
7878
_dn = nikola.__main__.main([])
7979
_dn.sub_cmds = _dn.get_commands()
8080
_site = _dn.nikola
81-
app.config['BCRYPT_LOG_ROUNDS'] = 12
8281
app.config['NIKOLA_ROOT'] = os.getcwd()
8382
app.config['DEBUG'] = False
8483

@@ -183,26 +182,45 @@ def configure_site():
183182

184183

185184
def password_hash(password):
186-
"""Hash the password, using bcrypt.
185+
"""Hash the password, using bcrypt+sha256.
186+
187+
.. versionchanged:: 1.1.0
187188
188189
:param str password: Password in plaintext
189190
:return: password hash
190191
:rtype: str
191192
"""
192-
return bcrypt.generate_password_hash(password)
193+
return bcrypt_sha256.encrypt(password)
193194

194195

195196
def check_password(pwdhash, password):
196197
"""Check the password hash from :func:`password_hash`.
197198
199+
.. versionchanged:: 1.1.0
200+
198201
:param str pwdhash: Hash from :func:`password_hash` to check
199202
:param str password: Password in plaintext
200203
:return: password match
201204
:rtype: bool
202205
"""
203-
return bcrypt.check_password_hash(pwdhash, password)
206+
return bcrypt_sha256.verify(password, pwdhash)
204207

205208

209+
def check_old_password(pwdhash, password):
210+
"""Check the old password hash from :func:`password_hash`.
211+
212+
.. versionadded:: 1.1.0
213+
214+
:param str pwdhash: Hash from :func:`password_hash` to check
215+
:param str password: Password in plaintext
216+
:return: password match
217+
:rtype: bool
218+
"""
219+
from flask.ext.bcrypt import Bcrypt
220+
app.config['BCRYPT_LOG_ROUNDS'] = 12
221+
bcrypt = Bcrypt(app)
222+
return bcrypt.check_password_hash(pwdhash, password)
223+
206224
def generate_menu():
207225
"""Generate ``menu`` with the rebuild link.
208226
@@ -355,7 +373,6 @@ def log_request(resp):
355373
app.http_logger.error(l)
356374
return resp
357375

358-
bcrypt = Bcrypt(app)
359376
login_manager = LoginManager()
360377
login_manager.init_app(app)
361378
login_manager.unauthorized_callback = _unauthorized
@@ -476,13 +493,28 @@ def login():
476493
alert = 'Invalid credentials.'
477494
code = 401
478495
else:
479-
if check_password(user.password,
480-
request.form['password']) and user.is_active:
496+
try:
497+
pwd_ok = check_password(user.password,
498+
request.form['password'])
499+
except ValueError:
500+
if user.password.startswith('$2a$12'):
501+
# old bcrypt hash
502+
pwd_ok = check_old_password(user.password,
503+
request.form['password'])
504+
if pwd_ok:
505+
user.password = password_hash(
506+
request.form['password'])
507+
write_user(user)
508+
else:
509+
pwd_ok = False
510+
511+
if pwd_ok and user.is_active:
481512
login_user(user, remember=('remember' in request.form))
482513
return redirect(url_for('index'))
483514
else:
484515
alert = "Invalid credentials."
485516
code = 401
517+
486518
else:
487519
alert = 'Invalid credentials.'
488520
code = 401
@@ -826,8 +858,15 @@ def acp_account():
826858
action = 'save'
827859
data = request.form
828860
if data['newpwd1']:
829-
if data['newpwd1'] == data['newpwd2'] and check_password(
830-
current_user.password, data['oldpwd']):
861+
try:
862+
pwd_ok = check_password(current_user.password, data['oldpwd'])
863+
except ValueError:
864+
if current_user.password.startswith('$2a$12'):
865+
# old bcrypt hash
866+
pwd_ok = check_old_password(current_user.password,
867+
data['oldpwd'])
868+
869+
if data['newpwd1'] == data['newpwd2'] and pwd_ok:
831870
current_user.password = password_hash(data['newpwd1'])
832871
current_user.must_change_password = False
833872
else:

docs/conf.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@
5555
# built documents.
5656
#
5757
# The short X.Y version.
58-
version = '1.0.0'
58+
version = '1.1.0'
5959
# The full version, including alpha/beta/rc tags.
60-
release = '1.0.0'
60+
release = '1.1.0'
6161

6262
# The language for content autogenerated by Sphinx. Refer to documentation
6363
# for a list of supported languages.

requirements.txt

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ lxml==3.4.1
1515
Mako==1.0.0
1616
MarkupSafe==0.23
1717
natsort==3.5.1
18+
passlib==1.6.2
1819
Pillow==2.7.0
1920
py-bcrypt==0.4
2021
Pygments==2.0.1

setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from setuptools import setup
55

66
setup(name='coil',
7-
version='1.0.0',
7+
version='1.1.0',
88
description='A user-friendly CMS frontend for Nikola.',
99
keywords='coil,nikola,cms',
1010
author='Chris Warrick, Roberto Alsina, Henry Hirsch et al.',

0 commit comments

Comments
 (0)