import base64
from contextlib import suppress

from django.conf import settings
from django.http import HttpResponseForbidden


def get_username_and_password(request):  # pragma: no cover
    # This method is vendored from assorted DRF bits, so we
    # skip it in our test coverage report
    auth = request.META.get("HTTP_AUTHORIZATION", b"")
    if isinstance(auth, str):
        # Work around django test client oddness
        auth = auth.encode("iso-8859-1")
    auth = auth.split()
    if not auth or auth[0].lower() != b"basic":
        return False, False
    if len(auth) != 2:
        return False, False

    with suppress(TypeError, ValueError):
        try:
            auth_decoded = base64.b64decode(auth[1]).decode("utf-8")
        except UnicodeDecodeError:
            auth_decoded = base64.b64decode(auth[1]).decode("latin-1")

        return auth_decoded.split(":", 1)

    return False, False


class OSBBasicAuthPermission:
    """
    Basic auth for OSB is implemented as a permission class rather than as
    an authentication class, because authentication is expected to associate
    the request with a Django user. However, the OSB/Exoscale requests do not
    relate to a user account, so we treat the auth result as a permission instead.
    """

    def dispatch(self, request, *args, **kwargs):
        osb_username = getattr(settings, "OSB_USERNAME", None)
        osb_password = getattr(settings, "OSB_PASSWORD", None)

        if not osb_username or not osb_password:
            return False  # pragma: no cover

        username, password = get_username_and_password(request)
        if username == osb_username and password == osb_password:
            return super().dispatch(request, *args, **kwargs)
        return HttpResponseForbidden()
