"""

Credential handling functionality for Empire.

"""

import helpers
import os
# import sqlite3

class Credentials:
    """
    Class that handles interaction with the backend credential model
    (adding creds, displaying, etc.).
    """
    def __init__(self, MainMenu, args=None):

        # pull out the controller objects
        self.mainMenu = MainMenu
        self.conn = MainMenu.conn
        self.installPath = self.mainMenu.installPath
        self.args = args

        # credential database schema:
        #   (ID, credtype, domain, username, password, host, OS, notes, sid)
        # credtype = hash or plaintext
        # sid is stored for krbtgt


    def is_credential_valid(self, credentialID):
        """
        Check if this credential ID is valid.
        """

        cur = self.conn.cursor()
        cur.execute('SELECT * FROM credentials WHERE id=? limit 1', [credentialID])
        results = cur.fetchall()
        cur.close()
        return len(results) > 0


    def get_credentials(self, filterTerm=None, credtype=None, note=None, os=None):
        """
        Return credentials from the database.

        'credtype' can be specified to return creds of a specific type.
        Values are: hash, plaintext, and token.
        """

        cur = self.conn.cursor()

        # if we're returning a single credential by ID
        if self.is_credential_valid(filterTerm):
            cur.execute("SELECT * FROM credentials WHERE id=? limit 1", [filterTerm])

        # if we're filtering by host/username
        elif filterTerm and filterTerm != '':
            filterTerm = filterTerm.replace('*', '%')
            cur.execute("SELECT * FROM credentials WHERE LOWER(domain) LIKE LOWER(?) or LOWER(username) like LOWER(?) or LOWER(host) like LOWER(?) or LOWER(password) like LOWER(?)", [filterTerm, filterTerm, filterTerm, filterTerm])

        # if we're filtering by credential type (hash, plaintext, token)
        elif credtype and credtype != "":
            cur.execute("SELECT * FROM credentials WHERE LOWER(credtype) LIKE LOWER(?)", [credtype])

        # if we're filtering by content in the note field
        elif note and note != "":
            cur.execute("SELECT * FROM credentials WHERE LOWER(note) LIKE LOWER(%?%)", [note])

        # if we're filtering by content in the OS field
        elif os and os != "":
            cur.execute("SELECT * FROM credentials WHERE LOWER(os) LIKE LOWER(%?%)", [os])

        # otherwise return all credentials
        else:
            cur.execute("SELECT * FROM credentials")

        results = cur.fetchall()
        cur.close()
        return results


    def get_krbtgt(self):
        """
        Return all krbtgt credentials from the database.
        """
        return self.get_credentials(credtype="hash", filterTerm="krbtgt")


    def add_credential(self, credtype, domain, username, password, host, os='', sid='', notes=''):
        """
        Add a credential with the specified information to the database.
        """
        cur = self.conn.cursor()

        cur.execute("SELECT * FROM credentials WHERE LOWER(credtype) LIKE LOWER(?) AND LOWER(domain) LIKE LOWER(?) AND LOWER(username) LIKE LOWER(?) AND password LIKE ?", [credtype, domain, username, password])
        results = cur.fetchall()

        if results == []:
            # only add the credential if the (credtype, domain, username, password) tuple doesn't already exist
            cur.execute("INSERT INTO credentials (credtype, domain, username, password, host, os, sid, notes) VALUES (?,?,?,?,?,?,?,?)", [credtype, domain, username, password, host, os, sid, notes])

        cur.close()


    def add_credential_note(self, credentialID, note):
        """
        Update a note to a credential in the database.
        """
        cur = self.conn.cursor()
        cur.execute("UPDATE credentials SET note = ? WHERE id=?", [note, credentialID])
        cur.close()


    def remove_credentials(self, credIDs):
        """
        Removes a list of IDs from the database
        """
        for credID in credIDs:
            cur = self.conn.cursor()
            cur.execute("DELETE FROM credentials WHERE id=?", [credID])
            cur.close()


    def remove_all_credentials(self):
        """
        Remove all credentials from the database.
        """
        cur = self.conn.cursor()
        cur.execute("DELETE FROM credentials")
        cur.close()


    def export_credentials(self, export_path=''):
        """
        Export the credentials in the database to an output file.
        """

        if export_path == '':
            print helpers.color("[!] Export path cannot be ''")

        export_path += ".csv"

        if os.path.exists(export_path):
            try:
                choice = raw_input(helpers.color("\n[>] File %s already exists, overwrite? [y/N] " % (export_path), "red"))
                if choice.lower() != "" and choice.lower()[0] == "y":
                    pass
                else:
                    return
            except KeyboardInterrupt:
                return

        creds = self.get_credentials()

        if len(creds) == 0:
            print helpers.color("[!] No credentials in the database.")
            return

        output_file = open(export_path, 'w')
        output_file.write("CredID,CredType,Domain,Username,Password,Host,OS,SID,Notes\n")
        for cred in creds:
            output_file.write("\"%s\"\n" % ('","'.join([str(x) for x in cred])))

        print "\n" + helpers.color("[*] Credentials exported to %s\n" % (export_path))
        output_file.close()
