Projet

Général

Profil

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

Benjamin Dauvergne, 11 mars 2019 15:13

Télécharger (4,73 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 | 37 ++++++++++++++++++++++++++++
 2 files changed, 77 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
@register.simple_tag
273
def standard_text(text_id):
274
    return mark_safe(TextsDirectory.get_html_text(str(text_id)))
275

  
276

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

  
290

  
291
@register.simple_tag
292
def token_decimal(length, *seeds):
293
    return generate_token(string.digits, length, *seeds)
294

  
295

  
296
@register.simple_tag
297
def token_alphanum(length, *seeds):
298
    return generate_token('23456789ABCDEFGHJKLMNPQRSTUVW', length, *seeds)
299

  
300

  
301
@register.filter
302
def token_check(token1, token2):
303
    return token1.strip().upper() == token2.strip().upper()
304

  
268
-