# -*- coding: utf-8 -*-
from netaddr import IPNetwork, IPAddress, AddrConversionError, AddrFormatError
import logging

from django.http import HttpResponseBadRequest
from django.conf import settings

SESSION_IP_KEY = '_restrictedsessions_ip'
SESSION_UA_KEY = '_restrictedsessions_ua'
logger = logging.getLogger('restrictedsessions')

class RestrictedSessionsMiddleware(object):
    def process_request(self, request):
        if not hasattr(request, 'session'):
            return

        remote_addr_key = getattr(settings, 'RESTRICTEDSESSIONS_REMOTE_ADDR_KEY', 'REMOTE_ADDR')
        remote_addr = request.META.get(remote_addr_key)
        if not remote_addr:
            return

        if not self.validate_ip(request, remote_addr) or not self.validate_ua(request):
            request.session.flush()
            logger.warning("Destroyed session due to invalid change of remote host or user agent")
            return HttpResponseBadRequest()

        request.session[SESSION_IP_KEY] = remote_addr
        if request.META.get('HTTP_USER_AGENT'):
            request.session[SESSION_UA_KEY] = request.META['HTTP_USER_AGENT']

    def validate_ip(self, request, remote_ip):
        if not getattr(settings, 'RESTRICTEDSESSIONS_RESTRICT_IP', True) or not SESSION_IP_KEY in request.session:
            return True

        session_network = IPNetwork(request.session[SESSION_IP_KEY])
        remote_ip = IPAddress(remote_ip)
        try:
            session_network = session_network.ipv4()
            remote_ip = remote_ip.ipv4()
            session_network.prefixlen = getattr(settings, 'RESTRICTEDSESSIONS_IPV4_LENGTH', 32)
        except AddrConversionError:
            try:
                session_network.prefixlen = getattr(settings, 'RESTRICTEDSESSIONS_IPV6_LENGTH', 64)
            except AddrFormatError:
                # session_network must be IPv4, but remote_ip is IPv6
                return False
        return remote_ip in session_network

    def validate_ua(self, request):
        if not getattr(settings, 'RESTRICTEDSESSIONS_RESTRICT_UA', True) or not SESSION_UA_KEY in request.session:
            return True
        return request.session[SESSION_UA_KEY] == request.META.get('HTTP_USER_AGENT')

@@ -327,16 +327,17 @@
 ions')%0A%0A
+%0A
 class Re
@@ -404,32 +404,90 @@
 self, request):%0A
+        # Short circuit when request doesn't have session%0A
         if not h
@@ -526,32 +526,92 @@
         return%0A%0A
+        # Extract remote IP address for validation purposes%0A
         remote_a
@@ -747,24 +747,25 @@
 dr_key)%0A
+%0A
         
 if not r
@@ -760,47 +760,77 @@
     
-if not remote_addr:%0A            return%0A
+# Clear the session and handle response when request doesn't validate
 %0A   
@@ -1094,16 +1094,94 @@
 uest()%0A%0A
+        # Set the UA/IP Address on the session since they validated correctly%0A
         
@@ -1400,16 +1400,78 @@
 te_ip):%0A
+        # When we aren't configured to restrict on IP address%0A
         
@@ -1526,39 +1526,145 @@
 TRICT_IP', True)
- or not
+:%0A            return True%0A        # When the IP address key hasn't yet been set on the request session%0A        if
  SESSION_IP_KEY 
@@ -1659,24 +1659,28 @@
 SION_IP_KEY 
+not 
 in request.s
@@ -1715,76 +1715,494 @@
 rue%0A
-%0A
+  
       
-  session_network = IPNetwork(request.session%5BSESSION_IP_KEY%5D
+# When there is no remote IP, check if one has been set on the session%0A        session_ip = request.session%5BSESSION_IP_KEY%5D%0A        if not remote_ip:%0A            if session_ip:  # session has remote IP value so validate :-(%0A                return False%0A            else:  # Session doesn't have remote IP value so possibly :-)%0A                return True%0A%0A        # Compute fuzzy IP compare based on settings on compare sensitivity%0A        session_network = IPNetwork(session_ip
 )%0A  
@@ -2804,32 +2804,94 @@
 self, request):%0A
+        # When we aren't configured to restrict on user agent%0A
         if not g
@@ -2946,23 +2946,129 @@
 ', True)
- or not
+:%0A            return True%0A        # When the user agent key hasn't been set yet in the request session%0A        if
  SESSION
@@ -3075,16 +3075,20 @@
 _UA_KEY 
+not 
 in reque
@@ -3115,32 +3115,112 @@
     return True%0A
+        # Compare the new user agent value with what is known about the session%0A
         return r

refactor existing flow--add comments