Projet

Général

Profil

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

Benjamin Dauvergne, 04 avril 2019 18:04

Télécharger (4,07 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 | 30 ++++++++++++++++++++++++++++++
 2 files changed, 58 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
    return ''.join([r.choice(alphabet) for i in range(length)])
276

  
277

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

  
285

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

  
294

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