瀏覽代碼

First final release.

Cixo Develop 6 月之前
父節點
當前提交
be2e964344

+ 42 - 0
pyproject.toml

@@ -0,0 +1,42 @@
+[build-system]
+requires = [ "setuptools >= 77.0.3" ]
+build-backend = "setuptools.build_meta"
+
+[tool.setuptools.packages.find]
+where = [ "source" ]
+
+[project]
+name = "cx-apikey"
+version = "2025.11.03-1"
+requires-python = ">= 3.7"
+
+readme = "README.md"
+description = "That is API key generator and manager."
+
+license = "MIT"
+license-files = [ "LICENSE" ]
+
+keywords = [ 
+    "API", "APIkey", "apikey", "key", "secrets", "random", "generator",
+]
+
+authors = [
+    { name = "Cixo", email = "cixo@cixoelectronic.pl" }
+]
+
+maintainers = [
+    { name = "Cixo", email = "cixo@cixoelectronic.pl" }
+]
+
+classifiers = [
+    "Development Status :: 5 - Production/Stable",
+    "Intended Audience :: Developers",
+    "Topic :: Software Development :: Libraries",
+    "Programming Language :: Python :: 3",
+]
+
+[project.urls]
+Homepage = "https://git.cixoelectronic.pl/cixo-electronic/cx-apikey"
+Repository = "https://git.cixoelectronic.pl/cixo-electronic/cx-apikey"
+Documentation = "https://git.cixoelectronic.pl/cixo-electronic/cx-apikey/wiki/Quickstart"
+Issues = "https://git.cixoelectronic.pl/cixo-electronic/cx-apikey/issues"

+ 118 - 1
source/cx_apikey/apikey.py

@@ -1,4 +1,10 @@
 class apikey:
+    """
+    That class represents API key. It store api key size, prefix and
+    key itself. It could be converted into string, to store it in database
+    and it would be created by the apikey_factory. Do not create it by hand.
+    """
+
     def __init__(
         self, 
         content: str, 
@@ -6,6 +12,25 @@ class apikey:
         prefix: str, 
         prefix_separator: str
     ) -> None:
+        """
+        That is constructor, it would be generated only by apikey_factory
+        not manual in the app. Use apikey_factory, not that function.
+
+        Parameters
+        ----------
+        content : str
+            Full generated API key.
+
+        size : int
+            Size of the full API key.
+
+        prefix : str
+            API key prefix.
+
+        prefix_separator : str
+            Separation character between prefix and API key.
+        """
+        
         self.__content = content
         self.__size = size
         self.__prefix = prefix
@@ -13,32 +38,124 @@ class apikey:
 
     @property
     def content(self) -> str:
+        """
+        Full API key, which could be used in app or store in database.
+
+        Returns
+        -------
+        str
+            API key to use.
+        """
+
         return self.__content
     
     @property
     def size(self) -> int:
+        """
+        Size of the full API key.
+
+        Returns
+        -------
+        int
+            API key size.
+        """
+
         return self.__size
 
     @property
-    def prefix(self) -> str:
+    def prefix(self) -> str:    
+        """
+        Prefix of the API key. Static part before random characters.
+
+        Returns
+        -------
+        str
+            Prefix of the API key.
+        """
+
         return self.__prefix
 
     @property
     def prefix_separator(self) -> str:
+        """
+        Separator between prefix and random part of the API key.
+
+        Returns
+        -------
+        str
+            Separator between prefix and random part API key.
+        """
+
         return self.__prefix_separator
 
     @property
     def key(self) -> str:
+        """
+        API key as string. Alias of content property.
+
+        Returns
+        -------
+        str 
+            API key as string.
+        """
+
         return self.__content
 
     def compare(self, target: str | object) -> bool:
+        """
+        That compare API key with second API key. The second API key could
+        be given as string or apikey object.
+
+        Parameters
+        ----------
+        target : str
+            API key to compare with.
+
+        Returns
+        -------
+        bool
+            Comparation result.
+        """
+
         return self.__content == str(target)
 
     def __eq__(self, target: str | object) -> bool:
+        """
+        That is alias of compare function.
+
+        Parameters
+        ----------
+        target : str
+            API key to compare with.
+
+        Returns
+        -------
+        bool
+            Comparation result.
+        """
+
         return self.compare(target)
 
     def __str__(self) -> str:
+        """
+        That convert API key to string, that mean return full API key.
+
+        Returns
+        -------
+        str
+            Fill API key.
+        """
+
         return self.__content
 
     def __repr__(self) -> str:
+        """
+        That return debug info about API key.
+        
+        Returns
+        -------
+        str
+            API key debug info.
+        """
+
         return "API key: \"" + self.__content + "\""

+ 4 - 0
source/cx_apikey/apikey_exceptions.py

@@ -1,3 +1,7 @@
 class apikey_syntax_error(Exception):
+    """
+    That exception had been raised when API key is not valid.
+    """
+
     def __init__(self) -> None:
         super().__init__("That is not valid API key.")

+ 219 - 2
source/cx_apikey/apikey_factory.py

@@ -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,

+ 67 - 1
source/cx_apikey/apikey_validator.py

@@ -1,29 +1,95 @@
 from .apikey import apikey
 
 class apikey_validator:
+    """
+    That is API key validator. It check that API key have valid prefix,
+    size and separator.
+    """
+
     def __init__(
         self,
         size: int,
         prefix: str,
         prefix_separator: str
     ) -> None:
+        """
+        That is API key validator constructor, it would be used by API key 
+        validator factory, not direct.
+
+        Parameters
+        ----------
+        size : int
+            Size of the apikey validator.
+        
+        prefix : str
+            Prefix of the API key.
+
+        prefix_separator : str
+            Separator between random part of the API key and prefix.
+        """
+
         self.__size = size
         self.__prefix = prefix
         self.__prefix_separator = prefix_separator
 
     @property
     def size(self) -> int:
+        """
+        Full size of the API key.
+
+        Returns
+        -------
+        int
+            Full lenght of the API key.
+        """
+
         return self.__size
 
     @property
     def prefix(self) -> str:
+        """
+        Prefix of the API key.
+
+        Returns
+        -------
+        str
+            Prefix of the API key.
+        """
+
         return self.__prefix
 
     @property
     def prefix_separator(self) -> str:
+        """
+        Character between prefix and random part of the API key.
+
+        Returns
+        -------
+        str
+            Separator character.
+        """
+
         return self.__prefix_separator
 
-    def validate(self, content: str) -> bool:
+    def validate(self, content: str | apikey) -> bool:
+        """
+        That validate API key, check that it prefix, prefix separator and 
+        size if proof.
+
+        Parameters
+        ----------
+        content : str | apikey
+            Target to validate that is proof API key.
+
+        Returns
+        -------
+        bool    
+            Result of the validation. True when valid, False when invalid.
+        """
+
+        if type(content) is not str:
+            content = str(content)
+
         parts = content.split(self.prefix_separator)
 
         if len(parts) != 2:

+ 7 - 2
tests/003-validator.py

@@ -25,10 +25,15 @@ def test(tag: str, result: bool) -> None:
     print("FAIL!!!")
     exit(-1)
 
-factory = apikey.apikey_factory("test").set_size(10)
+factory = apikey.apikey_factory("test").set_size(15)
 sample = factory.generate()
 sample_manual = "test_1234567890"
 bad_sample = "no_1234567890"
 other_bad = "test_uuuuuuuuuu"
 
-factory.get_validator()
+validator = factory.get_validator()
+
+test("self generated", validator.validate(sample))
+test("manual writen proof", validator.validate(sample_manual))
+test("bad sample, not validated", not validator.validate(bad_sample))
+test("second bad sample, not validated", not validator.validate(other_bad))