'''
对目标资产的管理,包括信息的更新维护等
'''
import re
import socket
import ipaddress
import geoip2.database
import ipwhois
import requests
import whois
import dns.resolver
import ssl
from urllib.parse import urlparse
from datetime import datetime

#pattern = r'^(https?://)?((?:[a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}|(?:\d{1,3}\.){3}\d{1,3})(:\d+)?(/.*)?$'
pattern = r'^(https?://)?((?:[0-9]{1,3}\.){3}[0-9]{1,3}|(?:[a-zA-Z0-9-]+\.)+[a-zA-Z]{2,})(:\d+)?(/.*)?$'

class TargetManager:
    def __init__(self):
        pass

    def extract_and_store_ips(self,str_target: str):
        # 正则匹配IP地址(包含IPv4、IPv6及带端口的情况)
        ip_pattern = r'''
            (?P<ipv6>\[?([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\]?|  # 完整IPv6
            ::([0-9a-fA-F]{1,4}:){0,6}[0-9a-fA-F]{1,4}|             # 缩写IPv6
            (?P<ipv4>(\d{1,3}\.){3}\d{1,3})(?::\d+)?                # IPv4及端口
        '''
        candidates = re.finditer(ip_pattern, str_target, re.VERBOSE)

        valid_ips = []
        for match in candidates:
            raw_ip = match.group().lstrip('[').rstrip(']')  # 处理IPv6方括号

            # 分离IP和端口(如192.168.1.1:8080)
            if ':' in raw_ip and not raw_ip.count(':') > 1:  # 排除IPv6的冒号
                ip_part = raw_ip.split(':')[0]
            else:
                ip_part = raw_ip

            # 验证IP有效性并分类
            try:
                ip_obj = ipaddress.ip_address(ip_part)
                ip_type = 'v6' if ip_obj.version == 6 else 'v4'
                valid_ips.append({
                    'binary_ip': ip_obj.packed,
                    'ip_type': ip_type,
                    'original': ip_part
                })
            except ValueError:
                continue

    # 辅助函数:验证IPv4地址的有效性
    def _is_valid_ipv4(self,ip):
        parts = ip.split('.')
        if len(parts) != 4:
            return False
        for part in parts:
            if not part.isdigit():
                return False
        return True

    #验证目标格式的合法性,并提取域名或IP
    def validate_and_extract(self,input_str):
        '''
        :param input_str:
        :return: bool,real_target,int(1-IP,2-domain),fake_target
        '''
        type = None
        fake_target = ""
        real_target = ""
        target_type,target = self.is_valid_target(input_str)
        if not target_type: #非法目标
            return False,input_str,type,fake_target

        if target_type =="IPv4" or target_type=="IPv6":
            type = 1    #IP
            real_target = target
            fake_target = "192.168.3.107"
        elif target_type == "URL":
            type = 2 #domain
            real_target = target
            fake_target = "czzfkjxx"
        else:   #目标不合法
            return False,real_target,type,fake_target
        return True,real_target,type,fake_target

    #验证目标是否合法
    def is_valid_target(self,target):
        '''
        检查目标的合法性,并对于URL地址,提取域名部分,若是ip的URL,提取IP
        :param target:
        :return: target_type new_target
        '''
        # Check if target is a valid IP address (IPv4 or IPv6)
        try:
            ip = ipaddress.ip_address(target)
            if ip.version == 4:
                return 'IPv4',target
            elif ip.version == 6:
                return 'IPv6',target
        except ValueError:
            pass

        # Check if target is a valid URL
        try:
            result = urlparse(target)
            # Only allow http or https schemes
            if not result.scheme:
                result = urlparse('http://'+target)
            netloc = result.netloc
            if not netloc:
                return None,None
            # Handle IPv6 addresses in URLs (enclosed in brackets)
            if netloc.startswith('[') and netloc.endswith(']'):
                ip_str = netloc[1:-1]
                try:
                    ipaddress.IPv6Address(ip_str)
                    return 'IPv6',ipaddress
                except ValueError:
                    return None,None
            # Handle potential IPv4 addresses
            elif self._is_valid_ipv4(netloc):
                try:
                    ipaddress.IPv4Address(netloc)
                    return 'IPv4',ipaddress
                except ValueError:
                    return None,None
            # If not an IP-like string, assume it's a domain name and accept
            return 'URL',netloc
        except ValueError:
            return None,None

    def collect_ip_info(self,ip):
        info = {}
        try:
            # 首先尝试 RDAP 查询
            obj = ipwhois.IPWhois(ip)
            whois_info = obj.lookup_rdap()
            info['asn'] = whois_info.get('asn')  # 获取 ASN
            info['isp'] = whois_info.get('network', {}).get('name')  # 获取 ISP
        except (ipwhois.exceptions.IPDefinedError, ipwhois.exceptions.ASNRegistryError,
                requests.exceptions.RequestException) as e:
            # 如果 RDAP 失败,回退到 WHOIS 查询
            try:
                whois_info = obj.lookup_whois()
                info['asn'] = whois_info.get('asn')  # 获取 ASN
                if whois_info.get('nets'):
                    # 从 WHOIS 的 'nets' 中提取 ISP(通常在 description 字段)
                    info['isp'] = whois_info['nets'][0].get('description')
            except Exception as e:
                info['whois_error'] = str(e)  # 记录错误信息
        return info

    def collect_domain_info(self,domain):
        info = {}
        try:
            w = whois.whois(domain)
            info['registrar'] = w.registrar
            # 处理 creation_date
            if isinstance(w.creation_date, list):
                info['creation_date'] = [dt.strftime('%Y-%m-%d %H:%M:%S') if isinstance(dt, datetime) else str(dt) for
                                         dt in w.creation_date]
            elif isinstance(w.creation_date, datetime):
                info['creation_date'] = w.creation_date.strftime('%Y-%m-%d %H:%M:%S')
            else:
                info['creation_date'] = str(w.creation_date)

            # 处理 expiration_date
            if isinstance(w.expiration_date, list):
                info['expiration_date'] = [dt.strftime('%Y-%m-%d %H:%M:%S') if isinstance(dt, datetime) else str(dt) for
                                           dt in w.expiration_date]
            elif isinstance(w.expiration_date, datetime):
                info['expiration_date'] = w.expiration_date.strftime('%Y-%m-%d %H:%M:%S')
            else:
                info['expiration_date'] = str(w.expiration_date)

            info['user_name'] = str(w.name)
            info['emails'] = str(w.emails)
            info['status'] = str(w.status)

        except Exception as e:
            info['whois_error'] = str(e)

        try:
            answers = dns.resolver.resolve(domain, 'A')
            info['A_records'] = [r.to_text() for r in answers]
        except Exception as e:
            info['dns_error'] = str(e)

        return info

    def test(self,str_target):
        bok, target, type, fake_target = self.validate_and_extract(str_target)
        if not bok:
            print(f"{str_target}目标不合法{target}")
        else:
            print(f"{str_target}目标合法{target} ---- {fake_target}")

g_TM = TargetManager()

if __name__ == "__main__":
    #tm = TargetManager()
    #示例测试
    test_cases = [
        "256.254.1111.23",
        "8.8.8.8",
        "2001:db8::1",
        "http://www.crnn.cc/",
        "https://www.crnn.cn",
        "http://www.crnn.cc/product_category/network-security-services",
        "192.168.1.1:80",
        "example.com/path/to/resource",
        "www.crnn.cn",
        "oa.crnn.cn",
        "ftp://invalid.com",  # 不合规
        "http://300.400.500.600"  # 不合规
    ]

    # test_cases = [
    #     "http://www.crnn.cc/",
    #     "http://www.crnn.cc/product_category/network-security-services"
    # ]

    #tm.test("https://www.crnn.cn")

    for case in test_cases:
        g_TM.test(case)