From 6a975a587561f6b3d3263b90f912364052d8233f Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Mon, 11 Mar 2019 14:41:08 +0100 Subject: [PATCH] templatetags: add tags for token generation/validation (#31268) --- tests/test_templates.py | 40 +++++++++++++++++++++++++++++++ wcs/qommon/templatetags/qommon.py | 37 ++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/tests/test_templates.py b/tests/test_templates.py index cae7e9fe..e06d24b5 100644 --- a/tests/test_templates.py +++ b/tests/test_templates.py @@ -1,7 +1,9 @@ # -*- coding: utf-8 -*- +import random import datetime import pytest +import string from quixote import cleanup from qommon.template import Template, TemplateError @@ -432,3 +434,41 @@ 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 + + +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) + + +def test_token_alphanum_with_seed(): + tokens1 = [Template('{% token_alphanum 4 seed1 seed2 %}').render({'seed1': i, 'seed2': i + 1}) for i in range(100)] + tokens2 = [Template('{% token_alphanum 4 seed1 seed2 %}').render({'seed1': i, 'seed2': i + 1}) for i in range(100)] + assert all(len(token) == 4 for token in tokens1) + assert all(token.upper() == token for token in tokens1) + assert all(token.isalnum() for token in tokens1) + assert all(len(token) == 4 for token in tokens2) + assert all(token.upper() == token for token in tokens2) + assert all(token.isalnum() for token in tokens2) + assert tokens1 == tokens2 + # token_check is case insensitive + t = Template('{% if token1|token_check:token2 %}ok{% endif %}') + for token1, token2 in zip(tokens1, tokens2): + assert t.render({'token1': token1, 'token2': token2.lower()}) == 'ok' diff --git a/wcs/qommon/templatetags/qommon.py b/wcs/qommon/templatetags/qommon.py index 81606a74..f7a43aa3 100644 --- a/wcs/qommon/templatetags/qommon.py +++ b/wcs/qommon/templatetags/qommon.py @@ -19,6 +19,9 @@ from decimal import Decimal from decimal import InvalidOperation as DecimalInvalidOperation from decimal import DivisionByZero as DecimalDivisionByZero import math +import string +import hashlib +import random from django import template from django.template import defaultfilters @@ -265,3 +268,37 @@ def floor(value): @register.filter(name='abs') def abs_(value): return decimal(abs(parse_decimal(value))) + +@register.simple_tag +def standard_text(text_id): + return mark_safe(TextsDirectory.get_html_text(str(text_id))) + + +def generate_token(alphabet, length, *seeds): + if length > 100: + return 'ERROR**TOKEN TOO LONG' + if not seeds: + choices = [random.SystemRandom().randrange(len(alphabet)) for i in range(length)] + else: + choices = [] + seed = ''.join(map(str, seeds)) + for i in range(length): + seed = hashlib.sha256(seed).hexdigest() + choices.append(int(seed, 16) % len(alphabet)) + return ''.join([alphabet[choice] for choice in choices]) + + +@register.simple_tag +def token_decimal(length, *seeds): + return generate_token(string.digits, length, *seeds) + + +@register.simple_tag +def token_alphanum(length, *seeds): + return generate_token('23456789ABCDEFGHJKLMNPQRSTUVW', length, *seeds) + + +@register.filter +def token_check(token1, token2): + return token1.upper() == token2.upper() + -- 2.20.1