diff --git a/.all-contributorsrc b/.all-contributorsrc new file mode 100644 index 00000000..dd2e8c30 --- /dev/null +++ b/.all-contributorsrc @@ -0,0 +1,13 @@ +{ + "files": [ + "README.md" + ], + "imageSize": 100, + "commit": false, + "contributorsPerLine": 7, + "projectName": "AuthX", + "projectOwner": "yezz123", + "repoType": "github", + "repoHost": "https://github.com", + "skipCi": true +} diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index 0e12eadf..16b38746 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -1,4 +1,4 @@ -name: Test Documentation Build +name: Test Documentation Building on: [pull_request] diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 284d0a81..36b7c0e2 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -1,4 +1,4 @@ -name: Testing on Docker +name: Docker tests on: push: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..a32a689b --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,27 @@ +name: Local tests + +on: [push, pull_request] + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: "3.9" + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install -r requirements.dev.txt + - name: Test Project + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + run: | + python -m pytest --cov=AuthX/ --cov-report=html + codecov + - name: lint + run: | + pre-commit run --all-files diff --git a/AuthX/__init__.py b/AuthX/__init__.py index 57c66192..83f453c0 100644 --- a/AuthX/__init__.py +++ b/AuthX/__init__.py @@ -1,6 +1,6 @@ """Ready to use and customizable Authentications and Oauth2 management for FastAPI""" -__version__ = "0.0.8" +__version__ = "0.0.9" __license__ = "MIT" diff --git a/AuthX/database/redis.py b/AuthX/database/redis.py index 73ffe1e8..70cace72 100644 --- a/AuthX/database/redis.py +++ b/AuthX/database/redis.py @@ -18,6 +18,7 @@ def set_client(self, redis: Redis) -> None: self._redis = redis async def get(self, key: str) -> str: + # TODO: Check if key exists return await self._redis.get(key) async def delete(self, key: str) -> None: diff --git a/AuthX/services/auth.py b/AuthX/services/auth.py index 62dfe0c3..9ddc0da5 100644 --- a/AuthX/services/auth.py +++ b/AuthX/services/auth.py @@ -25,6 +25,7 @@ class AuthService: + _repo: UsersRepo _auth_backend: JWTBackend _debug: bool @@ -80,6 +81,19 @@ def setup( cls._display_name = display_name def _validate_user_model(self, model, data: dict): + """ + Validate user model. + + Args: + model (UserInRegister): UserInRegister model. + data (dict): data. + + Raises: + HTTPException: 400 - validation error. + + Returns: + UserInRegister: UserInRegister model. + """ try: return model(**data) except ValidationError as e: @@ -87,9 +101,27 @@ def _validate_user_model(self, model, data: dict): raise HTTPException(400, detail=get_error_message(msg)) async def _email_exists(self, email: str) -> bool: + """ + Check if email exists. + + Args: + email (str): email. + + Returns: + bool: True if email exists. + """ return await self._repo.get_by_email(email) is not None async def _username_exists(self, username: str) -> bool: + """ + Check if username exists. + + Args: + username (str): username. + + Returns: + bool: True if username exists. + """ return await self._repo.get_by_username(username) is not None def _create_email_client(self) -> EmailClient: @@ -154,9 +186,25 @@ async def register(self, data: dict) -> Dict[str, str]: return self._auth_backend.create_tokens(payload) async def _is_bruteforce(self, ip: str, login: str) -> bool: + """ + Check if user is bruteforce. + + Args: + ip (str): ip. + login (str): login. + + Returns: + bool: True if user is bruteforce. + """ return await self._repo.is_bruteforce(ip, login) async def _update_last_login(self, id: int) -> None: + """ + Update last login. + + Args: + id (int): id. + """ await self._repo.update(id, {"last_login": datetime.utcnow()}) async def login(self, data: dict, ip: str) -> Dict[str, str]: @@ -199,8 +247,6 @@ async def login(self, data: dict, ip: str) -> Dict[str, str]: payload = UserPayload(**item).dict() return self._auth_backend.create_tokens(payload) - # async def token(self) -> dict: - async def refresh_access_token(self, refresh_token: str) -> str: """POST /token/refresh diff --git a/AuthX/services/password.py b/AuthX/services/password.py index b15ea45b..3199d3b9 100644 --- a/AuthX/services/password.py +++ b/AuthX/services/password.py @@ -19,6 +19,20 @@ class PasswordService: + """ + Password Service + + Raises: + HTTPException: 400 - validation or timeout. + HTTPException: 404 - token not found. + HTTPException: 406 - password already exists. + HTTPException: 409 - password reset before. + HTTPException: 500 - email not sent. + + Returns: + None + """ + _repo: UsersRepo _auth_backend: JWTBackend _debug: bool @@ -73,6 +87,19 @@ def _create_email_client(self) -> EmailClient: ) def _validate_user_model(self, model, data): + """ + Validate user model. + + Args: + model (UserInSetPassword): UserInSetPassword + data (dict): {password1: "password", password2: "password"} + + Raises: + HTTPException: 400 - validation or timeout. + + Returns: + UserInSetPassword: UserInSetPassword + """ try: return model(**data) except ValidationError as e: @@ -143,6 +170,12 @@ async def forgot_password(self, data: dict, ip: str) -> None: """ async def password_status(self) -> dict: + """ + POST /password_status + + Returns: + dict: password_status + """ status = await self._repo.get_password_status(self._user.id) return {"status": status} diff --git a/AuthX/services/search.py b/AuthX/services/search.py index adf89284..04f80045 100644 --- a/AuthX/services/search.py +++ b/AuthX/services/search.py @@ -7,6 +7,16 @@ class SearchService: + """ + Private + + Raises: + HTTPException: If the user does not exist. + + Returns: + The user. + """ + _repo: UsersRepo @classmethod diff --git a/AuthX/services/social.py b/AuthX/services/social.py index 1ee08d5e..19810578 100644 --- a/AuthX/services/social.py +++ b/AuthX/services/social.py @@ -14,6 +14,18 @@ class SocialService: + """ + Social Service + + Raises: + SocialException: social error + SocialException: email exists + SocialException: ban + + Returns: + Tuple[str, str]: access token, refresh token + """ + _repo: UsersRepo _auth_backend: JWTBackend _base_url: str diff --git a/README.md b/README.md index 870981ac..a0b14ae3 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,9 @@ [![Docker Build](https://github.com/yezz123/AuthX/actions/workflows/docker.yml/badge.svg)](https://github.com/yezz123/AuthX/actions/workflows/docker.yml) [![Python Package](https://github.com/yezz123/AuthX/actions/workflows/build.yml/badge.svg)](https://github.com/yezz123/AuthX/actions/workflows/build.yml) +[![Local tests](https://github.com/yezz123/AuthX/actions/workflows/test.yml/badge.svg)](https://github.com/yezz123/AuthX/actions/workflows/test.yml) +[![codecov](https://codecov.io/gh/yezz123/AuthX/branch/main/graph/badge.svg?token=3j5znCNzDp)](https://codecov.io/gh/yezz123/AuthX) +[![Codacy Badge](https://app.codacy.com/project/badge/Grade/b510202495654916843956856fd9a1f6)](https://www.codacy.com?utm_source=github.com&utm_medium=referral&utm_content=yezz123/AuthX&utm_campaign=Badge_Grade) [![PyPI version](https://badge.fury.io/py/AuthX.svg)](https://badge.fury.io/py/AuthX) [![Downloads](https://pepy.tech/badge/authx/month)](https://pepy.tech/project/authx) [![Downloads](https://pepy.tech/badge/authx/week)](https://pepy.tech/project/authx) @@ -66,7 +69,7 @@ app.include_router(auth.social_router, prefix="/auth") app.include_router(auth.password_router, prefix="/api/users") app.include_router(auth.admin_router, prefix="/api/users") app.include_router(auth.search_router, prefix="/api/users") -... + ``` ### Startup 🏁 @@ -121,7 +124,7 @@ def anonym_test(user: User = Depends(auth.get_user)): def user_test(user: User = Depends(auth.get_authenticated_user)): pass -# +# Set Admin User @router.get("/admin", dependencies=[Depends(auth.admin_required)]) def admin_test(): pass @@ -194,6 +197,20 @@ As you see the Package still under development, you can contribute to it, also i - [telegram](https://t.me/yezz123) - Where i can see the Project Roadmap? 🤔 - I use to manage AuthX on [Trello](https://trello.com/b/0NNZMP8T), you could check and see all the tasks if you could help me to do it. +- Check Also [Release Notes](https://yezz123.github.io/AuthX/release/). + +Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): + + + + + + + + + + +This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! ## License 📝 diff --git a/Setup.cfg b/Setup.cfg index 1c39de5c..09414b83 100644 --- a/Setup.cfg +++ b/Setup.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 0.0.8 +current_version = 0.0.9 commit = True tag = True diff --git a/docs/configuration/auth/jwt.md b/docs/configuration/auth/jwt.md index 53e7ba96..c33d51d1 100644 --- a/docs/configuration/auth/jwt.md +++ b/docs/configuration/auth/jwt.md @@ -86,9 +86,10 @@ __Notes__: For testing this and create a TestCases always assert a `payload.get` The Revoke Token is used to revoke the access token, and is used to generate a new access token, this one is based more on the cache backend. ```py +from datetime import datetime +from AuthX.core.jwt import JWTBackend + def logout(): - from datetime import datetime - from AuthX.core.jwt import JWTBackend key = # Key to revoke epoch = datetime.utcfromtimestamp(0) diff --git a/docs/faq.md b/docs/faq.md index 1df16f1a..d8e8b9ed 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -1,5 +1,7 @@ # Frequently Asked Questions 🍂 +![image](header.svg) + ## What is the purpose of this project? - This Project is an Authentication Package helping to Add a Fully registration and authentication or authorization system to your FastAPI project. Is designed to be as customizable and adaptable as possible, so that you can use it as you want. @@ -46,7 +48,7 @@ This book covers the following exciting features: If you feel this book is for you, get your [copy](https://amzn.to/3kTvgjG) today! -## How You Manage Your Projects? +## How Did You Manage AuthX? Managing the project during my Work was somehow Hard for me, cause as many know I start this project after i finish my ex. Job, and i start working on it even if i joined my new Job as a Backend Developer for [@Obytes](https://obytes.com). @@ -64,7 +66,7 @@ There you could buy me a [coffee ☕️](https://www.buymeacoffee.com/tahiri) to And you can also become a Silver or Gold sponsor for AuthX. 🏅🎉 -### Reference +### Basic References I use The Following Reference to Get The package Done: diff --git a/.github/header.svg b/docs/header.svg similarity index 100% rename from .github/header.svg rename to docs/header.svg diff --git a/docs/index.md b/docs/index.md index 4683016a..2df9dde4 100644 --- a/docs/index.md +++ b/docs/index.md @@ -6,10 +6,12 @@ Ready to use and customizable Authentications and Oauth2 management for FastAPI ⚡
+[![codecov](https://codecov.io/gh/yezz123/AuthX/branch/main/graph/badge.svg?token=3j5znCNzDp)](https://codecov.io/gh/yezz123/AuthX) +[![Codacy Badge](https://app.codacy.com/project/badge/Grade/b510202495654916843956856fd9a1f6)](https://www.codacy.com?utm_source=github.com&utm_medium=referral&utm_content=yezz123/AuthX&utm_campaign=Badge_Grade) [![PyPI version](https://badge.fury.io/py/AuthX.svg)](https://badge.fury.io/py/AuthX) [![Downloads](https://pepy.tech/badge/authx/month)](https://pepy.tech/project/authx) [![Downloads](https://pepy.tech/badge/authx/week)](https://pepy.tech/project/authx) -[![Lang](https://img.shields.io/badge/Language-Python-green?style)](https://github.com/yezz123) +[![Lang](https://img.shields.io/badge/Language-Python-green?style)](https://www.python.org/) [![framework](https://img.shields.io/badge/Framework-FastAPI-blue?style)](https://fastapi.tiangolo.com/) [![Star Badge](https://img.shields.io/static/v1?label=%F0%9F%8C%9F&message=If%20Useful&style=style=flatcolor=BC4E99)](https://github.com/yezz123/AuthX) [![Pypi](https://img.shields.io/pypi/pyversions/AuthX.svg?color=%2334D058)](https://pypi.org/project/AuthX) diff --git a/docs/release.md b/docs/release.md new file mode 100644 index 00000000..cb3e3ce8 --- /dev/null +++ b/docs/release.md @@ -0,0 +1,136 @@ +# Release Notes 🎞 + +## 0.0.9 + +- Add Code coverage and local testing for AuthenticationX. +- Add DocString to Some Functions relate to `Services`. +- Bump multiple packages to last release. + +### What's Changed + +- Bump mkdocs from 1.2.2 to 1.2.3 by @dependabot in