From aeae6cc29099c4bea84bbfd006615104ba719b1e Mon Sep 17 00:00:00 2001 From: Rodney Ewing Date: Mon, 8 Jul 2013 17:00:37 -0700 Subject: [PATCH 1/9] moved forgot pass to basic_auth plugin --- mediagoblin/auth/forms.py | 37 ---- mediagoblin/auth/routing.py | 7 +- mediagoblin/auth/tools.py | 37 +--- mediagoblin/auth/views.py | 161 ---------------- mediagoblin/plugins/basic_auth/__init__.py | 18 ++ mediagoblin/plugins/basic_auth/forms.py | 17 ++ .../plugins/basic_auth}/change_fp.html | 0 .../plugins/basic_auth}/forgot_password.html | 0 .../basic_auth}/fp_verification_email.txt | 0 mediagoblin/plugins/basic_auth/tools.py | 33 ++++ mediagoblin/plugins/basic_auth/views.py | 180 ++++++++++++++++++ 11 files changed, 253 insertions(+), 237 deletions(-) delete mode 100644 mediagoblin/auth/forms.py rename mediagoblin/{templates/mediagoblin/auth => plugins/basic_auth/templates/mediagoblin/plugins/basic_auth}/change_fp.html (100%) rename mediagoblin/{templates/mediagoblin/auth => plugins/basic_auth/templates/mediagoblin/plugins/basic_auth}/forgot_password.html (100%) rename mediagoblin/{templates/mediagoblin/auth => plugins/basic_auth/templates/mediagoblin/plugins/basic_auth}/fp_verification_email.txt (100%) create mode 100644 mediagoblin/plugins/basic_auth/views.py diff --git a/mediagoblin/auth/forms.py b/mediagoblin/auth/forms.py deleted file mode 100644 index 865502e9..00000000 --- a/mediagoblin/auth/forms.py +++ /dev/null @@ -1,37 +0,0 @@ -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -import wtforms - -from mediagoblin.tools.translate import lazy_pass_to_ugettext as _ -from mediagoblin.auth.tools import normalize_user_or_email_field - - -class ForgotPassForm(wtforms.Form): - username = wtforms.TextField( - _('Username or email'), - [wtforms.validators.Required(), - normalize_user_or_email_field()]) - - -class ChangePassForm(wtforms.Form): - password = wtforms.PasswordField( - 'Password', - [wtforms.validators.Required(), - wtforms.validators.Length(min=5, max=1024)]) - token = wtforms.HiddenField( - '', - [wtforms.validators.Required()]) diff --git a/mediagoblin/auth/routing.py b/mediagoblin/auth/routing.py index 2a6abb47..7a688a49 100644 --- a/mediagoblin/auth/routing.py +++ b/mediagoblin/auth/routing.py @@ -25,9 +25,4 @@ auth_routes = [ ('mediagoblin.auth.verify_email', '/verify_email/', 'mediagoblin.auth.views:verify_email'), ('mediagoblin.auth.resend_verification', '/resend_verification/', - 'mediagoblin.auth.views:resend_activation'), - ('mediagoblin.auth.forgot_password', '/forgot_password/', - 'mediagoblin.auth.views:forgot_password'), - ('mediagoblin.auth.verify_forgot_password', - '/forgot_password/verify/', - 'mediagoblin.auth.views:verify_forgot_password')] + 'mediagoblin.auth.views:resend_activation')] diff --git a/mediagoblin/auth/tools.py b/mediagoblin/auth/tools.py index 579775ff..20c1f5c2 100644 --- a/mediagoblin/auth/tools.py +++ b/mediagoblin/auth/tools.py @@ -101,38 +101,6 @@ def send_verification_email(user, request, email=None, rendered_email) -EMAIL_FP_VERIFICATION_TEMPLATE = ( - u"{uri}?" - u"token={fp_verification_key}") - - -def send_fp_verification_email(user, request): - """ - Send the verification email to users to change their password. - - Args: - - user: a user object - - request: the request - """ - fp_verification_key = get_timed_signer_url('mail_verification_token') \ - .dumps(user.id) - - rendered_email = render_template( - request, 'mediagoblin/auth/fp_verification_email.txt', - {'username': user.username, - 'verification_url': EMAIL_FP_VERIFICATION_TEMPLATE.format( - uri=request.urlgen('mediagoblin.auth.verify_forgot_password', - qualified=True), - fp_verification_key=fp_verification_key)}) - - # TODO: There is no error handling in place - send_email( - mg_globals.app_config['email_sender_address'], - [user.email], - 'GNU MediaGoblin - Change forgotten password!', - rendered_email) - - def basic_extra_validation(register_form, *args): users_with_username = User.query.filter_by( username=register_form.username.data).count() @@ -196,7 +164,10 @@ def check_auth_enabled(): def no_auth_logout(request): - """Log out the user if authentication_disabled, but don't delete the messages""" + """ + Log out the user if no authentication is enabled, but don't delete + the messages + """ if not mg_globals.app.auth and 'user_id' in request.session: del request.session['user_id'] request.session.save() diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py index dd71d5c1..285bddf6 100644 --- a/mediagoblin/auth/views.py +++ b/mediagoblin/auth/views.py @@ -24,11 +24,8 @@ from mediagoblin.tools.response import render_to_response, redirect, render_404 from mediagoblin.tools.translate import pass_to_ugettext as _ from mediagoblin.tools.mail import email_debug_message from mediagoblin.tools.pluginapi import hook_handle -from mediagoblin.auth import forms as auth_forms from mediagoblin.auth.tools import (send_verification_email, register_user, - send_fp_verification_email, check_login_simple) -from mediagoblin import auth @allow_registration @@ -204,161 +201,3 @@ def resend_activation(request): return redirect( request, 'mediagoblin.user_pages.user_home', user=request.user.username) - - -def forgot_password(request): - """ - Forgot password view - - Sends an email with an url to renew forgotten password. - Use GET querystring parameter 'username' to pre-populate the input field - """ - if not 'pass_auth' in request.template_env.globals: - return redirect(request, 'index') - - fp_form = auth_forms.ForgotPassForm(request.form, - username=request.args.get('username')) - - if not (request.method == 'POST' and fp_form.validate()): - # Either GET request, or invalid form submitted. Display the template - return render_to_response(request, - 'mediagoblin/auth/forgot_password.html', {'fp_form': fp_form,}) - - # If we are here: method == POST and form is valid. username casing - # has been sanitized. Store if a user was found by email. We should - # not reveal if the operation was successful then as we don't want to - # leak if an email address exists in the system. - found_by_email = '@' in fp_form.username.data - - if found_by_email: - user = User.query.filter_by( - email = fp_form.username.data).first() - # Don't reveal success in case the lookup happened by email address. - success_message=_("If that email address (case sensitive!) is " - "registered an email has been sent with instructions " - "on how to change your password.") - - else: # found by username - user = User.query.filter_by( - username = fp_form.username.data).first() - - if user is None: - messages.add_message(request, - messages.WARNING, - _("Couldn't find someone with that username.")) - return redirect(request, 'mediagoblin.auth.forgot_password') - - success_message=_("An email has been sent with instructions " - "on how to change your password.") - - if user and not(user.email_verified and user.status == 'active'): - # Don't send reminder because user is inactive or has no verified email - messages.add_message(request, - messages.WARNING, - _("Could not send password recovery email as your username is in" - "active or your account's email address has not been verified.")) - - return redirect(request, 'mediagoblin.user_pages.user_home', - user=user.username) - - # SUCCESS. Send reminder and return to login page - if user: - email_debug_message(request) - send_fp_verification_email(user, request) - - messages.add_message(request, messages.INFO, success_message) - return redirect(request, 'mediagoblin.auth.login') - - -def verify_forgot_password(request): - """ - Check the forgot-password verification and possibly let the user - change their password because of it. - """ - # get form data variables, and specifically check for presence of token - formdata = _process_for_token(request) - if not formdata['has_token']: - return render_404(request) - - formdata_vars = formdata['vars'] - - # Catch error if token is faked or expired - try: - token = get_timed_signer_url("mail_verification_token") \ - .loads(formdata_vars['token'], max_age=10*24*3600) - except BadSignature: - messages.add_message( - request, - messages.ERROR, - _('The verification key or user id is incorrect.')) - - return redirect( - request, - 'index') - - # check if it's a valid user id - user = User.query.filter_by(id=int(token)).first() - - # no user in db - if not user: - messages.add_message( - request, messages.ERROR, - _('The user id is incorrect.')) - return redirect( - request, 'index') - - # check if user active and has email verified - if user.email_verified and user.status == 'active': - - cp_form = auth_forms.ChangePassForm(formdata_vars) - - if request.method == 'POST' and cp_form.validate(): - user.pw_hash = auth.gen_password_hash( - cp_form.password.data) - user.save() - - messages.add_message( - request, - messages.INFO, - _("You can now log in using your new password.")) - return redirect(request, 'mediagoblin.auth.login') - else: - return render_to_response( - request, - 'mediagoblin/auth/change_fp.html', - {'cp_form': cp_form,}) - - if not user.email_verified: - messages.add_message( - request, messages.ERROR, - _('You need to verify your email before you can reset your' - ' password.')) - - if not user.status == 'active': - messages.add_message( - request, messages.ERROR, - _('You are no longer an active user. Please contact the system' - ' admin to reactivate your accoutn.')) - - return redirect( - request, 'index') - - -def _process_for_token(request): - """ - Checks for tokens in formdata without prior knowledge of request method - - For now, returns whether the userid and token formdata variables exist, and - the formdata variables in a hash. Perhaps an object is warranted? - """ - # retrieve the formdata variables - if request.method == 'GET': - formdata_vars = request.GET - else: - formdata_vars = request.form - - formdata = { - 'vars': formdata_vars, - 'has_token': 'token' in formdata_vars} - - return formdata diff --git a/mediagoblin/plugins/basic_auth/__init__.py b/mediagoblin/plugins/basic_auth/__init__.py index 33a554b0..913ccba4 100644 --- a/mediagoblin/plugins/basic_auth/__init__.py +++ b/mediagoblin/plugins/basic_auth/__init__.py @@ -13,6 +13,8 @@ # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +import os + from mediagoblin.plugins.basic_auth import forms as auth_forms from mediagoblin.plugins.basic_auth import tools as auth_tools from mediagoblin.auth.tools import create_basic_user @@ -20,10 +22,26 @@ from mediagoblin.db.models import User from mediagoblin.tools import pluginapi from sqlalchemy import or_ +PLUGIN_DIR = os.path.dirname(__file__) + def setup_plugin(): config = pluginapi.get_config('mediagoblin.plugins.basic_auth') + routes = [ + ('mediagoblin.plugins.basic_auth.edit.pass', + '/edit/password/', + 'mediagoblin.plugins.basic_auth.views:change_pass'), + ('mediagoblin.plugins.basic_auth.forgot_password', + '/auth/forgot_password/', + 'mediagoblin.plugins.basic_auth.views:forgot_password'), + ('mediagoblin.plugins.basic_auth.verify_forgot_password', + '/auth/forgot_password/verify/', + 'mediagoblin.plugins.basic_auth.views:verify_forgot_password')] + + pluginapi.register_routes(routes) + pluginapi.register_template_path(os.path.join(PLUGIN_DIR, 'templates')) + def get_user(**kwargs): username = kwargs.pop('username', None) diff --git a/mediagoblin/plugins/basic_auth/forms.py b/mediagoblin/plugins/basic_auth/forms.py index 6cf01b38..e1d38668 100644 --- a/mediagoblin/plugins/basic_auth/forms.py +++ b/mediagoblin/plugins/basic_auth/forms.py @@ -44,3 +44,20 @@ class LoginForm(wtforms.Form): stay_logged_in = wtforms.BooleanField( label='', description=_('Stay logged in')) + + +class ForgotPassForm(wtforms.Form): + username = wtforms.TextField( + _('Username or email'), + [wtforms.validators.Required(), + normalize_user_or_email_field()]) + + +class ChangeForgotPassForm(wtforms.Form): + password = wtforms.PasswordField( + 'Password', + [wtforms.validators.Required(), + wtforms.validators.Length(min=5, max=1024)]) + token = wtforms.HiddenField( + '', + [wtforms.validators.Required()]) diff --git a/mediagoblin/templates/mediagoblin/auth/change_fp.html b/mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/change_fp.html similarity index 100% rename from mediagoblin/templates/mediagoblin/auth/change_fp.html rename to mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/change_fp.html diff --git a/mediagoblin/templates/mediagoblin/auth/forgot_password.html b/mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/forgot_password.html similarity index 100% rename from mediagoblin/templates/mediagoblin/auth/forgot_password.html rename to mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/forgot_password.html diff --git a/mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt b/mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/fp_verification_email.txt similarity index 100% rename from mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt rename to mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/fp_verification_email.txt diff --git a/mediagoblin/plugins/basic_auth/tools.py b/mediagoblin/plugins/basic_auth/tools.py index 1300bb9a..97393976 100644 --- a/mediagoblin/plugins/basic_auth/tools.py +++ b/mediagoblin/plugins/basic_auth/tools.py @@ -82,3 +82,36 @@ def fake_login_attempt(): randplus_hashed_pass = bcrypt.hashpw(hashed_pass, rand_salt) randplus_stored_hash == randplus_hashed_pass + + +EMAIL_FP_VERIFICATION_TEMPLATE = ( + u"{uri}?" + u"token={fp_verification_key}") + + +def send_fp_verification_email(user, request): + """ + Send the verification email to users to change their password. + + Args: + - user: a user object + - request: the request + """ + fp_verification_key = get_timed_signer_url('mail_verification_token') \ + .dumps(user.id) + + rendered_email = render_template( + request, 'mediagoblin/auth/fp_verification_email.txt', + {'username': user.username, + 'verification_url': EMAIL_FP_VERIFICATION_TEMPLATE.format( + uri=request.urlgen('mediagoblin.auth.verify_forgot_password', + qualified=True), + fp_verification_key=fp_verification_key)}) + + # TODO: There is no error handling in place + send_email( + mg_globals.app_config['email_sender_address'], + [user.email], + 'GNU MediaGoblin - Change forgotten password!', + rendered_email) + diff --git a/mediagoblin/plugins/basic_auth/views.py b/mediagoblin/plugins/basic_auth/views.py new file mode 100644 index 00000000..64defdad --- /dev/null +++ b/mediagoblin/plugins/basic_auth/views.py @@ -0,0 +1,180 @@ +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +from itsdangerous import BadSignature + +from mediagoblin import messages +from mediagoblin.db.models import User +from mediagoblin.plugins.basic_auth import forms, tools +from mediagoblin.tools.crypto import get_timed_signer_url +from mediagoblin.tools.mail import email_debug_message +from mediagoblin.tools.response import redirect, render_to_response, render_404 +from mediagoblin.tools.translate import pass_to_ugettext as _ + + +def forgot_password(request): + """ + Forgot password view + + Sends an email with an url to renew forgotten password. + Use GET querystring parameter 'username' to pre-populate the input field + """ + fp_form = forms.ForgotPassForm(request.form, + username=request.args.get('username')) + + if not (request.method == 'POST' and fp_form.validate()): + # Either GET request, or invalid form submitted. Display the template + return render_to_response(request, + 'mediagoblin/plugins/basic_auth/forgot_password.html', + {'fp_form': fp_form}) + + # If we are here: method == POST and form is valid. username casing + # has been sanitized. Store if a user was found by email. We should + # not reveal if the operation was successful then as we don't want to + # leak if an email address exists in the system. + found_by_email = '@' in fp_form.username.data + + if found_by_email: + user = User.query.filter_by( + email=fp_form.username.data).first() + # Don't reveal success in case the lookup happened by email address. + success_message = _("If that email address (case sensitive!) is " + "registered an email has been sent with " + "instructions on how to change your password.") + + else: # found by username + user = User.query.filter_by( + username=fp_form.username.data).first() + + if user is None: + messages.add_message(request, + messages.WARNING, + _("Couldn't find someone with that username.")) + return redirect(request, 'mediagoblin.auth.forgot_password') + + success_message = _("An email has been sent with instructions " + "on how to change your password.") + + if user and not(user.email_verified and user.status == 'active'): + # Don't send reminder because user is inactive or has no verified email + messages.add_message(request, + messages.WARNING, + _("Could not send password recovery email as your username is in" + "active or your account's email address has not been verified.")) + + return redirect(request, 'mediagoblin.user_pages.user_home', + user=user.username) + + # SUCCESS. Send reminder and return to login page + if user: + email_debug_message(request) + tools.send_fp_verification_email(user, request) + + messages.add_message(request, messages.INFO, success_message) + return redirect(request, 'mediagoblin.auth.login') + + +def verify_forgot_password(request): + """ + Check the forgot-password verification and possibly let the user + change their password because of it. + """ + # get form data variables, and specifically check for presence of token + formdata = _process_for_token(request) + if not formdata['has_token']: + return render_404(request) + + formdata_vars = formdata['vars'] + + # Catch error if token is faked or expired + try: + token = get_timed_signer_url("mail_verification_token") \ + .loads(formdata_vars['token'], max_age=10*24*3600) + except BadSignature: + messages.add_message( + request, + messages.ERROR, + _('The verification key or user id is incorrect.')) + + return redirect( + request, + 'index') + + # check if it's a valid user id + user = User.query.filter_by(id=int(token)).first() + + # no user in db + if not user: + messages.add_message( + request, messages.ERROR, + _('The user id is incorrect.')) + return redirect( + request, 'index') + + # check if user active and has email verified + if user.email_verified and user.status == 'active': + + cp_form = forms.ChangePassForm(formdata_vars) + + if request.method == 'POST' and cp_form.validate(): + user.pw_hash = tools.bcrypt_gen_password_hash( + cp_form.password.data) + user.save() + + messages.add_message( + request, + messages.INFO, + _("You can now log in using your new password.")) + return redirect(request, 'mediagoblin.auth.login') + else: + return render_to_response( + request, + 'mediagoblin/plugins/basic_auth/change_fp.html', + {'cp_form': cp_form}) + + if not user.email_verified: + messages.add_message( + request, messages.ERROR, + _('You need to verify your email before you can reset your' + ' password.')) + + if not user.status == 'active': + messages.add_message( + request, messages.ERROR, + _('You are no longer an active user. Please contact the system' + ' admin to reactivate your accoutn.')) + + return redirect( + request, 'index') + + +def _process_for_token(request): + """ + Checks for tokens in formdata without prior knowledge of request method + + For now, returns whether the userid and token formdata variables exist, and + the formdata variables in a hash. Perhaps an object is warranted? + """ + # retrieve the formdata variables + if request.method == 'GET': + formdata_vars = request.GET + else: + formdata_vars = request.form + + formdata = { + 'vars': formdata_vars, + 'has_token': 'token' in formdata_vars} + + return formdata From af665c4eb9dfb53ef9ac28567f7f3806ed313093 Mon Sep 17 00:00:00 2001 From: Rodney Ewing Date: Mon, 8 Jul 2013 17:17:12 -0700 Subject: [PATCH 2/9] moved change_pass to basic_auth and fixed some typos with the moving of forgot pass --- mediagoblin/edit/forms.py | 13 ------ mediagoblin/edit/routing.py | 2 - mediagoblin/edit/views.py | 41 ------------------ mediagoblin/plugins/basic_auth/forms.py | 13 ++++++ .../plugins/basic_auth/change_fp.html | 2 +- .../plugins/basic_auth}/change_pass.html | 2 +- .../plugins/basic_auth/forgot_password.html | 2 +- .../plugins/basic_auth/verification.txt | 29 +++++++++++++ mediagoblin/plugins/basic_auth/views.py | 37 ++++++++++++++++ mediagoblin/tests/test_auth.py | 5 ++- mediagoblin/tests/test_basic_auth.py | 42 +++++++++++++++++++ mediagoblin/tests/test_edit.py | 35 ---------------- 12 files changed, 127 insertions(+), 96 deletions(-) rename mediagoblin/{templates/mediagoblin/edit => plugins/basic_auth/templates/mediagoblin/plugins/basic_auth}/change_pass.html (95%) create mode 100644 mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/verification.txt diff --git a/mediagoblin/edit/forms.py b/mediagoblin/edit/forms.py index 85c243a0..30dce151 100644 --- a/mediagoblin/edit/forms.py +++ b/mediagoblin/edit/forms.py @@ -98,16 +98,3 @@ class EditCollectionForm(wtforms.Form): description=_( "The title part of this collection's address. " "You usually don't need to change this.")) - - -class ChangePassForm(wtforms.Form): - old_password = wtforms.PasswordField( - _('Old password'), - [wtforms.validators.Required()], - description=_( - "Enter your old password to prove you own this account.")) - new_password = wtforms.PasswordField( - _('New password'), - [wtforms.validators.Required(), - wtforms.validators.Length(min=6, max=30)], - id="password") diff --git a/mediagoblin/edit/routing.py b/mediagoblin/edit/routing.py index 3592f708..e6264fb6 100644 --- a/mediagoblin/edit/routing.py +++ b/mediagoblin/edit/routing.py @@ -24,7 +24,5 @@ add_route('mediagoblin.edit.account', '/edit/account/', 'mediagoblin.edit.views:edit_account') add_route('mediagoblin.edit.delete_account', '/edit/account/delete/', 'mediagoblin.edit.views:delete_account') -add_route('mediagoblin.edit.pass', '/edit/password/', - 'mediagoblin.edit.views:change_pass') add_route('mediagoblin.edit.verify_email', '/edit/verify_email/', 'mediagoblin.edit.views:verify_email') diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py index 6aa2acd9..0bd04498 100644 --- a/mediagoblin/edit/views.py +++ b/mediagoblin/edit/views.py @@ -23,7 +23,6 @@ from werkzeug.utils import secure_filename from mediagoblin import messages from mediagoblin import mg_globals -from mediagoblin import auth from mediagoblin.auth import tools as auth_tools from mediagoblin.edit import forms from mediagoblin.edit.lib import may_edit_media @@ -340,46 +339,6 @@ def edit_collection(request, collection): 'form': form}) -@require_active_login -def change_pass(request): - # If no password authentication, no need to change your password - if 'pass_auth' not in request.template_env.globals: - return redirect(request, 'index') - - form = forms.ChangePassForm(request.form) - user = request.user - - if request.method == 'POST' and form.validate(): - - if not auth.check_password( - form.old_password.data, user.pw_hash): - form.old_password.errors.append( - _('Wrong password')) - - return render_to_response( - request, - 'mediagoblin/edit/change_pass.html', - {'form': form, - 'user': user}) - - # Password matches - user.pw_hash = auth.gen_password_hash( - form.new_password.data) - user.save() - - messages.add_message( - request, messages.SUCCESS, - _('Your password was changed successfully')) - - return redirect(request, 'mediagoblin.edit.account') - - return render_to_response( - request, - 'mediagoblin/edit/change_pass.html', - {'form': form, - 'user': user}) - - def verify_email(request): """ Email verification view for changing email address diff --git a/mediagoblin/plugins/basic_auth/forms.py b/mediagoblin/plugins/basic_auth/forms.py index e1d38668..c10496f8 100644 --- a/mediagoblin/plugins/basic_auth/forms.py +++ b/mediagoblin/plugins/basic_auth/forms.py @@ -61,3 +61,16 @@ class ChangeForgotPassForm(wtforms.Form): token = wtforms.HiddenField( '', [wtforms.validators.Required()]) + + +class ChangePassForm(wtforms.Form): + old_password = wtforms.PasswordField( + _('Old password'), + [wtforms.validators.Required()], + description=_( + "Enter your old password to prove you own this account.")) + new_password = wtforms.PasswordField( + _('New password'), + [wtforms.validators.Required(), + wtforms.validators.Length(min=6, max=30)], + id="password") diff --git a/mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/change_fp.html b/mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/change_fp.html index a3cf9cb9..47cd591e 100644 --- a/mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/change_fp.html +++ b/mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/change_fp.html @@ -29,7 +29,7 @@ {%- endblock %} {% block mediagoblin_content %} -
{{ csrf_token }}
diff --git a/mediagoblin/templates/mediagoblin/edit/change_pass.html b/mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/change_pass.html similarity index 95% rename from mediagoblin/templates/mediagoblin/edit/change_pass.html rename to mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/change_pass.html index 2a1ffee0..596a4def 100644 --- a/mediagoblin/templates/mediagoblin/edit/change_pass.html +++ b/mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/change_pass.html @@ -31,7 +31,7 @@ {%- endblock %} {% block mediagoblin_content %} -

diff --git a/mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/forgot_password.html b/mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/forgot_password.html index 6cfd2c85..b0028ab6 100644 --- a/mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/forgot_password.html +++ b/mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/forgot_password.html @@ -24,7 +24,7 @@ {%- endblock %} {% block mediagoblin_content %} - {{ csrf_token }}
diff --git a/mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/verification.txt b/mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/verification.txt new file mode 100644 index 00000000..d53cd5e8 --- /dev/null +++ b/mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/verification.txt @@ -0,0 +1,29 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +-#} + +{% trans username=username, verification_url=verification_url|safe -%} +Hi, + +We wanted to verify that you are {{ username }}. If this is the case, then +please follow the link below to verify your new email address. + +{{ verification_url }} + +If you are not {{ username }} or didn't request an email change, you can ignore +this email. +{%- endtrans %} diff --git a/mediagoblin/plugins/basic_auth/views.py b/mediagoblin/plugins/basic_auth/views.py index 64defdad..9a1b75d2 100644 --- a/mediagoblin/plugins/basic_auth/views.py +++ b/mediagoblin/plugins/basic_auth/views.py @@ -17,6 +17,7 @@ from itsdangerous import BadSignature from mediagoblin import messages from mediagoblin.db.models import User +from mediagoblin.decorators import require_active_login from mediagoblin.plugins.basic_auth import forms, tools from mediagoblin.tools.crypto import get_timed_signer_url from mediagoblin.tools.mail import email_debug_message @@ -178,3 +179,39 @@ def _process_for_token(request): 'has_token': 'token' in formdata_vars} return formdata + + +@require_active_login +def change_pass(request): + form = forms.ChangePassForm(request.form) + user = request.user + + if request.method == 'POST' and form.validate(): + + if not tools.bcrypt_check_password( + form.old_password.data, user.pw_hash): + form.old_password.errors.append( + _('Wrong password')) + + return render_to_response( + request, + 'mediagoblin/plugins/basic_auth/change_pass.html', + {'form': form, + 'user': user}) + + # Password matches + user.pw_hash = tools.bcrypt_gen_password_hash( + form.new_password.data) + user.save() + + messages.add_message( + request, messages.SUCCESS, + _('Your password was changed successfully')) + + return redirect(request, 'mediagoblin.edit.account') + + return render_to_response( + request, + 'mediagoblin/plugins/basic_auth/change_pass.html', + {'form': form, + 'user': user}) diff --git a/mediagoblin/tests/test_auth.py b/mediagoblin/tests/test_auth.py index 61503d32..e4bb60e5 100644 --- a/mediagoblin/tests/test_auth.py +++ b/mediagoblin/tests/test_auth.py @@ -183,7 +183,7 @@ def test_register_views(test_app): message = mail.EMAIL_TEST_INBOX.pop() assert message['To'] == 'happygrrl@example.org' email_context = template.TEMPLATE_TEST_CONTEXT[ - 'mediagoblin/auth/fp_verification_email.txt'] + 'mediagoblin/plugins/basic_auth/fp_verification_email.txt'] #TODO - change the name of verification_url to something forgot-password-ish assert email_context['verification_url'] in message.get_payload(decode=True) @@ -204,7 +204,8 @@ def test_register_views(test_app): ## Verify step 1 of password-change works -- can see form to change password template.clear_test_template_context() response = test_app.get("%s?%s" % (path, get_params)) - assert 'mediagoblin/auth/change_fp.html' in template.TEMPLATE_TEST_CONTEXT + assert 'mediagoblin/plugins/basic_auth/change_fp.html' in \ + template.TEMPLATE_TEST_CONTEXT ## Verify step 2.1 of password-change works -- report success to user template.clear_test_template_context() diff --git a/mediagoblin/tests/test_basic_auth.py b/mediagoblin/tests/test_basic_auth.py index cdd80fca..e03f90f0 100644 --- a/mediagoblin/tests/test_basic_auth.py +++ b/mediagoblin/tests/test_basic_auth.py @@ -13,7 +13,12 @@ # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +import urlparse + +from mediagoblin.db.models import User from mediagoblin.plugins.basic_auth import tools as auth_tools +from mediagoblin.tests.tools import fixture_add_user +from mediagoblin.tools import template from mediagoblin.tools.testing import _activate_testing _activate_testing() @@ -57,3 +62,40 @@ def test_bcrypt_gen_password_hash(): pw, hashed_pw, '3><7R45417') assert not auth_tools.bcrypt_check_password( 'notthepassword', hashed_pw, '3><7R45417') + + +def test_change_password(self, test_app): + """Test changing password correctly and incorrectly""" + test_user = fixture_add_user(password=u'toast') + + test_app.post( + '/auth/login/', { + 'username': u'chris', + 'password': u'toast'}) + + # test that the password can be changed + res = test_app.post( + '/edit/password/', { + 'old_password': 'toast', + 'new_password': '123456', + }) + res.follow() + + # Did we redirect to the correct page? + assert urlparse.urlsplit(res.location)[2] == '/edit/account/' + + # test_user has to be fetched again in order to have the current values + test_user = User.query.filter_by(username=u'chris').first() + assert auth_tools.bcrypt_check_password('123456', test_user.pw_hash) + + # test that the password cannot be changed if the given + # old_password is wrong + template.clear_test_template_context() + test_app.post( + '/edit/password/', { + 'old_password': 'toast', + 'new_password': '098765', + }) + + test_user = User.query.filter_by(username=u'chris').first() + assert not auth_tools.bcrypt_check_password('098765', test_user.pw_hash) diff --git a/mediagoblin/tests/test_edit.py b/mediagoblin/tests/test_edit.py index d70d0478..581af4ac 100644 --- a/mediagoblin/tests/test_edit.py +++ b/mediagoblin/tests/test_edit.py @@ -56,41 +56,6 @@ class TestUserEdit(object): self.login(test_app) - def test_change_password(self, test_app): - """Test changing password correctly and incorrectly""" - self.login(test_app) - - # test that the password can be changed - template.clear_test_template_context() - res = test_app.post( - '/edit/password/', { - 'old_password': 'toast', - 'new_password': '123456', - }) - res.follow() - - # Did we redirect to the correct page? - assert urlparse.urlsplit(res.location)[2] == '/edit/account/' - - # test_user has to be fetched again in order to have the current values - test_user = User.query.filter_by(username=u'chris').first() - assert auth.check_password('123456', test_user.pw_hash) - # Update current user passwd - self.user_password = '123456' - - # test that the password cannot be changed if the given - # old_password is wrong - template.clear_test_template_context() - test_app.post( - '/edit/password/', { - 'old_password': 'toast', - 'new_password': '098765', - }) - - test_user = User.query.filter_by(username=u'chris').first() - assert not auth.check_password('098765', test_user.pw_hash) - - def test_change_bio_url(self, test_app): """Test changing bio and URL""" self.login(test_app) From 36f901fbbd68479a911058f4ec3b9717e81e2b92 Mon Sep 17 00:00:00 2001 From: Rodney Ewing Date: Mon, 8 Jul 2013 17:28:21 -0700 Subject: [PATCH 3/9] used template hooks instead of hardcoding basic_auth functionality into templates --- mediagoblin/plugins/basic_auth/__init__.py | 11 ++++++++ .../static/js/autofilledin_password.js | 0 .../plugins/basic_auth/edit_link.html | 25 +++++++++++++++++++ .../plugins/basic_auth/fp_head.html | 20 +++++++++++++++ .../plugins/basic_auth/fp_link.html | 25 +++++++++++++++++++ .../mediagoblin/plugins/openid/login.html | 4 +-- .../templates/mediagoblin/auth/login.html | 11 +++----- .../mediagoblin/edit/edit_account.html | 7 ------ 8 files changed, 86 insertions(+), 17 deletions(-) rename mediagoblin/{ => plugins/basic_auth}/static/js/autofilledin_password.js (100%) create mode 100644 mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/edit_link.html create mode 100644 mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/fp_head.html create mode 100644 mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/fp_link.html diff --git a/mediagoblin/plugins/basic_auth/__init__.py b/mediagoblin/plugins/basic_auth/__init__.py index 913ccba4..06059a07 100644 --- a/mediagoblin/plugins/basic_auth/__init__.py +++ b/mediagoblin/plugins/basic_auth/__init__.py @@ -13,6 +13,7 @@ # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +from pkg_resources import resource_filename import os from mediagoblin.plugins.basic_auth import forms as auth_forms @@ -21,6 +22,8 @@ from mediagoblin.auth.tools import create_basic_user from mediagoblin.db.models import User from mediagoblin.tools import pluginapi from sqlalchemy import or_ +from mediagoblin.tools.staticdirect import PluginStatic + PLUGIN_DIR = os.path.dirname(__file__) @@ -42,6 +45,11 @@ def setup_plugin(): pluginapi.register_routes(routes) pluginapi.register_template_path(os.path.join(PLUGIN_DIR, 'templates')) + pluginapi.register_template_hooks( + {'edit_link': 'mediagoblin/plugins/basic_auth/edit_link.html', + 'fp_link': 'mediagoblin/plugins/basic_auth/fp_link.html', + 'fp_head': 'mediagoblin/plugins/basic_auth/fp_head.html'}) + def get_user(**kwargs): username = kwargs.pop('username', None) @@ -103,4 +111,7 @@ hooks = { 'auth_check_password': check_password, 'auth_fake_login_attempt': auth_tools.fake_login_attempt, 'template_global_context': append_to_global_context, + 'static_setup': lambda: PluginStatic( + 'coreplugin_basic_auth', + resource_filename('mediagoblin.plugins.basic_auth', 'static')) } diff --git a/mediagoblin/static/js/autofilledin_password.js b/mediagoblin/plugins/basic_auth/static/js/autofilledin_password.js similarity index 100% rename from mediagoblin/static/js/autofilledin_password.js rename to mediagoblin/plugins/basic_auth/static/js/autofilledin_password.js diff --git a/mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/edit_link.html b/mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/edit_link.html new file mode 100644 index 00000000..9fd09ab1 --- /dev/null +++ b/mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/edit_link.html @@ -0,0 +1,25 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} + +{% block change_pass_link %} +

+ + {% trans %}Change your password.{% endtrans %} + +

+{% endblock %} diff --git a/mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/fp_head.html b/mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/fp_head.html new file mode 100644 index 00000000..292dce28 --- /dev/null +++ b/mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/fp_head.html @@ -0,0 +1,20 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# + You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} + + diff --git a/mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/fp_link.html b/mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/fp_link.html new file mode 100644 index 00000000..404358d8 --- /dev/null +++ b/mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/fp_link.html @@ -0,0 +1,25 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} + +{% block fp_link %} +

+ + {% trans %}Forgot your password?{% endtrans %} +

+{% endblock %} + diff --git a/mediagoblin/plugins/openid/templates/mediagoblin/plugins/openid/login.html b/mediagoblin/plugins/openid/templates/mediagoblin/plugins/openid/login.html index 8d74c2b9..193a3b2d 100644 --- a/mediagoblin/plugins/openid/templates/mediagoblin/plugins/openid/login.html +++ b/mediagoblin/plugins/openid/templates/mediagoblin/plugins/openid/login.html @@ -20,8 +20,8 @@ {% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} {% block mediagoblin_head %} - + {{ super() }} + {% template_hook("fp_head") %} {% endblock %} {% block title -%} diff --git a/mediagoblin/templates/mediagoblin/auth/login.html b/mediagoblin/templates/mediagoblin/auth/login.html index 3329b5d0..c394245e 100644 --- a/mediagoblin/templates/mediagoblin/auth/login.html +++ b/mediagoblin/templates/mediagoblin/auth/login.html @@ -20,8 +20,8 @@ {% import "/mediagoblin/utils/wtforms.html" as wtforms_util %} {% block mediagoblin_head %} - + {{ super() }} + {% template_hook("fp_head") %} {% endblock %} {% block title -%} @@ -48,12 +48,7 @@ {% endif %} {% template_hook("login_link") %} {{ wtforms_util.render_divs(login_form, True) }} - {% if pass_auth %} -

- - {% trans %}Forgot your password?{% endtrans %} -

- {% endif %} + {% template_hook("fp_link") %}
diff --git a/mediagoblin/templates/mediagoblin/edit/edit_account.html b/mediagoblin/templates/mediagoblin/edit/edit_account.html index 51293acb..069cfd85 100644 --- a/mediagoblin/templates/mediagoblin/edit/edit_account.html +++ b/mediagoblin/templates/mediagoblin/edit/edit_account.html @@ -41,13 +41,6 @@ Changing {{ username }}'s account settings {%- endtrans -%}

- {% if pass_auth is defined %} -

- - {% trans %}Change your password.{% endtrans %} - -

- {% endif %} {% template_hook("edit_link") %} {{ wtforms_util.render_divs(form, True) }}
From 229f0bd8fb69463876be274598224150c7aff387 Mon Sep 17 00:00:00 2001 From: Rodney Ewing Date: Mon, 8 Jul 2013 17:34:18 -0700 Subject: [PATCH 4/9] fixed typo to check allow_registration not if auth is enabled --- mediagoblin/plugins/openid/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mediagoblin/plugins/openid/views.py b/mediagoblin/plugins/openid/views.py index b639a4cb..bb2de7ab 100644 --- a/mediagoblin/plugins/openid/views.py +++ b/mediagoblin/plugins/openid/views.py @@ -195,11 +195,11 @@ def finish_login(request): return redirect(request, "index") else: # No user, need to register - if not mg_globals.app.auth: + if not mg_globals.app_config['allow_registration']: messages.add_message( request, messages.WARNING, - _('Sorry, authentication is disabled on this instance.')) + _('Sorry, registration is disabled on this instance.')) return redirect(request, 'index') # Get email and nickname from response From 581e52c26424e6db0d2ce430e8766e8a8c929586 Mon Sep 17 00:00:00 2001 From: Rodney Ewing Date: Mon, 8 Jul 2013 17:34:52 -0700 Subject: [PATCH 5/9] deleted misplaced template --- .../plugins/basic_auth/verification.txt | 29 ------------------- 1 file changed, 29 deletions(-) delete mode 100644 mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/verification.txt diff --git a/mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/verification.txt b/mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/verification.txt deleted file mode 100644 index d53cd5e8..00000000 --- a/mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/verification.txt +++ /dev/null @@ -1,29 +0,0 @@ -{# -# GNU MediaGoblin -- federated, autonomous media hosting -# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . --#} - -{% trans username=username, verification_url=verification_url|safe -%} -Hi, - -We wanted to verify that you are {{ username }}. If this is the case, then -please follow the link below to verify your new email address. - -{{ verification_url }} - -If you are not {{ username }} or didn't request an email change, you can ignore -this email. -{%- endtrans %} From f66e4282d481fbc97e9c38eb805232a0a2d21960 Mon Sep 17 00:00:00 2001 From: Rodney Ewing Date: Tue, 9 Jul 2013 11:01:00 -0700 Subject: [PATCH 6/9] moved create account link on login page to a hook --- mediagoblin/plugins/basic_auth/__init__.py | 4 ++- .../basic_auth/create_account_link.html | 27 +++++++++++++++++++ .../templates/mediagoblin/auth/login.html | 8 +----- 3 files changed, 31 insertions(+), 8 deletions(-) create mode 100644 mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/create_account_link.html diff --git a/mediagoblin/plugins/basic_auth/__init__.py b/mediagoblin/plugins/basic_auth/__init__.py index 06059a07..64564c7f 100644 --- a/mediagoblin/plugins/basic_auth/__init__.py +++ b/mediagoblin/plugins/basic_auth/__init__.py @@ -48,7 +48,9 @@ def setup_plugin(): pluginapi.register_template_hooks( {'edit_link': 'mediagoblin/plugins/basic_auth/edit_link.html', 'fp_link': 'mediagoblin/plugins/basic_auth/fp_link.html', - 'fp_head': 'mediagoblin/plugins/basic_auth/fp_head.html'}) + 'fp_head': 'mediagoblin/plugins/basic_auth/fp_head.html', + 'create_account': + 'mediagoblin/plugins/basic_auth/create_account_link.html'}) def get_user(**kwargs): diff --git a/mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/create_account_link.html b/mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/create_account_link.html new file mode 100644 index 00000000..7425630b --- /dev/null +++ b/mediagoblin/plugins/basic_auth/templates/mediagoblin/plugins/basic_auth/create_account_link.html @@ -0,0 +1,27 @@ +{# +# GNU MediaGoblin -- federated, autonomous media hosting +# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +#} + +{% block create_account %} + {% if allow_registration %} +

+ {% trans %}Don't have an account yet?{% endtrans %} + + {%- trans %}Create one here!{% endtrans %} +

+ {% endif %} +{% endblock %} diff --git a/mediagoblin/templates/mediagoblin/auth/login.html b/mediagoblin/templates/mediagoblin/auth/login.html index c394245e..93cd82d9 100644 --- a/mediagoblin/templates/mediagoblin/auth/login.html +++ b/mediagoblin/templates/mediagoblin/auth/login.html @@ -39,13 +39,7 @@ {% trans %}Logging in failed!{% endtrans %}
{% endif %} - {% if allow_registration %} -

- {% trans %}Don't have an account yet?{% endtrans %} - - {%- trans %}Create one here!{% endtrans %} -

- {% endif %} + {% template_hook("create_account") %} {% template_hook("login_link") %} {{ wtforms_util.render_divs(login_form, True) }} {% template_hook("fp_link") %} From 33b5cebe750a8bc8a96401bd6cda729fa9b00a9d Mon Sep 17 00:00:00 2001 From: Rodney Ewing Date: Tue, 9 Jul 2013 16:52:37 -0700 Subject: [PATCH 7/9] fixed some typos and missed imports --- mediagoblin/plugins/basic_auth/tools.py | 10 +++++++--- mediagoblin/plugins/basic_auth/views.py | 2 +- mediagoblin/tests/test_basic_auth.py | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/mediagoblin/plugins/basic_auth/tools.py b/mediagoblin/plugins/basic_auth/tools.py index 97393976..f943bf39 100644 --- a/mediagoblin/plugins/basic_auth/tools.py +++ b/mediagoblin/plugins/basic_auth/tools.py @@ -16,6 +16,11 @@ import bcrypt import random +from mediagoblin import mg_globals +from mediagoblin.tools.crypto import get_timed_signer_url +from mediagoblin.tools.mail import send_email +from mediagoblin.tools.template import render_template + def bcrypt_check_password(raw_pass, stored_hash, extra_salt=None): """ @@ -101,10 +106,10 @@ def send_fp_verification_email(user, request): .dumps(user.id) rendered_email = render_template( - request, 'mediagoblin/auth/fp_verification_email.txt', + request, 'mediagoblin/plugins/basic_auth/fp_verification_email.txt', {'username': user.username, 'verification_url': EMAIL_FP_VERIFICATION_TEMPLATE.format( - uri=request.urlgen('mediagoblin.auth.verify_forgot_password', + uri=request.urlgen('mediagoblin.plugins.basic_auth.verify_forgot_password', qualified=True), fp_verification_key=fp_verification_key)}) @@ -114,4 +119,3 @@ def send_fp_verification_email(user, request): [user.email], 'GNU MediaGoblin - Change forgotten password!', rendered_email) - diff --git a/mediagoblin/plugins/basic_auth/views.py b/mediagoblin/plugins/basic_auth/views.py index 9a1b75d2..d0941ae5 100644 --- a/mediagoblin/plugins/basic_auth/views.py +++ b/mediagoblin/plugins/basic_auth/views.py @@ -127,7 +127,7 @@ def verify_forgot_password(request): # check if user active and has email verified if user.email_verified and user.status == 'active': - cp_form = forms.ChangePassForm(formdata_vars) + cp_form = forms.ChangeForgotPassForm(formdata_vars) if request.method == 'POST' and cp_form.validate(): user.pw_hash = tools.bcrypt_gen_password_hash( diff --git a/mediagoblin/tests/test_basic_auth.py b/mediagoblin/tests/test_basic_auth.py index e03f90f0..45deab7c 100644 --- a/mediagoblin/tests/test_basic_auth.py +++ b/mediagoblin/tests/test_basic_auth.py @@ -64,7 +64,7 @@ def test_bcrypt_gen_password_hash(): 'notthepassword', hashed_pw, '3><7R45417') -def test_change_password(self, test_app): +def test_change_password(test_app): """Test changing password correctly and incorrectly""" test_user = fixture_add_user(password=u'toast') From c37f31fbf3683ab8931ff43d98a743d607cea70c Mon Sep 17 00:00:00 2001 From: Rodney Ewing Date: Wed, 10 Jul 2013 13:56:32 -0700 Subject: [PATCH 8/9] use new in-memory db for testing --- .../tests/auth_configs/authentication_disabled_appconfig.ini | 4 ++-- mediagoblin/tests/auth_configs/openid_appconfig.ini | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mediagoblin/tests/auth_configs/authentication_disabled_appconfig.ini b/mediagoblin/tests/auth_configs/authentication_disabled_appconfig.ini index a64e9e40..07c69442 100644 --- a/mediagoblin/tests/auth_configs/authentication_disabled_appconfig.ini +++ b/mediagoblin/tests/auth_configs/authentication_disabled_appconfig.ini @@ -3,8 +3,8 @@ direct_remote_path = /test_static/ email_sender_address = "notice@mediagoblin.example.org" email_debug_mode = true -# TODO: Switch to using an in-memory database -sql_engine = "sqlite:///%(here)s/user_dev/mediagoblin.db" +sql_engine = "sqlite://" +run_migrations = true # Celery shouldn't be set up by the application as it's setup via # mediagoblin.init.celery.from_celery diff --git a/mediagoblin/tests/auth_configs/openid_appconfig.ini b/mediagoblin/tests/auth_configs/openid_appconfig.ini index c2bd82fd..3433e139 100644 --- a/mediagoblin/tests/auth_configs/openid_appconfig.ini +++ b/mediagoblin/tests/auth_configs/openid_appconfig.ini @@ -18,8 +18,8 @@ direct_remote_path = /test_static/ email_sender_address = "notice@mediagoblin.example.org" email_debug_mode = true -# TODO: Switch to using an in-memory database -sql_engine = "sqlite:///%(here)s/user_dev/mediagoblin.db" +sql_engine = "sqlite://" +run_migrations = true # Celery shouldn't be set up by the application as it's setup via # mediagoblin.init.celery.from_celery From f9931418d65c7823e13bc45f647a682ddf3b8632 Mon Sep 17 00:00:00 2001 From: Rodney Ewing Date: Wed, 10 Jul 2013 14:06:54 -0700 Subject: [PATCH 9/9] skip openid test if python-openid isn't installed --- mediagoblin/tests/test_openid.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mediagoblin/tests/test_openid.py b/mediagoblin/tests/test_openid.py index 23a2290e..3dfafb60 100644 --- a/mediagoblin/tests/test_openid.py +++ b/mediagoblin/tests/test_openid.py @@ -29,6 +29,7 @@ from mediagoblin.plugins.openid.models import OpenIDUserURL from mediagoblin.tests.tools import get_app, fixture_add_user from mediagoblin.tools import template + # App with plugin enabled @pytest.fixture() def openid_plugin_app(request):