Projet

Général

Profil

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

Benjamin Dauvergne, 12 mars 2019 10:57

Télécharger (3,77 ko)

Voir les différences:

Subject: [PATCH 1/2] 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
- token1|token_check:token2 -> verify token1 is equal to token2
  insensitive to case and prefix/suffix spaces.
 tests/test_templates.py           | 28 ++++++++++++++++++++++++++++
 wcs/qommon/templatetags/qommon.py | 26 ++++++++++++++++++++++++++
 2 files changed, 54 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
    t = Template('{% if token1|token_check:token2 %}ok{% endif %}')
446
    assert t.render({'token1': tokens[0] + ' ', 'token2': tokens[0].lower()}) == 'ok'
447

  
448

  
449
def test_token_alphanum():
450
    tokens = [Template('{% token_alphanum 4 %}').render() for i in range(100)]
451
    assert all(len(token) == 4 for token in tokens)
452
    assert all(token.upper() == token for token in tokens)
453
    assert all(token.isalnum() for token in tokens)
454
    # check randomness, i.e. duplicates are rare
455
    assert len(set(tokens)) > 90
456
    # check there are letters and digits
457
    assert any(set(token) & set(string.ascii_uppercase) for token in tokens)
458
    assert any(set(token) & set(string.digits) for token in tokens)
459
    # no look-alike characters
460
    assert not any(set(token) & set('01IiOo') for token in tokens)
461
    t = Template('{% if token1|token_check:token2 %}ok{% endif %}')
462
    assert t.render({'token1': tokens[0] + ' ', 'token2': tokens[0].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):
274
    # 128bits security is enough; for alphanum, 128 / log(32) = 36.9...
275
    if length > 37:
276
        raise ValueError('token_decimal/alphanum: length cannot be more than 37')
277
    choices = [random.SystemRandom().randrange(len(alphabet)) for i in range(length)]
278
    return ''.join([alphabet[choice] for choice in choices])
279

  
280

  
281
@register.simple_tag
282
def token_decimal(length):
283
    return generate_token(string.digits, length)
284

  
285

  
286
@register.simple_tag
287
def token_alphanum(length):
288
    return generate_token('23456789ABCDEFGHJKLMNPQRSTUVWXYZ', length)
289

  
290

  
291
@register.filter
292
def token_check(token1, token2):
293
    return token1.strip().upper() == token2.strip().upper()
268
-