Projet

Général

Profil

0002-templatetags-add-token-generation-with-seeds-31268.patch

Benjamin Dauvergne, 12 mars 2019 10:57

Télécharger (3,47 ko)

Voir les différences:

Subject: [PATCH 2/2] templatetags: add token generation with seeds (#31268)

- add {% token_decimal/alphanum n seed1 .. seedn %} -> generate token
  based on hash of concatenation of seed1 .. seedn
- using a form linked information (like "form_number") as seed you can
  generate deterministic unique token for a formdata, removing the need to
  store the token in a backoffice field of the formdef.
 tests/test_templates.py           | 16 ++++++++++++++++
 wcs/qommon/templatetags/qommon.py | 19 +++++++++++++------
 2 files changed, 29 insertions(+), 6 deletions(-)
tests/test_templates.py
460 460
    assert not any(set(token) & set('01IiOo') for token in tokens)
461 461
    t = Template('{% if token1|token_check:token2 %}ok{% endif %}')
462 462
    assert t.render({'token1': tokens[0] + ' ', 'token2': tokens[0].lower()}) == 'ok'
463

  
464

  
465
def test_token_alphanum_with_seed():
466
    tokens1 = [Template('{% token_alphanum 4 seed1 seed2 %}').render({'seed1': i, 'seed2': i + 1}) for i in range(100)]
467
    tokens2 = [Template('{% token_alphanum 4 seed1 seed2 %}').render({'seed1': i, 'seed2': i + 1}) for i in range(100)]
468
    assert all(len(token) == 4 for token in tokens1)
469
    assert all(token.upper() == token for token in tokens1)
470
    assert all(token.isalnum() for token in tokens1)
471
    assert all(len(token) == 4 for token in tokens2)
472
    assert all(token.upper() == token for token in tokens2)
473
    assert all(token.isalnum() for token in tokens2)
474
    assert tokens1 == tokens2
475
    # token_check is case insensitive
476
    t = Template('{% if token1|token_check:token2 %}ok{% endif %}')
477
    for token1, token2 in zip(tokens1, tokens2):
478
        assert t.render({'token1': token1 + ' ', 'token2': token2.lower()}) == 'ok'
wcs/qommon/templatetags/qommon.py
270 270
    return decimal(abs(parse_decimal(value)))
271 271

  
272 272

  
273
def generate_token(alphabet, length):
273
def generate_token(alphabet, length, *seeds):
274 274
    # 128bits security is enough; for alphanum, 128 / log(32) = 36.9...
275 275
    if length > 37:
276 276
        raise ValueError('token_decimal/alphanum: length cannot be more than 37')
277
    choices = [random.SystemRandom().randrange(len(alphabet)) for i in range(length)]
277
    if seeds:
278
        choices = []
279
        seed = ''.join(map(str, seeds))
280
        for i in range(length):
281
            seed = hashlib.sha256(seed).hexdigest()
282
            choices.append(int(seed, 16) % len(alphabet))
283
    else:
284
        choices = [random.SystemRandom().randrange(len(alphabet)) for i in range(length)]
278 285
    return ''.join([alphabet[choice] for choice in choices])
279 286

  
280 287

  
281 288
@register.simple_tag
282
def token_decimal(length):
283
    return generate_token(string.digits, length)
289
def token_decimal(length, *seeds):
290
    return generate_token(string.digits, length, *seeds)
284 291

  
285 292

  
286 293
@register.simple_tag
287
def token_alphanum(length):
288
    return generate_token('23456789ABCDEFGHJKLMNPQRSTUVWXYZ', length)
294
def token_alphanum(length, *seeds):
295
    return generate_token('23456789ABCDEFGHJKLMNPQRSTUVWXYZ', length, *seeds)
289 296

  
290 297

  
291 298
@register.filter
292
-