import sqlmodel import hashlib import Crypto from .user import user from .builder import builder 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") @property def in_database(self) -> bool: """ True when secret exists in database. """ return self.id is not None @property def ready(self) -> bool: """ True when all fields are filled. """ if self.name is None or self.domain is None: return False if self.crypted is None or self.nonce is None: return False if self.owner is None: return False return True def __str__(self) -> str: """ This cast user to string, very usefull for debug. Returns: (str): User dump as string """ result = "" result = result + "Secret " if self.id is not None: result = result + "(" + str(self.id) + ")" result = result + "\n" result = result + "Name: " + self.name + "\n" result = result + "Domain: " + self.domain + "\n" result = result + "Owner ID: " + str(self.owner) + "\n" result = result + "Crypted: " + self.crypted.hex() + "\n" result = result + "Nonce: " + self.nonce.hex() + "\n" return result class secret_builder(builder, target_type = secret): """ This class is responsible for creating new secrets for the user. """ @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 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.upper() @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