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

"""
Copyright (c) 2014-2016 pocsuite developers (https://seebug.org)
See the file 'docs/COPYING' for copying permission
"""

import re
import json
import time
from string import atof
from pocsuite.lib.core.common import parseTargetUrl
from pocsuite.lib.core.data import logger
from pocsuite.lib.core.enums import CUSTOM_LOGGING
from pocsuite.lib.core.data import kb
from pocsuite.lib.core.data import conf
from pocsuite.lib.core.data import resultJson
from pocsuite.lib.core.data import savedReq
from pocsuite.lib.request.basic import req


def initilizeJson(devilJson):
    _ = ("step", "method", "vulPath", "params", "headers")
    return [devilJson[i] for i in _] + [resSelect(devilJson["match"]), int(devilJson["status"])]


def resSelect(res):
    return res['regex'] or atof(res['time'])


def showResult(tag):
    for key1, value1 in resultJson[tag].iteritems():
        for key2, value2 in value1.iteritems():
            if key1 != 'verifyInfo':
                logger.log(CUSTOM_LOGGING.SUCCESS, key2 + " : " + resultJson[tag][key1][key2])

    pass


def execReq(poc, mode, targetUrl):
    pocInfo, devilJson = poc['pocInfo'], poc["pocExecute"]
    result = False

    infoMsg = "poc-%s '%s' has already been detected against '%s'." % (pocInfo["vulID"], pocInfo["name"], targetUrl)
    logger.log(CUSTOM_LOGGING.SUCCESS, infoMsg)

    for targetJson in devilJson[mode]:

        if mode == 'verify':
            result = _executeVerify(pocInfo, targetJson, targetUrl, 'verify')
            if targetJson['step'] == '0' and result:
                return True
            elif targetJson['step'] != '0' and not result:
                return False

        else:
            result = _executeAttack(pocInfo, targetJson, targetUrl)
            if targetJson['step'] == '0' and result:
                showResult(targetUrl + pocInfo['vulID'])
                return True
            elif targetJson['step'] != '0' and not result:
                return False

    if result:
        showResult(targetUrl + pocInfo['vulID'])

    return result


def _executeVerify(pocInfo, targetJson, targetUrl, mode):
    url, startTime = parseTargetUrl(targetUrl), time.time()
    step, method, path, params, headers, match, status_code = initilizeJson(targetJson)

    if (targetUrl + pocInfo['vulID']) not in resultJson:
        resultJson[targetUrl + pocInfo['vulID']] = {}
        resultJson[targetUrl + pocInfo['vulID']]['verifyInfo'] = {'URL': url, 'Postdata': params, 'Path': path}

    try:
        if method == 'get':
            r = req.get('%s/%s' % (url, path), params=params, headers=headers)
        else:
            r = req.post('%s/%s' % (url, path), data=params, headers=headers)

    except Exception, ex:
        logger.log(CUSTOM_LOGGING.ERROR, str(ex))
        return False

    if r.status_code != status_code:
        return False

    if isinstance(match, float) and (time.time() - startTime > match):
        savedReq.update({targetUrl + pocInfo['vulID']: r.req})

        if mode == 'verify':
            logger.log(CUSTOM_LOGGING.SUCCESS, "URL : " + targetUrl + path)
            if params:
                logger.log(CUSTOM_LOGGING.SUCCESS, "Postdata : " + params)
        return True

    else:
        for mat in match:
            # TODO
            if not re.search(mat.encode(), r.content):
                return False

        savedReq.update({targetUrl + pocInfo['vulID']: r.content})

        if mode == 'verify':
            logger.log(CUSTOM_LOGGING.SUCCESS, "URL : " + targetUrl + path)
            if params:
                logger.log(CUSTOM_LOGGING.SUCCESS, "Postdata : " + params)

        return True

    return False


def _executeAttack(pocInfo, targetJson, targetUrl):
    if not _executeVerify(pocInfo, targetJson, targetUrl, 'attack'):
        return False

    _filterColumn(targetJson['result'], targetUrl, pocInfo['vulID'])
    return True


def _filterColumn(Json, targetUrl, vulID):

    for k, v in Json.iteritems():
        if k not in resultJson[targetUrl + vulID]:
            resultJson[targetUrl + vulID][k] = {}
        resultJson[targetUrl + vulID][k].update(v)

    for key1, value1 in resultJson[targetUrl + vulID].iteritems():
        for key2, value2 in value1.iteritems():
            if value2.startswith("<regex>"):
                valuePattern = re.compile(value2[value2.index('>') + 1:])
                match = valuePattern.search(savedReq[targetUrl + vulID])
                if match:
                    resultJson[targetUrl + vulID][key1][key2] = match.group()