# 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

        # Not doing session data validation here, because
        # an instance of another type may need different data
        return session_data

    def __init__(self, session, initial=False):
        """
        Initializes the necessary session data.

        Takes a session object, e.g. django request.session,
        and a flag that tells whether to start new session or attempt to load an existing one
        """
        session_data = self.load_session_data(session)
        if initial:
            if session_data:
                try:
                    timestamp = session_data.timestamp
                except AttributeError:
                    timestamp = 0

                if time() < timestamp + self.SESSION_VALIDITY_TIMEOUT:
                    raise SigningSessionExists("Another authentication session already in progress")

                # session expired => create a fresh data store
                session_data = SessionData()

                # wipe the old data from session.
                self._cleanup_session(session)
        else:
            if not session_data:

# 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


        # Not doing session data validation here, because
        # an instance of another type may need different data
        return session_data

    def __init__(self, session, initial=False):
        """
        Initializes the necessary session data.

        Takes a session object, e.g. django request.session,
        and a flag that tells whether to start new session or attempt to load an existing one
        """
        session_data = self.load_session_data(session)
        if initial:
            if session_data:
                try:
                    timestamp = session_data.timestamp
                except AttributeError:
                    timestamp = 0

                if time() < timestamp + self.SESSION_VALIDITY_TIMEOUT:
                    raise SigningSessionExists("Another authentication session already in progress")

                # session expired => create a fresh data store
                session_data = SessionData()

                # wipe the old data from session.
                self._cleanup_session(session)
        else:
            if not session_data:

                raise SigningSessionDoesNotExist("No active authentication session found")