Ticket #4034: numcaptcha2.patch
| File numcaptcha2.patch, 7.3 KB (added by sergeych <sergeych@…>, 6 years ago) |
|---|
-
templates/settings.html
15 15 <div id="content" class="settings"> 16 16 17 17 <h1>Settings and Session Management</h1> 18 19 <p class="error" py:if="settings.session.capmode == 'error'"> 20 Invalid answer to the test question, sorry. Please, try again. 21 </p> 18 22 19 23 <h2>User Settings</h2> 20 24 <p>This page lets you customize your personal settings for this site. … … 94 98 </div> 95 99 </fieldset> 96 100 97 <div class="buttons"> 101 <fieldset py:if="settings.session.capmode"> 102 <legend>Accept changes</legend> 103 <p class="hint">By answering this question you confirm that you are a human 104 being as this page is not serving bots. This is one time operation; 105 sorry for inconvenience.</p> 106 <div class="field"> 107 <label>How many is ${question}? 108 <input type="text" name="answer" size="16" /> 109 </label> 110 </div> 111 <div class="buttons"> 112 <input type="hidden" name="action" value="save" /> 113 <input type="submit" value="Submit changes" /> 114 </div> 115 </fieldset> 116 117 <div class="buttons" py:if="not settings.session.capmode"> 98 118 <input type="hidden" name="action" value="save" /> 99 119 <input type="submit" value="Submit changes" /> 100 </div > 120 </div> 121 101 122 </form> 102 123 103 124 <py:if test="settings.session_id"> -
trac/Settings.py
21 21 from trac.util.datefmt import all_timezones, utc 22 22 from trac.web import IRequestHandler 23 23 from trac.web.chrome import INavigationContributor 24 from trac.util.numcaptcha import numCaptchaQuestion 24 25 25 26 26 class SettingsModule(Component): 27 27 28 28 implements(INavigationContributor, IRequestHandler) … … 45 45 46 46 def process_request(self, req): 47 47 action = req.args.get('action') 48 48 49 question = None 49 50 if req.method == 'POST': 50 51 if action == 'save': 51 52 self._do_save(req) 52 53 elif action == 'load': 53 54 self._do_load(req) 55 else: 56 # Get: consider whether to use captcha 57 if (req.session.has_key('name') and req.session['name']) or \ 58 (req.session.has_key('email') and req.session['email']): 59 capmode = req.session['capmode'] = None 60 else: 61 # Ask captcha question 62 question, req.session['capanswer'] = numCaptchaQuestion() 63 if not 'capmode' in req.session: 64 if req.session['capmode'] != 'error': 65 req.session['capmode'] = 'check' 54 66 55 67 data = {'session': req.session} 56 68 if req.authname == 'anonymous': 57 69 data['session_id'] = req.session.sid 58 59 return 'settings.html', {'settings': data, 70 71 return 'settings.html', {'settings': data, 'question':question, 60 72 'timezones': all_timezones}, None 61 73 62 74 # Internal methods 63 75 64 76 def _do_save(self, req): 65 for field in self._form_fields: 66 val = req.args.get(field) 67 if val: 68 if field == 'tz' and 'tz' in req.session and \ 69 val not in all_timezones: 70 del req.session['tz'] 71 elif field == 'newsid' and val: 72 req.session.change_sid(val) 73 else: 74 req.session[field] = val 75 elif field in req.session: 76 del req.session[field] 77 self.error = req.session['capmode'] > 0 and req.session['capanswer'] != req.args.get('answer') 78 if self.error: 79 req.session['capmode'] = 'error' 80 else: 81 req.session['capmode'] = 'check' 82 for field in self._form_fields: 83 val = req.args.get(field) 84 if val: 85 if field == 'tz' and 'tz' in req.session and \ 86 val not in all_timezones: 87 del req.session['tz'] 88 elif field == 'newsid' and val: 89 req.session.change_sid(val) 90 else: 91 req.session[field] = val 92 elif field in req.session: 93 del req.session[field] 77 94 req.redirect(req.href.settings()) 78 95 79 96 def _do_load(self, req): -
trac/util/numcaptcha.py
1 # 2 # Arithmetic captcha, English only 3 # 4 # The idea is to generate some expression 5 # like 5 * 7 or 3 * 11 + 2 and translate it 6 # to the text form 7 8 import re 9 10 _numerals = ( 'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 11 'eight', 'nine', 'ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 12 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen' ) 13 14 _tens = ( 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety' ) 15 16 # small positive numeral 0-99 17 def numeral(number): 18 number = int(number) 19 if number < 20: 20 return _numerals[number] 21 import math 22 t, r = (number / 10) - 2, number % 10 23 if r: 24 return _tens[ t ] + '-' + _numerals[ r ] 25 return _tens[t] 26 27 # basic operations 28 def operation(opchar): 29 if opchar == '+': 30 return 'plus' 31 elif opchar == '-': 32 return 'minus' 33 elif opchar == '*': 34 return 'multiplied by' 35 elif opchar == '/': 36 return 'divided by' 37 raise NotImplementedError( 'Operation '+opchar+' is not supported' ) 38 39 # numeral or operation 40 def term( op_or_number ): 41 try: 42 return operation(op_or_number) 43 except NotImplementedError: 44 return numeral(op_or_number) 45 46 # formulae parsing re 47 _re_formulae = re.compile( '([0-9]+|[+\-*/])' ) 48 49 # translate simple formulae to English 50 def say( formulae ): 51 parts = re.findall( _re_formulae, formulae ) 52 return ' '.join( [ term(x) for x in parts ] ) 53 54 from random import randint 55 56 # Get numeric captcha question as English phrase and result as str 57 def numCaptchaQuestion(): 58 expr, res = numCaptchaExpr() 59 return say(expr), str(res) 60 61 # Build numeric captcha expression as formulae return it and result as int 62 def numCaptchaExpr(): 63 64 total = randint(7,49) 65 m1 = randint( 2, total/2 ) 66 m2 = total / m1 67 rem = total - m1*m2 68 if rem: 69 return '%d * %d + %d' % (m1, m2, rem), total 70 return '%d * %d' % (m1, m2), total 71 72 if __name__ == '__main__': 73 74 # parts of tests 75 76 def _test_buildNumExpr(): 77 print 'Testing buildNumExpr' 78 for cnt in xrange(100000): 79 ex, res = numCaptchaExpr() 80 if eval(ex) != res: 81 print 'Error: %s is %d not %d!' % (ex, eval(ex), res) 82 return False 83 print 'BuildNumExpr test passed' 84 return True 85 86 _test_buildNumExpr()
