import sqlmodel import hashlib import Crypto from .user import user from .secret_crypto import secret_crypto class secret(sqlmodel.SQLModel, table = True): """ This class represents secret in the database. """ id: int | None = sqlmodel.Field(default = None, primary_key = True) name: str | None = sqlmodel.Field(default = None, index = True) domain: str | None = sqlmodel.Field(default = None, index = True) crypted: bytes | None = sqlmodel.Field(default = None) nonce: bytes | None = sqlmodel.Field(default = None) owner: int | None = sqlmodel.Field(default = None, foreign_key = "user.id") class secret_builder: """ This class is responsible for creating new secrets for the user. """ def __init__(self) -> None: """ This function create new clean builder. """ self.clean() def clean(self) -> None: """ This function clean builder, and prepare it to build new secret. """ self.__target = secret() @property def ready(self) -> bool: """ True when secret is ready, false when not. """ if self.__target.name is None or self.__target.domain is None: return False if self.__target.crypted is None or self.__target.nonce is None: return False if self.__target.owner is None: return False return True @property def owner(self) -> int | None: """ This return ID of the secret owner, or None if not set. """ return self.__target.owner @owner.setter def owner(self, target: user): """ This set new owner of the secret. """ self.__target.owner = user.id @property def result(self) -> secret: """ This return ready secret if it is ready, or raise Exception. """ if not self.ready: raise TypeError("Secret is not ready to load.") return self.__target @property def name(self) -> str | None: """ This return name of the secret or None if not set. """ return self.__target.name @property def domain(self) -> str | None: """ This return domain of the secret or None if not set. """ return self.__target.domain @name.setter def name(self, target: str) -> None: """ This set name of the secret. """ self.__target.name = target @domain.setter def domain(self, target: str) -> None: """ This set domain of the secret. """ self.__target.domain = target def crypt(self, key: str, target: str) -> None: """ This function crypt secret. It require password which could decrypt it laser, and target secret. It automatic set crypted and nonce secret fields. If secret already has nonce, then it use it. When secret nonce is empty, then it would provide new random nonce for secret. Parameters: key (str): Password to protect secret targer (str): Secret to encrypt """ crypter = secret_crypto(key) if self.__target.nonce is not None: crypter.set_iv(self.__target.nonce) crypted, nonce = crypter.crypted(target) self.__target.crypted = crypted self.__target.nonce = nonce