mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
31f54065f5
Summary: Using the `random` module in the Grist `UUID()` function is not cryptographically secure, and is only necessary for the old pynbox (Python 2) sandbox which doesn't support `os.urandom`. This diff uses the `uuid.uuidv4()` function from the Python standard library when possible, which is more secure, only falling back to the old implementation when necessary. Test Plan: Added Python unit tests to check both implementations. Reviewers: dsagal Subscribers: paulfitz, dsagal Differential Revision: https://phab.getgrist.com/D3578
83 lines
2.9 KiB
Python
83 lines
2.9 KiB
Python
import doctest
|
|
import os
|
|
import random
|
|
import re
|
|
import unittest
|
|
|
|
import six
|
|
|
|
import functions
|
|
import moment
|
|
|
|
_old_date_get_global_tz = None
|
|
|
|
def date_setUp(doc_test):
|
|
# pylint: disable=unused-argument
|
|
global _old_date_get_global_tz # pylint: disable=global-statement
|
|
_old_date_get_global_tz = functions.date._get_global_tz
|
|
functions.date._get_global_tz = lambda: moment.tzinfo('America/New_York')
|
|
|
|
def date_tearDown(doc_test):
|
|
# pylint: disable=unused-argument
|
|
functions.date._get_global_tz = _old_date_get_global_tz
|
|
|
|
class Py23DocChecker(doctest.OutputChecker):
|
|
def check_output(self, want, got, optionflags):
|
|
if six.PY3:
|
|
want = re.sub(r"^u'(.*?)'$", r"'\1'", want)
|
|
want = re.sub(r'^u"(.*?)"$', r'"\1"', want)
|
|
return doctest.OutputChecker.check_output(self, want, got, optionflags)
|
|
|
|
# This works with the unittest module to turn all the doctests in the functions' doc-comments into
|
|
# unittest test cases.
|
|
def load_tests(loader, tests, ignore):
|
|
# Set DOC_URL for SELF_HYPERLINK()
|
|
os.environ['DOC_URL'] = 'https://docs.getgrist.com/sbaltsirg/Example'
|
|
tests.addTests(doctest.DocTestSuite(functions.date, setUp = date_setUp, tearDown = date_tearDown))
|
|
tests.addTests(doctest.DocTestSuite(functions.info, setUp = date_setUp, tearDown = date_tearDown))
|
|
tests.addTests(doctest.DocTestSuite(functions.logical))
|
|
tests.addTests(doctest.DocTestSuite(functions.math))
|
|
tests.addTests(doctest.DocTestSuite(functions.stats))
|
|
tests.addTests(doctest.DocTestSuite(functions.text, checker=Py23DocChecker()))
|
|
tests.addTests(doctest.DocTestSuite(functions.schedule,
|
|
setUp = date_setUp, tearDown = date_tearDown))
|
|
tests.addTests(doctest.DocTestSuite(functions.lookup, checker=Py23DocChecker()))
|
|
return tests
|
|
|
|
|
|
class TestUuid(unittest.TestCase):
|
|
def check_uuids(self, expected_unique):
|
|
uuids = set()
|
|
for _ in range(100):
|
|
random.seed(0) # should make only 'fallback' UUIDs all the same
|
|
uuids.add(functions.UUID())
|
|
|
|
self.assertEqual(len(uuids), expected_unique)
|
|
for uid in uuids:
|
|
match = re.match(r'^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$', uid)
|
|
self.assertIsNotNone(match, uid)
|
|
|
|
def test_standard_uuid(self):
|
|
# Test that uuid.uuid4() is used correctly.
|
|
# uuid.uuid4() shouldn't be affected by random.seed().
|
|
# Depending on the test environment, uuid.uuid4() may or may not actually be available.
|
|
try:
|
|
os.urandom(1)
|
|
except NotImplementedError:
|
|
expected_unique = 1
|
|
else:
|
|
expected_unique = 100
|
|
|
|
self.check_uuids(expected_unique)
|
|
|
|
def test_fallback_uuid(self):
|
|
# Test that our custom implementation with the `random` module works
|
|
# and is used when uuid.uuid4() is not available.
|
|
import uuid
|
|
v4 = uuid.uuid4
|
|
del uuid.uuid4
|
|
try:
|
|
self.check_uuids(1) # because of the `random.seed(0)` in `check_uuids()`
|
|
finally:
|
|
uuid.uuid4 = v4
|