From 5f97349d6a81a0e59e837093290cb43aee708270 Mon Sep 17 00:00:00 2001 From: Andrej Shadura Date: Tue, 17 May 2022 11:43:37 +0200 Subject: New upstream version 2.1.0 --- .flake8 | 3 ++ .github/workflows/continuous-integration.yml | 48 +++++++++++++++++++++++++++ .gitignore | 4 +-- .travis.yml | 15 --------- MANIFEST.in | 4 --- README.rst | 16 +++------ pyproject.toml | 24 ++++++++++++++ setup.py | 49 ---------------------------- test_unpaddedbase64.py | 41 ----------------------- tests/__init__.py | 0 tests/test_unpaddedbase64.py | 41 +++++++++++++++++++++++ tox.ini | 27 --------------- unpaddedbase64.py | 40 ----------------------- unpaddedbase64/__init__.py | 41 +++++++++++++++++++++++ unpaddedbase64/py.typed | 0 15 files changed, 162 insertions(+), 191 deletions(-) create mode 100644 .flake8 create mode 100644 .github/workflows/continuous-integration.yml delete mode 100644 .travis.yml delete mode 100644 MANIFEST.in create mode 100644 pyproject.toml delete mode 100755 setup.py delete mode 100644 test_unpaddedbase64.py create mode 100644 tests/__init__.py create mode 100644 tests/test_unpaddedbase64.py delete mode 100644 tox.ini delete mode 100644 unpaddedbase64.py create mode 100644 unpaddedbase64/__init__.py create mode 100644 unpaddedbase64/py.typed diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..e4e5eb3 --- /dev/null +++ b/.flake8 @@ -0,0 +1,3 @@ +[flake8] +max-line-length = 88 +extend-ignore = E203, W503 diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml new file mode 100644 index 0000000..91426fe --- /dev/null +++ b/.github/workflows/continuous-integration.yml @@ -0,0 +1,48 @@ +name: Continuous Integration + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + lint: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: '3.x' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install flake8 black mypy + - name: Lint with flake8 + run: | + flake8 unpaddedbase64/ tests/ + - name: Lint with black + run: | + black --check --diff unpaddedbase64/ tests/ + - name: Lint with mypy + run: | + mypy --strict unpaddedbase64/ tests/ + + test: + needs: lint + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ['3.x', '3.6', 'pypy-3.6'] + + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Test with unittest + run: | + python -m unittest --verbose diff --git a/.gitignore b/.gitignore index 25ccf99..fff554a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,5 @@ .coverage .tox/ __pycache__/ -unpaddedbase64.egg-info/ -unpaddedbase64.pyc -build/ dist/ +poetry.lock diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index b10c59a..0000000 --- a/.travis.yml +++ /dev/null @@ -1,15 +0,0 @@ -language: python -env: -- TOXENV=packaging -- TOXENV=pep8 -- TOXENV=py3pep8 -- TOXENV=py27 -- TOXENV=py33 -- TOXENV=py34 -- TOXENV=pypy - -install: -- pip install tox - -script: -- tox diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 6429bd5..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,4 +0,0 @@ -include *.in -include *.py -include LICENSE -include tox.ini diff --git a/README.rst b/README.rst index 5796b7b..9c211d5 100644 --- a/README.rst +++ b/README.rst @@ -1,18 +1,10 @@ Unpadded Base64 =============== -.. image:: https://img.shields.io/pypi/v/unpaddedbase64.svg - :target: https://pypi.python.org/pypi/unpaddedbase64/ - :alt: Latest Version - -.. image:: https://img.shields.io/travis/matrix-org/python-unpaddedbase64.svg - :target: https://travis-ci.org/matrix-org/python-unpaddedbase64 - Encode and decode Base64 without "=" padding. `RFC 4648`_ specifies that Base64 should be padded to a multiple of 4 bytes -using "=" characters. However this conveys no benefit so many protocols choose -to use Base64 without the "=" padding. +using "=" characters. However many protocols choose to omit the "=" padding. .. _`RFC 4648`: https://tools.ietf.org/html/rfc4648 @@ -21,7 +13,7 @@ Installing .. code:: bash - pip install unpaddedbase64 + python3 -m pip install unpaddedbase64 Using ----- @@ -29,5 +21,5 @@ Using .. code:: python import unpaddedbase64 - assert (unpaddedbase64.encode_base64(b'\x00')) == u'AA' - assert (unpaddedbase64.decode_base64(u'AA')) == b'\x00' + assert (unpaddedbase64.encode_base64(b'\x00')) == 'AA' + assert (unpaddedbase64.decode_base64('AA')) == b'\x00' diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..eed1454 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,24 @@ +[build-system] +requires = ["poetry_core>=1.0.0"] +build-backend = "poetry.core.masonry.api" + +[tool.poetry] +name = "unpaddedbase64" +version = "2.1.0" +description = 'Encode and decode Base64 without "=" padding' +license = "Apache-2.0" +authors = [ "The Matrix.org Foundation C.I.C." ] +readme = "README.rst" +homepage = "https://github.com/matrix-org/python-unpaddedbase64" +keywords = ["base64"] + +[tool.poetry.urls] +"Issue Tracker" = "https://github.com/matrix-org/python-unpaddedbase64/issues" + +[tool.poetry.dependencies] +python = "^3.6" + +[tool.poetry.dev-dependencies] +black = "*" +flake8 = "*" +mypy = "*" diff --git a/setup.py b/setup.py deleted file mode 100755 index 6d7ee74..0000000 --- a/setup.py +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2015 OpenMarket Ltd -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from setuptools import setup -from codecs import open -import os - -here = os.path.abspath(os.path.dirname(__file__)) - - -def read_file(path_segments): - """Read a UTF-8 file from the package. Takes a list of strings to join to - make the path""" - file_path = os.path.join(here, *path_segments) - with open(file_path, encoding="utf-8") as f: - return f.read() - - -def exec_file(path_segments, name): - """Extract a constant from a python file by looking for a line defining - the constant and executing it.""" - result = {} - code = read_file(path_segments) - lines = [line for line in code.split('\n') if line.startswith(name)] - exec("\n".join(lines), result) - return result[name] - - -setup( - name="unpaddedbase64", - version=exec_file(("unpaddedbase64.py",), "__version__"), - py_modules=["unpaddedbase64"], - description="Unpadded Base64", - long_description=read_file(("README.rst",)), - keywords="base64", -) diff --git a/test_unpaddedbase64.py b/test_unpaddedbase64.py deleted file mode 100644 index a3c8463..0000000 --- a/test_unpaddedbase64.py +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright 2015 OpenMarket Ltd -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from unpaddedbase64 import encode_base64, decode_base64 -import unittest - - -class TestUnpaddedBase64(unittest.TestCase): - - def test_encode(self): - self.assertEqual(encode_base64(b''), u'') - self.assertEqual(encode_base64(b'\x00'), u'AA') - self.assertEqual(encode_base64(b'\x00\x00'), u'AAA') - self.assertEqual(encode_base64(b'\x00\x00\x00'), u'AAAA') - - def test_decode(self): - self.assertEqual(decode_base64(u''), b'') - self.assertEqual(decode_base64(u'AA'), b'\x00') - self.assertEqual(decode_base64(u'AAA'), b'\x00\x00') - self.assertEqual(decode_base64(u'AAAA'), b'\x00\x00\x00') - with self.assertRaises(Exception): - decode_base64(u'A') - - def test_encode_urlunsafe_chars(self): - self.assertEqual(encode_base64(b'\xff\xe6\x9a'), u'/+aa') - self.assertEqual(encode_base64(b'\xff\xe6\x9a', True), u'_-aa') - - def test_decode_urlunsafe_chars(self): - self.assertEqual(decode_base64(u'/+aa'), b'\xff\xe6\x9a') - self.assertEqual(decode_base64(u'_-aa'), b'\xff\xe6\x9a') diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_unpaddedbase64.py b/tests/test_unpaddedbase64.py new file mode 100644 index 0000000..90d21a0 --- /dev/null +++ b/tests/test_unpaddedbase64.py @@ -0,0 +1,41 @@ +# Copyright 2015 OpenMarket Ltd +# Copyright 2021 The Matrix.org Foundation C.I.C. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from unpaddedbase64 import encode_base64, decode_base64 +import unittest + + +class TestUnpaddedBase64(unittest.TestCase): + def test_encode(self) -> None: + self.assertEqual(encode_base64(b""), "") + self.assertEqual(encode_base64(b"\x00"), "AA") + self.assertEqual(encode_base64(b"\x00\x00"), "AAA") + self.assertEqual(encode_base64(b"\x00\x00\x00"), "AAAA") + + def test_decode(self) -> None: + self.assertEqual(decode_base64(""), b"") + self.assertEqual(decode_base64("AA"), b"\x00") + self.assertEqual(decode_base64("AAA"), b"\x00\x00") + self.assertEqual(decode_base64("AAAA"), b"\x00\x00\x00") + with self.assertRaises(Exception): + decode_base64("A") + + def test_encode_urlunsafe_chars(self) -> None: + self.assertEqual(encode_base64(b"\xff\xe6\x9a"), "/+aa") + self.assertEqual(encode_base64(b"\xff\xe6\x9a", True), "_-aa") + + def test_decode_urlunsafe_chars(self) -> None: + self.assertEqual(decode_base64("/+aa"), b"\xff\xe6\x9a") + self.assertEqual(decode_base64("_-aa"), b"\xff\xe6\x9a") diff --git a/tox.ini b/tox.ini deleted file mode 100644 index c368ee7..0000000 --- a/tox.ini +++ /dev/null @@ -1,27 +0,0 @@ -[tox] -envlist = packaging, pep8, py3pep8, py27, py33, py34, pypy - -[testenv] -deps = - coverage - pytest -commands = - coverage run --source unpaddedbase64 -m pytest - coverage report -m --fail-under 100 - -[testenv:packaging] -deps = - check-manifest -commands = check-manifest - -[testenv:pep8] -basepython = python2.7 -deps = - flake8 -commands = flake8 . - -[testenv:py3pep8] -basepython = python3.4 -deps = - flake8 -commands = flake8 . diff --git a/unpaddedbase64.py b/unpaddedbase64.py deleted file mode 100644 index 245697c..0000000 --- a/unpaddedbase64.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright 2014, 2015 OpenMarket Ltd -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import base64 - -__version__ = "1.1.0" - - -def encode_base64(input_bytes, urlsafe=False): - """Encode bytes as a base64 string without any padding.""" - - encode = base64.urlsafe_b64encode if urlsafe else base64.b64encode - output_bytes = encode(input_bytes) - output_string = output_bytes.decode("ascii") - return output_string.rstrip(u"=") - - -def decode_base64(input_string): - """Decode a base64 string to bytes inferring padding from the length of the - string.""" - - input_bytes = input_string.encode("ascii") - input_len = len(input_bytes) - padding = b"=" * (3 - ((input_len + 3) % 4)) - decode = base64.b64decode - if u'-' in input_string or u'_' in input_string: - decode = base64.urlsafe_b64decode - output_bytes = decode(input_bytes + padding) - return output_bytes diff --git a/unpaddedbase64/__init__.py b/unpaddedbase64/__init__.py new file mode 100644 index 0000000..9f45bee --- /dev/null +++ b/unpaddedbase64/__init__.py @@ -0,0 +1,41 @@ +# Copyright 2014, 2015 OpenMarket Ltd +# Copyright 2021 The Matrix.org Foundation C.I.C. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import base64 + + +def encode_base64(input_bytes: bytes, urlsafe: bool = False) -> str: + """Encode bytes as an unpadded base64 string.""" + + if urlsafe: + encode = base64.urlsafe_b64encode + else: + encode = base64.b64encode + + output_bytes = encode(input_bytes) + output_string = output_bytes.decode("ascii") + return output_string.rstrip("=") + + +def decode_base64(input_string: str) -> bytes: + """Decode an unpadded standard or urlsafe base64 string to bytes.""" + + input_bytes = input_string.encode("ascii") + input_len = len(input_bytes) + padding = b"=" * (3 - ((input_len + 3) % 4)) + + # Passing altchars here allows decoding both standard and urlsafe base64 + output_bytes = base64.b64decode(input_bytes + padding, altchars=b"-_") + return output_bytes diff --git a/unpaddedbase64/py.typed b/unpaddedbase64/py.typed new file mode 100644 index 0000000..e69de29 -- cgit v1.2.3