Add email-confirmed password changing.

This commit is contained in:
Ricky Zhou (周家杰) 2008-03-12 11:35:38 -04:00
parent d4b8fb66da
commit ef1c94e140
5 changed files with 102 additions and 47 deletions

View file

@ -10,7 +10,7 @@ legal_cla_email = "nobody@fedoraproject.org"
email_host = "fedoraproject.org" # as in, web-members@email_host
gpgexec = "/usr/bin/gpg"
gpghome = "/srv/fedora-infrastructure/fas/gnupg"
gpghome = "/home/ricky/work/fedora/fedora-infrastructure/fas/gnupg"
gpg_fingerprint = "C199 1E25 D00A D200 2D2E 54D1 BF7F 1647 C54E 8410"
gpg_passphrase = "m00!s@ysth3c0w"
gpg_keyserver = "hkp://subkeys.pgp.net"
@ -83,7 +83,7 @@ tg.strict_parameters = True
server.webpath='/accounts'
base_url_filter.on = True
base_url_filter.use_x_forwarded_host = True
base_url_filter.base_url = "https://publictest3.fedoraproject.org/accounts"
base_url_filter.base_url = "http://localhost:8088/accounts"
# Make the session cookie only return to the host over an SSL link
# Disabled for testing.

View file

@ -247,17 +247,16 @@ class People(SABase):
# Only admins can see internal_comments
del props['internal_comments']
del props['emailtoken']
del props['passwordtoken']
if identity.current.anonymous:
# Anonymous users can't see any of these
del props['email']
del props['emailtoken']
del props['unverified_email']
del props['ssh_key']
del props['gpg_keyid']
del props['affiliation']
del props['certificate_serial']
del props['password']
del props['passwordtoken']
del props['password_changed']
del props['postal_address']
del props['telephone']
@ -267,7 +266,6 @@ class People(SABase):
# Only an admin or the user themselves can see these fields
del props['unverified_email']
del props['password']
del props['passwordtoken']
del props['postal_address']
del props['password_changed']
del props['telephone']

View file

@ -8,7 +8,7 @@
</head>
<body>
<h2>${_('Reset Password')}</h2>
<form action="${tg.url('/user/sendpass')}" method="post">
<form action="${tg.url('/user/sendtoken')}" method="post">
<ul>
<div class="field"><label for="username">${_('Username:')}</label> <input type="text" id="username" name="username" /></div>
<div class="field"><label for="email">${_('Email:')}</label> <input type="text" id="email" name="email" /></div>

View file

@ -13,8 +13,8 @@
<p>
Do you really want to change your email to: ${person.unverified_email} ?
</p>
<input type="submit" name="confirmation" id="confirmation" value="${_('Confirm')}" />
<input type="submit" value="${_('Cancel')}" />
<input type="submit" value="${_('Confirm')}" />
<a href="${tg.url('/user/verifyemail/%s/%s/cancel') % (person.username, token)}">${_('Cancel')}</a>
</div>
</form>
</body>

View file

@ -125,6 +125,12 @@ class UserSetPassword(validators.Schema):
passwordcheck = validators.String
chained_validators = [validators.FieldsMatch('password', 'passwordcheck')]
class UserResetPassword(validators.Schema):
# TODO (after we're done with most testing): Add complexity requirements?
password = validators.String(min=8)
passwordcheck = validators.String
chained_validators = [validators.FieldsMatch('password', 'passwordcheck')]
class UserView(validators.Schema):
username = KnownUser
@ -271,8 +277,7 @@ login with your Fedora account first):
https://admin.fedoraproject.org/accounts/user/verifyemail/%s
''') % token
emailflash = _(' Your email ')
emailflash = _(' Before your new email takes effect, you must confirm it. You should receive an email with instructions shortly.')
turbomail.enqueue(message)
target.ircnick = ircnick
target.gpg_keyid = gpg_keyid
@ -326,7 +331,7 @@ https://admin.fedoraproject.org/accounts/user/verifyemail/%s
@identity.require(turbogears.identity.not_anonymous())
@expose(template='fas.templates.user.verifyemail')
def verifyemail(self, token):
def verifyemail(self, token, cancel=False):
username = turbogears.identity.current.user_name
person = People.by_username(username)
if not person.unverified_email:
@ -334,38 +339,38 @@ https://admin.fedoraproject.org/accounts/user/verifyemail/%s
turbogears.redirect('/user/view/%s' % username)
return dict()
if person.emailtoken and (person.emailtoken != token):
person.emailtoken = ''
turbogears.flash(_('Invalid email change token.'))
turbogears.redirect('/user/view/%s' % username)
return dict()
if cancel:
person.emailtoken = ''
turbogears.flash(_('Your pending email change has been canceled. The email change token has been invalidated.'))
turbogears.redirect('/user/view/%s' % username)
return dict()
return dict(person=person, token=token)
@identity.require(turbogears.identity.not_anonymous())
@expose(template='fas.templates.user.verifyemail')
def setemail(self, token, confirmation=None):
@expose()
def setemail(self, token):
username = turbogears.identity.current.user_name
person = People.by_username(username)
if not person.unverified_email:
if not (person.unverified_email and person.emailtoken):
turbogears.flash(_('You do not have any pending email changes.'))
turbogears.redirect('/user/view/%s' % username)
return dict()
if person.emailtoken and (person.emailtoken != token):
person.emailtoken = ''
if person.emailtoken != token:
turbogears.flash(_('Invalid email change token.'))
turbogears.redirect('/user/view/%s' % username)
return dict()
if confirmation:
''' Log this '''
oldEmail = person.email
person.email = person.unverified_email
Log(author_id=person.id, description='Email changed from %s to %s' % (oldEmail, person.email))
person.unverified_email = ''
session.flush()
turbogears.flash(_('You have successfully changed your email to \'%s\'') % person.email)
turbogears.redirect('/user/view/%s' % username)
else:
turbogears.flash(_('Your pending email change has been canceled. The email change token has been invalidated.') % person.email)
turbogears.redirect('/user/view/%s' % username)
''' Log this '''
oldEmail = person.email
person.email = person.unverified_email
Log(author_id=person.id, description='Email changed from %s to %s' % (oldEmail, person.email))
person.unverified_email = ''
session.flush()
turbogears.flash(_('You have successfully changed your email to \'%s\'') % person.email)
turbogears.redirect('/user/view/%s' % username)
return dict()
@expose(template='fas.templates.user.new')
def new(self):
@ -397,7 +402,7 @@ https://admin.fedoraproject.org/accounts/user/verifyemail/%s
You have created a new Fedora account!
Your new password is: %s
Please go to https://admin.fedoraproject.org/fas/ to change it.
Please go to https://admin.fedoraproject.org/accounts/ to change it.
Welcome to the Fedora Project. Now that you've signed up for an
account you're probably desperate to start contributing, and with that
@ -481,7 +486,7 @@ forward to working with you!
#TODO: Validate
@expose(template="fas.templates.user.resetpass")
def sendpass(self, username, email, encrypted=False):
def sendtoken(self, username, email, encrypted=False):
import turbomail
# Logged in
if turbogears.identity.current.user_name:
@ -496,14 +501,13 @@ forward to working with you!
if email != person.email:
turbogears.flash(_("username + email combo unknown."))
return dict()
newpass = generate_password()
token = generate_token()
message = turbomail.Message(config.get('accounts_email'), email, _('Fedora Project Password Reset'))
mail = _('''
You have requested a password reset!
Your new password is: %s
Please go to https://admin.fedoraproject.org/fas/ to change it.
''') % newpass['pass']
Somebody (hopefully you) has requested a password reset for your account!
To change your password (or to cancel the request), please visit
https://admin.fedoraproject.org/accounts/user/verifypass/%(user)s/%(token)s
''') % {'user': username, 'token': token}
if encrypted:
# TODO: Move this out to a single function (same as
# CLA one), think of how to make sure this doesn't get
@ -517,7 +521,8 @@ Please go to https://admin.fedoraproject.org/fas/ to change it.
return dict()
else:
try:
plaintext = StringIO.StringIO(mail)
# This may not be the neatest fix, but gpgme gave an error when mail was unicode.
plaintext = StringIO.StringIO(mail.encode('utf-8'))
ciphertext = StringIO.StringIO()
ctx = gpgme.Context()
ctx.armor = True
@ -533,26 +538,78 @@ Please go to https://admin.fedoraproject.org/fas/ to change it.
ciphertext)
message.plain = ciphertext.getvalue()
except:
turbogears.flash(_('Your password reset email could not be encrypted. Your password has not been changed.'))
turbogears.flash(_('Your password reset email could not be encrypted.'))
return dict()
else:
message.plain = mail;
turbomail.enqueue(message)
try:
person.password = newpass['hash']
turbogears.flash(_('Your new password has been emailed to you.'))
except:
turbogears.flash(_('Your password could not be reset.'))
return dict()
person.passwordtoken = token
turbogears.flash(_('A password reset URL has been emailed to you.'))
turbogears.redirect('/login')
return dict()
@expose(template="fas.templates.user.newpass")
# TODO: Validator
def newpass(self, username, token, password=None, passwordcheck=None):
person = People.by_username(username)
if not person.passwordtoken:
turbogears.flash(_('You do not have any pending password changes.'))
turbogears.redirect('/login')
return dict()
if person.passwordtoken != token:
person.emailtoken = ''
turbogears.flash(_('Invalid password change token.'))
turbogears.redirect('/login')
return dict()
return dict(person=person, token=token)
@expose(template="fas.templates.user.verifypass")
# TODO: Validator
def verifypass(self, username, token, cancel=False):
person = People.by_username(username)
if not person.passwordtoken:
turbogears.flash(_('You do not have any pending password changes.'))
turbogears.redirect('/login')
return dict()
if person.passwordtoken != token:
turbogears.flash(_('Invalid password change token.'))
turbogears.redirect('/login')
return dict()
if cancel:
person.passwordtoken = ''
turbogears.flash(_('Your password reset has been canceled. The password change token has been invalidated.'))
turbogears.redirect('/login')
return dict()
return dict(person=person, token=token)
@expose()
@validate(validators=UserResetPassword())
def setnewpass(self, username, token, password, passwordcheck):
person = People.by_username(username)
if not person.passwordtoken:
turbogears.flash(_('You do not have any pending password changes.'))
turbogears.redirect('/login')
return dict()
if person.passwordtoken != token:
person.emailtoken = ''
turbogears.flash(_('Invalid password change token.'))
turbogears.redirect('/login')
return dict()
''' Log this '''
newpass = generate_password(password)
person.password = newpass['hash']
person.passwordtoken = ''
Log(author_id=person.id, description='Password changed')
session.flush()
turbogears.flash(_('You have successfully reset your password. You should now be able to login below.'))
turbogears.redirect('/login')
return dict()
@identity.require(turbogears.identity.not_anonymous())
@expose(template="genshi-text:fas.templates.user.cert", format="text", content_type='text/plain; charset=utf-8')
def gencert(self):
username = turbogears.identity.current.user_name
person = People.by_username(username)
person = People.by_username(username)
if signedCLAPrivs(person):
person.certificate_serial = person.certificate_serial + 1