|
|
@@ -6,51 +6,219 @@ from .apikey_validator import apikey_validator
|
|
|
from .apikey_exceptions import apikey_syntax_error
|
|
|
|
|
|
class apikey_factory:
|
|
|
+ """
|
|
|
+ Factory for the API keys. That is useable to generating new random API
|
|
|
+ keys, importing API keys from string, with validation, generating
|
|
|
+ validators, and much more.
|
|
|
+ """
|
|
|
+
|
|
|
def __init__(self, prefix: str = "key") -> None:
|
|
|
+ """
|
|
|
+ That create new API keys factory, it require prefix, that mean static
|
|
|
+ string which is pushed always before random part of the string. It
|
|
|
+ also set API keys size, which is default 256.
|
|
|
+
|
|
|
+ Parameters
|
|
|
+ ----------
|
|
|
+ prefix : str (default: "key")
|
|
|
+ Prefix for the API keys.
|
|
|
+ """
|
|
|
+
|
|
|
self.__size = 256
|
|
|
self.__prefix = prefix
|
|
|
|
|
|
def set_size(self, size: int) -> object:
|
|
|
+ """
|
|
|
+ That change size of the API keys. Default API key size is 256, but
|
|
|
+ it could be changed to other custom size. Size must be greater than
|
|
|
+ prefix with prefix separator.
|
|
|
+
|
|
|
+ Parameters
|
|
|
+ ----------
|
|
|
+ size : int
|
|
|
+ Size of the API keys.
|
|
|
+
|
|
|
+ Raises
|
|
|
+ ------
|
|
|
+ RuntimeError
|
|
|
+ When new size is too small.
|
|
|
+
|
|
|
+ Returns
|
|
|
+ -------
|
|
|
+ apikey_factory
|
|
|
+ Self for chain loading.
|
|
|
+ """
|
|
|
+
|
|
|
+ if size <= len(self.prefix + self.prefix_separator):
|
|
|
+ raise RuntimeError("Size of the API keys must be bigger.")
|
|
|
+
|
|
|
self.__size = size
|
|
|
return self
|
|
|
|
|
|
def set_prefix(self, prefix: str) -> object:
|
|
|
+ """
|
|
|
+ That change prefix of the API keys generating by the factory.
|
|
|
+ It could not countain any white space, and cound not being empty.
|
|
|
+ Size of the API key also must being greater than prefix with
|
|
|
+ separator character.
|
|
|
+
|
|
|
+ Parameters
|
|
|
+ ----------
|
|
|
+ prefix : str
|
|
|
+ New prefix to set.
|
|
|
+
|
|
|
+ Raises
|
|
|
+ ------
|
|
|
+ ValueError
|
|
|
+ When prefix is empty.
|
|
|
+
|
|
|
+ ValueError
|
|
|
+ When prefix contain white characters.
|
|
|
+
|
|
|
+ RuntimeError
|
|
|
+ When prefix is too long.
|
|
|
+
|
|
|
+
|
|
|
+ Returns
|
|
|
+ -------
|
|
|
+ apikey_factory
|
|
|
+ Self to chain loading.
|
|
|
+ """
|
|
|
+
|
|
|
+ prefix = prefix.strip()
|
|
|
+
|
|
|
+ if len(prefix) == 0:
|
|
|
+ raise ValueError("Prefix can not being empty.")
|
|
|
+
|
|
|
+ for letter in prefix:
|
|
|
+ if letter.isspace():
|
|
|
+ raise ValueError("Prefix can not contain space.")
|
|
|
+
|
|
|
+ if len(prefix + self.prefix_separator) >= self.size:
|
|
|
+ raise RuntimeError("Prefix must be shorten")
|
|
|
+
|
|
|
self.__prefix = prefix
|
|
|
return self
|
|
|
|
|
|
@property
|
|
|
- def prefix_separator(self) -> str:
|
|
|
+ def prefix_separator(self) -> str:
|
|
|
+ """
|
|
|
+ That return prefix separator.
|
|
|
+
|
|
|
+ Returns
|
|
|
+ -------
|
|
|
+ str
|
|
|
+ Prefix separator.
|
|
|
+ """
|
|
|
+
|
|
|
return "_"
|
|
|
|
|
|
@property
|
|
|
def prefix(self) -> str:
|
|
|
+ """
|
|
|
+ That return current prefix separator.
|
|
|
+
|
|
|
+ Returns
|
|
|
+ -------
|
|
|
+ str
|
|
|
+ Current prefix separator.
|
|
|
+ """
|
|
|
+
|
|
|
return self.__prefix
|
|
|
|
|
|
@property
|
|
|
def size(self) -> int:
|
|
|
+ """
|
|
|
+ That return current API key size.
|
|
|
+
|
|
|
+ Returns
|
|
|
+ -------
|
|
|
+ int
|
|
|
+ Current API key size.
|
|
|
+ """
|
|
|
+
|
|
|
return self.__size
|
|
|
|
|
|
@functools.lru_cache
|
|
|
def __get_random_token_size(self, token_size: int) -> int:
|
|
|
+ """
|
|
|
+ That return size in bytes of random part of the API key.
|
|
|
+
|
|
|
+ Parameters
|
|
|
+ ----------
|
|
|
+ token_size : int
|
|
|
+ How much character have token.
|
|
|
+
|
|
|
+ Returns
|
|
|
+ -------
|
|
|
+ int
|
|
|
+ Size of the random token in bytes.
|
|
|
+ """
|
|
|
+
|
|
|
random_size = token_size / 2 + token_size % 2
|
|
|
random_size = int(random_size)
|
|
|
|
|
|
return random_size
|
|
|
|
|
|
@functools.lru_cache
|
|
|
- def __get_token_size(self, full_size: int, prefix_size: int) -> int:
|
|
|
+ def __get_token_size(self, full_size: int, prefix_size: int) -> int:
|
|
|
+ """
|
|
|
+ That return how much characters would have token.
|
|
|
+
|
|
|
+ Parameters
|
|
|
+ ----------
|
|
|
+ full_size : int
|
|
|
+ Full size of the API key.
|
|
|
+
|
|
|
+ prefix_size : int
|
|
|
+ Size of the API key prefix.
|
|
|
+
|
|
|
+ Returns
|
|
|
+ -------
|
|
|
+ int
|
|
|
+ Random token size.
|
|
|
+ """
|
|
|
+
|
|
|
return full_size - prefix_size - len(self.prefix_separator)
|
|
|
|
|
|
def __get_random(self) -> str:
|
|
|
+ """
|
|
|
+ That return new random part of the API key.
|
|
|
+
|
|
|
+ Returns
|
|
|
+ -------
|
|
|
+ str
|
|
|
+ New random part of the API key.
|
|
|
+ """
|
|
|
+
|
|
|
token_size = self.__get_token_size(self.size, len(self.prefix))
|
|
|
random_size = self.__get_random_token_size(token_size)
|
|
|
|
|
|
return os.urandom(random_size).hex()[0:token_size]
|
|
|
|
|
|
def __get_new_token(self) -> str:
|
|
|
+ """
|
|
|
+ That return new API key token.
|
|
|
+
|
|
|
+ Returns
|
|
|
+ -------
|
|
|
+ str
|
|
|
+ That return new API key token string.
|
|
|
+ """
|
|
|
+
|
|
|
return self.prefix + self.prefix_separator + self.__get_random()
|
|
|
|
|
|
def generate(self) -> apikey:
|
|
|
+ """
|
|
|
+ That generate new random API key. Result is API key object, with
|
|
|
+ parameters like size, prefix etc from the factory.
|
|
|
+
|
|
|
+ Returns
|
|
|
+ -------
|
|
|
+ apikey
|
|
|
+ New random API key.
|
|
|
+ """
|
|
|
+
|
|
|
return apikey(
|
|
|
self.__get_new_token(),
|
|
|
self.size,
|
|
|
@@ -59,6 +227,26 @@ class apikey_factory:
|
|
|
)
|
|
|
|
|
|
def load(self, token: str) -> apikey:
|
|
|
+ """
|
|
|
+ That import API key from its string form to the API key object. It
|
|
|
+ also validate it, and raise error when API key is not valid.
|
|
|
+
|
|
|
+ Parameters
|
|
|
+ ----------
|
|
|
+ token : str
|
|
|
+ API key as string to import.
|
|
|
+
|
|
|
+ Raises
|
|
|
+ ------
|
|
|
+ apikey_syntax_error
|
|
|
+ When API key is not valid.
|
|
|
+
|
|
|
+ Returns
|
|
|
+ -------
|
|
|
+ apikey
|
|
|
+ API key in its object form.
|
|
|
+ """
|
|
|
+
|
|
|
if not self.get_validator().validate(token):
|
|
|
raise apikey_syntax_error()
|
|
|
|
|
|
@@ -70,6 +258,15 @@ class apikey_factory:
|
|
|
)
|
|
|
|
|
|
def get_validator(self) -> apikey_validator:
|
|
|
+ """
|
|
|
+ That generate API keys validator.
|
|
|
+
|
|
|
+ Returns
|
|
|
+ -------
|
|
|
+ apikey_validator
|
|
|
+ New API key validator with parameters from factory.
|
|
|
+ """
|
|
|
+
|
|
|
return self.__get_validator_cache(
|
|
|
self.size,
|
|
|
self.prefix,
|
|
|
@@ -83,6 +280,26 @@ class apikey_factory:
|
|
|
prefix: str,
|
|
|
prefix_separator: str
|
|
|
) -> apikey_validator:
|
|
|
+ """
|
|
|
+ That is cache for API keys validator.
|
|
|
+
|
|
|
+ Parameters
|
|
|
+ ----------
|
|
|
+ size : int
|
|
|
+ Size of the API keys.
|
|
|
+
|
|
|
+ prefix : str
|
|
|
+ Prefix of the API keys.
|
|
|
+
|
|
|
+ prefix_separator : str
|
|
|
+ Prefix separator character.
|
|
|
+
|
|
|
+ Returns
|
|
|
+ -------
|
|
|
+ apikey_validator
|
|
|
+ New API key validator.
|
|
|
+ """
|
|
|
+
|
|
|
return apikey_validator(
|
|
|
size,
|
|
|
prefix,
|