ghosttrace-osint 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Benthota Malavi Arachchige Kaveesha Mishen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,3 @@
1
+ include README.md
2
+ include LICENSE
3
+ include requirements.txt
@@ -0,0 +1,21 @@
1
+ Metadata-Version: 2.4
2
+ Name: ghosttrace-osint
3
+ Version: 1.0.0
4
+ Summary: OSINT Recon Engine — IP, Domain, Username Intelligence
5
+ Home-page: https://github.com/YOURUSERNAME/ghosttrace
6
+ Author: YourName
7
+ Author-email: youremail@gmail.com
8
+ License: MIT
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Topic :: Security
13
+ Requires-Python: >=3.7
14
+ Description-Content-Type: text/markdown
15
+ License-File: LICENSE
16
+ Requires-Dist: requests>=2.28.0
17
+ Requires-Dist: python-dotenv>=1.0.0
18
+ Dynamic: license-file
19
+
20
+ # GhostTrace
21
+ OSINT Recon Engine - IP · Domain · Username Intelligence
@@ -0,0 +1,2 @@
1
+ # GhostTrace
2
+ OSINT Recon Engine - IP · Domain · Username Intelligence
@@ -0,0 +1,2 @@
1
+ __version__ = "1.0.0"
2
+ __author__ = "Kaveesha Mishen"
@@ -0,0 +1,92 @@
1
+ import sys
2
+ import os
3
+
4
+ if sys.platform == "win32":
5
+ import io
6
+ sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')
7
+
8
+ import argparse
9
+ from ghosttrace.modules.colors import enable_windows_ansi, GREEN, CYAN, YELLOW, WHITE, GRAY, RED, RESET
10
+ from ghosttrace.modules.banner import print_banner
11
+ from ghosttrace.modules.detector import detect_target_type
12
+ from ghosttrace.modules.ip_lookup import scan_ip
13
+ from ghosttrace.modules.domain_lookup import scan_domain
14
+ from ghosttrace.modules.username_lookup import scan_username
15
+ from ghosttrace.modules.reporter import save_report
16
+
17
+ enable_windows_ansi()
18
+
19
+
20
+ def parse_args():
21
+ parser = argparse.ArgumentParser(
22
+ description="GhostTrace - OSINT Recon Engine",
23
+ formatter_class=argparse.RawTextHelpFormatter
24
+ )
25
+ parser.add_argument("target", nargs="?", help="Target: IP, domain, or username")
26
+ parser.add_argument("-o", "--output", help="Save report (e.g. report.json)", metavar="FILE")
27
+ parser.add_argument("-t", "--type", choices=["ip", "domain", "username"],
28
+ help="Force target type")
29
+ return parser.parse_args()
30
+
31
+
32
+ def interactive_mode():
33
+ print(f"\n{CYAN} What do you want to scan?{RESET}")
34
+ print(f" {GREEN}[1]{RESET} IP Address")
35
+ print(f" {GREEN}[2]{RESET} Domain")
36
+ print(f" {GREEN}[3]{RESET} Username")
37
+ print()
38
+ choice = input(f" {YELLOW}Select (1/2/3) or just type your target:{RESET} ").strip()
39
+
40
+ type_map = {"1": "ip", "2": "domain", "3": "username"}
41
+ if choice in type_map:
42
+ target = input(f" {YELLOW}Enter target:{RESET} ").strip()
43
+ return target, type_map[choice]
44
+ else:
45
+ return choice, None
46
+
47
+
48
+ def main():
49
+ print_banner()
50
+ args = parse_args()
51
+
52
+ if args.target:
53
+ target = args.target.strip()
54
+ target_type = args.type if args.type else detect_target_type(target)
55
+ else:
56
+ target, target_type = interactive_mode()
57
+ if not target_type:
58
+ target_type = detect_target_type(target)
59
+
60
+ if not target:
61
+ print(f"\n {RED}[!] No target provided. Exiting.{RESET}\n")
62
+ sys.exit(1)
63
+
64
+ print(f"\n{GRAY} {'─' * 52}{RESET}")
65
+ print(f" {GREEN}[>>]{RESET} Target : {WHITE}{target}{RESET}")
66
+ print(f" {GREEN}[>>]{RESET} Type : {WHITE}{target_type.upper()}{RESET}")
67
+ print(f" {GREEN}[>>]{RESET} Status : {YELLOW}Initiating scan...{RESET}")
68
+ print(f"{GRAY} {'─' * 52}{RESET}\n")
69
+
70
+ results = {}
71
+ if target_type == "ip":
72
+ results = scan_ip(target)
73
+ elif target_type == "domain":
74
+ results = scan_domain(target)
75
+ elif target_type == "username":
76
+ results = scan_username(target)
77
+ else:
78
+ print(f"\n {RED}[!] Unknown target type. Use -t ip/domain/username{RESET}\n")
79
+ sys.exit(1)
80
+
81
+ print(f"\n{GRAY} {'─' * 52}{RESET}")
82
+
83
+ if args.output:
84
+ save_report(target, target_type, results, args.output)
85
+ print(f" {GREEN}[✓]{RESET} Report saved → {WHITE}{args.output}{RESET}")
86
+
87
+ print(f"\n {GRAY}[GhostTrace] Scan complete. Stay invisible.{RESET}\n")
88
+ input(f" {YELLOW}Press Enter to exit...{RESET}")
89
+
90
+
91
+ if __name__ == "__main__":
92
+ main()
@@ -0,0 +1 @@
1
+ # GhostTrace modules
@@ -0,0 +1,18 @@
1
+ from ghosttrace.modules.colors import enable_windows_ansi, GREEN, GRAY, RESET
2
+
3
+ enable_windows_ansi()
4
+
5
+ def print_banner():
6
+ banner = f"""
7
+ {GREEN}
8
+ ██████╗ ██╗ ██╗ ██████╗ ███████╗████████╗████████╗██████╗ █████╗ ██████╗███████╗
9
+ ██╔════╝ ██║ ██║██╔═══██╗██╔════╝╚══██╔══╝╚══██╔══╝██╔══██╗██╔══██╗██╔════╝██╔════╝
10
+ ██║ ███╗███████║██║ ██║███████╗ ██║ ██║ ██████╔╝███████║██║ █████╗
11
+ ██║ ██║██╔══██║██║ ██║╚════██║ ██║ ██║ ██╔══██╗██╔══██║██║ ██╔══╝
12
+ ╚██████╔╝██║ ██║╚██████╔╝███████║ ██║ ██║ ██║ ██║██║ ██║╚██████╗███████╗
13
+ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝╚══════╝
14
+ {RESET}
15
+ {GRAY} [ OSINT Recon Engine v1.0 ] [ IP • Domain • Username Intelligence ]
16
+ [ "Leave no trace. Find every trace." ]
17
+ {RESET}"""
18
+ print(banner)
@@ -0,0 +1,44 @@
1
+ import sys
2
+ import os
3
+
4
+ def enable_windows_ansi():
5
+ if sys.platform == "win32":
6
+ try:
7
+ import ctypes
8
+ kernel32 = ctypes.windll.kernel32
9
+ kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7)
10
+ except Exception:
11
+ pass
12
+ os.environ["PYTHONIOENCODING"] = "utf-8"
13
+
14
+ enable_windows_ansi()
15
+
16
+ GREEN = "\033[92m"
17
+ CYAN = "\033[96m"
18
+ YELLOW = "\033[93m"
19
+ RED = "\033[91m"
20
+ WHITE = "\033[97m"
21
+ GRAY = "\033[90m"
22
+ RESET = "\033[0m"
23
+ BOLD = "\033[1m"
24
+
25
+ def field(label, value, color=None):
26
+ if color is None:
27
+ color = WHITE
28
+ print(f" {GREEN}[+]{RESET} {label:<22} {color}{value}{RESET}")
29
+
30
+ def section(title):
31
+ print(f"\n{CYAN} ◈ {title}{RESET}")
32
+ print(f"{GRAY} {'─' * 52}{RESET}")
33
+
34
+ def error(msg):
35
+ print(f" {RED}[!]{RESET} {msg}")
36
+
37
+ def warn(msg):
38
+ print(f" {YELLOW}[~]{RESET} {msg}")
39
+
40
+ def success(msg):
41
+ print(f" {GREEN}[✓]{RESET} {msg}")
42
+
43
+ def info(msg):
44
+ print(f" {GRAY}[·]{RESET} {msg}")
@@ -0,0 +1,14 @@
1
+ import re
2
+
3
+ def detect_target_type(target: str) -> str:
4
+ ipv4_pattern = re.compile(r"^(\d{1,3}\.){3}\d{1,3}$")
5
+ ipv6_pattern = re.compile(r"^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$")
6
+ domain_pattern = re.compile(
7
+ r"^(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$"
8
+ )
9
+ if ipv4_pattern.match(target) or ipv6_pattern.match(target):
10
+ return "ip"
11
+ elif domain_pattern.match(target):
12
+ return "domain"
13
+ else:
14
+ return "username"
@@ -0,0 +1,135 @@
1
+ import socket
2
+ import ssl
3
+ import datetime
4
+ import subprocess
5
+ import requests
6
+ from ghosttrace.modules.colors import field, section, error, warn, info, GREEN, RED, YELLOW, GRAY, WHITE, RESET
7
+
8
+ def scan_domain(domain: str) -> dict:
9
+ results = {"target": domain, "type": "domain"}
10
+
11
+ section("IP RESOLUTION")
12
+ try:
13
+ ip = socket.gethostbyname(domain)
14
+ field("Resolved IP", ip)
15
+ results["resolved_ip"] = ip
16
+ r = requests.get(f"http://ip-api.com/json/{ip}?fields=country,city,isp,org,as", timeout=5)
17
+ geo = r.json()
18
+ field("Country", geo.get("country", "N/A"))
19
+ field("City", geo.get("city", "N/A"))
20
+ field("ISP", geo.get("isp", "N/A"))
21
+ field("ASN", geo.get("as", "N/A"))
22
+ results["geo"] = geo
23
+ except Exception as e:
24
+ error(str(e))
25
+
26
+ section("WHOIS / REGISTRATION INFO")
27
+ try:
28
+ r = requests.get(f"https://rdap.org/domain/{domain}", timeout=6)
29
+ rdap = r.json()
30
+ whois_data = {}
31
+ for event in rdap.get("events", []):
32
+ action = event.get("eventAction", "")
33
+ date = event.get("eventDate", "N/A")
34
+ if action == "registration":
35
+ field("Registered", date[:10]); whois_data["registered"] = date[:10]
36
+ elif action == "expiration":
37
+ field("Expires", date[:10]); whois_data["expires"] = date[:10]
38
+ elif action == "last changed":
39
+ field("Last Updated", date[:10]); whois_data["last_updated"] = date[:10]
40
+ for entity in rdap.get("entities", []):
41
+ if "registrar" in entity.get("roles", []):
42
+ vcard = entity.get("vcardArray", [])
43
+ if vcard and len(vcard) > 1:
44
+ for v in vcard[1]:
45
+ if v[0] == "fn":
46
+ field("Registrar", v[3])
47
+ whois_data["registrar"] = v[3]
48
+ break
49
+ ns_list = [ns.get("ldhName", "") for ns in rdap.get("nameservers", [])]
50
+ if ns_list:
51
+ field("Nameservers", ", ".join(ns_list))
52
+ whois_data["nameservers"] = ns_list
53
+ status = rdap.get("status", [])
54
+ if status:
55
+ field("Domain Status", ", ".join(status))
56
+ results["whois"] = whois_data
57
+ except Exception as e:
58
+ warn(f"WHOIS lookup failed: {e}")
59
+
60
+ section("DNS RECORDS")
61
+ try:
62
+ dns_records = {}
63
+ for rtype in ["A", "MX", "TXT", "NS", "CNAME"]:
64
+ try:
65
+ result = subprocess.run(
66
+ ["nslookup", f"-type={rtype}", domain],
67
+ capture_output=True, text=True, timeout=4
68
+ )
69
+ lines = [
70
+ l.strip() for l in result.stdout.splitlines()
71
+ if l.strip()
72
+ and "Server:" not in l
73
+ and "Address:" not in l
74
+ and "#" not in l
75
+ and domain.lower() in l.lower()
76
+ ]
77
+ if lines:
78
+ field(f"{rtype} Record", lines[0][:58])
79
+ dns_records[rtype] = lines
80
+ except Exception:
81
+ pass
82
+ results["dns"] = dns_records
83
+ except Exception as e:
84
+ error(str(e))
85
+
86
+ section("SSL CERTIFICATE")
87
+ try:
88
+ ctx = ssl.create_default_context()
89
+ conn = ctx.wrap_socket(socket.socket(), server_hostname=domain)
90
+ conn.settimeout(5)
91
+ conn.connect((domain, 443))
92
+ cert = conn.getpeercert()
93
+ conn.close()
94
+ subject = dict(x[0] for x in cert.get("subject", []))
95
+ issuer = dict(x[0] for x in cert.get("issuer", []))
96
+ not_after = cert.get("notAfter", "N/A")
97
+ field("Common Name", subject.get("commonName", "N/A"))
98
+ field("Issued By", issuer.get("organizationName", "N/A"))
99
+ field("Valid Until", not_after)
100
+ sans = [v for k, v in cert.get("subjectAltName", []) if k == "DNS"]
101
+ if sans:
102
+ field("Alt Names (SANs)", ", ".join(sans[:5]))
103
+ try:
104
+ expiry = datetime.datetime.strptime(not_after, "%b %d %H:%M:%S %Y %Z")
105
+ days_left = (expiry - datetime.datetime.utcnow()).days
106
+ color = RED if days_left < 30 else GREEN
107
+ field("Days Until Expiry", str(days_left), color)
108
+ except Exception:
109
+ pass
110
+ results["ssl"] = {"subject": subject, "issuer": issuer, "expiry": not_after, "sans": sans}
111
+ except Exception as e:
112
+ warn(f"SSL check failed: {e}")
113
+
114
+ section("SUBDOMAIN RECON (Certificate Transparency)")
115
+ try:
116
+ r = requests.get(f"https://crt.sh/?q=%.{domain}&output=json", timeout=8)
117
+ certs = r.json()
118
+ subdomains = set()
119
+ for entry in certs:
120
+ for sub in entry.get("name_value", "").split("\n"):
121
+ sub = sub.strip().lstrip("*.")
122
+ if sub.endswith(domain) and sub != domain:
123
+ subdomains.add(sub)
124
+ if subdomains:
125
+ for sub in sorted(subdomains)[:15]:
126
+ field("Subdomain", sub, YELLOW)
127
+ if len(subdomains) > 15:
128
+ info(f"...and {len(subdomains)-15} more subdomains found")
129
+ else:
130
+ info("No subdomains found in certificate transparency logs")
131
+ results["subdomains"] = list(subdomains)
132
+ except Exception as e:
133
+ error(str(e))
134
+
135
+ return results
@@ -0,0 +1,105 @@
1
+ import socket
2
+ import requests
3
+ from ghosttrace.modules.colors import field, section, error, warn, info, GREEN, RED, YELLOW, GRAY, RESET
4
+
5
+ def scan_ip(ip: str) -> dict:
6
+ results = {"target": ip, "type": "ip"}
7
+
8
+ section("GEOLOCATION & NETWORK INFO")
9
+ try:
10
+ r = requests.get(
11
+ f"http://ip-api.com/json/{ip}?fields=status,message,country,regionName,city,zip,lat,lon,timezone,isp,org,as,query",
12
+ timeout=6
13
+ )
14
+ geo = r.json()
15
+ if geo.get("status") == "success":
16
+ data = {
17
+ "IP Address": geo.get("query", "N/A"),
18
+ "Country": geo.get("country", "N/A"),
19
+ "Region": geo.get("regionName", "N/A"),
20
+ "City": geo.get("city", "N/A"),
21
+ "ZIP Code": geo.get("zip", "N/A"),
22
+ "Latitude": str(geo.get("lat", "N/A")),
23
+ "Longitude": str(geo.get("lon", "N/A")),
24
+ "Timezone": geo.get("timezone", "N/A"),
25
+ "ISP": geo.get("isp", "N/A"),
26
+ "Organization": geo.get("org", "N/A"),
27
+ "ASN": geo.get("as", "N/A"),
28
+ }
29
+ for k, v in data.items():
30
+ field(k, v)
31
+ results["geolocation"] = data
32
+ else:
33
+ error(f"Geo lookup failed: {geo.get('message', 'unknown error')}")
34
+ except Exception as e:
35
+ error(f"Geo lookup failed: {e}")
36
+
37
+ section("REVERSE DNS")
38
+ try:
39
+ hostname = socket.gethostbyaddr(ip)[0]
40
+ field("Hostname", hostname)
41
+ results["reverse_dns"] = hostname
42
+ except socket.herror:
43
+ info("No PTR record found for this IP")
44
+ results["reverse_dns"] = None
45
+ except Exception as e:
46
+ error(str(e))
47
+
48
+ section("THREAT INTELLIGENCE (AbuseIPDB)")
49
+ import os
50
+ from dotenv import load_dotenv
51
+ load_dotenv()
52
+ ABUSEIPDB_KEY = os.getenv("ABUSEIPDB_KEY", "YOUR_ABUSEIPDB_API_KEY")
53
+ if ABUSEIPDB_KEY != "YOUR_ABUSEIPDB_API_KEY":
54
+ try:
55
+ headers = {"Key": ABUSEIPDB_KEY, "Accept": "application/json"}
56
+ r = requests.get(
57
+ "https://api.abuseipdb.com/api/v2/check",
58
+ headers=headers,
59
+ params={"ipAddress": ip, "maxAgeInDays": 90},
60
+ timeout=6
61
+ )
62
+ data = r.json().get("data", {})
63
+ score = data.get("abuseConfidenceScore", 0)
64
+ color = RED if score > 50 else GREEN
65
+ field("Abuse Score", f"{score}/100", color)
66
+ field("Total Reports", str(data.get("totalReports", 0)))
67
+ field("Last Reported", data.get("lastReportedAt") or "Never")
68
+ field("Tor Node", str(data.get("isTor", False)))
69
+ results["threat_intel"] = data
70
+ except Exception as e:
71
+ error(str(e))
72
+ else:
73
+ warn("AbuseIPDB key not set — create a .env file with ABUSEIPDB_KEY=yourkey")
74
+ info("Get a free key at: https://www.abuseipdb.com/register")
75
+
76
+ section("PORT SCAN (Top 15 Common Ports)")
77
+ common_ports = {
78
+ 21: "FTP", 22: "SSH", 23: "Telnet",
79
+ 25: "SMTP", 53: "DNS", 80: "HTTP",
80
+ 110: "POP3", 143: "IMAP", 443: "HTTPS",
81
+ 445: "SMB", 3306: "MySQL", 3389: "RDP",
82
+ 5900: "VNC", 6379: "Redis", 8080: "HTTP-Alt"
83
+ }
84
+ open_ports = []
85
+ print(f" {GRAY}Scanning ports", end="", flush=True)
86
+ for port, service in common_ports.items():
87
+ print(f"{GRAY}.{RESET}", end="", flush=True)
88
+ try:
89
+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
90
+ s.settimeout(0.5)
91
+ if s.connect_ex((ip, port)) == 0:
92
+ open_ports.append((port, service))
93
+ s.close()
94
+ except Exception:
95
+ pass
96
+ print(f" Done{RESET}")
97
+
98
+ if open_ports:
99
+ for port, service in open_ports:
100
+ field(f"Port {port}/{service}", "OPEN", RED)
101
+ else:
102
+ info("No common ports open (or filtered by firewall)")
103
+ results["open_ports"] = open_ports
104
+
105
+ return results
@@ -0,0 +1,24 @@
1
+ import json
2
+ import datetime
3
+
4
+ def save_report(target: str, target_type: str, results: dict, filepath: str):
5
+ timestamp = datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC")
6
+ report = {
7
+ "tool": "GhostTrace v1.0",
8
+ "timestamp": timestamp,
9
+ "target": target,
10
+ "type": target_type,
11
+ "results": results
12
+ }
13
+ if filepath.endswith(".json"):
14
+ with open(filepath, "w") as f:
15
+ json.dump(report, f, indent=4)
16
+ else:
17
+ with open(filepath, "w") as f:
18
+ f.write("=" * 60 + "\n")
19
+ f.write(" GHOSTTRACE OSINT REPORT\n")
20
+ f.write(f" Generated : {timestamp}\n")
21
+ f.write(f" Target : {target} [{target_type.upper()}]\n")
22
+ f.write("=" * 60 + "\n\n")
23
+ f.write(json.dumps(results, indent=4))
24
+ f.write("\n\n[GhostTrace] End of Report\n")
@@ -0,0 +1,71 @@
1
+ import requests
2
+ import threading
3
+ from ghosttrace.modules.colors import field, section, info, GREEN, GRAY, WHITE, RESET
4
+
5
+ PLATFORMS = [
6
+ ("GitHub", "https://github.com/{u}", "status", 200),
7
+ ("GitLab", "https://gitlab.com/{u}", "status", 200),
8
+ ("Twitter/X", "https://x.com/{u}", "status", 200),
9
+ ("Reddit", "https://www.reddit.com/user/{u}", "status", 200),
10
+ ("Instagram", "https://www.instagram.com/{u}/", "status", 200),
11
+ ("TikTok", "https://www.tiktok.com/@{u}", "status", 200),
12
+ ("YouTube", "https://www.youtube.com/@{u}", "status", 200),
13
+ ("Pinterest", "https://www.pinterest.com/{u}/", "status", 200),
14
+ ("Tumblr", "https://{u}.tumblr.com", "status", 200),
15
+ ("Medium", "https://medium.com/@{u}", "status", 200),
16
+ ("Dev.to", "https://dev.to/{u}", "status", 200),
17
+ ("Hashnode", "https://hashnode.com/@{u}", "status", 200),
18
+ ("Twitch", "https://www.twitch.tv/{u}", "status", 200),
19
+ ("Steam", "https://steamcommunity.com/id/{u}", "status", 200),
20
+ ("Keybase", "https://keybase.io/{u}", "status", 200),
21
+ ("HackerNews", "https://news.ycombinator.com/user?id={u}", "text", "user?id="),
22
+ ("Product Hunt", "https://www.producthunt.com/@{u}", "status", 200),
23
+ ("Pastebin", "https://pastebin.com/u/{u}", "status", 200),
24
+ ("DockerHub", "https://hub.docker.com/u/{u}", "status", 200),
25
+ ("NPM", "https://www.npmjs.com/~{u}", "status", 200),
26
+ ("PyPI", "https://pypi.org/user/{u}/", "status", 200),
27
+ ("HackTheBox", "https://app.hackthebox.com/users/profile/{u}", "status", 200),
28
+ ("TryHackMe", "https://tryhackme.com/p/{u}", "status", 200),
29
+ ]
30
+
31
+ HEADERS = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"}
32
+
33
+ def _check(username, name, url_tpl, check_type, match, found, lock):
34
+ url = url_tpl.replace("{u}", username)
35
+ try:
36
+ r = requests.get(url, headers=HEADERS, timeout=6, allow_redirects=True)
37
+ hit = (check_type == "status" and r.status_code == match) or \
38
+ (check_type == "text" and match in r.text)
39
+ if hit:
40
+ with lock:
41
+ found[name] = url
42
+ except Exception:
43
+ pass
44
+
45
+ def scan_username(username: str) -> dict:
46
+ results = {"target": username, "type": "username"}
47
+ section(f"USERNAME HUNT — @{username}")
48
+ print(f" {GRAY}Scanning {len(PLATFORMS)} platforms, please wait...{RESET}\n")
49
+
50
+ found = {}
51
+ lock = threading.Lock()
52
+ threads = [
53
+ threading.Thread(target=_check, args=(username, name, url_tpl, ct, match, found, lock))
54
+ for name, url_tpl, ct, match in PLATFORMS
55
+ ]
56
+ for t in threads: t.start()
57
+ for t in threads: t.join()
58
+
59
+ section(f"RESULTS — {len(found)} of {len(PLATFORMS)} platforms matched")
60
+ all_checked = []
61
+ for name, url_tpl, _, _ in PLATFORMS:
62
+ if name in found:
63
+ print(f" {GREEN}[FOUND]{RESET} {name:<18} {WHITE}{found[name]}{RESET}")
64
+ all_checked.append({"platform": name, "url": found[name], "found": True})
65
+ else:
66
+ print(f" {GRAY}[-----]{RESET} {name:<18} not found")
67
+ all_checked.append({"platform": name, "found": False})
68
+
69
+ results["platforms"] = all_checked
70
+ results["found_count"] = len(found)
71
+ return results
@@ -0,0 +1,21 @@
1
+ Metadata-Version: 2.4
2
+ Name: ghosttrace-osint
3
+ Version: 1.0.0
4
+ Summary: OSINT Recon Engine — IP, Domain, Username Intelligence
5
+ Home-page: https://github.com/YOURUSERNAME/ghosttrace
6
+ Author: YourName
7
+ Author-email: youremail@gmail.com
8
+ License: MIT
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Topic :: Security
13
+ Requires-Python: >=3.7
14
+ Description-Content-Type: text/markdown
15
+ License-File: LICENSE
16
+ Requires-Dist: requests>=2.28.0
17
+ Requires-Dist: python-dotenv>=1.0.0
18
+ Dynamic: license-file
19
+
20
+ # GhostTrace
21
+ OSINT Recon Engine - IP · Domain · Username Intelligence
@@ -0,0 +1,23 @@
1
+ LICENSE
2
+ MANIFEST.in
3
+ README.md
4
+ pyproject.toml
5
+ requirements.txt
6
+ setup.cfg
7
+ setup.py
8
+ ghosttrace/__init__.py
9
+ ghosttrace/__main__.py
10
+ ghosttrace/modules/__init__.py
11
+ ghosttrace/modules/banner.py
12
+ ghosttrace/modules/colors.py
13
+ ghosttrace/modules/detector.py
14
+ ghosttrace/modules/domain_lookup.py
15
+ ghosttrace/modules/ip_lookup.py
16
+ ghosttrace/modules/reporter.py
17
+ ghosttrace/modules/username_lookup.py
18
+ ghosttrace_osint.egg-info/PKG-INFO
19
+ ghosttrace_osint.egg-info/SOURCES.txt
20
+ ghosttrace_osint.egg-info/dependency_links.txt
21
+ ghosttrace_osint.egg-info/entry_points.txt
22
+ ghosttrace_osint.egg-info/requires.txt
23
+ ghosttrace_osint.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ ghosttrace = ghosttrace.__main__:main
@@ -0,0 +1,2 @@
1
+ requests>=2.28.0
2
+ python-dotenv>=1.0.0
@@ -0,0 +1,3 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
@@ -0,0 +1 @@
1
+ requests>=2.28.0
@@ -0,0 +1,31 @@
1
+ [metadata]
2
+ name = ghosttrace-osint
3
+ version = 1.0.0
4
+ author = YourName
5
+ author_email = youremail@gmail.com
6
+ description = OSINT Recon Engine — IP, Domain, Username Intelligence
7
+ long_description = file: README.md
8
+ long_description_content_type = text/markdown
9
+ url = https://github.com/YOURUSERNAME/ghosttrace
10
+ license = MIT
11
+ classifiers =
12
+ Programming Language :: Python :: 3
13
+ License :: OSI Approved :: MIT License
14
+ Operating System :: OS Independent
15
+ Topic :: Security
16
+
17
+ [options]
18
+ packages = find:
19
+ python_requires = >=3.7
20
+ install_requires =
21
+ requests>=2.28.0
22
+ python-dotenv>=1.0.0
23
+
24
+ [options.entry_points]
25
+ console_scripts =
26
+ ghosttrace = ghosttrace.__main__:main
27
+
28
+ [egg_info]
29
+ tag_build =
30
+ tag_date = 0
31
+
@@ -0,0 +1,3 @@
1
+ from setuptools import setup
2
+
3
+ setup()