Skip to content

Helpers

helpers.aes

helpers.aes

This module provides a class for encrypting and decrypting data using AES in GCM mode.

AESHelper

Source code in helpers/aes.py
class AESHelper:
    def __init__(self, key: bytes | str):
        """
        Initialize the AESHelper instance with the provided key.

        Args:
            key (bytes | str): The key to use for encryption and decryption.

        Returns:
            The hex-encoded AES key.

        Raises:
            TypeError: If the key is not a string or bytes.
            ValueError: If the key is not a string or bytes and cannot be converted to bytes.
        """
        if not isinstance(key, (bytes, str)):
            raise TypeError("Key must be a string or bytes.")

        if isinstance(key, str):
            key = self.try_encode_str(key)

        if not isinstance(key, bytes):
            raise ValueError("Cannot convert key to bytes.")

        if len(key) not in [16, 24, 32]:
            # This is a hacky way to resize the key to an UUID and then get the hex of it
            key = hash_bytes(key).hex.encode()

        self.key = key

    @staticmethod
    def try_encode_str(key: str) -> bytes | None:
        """
        Try to convert a string key to bytes.

        Args:
            key (str): The string key to convert.

        Returns:
            bytes | None: The converted key or None if conversion fails.
        """
        if not isinstance(key, str):
            return key
        try:
            return bytes.fromhex(key)
        except Exception:
            pass
        try:
            return key.encode()
        except Exception:
            pass

    @staticmethod
    def get_random_key(size: Literal[16, 24, 32] = 16) -> bytes:
        """
        Generate a random AES key of the specified size (16, 24, or 32 bytes).

        Args:
            size (Literal[16, 24, 32]): The size of the key to generate.

        Returns:
            bytes: The generated key as a hex-encoded string.
        """
        return get_random_bytes(size)

    @staticmethod
    def _verify_data_type(data: bytes):
        """
        Verify that the provided data is of type bytes.

        Args:
            data (bytes): The data to verify.

        Raises:
            TypeError: If the data is not bytes.
        """
        if not isinstance(data, bytes):
            raise TypeError("Data must be bytes.")

    def encrypt(self, data: bytes) -> bytes:
        """
        Encrypt data using AES in GCM mode.

        Args:
            data (bytes): The data to encrypt.

        Returns:
            bytes: The ciphertext, which includes the nonce and authentication tag.
        """
        self._verify_data_type(data)
        cipher = AES.new(self.key, AES.MODE_GCM)  # GCM mode automatically generates a nonce
        ciphertext, tag = cipher.encrypt_and_digest(data)
        return cipher.nonce + tag + ciphertext

    def decrypt(self, encrypted_data: bytes) -> bytes:
        """
        Decrypt data using AES in GCM mode.
        Extracts the nonce, tag, and ciphertext from the encrypted data.

        Args:
            encrypted_data (bytes): The encrypted data to decrypt.

        Returns:
            bytes: The decrypted data.
        """
        self._verify_data_type(encrypted_data)
        nonce = encrypted_data[:16]  # GCM nonce is 16 bytes
        tag = encrypted_data[16:32]  # GCM tag is 16 bytes
        ciphertext = encrypted_data[32:]
        cipher = AES.new(self.key, AES.MODE_GCM, nonce=nonce)
        return cipher.decrypt_and_verify(ciphertext, tag)
__init__(key)

Initialize the AESHelper instance with the provided key.

Parameters:

Name Type Description Default
key bytes | str

The key to use for encryption and decryption.

required

Returns:

Type Description

The hex-encoded AES key.

Raises:

Type Description
TypeError

If the key is not a string or bytes.

ValueError

If the key is not a string or bytes and cannot be converted to bytes.

Source code in helpers/aes.py
def __init__(self, key: bytes | str):
    """
    Initialize the AESHelper instance with the provided key.

    Args:
        key (bytes | str): The key to use for encryption and decryption.

    Returns:
        The hex-encoded AES key.

    Raises:
        TypeError: If the key is not a string or bytes.
        ValueError: If the key is not a string or bytes and cannot be converted to bytes.
    """
    if not isinstance(key, (bytes, str)):
        raise TypeError("Key must be a string or bytes.")

    if isinstance(key, str):
        key = self.try_encode_str(key)

    if not isinstance(key, bytes):
        raise ValueError("Cannot convert key to bytes.")

    if len(key) not in [16, 24, 32]:
        # This is a hacky way to resize the key to an UUID and then get the hex of it
        key = hash_bytes(key).hex.encode()

    self.key = key
decrypt(encrypted_data)

Decrypt data using AES in GCM mode. Extracts the nonce, tag, and ciphertext from the encrypted data.

Parameters:

Name Type Description Default
encrypted_data bytes

The encrypted data to decrypt.

required

Returns:

Name Type Description
bytes bytes

The decrypted data.

Source code in helpers/aes.py
def decrypt(self, encrypted_data: bytes) -> bytes:
    """
    Decrypt data using AES in GCM mode.
    Extracts the nonce, tag, and ciphertext from the encrypted data.

    Args:
        encrypted_data (bytes): The encrypted data to decrypt.

    Returns:
        bytes: The decrypted data.
    """
    self._verify_data_type(encrypted_data)
    nonce = encrypted_data[:16]  # GCM nonce is 16 bytes
    tag = encrypted_data[16:32]  # GCM tag is 16 bytes
    ciphertext = encrypted_data[32:]
    cipher = AES.new(self.key, AES.MODE_GCM, nonce=nonce)
    return cipher.decrypt_and_verify(ciphertext, tag)
encrypt(data)

Encrypt data using AES in GCM mode.

Parameters:

Name Type Description Default
data bytes

The data to encrypt.

required

Returns:

Name Type Description
bytes bytes

The ciphertext, which includes the nonce and authentication tag.

Source code in helpers/aes.py
def encrypt(self, data: bytes) -> bytes:
    """
    Encrypt data using AES in GCM mode.

    Args:
        data (bytes): The data to encrypt.

    Returns:
        bytes: The ciphertext, which includes the nonce and authentication tag.
    """
    self._verify_data_type(data)
    cipher = AES.new(self.key, AES.MODE_GCM)  # GCM mode automatically generates a nonce
    ciphertext, tag = cipher.encrypt_and_digest(data)
    return cipher.nonce + tag + ciphertext
get_random_key(size=16) staticmethod

Generate a random AES key of the specified size (16, 24, or 32 bytes).

Parameters:

Name Type Description Default
size Literal[16, 24, 32]

The size of the key to generate.

16

Returns:

Name Type Description
bytes bytes

The generated key as a hex-encoded string.

Source code in helpers/aes.py
@staticmethod
def get_random_key(size: Literal[16, 24, 32] = 16) -> bytes:
    """
    Generate a random AES key of the specified size (16, 24, or 32 bytes).

    Args:
        size (Literal[16, 24, 32]): The size of the key to generate.

    Returns:
        bytes: The generated key as a hex-encoded string.
    """
    return get_random_bytes(size)
try_encode_str(key) staticmethod

Try to convert a string key to bytes.

Parameters:

Name Type Description Default
key str

The string key to convert.

required

Returns:

Type Description
bytes | None

bytes | None: The converted key or None if conversion fails.

Source code in helpers/aes.py
@staticmethod
def try_encode_str(key: str) -> bytes | None:
    """
    Try to convert a string key to bytes.

    Args:
        key (str): The string key to convert.

    Returns:
        bytes | None: The converted key or None if conversion fails.
    """
    if not isinstance(key, str):
        return key
    try:
        return bytes.fromhex(key)
    except Exception:
        pass
    try:
        return key.encode()
    except Exception:
        pass

helpers.ecdh

helpers.ecdh

This module provides a class for Elliptic-curve Diffie-Hellman (ECDH) key exchange operations, including key pair generation, serialization/deserialization of keys, shared secret generation, and data encryption/decryption.

ECDHHelper

Helper class for ECDH key exchange operations, including key pair generation, serialization/deserialization of keys, shared secret generation, and data encryption/decryption.

Source code in helpers/ecdh.py
class ECDHHelper:
    """
    Helper class for ECDH key exchange operations, including key pair generation,
    serialization/deserialization of keys, shared secret generation, and data encryption/decryption.
    """

    @staticmethod
    @overload
    def generate_key_pair(
        out_format: Literal[KeyFormat.OBJECT, 0],
    ) -> KeyPairObjects: ...

    @staticmethod
    @overload
    def generate_key_pair(out_format: Literal[KeyFormat.BYTE, 1]) -> KeyPairBytes: ...

    @staticmethod
    @overload
    def generate_key_pair(
        out_format: Literal[KeyFormat.STRING, 2],
    ) -> KeyPairStrings: ...

    @staticmethod
    def generate_key_pair(out_format: KeyFormat | int = KeyFormat.OBJECT) -> TKeyPair:
        """
        Generates an elliptic curve key pair in the specified format.

        Args:
            out_format (KeyFormat | int): Desired output format for the key pair (OBJECT, BYTE, STRING).

        Returns:
            TKeyPair: Key pair in the specified format.
        """
        if out_format not in [KeyFormat.BYTE, KeyFormat.STRING, KeyFormat.OBJECT]:
            out_format = KeyFormat.OBJECT

        private_key = ec.generate_private_key(ec.SECP256R1(), default_backend())
        public_key = private_key.public_key()

        if out_format == KeyFormat.BYTE:
            return KeyPairBytes(
                ECDHHelper.serialize_private_key(private_key, return_type=bytes),
                ECDHHelper.serialize_public_key(public_key, return_type=bytes),
            )
        elif out_format == KeyFormat.STRING:
            return KeyPairStrings(
                ECDHHelper.serialize_private_key(private_key, return_type=str),
                ECDHHelper.serialize_public_key(public_key, return_type=str),
            )
        elif out_format == KeyFormat.OBJECT:
            return KeyPairObjects(private_key, public_key)

    @staticmethod
    def serialize_private_key(
        private_key: ec.EllipticCurvePrivateKey,
        return_type: type[StrBytes] = bytes,
    ) -> StrBytes:
        """
        Serializes a private key to PEM format.

        Args:
            private_key (ec.EllipticCurvePrivateKey): Elliptic curve private key.
            return_type (type[StrBytes]): Whether to return the serialized key as a string or bytes.

        Returns:
            StrBytes: Serialized private key in PEM format.
        """
        key = private_key.private_bytes(
            encoding=serialization.Encoding.PEM,
            format=serialization.PrivateFormat.TraditionalOpenSSL,
            encryption_algorithm=serialization.NoEncryption(),
        )
        return key.decode() if return_type is str else key

    @staticmethod
    def deserialize_private_key(data: bytes | str):
        """
        Deserializes a PEM-encoded private key from bytes or hex string.

        Args:
            data (bytes | str): Serialized private key in bytes or hex string format.

        Returns:
            ec.EllipticCurvePrivateKey: Elliptic curve private key object.
        """
        if isinstance(data, str):
            data = bytes.fromhex(data)
        return serialization.load_pem_private_key(
            data, password=None, backend=default_backend()
        )

    @staticmethod
    def serialize_public_key(
        public_key: ec.EllipticCurvePublicKey,
        return_type: type[StrBytes] = bytes,
    ) -> StrBytes:
        """
        Serializes a public key to PEM format.

        Args:
            public_key (ec.EllipticCurvePublicKey): Elliptic curve public key.
            return_type (type[StrBytes]): Whether to return the serialized key as a string or bytes.

        Returns:
            StrBytes: Serialized public key in PEM format.
        """
        key = public_key.public_bytes(
            encoding=serialization.Encoding.PEM,
            format=serialization.PublicFormat.SubjectPublicKeyInfo,
        )
        return key.decode() if return_type is str else key

    @staticmethod
    def deserialize_public_key(data: bytes | str):
        """
        Deserializes a PEM-encoded public key from bytes or hex string.

        Args:
            data (bytes | str): Serialized public key in bytes or hex string format.

        Returns:
            ec.EllipticCurvePublicKey: Elliptic curve public key object.
        """
        if isinstance(data, str):
            data = bytes.fromhex(data)
        return serialization.load_pem_public_key(data, backend=default_backend())

    @staticmethod
    def generate_shared_secret(
        private_key: ec.EllipticCurvePrivateKey,
        public_key: ec.EllipticCurvePublicKey,
    ) -> bytes:
        """
        Generates a shared secret using ECDH key exchange.

        Args:
            private_key (ec.EllipticCurvePrivateKey): Elliptic curve private key.
            public_key (ec.EllipticCurvePublicKey): Elliptic curve public key.

        Returns:
            bytes: Shared secret bytes.
        """
        shared_secret = private_key.exchange(ec.ECDH(), public_key)
        return shared_secret

    @staticmethod
    def encrypt_data(data: bytes, shared_secret: bytes) -> bytes:
        """
        Encrypts data using AES encryption with the given shared secret.

        Args:
            data (bytes): Data to encrypt.
            shared_secret (bytes): Shared secret used for encryption.

        Returns:
            bytes: Encrypted data (ciphertext).
        """
        ciphertext = AESHelper(shared_secret).encrypt(data)
        return ciphertext

    @staticmethod
    def decrypt_data(ciphertext: bytes, shared_secret: bytes) -> bytes:
        """
        Decrypts data using AES encryption with the given shared secret.

        Args:
            ciphertext (bytes): Encrypted data (ciphertext).
            shared_secret (bytes): Shared secret used for decryption.

        Returns:
            bytes: Decrypted data.
        """
        data = AESHelper(shared_secret).decrypt(ciphertext)
        return data
decrypt_data(ciphertext, shared_secret) staticmethod

Decrypts data using AES encryption with the given shared secret.

Parameters:

Name Type Description Default
ciphertext bytes

Encrypted data (ciphertext).

required
shared_secret bytes

Shared secret used for decryption.

required

Returns:

Name Type Description
bytes bytes

Decrypted data.

Source code in helpers/ecdh.py
@staticmethod
def decrypt_data(ciphertext: bytes, shared_secret: bytes) -> bytes:
    """
    Decrypts data using AES encryption with the given shared secret.

    Args:
        ciphertext (bytes): Encrypted data (ciphertext).
        shared_secret (bytes): Shared secret used for decryption.

    Returns:
        bytes: Decrypted data.
    """
    data = AESHelper(shared_secret).decrypt(ciphertext)
    return data
deserialize_private_key(data) staticmethod

Deserializes a PEM-encoded private key from bytes or hex string.

Parameters:

Name Type Description Default
data bytes | str

Serialized private key in bytes or hex string format.

required

Returns:

Type Description

ec.EllipticCurvePrivateKey: Elliptic curve private key object.

Source code in helpers/ecdh.py
@staticmethod
def deserialize_private_key(data: bytes | str):
    """
    Deserializes a PEM-encoded private key from bytes or hex string.

    Args:
        data (bytes | str): Serialized private key in bytes or hex string format.

    Returns:
        ec.EllipticCurvePrivateKey: Elliptic curve private key object.
    """
    if isinstance(data, str):
        data = bytes.fromhex(data)
    return serialization.load_pem_private_key(
        data, password=None, backend=default_backend()
    )
deserialize_public_key(data) staticmethod

Deserializes a PEM-encoded public key from bytes or hex string.

Parameters:

Name Type Description Default
data bytes | str

Serialized public key in bytes or hex string format.

required

Returns:

Type Description

ec.EllipticCurvePublicKey: Elliptic curve public key object.

Source code in helpers/ecdh.py
@staticmethod
def deserialize_public_key(data: bytes | str):
    """
    Deserializes a PEM-encoded public key from bytes or hex string.

    Args:
        data (bytes | str): Serialized public key in bytes or hex string format.

    Returns:
        ec.EllipticCurvePublicKey: Elliptic curve public key object.
    """
    if isinstance(data, str):
        data = bytes.fromhex(data)
    return serialization.load_pem_public_key(data, backend=default_backend())
encrypt_data(data, shared_secret) staticmethod

Encrypts data using AES encryption with the given shared secret.

Parameters:

Name Type Description Default
data bytes

Data to encrypt.

required
shared_secret bytes

Shared secret used for encryption.

required

Returns:

Name Type Description
bytes bytes

Encrypted data (ciphertext).

Source code in helpers/ecdh.py
@staticmethod
def encrypt_data(data: bytes, shared_secret: bytes) -> bytes:
    """
    Encrypts data using AES encryption with the given shared secret.

    Args:
        data (bytes): Data to encrypt.
        shared_secret (bytes): Shared secret used for encryption.

    Returns:
        bytes: Encrypted data (ciphertext).
    """
    ciphertext = AESHelper(shared_secret).encrypt(data)
    return ciphertext
generate_key_pair(out_format=KeyFormat.OBJECT) staticmethod
generate_key_pair(out_format: Literal[KeyFormat.OBJECT, 0]) -> KeyPairObjects
generate_key_pair(out_format: Literal[KeyFormat.BYTE, 1]) -> KeyPairBytes
generate_key_pair(out_format: Literal[KeyFormat.STRING, 2]) -> KeyPairStrings

Generates an elliptic curve key pair in the specified format.

Parameters:

Name Type Description Default
out_format KeyFormat | int

Desired output format for the key pair (OBJECT, BYTE, STRING).

OBJECT

Returns:

Name Type Description
TKeyPair TKeyPair

Key pair in the specified format.

Source code in helpers/ecdh.py
@staticmethod
def generate_key_pair(out_format: KeyFormat | int = KeyFormat.OBJECT) -> TKeyPair:
    """
    Generates an elliptic curve key pair in the specified format.

    Args:
        out_format (KeyFormat | int): Desired output format for the key pair (OBJECT, BYTE, STRING).

    Returns:
        TKeyPair: Key pair in the specified format.
    """
    if out_format not in [KeyFormat.BYTE, KeyFormat.STRING, KeyFormat.OBJECT]:
        out_format = KeyFormat.OBJECT

    private_key = ec.generate_private_key(ec.SECP256R1(), default_backend())
    public_key = private_key.public_key()

    if out_format == KeyFormat.BYTE:
        return KeyPairBytes(
            ECDHHelper.serialize_private_key(private_key, return_type=bytes),
            ECDHHelper.serialize_public_key(public_key, return_type=bytes),
        )
    elif out_format == KeyFormat.STRING:
        return KeyPairStrings(
            ECDHHelper.serialize_private_key(private_key, return_type=str),
            ECDHHelper.serialize_public_key(public_key, return_type=str),
        )
    elif out_format == KeyFormat.OBJECT:
        return KeyPairObjects(private_key, public_key)
generate_shared_secret(private_key, public_key) staticmethod

Generates a shared secret using ECDH key exchange.

Parameters:

Name Type Description Default
private_key EllipticCurvePrivateKey

Elliptic curve private key.

required
public_key EllipticCurvePublicKey

Elliptic curve public key.

required

Returns:

Name Type Description
bytes bytes

Shared secret bytes.

Source code in helpers/ecdh.py
@staticmethod
def generate_shared_secret(
    private_key: ec.EllipticCurvePrivateKey,
    public_key: ec.EllipticCurvePublicKey,
) -> bytes:
    """
    Generates a shared secret using ECDH key exchange.

    Args:
        private_key (ec.EllipticCurvePrivateKey): Elliptic curve private key.
        public_key (ec.EllipticCurvePublicKey): Elliptic curve public key.

    Returns:
        bytes: Shared secret bytes.
    """
    shared_secret = private_key.exchange(ec.ECDH(), public_key)
    return shared_secret
serialize_private_key(private_key, return_type=bytes) staticmethod

Serializes a private key to PEM format.

Parameters:

Name Type Description Default
private_key EllipticCurvePrivateKey

Elliptic curve private key.

required
return_type type[StrBytes]

Whether to return the serialized key as a string or bytes.

bytes

Returns:

Name Type Description
StrBytes StrBytes

Serialized private key in PEM format.

Source code in helpers/ecdh.py
@staticmethod
def serialize_private_key(
    private_key: ec.EllipticCurvePrivateKey,
    return_type: type[StrBytes] = bytes,
) -> StrBytes:
    """
    Serializes a private key to PEM format.

    Args:
        private_key (ec.EllipticCurvePrivateKey): Elliptic curve private key.
        return_type (type[StrBytes]): Whether to return the serialized key as a string or bytes.

    Returns:
        StrBytes: Serialized private key in PEM format.
    """
    key = private_key.private_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PrivateFormat.TraditionalOpenSSL,
        encryption_algorithm=serialization.NoEncryption(),
    )
    return key.decode() if return_type is str else key
serialize_public_key(public_key, return_type=bytes) staticmethod

Serializes a public key to PEM format.

Parameters:

Name Type Description Default
public_key EllipticCurvePublicKey

Elliptic curve public key.

required
return_type type[StrBytes]

Whether to return the serialized key as a string or bytes.

bytes

Returns:

Name Type Description
StrBytes StrBytes

Serialized public key in PEM format.

Source code in helpers/ecdh.py
@staticmethod
def serialize_public_key(
    public_key: ec.EllipticCurvePublicKey,
    return_type: type[StrBytes] = bytes,
) -> StrBytes:
    """
    Serializes a public key to PEM format.

    Args:
        public_key (ec.EllipticCurvePublicKey): Elliptic curve public key.
        return_type (type[StrBytes]): Whether to return the serialized key as a string or bytes.

    Returns:
        StrBytes: Serialized public key in PEM format.
    """
    key = public_key.public_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PublicFormat.SubjectPublicKeyInfo,
    )
    return key.decode() if return_type is str else key

helpers.jwt_token

helpers.jwt_token

create_access_token(data, expires_delta=timedelta(minutes=JWT_EXPIRE_MINUTES))

Generates a JWT token.

Parameters:

Name Type Description Default
data dict[str, str]

The payload of the JWT token.

required
expires_delta timedelta

The time delta for token expiration. Defaults to timedelta(minutes=JWT_EXPIRE_MINUTES).

timedelta(minutes=JWT_EXPIRE_MINUTES)

Returns:

Name Type Description
str str

The generated JWT token.

Source code in helpers/jwt_token.py
def create_access_token(
    data: dict[str, str], expires_delta: timedelta = timedelta(minutes=JWT_EXPIRE_MINUTES)
) -> str:
    """Generates a JWT token.

    Args:
        data (dict[str, str]): The payload of the JWT token.
        expires_delta (timedelta, optional): The time delta for token expiration. Defaults to timedelta(minutes=JWT_EXPIRE_MINUTES).

    Returns:
        str: The generated JWT token.
    """
    to_encode = data.copy()
    if expires_delta:
        expire = datetime.now(tz=timezone.utc) + expires_delta
    else:
        expire = datetime.now(tz=timezone.utc) + timedelta(minutes=15)
    to_encode.update({"exp": expire})
    return jwt.encode(to_encode, JWT_SECRET_KEY, algorithm=JWT_ALGORITHM)

decode_access_token(token)

Decodes and validates a JWT token. Returns the username and password.

Parameters:

Name Type Description Default
token str

The JWT token to decode.

required

Returns:

Type Description
tuple[str, str]

tuple[str, str]: A tuple containing the username and password.

Source code in helpers/jwt_token.py
def decode_access_token(token: str) -> tuple[str, str]:
    """Decodes and validates a JWT token. Returns the username and password.

    Args:
        token (str): The JWT token to decode.

    Returns:
        tuple[str, str]: A tuple containing the username and password.
    """
    try:
        payload: dict[str, str] = jwt.decode(token, JWT_SECRET_KEY, algorithms=[JWT_ALGORITHM])
        username: str = payload.get("username")
        password: str = payload.get("password")
        if username is None:
            raise _get_exception("Invalid token payload")
        return username, password
    except jwt.ExpiredSignatureError:
        raise _get_exception("Token has expired")
    except jwt.exceptions.PyJWTError:
        raise _get_exception("Invalid token")

helpers.rsa

helpers.rsa

This module provides a class for RSA key exchange operations, including key pair generation, serialization/deserialization of keys, and data encryption/decryption.

RSAHelper

Helper class for RSA key exchange operations, including key pair generation, serialization/deserialization of keys, and data encryption/decryption.

Source code in helpers/rsa.py
class RSAHelper:
    """
    Helper class for RSA key exchange operations, including key pair generation,
    serialization/deserialization of keys, and data encryption/decryption.
    """

    @staticmethod
    @overload
    def generate_key_pair(out_format: Literal[KeyFormat.OBJECT, 0]) -> KeyPairObjects:
        ...

    @staticmethod
    @overload
    def generate_key_pair(out_format: Literal[KeyFormat.BYTE, 1]) -> KeyPairBytes:
        ...

    @staticmethod
    @overload
    def generate_key_pair(out_format: Literal[KeyFormat.STRING, 2]) -> KeyPairStrings:
        ...

    @staticmethod
    def generate_key_pair(out_format: KeyFormat | int = KeyFormat.OBJECT) -> TKeyPair:
        """
        Generates an RSA key pair in the specified format.

        Args:
            out_format (KeyFormat): Desired output format for the key pair (OBJECT, BYTE, STRING)

        Returns:
            TKeyPair: Key pair in the specified format
        """
        if out_format not in [KeyFormat.BYTE, KeyFormat.STRING, KeyFormat.OBJECT]:
            out_format = KeyFormat.OBJECT

        private_key = rsa.generate_private_key(
            public_exponent=65537,
            key_size=2048,
            backend=default_backend(),
        )
        public_key = private_key.public_key()

        if out_format == KeyFormat.BYTE:
            return KeyPairBytes(
                RSAHelper.serialize_private_key(private_key, return_type=bytes),
                RSAHelper.serialize_public_key(public_key, return_type=bytes),
            )
        elif out_format == KeyFormat.STRING:
            return KeyPairStrings(
                RSAHelper.serialize_private_key(private_key, return_type=str),
                RSAHelper.serialize_public_key(public_key, return_type=str),
            )
        elif out_format == KeyFormat.OBJECT:
            return KeyPairObjects(private_key, public_key)

    @staticmethod
    def serialize_private_key(private_key: rsa.RSAPrivateKey, return_type: type[StrBytes] = bytes) -> StrBytes:
        """
        Serializes a private key to PEM format.

        Args:
            private_key (rsa.RSAPrivateKey): RSA private key
            return_type (type[StrBytes]): Whether to return the serialized key as a string or bytes

        Returns:
            StrBytes: Serialized private key in PEM format as a string or bytes
        """
        key = private_key.private_bytes(
            encoding=serialization.Encoding.PEM,
            format=serialization.PrivateFormat.PKCS8,
            encryption_algorithm=serialization.NoEncryption(),
        )
        return key.decode() if return_type is str else key

    @staticmethod
    def deserialize_private_key(data: bytes | str) -> rsa.RSAPrivateKey:
        """
        Deserializes a PEM-encoded private key from bytes or hex string.

        Args:
            data (bytes | str): Serialized private key in bytes or hex string format.

        Returns:
            rsa.RSAPrivateKey: Elliptic curve private key object.
        """
        if isinstance(data, str):
            data = data.encode()
        try:
            key = serialization.load_pem_private_key(
                data, password=None, backend=default_backend()
            )
            return key
        except Exception as e:
            raise ValueError(f"Failed to deserialize private key: {e}")

    @staticmethod
    def serialize_public_key(public_key: rsa.RSAPublicKey, return_type: type[StrBytes] = bytes) -> StrBytes:
        """
        Serializes a public key to PEM format.

        Args:
            public_key (rsa.RSAPublicKey): RSA public key
            return_type (type[StrBytes]): Desired return type for the serialized key (str or bytes)

        Returns:
            StrBytes: Serialized public key in PEM format as a string or bytes
        """
        key = public_key.public_bytes(
            encoding=serialization.Encoding.PEM,
            format=serialization.PublicFormat.SubjectPublicKeyInfo,
        )
        return key.decode() if return_type is str else key

    @staticmethod
    def deserialize_public_key(data: bytes | str) -> rsa.RSAPublicKey:
        """
        Deserializes a PEM-encoded public key from bytes or hex string.

        Args:
            data (bytes | str): Serialized public key in bytes or hex string format

        Returns:
            rsa.RSAPublicKey: RSA public key object
        """
        if isinstance(data, str):
            data = data.encode()
        try:
            key = serialization.load_pem_public_key(data, backend=default_backend())
            return key
        except Exception as e:
            raise ValueError(f"Failed to deserialize public key: {e}")

    @staticmethod
    def get_padding() -> padding.OAEP:
        """
        Returns an OAEP padding object configured with MGF1 using SHA-256
        as the hash algorithm. This padding is used for RSA encryption
        to provide additional security measures, such as preventing
        chosen ciphertext attacks. No label is used in this configuration.

        Returns:
            padding.OAEP: OAEP padding object configured with MGF1 using SHA-256
        """
        return padding.OAEP(
            mgf=padding.MGF1(algorithm=hashes.SHA256()),  # Mask generation function
            algorithm=hashes.SHA256(),  # Hash algorithm used for OAEP
            label=None,  # No label is used
        )

    @staticmethod
    def encrypt_data(data: bytes, public_key: rsa.RSAPublicKey | str | bytes) -> bytes:
        """
        Encrypts data using AES encryption with the given shared secret.

        Args:
            data (bytes): Data to encrypt
            public_key (rsa.RSAPublicKey | str | bytes): Public key used for encryption, can be an RSAPublicKey object, a PEM string, or bytes

        Returns:
            bytes: Encrypted data (ciphertext)
        """
        if isinstance(public_key, (str, bytes)):
            public_key = RSAHelper.deserialize_public_key(public_key)
        ciphertext = public_key.encrypt(data, RSAHelper.get_padding())
        return ciphertext

    @staticmethod
    def decrypt_data(
        ciphertext: bytes, private_key: rsa.RSAPrivateKey | str | bytes
    ) -> bytes:
        """
        Decrypt data using AES encryption with the given shared secret.

        Args:
            ciphertext (bytes): Encrypted data (ciphertext)
            private_key (rsa.RSAPrivateKey | str | bytes): Private key used for decryption, can be an RSAPrivateKey object, a PEM string, or bytes

        Returns:
            bytes: Decrypted data
        """
        if isinstance(private_key, (str, bytes)):
            private_key = RSAHelper.deserialize_private_key(private_key)
        data = private_key.decrypt(ciphertext, RSAHelper.get_padding())
        return data

    @staticmethod
    def sign_data(data: bytes, private_key: rsa.RSAPrivateKey | str | bytes) -> bytes:
        """
        Signs the given data using the provided private key.

        Args:
            data (bytes): Data to be signed
            private_key (rsa.RSAPrivateKey | str | bytes): Private key used for signing, can be an RSAPrivateKey object, a PEM string, or bytes

        Returns:
            bytes: The generated signature as bytes
        """
        if isinstance(private_key, (str, bytes)):
            private_key = RSAHelper.deserialize_private_key(private_key)
        signature = private_key.sign(data, RSAHelper.get_padding(), hashes.SHA256())
        return signature

    @staticmethod
    def verify_signature(
        data: bytes, signature: bytes, public_key: rsa.RSAPublicKey | str | bytes
    ) -> bool:
        """
        Verifies the given signature against the given data and public key.

        Args:
            data (bytes): Data that was signed
            signature (bytes): Signature to verify
            public_key (rsa.RSAPublicKey | str | bytes): Public key to use for verification, can be an RSAPublicKey object, a PEM string, or bytes

        Returns:
            bool: True if the signature is valid, False otherwise
        """
        if isinstance(public_key, (str, bytes)):
            public_key = RSAHelper.deserialize_public_key(public_key)
        try:
            public_key.verify(signature, data, RSAHelper.get_padding(), hashes.SHA256())
            return True
        except Exception:
            return False

    @staticmethod
    def verify_key_pair(
        private_key: rsa.RSAPrivateKey | str | bytes,
        public_key: rsa.RSAPublicKey | str | bytes,
    ) -> bool:
        """
        Verifies that the given private and public key are a matching pair.

        Args:
            private_key (rsa.RSAPrivateKey | str | bytes): Private key to verify, can be an RSAPrivateKey object, a PEM string, or bytes
            public_key (rsa.RSAPublicKey | str | bytes): Public key to verify, can be an RSAPublicKey object, a PEM string, or bytes

        Returns:
            bool: True if the key pair is valid, False otherwise
        """
        if isinstance(private_key, (str, bytes)):
            private_key = RSAHelper.deserialize_private_key(private_key)
        if isinstance(public_key, (str, bytes)):
            public_key = RSAHelper.deserialize_public_key(public_key)
        return private_key.public_key() == public_key
decrypt_data(ciphertext, private_key) staticmethod

Decrypt data using AES encryption with the given shared secret.

Parameters:

Name Type Description Default
ciphertext bytes

Encrypted data (ciphertext)

required
private_key RSAPrivateKey | str | bytes

Private key used for decryption, can be an RSAPrivateKey object, a PEM string, or bytes

required

Returns:

Name Type Description
bytes bytes

Decrypted data

Source code in helpers/rsa.py
@staticmethod
def decrypt_data(
    ciphertext: bytes, private_key: rsa.RSAPrivateKey | str | bytes
) -> bytes:
    """
    Decrypt data using AES encryption with the given shared secret.

    Args:
        ciphertext (bytes): Encrypted data (ciphertext)
        private_key (rsa.RSAPrivateKey | str | bytes): Private key used for decryption, can be an RSAPrivateKey object, a PEM string, or bytes

    Returns:
        bytes: Decrypted data
    """
    if isinstance(private_key, (str, bytes)):
        private_key = RSAHelper.deserialize_private_key(private_key)
    data = private_key.decrypt(ciphertext, RSAHelper.get_padding())
    return data
deserialize_private_key(data) staticmethod

Deserializes a PEM-encoded private key from bytes or hex string.

Parameters:

Name Type Description Default
data bytes | str

Serialized private key in bytes or hex string format.

required

Returns:

Type Description
RSAPrivateKey

rsa.RSAPrivateKey: Elliptic curve private key object.

Source code in helpers/rsa.py
@staticmethod
def deserialize_private_key(data: bytes | str) -> rsa.RSAPrivateKey:
    """
    Deserializes a PEM-encoded private key from bytes or hex string.

    Args:
        data (bytes | str): Serialized private key in bytes or hex string format.

    Returns:
        rsa.RSAPrivateKey: Elliptic curve private key object.
    """
    if isinstance(data, str):
        data = data.encode()
    try:
        key = serialization.load_pem_private_key(
            data, password=None, backend=default_backend()
        )
        return key
    except Exception as e:
        raise ValueError(f"Failed to deserialize private key: {e}")
deserialize_public_key(data) staticmethod

Deserializes a PEM-encoded public key from bytes or hex string.

Parameters:

Name Type Description Default
data bytes | str

Serialized public key in bytes or hex string format

required

Returns:

Type Description
RSAPublicKey

rsa.RSAPublicKey: RSA public key object

Source code in helpers/rsa.py
@staticmethod
def deserialize_public_key(data: bytes | str) -> rsa.RSAPublicKey:
    """
    Deserializes a PEM-encoded public key from bytes or hex string.

    Args:
        data (bytes | str): Serialized public key in bytes or hex string format

    Returns:
        rsa.RSAPublicKey: RSA public key object
    """
    if isinstance(data, str):
        data = data.encode()
    try:
        key = serialization.load_pem_public_key(data, backend=default_backend())
        return key
    except Exception as e:
        raise ValueError(f"Failed to deserialize public key: {e}")
encrypt_data(data, public_key) staticmethod

Encrypts data using AES encryption with the given shared secret.

Parameters:

Name Type Description Default
data bytes

Data to encrypt

required
public_key RSAPublicKey | str | bytes

Public key used for encryption, can be an RSAPublicKey object, a PEM string, or bytes

required

Returns:

Name Type Description
bytes bytes

Encrypted data (ciphertext)

Source code in helpers/rsa.py
@staticmethod
def encrypt_data(data: bytes, public_key: rsa.RSAPublicKey | str | bytes) -> bytes:
    """
    Encrypts data using AES encryption with the given shared secret.

    Args:
        data (bytes): Data to encrypt
        public_key (rsa.RSAPublicKey | str | bytes): Public key used for encryption, can be an RSAPublicKey object, a PEM string, or bytes

    Returns:
        bytes: Encrypted data (ciphertext)
    """
    if isinstance(public_key, (str, bytes)):
        public_key = RSAHelper.deserialize_public_key(public_key)
    ciphertext = public_key.encrypt(data, RSAHelper.get_padding())
    return ciphertext
generate_key_pair(out_format=KeyFormat.OBJECT) staticmethod
generate_key_pair(out_format: Literal[KeyFormat.OBJECT, 0]) -> KeyPairObjects
generate_key_pair(out_format: Literal[KeyFormat.BYTE, 1]) -> KeyPairBytes
generate_key_pair(out_format: Literal[KeyFormat.STRING, 2]) -> KeyPairStrings

Generates an RSA key pair in the specified format.

Parameters:

Name Type Description Default
out_format KeyFormat

Desired output format for the key pair (OBJECT, BYTE, STRING)

OBJECT

Returns:

Name Type Description
TKeyPair TKeyPair

Key pair in the specified format

Source code in helpers/rsa.py
@staticmethod
def generate_key_pair(out_format: KeyFormat | int = KeyFormat.OBJECT) -> TKeyPair:
    """
    Generates an RSA key pair in the specified format.

    Args:
        out_format (KeyFormat): Desired output format for the key pair (OBJECT, BYTE, STRING)

    Returns:
        TKeyPair: Key pair in the specified format
    """
    if out_format not in [KeyFormat.BYTE, KeyFormat.STRING, KeyFormat.OBJECT]:
        out_format = KeyFormat.OBJECT

    private_key = rsa.generate_private_key(
        public_exponent=65537,
        key_size=2048,
        backend=default_backend(),
    )
    public_key = private_key.public_key()

    if out_format == KeyFormat.BYTE:
        return KeyPairBytes(
            RSAHelper.serialize_private_key(private_key, return_type=bytes),
            RSAHelper.serialize_public_key(public_key, return_type=bytes),
        )
    elif out_format == KeyFormat.STRING:
        return KeyPairStrings(
            RSAHelper.serialize_private_key(private_key, return_type=str),
            RSAHelper.serialize_public_key(public_key, return_type=str),
        )
    elif out_format == KeyFormat.OBJECT:
        return KeyPairObjects(private_key, public_key)
get_padding() staticmethod

Returns an OAEP padding object configured with MGF1 using SHA-256 as the hash algorithm. This padding is used for RSA encryption to provide additional security measures, such as preventing chosen ciphertext attacks. No label is used in this configuration.

Returns:

Type Description
OAEP

padding.OAEP: OAEP padding object configured with MGF1 using SHA-256

Source code in helpers/rsa.py
@staticmethod
def get_padding() -> padding.OAEP:
    """
    Returns an OAEP padding object configured with MGF1 using SHA-256
    as the hash algorithm. This padding is used for RSA encryption
    to provide additional security measures, such as preventing
    chosen ciphertext attacks. No label is used in this configuration.

    Returns:
        padding.OAEP: OAEP padding object configured with MGF1 using SHA-256
    """
    return padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA256()),  # Mask generation function
        algorithm=hashes.SHA256(),  # Hash algorithm used for OAEP
        label=None,  # No label is used
    )
serialize_private_key(private_key, return_type=bytes) staticmethod

Serializes a private key to PEM format.

Parameters:

Name Type Description Default
private_key RSAPrivateKey

RSA private key

required
return_type type[StrBytes]

Whether to return the serialized key as a string or bytes

bytes

Returns:

Name Type Description
StrBytes StrBytes

Serialized private key in PEM format as a string or bytes

Source code in helpers/rsa.py
@staticmethod
def serialize_private_key(private_key: rsa.RSAPrivateKey, return_type: type[StrBytes] = bytes) -> StrBytes:
    """
    Serializes a private key to PEM format.

    Args:
        private_key (rsa.RSAPrivateKey): RSA private key
        return_type (type[StrBytes]): Whether to return the serialized key as a string or bytes

    Returns:
        StrBytes: Serialized private key in PEM format as a string or bytes
    """
    key = private_key.private_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PrivateFormat.PKCS8,
        encryption_algorithm=serialization.NoEncryption(),
    )
    return key.decode() if return_type is str else key
serialize_public_key(public_key, return_type=bytes) staticmethod

Serializes a public key to PEM format.

Parameters:

Name Type Description Default
public_key RSAPublicKey

RSA public key

required
return_type type[StrBytes]

Desired return type for the serialized key (str or bytes)

bytes

Returns:

Name Type Description
StrBytes StrBytes

Serialized public key in PEM format as a string or bytes

Source code in helpers/rsa.py
@staticmethod
def serialize_public_key(public_key: rsa.RSAPublicKey, return_type: type[StrBytes] = bytes) -> StrBytes:
    """
    Serializes a public key to PEM format.

    Args:
        public_key (rsa.RSAPublicKey): RSA public key
        return_type (type[StrBytes]): Desired return type for the serialized key (str or bytes)

    Returns:
        StrBytes: Serialized public key in PEM format as a string or bytes
    """
    key = public_key.public_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PublicFormat.SubjectPublicKeyInfo,
    )
    return key.decode() if return_type is str else key
sign_data(data, private_key) staticmethod

Signs the given data using the provided private key.

Parameters:

Name Type Description Default
data bytes

Data to be signed

required
private_key RSAPrivateKey | str | bytes

Private key used for signing, can be an RSAPrivateKey object, a PEM string, or bytes

required

Returns:

Name Type Description
bytes bytes

The generated signature as bytes

Source code in helpers/rsa.py
@staticmethod
def sign_data(data: bytes, private_key: rsa.RSAPrivateKey | str | bytes) -> bytes:
    """
    Signs the given data using the provided private key.

    Args:
        data (bytes): Data to be signed
        private_key (rsa.RSAPrivateKey | str | bytes): Private key used for signing, can be an RSAPrivateKey object, a PEM string, or bytes

    Returns:
        bytes: The generated signature as bytes
    """
    if isinstance(private_key, (str, bytes)):
        private_key = RSAHelper.deserialize_private_key(private_key)
    signature = private_key.sign(data, RSAHelper.get_padding(), hashes.SHA256())
    return signature
verify_key_pair(private_key, public_key) staticmethod

Verifies that the given private and public key are a matching pair.

Parameters:

Name Type Description Default
private_key RSAPrivateKey | str | bytes

Private key to verify, can be an RSAPrivateKey object, a PEM string, or bytes

required
public_key RSAPublicKey | str | bytes

Public key to verify, can be an RSAPublicKey object, a PEM string, or bytes

required

Returns:

Name Type Description
bool bool

True if the key pair is valid, False otherwise

Source code in helpers/rsa.py
@staticmethod
def verify_key_pair(
    private_key: rsa.RSAPrivateKey | str | bytes,
    public_key: rsa.RSAPublicKey | str | bytes,
) -> bool:
    """
    Verifies that the given private and public key are a matching pair.

    Args:
        private_key (rsa.RSAPrivateKey | str | bytes): Private key to verify, can be an RSAPrivateKey object, a PEM string, or bytes
        public_key (rsa.RSAPublicKey | str | bytes): Public key to verify, can be an RSAPublicKey object, a PEM string, or bytes

    Returns:
        bool: True if the key pair is valid, False otherwise
    """
    if isinstance(private_key, (str, bytes)):
        private_key = RSAHelper.deserialize_private_key(private_key)
    if isinstance(public_key, (str, bytes)):
        public_key = RSAHelper.deserialize_public_key(public_key)
    return private_key.public_key() == public_key
verify_signature(data, signature, public_key) staticmethod

Verifies the given signature against the given data and public key.

Parameters:

Name Type Description Default
data bytes

Data that was signed

required
signature bytes

Signature to verify

required
public_key RSAPublicKey | str | bytes

Public key to use for verification, can be an RSAPublicKey object, a PEM string, or bytes

required

Returns:

Name Type Description
bool bool

True if the signature is valid, False otherwise

Source code in helpers/rsa.py
@staticmethod
def verify_signature(
    data: bytes, signature: bytes, public_key: rsa.RSAPublicKey | str | bytes
) -> bool:
    """
    Verifies the given signature against the given data and public key.

    Args:
        data (bytes): Data that was signed
        signature (bytes): Signature to verify
        public_key (rsa.RSAPublicKey | str | bytes): Public key to use for verification, can be an RSAPublicKey object, a PEM string, or bytes

    Returns:
        bool: True if the signature is valid, False otherwise
    """
    if isinstance(public_key, (str, bytes)):
        public_key = RSAHelper.deserialize_public_key(public_key)
    try:
        public_key.verify(signature, data, RSAHelper.get_padding(), hashes.SHA256())
        return True
    except Exception:
        return False

helpers.utils

helpers.utils

hash_bytes(data, algorithm='sha256', return_type=uuid.UUID)

Calculate the hash of the given bytes using the specified algorithm.

Parameters:

Name Type Description Default
data bytes

The data to be hashed.

required
algorithm str

Hashing algorithm to use (default is 'sha256'). Options include 'md5', 'sha1', 'sha256', 'sha512', etc.

'sha256'
return_type type[str | UUID]

Type to return the hash as (default is uuid.UUID).

UUID

Returns:

Type Description
StrUuid

str | uuid.UUID: The hash of the data as a string or UUID.

Source code in helpers/utils.py
def hash_bytes(
    data: bytes, algorithm="sha256", return_type: type[StrUuid] = uuid.UUID
) -> StrUuid:
    """
    Calculate the hash of the given bytes using the specified algorithm.

    Args:
        data (bytes): The data to be hashed.
        algorithm (str): Hashing algorithm to use (default is 'sha256').
                         Options include 'md5', 'sha1', 'sha256', 'sha512', etc.
        return_type (type[str | uuid.UUID]): Type to return the hash as (default is uuid.UUID).

    Returns:
        str | uuid.UUID: The hash of the data as a string or UUID.
    """

    return hash_file(data, algorithm, return_type)

hash_file(file, algorithm='sha256', return_type=uuid.UUID)

Calculate the hash of a file or its contents.

Parameters:

Name Type Description Default
file str | Path | bytes

Path to the file or contents of the file as bytes.

required
algorithm str

Hashing algorithm (default is 'sha256'). Options include 'md5', 'sha1', 'sha256', 'sha512', etc.

'sha256'
return_type type[str | UUID]

Type to return the hash as (default is uuid.UUID).

UUID

Returns:

Type Description
StrUuid

str | uuid.UUID: The hash of the file or its contents as a string or UUID.

Source code in helpers/utils.py
def hash_file(
    file: str | Path | bytes, algorithm="sha256", return_type: type[StrUuid] = uuid.UUID
) -> StrUuid:
    """
    Calculate the hash of a file or its contents.

    Args:
        file (str  | Path | bytes): Path to the file or contents of the file as bytes.
        algorithm (str): Hashing algorithm (default is 'sha256').
                         Options include 'md5', 'sha1', 'sha256', 'sha512', etc.
        return_type (type[str | uuid.UUID]): Type to return the hash as (default is uuid.UUID).

    Returns:
        str | uuid.UUID: The hash of the file or its contents as a string or UUID.
    """
    hash_func = hashlib.new(algorithm)
    buffer_size = 65536  # Read in chunks of 64 KB

    if isinstance(file, (str, Path)):
        if not Path(file).exists():
            raise FileNotFoundError(
                f"The file '{file}' does not exist in the local file system."
            )
        file_reader = open(file, "rb")
    else:
        file_reader = BytesIO(file)

    try:
        while chunk := file_reader.read(buffer_size):
            hash_func.update(chunk)
        _hash = hash_func.hexdigest()
        if return_type == uuid.UUID:
            return hash_text(_hash)
        return _hash
    finally:
        file_reader.close()

hash_text(text, base_uuid=None)

Generates a hash-based UUID using the given text and an optional base UUID.

Parameters:

Name Type Description Default
text str

The text to be used for generating the hash-based UUID.

required
base_uuid UUID | None

The optional base UUID to use for hashing. Defaults to None.

None

Returns:

Type Description

uuid.UUID: The hash-based UUID generated from the input text and base UUID.

Source code in helpers/utils.py
def hash_text(text: str, base_uuid: uuid.UUID | None = None):
    """
    Generates a hash-based UUID using the given text and an optional base UUID.

    Args:
        text (str): The text to be used for generating the hash-based UUID.
        base_uuid (uuid.UUID | None, optional): The optional base UUID to use for hashing. Defaults to None.

    Returns:
        uuid.UUID: The hash-based UUID generated from the input text and base UUID.
    """
    if not isinstance(base_uuid, uuid.UUID):
        base_uuid = uuid.NAMESPACE_DNS
    return uuid.uuid3(base_uuid, text)

slugify(text, replace_specials_with='_', replace_spaces_with='-')

Convert a given string into a slug format.

Parameters:

Name Type Description Default
text str

The string to be converted into a slug.

required
replace_specials_with str

The character to replace special characters with. Defaults to "_.

'_'
replace_spaces_with str

The character to replace spaces with. Defaults to "-".

'-'

Returns:

Name Type Description
str str

The slugified string.

Source code in helpers/utils.py
def slugify(
    text: str, replace_specials_with: str = "_", replace_spaces_with: str = "-"
) -> str:
    """
    Convert a given string into a slug format.

    Args:
        text (str): The string to be converted into a slug.
        replace_specials_with (str, optional): The character to replace special characters with. Defaults to "_.
        replace_spaces_with (str, optional): The character to replace spaces with. Defaults to "-".

    Returns:
        str: The slugified string.
    """
    return (
        re.sub(r"[^\w\s-]+", replace_specials_with, text)
        .strip()
        .lower()
        .replace(" ", replace_spaces_with)
    )