Projet

Général

Profil

0001-templatetags-add-tags-for-token-generation-validatio.patch

Benjamin Dauvergne, 12 mars 2019 07:53

Télécharger (4,61 ko)

Voir les différences:

Subject: [PATCH] templatetags: add tags for token generation/validation
 (#31268)

- add {% token_decimal n %} -> n digits random token
- add {% token_alphanum n %} -> n digits/uppercase-letters (without
  0,1,I and O) random token
- add {% token_decimal/alphanum n seed1 .. seedn %} -> generate token
  based on hash of concatenation of seed1 .. seedn
- token1|token_check:token2 -> verify token1 is equal to token2
  insensitive to case and prefix/suffix spaces.
 tests/test_templates.py           | 40 +++++++++++++++++++++++++++++++
 wcs/qommon/templatetags/qommon.py | 32 +++++++++++++++++++++++++
 2 files changed, 72 insertions(+)
tests/test_templates.py
1 1
# -*- coding: utf-8 -*-
2 2

  
3
import random
3 4
import datetime
4 5
import pytest
6
import string
5 7

  
6 8
from quixote import cleanup
7 9
from qommon.template import Template, TemplateError
......
432 434
    assert tmpl.render({'value': 'not a number'}) == '0'
433 435
    assert tmpl.render({'value': ''}) == '0'
434 436
    assert tmpl.render({'value': None}) == '0'
437

  
438

  
439
def test_token_decimal():
440
    tokens = [Template('{% token_decimal 4 %}').render() for i in range(100)]
441
    assert all(len(token) == 4 for token in tokens)
442
    assert all(token.isdigit() for token in tokens)
443
    # check randomness, i.e. duplicates are rare
444
    assert len(set(tokens)) > 70
445

  
446

  
447
def test_token_alphanum():
448
    tokens = [Template('{% token_alphanum 4 %}').render() for i in range(100)]
449
    assert all(len(token) == 4 for token in tokens)
450
    assert all(token.upper() == token for token in tokens)
451
    assert all(token.isalnum() for token in tokens)
452
    # check randomness, i.e. duplicates are rare
453
    assert len(set(tokens)) > 90
454
    # check there are letters and digits
455
    assert any(set(token) & set(string.ascii_uppercase) for token in tokens)
456
    assert any(set(token) & set(string.digits) for token in tokens)
457
    # no look-alike characters
458
    assert not any(set(token) & set('01IiOo') for token in tokens)
459

  
460

  
461
def test_token_alphanum_with_seed():
462
    tokens1 = [Template('{% token_alphanum 4 seed1 seed2 %}').render({'seed1': i, 'seed2': i + 1}) for i in range(100)]
463
    tokens2 = [Template('{% token_alphanum 4 seed1 seed2 %}').render({'seed1': i, 'seed2': i + 1}) for i in range(100)]
464
    assert all(len(token) == 4 for token in tokens1)
465
    assert all(token.upper() == token for token in tokens1)
466
    assert all(token.isalnum() for token in tokens1)
467
    assert all(len(token) == 4 for token in tokens2)
468
    assert all(token.upper() == token for token in tokens2)
469
    assert all(token.isalnum() for token in tokens2)
470
    assert tokens1 == tokens2
471
    # token_check is case insensitive
472
    t = Template('{% if token1|token_check:token2 %}ok{% endif %}')
473
    for token1, token2 in zip(tokens1, tokens2):
474
        assert t.render({'token1': token1 + ' ', 'token2': token2.lower()}) == 'ok'
wcs/qommon/templatetags/qommon.py
19 19
from decimal import InvalidOperation as DecimalInvalidOperation
20 20
from decimal import DivisionByZero as DecimalDivisionByZero
21 21
import math
22
import string
23
import hashlib
24
import random
22 25

  
23 26
from django import template
24 27
from django.template import defaultfilters
......
265 268
@register.filter(name='abs')
266 269
def abs_(value):
267 270
    return decimal(abs(parse_decimal(value)))
271

  
272

  
273
def generate_token(alphabet, length, *seeds):
274
    if length > 100:
275
        return 'ERROR**TOKEN TOO LONG'
276
    if not seeds:
277
        choices = [random.SystemRandom().randrange(len(alphabet)) for i in range(length)]
278
    else:
279
        choices = []
280
        seed = ''.join(map(str, seeds))
281
        for i in range(length):
282
            seed = hashlib.sha256(seed).hexdigest()
283
            choices.append(int(seed, 16) % len(alphabet))
284
    return ''.join([alphabet[choice] for choice in choices])
285

  
286

  
287
@register.simple_tag
288
def token_decimal(length, *seeds):
289
    return generate_token(string.digits, length, *seeds)
290

  
291

  
292
@register.simple_tag
293
def token_alphanum(length, *seeds):
294
    return generate_token('23456789ABCDEFGHJKLMNPQRSTUVW', length, *seeds)
295

  
296

  
297
@register.filter
298
def token_check(token1, token2):
299
    return token1.strip().upper() == token2.strip().upper()
268
-