-
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 pull request #330 from pepkit/313_mint_tokens
Add the ability to mint new API tokens through the UI
- Loading branch information
Showing
26 changed files
with
927 additions
and
127 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 |
---|---|---|
@@ -0,0 +1,81 @@ | ||
from datetime import datetime, timedelta | ||
from typing import Dict, List | ||
|
||
import secrets | ||
|
||
from fastapi import HTTPException | ||
|
||
from .routers.models import DeveloperKey | ||
|
||
from .helpers import jwt_encode_user_data | ||
from .const import MAX_NEW_KEYS | ||
|
||
|
||
class DeveloperKeyHandler: | ||
def __init__(self, default_exp: int = 30 * 24 * 60 * 60): | ||
self._keys: Dict[str, List[DeveloperKey]] = {} | ||
self._default_exp = default_exp | ||
self._bad_jwts = [] | ||
|
||
def add_key(self, namespace: str, key: DeveloperKey): | ||
""" | ||
Add a key to the handler for a given namespace/user | ||
:param namespace: namespace for the key | ||
:param key: DeveloperKey object | ||
""" | ||
if namespace not in self._keys: | ||
self._keys[namespace] = [] | ||
if len(self._keys[namespace]) >= MAX_NEW_KEYS: | ||
raise HTTPException( | ||
status_code=400, | ||
detail="You have reached the maximum number of keys allowed", | ||
) | ||
self._keys[namespace].append(key) | ||
|
||
def get_keys_for_namespace(self, namespace: str) -> List[DeveloperKey]: | ||
""" | ||
Get all the keys for a given namespace | ||
:param namespace: namespace for the key | ||
""" | ||
return self._keys.get(namespace) or [] | ||
|
||
def remove_key(self, namespace: str, last_five_chars: str): | ||
""" | ||
Remove a key from the handler for a given namespace/user | ||
:param namespace: namespace for the key | ||
:param key: key to remove | ||
""" | ||
if namespace in self._keys: | ||
self._keys[namespace] = [ | ||
key for key in self._keys[namespace] if key.key[-5:] != last_five_chars | ||
] | ||
self._bad_jwts.append(last_five_chars) | ||
|
||
def mint_key_for_namespace( | ||
self, namespace: str, session_info: dict | ||
) -> DeveloperKey: | ||
""" | ||
Mint a new key for a given namespace | ||
:param namespace: namespace for the key | ||
""" | ||
salt = secrets.token_hex(32) | ||
session_info["salt"] = salt | ||
expiry = datetime.utcnow() + timedelta(seconds=self._default_exp) | ||
new_key = jwt_encode_user_data(session_info, exp=expiry) | ||
key = DeveloperKey( | ||
key=new_key, | ||
created_at=datetime.utcnow().isoformat(), | ||
expires=expiry.isoformat(), | ||
) | ||
self.add_key(namespace, key) | ||
return key | ||
|
||
def is_key_bad(self, last_five_chars: str) -> bool: | ||
return last_five_chars in self._bad_jwts | ||
|
||
|
||
dev_key_handler = DeveloperKeyHandler() |
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,23 @@ | ||
from fastapi import Request, HTTPException | ||
from slowapi import Limiter, _rate_limit_exceeded_handler | ||
from slowapi.util import get_remote_address | ||
from slowapi.errors import RateLimitExceeded | ||
|
||
|
||
limiter = Limiter(key_func=get_remote_address) | ||
|
||
|
||
def _custom_rate_limit_exceeded_handler(request: Request, exc: RateLimitExceeded): | ||
""" | ||
Custom rate limit exceeded handler. Simple wrapper around slowapi's handler to ensure that | ||
we properly raise an HTTPException with status code 429. | ||
:param request: request object | ||
:param exc: RateLimitExceeded exception | ||
""" | ||
_ = _rate_limit_exceeded_handler(request, exc) | ||
raise HTTPException( | ||
status_code=429, | ||
detail="You are requesting too many new keys. Please try again later.", | ||
) |
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
Oops, something went wrong.