Projet

Général

Profil

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

Benjamin Dauvergne, 04 avril 2019 12:08

Télécharger (4,13 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 | 31 +++++++++++++++++++++++++++++++
 2 files changed, 59 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
    r = random.SystemRandom()
275
    choices = [r.randrange(len(alphabet)) for i in range(length)]
276
    return ''.join([alphabet[choice] for choice in choices])
277

  
278

  
279
@register.simple_tag
280
def token_decimal(length=6):
281
    # entropy by default is log(10^6)/log(2) = 19.93 bits
282
    # decimal always need more length than alphanum for the same security level
283
    # for 128bits security level, length must be more than log(2^128)/log(10) = 38.53 digits
284
    return generate_token(string.digits, length)
285

  
286

  
287
@register.simple_tag
288
def token_alphanum(length=4):
289
    # use of a 28 characters alphabet using uppercase letters and digits but
290
    # removing confusing characters and digits 0, O, 1 and I.
291
    # entropy by default is log(28^4)/log(2) = 19.22 bits
292
    # for 128 bits security level length must be more than log(2^128)/log(28) = 26.62 characters
293
    return generate_token('23456789ABCDEFGHJKLMNPQRSTUVWXYZ', length)
294

  
295

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