-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'dev' into asynctestclient_changes
- Loading branch information
Showing
21 changed files
with
280 additions
and
49 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
from .async_session import * # noqa | ||
from .helpers import * # noqa | ||
from .session import * # noqa | ||
from .async_session import * # noqa |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import os | ||
|
||
from dotenv import load_dotenv | ||
|
||
load_dotenv() | ||
|
||
host = os.getenv("POSTGRES_HOST", "localhost") | ||
user = os.getenv("POSTGRES_USER", "postgres") | ||
password = os.getenv("POSTGRES_PASSWORD", "root") | ||
port = os.getenv("POSTGRES_PORT", "5432") | ||
name = os.getenv("POSTGRES_DB", "fastapi") | ||
|
||
SQLALCHEMY_DATABASE_URL = f"postgresql+psycopg://{user}:{password}@{host}:{port}/" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
from sqlalchemy_utils import create_database, database_exists | ||
|
||
|
||
def create_if_not_exists(db_name: str): | ||
from .common import SQLALCHEMY_DATABASE_URL | ||
|
||
if not database_exists(SQLALCHEMY_DATABASE_URL + db_name): | ||
create_database(SQLALCHEMY_DATABASE_URL + db_name) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import secrets | ||
import string | ||
|
||
|
||
def create_random_password(length: int = 12) -> str: | ||
all_characters = string.ascii_letters + string.digits + string.punctuation | ||
|
||
password = [ | ||
secrets.choice(string.ascii_lowercase), | ||
secrets.choice(string.ascii_uppercase), | ||
secrets.choice(string.digits), | ||
secrets.choice(string.punctuation), | ||
] | ||
password += [secrets.choice(all_characters) for _ in range(length - 4)] | ||
secrets.SystemRandom().shuffle(password) | ||
return "".join(password) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from .auth0 import * # noqa |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from .exceptions import * # noqa | ||
from .manage import * # noqa | ||
from .utils import * # noqa |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import os | ||
|
||
from dotenv import load_dotenv | ||
|
||
load_dotenv() | ||
|
||
AUTH0_DOMAIN = os.getenv("AUTH0_DOMAIN") | ||
AUTH0_CLIENT_ID = os.getenv("AUTH0_CLIENT_ID") | ||
AUTH0_CLIENT_SECRET = os.getenv("AUTH0_CLIENT_SECRET") | ||
AUTH0_ALGORIGHM = os.getenv("AUTH0_ALGORIGHM", "RS256") | ||
|
||
AUTH0_AUDIENCE = os.getenv("AUTH0_AUDIENCE") | ||
AUTH0_ISSUER = os.getenv("AUTH0_ISSUER") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
from fastapi import HTTPException, status | ||
|
||
|
||
class UnauthorizedException(HTTPException): | ||
def __init__(self, detail: str, **kwargs): | ||
"""Returns HTTP 403""" | ||
super().__init__(status.HTTP_403_FORBIDDEN, detail=detail) | ||
|
||
|
||
class UnauthenticatedException(HTTPException): | ||
def __init__(self): | ||
super().__init__(status_code=status.HTTP_401_UNAUTHORIZED, detail="Requires authentication") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import requests | ||
from cachetools import TTLCache, cached | ||
|
||
from .common import AUTH0_CLIENT_ID, AUTH0_CLIENT_SECRET, AUTH0_DOMAIN | ||
|
||
cache = TTLCache(maxsize=100, ttl=600) | ||
|
||
|
||
@cached(cache) | ||
def get_management_token() -> str: | ||
response = requests.post( | ||
f"https://{AUTH0_DOMAIN}/oauth/token", | ||
json={ | ||
"client_id": AUTH0_CLIENT_ID, | ||
"client_secret": AUTH0_CLIENT_SECRET, | ||
"audience": f"https://{AUTH0_DOMAIN}/api/v2/", # This should be the management audience | ||
"grant_type": "client_credentials", | ||
}, | ||
timeout=5, # Add a timeout parameter to avoid hanging requests | ||
).json() | ||
return response["access_token"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
from typing import Optional | ||
|
||
import jwt | ||
import requests | ||
from fastapi import HTTPException, Request, Security | ||
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer | ||
|
||
from creyPY.helpers import create_random_password | ||
|
||
from .common import ( | ||
AUTH0_ALGORIGHM, | ||
AUTH0_AUDIENCE, | ||
AUTH0_CLIENT_ID, | ||
AUTH0_DOMAIN, | ||
AUTH0_ISSUER, | ||
) | ||
from .exceptions import UnauthenticatedException, UnauthorizedException | ||
from .manage import get_management_token | ||
|
||
JWKS_CLIENT = jwt.PyJWKClient(f"https://{AUTH0_DOMAIN}/.well-known/jwks.json") | ||
|
||
|
||
async def verify( | ||
request: Request, | ||
token: Optional[HTTPAuthorizationCredentials] = Security(HTTPBearer(auto_error=False)), | ||
) -> str: | ||
if token is None: | ||
raise UnauthenticatedException | ||
|
||
# This gets the 'kid' from the passed token | ||
try: | ||
signing_key = JWKS_CLIENT.get_signing_key_from_jwt(token.credentials).key | ||
except jwt.exceptions.PyJWKClientError as error: | ||
raise UnauthorizedException(str(error)) | ||
except jwt.exceptions.DecodeError as error: | ||
raise UnauthorizedException(str(error)) | ||
|
||
try: | ||
payload = jwt.decode( | ||
token.credentials, | ||
signing_key, | ||
algorithms=[AUTH0_ALGORIGHM], | ||
audience=AUTH0_AUDIENCE, | ||
issuer=AUTH0_ISSUER, | ||
) | ||
except Exception as error: | ||
raise UnauthorizedException(str(error)) | ||
|
||
return payload["sub"] | ||
|
||
|
||
### GENERIC AUTH0 CALLS ### | ||
def get_user(sub) -> dict: | ||
re = requests.get( | ||
f"https://{AUTH0_DOMAIN}/api/v2/users/{sub}", | ||
headers={"Authorization": f"Bearer {get_management_token()}"}, | ||
timeout=5, | ||
) | ||
if re.status_code != 200: | ||
raise HTTPException(re.status_code, re.json()) | ||
return re.json() | ||
|
||
|
||
def patch_user(input_obj: dict, sub) -> dict: | ||
re = requests.patch( | ||
f"https://{AUTH0_DOMAIN}/api/v2/users/{sub}", | ||
headers={"Authorization": f"Bearer {get_management_token()}"}, | ||
json=input_obj, | ||
timeout=5, | ||
) | ||
if re.status_code != 200: | ||
raise HTTPException(re.status_code, re.json()) | ||
return re.json() | ||
|
||
|
||
### USER METADATA CALLS ### | ||
def get_user_metadata(sub) -> dict: | ||
try: | ||
return get_user(sub).get("user_metadata", {}) | ||
except: | ||
return {} | ||
|
||
|
||
def patch_user_metadata(input_obj: dict, sub) -> dict: | ||
return patch_user({"user_metadata": input_obj}, sub) | ||
|
||
|
||
def clear_user_metadata(sub) -> dict: | ||
return patch_user({"user_metadata": {}}, sub) | ||
|
||
|
||
def request_verification_mail(sub: str) -> None: | ||
re = requests.post( | ||
f"https://{AUTH0_DOMAIN}/api/v2/jobs/verification-email", | ||
headers={"Authorization": f"Bearer {get_management_token()}"}, | ||
json={"user_id": sub}, | ||
timeout=5, | ||
) | ||
if re.status_code != 201: | ||
raise HTTPException(re.status_code, re.json()) | ||
return re.json() | ||
|
||
|
||
def create_user_invite(email: str) -> dict: | ||
re = requests.post( | ||
f"https://{AUTH0_DOMAIN}/api/v2/users", | ||
headers={"Authorization": f"Bearer {get_management_token()}"}, | ||
json={ | ||
"email": email, | ||
"connection": "Username-Password-Authentication", | ||
"password": create_random_password(), | ||
"verify_email": False, | ||
"app_metadata": {"invitedToMyApp": True}, | ||
}, | ||
timeout=5, | ||
) | ||
if re.status_code != 201: | ||
raise HTTPException(re.status_code, re.json()) | ||
return re.json() | ||
|
||
|
||
def password_change_mail(email: str) -> bool: | ||
re = requests.post( | ||
f"https://{AUTH0_DOMAIN}/dbconnections/change_password", | ||
headers={"Authorization": f"Bearer {get_management_token()}"}, | ||
json={ | ||
"client_id": AUTH0_CLIENT_ID, | ||
"email": email, | ||
"connection": "Username-Password-Authentication", | ||
}, | ||
timeout=5, | ||
) | ||
|
||
if re.status_code != 200: | ||
raise HTTPException(re.status_code, re.json()) | ||
return True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"$schema": "https://docs.renovatebot.com/renovate-schema.json", | ||
"extends": [ | ||
"config:recommended", | ||
":semanticCommitTypeAll(feat)" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
cachetools>=5.5.0 # for caching | ||
charset-normalizer>=3.4.0 # Auth0 API interactions | ||
requests>=2.32.3 # Auth0 API interactions | ||
pyjwt>=2.10.1 # Auth0 API interactions | ||
cffi>=1.17.1 # Auth0 API interactions | ||
cryptography>=43.0.3 # Auth0 API interactions | ||
pycparser>=2.22 # Auth0 API interactions |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,5 +23,3 @@ twine>=5.0.0 | |
urllib3>=2.2.1 | ||
wheel>=0.43.0 | ||
zipp>=3.18.1 | ||
|
||
-r requirements.txt |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
psycopg>=3.2.1 # PostgreSQL | ||
psycopg-binary>=3.2.1 # PostgreSQL | ||
psycopg-pool>=3.2.2 # PostgreSQL | ||
asyncpg>=0.30.0 # SQLAlchemy | ||
greenlet>=3.1.1 # Async |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.