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.
This commit is contained in:
parent
51df06ed9d
commit
bbeb4033ba
|
@ -2,6 +2,7 @@
|
|||
|
||||
import datetime
|
||||
import pytest
|
||||
import string
|
||||
|
||||
from quixote import cleanup
|
||||
from qommon.template import Template, TemplateError
|
||||
|
@ -432,3 +433,29 @@ def test_abs_templatetag():
|
|||
assert tmpl.render({'value': 'not a number'}) == '0'
|
||||
assert tmpl.render({'value': ''}) == '0'
|
||||
assert tmpl.render({'value': None}) == '0'
|
||||
|
||||
|
||||
def test_token_decimal():
|
||||
tokens = [Template('{% token_decimal 4 %}').render() for i in range(100)]
|
||||
assert all(len(token) == 4 for token in tokens)
|
||||
assert all(token.isdigit() for token in tokens)
|
||||
# check randomness, i.e. duplicates are rare
|
||||
assert len(set(tokens)) > 70
|
||||
t = Template('{% if token1|token_check:token2 %}ok{% endif %}')
|
||||
assert t.render({'token1': tokens[0] + ' ', 'token2': tokens[0].lower()}) == 'ok'
|
||||
|
||||
|
||||
def test_token_alphanum():
|
||||
tokens = [Template('{% token_alphanum 4 %}').render() for i in range(100)]
|
||||
assert all(len(token) == 4 for token in tokens)
|
||||
assert all(token.upper() == token for token in tokens)
|
||||
assert all(token.isalnum() for token in tokens)
|
||||
# check randomness, i.e. duplicates are rare
|
||||
assert len(set(tokens)) > 90
|
||||
# check there are letters and digits
|
||||
assert any(set(token) & set(string.ascii_uppercase) for token in tokens)
|
||||
assert any(set(token) & set(string.digits) for token in tokens)
|
||||
# no look-alike characters
|
||||
assert not any(set(token) & set('01IiOo') for token in tokens)
|
||||
t = Template('{% if token1|token_check:token2 %}ok{% endif %}')
|
||||
assert t.render({'token1': tokens[0] + ' ', 'token2': tokens[0].lower()}) == 'ok'
|
||||
|
|
|
@ -20,6 +20,8 @@ from decimal import InvalidOperation as DecimalInvalidOperation
|
|||
from decimal import DivisionByZero as DecimalDivisionByZero
|
||||
import hashlib
|
||||
import math
|
||||
import string
|
||||
import random
|
||||
|
||||
from django import template
|
||||
from django.template import defaultfilters
|
||||
|
@ -271,3 +273,30 @@ def abs_(value):
|
|||
def version_hash():
|
||||
from wcs.qommon.admin.menu import get_vc_version
|
||||
return hashlib.md5(str(get_vc_version())).hexdigest()
|
||||
|
||||
|
||||
def generate_token(alphabet, length):
|
||||
r = random.SystemRandom()
|
||||
return ''.join([r.choice(alphabet) for i in range(length)])
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def token_decimal(length=6):
|
||||
# entropy by default is log(10^6)/log(2) = 19.93 bits
|
||||
# decimal always need more length than alphanum for the same security level
|
||||
# for 128bits security level, length must be more than log(2^128)/log(10) = 38.53 digits
|
||||
return generate_token(string.digits, length)
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def token_alphanum(length=4):
|
||||
# use of a 28 characters alphabet using uppercase letters and digits but
|
||||
# removing confusing characters and digits 0, O, 1 and I.
|
||||
# entropy by default is log(28^4)/log(2) = 19.22 bits
|
||||
# for 128 bits security level length must be more than log(2^128)/log(28) = 26.62 characters
|
||||
return generate_token('23456789ABCDEFGHJKLMNPQRSTUVWXYZ', length)
|
||||
|
||||
|
||||
@register.filter
|
||||
def token_check(token1, token2):
|
||||
return token1.strip().upper() == token2.strip().upper()
|
||||
|
|
Loading…
Reference in New Issue