#import collections
from operator import itemgetter
import fileinput
try:
    from fileinput import hook_compressed
except ImportError: # 2.4
    hook_compressed = None
import re
import sys

finder = re.compile('\"(?P<method>GET|POST) (?P<path>.*) HTTP/(.*?)\" (?P<result>\d{3})', 
            flags=re.MULTILINE)

class Exploit(object):
    def __init__(self, method, subpath):
        super(Exploit, self).__init__()
        self.method = method
        self.subpath = subpath
    
    def __eq__(self, other):
        if self.method == 'POST':
            method_match = self.method == other.method
        else:
            method_match = True        
        path_match = self.subpath in other.path
        return path_match and method_match

class LogLine(tuple):
        'LogLine(method, path, version, status)' 

        __slots__ = () 

        _fields = ('method', 'path', 'version', 'status') 

        def __new__(cls, method, path, version, status):
            return tuple.__new__(cls, (method, path, version, status)) 

        @classmethod
        def _make(cls, iterable, new=tuple.__new__, len=len):
            'Make a new LogLine object from a sequence or iterable'
            result = new(cls, iterable)
            if len(result) != 4:
                raise TypeError('Expected 4 arguments, got %d' % len(result))
            return result 

        def __repr__(self):
            return 'LogLine(method=%r, path=%r, version=%r, status=%r)' % self 

        def _asdict(t):
            'Return a new dict which maps field names to their values'
            return {'method': t[0], 'path': t[1], 'version': t[2], 'status': t[3]} 

        def _replace(self, **kwds):
            'Return a new LogLine object replacing specified fields with new values'
            result = self._make(map(kwds.pop, ('method', 'path', 'version', 'status'), self))
            if kwds:
                raise ValueError('Got unexpected field names: %r' % kwds.keys())
            return result 

        def __getnewargs__(self):
            return tuple(self) 

        method = property(itemgetter(0))
        path = property(itemgetter(1))
        version = property(itemgetter(2))
        status = property(itemgetter(3))


data_leaks = [Exploit('GET', 'getMetadataForUID'),
              Exploit('GET', 'getMetadataForRID'),
              Exploit('GET', 'getIndexDataForUID'),
              Exploit('GET', 'getIndexDataForRID'),
              Exploit('GET', 'getUserNames'),
              Exploit('GET', 'getUsers'),
              Exploit('GET', 'getUserIds'),
              Exploit('GET', 'enumerateUsers'),
              ]
             
dos = [Exploit('GET', 'deleteUser'),
       Exploit('GET', 'unregisterTransform'),
       Exploit('POST', 'userFolderDelUser'),            
       ]

elevation = [Exploit('GET', 'credentialsChanged'),
             Exploit('GET', 'userSetPassword'),
             Exploit('POST', 'userFolderEditUser'),            
             Exploit('POST', 'userFolderAddUser'),            
             Exploit('POST', 'userFolderEditGroup'),           
             ]

exploits = data_leaks + dos + elevation
      
if __name__ == '__main__':
    verbose = '-v' in sys.argv
    if verbose:
        sys.argv.remove("-v")
    
    if hook_compressed is not None:
        log = fileinput.input(openhook=fileinput.hook_compressed)
    else:
        log = fileinput.input()
        
    found = []
    dl = ds = ele = False
    
    for line in log:
        found = finder.findall(line)
        if not found:
            continue
        else:
            parsed_line = LogLine(*found[0])
        
        if parsed_line.status != '200':
            continue
        
        if verbose:
            if parsed_line in exploits:
                print line,
        else:
            if parsed_line in data_leaks:
                dl = True
            if parsed_line in dos:
                ds = True
            if parsed_line in elevation:
                ele = True
    
    if not verbose:
        print "Potential denials of service: %s" % ds
        print "Potential extraction of confidential data: %s" % dl
        print "Potential elevation of privileges: %s" % ele

