milenium 0.4.2__tar.gz → 0.5.1__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.
Files changed (51) hide show
  1. {milenium-0.4.2 → milenium-0.5.1}/PKG-INFO +2 -1
  2. milenium-0.5.1/README.md +2 -0
  3. {milenium-0.4.2 → milenium-0.5.1}/milenium/cli.py +67 -0
  4. milenium-0.5.1/milenium/modules/aggregator.py +41 -0
  5. milenium-0.5.1/milenium/modules/email_validator.py +22 -0
  6. milenium-0.5.1/milenium/modules/exif_extractor.py +22 -0
  7. milenium-0.5.1/milenium/modules/github_search.py +29 -0
  8. milenium-0.5.1/milenium/modules/gravatar.py +13 -0
  9. milenium-0.5.1/milenium/modules/instagram_osint.py +25 -0
  10. milenium-0.5.1/milenium/modules/ip_geo_advanced.py +16 -0
  11. milenium-0.5.1/milenium/modules/password_pattern.py +32 -0
  12. milenium-0.5.1/milenium/modules/pgp_lookup.py +10 -0
  13. milenium-0.5.1/milenium/modules/reverse_whois.py +24 -0
  14. milenium-0.5.1/milenium/modules/tg_parser.py +20 -0
  15. milenium-0.5.1/milenium/modules/twitter_osint.py +13 -0
  16. milenium-0.5.1/milenium/modules/vk_osint.py +23 -0
  17. milenium-0.5.1/milenium/modules/wayback.py +18 -0
  18. milenium-0.5.1/milenium/modules/wifi_geolocation.py +27 -0
  19. {milenium-0.4.2 → milenium-0.5.1}/milenium/tui.py +65 -4
  20. {milenium-0.4.2 → milenium-0.5.1}/milenium.egg-info/PKG-INFO +2 -1
  21. {milenium-0.4.2 → milenium-0.5.1}/milenium.egg-info/SOURCES.txt +15 -1
  22. {milenium-0.4.2 → milenium-0.5.1}/pyproject.toml +1 -1
  23. milenium-0.4.2/README.md +0 -1
  24. milenium-0.4.2/milenium/modules/aggregator.py +0 -26
  25. {milenium-0.4.2 → milenium-0.5.1}/milenium/__init__.py +0 -0
  26. {milenium-0.4.2 → milenium-0.5.1}/milenium/modules/__init__.py +0 -0
  27. {milenium-0.4.2 → milenium-0.5.1}/milenium/modules/breach.py +0 -0
  28. {milenium-0.4.2 → milenium-0.5.1}/milenium/modules/breach_local.py +0 -0
  29. {milenium-0.4.2 → milenium-0.5.1}/milenium/modules/dehashed.py +0 -0
  30. {milenium-0.4.2 → milenium-0.5.1}/milenium/modules/dns_history.py +0 -0
  31. {milenium-0.4.2 → milenium-0.5.1}/milenium/modules/domain.py +0 -0
  32. {milenium-0.4.2 → milenium-0.5.1}/milenium/modules/dorker.py +0 -0
  33. {milenium-0.4.2 → milenium-0.5.1}/milenium/modules/email.py +0 -0
  34. {milenium-0.4.2 → milenium-0.5.1}/milenium/modules/hibp.py +0 -0
  35. {milenium-0.4.2 → milenium-0.5.1}/milenium/modules/ip.py +0 -0
  36. {milenium-0.4.2 → milenium-0.5.1}/milenium/modules/ip_reputation.py +0 -0
  37. {milenium-0.4.2 → milenium-0.5.1}/milenium/modules/leakcheck.py +0 -0
  38. {milenium-0.4.2 → milenium-0.5.1}/milenium/modules/logger.py +0 -0
  39. {milenium-0.4.2 → milenium-0.5.1}/milenium/modules/permutator.py +0 -0
  40. {milenium-0.4.2 → milenium-0.5.1}/milenium/modules/phone.py +0 -0
  41. {milenium-0.4.2 → milenium-0.5.1}/milenium/modules/pwned_passwords.py +0 -0
  42. {milenium-0.4.2 → milenium-0.5.1}/milenium/modules/report.py +0 -0
  43. {milenium-0.4.2 → milenium-0.5.1}/milenium/modules/shodan_lite.py +0 -0
  44. {milenium-0.4.2 → milenium-0.5.1}/milenium/modules/social.py +0 -0
  45. {milenium-0.4.2 → milenium-0.5.1}/milenium/modules/telegram_osint.py +0 -0
  46. {milenium-0.4.2 → milenium-0.5.1}/milenium/modules/username.py +0 -0
  47. {milenium-0.4.2 → milenium-0.5.1}/milenium.egg-info/dependency_links.txt +0 -0
  48. {milenium-0.4.2 → milenium-0.5.1}/milenium.egg-info/entry_points.txt +0 -0
  49. {milenium-0.4.2 → milenium-0.5.1}/milenium.egg-info/requires.txt +0 -0
  50. {milenium-0.4.2 → milenium-0.5.1}/milenium.egg-info/top_level.txt +0 -0
  51. {milenium-0.4.2 → milenium-0.5.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: milenium
3
- Version: 0.4.2
3
+ Version: 0.5.1
4
4
  Summary: OSINT / dox / deanon toolkit
5
5
  Requires-Python: >=3.9
6
6
  Description-Content-Type: text/markdown
@@ -13,3 +13,4 @@ Requires-Dist: click
13
13
  Requires-Dist: python-whois
14
14
 
15
15
  # milenium
16
+ # exiftool
@@ -0,0 +1,2 @@
1
+ # milenium
2
+ # exiftool
@@ -84,6 +84,73 @@ def user(nick, permutations, dorks):
84
84
  console.print(f"[bold cyan]Лог:[/bold cyan] {logger.path}")
85
85
  logger.close()
86
86
 
87
+ @main.command()
88
+ @click.argument("email")
89
+ def email_check(email):
90
+ """SMTP-валидация email + Gravatar + PGP + GitHub"""
91
+ logger = _init_logger()
92
+ from milenium.modules import email_validator, gravatar, pgp_lookup, github_search
93
+ res = {
94
+ "smtp": email_validator.check(email),
95
+ "gravatar": gravatar.check(email),
96
+ "pgp": pgp_lookup.check(email),
97
+ "github": github_search.check_email(email),
98
+ }
99
+ for k, v in res.items():
100
+ console.print(f"[bold]{k}:[/bold] {v}")
101
+ logger.close()
102
+
103
+
104
+ @main.command()
105
+ @click.argument("image_path")
106
+ def exif(image_path):
107
+ """Извлечь EXIF/GPS из фото"""
108
+ logger = _init_logger()
109
+ from milenium.modules import exif_extractor
110
+ res = exif_extractor.check(image_path)
111
+ for k, v in res.items():
112
+ console.print(f"[bold]{k}:[/bold] {v}")
113
+ logger.close()
114
+
115
+
116
+ @main.command()
117
+ @click.argument("domain")
118
+ def whois_rev(domain):
119
+ """Reverse WHOIS по домену"""
120
+ logger = _init_logger()
121
+ from milenium.modules import reverse_whois
122
+ res = reverse_whois.check(domain)
123
+ for d in res.get("domains", []):
124
+ console.print(d)
125
+ logger.close()
126
+
127
+
128
+ @main.command()
129
+ @click.option("--name", default=None)
130
+ @click.option("--surname", default=None)
131
+ @click.option("--year", default=None)
132
+ @click.option("--nick", default=None)
133
+ def pwgen(name, surname, year, nick):
134
+ """Генератор вероятных паролей по данным жертвы"""
135
+ logger = _init_logger()
136
+ from milenium.modules import password_pattern
137
+ res = password_pattern.generate(name=name, surname=surname, birth_year=year, nick=nick)
138
+ for p in res["passwords"][:50]:
139
+ console.print(p)
140
+ console.print(f"\n[bold]Всего:[/bold] {res['count']}")
141
+ logger.close()
142
+
143
+
144
+ @main.command()
145
+ @click.argument("image_path")
146
+ def exif_cmd(image_path):
147
+ """EXIF из фото"""
148
+ logger = _init_logger()
149
+ from milenium.modules import exif_extractor
150
+ res = exif_extractor.check(image_path)
151
+ for k, v in res.items():
152
+ console.print(f"[bold]{k}:[/bold] {v}")
153
+ logger.close()
87
154
 
88
155
  @main.command()
89
156
  @click.argument("mail")
@@ -0,0 +1,41 @@
1
+ from milenium.modules import (
2
+ pwned_passwords, breach_local, hibp, dehashed, leakcheck,
3
+ email_validator, gravatar, pgp_lookup, github_search,
4
+ wayback, reverse_whois, password_pattern,
5
+ ip_geo_advanced, tg_parser,
6
+ )
7
+
8
+ def run(email=None, username=None, phone=None, password=None, db_path=None, domain=None):
9
+ out = {}
10
+
11
+ if password:
12
+ out["pwned_passwords"] = pwned_passwords.check_password(password)
13
+
14
+ if email:
15
+ out["hibp"] = hibp.check_email(email)
16
+ out["dehashed_email"] = dehashed.search(f'email:"{email}"')
17
+ out["leakcheck_email"] = leakcheck.search(email)
18
+ out["gravatar"] = gravatar.check(email)
19
+ out["pgp"] = pgp_lookup.check(email)
20
+ out["github_email"] = github_search.check_email(email)
21
+ out["email_valid"] = email_validator.check(email)
22
+
23
+ if username:
24
+ out["dehashed_username"] = dehashed.search(f'username:"{username}"')
25
+ out["leakcheck_username"] = leakcheck.search(username)
26
+ out["github_user"] = github_search.check_username(username)
27
+ out["telegram"] = tg_parser.channel_info(username)
28
+
29
+ if phone:
30
+ out["leakcheck_phone"] = leakcheck.search(phone)
31
+
32
+ if domain:
33
+ out["wayback"] = wayback.check(f"http://{domain}")
34
+ out["reverse_whois"] = reverse_whois.check(domain)
35
+
36
+ if db_path:
37
+ q = email or username or phone
38
+ if q:
39
+ out["breach_local"] = breach_local.search(q, db_path)
40
+
41
+ return out
@@ -0,0 +1,22 @@
1
+ import smtplib
2
+ import dns.resolver
3
+
4
+ def check(email):
5
+ """Проверка существования email через SMTP RCPT TO (без отправки письма)."""
6
+ domain = email.split("@")[1]
7
+ try:
8
+ mx_records = dns.resolver.resolve(domain, "MX")
9
+ mx_host = str(sorted(mx_records, key=lambda r: r.preference)[0].exchange).rstrip(".")
10
+ except Exception as e:
11
+ return {"error": f"MX lookup failed: {e}"}
12
+
13
+ try:
14
+ server = smtplib.SMTP(timeout=10)
15
+ server.connect(mx_host, 25)
16
+ server.helo("milenium.local")
17
+ server.mail("check@milenium.local")
18
+ code, _ = server.rcpt(email)
19
+ server.quit()
20
+ return {"exists": code in (250, 251), "code": code, "mx": mx_host}
21
+ except Exception as e:
22
+ return {"error": str(e), "mx": mx_host}
@@ -0,0 +1,22 @@
1
+ import subprocess
2
+ import os
3
+
4
+ def check(image_path):
5
+ """Требует exiftool в PATH. Установка: apt install libimage-exiftool-perl / choco install exiftool."""
6
+ if not os.path.exists(image_path):
7
+ return {"error": "file not found"}
8
+ try:
9
+ r = subprocess.run(
10
+ ["exiftool", "-j", image_path],
11
+ capture_output=True, text=True, timeout=20
12
+ )
13
+ if r.returncode != 0:
14
+ return {"error": r.stderr.strip() or "exiftool failed"}
15
+ import json
16
+ data = json.loads(r.stdout)[0]
17
+ keys = ["GPSLatitude", "GPSLongitude", "Model", "Make", "DateTimeOriginal", "Software"]
18
+ return {k: data.get(k) for k in keys if data.get(k)}
19
+ except FileNotFoundError:
20
+ return {"error": "exiftool not installed"}
21
+ except Exception as e:
22
+ return {"error": str(e)}
@@ -0,0 +1,29 @@
1
+ import requests
2
+
3
+ def check_email(email):
4
+ try:
5
+ r = requests.get(
6
+ f"https://api.github.com/search/users?q={email}+in:email",
7
+ headers={"Accept": "application/vnd.github+json"},
8
+ timeout=10,
9
+ )
10
+ if r.status_code == 200:
11
+ items = r.json().get("items", [])
12
+ return {"users": [{"login": u["login"], "url": u["html_url"]} for u in items]}
13
+ return {"error": f"HTTP {r.status_code}"}
14
+ except Exception as e:
15
+ return {"error": str(e)}
16
+
17
+ def check_username(username):
18
+ try:
19
+ r = requests.get(
20
+ f"https://api.github.com/search/users?q={username}+in:login",
21
+ headers={"Accept": "application/vnd.github+json"},
22
+ timeout=10,
23
+ )
24
+ if r.status_code == 200:
25
+ items = r.json().get("items", [])
26
+ return {"users": [{"login": u["login"], "url": u["html_url"]} for u in items]}
27
+ return {"error": f"HTTP {r.status_code}"}
28
+ except Exception as e:
29
+ return {"error": str(e)}
@@ -0,0 +1,13 @@
1
+ import hashlib
2
+ import requests
3
+
4
+ def check(email):
5
+ h = hashlib.md5(email.strip().lower().encode()).hexdigest()
6
+ url = f"https://www.gravatar.com/avatar/{h}?d=404"
7
+ try:
8
+ r = requests.get(url, timeout=10)
9
+ if r.status_code == 200:
10
+ return {"exists": True, "url": f"https://www.gravatar.com/{h}"}
11
+ return {"exists": False}
12
+ except Exception as e:
13
+ return {"error": str(e)}
@@ -0,0 +1,25 @@
1
+ import requests
2
+ import re
3
+
4
+ def check(username):
5
+ """Парсит публичный профиль Instagram без API (может ломаться при защите)."""
6
+ headers = {"User-Agent": "Mozilla/5.0"}
7
+ try:
8
+ r = requests.get(f"https://www.instagram.com/{username}/", headers=headers, timeout=15)
9
+ if r.status_code != 200:
10
+ return {"error": f"HTTP {r.status_code}"}
11
+ m = re.search(r'"edge_followed_by":\{"count":(\d+)\}', r.text)
12
+ followers = m.group(1) if m else None
13
+ m2 = re.search(r'"edge_follow":\{"count":(\d+)\}', r.text)
14
+ following = m2.group(1) if m2 else None
15
+ m3 = re.search(r'"biography":"(.*?)"', r.text)
16
+ bio = m3.group(1) if m3 else None
17
+ return {
18
+ "exists": True,
19
+ "followers": followers,
20
+ "following": following,
21
+ "bio": bio,
22
+ "url": f"https://instagram.com/{username}",
23
+ }
24
+ except Exception as e:
25
+ return {"error": str(e)}
@@ -0,0 +1,16 @@
1
+ import requests
2
+
3
+ def check(ip):
4
+ out = {}
5
+ try:
6
+ r = requests.get(f"https://ipapi.co/{ip}/json/", timeout=10).json()
7
+ out["ipapi"] = {k: r.get(k) for k in ["city", "region", "country_name", "org", "asn", "timezone"]}
8
+ except Exception as e:
9
+ out["ipapi_error"] = str(e)
10
+
11
+ try:
12
+ r = requests.get(f"https://ipwho.is/{ip}", timeout=10).json()
13
+ out["ipwhois"] = {k: r.get(k) for k in ["city", "region", "country", "connection"]}
14
+ except Exception as e:
15
+ out["ipwhois_error"] = str(e)
16
+ return out
@@ -0,0 +1,32 @@
1
+ import itertools
2
+ from datetime import datetime
3
+
4
+ def generate(name=None, surname=None, birth_year=None, nick=None, limit=500):
5
+ """Генерит вероятные пароли по данным жертвы."""
6
+ base = []
7
+ if name: base.append(name.lower())
8
+ if surname: base.append(surname.lower())
9
+ if nick: base.append(nick.lower())
10
+ if name and surname:
11
+ base.append(f"{name.lower()}{surname.lower()}")
12
+ base.append(f"{name.lower()}.{surname.lower()}")
13
+ base.append(f"{name.lower()}_{surname.lower()}")
14
+
15
+ suffixes = ["", "123", "1234", "12345", "2024", "2025", "!", "@", "#", "_"]
16
+ if birth_year:
17
+ suffixes += [str(birth_year), str(birth_year)[-2:], f"{birth_year}!"]
18
+
19
+ out = set()
20
+ for b in base:
21
+ for s in suffixes:
22
+ out.add(b + s)
23
+ out.add(b.capitalize() + s)
24
+ out.add(b.upper() + s)
25
+
26
+ # leet
27
+ leet_map = {"a": "4", "e": "3", "i": "1", "o": "0", "s": "5"}
28
+ for b in list(out)[:100]:
29
+ leet = "".join(leet_map.get(c, c) for c in b)
30
+ out.add(leet)
31
+
32
+ return {"passwords": list(out)[:limit], "count": len(out)}
@@ -0,0 +1,10 @@
1
+ import requests
2
+
3
+ def check(email):
4
+ try:
5
+ r = requests.get(f"https://keys.openpgp.org/vks/v1/by-email/{email}", timeout=10)
6
+ if r.status_code == 200:
7
+ return {"found": True, "key": r.text[:500]}
8
+ return {"found": False}
9
+ except Exception as e:
10
+ return {"error": str(e)}
@@ -0,0 +1,24 @@
1
+ import requests
2
+ from bs4 import BeautifulSoup
3
+
4
+ def check(query):
5
+ """Парсит viewdns.info — бесплатно, без API-ключа."""
6
+ try:
7
+ r = requests.get(
8
+ "https://viewdns.info/reversewhois/",
9
+ params={"q": query},
10
+ headers={"User-Agent": "Mozilla/5.0"},
11
+ timeout=20,
12
+ )
13
+ soup = BeautifulSoup(r.text, "html.parser")
14
+ table = soup.find("table", {"border": "1"})
15
+ if not table:
16
+ return {"domains": []}
17
+ domains = []
18
+ for row in table.find_all("tr")[1:]:
19
+ cols = row.find_all("td")
20
+ if cols:
21
+ domains.append(cols[0].text.strip())
22
+ return {"domains": domains[:100]}
23
+ except Exception as e:
24
+ return {"error": str(e)}
@@ -0,0 +1,20 @@
1
+ import requests
2
+ from bs4 import BeautifulSoup
3
+
4
+ def channel_info(username):
5
+ try:
6
+ r = requests.get(f"https://t.me/{username}", timeout=10)
7
+ if r.status_code != 200:
8
+ return {"error": f"HTTP {r.status_code}"}
9
+ soup = BeautifulSoup(r.text, "html.parser")
10
+ title = soup.find("meta", property="og:title")
11
+ desc = soup.find("meta", property="og:description")
12
+ members = soup.find("div", class_="tgme_page_extra")
13
+ return {
14
+ "title": title["content"] if title else None,
15
+ "description": desc["content"] if desc else None,
16
+ "extra": members.text.strip() if members else None,
17
+ "url": f"https://t.me/{username}",
18
+ }
19
+ except Exception as e:
20
+ return {"error": str(e)}
@@ -0,0 +1,13 @@
1
+ import requests
2
+
3
+ def check(username):
4
+ """Через nitter-зеркало (может не работать, зеркала меняются)."""
5
+ mirrors = ["https://nitter.net", "https://nitter.privacydev.net"]
6
+ for base in mirrors:
7
+ try:
8
+ r = requests.get(f"{base}/{username}", timeout=10)
9
+ if r.status_code == 200 and "user-profile" in r.text:
10
+ return {"exists": True, "url": f"https://twitter.com/{username}", "mirror": base}
11
+ except Exception:
12
+ continue
13
+ return {"exists": False}
@@ -0,0 +1,23 @@
1
+ import requests
2
+
3
+ def check(user_id, token=""):
4
+ """VK API: нужен сервисный токен. Без него вернёт ошибку."""
5
+ if not token:
6
+ return {"error": "no VK token"}
7
+ try:
8
+ r = requests.get(
9
+ "https://api.vk.com/method/users.get",
10
+ params={
11
+ "user_ids": user_id,
12
+ "fields": "followers_count,country,city,photo_max,bdate",
13
+ "access_token": token,
14
+ "v": "5.199",
15
+ },
16
+ timeout=15,
17
+ )
18
+ data = r.json()
19
+ if "response" in data:
20
+ return data["response"][0]
21
+ return {"error": data.get("error", {}).get("error_msg")}
22
+ except Exception as e:
23
+ return {"error": str(e)}
@@ -0,0 +1,18 @@
1
+ import requests
2
+
3
+ def check(url):
4
+ try:
5
+ r = requests.get(
6
+ "http://archive.org/wayback/available",
7
+ params={"url": url},
8
+ timeout=15,
9
+ )
10
+ if r.status_code == 200:
11
+ data = r.json()
12
+ snap = data.get("archived_snapshots", {}).get("closest")
13
+ if snap:
14
+ return {"available": True, "snapshot": snap["url"], "timestamp": snap["timestamp"]}
15
+ return {"available": False}
16
+ return {"error": f"HTTP {r.status_code}"}
17
+ except Exception as e:
18
+ return {"error": str(e)}
@@ -0,0 +1,27 @@
1
+ import requests
2
+
3
+ def check(bssid):
4
+ """Wi-Fi геолокация через wigle.net (нужен API-токен)."""
5
+ try:
6
+ r = requests.get(
7
+ "https://api.wigle.net/api/v2/network/search",
8
+ params={"netid": bssid},
9
+ headers={"Authorization": "Basic YOUR_BASE64_TOKEN"},
10
+ timeout=15,
11
+ )
12
+ if r.status_code == 200:
13
+ data = r.json()
14
+ results = data.get("results", [])
15
+ if results:
16
+ first = results[0]
17
+ return {
18
+ "lat": first.get("trilat"),
19
+ "lon": first.get("trilong"),
20
+ "ssid": first.get("ssid"),
21
+ "country": first.get("country"),
22
+ "city": first.get("city"),
23
+ }
24
+ return {"found": False}
25
+ return {"error": f"HTTP {r.status_code}"}
26
+ except Exception as e:
27
+ return {"error": str(e)}
@@ -53,6 +53,39 @@ SESSION = {
53
53
  "db_loaded": False,
54
54
  }
55
55
 
56
+ OUTPUT_LOG = [] # буфер вывода последних строк
57
+
58
+ def push_output(text):
59
+ ts = datetime.now().strftime("%H:%M:%S")
60
+ OUTPUT_LOG.append(f"[red]{ts}[/red] [white]{text}[/white]")
61
+ if len(OUTPUT_LOG) > 20:
62
+ OUTPUT_LOG.pop(0)
63
+
64
+
65
+ def clear_output():
66
+ OUTPUT_LOG.clear()
67
+
68
+ def render_output():
69
+ lines = []
70
+ lines.append("[bold red]=== ВЫВОД КОМАНДЫ ===[/bold red]")
71
+ if OUTPUT_LOG:
72
+ lines.extend(OUTPUT_LOG[-10:])
73
+ else:
74
+ lines.append("[white]Пока ничего. Введи команду ниже.[/white]")
75
+ return Panel(
76
+ "\n".join(lines),
77
+ title="[bold red]ПРОЦЕСС[/bold red]",
78
+ border_style="red",
79
+ )
80
+
81
+
82
+ def render_input():
83
+ return Panel(
84
+ "[bold red]milenium[/bold red] [white]@[/white] [red]VexxDev200[/red] [white]~[/white] [bold white]введи команду ниже[/bold white]",
85
+ title="[bold red]ВВОД[/bold red]",
86
+ border_style="red",
87
+ )
88
+
56
89
 
57
90
  def log_result(text):
58
91
  ts = datetime.now().strftime("%H:%M:%S")
@@ -65,7 +98,9 @@ def build_layout():
65
98
  layout = Layout()
66
99
  layout.split_column(
67
100
  Layout(name="header", size=10),
68
- Layout(name="body"),
101
+ Layout(name="body", ratio=2),
102
+ Layout(name="output", size=12),
103
+ Layout(name="input", size=3),
69
104
  Layout(name="footer", size=3),
70
105
  )
71
106
  layout["body"].split_row(
@@ -76,6 +111,14 @@ def build_layout():
76
111
  return layout
77
112
 
78
113
 
114
+ def render_input():
115
+ return Panel(
116
+ "[bold red]milenium[/bold red] [white]@[/white] [red]VexxDev200[/red] [white]~[/white] [bold white]введи команду ниже[/bold white]",
117
+ title="[bold red]ВВОД[/bold red]",
118
+ border_style="red",
119
+ )
120
+
121
+
79
122
  def render_header():
80
123
  logo = Text.from_markup(ASCII_LOGO)
81
124
  banner = Text.from_markup(BANNER)
@@ -160,30 +203,48 @@ def draw():
160
203
  layout["left"].update(render_left())
161
204
  layout["center"].update(render_center())
162
205
  layout["right"].update(render_right())
206
+ layout["output"].update(render_output())
207
+ layout["input"].update(render_input())
163
208
  layout["footer"].update(render_footer())
164
209
  return layout
165
210
 
166
211
 
167
212
  def interactive():
168
213
  console.clear()
169
- with Live(draw(), refresh_per_second=4, screen=True) as live:
214
+ push_output("сессия запущена")
215
+ with Live(draw(), refresh_per_second=4) as live:
170
216
  while True:
171
217
  try:
218
+ live.stop()
172
219
  cmd = Prompt.ask("[bold red]milenium[/bold red] [white]@[/white] [red]VexxDev200[/red] [white]~[/white]")
220
+ live.start()
221
+
173
222
  if cmd.strip().lower() in ("exit", "quit", "q"):
174
223
  break
175
224
  if not cmd.strip():
225
+ live.update(draw())
176
226
  continue
227
+
177
228
  SESSION["queries"] += 1
229
+ push_output(f"выполняю: {cmd}")
230
+
178
231
  import shlex
232
+ import io
233
+ import contextlib
179
234
  from milenium.cli import main
235
+
180
236
  args = shlex.split(cmd)
237
+ buf = io.StringIO()
181
238
  try:
182
- main(args, standalone_mode=False)
239
+ with contextlib.redirect_stdout(buf):
240
+ main(args, standalone_mode=False)
241
+ for line in buf.getvalue().splitlines():
242
+ if line.strip():
243
+ push_output(line)
183
244
  except SystemExit:
184
245
  pass
185
246
  except Exception as e:
186
- console.print(f"[bold red]Ошибка:[/bold red] {e}")
247
+ push_output(f"[red]ошибка: {e}[/red]")
187
248
  live.update(draw())
188
249
  except KeyboardInterrupt:
189
250
  break
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: milenium
3
- Version: 0.4.2
3
+ Version: 0.5.1
4
4
  Summary: OSINT / dox / deanon toolkit
5
5
  Requires-Python: >=3.9
6
6
  Description-Content-Type: text/markdown
@@ -13,3 +13,4 @@ Requires-Dist: click
13
13
  Requires-Dist: python-whois
14
14
 
15
15
  # milenium
16
+ # exiftool
@@ -18,16 +18,30 @@ milenium/modules/dns_history.py
18
18
  milenium/modules/domain.py
19
19
  milenium/modules/dorker.py
20
20
  milenium/modules/email.py
21
+ milenium/modules/email_validator.py
22
+ milenium/modules/exif_extractor.py
23
+ milenium/modules/github_search.py
24
+ milenium/modules/gravatar.py
21
25
  milenium/modules/hibp.py
26
+ milenium/modules/instagram_osint.py
22
27
  milenium/modules/ip.py
28
+ milenium/modules/ip_geo_advanced.py
23
29
  milenium/modules/ip_reputation.py
24
30
  milenium/modules/leakcheck.py
25
31
  milenium/modules/logger.py
32
+ milenium/modules/password_pattern.py
26
33
  milenium/modules/permutator.py
34
+ milenium/modules/pgp_lookup.py
27
35
  milenium/modules/phone.py
28
36
  milenium/modules/pwned_passwords.py
29
37
  milenium/modules/report.py
38
+ milenium/modules/reverse_whois.py
30
39
  milenium/modules/shodan_lite.py
31
40
  milenium/modules/social.py
32
41
  milenium/modules/telegram_osint.py
33
- milenium/modules/username.py
42
+ milenium/modules/tg_parser.py
43
+ milenium/modules/twitter_osint.py
44
+ milenium/modules/username.py
45
+ milenium/modules/vk_osint.py
46
+ milenium/modules/wayback.py
47
+ milenium/modules/wifi_geolocation.py
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "milenium"
3
- version = "0.4.2"
3
+ version = "0.5.1"
4
4
  description = "OSINT / dox / deanon toolkit"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.9"
milenium-0.4.2/README.md DELETED
@@ -1 +0,0 @@
1
- # milenium
@@ -1,26 +0,0 @@
1
- from milenium.modules import pwned_passwords, breach_local, hibp, dehashed, leakcheck
2
-
3
- def run(email=None, username=None, phone=None, password=None, db_path=None):
4
- out = {}
5
-
6
- if password:
7
- out["pwned_passwords"] = pwned_passwords.check_password(password)
8
-
9
- if email:
10
- out["hibp"] = hibp.check_email(email)
11
- out["dehashed_email"] = dehashed.search(f'email:"{email}"')
12
- out["leakcheck_email"] = leakcheck.search(email)
13
-
14
- if username:
15
- out["dehashed_username"] = dehashed.search(f'username:"{username}"')
16
- out["leakcheck_username"] = leakcheck.search(username)
17
-
18
- if phone:
19
- out["leakcheck_phone"] = leakcheck.search(phone)
20
-
21
- if db_path:
22
- q = email or username or phone
23
- if q:
24
- out["breach_local"] = breach_local.search(q, db_path)
25
-
26
- return out
File without changes
File without changes