import subprocess
import os

try:
    import simplejson as json
except ImportError:
    import json


class SecretsProcessor(object):
    def __init__(self
                , src="raw_secrets"
                , dst="secrets"):
        self.src = src
        self.dst = dst

    def run(self):
        print("Processing secrets from log {0} to {1}".format(self.src, self.dst))

        with open(self.dst, "w") as wfd:
            with open(self.src) as rfd:
                proc_count = 0
                for line in rfd:
                    data = line.split()
                    client_random = data[3][14:]
                    master_secret = data[5][14:]
                    wfd.write("CLIENT_RANDOM {0} {1}\n".format(client_random, master_secret))
                    proc_count += 1

                print("Lines processed: {0}".format(proc_count))


class PCAPProcessor(object):
    def __init__(self
                , tshark=None
                , pcap = "packets.pcap"
                , pcap_split_path = "pcaps"
                , lua="utils/tshark.lua"
                , dump="packets.json"
                , force_dump = False
                , secrets="secrets"
                , port="443,11111,11112"):
        self.tshark_path = tshark
        self.pcap_path = pcap
        self.pcap_split_path = pcap_split_path
        self.lua_path = lua
        self.secrets_path = secrets
        self.ssl_port = port
        self.dump_path = dump
        self.force_dump = force_dump

        self._check_tshark_path()
        self._check_data_path()

    def _check_tshark_path(self):
        def is_runnable(path):
            return os.path.isfile(path) and os.access(path, os.X_OK)

        if self.tshark_path is not None:
            return

        for path in os.environ["PATH"].split(os.pathsep):
            if is_runnable(os.path.join(path, "tshark")):
                self.tshark_path = os.path.join(path, "tshark")
                break

        if self.tshark_path is None:
            raise Exception("No tshark executable was found")

    def _check_data_path(self):
        if not os.path.isfile(self.lua_path):
            raise Exception("No lua script was found")
        if not os.path.isfile(self.pcap_path):
            raise Exception("No dump file was found")
        if not os.path.isfile(self.secrets_path):
            raise Exception("No secrets file was found")

    def run(self):
        if not os.path.isfile(self.dump_path) or self.force_dump:
            with open(self.dump_path, "wb") as wfd:
                self.proc = subprocess.Popen([
                    str(self.tshark_path),
                    "-q2X", "lua_script:" + str(self.lua_path),
                    "-X", "lua_script1:" + str(self.pcap_split_path),
                    "-r", str(self.pcap_path),
                    "-o", "ssl.desegment_ssl_records: TRUE",
                    "-o", "ssl.desegment_ssl_application_data: TRUE",
                    "-o", "ssl.keylog_file:" + str(self.secrets_path),
                    "-o", "http.ssl.port:" + str(self.ssl_port),
                    "-o", "http.desegment_body: FALSE"], stdout=wfd)

                print("Running tshark from {0}".format(self.tshark_path))
                js, errs = self.proc.communicate()
                if self.proc.returncode != 0:
                    raise Exception("Could not run tshark")
        else:
            print("Loading saved data from {0}".format(self.dump_path))

        js = ""
        with open(self.dump_path) as rfd:
            js = rfd.read()

        data = []
        for line in js.splitlines():
            try:
                data.append(json.loads(str(line)))
            except ValueError:
                print("Failed to parse string: " + str(line))
        return data
