Mercurial > p > roundup > code
comparison roundup/cgi/templating.py @ 5488:52cb53eedf77
reworked random number use
prefer secrets module from Python 3.6+, random.SystemRandom and finally plain random
| author | Christof Meerwald <cmeerw@cmeerw.org> |
|---|---|
| date | Sat, 04 Aug 2018 22:40:16 +0100 |
| parents | b0359a7c5b6d |
| children | 6b0c542642be |
comparison
equal
deleted
inserted
replaced
| 5487:ce171c81d823 | 5488:52cb53eedf77 |
|---|---|
| 18 """ | 18 """ |
| 19 | 19 |
| 20 __docformat__ = 'restructuredtext' | 20 __docformat__ = 'restructuredtext' |
| 21 | 21 |
| 22 | 22 |
| 23 import cgi, re, os.path, mimetypes, csv, string | 23 import base64, cgi, re, os.path, mimetypes, csv, string |
| 24 import calendar | 24 import calendar |
| 25 import textwrap | 25 import textwrap |
| 26 import time, hashlib | 26 import time, hashlib |
| 27 | 27 |
| 28 from roundup.anypy import urllib_ | 28 from roundup.anypy import urllib_ |
| 29 from roundup import hyperdb, date, support | 29 from roundup import hyperdb, date, support |
| 30 from roundup import i18n | 30 from roundup import i18n |
| 31 from roundup.i18n import _ | 31 from roundup.i18n import _ |
| 32 from roundup.anypy.strings import is_us, s2b, us2s, s2u, u2s, StringIO | 32 from roundup.anypy.strings import is_us, b2s, s2b, us2s, s2u, u2s, StringIO |
| 33 | 33 |
| 34 from .KeywordsExpr import render_keywords_expression_editor | 34 from .KeywordsExpr import render_keywords_expression_editor |
| 35 | 35 |
| 36 try: | 36 import roundup.anypy.random_ as random_ |
| 37 # Use the cryptographic source of randomness if available | |
| 38 from random import SystemRandom | |
| 39 random=SystemRandom() | |
| 40 except ImportError: | |
| 41 from random import random | |
| 42 try: | 37 try: |
| 43 import cPickle as pickle | 38 import cPickle as pickle |
| 44 except ImportError: | 39 except ImportError: |
| 45 import pickle | 40 import pickle |
| 46 try: | 41 try: |
| 66 # this global translation service is not thread-safe. | 61 # this global translation service is not thread-safe. |
| 67 # it is left here for backward compatibility | 62 # it is left here for backward compatibility |
| 68 # until all Web UI translations are done via client.translator object | 63 # until all Web UI translations are done via client.translator object |
| 69 translationService = TranslationService.get_translation() | 64 translationService = TranslationService.get_translation() |
| 70 | 65 |
| 71 def anti_csrf_nonce(self, client, lifetime=None): | 66 def anti_csrf_nonce(client, lifetime=None): |
| 72 ''' Create a nonce for defending against CSRF attack. | 67 ''' Create a nonce for defending against CSRF attack. |
| 73 | |
| 74 This creates a nonce by hex encoding the sha256 of | |
| 75 random.random(), the address of the object requesting | |
| 76 the nonce and time.time(). | |
| 77 | 68 |
| 78 Then it stores the nonce, the session id for the user | 69 Then it stores the nonce, the session id for the user |
| 79 and the user id in the one time key database for use | 70 and the user id in the one time key database for use |
| 80 by the csrf validator that runs in the client::inner_main | 71 by the csrf validator that runs in the client::inner_main |
| 81 module/function. | 72 module/function. |
| 82 ''' | 73 ''' |
| 83 otks=client.db.getOTKManager() | 74 otks=client.db.getOTKManager() |
| 84 # include id(self) as the exact location of self (including address) | 75 key = b2s(base64.b32encode(random_.token_bytes(40))) |
| 85 # is unpredicatable (depends on number of previous connections etc.) | |
| 86 key = '%s%s%s'%(random.random(),id(self),time.time()) | |
| 87 key = hashlib.sha256(s2b(key)).hexdigest() | |
| 88 | 76 |
| 89 while otks.exists(key): | 77 while otks.exists(key): |
| 90 key = '%s%s%s'%(random.random(),id(self),time.time()) | 78 key = b2s(base64.b32encode(random_.token_bytes(40))) |
| 91 key = hashlib.sha256(s2b(key)).hexdigest() | |
| 92 | 79 |
| 93 # lifetime is in minutes. | 80 # lifetime is in minutes. |
| 94 if lifetime is None: | 81 if lifetime is None: |
| 95 lifetime = client.db.config['WEB_CSRF_TOKEN_LIFETIME'] | 82 lifetime = client.db.config['WEB_CSRF_TOKEN_LIFETIME'] |
| 96 | 83 |
| 782 """ | 769 """ |
| 783 if not self.is_edit_ok(): | 770 if not self.is_edit_ok(): |
| 784 return '' | 771 return '' |
| 785 | 772 |
| 786 return self.input(type="hidden", name="@csrf", | 773 return self.input(type="hidden", name="@csrf", |
| 787 value=anti_csrf_nonce(self, self._client)) + \ | 774 value=anti_csrf_nonce(self._client)) + \ |
| 788 '\n' + \ | 775 '\n' + \ |
| 789 self.input(type="hidden", name="@action", value=action) + \ | 776 self.input(type="hidden", name="@action", value=action) + \ |
| 790 '\n' + \ | 777 '\n' + \ |
| 791 self.input(type="submit", name="submit_button", value=self._(label)) | 778 self.input(type="submit", name="submit_button", value=self._(label)) |
| 792 | 779 |
| 925 """ | 912 """ |
| 926 return self.input(type="hidden", name="@lastactivity", | 913 return self.input(type="hidden", name="@lastactivity", |
| 927 value=self.activity.local(0)) + \ | 914 value=self.activity.local(0)) + \ |
| 928 '\n' + \ | 915 '\n' + \ |
| 929 self.input(type="hidden", name="@csrf", | 916 self.input(type="hidden", name="@csrf", |
| 930 value=anti_csrf_nonce(self, self._client)) + \ | 917 value=anti_csrf_nonce(self._client)) + \ |
| 931 '\n' + \ | 918 '\n' + \ |
| 932 self.input(type="hidden", name="@action", value=action) + \ | 919 self.input(type="hidden", name="@action", value=action) + \ |
| 933 '\n' + \ | 920 '\n' + \ |
| 934 self.input(type="submit", name="submit_button", | 921 self.input(type="submit", name="submit_button", |
| 935 value=self._(label)) | 922 value=self._(label)) |
| 3080 def Batch(self, sequence, size, start, end=0, orphan=0, overlap=0): | 3067 def Batch(self, sequence, size, start, end=0, orphan=0, overlap=0): |
| 3081 return Batch(self.client, sequence, size, start, end, orphan, | 3068 return Batch(self.client, sequence, size, start, end, orphan, |
| 3082 overlap) | 3069 overlap) |
| 3083 | 3070 |
| 3084 def anti_csrf_nonce(self, lifetime=None): | 3071 def anti_csrf_nonce(self, lifetime=None): |
| 3085 return anti_csrf_nonce(self, self.client, lifetime=lifetime) | 3072 return anti_csrf_nonce(self.client, lifetime=lifetime) |
| 3086 | 3073 |
| 3087 def url_quote(self, url): | 3074 def url_quote(self, url): |
| 3088 """URL-quote the supplied text.""" | 3075 """URL-quote the supplied text.""" |
| 3089 return urllib_.quote(url) | 3076 return urllib_.quote(url) |
| 3090 | 3077 |
