Example #1
0
def write_secret(passphrase: str, secret: str, expire: int, tries: int,
                 haveibeenpwned: bool) -> Tuple[WriteResponse, int]:
    """Write a secret.

    Args:
        passphrase (str): Passphrase needed to encrypt the secret.
        secret (str): Secret to encrypt.
        expire (int): Number of days the secret will be stored.
        tries (int): Number of tries to read the secret before it gets deleted.
        haveibeenpwned (bool): Passphrase has been checked with haveibeenpwned.

    """
    now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    exp_date = datetime.strptime(now,
                                 "%Y-%m-%d %H:%M:%S") + timedelta(days=expire)

    slug = generate_unique_slug()
    Entries.create(
        slug_link=slug,
        encrypted_text=Secret(secret.encode(), passphrase).encrypt(),
        date_created=now,
        date_expires=exp_date,
        tries=tries,
        haveibeenpwned=haveibeenpwned,
    )

    app.logger.info(f"{slug} created and expires on {exp_date}")
    timez = datetime.now(timezone.utc).astimezone().tzname()

    expires_on = f"{exp_date.strftime('%Y-%m-%d at %H:%M')} {timez}"
    return (
        WriteResponse(Status.CREATED.value, Messages.CREATED.value, slug,
                      expires_on),
        HTTPStatus.CREATED.value,
    )
Example #2
0
def read_secret(slug: str, passphrase: str) -> Tuple[ReadResponse, int]:
    """Read a secret.

    Args:
        slug (str): Unique slug link to access the secret.
        passphrase (str): Passphrase needed to decrypt the secret.

    """
    secret = Entries.query.filter_by(slug_link=slug).first()
    if not secret:
        app.logger.info(f"{slug} tried to read but do not exists in database")
        return (
            ReadResponse(Status.EXPIRED.value, Messages.NOT_FOUND.value),
            HTTPStatus.NOT_FOUND.value,
        )

    try:
        msg = Secret(secret.encrypted_text, passphrase).decrypt()
    except InvalidToken:
        remaining = secret.tries - 1
        if remaining == 0:
            # Number of tries exceeded, delete secret
            app.logger.warning(f"{slug} tries to open secret exceeded")
            secret.delete()
            return (
                ReadResponse(Status.INVALID.value, Messages.EXCEEDED.value),
                HTTPStatus.UNAUTHORIZED.value,
            )

        secret.update(tries=remaining)
        app.logger.info(
            f"{slug} wrong passphrase used. Number of tries remaining: {remaining}"
        )
        return (
            ReadResponse(
                Status.INVALID.value,
                Messages.INVALID.value.format(remaining=remaining),
            ),
            HTTPStatus.UNAUTHORIZED.value,
        )

    secret.delete()  # Delete message after it's read
    app.logger.info(f"{slug} was decrypted and deleted")
    return (
        ReadResponse(Status.SUCCESS.value, html.escape(msg)),
        HTTPStatus.OK.value,
    )
Example #3
0
 def test_decryption(self):
     self.assertEqual(
         Secret(self.encrypted_text, self.passphrase).decrypt(), self.secret)
Example #4
0
 def test_wrong_passphrase(self):
     with self.assertRaises(InvalidToken):
         Secret(self.encrypted_text, "wrongPassphrase").decrypt()
Example #5
0
 def test_unique_encryption(self):
     encrypted = Secret(self.secret.encode(), self.passphrase).encrypt()
     self.assertNotEqual(encrypted, self.encrypted_text)