Changeset 3799
- Timestamp:
- 06/07/08 22:48:51 (4 months ago)
- Files:
-
- accountmanagerplugin/trunk/acct_mgr/pwhash.py (modified) (2 diffs)
- accountmanagerplugin/trunk/acct_mgr/templates/verify_email.html (added)
- accountmanagerplugin/trunk/acct_mgr/templates/verify_email.txt (added)
- accountmanagerplugin/trunk/acct_mgr/util.py (modified) (1 diff)
- accountmanagerplugin/trunk/acct_mgr/web_ui.py (modified) (6 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
accountmanagerplugin/trunk/acct_mgr/pwhash.py
r2127 r3799 17 17 18 18 from md5crypt import md5crypt 19 from acct_mgr.util import urandom 19 20 20 21 class IPasswordHashMethod(Interface): … … 64 65 crypt = None 65 66 66 # os.urandom was added in Python 2.467 # try to fall back on reading from /dev/urandom on older Python versions68 try:69 from os import urandom70 except ImportError:71 from random import randrange72 def urandom(n):73 return ''.join([chr(randrange(256)) for _ in xrange(n)])74 75 67 def salt(): 76 68 s = '' accountmanagerplugin/trunk/acct_mgr/util.py
r2068 r3799 23 23 return path 24 24 return os.path.normpath(os.path.join(instance.env.path, path)) 25 26 27 # os.urandom was added in Python 2.4 28 # try to fall back on pseudo-random values if it's not available 29 try: 30 from os import urandom 31 except ImportError: 32 from random import randrange 33 def urandom(n): 34 return ''.join([chr(randrange(256)) for _ in xrange(n)]) 35 36 accountmanagerplugin/trunk/acct_mgr/web_ui.py
r3731 r3799 10 10 # Author: Matthew Good <trac@matt-good.net> 11 11 12 import base64 13 import os 12 14 import random 13 15 import string … … 21 23 from trac.web.api import IAuthenticator 22 24 from trac.web.main import IRequestHandler, IRequestFilter 25 from trac.web import chrome 23 26 from trac.web.chrome import INavigationContributor, ITemplateProvider 24 27 from genshi.builder import tag 25 28 26 29 from api import AccountManager 30 from acct_mgr.util import urandom 27 31 28 32 def _create_user(req, env, check_permissions=True): … … 79 83 80 84 81 class PasswordResetNotification(NotifyEmail): 82 template_name = 'reset_password_email.txt' 85 class SingleUserNofification(NotifyEmail): 86 """Helper class used for account email notifications which should only be 87 sent to one persion, not including the rest of the normally CCed users 88 """ 83 89 _username = None 84 90 … … 95 101 return None 96 102 97 def notify(self, username, password):103 def notify(self, username, subject): 98 104 # save the username for use in `get_smtp_address` 99 105 self._username = username 106 old_public_cc = self.config.getbool('notification', 'use_public_cc') 107 # override public cc option so that the user's email is included in the To: field 108 self.config.set('notification', 'use_public_cc', 'true') 109 try: 110 NotifyEmail.notify(self, username, subject) 111 finally: 112 self.config.set('notification', 'use_public_cc', old_public_cc) 113 114 115 class PasswordResetNotification(SingleUserNofification): 116 template_name = 'reset_password_email.txt' 117 118 def notify(self, username, password): 100 119 self.data.update({ 101 120 'account': { … … 111 130 subject = '[%s] Trac password reset for user: %s' % (projname, username) 112 131 113 NotifyEmail.notify(self, username, subject)132 SingleUserNofification.notify(self, username, subject) 114 133 115 134 … … 453 472 return [resource_filename(__name__, 'templates')] 454 473 474 475 class MessageWrapper(object): 476 """Wrapper for add_warning and add_notice to work around the requirement 477 for a % operator.""" 478 def __init__(self, body): 479 self.body = body 480 481 def __mod__(self, rhs): 482 return self.body 483 484 485 class EmailVerificationNotification(SingleUserNofification): 486 template_name = 'verify_email.txt' 487 488 def notify(self, username, token): 489 self.data.update({ 490 'account': { 491 'username': username, 492 'token': token, 493 }, 494 'verify': { 495 'link': self.env.abs_href.verify_email(token=token), 496 } 497 }) 498 499 projname = self.config.get('project', 'name') 500 subject = '[%s] Trac email verification for user: %s' % (projname, username) 501 502 SingleUserNofification.notify(self, username, subject) 503 504 505 class EmailVerificationModule(Component): 506 implements(IRequestFilter, IRequestHandler) 507 508 # IRequestFilter methods 509 510 def pre_process_request(self, req, handler): 511 if handler is not self and 'email_verification_token' in req.session: 512 chrome.add_warning(req, MessageWrapper(tag.span( 513 'Your permissions have been limited until you ', 514 tag.a(href=req.href.verify_email())( 515 'verify your email address')))) 516 req.perm = perm.PermissionCache(self.env, 'anonymous') 517 return handler 518 519 def post_process_request(self, req, template, data, content_type): 520 if req.session.get('email') != req.session.get('email_verification_sent_to'): 521 req.session['email_verification_token'] = self._gen_token() 522 req.session['email_verification_sent_to'] = req.session.get('email') 523 self._send_email(req) 524 chrome.add_notice(req, MessageWrapper(tag.span( 525 'An email has been sent to ', req.session['email'], 526 ' with a token to ', 527 tag.a(href=req.href.verify_email())( 528 'verify your new email address')))) 529 return template, data, content_type 530 531 # IRequestHandler methods 532 533 def match_request(self, req): 534 return req.path_info == '/verify_email' 535 536 def process_request(self, req): 537 if 'email_verification_token' not in req.session: 538 chrome.add_notice(req, 'Your email is already verified') 539 elif req.method != 'POST': 540 pass 541 elif 'resend' in req.args: 542 self._send_email(req) 543 chrome.add_notice(req, 544 'A notification email has been resent to %s.', 545 req.session.get('email')) 546 elif 'verify' in req.args: 547 if req.args['token'] == req.session['email_verification_token']: 548 del req.session['email_verification_token'] 549 chrome.add_notice(req, 'Thank you for verifying your email address') 550 else: 551 chrome.add_warning(req, 'Invalid verification token') 552 data = {} 553 if 'token' in req.args: 554 data['token'] = req.args['token'] 555 return 'verify_email.html', data, None 556 557 def _gen_token(self): 558 return base64.urlsafe_b64encode(urandom(6)) 559 560 def _send_email(self, req): 561 notifier = EmailVerificationNotification(self.env) 562 notifier.notify(req.authname, req.session['email_verification_token'])
