-
Notifications
You must be signed in to change notification settings - Fork 0
/
rutabaga.py
291 lines (249 loc) · 8.39 KB
/
rutabaga.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
import argparse
import itertools
import sys
import os
import re
import threading
from datetime import datetime
import textwrap
if __name__ == "__main__":
os.system("cls")
parser = argparse.ArgumentParser(
formatter_class=argparse.RawTextHelpFormatter,
description=textwrap.dedent(
""" __ ___ __ __ _\\|/_
|__) | | | /\\ |__) /\\ / _` /\\ ( )
| \\ \\__/ | /~~\\ |__) /~~\\ \\__> /~~\\ '-,-'
Email address and login generator.
example:
rutabaga.py -d domain.com -s f -m $f_$l$l -o save.txt
Mask parameters:
$f - Last name
$i - First name
$o - Middle name
$l - Letters
Gender parameters (optional):
m - Male
f - Female
"""
),
)
# Аргументы
# Маска
parser.add_argument(
"-m",
"--mask",
type=str,
required=True,
)
# Домен почты
parser.add_argument(
"-d",
"--domain",
type=str,
required=False,
metavar="DOMAIN",
)
# Файл вывода
parser.add_argument(
"-o",
"--output",
type=str,
required=False,
metavar="PATH",
)
# Пол
parser.add_argument(
"-s",
"--sex",
type=str,
choices=[
"m", # Мужской
"f", # Женский
],
required=False,
)
# Йотированные буквы в инициалах
parser.add_argument(
"-i",
"--iotized",
required=False,
action="store_const",
const=True,
default=False,
)
# Потоки
parser.add_argument(
"-t",
"--threads",
type=int,
default=4,
)
args = parser.parse_args()
time = datetime.now().strftime("%Y.%m.%d_%H.%M.%S")
DOM = ""
iotized_symbols = [
"ye",
"ya",
"yu",
"yo",
] # Йотированные буквы (Е Ё Ю Я)
symbols = [
"a",
"e",
"r",
"t",
"y",
"u",
"i",
"o",
"p",
"s",
"d",
"f",
"g",
"h",
"j",
"k",
"l",
"z",
"c",
"v",
"b",
"n",
"m",
"w",
"q",
]
if args.domain:
DOM = args.domain.strip()
if DOM and "@" not in DOM:
DOM = "@" + DOM
if args.iotized:
symbols.extend(iotized_symbols)
# Загружаем данные из файлов
def load_data(sex=None):
"""Загружает данные о фамилиях, именах и отчествах из файлов.
Загружает данные о фамилиях, именах и отчествах из файлов,
расположенных в подкаталогах Data_M и Data_F,
в зависимости от переданного параметра sex.
Args:
sex (str, optional): Пол ("m" или "f"). Если не указан,
загружаются данные для обоих полов. По умолчанию None.
Returns:
tuple: Кортеж из трех списков: фамилий, имен и отчеств.
Возвращает пустые списки, если файлы не найдены.
"""
if sex == "m":
path = ".\\Data_M\\"
elif sex == "f":
path = ".\\Data_F\\"
else:
path = None
if path:
with open(
path + "Familias_" + sex + ".txt", "r", encoding="UTF-8"
) as file:
familias = [line.strip() for line in file]
with open(
path + "Names_" + sex + ".txt", "r", encoding="UTF-8"
) as file:
names = [line.strip() for line in file]
with open(
path + "Surnames_" + sex + ".txt", "r", encoding="UTF-8"
) as file:
surnames = [line.strip() for line in file]
else:
familias = []
names = []
surnames = []
for gender in ("M", "F"):
with open(
f".\\Data_{gender}\\Familias_{gender}.txt", "r", encoding="UTF-8"
) as file:
familias.extend([line.strip() for line in file])
with open(
f".\\Data_{gender}\\Names_{gender}.txt", "r", encoding="UTF-8"
) as file:
names.extend([line.strip() for line in file])
with open(
f".\\Data_{gender}\\Surnames_{gender}.txt", "r", encoding="UTF-8"
) as file:
surnames.extend([line.strip() for line in file])
return familias, names, surnames
# Получаем шаблон от пользователя
template = args.mask
# Проверка на валидность шаблона
if "$" not in template:
sys.exit("Ошибка: Шаблон должен содержать хотя бы одну переменную.")
# Разбиваем шаблон на части, учитывая символы после $
parts = re.split(r"\$([a-z]+)", template)
# Используем множество для хранения уникальных логинов
unique_logins = set()
lock = threading.Lock()
def generate_and_write(sex, file):
"""Генерирует и записывает уникальные логины в файл.
Генерирует уникальные логины, используя данные о фамилиях,
именах, отчествах и символах, и записывает их в файл.
Args:
sex (str): Пол ("m" или "f"), используемый для загрузки данных.
file (file object): Открытый файл для записи сгенерированных логинов.
"""
# Создаем локальный словарь для каждого потока
data = {
"f": [],
"i": [],
"o": [],
"l": symbols,
}
familias, names, surnames = load_data(sex)
data["f"] = familias
data["i"] = names
data["o"] = surnames
variants = []
for i, part in enumerate(parts):
if i % 2 == 1: # Если индекс нечетный - это плейсхолдер
key = part
if key in data:
variants.append(data[key])
else:
print(f"Unknown placeholder: {key}")
variants.append([part])
else: # Если индекс четный - это обычный текст
variants.append([part])
for combination in itertools.product(*variants):
# Соединяем части в логин
login = "".join(combination) + DOM
# Проверяем, есть ли логин в множестве
with lock:
if login not in unique_logins:
# Если логина нет, добавляем его в множество
unique_logins.add(login)
print(login)
file.write(login + "\n")
def worker(sex, file):
"""Запускает генерацию и запись уникальных логинов для заданного пола.
Функция-обертка, которая запускает генерацию и запись уникальных логинов
в файл с помощью функции `generate_and_write` для указанного пола.
Args:
sex (str): Пол ("m" или "f"), используемый для загрузки данных.
file (file object): Открытый файл для записи сгенерированных логинов.
"""
generate_and_write(sex, file)
if __name__ == "__main__":
threads = []
output_file = args.output or f"rutabaga_[{time}].txt"
try:
with open(output_file, "a", encoding="UTF-8") as filezx:
for sex in args.sex or ["m", "f"]:
for _ in range(args.threads):
thread = threading.Thread(target=worker, args=(sex, filezx))
threads.append(thread)
thread.start()
for thread in threads:
thread.join()
except FileNotFoundError:
print(f"ERROR: cant create '{output_file}' or something.")
except PermissionError:
print(f"ERROR: No access to '{output_file}'.")
print(f"\n{output_file} \n\nLogins generated: {len(unique_logins)}")