milenium 0.5.2__tar.gz → 0.5.4__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 (52) hide show
  1. {milenium-0.5.2 → milenium-0.5.4}/PKG-INFO +3 -2
  2. milenium-0.5.4/milenium/cli.py +227 -0
  3. milenium-0.5.4/milenium/modules/neon_db.py +78 -0
  4. milenium-0.5.4/milenium/tui.py +245 -0
  5. {milenium-0.5.2 → milenium-0.5.4}/milenium.egg-info/PKG-INFO +3 -2
  6. {milenium-0.5.2 → milenium-0.5.4}/milenium.egg-info/SOURCES.txt +1 -0
  7. {milenium-0.5.2 → milenium-0.5.4}/milenium.egg-info/requires.txt +1 -0
  8. {milenium-0.5.2 → milenium-0.5.4}/pyproject.toml +7 -2
  9. milenium-0.5.2/milenium/cli.py +0 -309
  10. milenium-0.5.2/milenium/tui.py +0 -235
  11. {milenium-0.5.2 → milenium-0.5.4}/README.md +0 -0
  12. {milenium-0.5.2 → milenium-0.5.4}/milenium/__init__.py +0 -0
  13. {milenium-0.5.2 → milenium-0.5.4}/milenium/modules/__init__.py +0 -0
  14. {milenium-0.5.2 → milenium-0.5.4}/milenium/modules/aggregator.py +0 -0
  15. {milenium-0.5.2 → milenium-0.5.4}/milenium/modules/breach.py +0 -0
  16. {milenium-0.5.2 → milenium-0.5.4}/milenium/modules/breach_local.py +0 -0
  17. {milenium-0.5.2 → milenium-0.5.4}/milenium/modules/dehashed.py +0 -0
  18. {milenium-0.5.2 → milenium-0.5.4}/milenium/modules/dns_history.py +0 -0
  19. {milenium-0.5.2 → milenium-0.5.4}/milenium/modules/domain.py +0 -0
  20. {milenium-0.5.2 → milenium-0.5.4}/milenium/modules/dorker.py +0 -0
  21. {milenium-0.5.2 → milenium-0.5.4}/milenium/modules/email.py +0 -0
  22. {milenium-0.5.2 → milenium-0.5.4}/milenium/modules/email_validator.py +0 -0
  23. {milenium-0.5.2 → milenium-0.5.4}/milenium/modules/exif_extractor.py +0 -0
  24. {milenium-0.5.2 → milenium-0.5.4}/milenium/modules/github_search.py +0 -0
  25. {milenium-0.5.2 → milenium-0.5.4}/milenium/modules/gravatar.py +0 -0
  26. {milenium-0.5.2 → milenium-0.5.4}/milenium/modules/hibp.py +0 -0
  27. {milenium-0.5.2 → milenium-0.5.4}/milenium/modules/instagram_osint.py +0 -0
  28. {milenium-0.5.2 → milenium-0.5.4}/milenium/modules/ip.py +0 -0
  29. {milenium-0.5.2 → milenium-0.5.4}/milenium/modules/ip_geo_advanced.py +0 -0
  30. {milenium-0.5.2 → milenium-0.5.4}/milenium/modules/ip_reputation.py +0 -0
  31. {milenium-0.5.2 → milenium-0.5.4}/milenium/modules/leakcheck.py +0 -0
  32. {milenium-0.5.2 → milenium-0.5.4}/milenium/modules/logger.py +0 -0
  33. {milenium-0.5.2 → milenium-0.5.4}/milenium/modules/password_pattern.py +0 -0
  34. {milenium-0.5.2 → milenium-0.5.4}/milenium/modules/permutator.py +0 -0
  35. {milenium-0.5.2 → milenium-0.5.4}/milenium/modules/pgp_lookup.py +0 -0
  36. {milenium-0.5.2 → milenium-0.5.4}/milenium/modules/phone.py +0 -0
  37. {milenium-0.5.2 → milenium-0.5.4}/milenium/modules/pwned_passwords.py +0 -0
  38. {milenium-0.5.2 → milenium-0.5.4}/milenium/modules/report.py +0 -0
  39. {milenium-0.5.2 → milenium-0.5.4}/milenium/modules/reverse_whois.py +0 -0
  40. {milenium-0.5.2 → milenium-0.5.4}/milenium/modules/shodan_lite.py +0 -0
  41. {milenium-0.5.2 → milenium-0.5.4}/milenium/modules/social.py +0 -0
  42. {milenium-0.5.2 → milenium-0.5.4}/milenium/modules/telegram_osint.py +0 -0
  43. {milenium-0.5.2 → milenium-0.5.4}/milenium/modules/tg_parser.py +0 -0
  44. {milenium-0.5.2 → milenium-0.5.4}/milenium/modules/twitter_osint.py +0 -0
  45. {milenium-0.5.2 → milenium-0.5.4}/milenium/modules/username.py +0 -0
  46. {milenium-0.5.2 → milenium-0.5.4}/milenium/modules/vk_osint.py +0 -0
  47. {milenium-0.5.2 → milenium-0.5.4}/milenium/modules/wayback.py +0 -0
  48. {milenium-0.5.2 → milenium-0.5.4}/milenium/modules/wifi_geolocation.py +0 -0
  49. {milenium-0.5.2 → milenium-0.5.4}/milenium.egg-info/dependency_links.txt +0 -0
  50. {milenium-0.5.2 → milenium-0.5.4}/milenium.egg-info/entry_points.txt +0 -0
  51. {milenium-0.5.2 → milenium-0.5.4}/milenium.egg-info/top_level.txt +0 -0
  52. {milenium-0.5.2 → milenium-0.5.4}/setup.cfg +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: milenium
3
- Version: 0.5.2
4
- Summary: OSINT / dox / deanon toolkit
3
+ Version: 0.5.4
4
+ Summary: OSINT toolkit
5
5
  Requires-Python: >=3.9
6
6
  Description-Content-Type: text/markdown
7
7
  Requires-Dist: requests
@@ -11,6 +11,7 @@ Requires-Dist: beautifulsoup4
11
11
  Requires-Dist: rich
12
12
  Requires-Dist: click
13
13
  Requires-Dist: python-whois
14
+ Requires-Dist: psycopg2-binary
14
15
 
15
16
  # milenium
16
17
  # exiftool
@@ -0,0 +1,227 @@
1
+ import sys
2
+ import json
3
+ import click
4
+ from rich.console import Console
5
+ from rich.table import Table
6
+ from milenium.modules.logger import TeeLogger
7
+ from milenium.modules import (
8
+ username, email, phone, ip, domain, breach, social, report,
9
+ dorker, pwned_passwords, breach_local, hibp, dehashed, leakcheck,
10
+ aggregator, shodan_lite, ip_reputation, dns_history, telegram_osint,
11
+ neon_db,
12
+ )
13
+
14
+ console = Console()
15
+
16
+
17
+ def _init_logger():
18
+ logger = TeeLogger("milenium.log", mode="a")
19
+ sys.stdout = logger
20
+ return logger
21
+
22
+
23
+ def _save_neon(command, target, module, data):
24
+ try:
25
+ neon_db.init()
26
+ neon_db.save(command, target, module, data)
27
+ except Exception:
28
+ pass
29
+
30
+
31
+ @click.group()
32
+ def main():
33
+ """milenium — OSINT toolkit"""
34
+ pass
35
+
36
+
37
+ @main.command()
38
+ @click.argument("nick")
39
+ @click.option("--permutations", default=30)
40
+ @click.option("--dorks/--no-dorks", default=True)
41
+ def user(nick, permutations, dorks):
42
+ """Глубокий поиск по нику"""
43
+ logger = _init_logger()
44
+ results = username.check(nick, permutations=permutations)
45
+ _save_neon("user", nick, "username", results)
46
+
47
+ table = Table(title=f"Username: {nick}")
48
+ table.add_column("Вариация")
49
+ table.add_column("Сайт")
50
+ table.add_column("Статус")
51
+ table.add_column("URL")
52
+ found = 0
53
+ for variant, sites in results.items():
54
+ for site, info in sites.items():
55
+ if info["found"]:
56
+ table.add_row(variant, site, "[green]FOUND[/green]", info["url"])
57
+ found += 1
58
+ console.print(table)
59
+ console.print(f"[bold green]Найдено: {found}[/bold green]")
60
+
61
+ if dorks:
62
+ d = dorker.search_nick(nick, num=10)
63
+ for q, links in d.items():
64
+ console.print(f"\n[bold]{q}[/bold]")
65
+ for link in links:
66
+ console.print(f" {link}")
67
+
68
+ logger.close()
69
+
70
+
71
+ @main.command()
72
+ @click.argument("mail")
73
+ def mail(mail):
74
+ """Проверка email"""
75
+ logger = _init_logger()
76
+ results = email.check(mail)
77
+ _save_neon("mail", mail, "email", results)
78
+ for k, v in results.items():
79
+ console.print(f"[bold]{k}:[/bold] {v}")
80
+ logger.close()
81
+
82
+
83
+ @main.command()
84
+ @click.argument("number")
85
+ def phone_cmd(number):
86
+ """Инфа по номеру"""
87
+ logger = _init_logger()
88
+ results = phone.check(number)
89
+ _save_neon("phone", number, "phone", results)
90
+ for k, v in results.items():
91
+ console.print(f"[bold]{k}:[/bold] {v}")
92
+ logger.close()
93
+
94
+
95
+ @main.command()
96
+ @click.argument("address")
97
+ def ip_cmd(address):
98
+ """Гео, ASN, Shodan, репутация"""
99
+ logger = _init_logger()
100
+ results = ip.check(address)
101
+ results["shodan"] = shodan_lite.check_ip(address)
102
+ results["reputation"] = ip_reputation.check(address)
103
+ _save_neon("ip", address, "ip", results)
104
+ for k, v in results.items():
105
+ console.print(f"[bold]{k}:[/bold] {v}")
106
+ logger.close()
107
+
108
+
109
+ @main.command()
110
+ @click.argument("host")
111
+ def dom(host):
112
+ """WHOIS, DNS, crt.sh"""
113
+ logger = _init_logger()
114
+ results = domain.check(host)
115
+ results["crt"] = dns_history.check(host)
116
+ _save_neon("dom", host, "domain", results)
117
+ for k, v in results.items():
118
+ console.print(f"[bold]{k}:[/bold] {v}")
119
+ logger.close()
120
+
121
+
122
+ @main.command()
123
+ @click.argument("query")
124
+ def leaks(query):
125
+ """HIBP утечки"""
126
+ logger = _init_logger()
127
+ results = breach.check(query)
128
+ _save_neon("leaks", query, "breach", results)
129
+ for k, v in results.items():
130
+ console.print(f"[bold]{k}:[/bold] {v}")
131
+ logger.close()
132
+
133
+
134
+ @main.command()
135
+ @click.argument("nick")
136
+ def social_cmd(nick):
137
+ """Поиск соцсетей"""
138
+ logger = _init_logger()
139
+ results = social.check(nick)
140
+ _save_neon("social", nick, "social", results)
141
+ for site, info in results.items():
142
+ status = "FOUND" if info["found"] else "NO"
143
+ console.print(f"[bold]{site}:[/bold] {status} — {info['url']}")
144
+ logger.close()
145
+
146
+
147
+ @main.command()
148
+ @click.argument("password")
149
+ def pwned(password):
150
+ """Проверка пароля"""
151
+ logger = _init_logger()
152
+ res = pwned_passwords.check_password(password)
153
+ if res.get("pwned"):
154
+ console.print(f"[red]ПАРОЛЬ В УТЕЧКАХ[/red] — {res['count']} раз")
155
+ elif "error" in res:
156
+ console.print(f"[yellow]Ошибка:[/yellow] {res['error']}")
157
+ else:
158
+ console.print("[green]Не найден[/green]")
159
+ logger.close()
160
+
161
+
162
+ @main.command()
163
+ @click.argument("channel")
164
+ def telegram(channel):
165
+ """Парсинг TG-канала"""
166
+ logger = _init_logger()
167
+ res = telegram_osint.check_channel(channel)
168
+ for k, v in res.items():
169
+ console.print(f"[bold]{k}:[/bold] {v}")
170
+ logger.close()
171
+
172
+
173
+ @main.command()
174
+ @click.option("--email", default=None)
175
+ @click.option("--username", default=None)
176
+ @click.option("--phone", default=None)
177
+ @click.option("--password", default=None)
178
+ @click.option("--db-path", default=None)
179
+ def full(email, username, phone, password, db_path):
180
+ """Агрегатор"""
181
+ logger = _init_logger()
182
+ res = aggregator.run(email=email, username=username, phone=phone,
183
+ password=password, db_path=db_path)
184
+ _save_neon("full", email or username or phone, "aggregator", res)
185
+ console.print(json.dumps(res, indent=2, ensure_ascii=False))
186
+ logger.close()
187
+
188
+
189
+ @main.command()
190
+ @click.option("--target", default=None)
191
+ @click.option("--module", default=None)
192
+ @click.option("--limit", default=50)
193
+ @click.option("--stats", is_flag=True)
194
+ def db_neon(target, module, limit, stats):
195
+ """NeonDB работа"""
196
+ logger = _init_logger()
197
+ try:
198
+ neon_db.init()
199
+ if stats:
200
+ s = neon_db.stats()
201
+ console.print(f"[bold]Всего:[/bold] {s['total']}")
202
+ for m, c in s["by_module"].items():
203
+ console.print(f" [red]{m}[/red]: {c}")
204
+ else:
205
+ rows = neon_db.query(target=target, module=module, limit=limit)
206
+ table = Table(title="NeonDB")
207
+ table.add_column("Время")
208
+ table.add_column("Команда")
209
+ table.add_column("Цель")
210
+ table.add_column("Модуль")
211
+ for r in rows:
212
+ table.add_row(r["ts"][:19], r["command"], r["target"], r["module"])
213
+ console.print(table)
214
+ except Exception as e:
215
+ console.print(f"[bold red]Ошибка Neon:[/bold red] {e}")
216
+ logger.close()
217
+
218
+
219
+ @main.command()
220
+ def tui():
221
+ """TUI-интерфейс"""
222
+ from milenium.tui import interactive
223
+ interactive()
224
+
225
+
226
+ if __name__ == "__main__":
227
+ main()
@@ -0,0 +1,78 @@
1
+ import os
2
+ import json
3
+ import psycopg2
4
+ import psycopg2.extras
5
+
6
+ DATABASE_URL = os.environ.get("DATABASE_URL", "postgresql://neondb_owner:npg_JNAjnTaz0UK5@ep-twilight-bar-b1ofdyot-pooler.c-5.eu-central-1.aws.neon.tech/neondb?sslmode=require&channel_binding=require")
7
+
8
+
9
+ def _conn():
10
+ if not DATABASE_URL:
11
+ raise RuntimeError("DATABASE_URL not set")
12
+ return psycopg2.connect(DATABASE_URL, sslmode="require")
13
+
14
+
15
+ def init():
16
+ with _conn() as conn:
17
+ with conn.cursor() as cur:
18
+ cur.execute("""
19
+ CREATE TABLE IF NOT EXISTS results (
20
+ id SERIAL PRIMARY KEY,
21
+ ts TIMESTAMP DEFAULT NOW(),
22
+ command TEXT,
23
+ target TEXT,
24
+ module TEXT,
25
+ data JSONB
26
+ )
27
+ """)
28
+ cur.execute("""
29
+ CREATE TABLE IF NOT EXISTS sessions (
30
+ id SERIAL PRIMARY KEY,
31
+ ts TIMESTAMP DEFAULT NOW(),
32
+ queries INTEGER,
33
+ results INTEGER
34
+ )
35
+ """)
36
+ conn.commit()
37
+
38
+
39
+ def save(command, target, module, data):
40
+ with _conn() as conn:
41
+ with conn.cursor() as cur:
42
+ cur.execute(
43
+ "INSERT INTO results (command, target, module, data) VALUES (%s, %s, %s, %s)",
44
+ (command, target, module, json.dumps(data, ensure_ascii=False)),
45
+ )
46
+ conn.commit()
47
+
48
+
49
+ def query(target=None, module=None, limit=50):
50
+ sql = "SELECT ts, command, target, module, data FROM results WHERE 1=1"
51
+ params = []
52
+ if target:
53
+ sql += " AND target LIKE %s"
54
+ params.append(f"%{target}%")
55
+ if module:
56
+ sql += " AND module = %s"
57
+ params.append(module)
58
+ sql += " ORDER BY id DESC LIMIT %s"
59
+ params.append(limit)
60
+ with _conn() as conn:
61
+ with conn.cursor(cursor_factory=psycopg2.extras.DictCursor) as cur:
62
+ cur.execute(sql, params)
63
+ rows = cur.fetchall()
64
+ return [
65
+ {"ts": str(r["ts"]), "command": r["command"], "target": r["target"],
66
+ "module": r["module"], "data": r["data"]}
67
+ for r in rows
68
+ ]
69
+
70
+
71
+ def stats():
72
+ with _conn() as conn:
73
+ with conn.cursor() as cur:
74
+ cur.execute("SELECT COUNT(*) FROM results")
75
+ total = cur.fetchone()[0]
76
+ cur.execute("SELECT module, COUNT(*) FROM results GROUP BY module")
77
+ by_module = dict(cur.fetchall())
78
+ return {"total": total, "by_module": by_module}
@@ -0,0 +1,245 @@
1
+ import sys
2
+ import shlex
3
+ import io
4
+ import contextlib
5
+ from datetime import datetime
6
+ from rich.console import Console
7
+ from rich.layout import Layout
8
+ from rich.panel import Panel
9
+ from rich.text import Text
10
+ from rich.table import Table
11
+ from rich.align import Align
12
+ from rich.live import Live
13
+ from rich.prompt import Prompt
14
+
15
+ console = Console()
16
+
17
+ LOGO = r"""
18
+ ███╗ ███╗██╗██╗ ███████╗███╗ ██╗██╗██╗ ██╗███╗ ███╗
19
+ ████╗ ████║██║██║ ██╔════╝████╗ ██║██║██║ ██║████╗ ████║
20
+ ██╔████╔██║██║██║ █████╗ ██╔██╗ ██║██║██║ ██║██╔████╔██║
21
+ ██║╚██╔╝██║██║██║ ██╔══╝ ██║╚██╗██║██║██║ ██║██║╚██╔╝██║
22
+ ██║ ╚═╝ ██║██║███████╗███████╗██║ ╚████║██║╚██████╔╝██║ ╚═╝ ██║
23
+ ╚═╝ ╚═╝╚═╝╚══════╝╚══════╝╚═╝ ╚═══╝╚═╝ ╚═════╝ ╚═╝ ╚═╝
24
+ """
25
+
26
+ COMMANDS = {
27
+ "ПОИСК": [
28
+ ("user <ник>", "Ник + вариации + Dorks"),
29
+ ("social_cmd <ник>", "Соцсети по нику"),
30
+ ("email_check <email>", "SMTP + Gravatar + PGP"),
31
+ ("mail <email>", "MX, HIBP, Gravatar"),
32
+ ("phone_cmd <номер>", "Оператор, страна"),
33
+ ("telegram <канал>", "TG-канал"),
34
+ ],
35
+ "УТЕЧКИ": [
36
+ ("pwned <пароль>", "Проверка пароля"),
37
+ ("leaks <email>", "HIBP утечки"),
38
+ ("pwgen --name N", "Генератор паролей"),
39
+ ("full --email E", "Агрегатор"),
40
+ ],
41
+ "СЕТЬ": [
42
+ ("ip_cmd <IP>", "Гео, Shodan, репутация"),
43
+ ("dom <домен>", "WHOIS, DNS, crt.sh"),
44
+ ("whois_rev <домен>", "Reverse WHOIS"),
45
+ ("ssl_info <host>", "SSL-сертификат"),
46
+ ("robots <домен>", "robots.txt"),
47
+ ],
48
+ "ФАЙЛЫ": [
49
+ ("exif <path>", "EXIF из фото"),
50
+ ("eml <path>", "Заголовки письма"),
51
+ ("wayback <url>", "Wayback Machine"),
52
+ ],
53
+ "NEON DB": [
54
+ ("db_neon --stats", "Статистика"),
55
+ ("db_neon --target X", "Поиск"),
56
+ ],
57
+ "СИСТЕМА": [
58
+ ("help", "Список команд"),
59
+ ("clear", "Очистить вывод"),
60
+ ("exit / q", "Выход"),
61
+ ],
62
+ }
63
+
64
+ SESSION = {"start": datetime.now(), "queries": 0, "results": 0, "last": []}
65
+ OUTPUT_LOG = []
66
+
67
+
68
+ def push_output(text):
69
+ ts = datetime.now().strftime("%H:%M:%S")
70
+ OUTPUT_LOG.append(f"[red]{ts}[/red] [white]{text}[/white]")
71
+ if len(OUTPUT_LOG) > 50:
72
+ OUTPUT_LOG.pop(0)
73
+
74
+
75
+ def build_layout():
76
+ layout = Layout()
77
+ layout.split_column(
78
+ Layout(name="header", size=9),
79
+ Layout(name="body", ratio=2),
80
+ Layout(name="output", size=12),
81
+ Layout(name="input", size=3),
82
+ Layout(name="footer", size=3),
83
+ )
84
+ layout["body"].split_row(
85
+ Layout(name="left", ratio=3),
86
+ Layout(name="center", ratio=2),
87
+ Layout(name="right", ratio=1),
88
+ )
89
+ return layout
90
+
91
+
92
+ def render_header():
93
+ logo_text = Text(LOGO, style="bold red")
94
+ banner = Text.from_markup(
95
+ "[bold white]MILENIUM[/bold white] [red]|[/red] [bold white]@VexxDev200[/bold white] "
96
+ "[red]|[/red] [bold white]TG:[/bold white] [red]@milenium[/red] "
97
+ "[red]|[/red] [bold white]STATUS:[/bold white] [green]● ONLINE[/green]"
98
+ )
99
+ return Panel(Align.center(logo_text + banner), border_style="red",
100
+ title="[bold red]MILENIUM[/bold red]", subtitle="[red]v0.6.1[/red]")
101
+
102
+
103
+ def render_commands():
104
+ from rich.columns import Columns
105
+ left_lines, right_lines = [], []
106
+ items = []
107
+ for cat, cmds in COMMANDS.items():
108
+ items.append(("cat", cat))
109
+ for cmd, desc in cmds:
110
+ items.append(("cmd", (cmd, desc)))
111
+ half = len(items) // 2
112
+ for i, (kind, val) in enumerate(items):
113
+ target = left_lines if i < half else right_lines
114
+ if kind == "cat":
115
+ target.append(Text(f"━━ {val} ━━", style="bold red"))
116
+ else:
117
+ cmd, desc = val
118
+ t = Text()
119
+ t.append(cmd, style="bold white")
120
+ t.append(" — ", style="red")
121
+ t.append(desc, style="red")
122
+ target.append(t)
123
+ left = Text("\n").join(left_lines)
124
+ right = Text("\n").join(right_lines)
125
+ cols = Columns([left, right], expand=True, equal=True)
126
+ return Panel(cols, title="[bold red]КОМАНДЫ[/bold red]", border_style="red")
127
+
128
+
129
+ def render_session():
130
+ lines = []
131
+ uptime = datetime.now() - SESSION["start"]
132
+ mins, secs = divmod(int(uptime.total_seconds()), 60)
133
+ lines.append(f"[white]Uptime:[/white] [red]{mins:02d}:{secs:02d}[/red]")
134
+ lines.append(f"[white]Запросов:[/white] [red]{SESSION['queries']}[/red]")
135
+ lines.append(f"[white]Найдено:[/white] [red]{SESSION['results']}[/red]")
136
+ lines.append("")
137
+ lines.append("[bold red]━━ ПОСЛЕДНИЕ ━━[/bold red]")
138
+ if SESSION["last"]:
139
+ lines.extend(SESSION["last"])
140
+ else:
141
+ lines.append("[white]Пока ничего.[/white]")
142
+ return Panel("\n".join(lines), title="[bold red]СЕССИЯ[/bold red]", border_style="red")
143
+
144
+
145
+ def render_status():
146
+ from milenium.modules import neon_db
147
+ lines = []
148
+ lines.append("[bold red]━━ NEON DB ━━[/bold red]")
149
+ try:
150
+ s = neon_db.stats()
151
+ lines.append(f"[white]Записей:[/white] [red]{s['total']}[/red]")
152
+ for m, c in list(s["by_module"].items())[:3]:
153
+ lines.append(f"[white]{m}[/white] [red]{c}[/red]")
154
+ except Exception:
155
+ lines.append("[red]NOT CONNECTED[/red]")
156
+ lines.append("")
157
+ lines.append("[bold red]━━ МОДУЛИ ━━[/bold red]")
158
+ for m in ["whois", "dns", "requests", "rich", "click"]:
159
+ lines.append(f"[white]{m}[/white] [green]OK[/green]")
160
+ return Panel("\n".join(lines), title="[bold red]СТАТУС[/bold red]", border_style="red")
161
+
162
+
163
+ def render_output():
164
+ lines = ["[bold red]━━ ПРОЦЕСС ━━[/bold red]"]
165
+ if OUTPUT_LOG:
166
+ lines.extend(OUTPUT_LOG[-10:])
167
+ else:
168
+ lines.append("[white]Введи команду ниже.[/white]")
169
+ return Panel("\n".join(lines), title="[bold red]ВЫВОД[/bold red]", border_style="red")
170
+
171
+
172
+ def render_input():
173
+ return Panel(
174
+ "[bold red]milenium[/bold red] [white]@[/white] [red]VexxDev200[/red] [white]~[/white] [bold white]введи команду[/bold white]",
175
+ title="[bold red]ВВОД[/bold red]", border_style="red")
176
+
177
+
178
+ def render_footer():
179
+ return Panel(Align.center(
180
+ "[bold red]milenium[/bold red] [white]@[/white] [red]VexxDev200[/red] "
181
+ "[white]|[/white] [green]SYSTEM READY[/green] "
182
+ "[white]|[/white] [red]Ctrl+C для выхода[/red]"), border_style="red")
183
+
184
+
185
+ def draw():
186
+ layout = build_layout()
187
+ layout["header"].update(render_header())
188
+ layout["left"].update(render_commands())
189
+ layout["center"].update(render_session())
190
+ layout["right"].update(render_status())
191
+ layout["output"].update(render_output())
192
+ layout["input"].update(render_input())
193
+ layout["footer"].update(render_footer())
194
+ return layout
195
+
196
+
197
+ def _handle_builtin(cmd):
198
+ c = cmd.strip().lower()
199
+ if c == "help":
200
+ push_output("список команд в левой панели")
201
+ return True
202
+ if c == "clear":
203
+ OUTPUT_LOG.clear()
204
+ push_output("вывод очищен")
205
+ return True
206
+ return False
207
+
208
+
209
+ def interactive():
210
+ console.clear()
211
+ push_output("сессия запущена")
212
+ push_output("введи 'help'")
213
+ with Live(draw(), refresh_per_second=4) as live:
214
+ while True:
215
+ try:
216
+ live.stop()
217
+ cmd = Prompt.ask("[bold red]milenium[/bold red] [white]@[/white] [red]VexxDev200[/red] [white]~[/white]")
218
+ live.start()
219
+ if cmd.strip().lower() in ("exit", "quit", "q"):
220
+ break
221
+ if not cmd.strip():
222
+ live.update(draw())
223
+ continue
224
+ SESSION["queries"] += 1
225
+ push_output(f"выполняю: {cmd}")
226
+ if _handle_builtin(cmd):
227
+ live.update(draw())
228
+ continue
229
+ from milenium.cli import main
230
+ args = shlex.split(cmd)
231
+ buf = io.StringIO()
232
+ try:
233
+ with contextlib.redirect_stdout(buf):
234
+ main(args, standalone_mode=False)
235
+ for line in buf.getvalue().splitlines():
236
+ if line.strip():
237
+ push_output(line)
238
+ except SystemExit:
239
+ pass
240
+ except Exception as e:
241
+ push_output(f"[red]ошибка: {e}[/red]")
242
+ live.update(draw())
243
+ except KeyboardInterrupt:
244
+ break
245
+ console.clear()
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: milenium
3
- Version: 0.5.2
4
- Summary: OSINT / dox / deanon toolkit
3
+ Version: 0.5.4
4
+ Summary: OSINT toolkit
5
5
  Requires-Python: >=3.9
6
6
  Description-Content-Type: text/markdown
7
7
  Requires-Dist: requests
@@ -11,6 +11,7 @@ Requires-Dist: beautifulsoup4
11
11
  Requires-Dist: rich
12
12
  Requires-Dist: click
13
13
  Requires-Dist: python-whois
14
+ Requires-Dist: psycopg2-binary
14
15
 
15
16
  # milenium
16
17
  # exiftool
@@ -29,6 +29,7 @@ milenium/modules/ip_geo_advanced.py
29
29
  milenium/modules/ip_reputation.py
30
30
  milenium/modules/leakcheck.py
31
31
  milenium/modules/logger.py
32
+ milenium/modules/neon_db.py
32
33
  milenium/modules/password_pattern.py
33
34
  milenium/modules/permutator.py
34
35
  milenium/modules/pgp_lookup.py
@@ -5,3 +5,4 @@ beautifulsoup4
5
5
  rich
6
6
  click
7
7
  python-whois
8
+ psycopg2-binary
@@ -1,7 +1,7 @@
1
1
  [project]
2
2
  name = "milenium"
3
- version = "0.5.2"
4
- description = "OSINT / dox / deanon toolkit"
3
+ version = "0.5.4"
4
+ description = "OSINT toolkit"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.9"
7
7
  dependencies = [
@@ -12,10 +12,15 @@ dependencies = [
12
12
  "rich",
13
13
  "click",
14
14
  "python-whois",
15
+ "psycopg2-binary",
15
16
  ]
16
17
 
17
18
  [project.scripts]
18
19
  milenium = "milenium.cli:main"
19
20
 
21
+ [build-system]
22
+ requires = ["setuptools>=61.0", "wheel"]
23
+ build-backend = "setuptools.build_meta"
24
+
20
25
  [tool.setuptools.packages.find]
21
26
  include = ["milenium*"]