Spaces:
Sleeping
Sleeping
# Ultralytics YOLO π, AGPL-3.0 license | |
import requests | |
from ultralytics.hub.utils import HUB_API_ROOT, HUB_WEB_ROOT, PREFIX, request_with_credentials | |
from ultralytics.utils import LOGGER, SETTINGS, emojis, is_colab | |
API_KEY_URL = f"{HUB_WEB_ROOT}/settings?tab=api+keys" | |
class Auth: | |
""" | |
Manages authentication processes including API key handling, cookie-based authentication, and header generation. | |
The class supports different methods of authentication: | |
1. Directly using an API key. | |
2. Authenticating using browser cookies (specifically in Google Colab). | |
3. Prompting the user to enter an API key. | |
Attributes: | |
id_token (str or bool): Token used for identity verification, initialized as False. | |
api_key (str or bool): API key for authentication, initialized as False. | |
model_key (bool): Placeholder for model key, initialized as False. | |
""" | |
id_token = api_key = model_key = False | |
def __init__(self, api_key="", verbose=False): | |
""" | |
Initialize the Auth class with an optional API key. | |
Args: | |
api_key (str, optional): May be an API key or a combination API key and model ID, i.e. key_id | |
""" | |
# Split the input API key in case it contains a combined key_model and keep only the API key part | |
api_key = api_key.split("_")[0] | |
# Set API key attribute as value passed or SETTINGS API key if none passed | |
self.api_key = api_key or SETTINGS.get("api_key", "") | |
# If an API key is provided | |
if self.api_key: | |
# If the provided API key matches the API key in the SETTINGS | |
if self.api_key == SETTINGS.get("api_key"): | |
# Log that the user is already logged in | |
if verbose: | |
LOGGER.info(f"{PREFIX}Authenticated β ") | |
return | |
else: | |
# Attempt to authenticate with the provided API key | |
success = self.authenticate() | |
# If the API key is not provided and the environment is a Google Colab notebook | |
elif is_colab(): | |
# Attempt to authenticate using browser cookies | |
success = self.auth_with_cookies() | |
else: | |
# Request an API key | |
success = self.request_api_key() | |
# Update SETTINGS with the new API key after successful authentication | |
if success: | |
SETTINGS.update({"api_key": self.api_key}) | |
# Log that the new login was successful | |
if verbose: | |
LOGGER.info(f"{PREFIX}New authentication successful β ") | |
elif verbose: | |
LOGGER.info(f"{PREFIX}Get API key from {API_KEY_URL} and then run 'yolo hub login API_KEY'") | |
def request_api_key(self, max_attempts=3): | |
""" | |
Prompt the user to input their API key. | |
Returns the model ID. | |
""" | |
import getpass | |
for attempts in range(max_attempts): | |
LOGGER.info(f"{PREFIX}Login. Attempt {attempts + 1} of {max_attempts}") | |
input_key = getpass.getpass(f"Enter API key from {API_KEY_URL} ") | |
self.api_key = input_key.split("_")[0] # remove model id if present | |
if self.authenticate(): | |
return True | |
raise ConnectionError(emojis(f"{PREFIX}Failed to authenticate β")) | |
def authenticate(self) -> bool: | |
""" | |
Attempt to authenticate with the server using either id_token or API key. | |
Returns: | |
(bool): True if authentication is successful, False otherwise. | |
""" | |
try: | |
if header := self.get_auth_header(): | |
r = requests.post(f"{HUB_API_ROOT}/v1/auth", headers=header) | |
if not r.json().get("success", False): | |
raise ConnectionError("Unable to authenticate.") | |
return True | |
raise ConnectionError("User has not authenticated locally.") | |
except ConnectionError: | |
self.id_token = self.api_key = False # reset invalid | |
LOGGER.warning(f"{PREFIX}Invalid API key β οΈ") | |
return False | |
def auth_with_cookies(self) -> bool: | |
""" | |
Attempt to fetch authentication via cookies and set id_token. User must be logged in to HUB and running in a | |
supported browser. | |
Returns: | |
(bool): True if authentication is successful, False otherwise. | |
""" | |
if not is_colab(): | |
return False # Currently only works with Colab | |
try: | |
authn = request_with_credentials(f"{HUB_API_ROOT}/v1/auth/auto") | |
if authn.get("success", False): | |
self.id_token = authn.get("data", {}).get("idToken", None) | |
self.authenticate() | |
return True | |
raise ConnectionError("Unable to fetch browser authentication details.") | |
except ConnectionError: | |
self.id_token = False # reset invalid | |
return False | |
def get_auth_header(self): | |
""" | |
Get the authentication header for making API requests. | |
Returns: | |
(dict): The authentication header if id_token or API key is set, None otherwise. | |
""" | |
if self.id_token: | |
return {"authorization": f"Bearer {self.id_token}"} | |
elif self.api_key: | |
return {"x-api-key": self.api_key} | |
# else returns None | |