From 15cc1146566ee1b6acc74b82d562496886c297e6 Mon Sep 17 00:00:00 2001 From: "Nick V. Anokhin" Date: Fri, 10 Jul 2026 15:08:00 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20=D1=81=D0=BB=D1=83=D0=B6=D0=B5=D0=B1=D0=BD=D1=8B=D0=B9?= =?UTF-8?q?=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=20Crypto=20=D0=B8=20=D1=82?= =?UTF-8?q?=D0=B5=D1=81=D1=82=D1=8B=20=D0=BA=20=D0=BD=D0=B5=D0=BC=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- net/xeaf/rack/core/__init__.py | 2 + net/xeaf/rack/core/core_test_case.py | 26 ++++++++ net/xeaf/rack/tests/util/__init__.py | 11 ++++ net/xeaf/rack/tests/util/crypto_tests.py | 81 ++++++++++++++++++++++++ net/xeaf/rack/util/__init__.py | 2 + net/xeaf/rack/util/crypto.py | 51 +++++++++++++++ 6 files changed, 173 insertions(+) create mode 100644 net/xeaf/rack/core/core_test_case.py create mode 100644 net/xeaf/rack/tests/util/__init__.py create mode 100644 net/xeaf/rack/tests/util/crypto_tests.py create mode 100644 net/xeaf/rack/util/crypto.py diff --git a/net/xeaf/rack/core/__init__.py b/net/xeaf/rack/core/__init__.py index 51e7f66..ceee9ef 100644 --- a/net/xeaf/rack/core/__init__.py +++ b/net/xeaf/rack/core/__init__.py @@ -7,3 +7,5 @@ """ Пакет базовых классов """ + +from .core_test_case import CoreTestCase diff --git a/net/xeaf/rack/core/core_test_case.py b/net/xeaf/rack/core/core_test_case.py new file mode 100644 index 0000000..d8c392f --- /dev/null +++ b/net/xeaf/rack/core/core_test_case.py @@ -0,0 +1,26 @@ +# DRF Rack +# Библиотека классов расширений для Django REST Framework +# +# Автор: Николай В. Анохин +# Все права защищены. Лицензия: MIT + +""" +Описание класса CoreTestCase +""" + +from django.test import TestCase + + +class CoreTestCase(TestCase): + """ + Расширяет функции кейса тестирования + """ + + def assertLowerHex(self, value: str): + """ + Проверяет, что строка состоит из символов в нижнем регистре и шестнадцатеричных цифр + + :param value: Проверяемая строка + """ + + self.assertRegex(value, r'^[0-9a-f]+$') diff --git a/net/xeaf/rack/tests/util/__init__.py b/net/xeaf/rack/tests/util/__init__.py new file mode 100644 index 0000000..44dbc4d --- /dev/null +++ b/net/xeaf/rack/tests/util/__init__.py @@ -0,0 +1,11 @@ +# DRF Rack +# Библиотека классов расширений для Django REST Framework +# +# Автор: Николай В. Анохин +# Все права защищены. Лицензия: MIT + +""" +Пакет описания классов тестов для служебных классов и утилит +""" + +from .crypto_tests import CryptoTests \ No newline at end of file diff --git a/net/xeaf/rack/tests/util/crypto_tests.py b/net/xeaf/rack/tests/util/crypto_tests.py new file mode 100644 index 0000000..4a3dc23 --- /dev/null +++ b/net/xeaf/rack/tests/util/crypto_tests.py @@ -0,0 +1,81 @@ +# DRF Rack +# Библиотека классов расширений для Django REST Framework +# +# Автор: Николай В. Анохин +# Все права защищены. Лицензия: MIT + +""" +Описание класса CryptoTests +""" + +from net.xeaf.rack.core import CoreTestCase +from net.xeaf.rack.util import Crypto + + +class CryptoTests(CoreTestCase): + """ + Тесты для Crypto + """ + + def test_gen_token(self): + """ + Тест генерации токена + """ + + token = Crypto.gen_token() + self.assertEqual(len(token), Crypto.DEFAULT_TOKEN_LENGTH) + self.assertLowerHex(token) + + def test_gen_token_length(self): + """ + Тест генерации токена с указанием длины + """ + + token = Crypto.gen_token(length=15) + self.assertEqual(len(token), 15) + + def test_gen_token_different(self): + """ + Тест генерации разных токенов + """ + + token1 = Crypto.gen_token() + token2 = Crypto.gen_token() + self.assertNotEqual(token1, token2) + + def test_gen_pin_code(self): + """ + Тест генерации PIN-кода + """ + + pin_code = Crypto.gen_pin_code() + self.assertEqual(len(pin_code), Crypto.DEFAULT_PIN_CODE_LENGTH) + self.assertTrue(all(c in Crypto.DEFAULT_PIN_CODE_ALPHABET for c in pin_code)) + + def test_gen_pin_code_length(self): + """ + Тест генерации PIN-кода с указанием длины + """ + + pin_code = Crypto.gen_pin_code(length=8) + self.assertEqual(len(pin_code), 8) + self.assertTrue(all(c in Crypto.DEFAULT_PIN_CODE_ALPHABET for c in pin_code)) + + def test_gen_pin_code_alphabet(self): + """ + Тест генерации PIN-кода с указанием алфавита + """ + + letters = 'ABCD' + pin_code = Crypto.gen_pin_code(alphabet=letters) + self.assertEqual(len(pin_code), Crypto.DEFAULT_PIN_CODE_LENGTH) + self.assertTrue(all(c in letters for c in pin_code)) + + def test_gen_pin_code_different(self): + """ + Тест генерации разных PIN-кодов + """ + + pin_code_1 = Crypto.gen_pin_code() + pin_code_2 = Crypto.gen_pin_code() + self.assertNotEqual(pin_code_1, pin_code_2) diff --git a/net/xeaf/rack/util/__init__.py b/net/xeaf/rack/util/__init__.py index b735ee6..6dfa226 100644 --- a/net/xeaf/rack/util/__init__.py +++ b/net/xeaf/rack/util/__init__.py @@ -7,3 +7,5 @@ """ Пакет служебных классов и функций """ + +from .crypto import Crypto diff --git a/net/xeaf/rack/util/crypto.py b/net/xeaf/rack/util/crypto.py new file mode 100644 index 0000000..198f68f --- /dev/null +++ b/net/xeaf/rack/util/crypto.py @@ -0,0 +1,51 @@ +# DRF Rack +# Библиотека классов расширений для Django REST Framework +# +# Автор: Николай В. Анохин +# Все права защищены. Лицензия: MIT + +""" +Работа с криптографией +""" + +import secrets + + +class Crypto: + """ + Реализует методы работы со случайными и криптографическими значениями + """ + + DEFAULT_TOKEN_LENGTH = 32 + """ Длина токена по умолчанию """ + + DEFAULT_PIN_CODE_LENGTH = 4 + """ Длина PIN-кода по умолчанию """ + + DEFAULT_PIN_CODE_ALPHABET = "0123456789" + """ Алфавит PIN-кода по умолчанию """ + + @classmethod + def gen_token(cls, length: int = DEFAULT_TOKEN_LENGTH) -> str: + """ + Генерирует случайный токен + + :param length: Длина токена + :return: Сгенерированный токен + """ + + bytes_needed = (length + 1) // 2 + token = secrets.token_hex(bytes_needed) + return token[:length] + + @classmethod + def gen_pin_code(cls, length: int = DEFAULT_PIN_CODE_LENGTH, alphabet: str = DEFAULT_PIN_CODE_ALPHABET): + """ + Генерирует случайный PIN-код + + :param length: Длина PIN-кода + :param alphabet: Алфавит PIN-кода + :return: Сгенерированный PIN-код + """ + + return "".join(secrets.choice(alphabet) for _ in range(length))