from doctest import master
import logging
from datetime import datetime

from pypykatz.pypykatz import pypykatz

from lsassy.credential import Credential


class Parser:
    """
    Parse remote lsass dump file using impacketfile and pypykatz
    """

    def __init__(self, dumpfile):
        self._dumpfile = dumpfile

    def parse(self):
        """
        Parse remote dump file and delete it after parsing
        :return: List of Credentials
        """
        credentials = []
        tickets = []
        masterkeys = []
        try:
            pypy_parse = pypykatz.parse_minidump_external(self._dumpfile, chunksize = 60*1024)
        except Exception as e:
            logging.error("An error occurred while parsing lsass dump", exc_info=True)
            return None

        ssps = ['msv_creds', 'wdigest_creds', 'ssp_creds', 'livessp_creds', 'kerberos_creds', 'credman_creds',
                'tspkg_creds', 'dpapi_creds']
        for luid in pypy_parse.logon_sessions:
            for ssp in ssps:
                for cred in getattr(pypy_parse.logon_sessions[luid], ssp, []):
                    domain = getattr(cred, "domainname", None)
                    username = getattr(cred, "username", None)
                    password = getattr(cred, "password", None)
                    LMHash = getattr(cred, "LMHash", None)
                    NThash = getattr(cred, "NThash", None)
                    SHA1 = getattr(cred, "SHAHash", None)
                    if LMHash is not None:
                        LMHash = LMHash.hex()
                    if NThash is not None:
                        NThash = NThash.hex()
                    if SHA1 is not None:
                        SHA1 = SHA1.hex()
                    if username and (password
                                     or (NThash and NThash != "00000000000000000000000000000000")
                                     or (LMHash and LMHash != "00000000000000000000000000000000")):
                        credentials.append(
                            Credential(ssp=ssp, domain=domain, username=username, password=password, lmhash=LMHash,
                                       nthash=NThash, sha1=SHA1))

            for kcred in pypy_parse.logon_sessions[luid].kerberos_creds:
                for ticket in kcred.tickets:
                    tickets.append(ticket)

            for dpapicred in pypy_parse.logon_sessions[luid].dpapi_creds:
                m = "{%s}:%s" % (dpapicred.key_guid,dpapicred.sha1_masterkey)
                if m not in masterkeys:
                    masterkeys.append(m)
                    credentials.append(
                        Credential(ssp='dpapi', domain='', username='', masterkey=m)
                    )

        for cred in pypy_parse.orphaned_creds:
            if cred.credtype == 'kerberos':
                for ticket in cred.tickets:
                    tickets.append(ticket)

        for ticket in tickets:
            if ticket.ServiceName is not None and ticket.ServiceName[0] == 'krbtgt':
                if ticket.EClientName is not None and ticket.DomainName is not None:
                    if ticket.TargetDomainName is not None and ticket.TargetDomainName != ticket.DomainName:
                        target_domain = ticket.TargetDomainName
                    else:
                        target_domain = ticket.DomainName
                    # Keep only valid tickets
                    if ticket.EndTime > datetime.now(ticket.EndTime.tzinfo):

                        credentials.append(Credential(
                            ssp="kerberos",
                            domain=ticket.DomainName,
                            username=ticket.EClientName[0],
                            ticket={'file': list(ticket.kirbi_data)[0], 'domain': target_domain, 'endtime': ticket.EndTime}
                        ))

        return credentials, tickets, masterkeys
