Source code for mantlebio.core.auth.creds
from abc import abstractmethod
from getpass import getpass
import os
from dotenv import load_dotenv
from mantlebio.core.constants import MANTLE_PROD_API
from mantlebio.helpers.decorators import deprecated
import requests
import time
import random
from mantlebio.exceptions import MantleRetriesExceededError
[docs]
class AuthMethod:
[docs]
@abstractmethod
def authenticate(self, mantle_api: str = MANTLE_PROD_API):
pass
[docs]
@abstractmethod
def get_token(self):
pass
[docs]
class PasswordCredentials(AuthMethod):
"""Object for storing password credentials"""
def __init__(self, email: str = None, password: str = None) -> None:
self.email = email
self.password = password
self._max_retries = 5
# load from .env if not provided
if not self.email:
self.email = os.getenv("MANTLE_USER")
if not self.password:
self.password = os.getenv("MANTLE_PASSWORD")
[docs]
def authenticate(self, mantle_api: str = MANTLE_PROD_API):
"""Authenticate the session object with a password"""
if not (self.email and self.password):
# prompt user to enter credentials
self.email = input("Email: ")
self.password = getpass()
base_delay = 1
max_total_delay = 600 # Maximum total delay in seconds (10 minutes)
total_delay = 0
for attempt in range(self._max_retries):
data = requests.post(mantle_api + '/signin',
json={'email': self.email, 'password': self.password})
if data.status_code < 300:
self._access_token = data.json()["access_token"]
return data
elif data.status_code in [500, 502, 503, 504, 401, 400, 403]:
# Calculate delay with jitter
delay = base_delay * (2 ** attempt)
jitter = random.uniform(0, delay)
delay_with_jitter = delay + jitter
# Ensure the cumulative delay does not exceed max_total_delay
if total_delay + delay_with_jitter > max_total_delay:
delay_with_jitter = max_total_delay - total_delay
total_delay += delay_with_jitter
print(
f"Transient error received ({data.status_code}), retrying in {delay_with_jitter:.2f} seconds... (total delay: {total_delay:.2f} seconds)")
time.sleep(delay_with_jitter)
if total_delay >= max_total_delay:
break
continue
raise MantleRetriesExceededError("Maximum retries exceeded")
[docs]
def get_token(self):
if self._access_token:
return self._access_token
else:
self.authenticate()
return self._access_token
[docs]
class JwtCredentials(AuthMethod):
"""Object for storing JWT credentials"""
def __init__(self, jwt: str) -> None:
self.jwt = jwt
[docs]
def authenticate(self, mantle_api: str = MANTLE_PROD_API):
data = requests.get(mantle_api + '/user', headers={
'Authorization': f'Bearer {self.jwt}'})
if data.status_code < 300:
return data
else:
raise Exception("Error authenticating with JWT")
[docs]
def get_token(self):
return self.jwt