From 99e378286865c1eb7e3105641b8f91ab33729d42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Germ=C3=A1n=20Larra=C3=ADn?= Date: Wed, 24 Apr 2019 18:53:01 -0400 Subject: [PATCH] libs: add module `encoding_utils` --- cl_sii/libs/encoding_utils.py | 55 +++++++++++++++++++++++++++++++ tests/test_libs_encoding_utils.py | 18 ++++++++++ 2 files changed, 73 insertions(+) create mode 100644 cl_sii/libs/encoding_utils.py create mode 100644 tests/test_libs_encoding_utils.py diff --git a/cl_sii/libs/encoding_utils.py b/cl_sii/libs/encoding_utils.py new file mode 100644 index 00000000..9a6adb14 --- /dev/null +++ b/cl_sii/libs/encoding_utils.py @@ -0,0 +1,55 @@ +import base64 +import binascii +from typing import Union + + +def clean_base64(value: Union[str, bytes]) -> bytes: + """ + Force bytes and remove line breaks and spaces. + + Does not validate base64 format. + + :raises ValueError: + :raises TypeError: + + """ + if isinstance(value, bytes): + value_base64_bytes = value + elif isinstance(value, str): + try: + value_base64_bytes = value.strip().encode(encoding='ascii', errors='strict') + except UnicodeEncodeError as exc: + raise ValueError("Only ASCII characters are accepted.", str(exc)) from exc + else: + raise TypeError("Value must be str or bytes.") + + # remove line breaks and spaces + value_base64_bytes_cleaned = value_base64_bytes.replace(b'\n', b'').replace(b' ', b'') + + return value_base64_bytes_cleaned + + +def decode_base64_strict(value: Union[str, bytes]) -> bytes: + """ + Strict conversion for str/bytes, tolerating only line breaks and spaces. + + :raises ValueError: non-base64 input or non-ASCII characters included + + """ + value_base64_bytes_cleaned = clean_base64(value) + try: + value_bytes = base64.b64decode(value_base64_bytes_cleaned, validate=True) + except binascii.Error as exc: + raise ValueError("Input is not a valid base64 value.", str(exc)) from exc + return value_bytes + + +def validate_base64(value: Union[str, bytes]) -> None: + """ + Validate that ``value`` is base64-encoded data. + + :raises ValueError: + :raises TypeError: + + """ + decode_base64_strict(value) diff --git a/tests/test_libs_encoding_utils.py b/tests/test_libs_encoding_utils.py new file mode 100644 index 00000000..0065d6f6 --- /dev/null +++ b/tests/test_libs_encoding_utils.py @@ -0,0 +1,18 @@ +import unittest + +from cl_sii.libs.encoding_utils import clean_base64, decode_base64_strict, validate_base64 # noqa: F401,E501 + + +class FunctionsTest(unittest.TestCase): + + def test_clean_base64(self): + # TODO: implement for function 'clean_base64'. + pass + + def test_decode_base64_strict(self): + # TODO: implement for function 'decode_base64_strict'. + pass + + def test_validate_base64(self): + # TODO: implement for function 'validate_base64'. + pass