"""Authentication for HTTP component."""
import asyncio
import base64
import hmac
import logging

from aiohttp import hdrs
from aiohttp.web import middleware

from homeassistant.const import HTTP_HEADER_HA_AUTH
from .util import get_real_ip
from .const import KEY_TRUSTED_NETWORKS, KEY_AUTHENTICATED

DATA_API_PASSWORD = 'api_password'

_LOGGER = logging.getLogger(__name__)


@middleware
@asyncio.coroutine
def auth_middleware(request, handler):
    """Authenticate as middleware."""
    # If no password set, just always set authenticated=True
    if request.app['hass'].http.api_password is None:
        request[KEY_AUTHENTICATED] = True
        return (yield from handler(request))

    # Check authentication
    authenticated = False

    if (HTTP_HEADER_HA_AUTH in request.headers and
            validate_password(
                request, request.headers[HTTP_HEADER_HA_AUTH])):
        # A valid auth header has been set
        authenticated = True

    elif (DATA_API_PASSWORD in request.query and
          validate_password(request, request.query[DATA_API_PASSWORD])):
        authenticated = True

    elif (hdrs.AUTHORIZATION in request.headers and
          validate_authorization_header(request)):
        authenticated = True

    elif is_trusted_ip(request):
        authenticated = True

    request[KEY_AUTHENTICATED] = authenticated
    return (yield from handler(request))


def is_trusted_ip(request):
    """Test if request is from a trusted ip."""
    ip_addr = get_real_ip(request)

    return ip_addr and any(
        ip_addr in trusted_network for trusted_network
        in request.app[KEY_TRUSTED_NETWORKS])


def validate_password(request, api_password):
    """Test if password is valid."""
    return hmac.compare_digest(
        api_password, request.app['hass'].http.api_password)


def validate_authorization_header(request):
    """Test an authorization header if valid password."""
    if hdrs.AUTHORIZATION not in request.headers:
        return False

    auth_type, auth = request.headers.get(hdrs.AUTHORIZATION).split(' ', 1)

    if auth_type != 'Basic':
        return False

    decoded = base64.b64decode(auth).decode('utf-8')
    username, password = decoded.split(':', 1)

    if username != 'homeassistant':
        return False

    return validate_password(request, password)
