class InvalidToken(Exception): ...

class Fernet:
    def __init__(self, key: bytes | str) -> None: ...
    def decrypt(self, token: bytes, ttl: int | None = ...) -> bytes: ...
    # decrypt_at_time accepts None ttl at runtime but it's an implementtion detail and it doesn't really
    # make sense for the client code to use it like that, so the parameter is typed as int as opposed to
    # int | None.
    def decrypt_at_time(self, token: bytes, ttl: int, current_time: int) -> bytes: ...
    def encrypt(self, data: bytes) -> bytes: ...
    def encrypt_at_time(self, data: bytes, current_time: int) -> bytes: ...
    def extract_timestamp(self, token: bytes) -> int: ...
    @classmethod
    def generate_key(cls) -> bytes: ...

class MultiFernet:
    def __init__(self, fernets: list[Fernet]) -> None: ...
    def decrypt(self, token: bytes, ttl: int | None = ...) -> bytes: ...
    # See a note above on the typing of the ttl parameter.
    def decrypt_at_time(self, token: bytes, ttl: int, current_time: int) -> bytes: ...
    def encrypt(self, data: bytes) -> bytes: ...
    def encrypt_at_time(self, data: bytes, current_time: int) -> bytes: ...
    def rotate(self, msg: bytes) -> bytes: ...
