# Path: privacyscore/utils.py
# def get_list_item_by_dict_entry(search: list, key: str, value: str):
#     """Get the first raw data element with the specified value for key."""
#     return next((
#         s for s in search if s[key] == value), None)
# 
# Path: privacyscore/test_suites/testssl/common.py
# def run_testssl(hostname: str, check_mx: bool, remote_host: str = None) -> bytes:
#     """Test the specified hostname with testssl and return the raw json result."""
#     # determine hostname
#     if remote_host:
#         out =  _remote_testssl(hostname, remote_host)
#     else:
#         out = _local_testssl(hostname, check_mx)
# 
#     # fix json syntax error
#     out = re.sub(r'"Invocation.*?\n', '', out.decode(), 1).encode()
# 
#     return out
# 
# def parse_common_testssl(json: str, prefix: str):
#     """Perform common parsing tasks on result JSONs."""
#     result = {
#         '{}_has_ssl'.format(prefix): True,  # otherwise an exception would have been thrown before
#     }
# 
#     # Detect if cert is valid
#     trust_cert = None
#     trust_chain = None
#     trust_pat = re.compile(r'(^trust$)|(.*? trust)')
#     chain_pat = re.compile(r'.*?chain_of_trust$')
#     # TODO If a server uses more than one certificate, this code will validate only the last one.
#     for default in json['scanResult'][0]['serverDefaults']:
#         if trust_pat.search(default['id']) is not None:
#             trust_cert = default
#         elif chain_pat.search(default['id']) is not None:
#             trust_chain = default
#         elif default["id"] == "issuer" and default["severity"] == "CRITICAL":
#             trust_chain = default
# 
#     assert trust_cert is not None
#     assert trust_chain is not None
#     
#     reason = ""
#     trusted = True
#     if not trust_cert['severity'] in ['OK', "INFO"]:
#         reason += trust_cert['finding']
#         trusted = False
#     if not trust_chain['severity'] in ['OK', 'INFO']:
#         reason += trust_chain['finding']
#         trusted = False
# 
#     result['{}_cert_trusted'.format(prefix)] = trusted
#     result['{}_cert_trusted_reason'.format(prefix)] = reason
# 
# 
#     # pfs
#     result['{}_pfs'.format(prefix)] = json['scanResult'][0]['pfs'][0]['severity'] == 'OK'
# 
#     # detect protocols
#     pattern = re.compile(r'is (not )?offered')
#     for p in json['scanResult'][0]['protocols']:
#         if p['severity'] == "CRITICAL":
#             # Hardcoded special case to grab a specific error
#             # This is horrible style
#             # TODO make less horrible
#             pat = re.compile(r'higher version number')
#             match = pat.search(p['finding'])
#             result['{}_has_protocol_{}'.format(prefix, p['id'])] = match is None
#             continue
#         match = pattern.search(p['finding'])
#         if not match:
#             continue
#         result['{}_has_protocol_{}'.format(prefix, p['id'])] = match.group(1) is None
# 
#     # Detect vulnerabilities
#     result['{}_vulnerabilities'.format(prefix)] = {}
#     for vuln in json['scanResult'][0]['vulnerabilities']:
#         if vuln['severity'] != u"OK" and vuln['severity'] != u'INFO':
#             result['{}_vulnerabilities'.format(prefix)][vuln['id']] = {
#                 'severity': vuln['severity'],
#                 'cve': vuln['cve'] if 'cve' in vuln.keys() else "",
#                 'finding': vuln['finding'],
#             }
#     
#     # Detect ciphers
#     # TODO Do we maybe want to get all cipher info, not only the bad ones?
#     result['{}_ciphers'.format(prefix)] = {}
#     for cipher in json['scanResult'][0]['ciphers']:
#         if cipher['severity'] != u"OK" and cipher['severity'] != u'INFO':
#             result['{}_ciphers'.format(prefix)][cipher['id']] = {
#                 'severity': cipher['severity'],
#                 'finding': cipher['finding'],
#             }
# 
#     return result


import json
import re
import os
from typing import Dict, Union
from urllib.parse import urlparse
from django.conf import settings
from privacyscore.utils import get_list_item_by_dict_entry
from .testssl.common import run_testssl, parse_common_testssl
    if result['web_has_hsts_preload_header']:
        result['web_has_hsts_header'] = True
    elif hsts_item is not None:
        result['web_has_hsts_header'] = hsts_item['severity'] == 'OK'
    
    if hsts_time_item is not None:
        result['web_has_hsts_header'] = True
        result["web_has_hsts_header_sufficient_time"] = hsts_time_item['severity'] == 'OK'

    # Check the HSTS Preloading database
    result["web_has_hsts_preload"] = False
    with open(os.path.join(settings.SCAN_TEST_BASEPATH, "vendor/HSTSPreload", "transport_security_state_static")) as fo:
        preloads = json.loads(fo.read())
    host = data["target host"]
    # Check if exact hostname is included
    if not _check_contained(preloads, host):
        # If not included, construct ever shorter hostnames and look for policies
        # on those versions that include subdomains
        split = host.split(".")
        for i in range(1, len(split)):
            if _check_contained(preloads, ".".join(split[i:]), True):
                # Found
                result["web_has_hsts_preload"] = True
    else:
        # Found
        result["web_has_hsts_preload"] = True
    return result


def _detect_hpkp(data: dict) -> dict:

# Path: privacyscore/utils.py
# def get_list_item_by_dict_entry(search: list, key: str, value: str):
#     """Get the first raw data element with the specified value for key."""
#     return next((
#         s for s in search if s[key] == value), None)
# 
# Path: privacyscore/test_suites/testssl/common.py
# def run_testssl(hostname: str, check_mx: bool, remote_host: str = None) -> bytes:
#     """Test the specified hostname with testssl and return the raw json result."""
#     # determine hostname
#     if remote_host:
#         out =  _remote_testssl(hostname, remote_host)
#     else:
#         out = _local_testssl(hostname, check_mx)
# 
#     # fix json syntax error
#     out = re.sub(r'"Invocation.*?\n', '', out.decode(), 1).encode()
# 
#     return out
# 
# def parse_common_testssl(json: str, prefix: str):
#     """Perform common parsing tasks on result JSONs."""
#     result = {
#         '{}_has_ssl'.format(prefix): True,  # otherwise an exception would have been thrown before
#     }
# 
#     # Detect if cert is valid
#     trust_cert = None
#     trust_chain = None
#     trust_pat = re.compile(r'(^trust$)|(.*? trust)')
#     chain_pat = re.compile(r'.*?chain_of_trust$')
#     # TODO If a server uses more than one certificate, this code will validate only the last one.
#     for default in json['scanResult'][0]['serverDefaults']:
#         if trust_pat.search(default['id']) is not None:
#             trust_cert = default
#         elif chain_pat.search(default['id']) is not None:
#             trust_chain = default
#         elif default["id"] == "issuer" and default["severity"] == "CRITICAL":
#             trust_chain = default
# 
#     assert trust_cert is not None
#     assert trust_chain is not None
#     
#     reason = ""
#     trusted = True
#     if not trust_cert['severity'] in ['OK', "INFO"]:
#         reason += trust_cert['finding']
#         trusted = False
#     if not trust_chain['severity'] in ['OK', 'INFO']:
#         reason += trust_chain['finding']
#         trusted = False
# 
#     result['{}_cert_trusted'.format(prefix)] = trusted
#     result['{}_cert_trusted_reason'.format(prefix)] = reason
# 
# 
#     # pfs
#     result['{}_pfs'.format(prefix)] = json['scanResult'][0]['pfs'][0]['severity'] == 'OK'
# 
#     # detect protocols
#     pattern = re.compile(r'is (not )?offered')
#     for p in json['scanResult'][0]['protocols']:
#         if p['severity'] == "CRITICAL":
#             # Hardcoded special case to grab a specific error
#             # This is horrible style
#             # TODO make less horrible
#             pat = re.compile(r'higher version number')
#             match = pat.search(p['finding'])
#             result['{}_has_protocol_{}'.format(prefix, p['id'])] = match is None
#             continue
#         match = pattern.search(p['finding'])
#         if not match:
#             continue
#         result['{}_has_protocol_{}'.format(prefix, p['id'])] = match.group(1) is None
# 
#     # Detect vulnerabilities
#     result['{}_vulnerabilities'.format(prefix)] = {}
#     for vuln in json['scanResult'][0]['vulnerabilities']:
#         if vuln['severity'] != u"OK" and vuln['severity'] != u'INFO':
#             result['{}_vulnerabilities'.format(prefix)][vuln['id']] = {
#                 'severity': vuln['severity'],
#                 'cve': vuln['cve'] if 'cve' in vuln.keys() else "",
#                 'finding': vuln['finding'],
#             }
#     
#     # Detect ciphers
#     # TODO Do we maybe want to get all cipher info, not only the bad ones?
#     result['{}_ciphers'.format(prefix)] = {}
#     for cipher in json['scanResult'][0]['ciphers']:
#         if cipher['severity'] != u"OK" and cipher['severity'] != u'INFO':
#             result['{}_ciphers'.format(prefix)][cipher['id']] = {
#                 'severity': cipher['severity'],
#                 'finding': cipher['finding'],
#             }
# 
#     return result


# Path: privacyscore/test_suites/testssl_https.py
import json
import re
import os
from typing import Dict, Union
from urllib.parse import urlparse
from django.conf import settings
from privacyscore.utils import get_list_item_by_dict_entry
from .testssl.common import run_testssl, parse_common_testssl

    if result['web_has_hsts_preload_header']:
        result['web_has_hsts_header'] = True
    elif hsts_item is not None:
        result['web_has_hsts_header'] = hsts_item['severity'] == 'OK'
    
    if hsts_time_item is not None:
        result['web_has_hsts_header'] = True
        result["web_has_hsts_header_sufficient_time"] = hsts_time_item['severity'] == 'OK'

    # Check the HSTS Preloading database
    result["web_has_hsts_preload"] = False
    with open(os.path.join(settings.SCAN_TEST_BASEPATH, "vendor/HSTSPreload", "transport_security_state_static")) as fo:
        preloads = json.loads(fo.read())
    host = data["target host"]
    # Check if exact hostname is included
    if not _check_contained(preloads, host):
        # If not included, construct ever shorter hostnames and look for policies
        # on those versions that include subdomains
        split = host.split(".")
        for i in range(1, len(split)):
            if _check_contained(preloads, ".".join(split[i:]), True):
                # Found
                result["web_has_hsts_preload"] = True
    else:
        # Found
        result["web_has_hsts_preload"] = True
    return result


def _detect_hpkp(data: dict) -> dict:

    hpkp_item = get_list_item_by_dict_entry(