# Path: esteid/authentication/types.py
# class AuthenticationResult(PredictableDict):
#     country: str
#     id_code: str
#     given_name: str
#     surname: str
#     certificate_b64: str
# 
# class SessionData(PredictableDict):
#     """
#     Wrapper for temporary data stored between authentication polling requests.
# 
#     Contains the upstream service's session ID and the hash value used to calculate the authentication signature,
#      along with a timestamp that is used to determine session validity timeout.
#     """
# 
#     timestamp: int
#     session_id: str
#     hash_value_b64: str
# 
# Path: esteid/exceptions.py
# class EsteidError(Exception):
#     """
#     A generic Esteid error.
# 
#     Provides an interface for displaying a translated message to the user.
# 
#     Note: by default, any message passed as a first positional argument is ignored, because it only
#     serves for better logging. The User Interface should display a verbose error message
#     in case of a user-caused error so that user can take action accordingly. Errors caused by service malfunction
#     are likely not informative to a user without malicious intent.
# 
#     If the default message contains {key} placeholders, the exception is supposed to be
#     raised with kwargs, these will be passed on to <translated default message>.format(**kwargs).
#     """
# 
#     status = HTTPStatus.INTERNAL_SERVER_ERROR
# 
#     default_message = _("Something went wrong")
# 
#     kwargs: dict
# 
#     def __init__(self, message=None, **kwargs):
#         super().__init__(message)
#         self.kwargs = kwargs
# 
#     def get_message(self):
#         return str(self.default_message).format(**self.kwargs)
# 
#     def get_user_error(self):
#         return {
#             "error": self.__class__.__name__,  # error code that can be bound to JS translations
#             # TODO review errors and add translations
#             "message": self.get_message(),
#         }
# 
# class SigningSessionDoesNotExist(SigningSessionError):
#     """A signing session does not exist while expected to exist"""
# 
#     default_message = _("No signing session found.")
# 
# class SigningSessionExists(SigningSessionError):
#     """A signing session already exists while not expected to exist (when initializing)"""
# 
#     default_message = _("A signing session is already in progress.")


import logging
from time import time
from typing import Dict, Optional, Type
from esteid.authentication.types import AuthenticationResult, SessionData
from esteid.exceptions import EsteidError, SigningSessionDoesNotExist, SigningSessionExists
        """
        return self._cleanup_session(self.session)

    @classmethod
    def start_session(cls, session, initial_data) -> "Authenticator":
        """
        Initializes a fresh authentication session.
        """
        signer = cls(session, initial=True)
        signer.setup(initial_data)
        return signer

    @classmethod
    def load_session(cls, session) -> "Authenticator":
        """
        Continues (loads) an existing authentication session from the `session` object
        """
        return cls(session, initial=False)

    @classmethod
    def _cleanup_session(cls, session):
        session.pop(cls._SESSION_KEY, None)

    # "Magic" registration of subclasses

    @staticmethod
    def select_authenticator(authentication_method: str) -> Type["Authenticator"]:
        try:
            authenticator_class = Authenticator.AUTHENTICATION_METHODS[authentication_method]
        except KeyError as e:

# Path: esteid/authentication/types.py
# class AuthenticationResult(PredictableDict):
#     country: str
#     id_code: str
#     given_name: str
#     surname: str
#     certificate_b64: str
# 
# class SessionData(PredictableDict):
#     """
#     Wrapper for temporary data stored between authentication polling requests.
# 
#     Contains the upstream service's session ID and the hash value used to calculate the authentication signature,
#      along with a timestamp that is used to determine session validity timeout.
#     """
# 
#     timestamp: int
#     session_id: str
#     hash_value_b64: str
# 
# Path: esteid/exceptions.py
# class EsteidError(Exception):
#     """
#     A generic Esteid error.
# 
#     Provides an interface for displaying a translated message to the user.
# 
#     Note: by default, any message passed as a first positional argument is ignored, because it only
#     serves for better logging. The User Interface should display a verbose error message
#     in case of a user-caused error so that user can take action accordingly. Errors caused by service malfunction
#     are likely not informative to a user without malicious intent.
# 
#     If the default message contains {key} placeholders, the exception is supposed to be
#     raised with kwargs, these will be passed on to <translated default message>.format(**kwargs).
#     """
# 
#     status = HTTPStatus.INTERNAL_SERVER_ERROR
# 
#     default_message = _("Something went wrong")
# 
#     kwargs: dict
# 
#     def __init__(self, message=None, **kwargs):
#         super().__init__(message)
#         self.kwargs = kwargs
# 
#     def get_message(self):
#         return str(self.default_message).format(**self.kwargs)
# 
#     def get_user_error(self):
#         return {
#             "error": self.__class__.__name__,  # error code that can be bound to JS translations
#             # TODO review errors and add translations
#             "message": self.get_message(),
#         }
# 
# class SigningSessionDoesNotExist(SigningSessionError):
#     """A signing session does not exist while expected to exist"""
# 
#     default_message = _("No signing session found.")
# 
# class SigningSessionExists(SigningSessionError):
#     """A signing session already exists while not expected to exist (when initializing)"""
# 
#     default_message = _("A signing session is already in progress.")


# Path: esteid/authentication/authenticator.py
import logging
from time import time
from typing import Dict, Optional, Type
from esteid.authentication.types import AuthenticationResult, SessionData
from esteid.exceptions import EsteidError, SigningSessionDoesNotExist, SigningSessionExists

        """
        return self._cleanup_session(self.session)

    @classmethod
    def start_session(cls, session, initial_data) -> "Authenticator":
        """
        Initializes a fresh authentication session.
        """
        signer = cls(session, initial=True)
        signer.setup(initial_data)
        return signer

    @classmethod
    def load_session(cls, session) -> "Authenticator":
        """
        Continues (loads) an existing authentication session from the `session` object
        """
        return cls(session, initial=False)

    @classmethod
    def _cleanup_session(cls, session):
        session.pop(cls._SESSION_KEY, None)

    # "Magic" registration of subclasses

    @staticmethod
    def select_authenticator(authentication_method: str) -> Type["Authenticator"]:
        try:
            authenticator_class = Authenticator.AUTHENTICATION_METHODS[authentication_method]
        except KeyError as e:

            raise EsteidError(f"Failed to load signer: method `{authentication_method}` not registered") from e