diff --git a/.gitignore b/.gitignore index 96c28df..15f1070 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,6 @@ !.travis.yml __pycache__ *.egg-info - +/build +/.idea +/htmlcov diff --git a/.travis.yml b/.travis.yml index 34d44cc..8a8be7e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,12 @@ language: python python: - - "3.6" - - "3.7" - - "3.8" - - "3.9" + - "3.10" + - "3.11" + - "3.12" + - "3.13" + - "3.14" install: - - pip install -r requirements.txt + - pip install . script: - - python setup.py test + - python -m pytest diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md deleted file mode 100644 index 75a5128..0000000 --- a/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,4 +0,0 @@ -# Contributor Covenant Code of Conduct - -Be nice, don't panic and always remember your towel. - diff --git a/LICENSE b/LICENSE deleted file mode 100644 index cf1ab25..0000000 --- a/LICENSE +++ /dev/null @@ -1,24 +0,0 @@ -This is free and unencumbered software released into the public domain. - -Anyone is free to copy, modify, publish, use, compile, sell, or -distribute this software, either in source code form or as a compiled -binary, for any purpose, commercial or non-commercial, and by any -means. - -In jurisdictions that recognize copyright laws, the author or authors -of this software dedicate any and all copyright interest in the -software to the public domain. We make this dedication for the benefit -of the public at large and to the detriment of our heirs and -successors. We intend this dedication to be an overt act of -relinquishment in perpetuity of all present and future rights to this -software under copyright law. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - -For more information, please refer to diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..5f02a23 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,7 @@ +Copyright 2025 Georgy Bazhukov + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 9561fb1..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1 +0,0 @@ -include README.rst diff --git a/README.md b/README.md index 56b3981..072587b 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,9 @@ Aiohttp middleware for simple http basic auth protection for some urls. -Works with Python ≥ 3.6. +Works with +- Python ≥ 3.6 (till version 1.2.*); +- Python ≥ 3.10 (from version 1.3.0); Works with UTF-8 🖖 @@ -36,9 +38,9 @@ app.middlewares.append( 1. list of protected urls. For example `['/admin']` will match with `/admin/user`, but will not match with `/user/admin`. 2. auth dict – a dict with pairs: login-password. -3. strategy (optional) for password comparision. For example you can +3. strategy (optional) for password comparison. For example you can store hashed password in `auth_dict`. See `aiohttp_basicauth_middleware.strategy.BaseStrategy` and - `example.strategy` for more information. + `tests.example.strategy` for more information. Example with md5 password hashing: diff --git a/README.rst b/README.rst deleted file mode 100644 index 603cb37..0000000 --- a/README.rst +++ /dev/null @@ -1,65 +0,0 @@ -aiohttp-basicauth-middleware -============================ - -.. figure:: https://travis-ci.org/bugov/aiohttp-basicauth-middleware.svg?branch=master - - -Aiohttp middleware for simple http basic -auth protection for some urls. - -Works with Python >= 3.6. - -Works with UTF-8 🖖 - -Installation ------------- - -.. code:: bash - - pip install aiohttp-basicauth-middleware - -Usage ------ - -.. code:: python - - app = web.Application(loop=loop) - - app.router.add_route('GET', '/hello', handler_a) - app.router.add_route('GET', '/admin/hello', handler_b) - - app.middlewares.append( - basic_auth_middleware( - ('/admin',), - {'user': 'password'}, - ) - ) - - -`basic_auth_middleware` has 3 params: - -1. list of protected urls. For example `['/admin']` will match - with `/admin/user`, but will not match with `/user/admin`. -2. auth dict – a dict with pairs: login-password. -3. strategy (optional) for password comparision. For example you can - store hashed password in `auth_dict`. See `aiohttp_basicauth_middleware.strategy.BaseStrategy` and - `example.strategy` for more information. - -Example with md5 password hashing: - -.. code:: python - - app = web.Application(loop=loop) - - app.router.add_route('GET', '/hello', handler_a) - app.router.add_route('GET', '/admin/hello', handler_b) - - app.middlewares.append( - basic_auth_middleware( - ('/admin',), - {'user': '5f4dcc3b5aa765d61d8327deb882cf99'}, - lambda x: hashlib.md5(bytes(x, encoding='utf-8')).hexdigest(), - ) - ) - -`/admin/...` will be accessed by the same login+password pair ('user', 'password'). diff --git a/aiohttp_basicauth_middleware/__init__.py b/aiohttp_basicauth_middleware/__init__.py index 907cd1e..5b832dc 100644 --- a/aiohttp_basicauth_middleware/__init__.py +++ b/aiohttp_basicauth_middleware/__init__.py @@ -39,7 +39,7 @@ def check_access( def basic_auth_middleware( urls: Iterable, auth_dict: dict, - strategy: Type[BaseStrategy] = lambda x: x + strategy: Type[BaseStrategy] | Callable = lambda x: x ) -> Coroutine: async def factory(app, handler) -> Coroutine: async def middleware(request) -> web.Response: diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..f5031fa --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,47 @@ +[build-system] +requires = ["setuptools >= 42.0.0"] +build-backend = "setuptools.build_meta" + +[project] +name = "aiohttp-basicauth-middleware" +version = "1.3.0" +dependencies = [ + "http_basic_auth", + "aiohttp", +] +requires-python = ">=3.10" +authors = [ + {name = "Georgy Bazhukov", email = "georgy.bazhukov@gmail.com"}, +] +maintainers = [ + {name = "Georgy Bazhukov", email = "georgy.bazhukov@gmail.com"}, +] +description = "An incredibly simple HTTP basic auth implementation for Aiohttp." +readme = "README.md" +license = "MIT" +license-files = ["LICEN[CS]E.*"] +keywords = ["aiohttp", "security", "basicauth", "http", "middleware"] +classifiers = [ + 'Intended Audience :: Developers', + 'Programming Language :: Python', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12', + 'Programming Language :: Python :: 3.13', + 'Programming Language :: Python :: 3.14', +] + +[project.optional-dependencies] +dev = [ + "pytest>=6.0.0", + "pytest-cov>=6.0.0", + "black", + "flake8", + "tox" +] + +[project.urls] +Homepage = "https://github.com/bugov/aiohttp-basicauth-middleware" +Repository = "https://github.com/bugov/aiohttp-basicauth-middleware.git" +"Bug Tracker" = "https://github.com/bugov/aiohttp-basicauth-middleware/issues" diff --git a/requirements-dev.txt b/requirements-dev.txt deleted file mode 100644 index 0da1e35..0000000 --- a/requirements-dev.txt +++ /dev/null @@ -1,6 +0,0 @@ --r requirements.txt -pytest==4.6.11; python_version < '3.7.0' -pytest>=5.1.2; python_version >= '3.7.0' -pytest-cov==2.7.1; python_version < '3.7.0' -pytest-cov>=2.7.1; python_version >= '3.7.0' -tox diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 0ab1d8b..0000000 --- a/requirements.txt +++ /dev/null @@ -1,4 +0,0 @@ -aiohttp==3.7.4; python_version < '3.7.0' -aiohttp>=3.8.0; python_version >= '3.7.0' -http_basic_auth>=1.2.0 -wheel diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index b7e4789..0000000 --- a/setup.cfg +++ /dev/null @@ -1,2 +0,0 @@ -[aliases] -test=pytest diff --git a/setup.py b/setup.py deleted file mode 100644 index aeb4c67..0000000 --- a/setup.py +++ /dev/null @@ -1,49 +0,0 @@ -import os -from setuptools import setup - - -requires = ['wheel', 'http_basic_auth', 'aiohttp'] - - -def read(fname): - return open(os.path.join(os.path.dirname(__file__), fname), encoding='utf-8').read() - - -setup( - # Basic package information: - name='aiohttp-basicauth-middleware', - version='1.2.0', - py_modules=('aiohttp_basicauth_middleware',), - - # Packaging options: - zip_safe=False, - include_package_data=True, - packages=('aiohttp_basicauth_middleware',), - - classifiers=[ - 'License :: OSI Approved :: BSD License', - 'Intended Audience :: Developers', - 'Programming Language :: Python', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3.9', - 'Programming Language :: Python :: 3.10', - ], - - # Package dependencies: - requires=requires, - tests_require=requires + ["pytest"], - setup_requires=requires + ["pytest-runner"], - install_requires=requires, - - # Metadata for PyPI: - author='Georgy Bazhukov', - author_email='georgy.bazhukov@gmail.com', - license='BSD', - url='https://github.com/bugov/aiohttp-basicauth-middleware', - keywords='aiohttp security basicauth http middleware', - description='An incredibly simple HTTP basic auth implementation for Aiohttp.', - long_description=read('README.rst') -) diff --git a/example/__init__.py b/tests/__init__.py similarity index 100% rename from example/__init__.py rename to tests/__init__.py diff --git a/conftest.py b/tests/conftest.py similarity index 100% rename from conftest.py rename to tests/conftest.py diff --git a/tests/example/__init__.py b/tests/example/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/example/server.py b/tests/example/server.py similarity index 95% rename from example/server.py rename to tests/example/server.py index 4cef51b..2d7c583 100644 --- a/example/server.py +++ b/tests/example/server.py @@ -3,7 +3,7 @@ from aiohttp_basicauth_middleware import basic_auth_middleware -def hello(request): +async def hello(request): return web.Response(text='Hello') diff --git a/example/strategy.py b/tests/example/strategy.py similarity index 93% rename from example/strategy.py rename to tests/example/strategy.py index 504902a..ead8af0 100644 --- a/example/strategy.py +++ b/tests/example/strategy.py @@ -1,7 +1,7 @@ import asyncio from aiohttp import web from aiohttp_basicauth_middleware import basic_auth_middleware -from aiohttp_basicauth_middleware.strategy import BaseStrategy +from aiohttp_basicauth_middleware import BaseStrategy class SkipOptionsStrategy(BaseStrategy): diff --git a/test/test_middleware.py b/tests/test_middleware.py similarity index 97% rename from test/test_middleware.py rename to tests/test_middleware.py index fc05664..b98bb21 100644 --- a/test/test_middleware.py +++ b/tests/test_middleware.py @@ -1,7 +1,7 @@ import hashlib from http_basic_auth import generate_header -from example.server import get_app +from test.example.server import get_app async def test_no_auth_ok_url(aiohttp_server, aiohttp_client, loop): diff --git a/test/test_strategy.py b/tests/test_strategy.py similarity index 98% rename from test/test_strategy.py rename to tests/test_strategy.py index b192758..2e53a47 100644 --- a/test/test_strategy.py +++ b/tests/test_strategy.py @@ -3,7 +3,7 @@ from aiohttp_basicauth_middleware import basic_auth_middleware from http_basic_auth import generate_header -from example.strategy import get_app +from test.example.strategy import get_app async def test_skip_options_check(aiohttp_server, aiohttp_client, loop): diff --git a/tox.ini b/tox.ini index 407c75e..c8fcc30 100644 --- a/tox.ini +++ b/tox.ini @@ -1,16 +1,20 @@ [tox] skipsdist = True -envlist = py36, py37, py38, py39, py310 +envlist = py310, py311, py312, py313, p314 [testenv] -deps= -r{toxinidir}/requirements-dev.txt +deps = + aiohttp + http_basic_auth commands = - pytest -x --cov=aiohttp_basicauth_middleware --no-cov-on-fail + pytest --cov=aiohttp_basicauth_middleware --cov-report=html coverage html --fail-under=100 setenv = LANG = ru_RU.UTF-8 PYTHONPATH = {toxinidir} recreate = False +allowlist_externals = + pytest [pep8] max-line-length = 120