#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Native imports
import re
import sys
import getopt
from core.libs.process import Take

# TO-DO List:
# Support github api_keys
# Extract Bing search api keys
# Add other country SSN Number support.
# Incorporate bitcoin pre-fixes into bitcoin grabbing function
# Work on better case detection for diffent phone number formats
# suppport an option where the user uses their own regex to look for something.

# Bugs:
# Phone number false readings.
# Can not grab any Bitcoin wallet addresses that are 31 - 32 characters in length.

class LootRuntimeError(RuntimeError):
    pass

class Loot(object):

    def __init__(self):
        self.verbose = True
        self.__options = {}
        self.__take = Take()

    def __tell(self, text, sep=' ', end='\n', stream=sys.stdout, flush=False):
        if self.verbose or stream != sys.stdout:
            stream.write(text)
            if end is not None:
                stream.write(end)
            else:
                if sep is not None:
                    stream.write(sep)
            if flush or end is None:
                stream.flush()

    def prepare(self):
        args, commands = getopt.getopt(sys.argv[1:], 'f:')
        args = dict(args)

        if len(commands) == 1 and commands[0] in self.commands:
            command = commands[0]
        else:
            # if no args or options exist, show the help.
            command = 'help'
            args = {}
        # if everything checks out. Run the desired command with the desired option(s)
        func = self.commands[command]

        req_params, opt_params = func.cli_options
        for param in req_params:
            if param not in ('-u',) and param not in args:
                raise TreasureRuntimError("The command '%s' requires the " \
                                        "option '%s'. See 'help'." % \
                                        (command, param))
        for arg, value in args.iteritems():
            if arg in req_params or arg in opt_params:

                if arg == '-f':
                    self.__options['file'] = value

                    # Prevent messages from corrupting stdout
                    if value == '-':
                        self.verbose = False
            else:
                raise TreasureRuntimError("The command '%s' ignores the " \
                                        "option '%s'." % (command, arg))

        self.__tell("\nLoot | GuerrillaWarfare - https://twitter.com/GuerrillaWF")

        try:
            func(self, **self.__options) # A wild TypeError appears from the tall grass.
            # Will have to fix this TypeError later. Not sure what's causing it exactly.
        except TypeError:
            self.print_help() # For now call on the help, so they always know what to do.

    def print_help(self):
        """Show this message again.
        """
        self.__tell('Usage Loot [option(s)] [command]'
            '\n'
            '\n Options:'
            '\n  -f    : File name to extract some type of content from.'
            '\n'
            '\n Commands:')
        m = max([len(command) for command in self.commands])
        for command, func in sorted(self.commands.items()):
            self.__tell('  %s%s  : %s' % (command, \
                                        ' ' * (m - len(command)), \
                                        func.__doc__.split('\n')[0]))
    print_help.cli_options = ((), ())

    def __iat__(self, file):
        """Grab instagram access tokens from a file. (if any)
        """
        self.__take.InstagramAccessToken(file)
    __iat__.cli_options = (('-f',), ())

    def __ipv4__(self, file):
        """Grab ipv4 addresses from a file. (if any)
        """
        self.__take.IPv4Addresses(file)
    __ipv4__.cli_options = (('-f',), ())

    def __ipv6__(self, file):
        """Grab ipv6 addresses from a file. (if any)
        """
        self.__take.IPv6Addresses(file)
    __ipv6__.cli_options = (('-f',), ())

    def __btc__(self, file):
        """Grab bitcoin wallet addresses from a file. (if any)
        """
        self.__take.BTCAddresses(file)
    __btc__.cli_options = (('-f',), ())

    def __fat__(self, file):
        """Grab facebook access tokens from a file. (if any)
        """
        self.__take.FacebookAccessTokens(file)
    __fat__.cli_options = (('-f',), ())

    def __bid__(self, file):
        """Grab blockchain identifiers from a file. (if any)
        """
        self.__take.BlockchainIdentifiers(file)
    __bid__.cli_options = (('-f',), ())

    def __link__(self, file):
        """Grab links from a file. (if any)
        """
        self.__take.HyperLinks(file)
    __link__.cli_options = (('-f',), ())

    def __mac__(self, file):
        """Grab mac addresses from a file. (if any)
        """
        self.__take.MACAddresses(file)
    __mac__.cli_options = (('-f',), ())

    def __ssn__(self, file):
        """Grab social security numbers from a file. (if any)
        """
        self.__take.SocialSecurityNumbers(file)
    __ssn__.cli_options = (('-f',), ())

    def __ccn__(self, file):
        """Grab credit card numbers from a file. (if any)
        """
        self.__take.CreditCardNumbers(file)
    __ccn__.cli_options = (('-f',), ())

    def __hashes__(self, file):
        """Grab hash values from a file. (if any)
        """
        self.__take.HashTypes(file)
    __hashes__.cli_options = (('-f',), ())

    def __phone__(self, file):
        """Grab phone numbers from a file. (if any)
        """
        self.__take.PhoneNumbers(file)
    __phone__.cli_options = (('-f',), ())

    def __email__(self, file):
        """Grab email addresses from a file. (if any)
        """
        self.__take.Emails(file)
    __email__.cli_options = (('-f',), ())

    def documentation(self):
        """Documentation, for those who need it.
        """
        print """
 ./loot -f [FILE] iat   | Grab instagram access tokens from .code.dump (if any)
 ./loot -f [FILE] ipv4  | Grab ipv4 addresses from .code.dump (if any)
 ./loot -f [FILE] ipv6  | Grab ipv6 addresses from .code.dump (if any)
 ./loot -f [FILE] btc   | Grab bitcoin wallet addresses from .code.dump (if any)
 ./loot -f [FILE] bid   | Grab blockchain identifiers from .code.dump (if any)
 ./loot -f [FILE] fat   | Grab facebook access tokens from .code.dump (if any)
 ./loot -f [FILE] mac   | Grab MAC addresses if any are in file.
 ./loot -f [FILE] ssn   | Grab social security numbers if any are in file.
 ./loot -f [FILE] ccn   | Grab credit card numbers if any are in file.
 ./loot -f [FILE] email | Grab Email addresses if any are in file.
 ./loot -f [FILE] hash  | Grab hash values if any are in file.
 ./loot -f [FILE] phn   | Grab phone numbers if any are in file.
        """
    documentation.cli_options = ((), ())

    commands = {
    'help':print_help,
    'iat':__iat__,
    'link':__link__,
    'mac':__mac__,
    'ssn':__ssn__,
    'ccn':__ccn__,
    'hash':__hashes__,
    'phn':__phone__,
    'email':__email__,
    'ipv4':__ipv4__,
    'ipv6':__ipv6__,
    'btc':__btc__,
    'bid':__bid__,
    'fat':__fat__,
    'docs':documentation
    }

if __name__ == "__main__":
    Loot().prepare()
