absfuyu 4.2.0__py3-none-any.whl → 5.0.0__py3-none-any.whl
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.
Potentially problematic release.
This version of absfuyu might be problematic. Click here for more details.
- absfuyu/__init__.py +4 -4
- absfuyu/__main__.py +13 -1
- absfuyu/cli/color.py +7 -0
- absfuyu/cli/do_group.py +0 -35
- absfuyu/cli/tool_group.py +5 -5
- absfuyu/config/__init__.py +17 -34
- absfuyu/core/__init__.py +49 -0
- absfuyu/core/baseclass.py +299 -0
- absfuyu/core/baseclass2.py +165 -0
- absfuyu/core/decorator.py +67 -0
- absfuyu/core/docstring.py +163 -0
- absfuyu/core/dummy_cli.py +67 -0
- absfuyu/core/dummy_func.py +47 -0
- absfuyu/dxt/__init__.py +42 -0
- absfuyu/dxt/dictext.py +201 -0
- absfuyu/dxt/dxt_support.py +79 -0
- absfuyu/dxt/intext.py +586 -0
- absfuyu/dxt/listext.py +508 -0
- absfuyu/dxt/strext.py +530 -0
- absfuyu/{extensions → extra}/__init__.py +2 -2
- absfuyu/extra/beautiful.py +251 -0
- absfuyu/{extensions → extra}/data_analysis.py +51 -82
- absfuyu/fun/__init__.py +110 -135
- absfuyu/fun/tarot.py +9 -17
- absfuyu/game/__init__.py +6 -0
- absfuyu/game/game_stat.py +6 -0
- absfuyu/game/sudoku.py +7 -1
- absfuyu/game/tictactoe.py +12 -5
- absfuyu/game/wordle.py +14 -8
- absfuyu/general/__init__.py +6 -79
- absfuyu/general/content.py +22 -36
- absfuyu/general/generator.py +17 -42
- absfuyu/general/human.py +108 -228
- absfuyu/general/shape.py +1334 -0
- absfuyu/logger.py +8 -13
- absfuyu/pkg_data/__init__.py +136 -99
- absfuyu/pkg_data/deprecated.py +133 -0
- absfuyu/sort.py +6 -130
- absfuyu/tools/__init__.py +2 -2
- absfuyu/tools/checksum.py +33 -22
- absfuyu/tools/converter.py +51 -48
- absfuyu/tools/keygen.py +25 -30
- absfuyu/tools/obfuscator.py +246 -112
- absfuyu/tools/passwordlib.py +99 -29
- absfuyu/tools/shutdownizer.py +68 -47
- absfuyu/tools/web.py +2 -9
- absfuyu/util/__init__.py +15 -15
- absfuyu/util/api.py +10 -15
- absfuyu/util/json_method.py +7 -24
- absfuyu/util/lunar.py +3 -9
- absfuyu/util/path.py +22 -27
- absfuyu/util/performance.py +43 -67
- absfuyu/util/shorten_number.py +65 -14
- absfuyu/util/zipped.py +9 -15
- {absfuyu-4.2.0.dist-info → absfuyu-5.0.0.dist-info}/METADATA +41 -14
- absfuyu-5.0.0.dist-info/RECORD +68 -0
- absfuyu/core.py +0 -57
- absfuyu/everything.py +0 -32
- absfuyu/extensions/beautiful.py +0 -188
- absfuyu/fun/WGS.py +0 -134
- absfuyu/general/data_extension.py +0 -1796
- absfuyu/tools/stats.py +0 -226
- absfuyu/util/pkl.py +0 -67
- absfuyu-4.2.0.dist-info/RECORD +0 -59
- {absfuyu-4.2.0.dist-info → absfuyu-5.0.0.dist-info}/WHEEL +0 -0
- {absfuyu-4.2.0.dist-info → absfuyu-5.0.0.dist-info}/entry_points.txt +0 -0
- {absfuyu-4.2.0.dist-info → absfuyu-5.0.0.dist-info}/licenses/LICENSE +0 -0
absfuyu/tools/obfuscator.py
CHANGED
|
@@ -3,38 +3,121 @@ Absfuyu: Obfuscator
|
|
|
3
3
|
-------------------
|
|
4
4
|
Obfuscate code
|
|
5
5
|
|
|
6
|
-
Version:
|
|
7
|
-
Date updated:
|
|
6
|
+
Version: 5.0.0
|
|
7
|
+
Date updated: 23/02/2025 (dd/mm/yyyy)
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
# Module level
|
|
11
|
-
|
|
12
|
-
__all__ = ["Obfuscator"]
|
|
11
|
+
# ---------------------------------------------------------------------------
|
|
12
|
+
__all__ = ["Obfuscator", "StrShifter"]
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
# Library
|
|
16
|
-
|
|
16
|
+
# ---------------------------------------------------------------------------
|
|
17
17
|
import base64
|
|
18
18
|
import codecs
|
|
19
19
|
import random
|
|
20
20
|
import zlib
|
|
21
|
+
from collections import deque
|
|
22
|
+
from string import Template
|
|
23
|
+
from typing import ClassVar
|
|
21
24
|
|
|
22
|
-
from absfuyu.
|
|
23
|
-
from absfuyu.
|
|
24
|
-
from absfuyu.general.generator import Generator
|
|
25
|
+
from absfuyu.core import BaseClass, ShowAllMethodsMixin, versionadded
|
|
26
|
+
from absfuyu.dxt import Text
|
|
27
|
+
from absfuyu.general.generator import Charset, Generator
|
|
25
28
|
from absfuyu.logger import logger
|
|
26
29
|
|
|
27
30
|
|
|
28
31
|
# Class
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
# ---------------------------------------------------------------------------
|
|
33
|
+
@versionadded("5.0.0")
|
|
34
|
+
class StrShifter(BaseClass):
|
|
35
|
+
"""Shift characters in a string by a specified number of positions."""
|
|
33
36
|
|
|
37
|
+
__slots__ = ("_str_to_shift", "shift_by")
|
|
34
38
|
|
|
35
|
-
|
|
39
|
+
def __init__(self, str_to_shift: str, shift_by: int = 5) -> None:
|
|
40
|
+
"""
|
|
41
|
+
Initialize the StrShifter with the string to shift and the shift amount.
|
|
42
|
+
|
|
43
|
+
Parameters
|
|
44
|
+
----------
|
|
45
|
+
str_to_shift : str
|
|
46
|
+
The string whose characters will be shifted.
|
|
47
|
+
|
|
48
|
+
shift_by : int, optional
|
|
49
|
+
The number of positions to shift the characters, by default ``5``.
|
|
50
|
+
"""
|
|
51
|
+
if not isinstance(str_to_shift, str):
|
|
52
|
+
raise TypeError("Value must be an instance of str")
|
|
53
|
+
self._str_to_shift = str_to_shift
|
|
54
|
+
self.shift_by = shift_by
|
|
55
|
+
|
|
56
|
+
def _make_convert_table(self) -> dict[str, str]:
|
|
57
|
+
"""
|
|
58
|
+
Create a translation table for shifting characters.
|
|
59
|
+
|
|
60
|
+
Returns
|
|
61
|
+
-------
|
|
62
|
+
dict[str, str]
|
|
63
|
+
A dictionary mapping each character to its shifted counterpart.
|
|
64
|
+
"""
|
|
65
|
+
data = self._str_to_shift # Make a copy
|
|
66
|
+
|
|
67
|
+
unique_char_sorted = deque(sorted(list(set(data))))
|
|
68
|
+
translate = unique_char_sorted.copy()
|
|
69
|
+
translate.rotate(self.shift_by)
|
|
70
|
+
convert_table = dict(zip(unique_char_sorted, translate))
|
|
71
|
+
|
|
72
|
+
return convert_table
|
|
73
|
+
|
|
74
|
+
def _use_convert_table(self, convert_table: dict[str, str]) -> str:
|
|
75
|
+
"""
|
|
76
|
+
Convert the original string using the provided conversion table.
|
|
77
|
+
|
|
78
|
+
Parameters
|
|
79
|
+
----------
|
|
80
|
+
convert_table : dict[str, str]
|
|
81
|
+
The conversion table mapping original characters to shifted characters.
|
|
82
|
+
|
|
83
|
+
Returns
|
|
84
|
+
-------
|
|
85
|
+
str
|
|
86
|
+
The transformed string after applying the conversion table.
|
|
87
|
+
"""
|
|
88
|
+
return "".join([convert_table[char] for char in list(self._str_to_shift)])
|
|
89
|
+
|
|
90
|
+
def shift(self) -> str:
|
|
91
|
+
"""
|
|
92
|
+
Shift the characters in the string and return the new string.
|
|
93
|
+
|
|
94
|
+
Returns
|
|
95
|
+
-------
|
|
96
|
+
str
|
|
97
|
+
The resulting string after shifting.
|
|
98
|
+
"""
|
|
99
|
+
return self._use_convert_table(self._make_convert_table())
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class Obfuscator(ShowAllMethodsMixin):
|
|
36
103
|
"""Obfuscate code"""
|
|
37
104
|
|
|
105
|
+
# Var
|
|
106
|
+
LIB_BASE64_ONLY: ClassVar[list[str]] = ["base64"]
|
|
107
|
+
LIB_FULL: ClassVar[list[str]] = ["base64", "codecs", "zlib"]
|
|
108
|
+
|
|
109
|
+
# Template
|
|
110
|
+
SINGLE_LINE_TEMPLATE: ClassVar[Template] = Template(
|
|
111
|
+
"exec(bytes.fromhex('$one_line_code').decode('utf-8'))"
|
|
112
|
+
)
|
|
113
|
+
PRE_HEX_B64_TEMPLATE: ClassVar[Template] = Template(
|
|
114
|
+
"eval(compile(base64.b64decode($encoded_string),$type_var,$execute))"
|
|
115
|
+
)
|
|
116
|
+
PRE_HEX_FULL_TEMPLATE: ClassVar[Template] = Template(
|
|
117
|
+
"eval(compile(base64.b64decode(zlib.decompress(base64.b64decode(codecs."
|
|
118
|
+
"encode($encoded_string,$codec_to_decode).encode()))),$type_var,$execute))"
|
|
119
|
+
)
|
|
120
|
+
|
|
38
121
|
def __init__(
|
|
39
122
|
self,
|
|
40
123
|
code: str,
|
|
@@ -45,56 +128,73 @@ class Obfuscator:
|
|
|
45
128
|
fake_data: bool = False,
|
|
46
129
|
) -> None:
|
|
47
130
|
"""
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
131
|
+
Obfuscator
|
|
132
|
+
|
|
133
|
+
Parameters
|
|
134
|
+
----------
|
|
135
|
+
code : str
|
|
136
|
+
Code text
|
|
137
|
+
|
|
138
|
+
base64_only : bool, optional
|
|
139
|
+
- ``True``: encode in base64 form only
|
|
140
|
+
- ``False``: base64, compress, rot13 (default)
|
|
141
|
+
|
|
142
|
+
split_every : int, optional
|
|
143
|
+
Split the long line of code every ``x`` character.
|
|
144
|
+
Minimum is ``1``, by default ``60``
|
|
145
|
+
|
|
146
|
+
variable_length : int, optional
|
|
147
|
+
Length of variable name (when data string split).
|
|
148
|
+
Minimum is ``7``, by default ``12``
|
|
149
|
+
|
|
150
|
+
fake_data : bool, optional
|
|
151
|
+
Generate additional meaningless data, by default ``False``
|
|
53
152
|
"""
|
|
54
153
|
self.base_code = code
|
|
55
154
|
self.base64_only = base64_only
|
|
56
|
-
self.split_every_length = split_every
|
|
57
|
-
self.variable_length =
|
|
155
|
+
self.split_every_length = max(1, split_every)
|
|
156
|
+
self.variable_length = max(7, variable_length)
|
|
58
157
|
self.fake_data = fake_data
|
|
59
158
|
|
|
60
159
|
# Setting
|
|
61
160
|
self._library_import_variable_length = self.variable_length - 1
|
|
62
161
|
self._splited_variable_length = self.variable_length
|
|
63
162
|
self._decode_variable_length = self.variable_length + 3
|
|
64
|
-
# logger.debug("Class initiated.")
|
|
65
163
|
|
|
66
164
|
def __str__(self) -> str:
|
|
67
|
-
|
|
68
|
-
|
|
165
|
+
return self.__repr__()
|
|
166
|
+
|
|
167
|
+
def __repr__(self) -> str:
|
|
168
|
+
repr_out_dict = {
|
|
69
169
|
"base_code": "...",
|
|
70
170
|
"base64_only": self.base64_only,
|
|
71
171
|
"split_every_length": self.split_every_length,
|
|
72
172
|
"variable_length": self.variable_length,
|
|
73
173
|
"fake_data": self.fake_data,
|
|
74
174
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
def __repr__(self) -> str:
|
|
78
|
-
return self.__str__()
|
|
175
|
+
repr_out = ", ".join([f"{k}={repr(v)}" for k, v in repr_out_dict.items()])
|
|
176
|
+
return f"{self.__class__.__name__}({repr_out})"
|
|
79
177
|
|
|
80
178
|
def to_single_line(self) -> str:
|
|
81
179
|
"""
|
|
82
180
|
Convert multiple lines of code into one line
|
|
83
181
|
|
|
84
|
-
|
|
85
|
-
|
|
182
|
+
Returns
|
|
183
|
+
-------
|
|
184
|
+
str
|
|
185
|
+
Converted code.
|
|
86
186
|
"""
|
|
87
187
|
newcode = self.base_code.encode("utf-8").hex()
|
|
88
|
-
|
|
89
|
-
output = f"exec(bytes.fromhex('{newcode}').decode('utf-8'))"
|
|
188
|
+
output = self.SINGLE_LINE_TEMPLATE.substitute(one_line_code=newcode)
|
|
90
189
|
return output
|
|
91
190
|
|
|
191
|
+
# Obfuscate original code
|
|
92
192
|
def _obfuscate(self) -> str:
|
|
93
193
|
"""
|
|
94
194
|
Convert multiple lines of code through multiple transformation
|
|
95
195
|
(base64 -> compress -> base64 -> caesar (13))
|
|
96
196
|
"""
|
|
97
|
-
code = self.base_code
|
|
197
|
+
code = self.base_code # Make a copy
|
|
98
198
|
logger.debug("Encoding...")
|
|
99
199
|
|
|
100
200
|
b64_encode = base64.b64encode(code.encode())
|
|
@@ -102,12 +202,12 @@ class Obfuscator:
|
|
|
102
202
|
output = b64_encode.decode()
|
|
103
203
|
else:
|
|
104
204
|
compressed_data = zlib.compress(b64_encode)
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
logger.debug(f"Base64 encode 2: {b64_encode_2}
|
|
110
|
-
caesar_data = codecs.encode(b64_encode_2
|
|
205
|
+
logger.debug(
|
|
206
|
+
f"Compressed data: {str(compressed_data)} | Len: {len(str(compressed_data))}"
|
|
207
|
+
)
|
|
208
|
+
b64_encode_2 = base64.b64encode(compressed_data).decode()
|
|
209
|
+
logger.debug(f"Base64 encode 2: {b64_encode_2} | Len: {len(b64_encode_2)}")
|
|
210
|
+
caesar_data = codecs.encode(b64_encode_2, "rot_13")
|
|
111
211
|
output = caesar_data
|
|
112
212
|
|
|
113
213
|
logger.debug(f"Output: {output}")
|
|
@@ -122,16 +222,100 @@ class Obfuscator:
|
|
|
122
222
|
text: Code that need to convert
|
|
123
223
|
raw: Return hex form only
|
|
124
224
|
"""
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
b64_decode_codec = f"base64.b64decode('{b64_encode_codec}'.encode())"
|
|
225
|
+
b64_encode_codec = base64.b64encode(text.encode()).decode()
|
|
226
|
+
b64_decode_codec = f"base64.b64decode('{b64_encode_codec}'.encode()).decode()"
|
|
128
227
|
hex = Text(b64_decode_codec).to_hex()
|
|
129
|
-
out = f"eval('{hex}')
|
|
228
|
+
out = f"eval('{hex}')"
|
|
130
229
|
if raw:
|
|
131
230
|
return hex
|
|
132
231
|
return out
|
|
133
232
|
|
|
134
|
-
|
|
233
|
+
# Generate output (decode obfuscated code)
|
|
234
|
+
def _make_output_lib(self) -> list[str]:
|
|
235
|
+
"""Obfuscate the `import <lib>`"""
|
|
236
|
+
output = []
|
|
237
|
+
|
|
238
|
+
# Make import lib
|
|
239
|
+
library_list = self.LIB_BASE64_ONLY if self.base64_only else self.LIB_FULL
|
|
240
|
+
imports = [f"import {lib}" for lib in library_list]
|
|
241
|
+
logger.debug(f"Lib: {imports}")
|
|
242
|
+
|
|
243
|
+
# Convert to hex
|
|
244
|
+
lib_hex = Text("\n".join(imports)).to_hex()
|
|
245
|
+
output.append(f"exec('{lib_hex}')")
|
|
246
|
+
logger.debug(f"Current output (import library): {output}")
|
|
247
|
+
|
|
248
|
+
return output
|
|
249
|
+
|
|
250
|
+
def _make_prep_for_decode_var(self) -> tuple[list[str], list[str]]:
|
|
251
|
+
"""
|
|
252
|
+
``<var> = "rot_13"``
|
|
253
|
+
``<var> = "<string>"``
|
|
254
|
+
``<var> = "exec"``
|
|
255
|
+
|
|
256
|
+
Returns
|
|
257
|
+
-------
|
|
258
|
+
tuple[list[str], list[str]]
|
|
259
|
+
- tuple[0]: output
|
|
260
|
+
- tuple[1]: decode var name
|
|
261
|
+
"""
|
|
262
|
+
output = []
|
|
263
|
+
|
|
264
|
+
# Make variables for "rot_13", "<string>", "exec"
|
|
265
|
+
dc_name_lst: list[str] = Generator.generate_string(
|
|
266
|
+
charset=Charset.ALPHABET,
|
|
267
|
+
size=self._decode_variable_length,
|
|
268
|
+
times=3,
|
|
269
|
+
unique=True,
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
# Assign and convert to hex
|
|
273
|
+
encode_codec = "rot_13" # full
|
|
274
|
+
if not self.base64_only: # full
|
|
275
|
+
hex_0 = self._convert_to_base64_decode(encode_codec)
|
|
276
|
+
output.append(f"{dc_name_lst[0]}={hex_0}")
|
|
277
|
+
|
|
278
|
+
for i, x in enumerate(["<string>", "exec"], start=1):
|
|
279
|
+
# hex_str = Text(x).to_hex()
|
|
280
|
+
hex_str = self._convert_to_base64_decode(x)
|
|
281
|
+
output.append(f"{dc_name_lst[i]}={hex_str}")
|
|
282
|
+
logger.debug(f"Current output (decode variables): {output}")
|
|
283
|
+
|
|
284
|
+
return output, dc_name_lst
|
|
285
|
+
|
|
286
|
+
def _make_fake_output(self, input_size: int) -> list[str]:
|
|
287
|
+
"""Fake data"""
|
|
288
|
+
output = []
|
|
289
|
+
|
|
290
|
+
f1 = Generator.generate_string(
|
|
291
|
+
charset=Charset.DEFAULT,
|
|
292
|
+
size=input_size,
|
|
293
|
+
times=1,
|
|
294
|
+
string_type_if_1=True,
|
|
295
|
+
) # Generate fake data with len of original data
|
|
296
|
+
f2 = Text(f1).divide_with_variable(
|
|
297
|
+
self.split_every_length, self._splited_variable_length
|
|
298
|
+
)
|
|
299
|
+
output.extend(f2[:-1])
|
|
300
|
+
|
|
301
|
+
# Random data
|
|
302
|
+
bait_lst = Generator.generate_string(
|
|
303
|
+
charset=Charset.ALPHABET, size=self._splited_variable_length, times=25
|
|
304
|
+
)
|
|
305
|
+
for x in bait_lst:
|
|
306
|
+
output.append(
|
|
307
|
+
f"{x}='{Generator.generate_string(charset=Charset.DEFAULT, size=self.split_every_length, times=1, string_type_if_1=True)}'"
|
|
308
|
+
)
|
|
309
|
+
|
|
310
|
+
random_eval_text = str(random.randint(1, 100))
|
|
311
|
+
for _ in range(random.randint(10, 50)):
|
|
312
|
+
random_eval_text += f"+{random.randint(1, 100)}"
|
|
313
|
+
random_eval_text_final = Text(random_eval_text).to_hex()
|
|
314
|
+
output.append(f"eval('{random_eval_text_final}')")
|
|
315
|
+
|
|
316
|
+
return output
|
|
317
|
+
|
|
318
|
+
def _make_obfuscate_output(self) -> list[str]:
|
|
135
319
|
"""
|
|
136
320
|
Convert multiple lines of code through multiple transformation
|
|
137
321
|
(base64 -> compress -> base64 -> caesar (13))
|
|
@@ -146,16 +330,7 @@ class Obfuscator:
|
|
|
146
330
|
output = []
|
|
147
331
|
|
|
148
332
|
# Import library
|
|
149
|
-
|
|
150
|
-
ObfuscatorLibraryList.BASE64_ONLY
|
|
151
|
-
if self.base64_only
|
|
152
|
-
else ObfuscatorLibraryList.FULL
|
|
153
|
-
)
|
|
154
|
-
temp = [f"import {lib}" for lib in library_list]
|
|
155
|
-
logger.debug(f"Lib: {temp}")
|
|
156
|
-
lib_hex = Text("\n".join(temp)).to_hex() # Convert to hex
|
|
157
|
-
output.append(f"exec('{lib_hex}')")
|
|
158
|
-
logger.debug(f"Current output (import library): {output}")
|
|
333
|
+
output.extend(self._make_output_lib())
|
|
159
334
|
|
|
160
335
|
# Append divided long text list
|
|
161
336
|
input_list = input_str.divide_with_variable(
|
|
@@ -167,64 +342,30 @@ class Obfuscator:
|
|
|
167
342
|
logger.debug(f"Current output (encoded code): {output}")
|
|
168
343
|
|
|
169
344
|
# Decode: encoded_str
|
|
170
|
-
dc_name_lst =
|
|
171
|
-
|
|
172
|
-
)
|
|
173
|
-
encode_codec = "rot_13" # full
|
|
174
|
-
if not self.base64_only: # full
|
|
175
|
-
hex_0 = self._convert_to_base64_decode(encode_codec)
|
|
176
|
-
output.append(f"{dc_name_lst[0]}={hex_0}")
|
|
177
|
-
hex_1 = Text("<string>").to_hex()
|
|
178
|
-
output.append(f"{dc_name_lst[1]}='{hex_1}'")
|
|
179
|
-
hex_2 = Text("exec").to_hex()
|
|
180
|
-
output.append(f"{dc_name_lst[2]}='{hex_2}'")
|
|
181
|
-
logger.debug(f"Current output (decode variables): {output}")
|
|
345
|
+
dc_out, dc_name_lst = self._make_prep_for_decode_var()
|
|
346
|
+
output.extend(dc_out)
|
|
182
347
|
|
|
183
348
|
if self.base64_only: # b64
|
|
184
|
-
pre_hex = (
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
349
|
+
pre_hex = self.PRE_HEX_B64_TEMPLATE.substitute(
|
|
350
|
+
encoded_string=encoded_str,
|
|
351
|
+
type_var=dc_name_lst[1],
|
|
352
|
+
execute=dc_name_lst[2],
|
|
188
353
|
)
|
|
189
354
|
else: # full
|
|
190
|
-
pre_hex = (
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
f"encode()))),{dc_name_lst[1]},{dc_name_lst[2]}))"
|
|
355
|
+
pre_hex = self.PRE_HEX_FULL_TEMPLATE.substitute(
|
|
356
|
+
encoded_string=encoded_str,
|
|
357
|
+
codec_to_decode=dc_name_lst[0],
|
|
358
|
+
type_var=dc_name_lst[1],
|
|
359
|
+
execute=dc_name_lst[2],
|
|
196
360
|
)
|
|
361
|
+
|
|
197
362
|
t_hex = Text(pre_hex).to_hex()
|
|
198
363
|
output.append(f"exec('{t_hex}')")
|
|
199
364
|
logger.debug(f"Current output (decode code): {output}")
|
|
200
365
|
|
|
201
366
|
# Fake data
|
|
202
367
|
if self.fake_data:
|
|
203
|
-
|
|
204
|
-
charset=Charset.DEFAULT,
|
|
205
|
-
size=len(input_str),
|
|
206
|
-
times=1,
|
|
207
|
-
string_type_if_1=True,
|
|
208
|
-
) # Generate fake data with len of original data
|
|
209
|
-
f2 = Text(f1).divide_with_variable(
|
|
210
|
-
self.split_every_length, self._splited_variable_length
|
|
211
|
-
)
|
|
212
|
-
output.extend(f2[:-1])
|
|
213
|
-
|
|
214
|
-
# Random data
|
|
215
|
-
bait_lst = gen.generate_string(
|
|
216
|
-
charset=Charset.ALPHABET, size=self._splited_variable_length, times=25
|
|
217
|
-
)
|
|
218
|
-
for x in bait_lst:
|
|
219
|
-
output.append(
|
|
220
|
-
f"{x}='{gen.generate_string(charset=Charset.DEFAULT, size=self.split_every_length, times=1, string_type_if_1=True)}'"
|
|
221
|
-
)
|
|
222
|
-
|
|
223
|
-
random_eval_text = str(random.randint(1, 100))
|
|
224
|
-
for _ in range(random.randint(10, 50)):
|
|
225
|
-
random_eval_text += f"+{random.randint(1, 100)}"
|
|
226
|
-
random_eval_text_final = Text(random_eval_text).to_hex()
|
|
227
|
-
output.append(f"eval('{random_eval_text_final}')")
|
|
368
|
+
output.extend(self._make_fake_output(len(input_str)))
|
|
228
369
|
|
|
229
370
|
logger.debug("Code obfuscated.")
|
|
230
371
|
return output
|
|
@@ -233,16 +374,9 @@ class Obfuscator:
|
|
|
233
374
|
"""
|
|
234
375
|
Obfuscate code
|
|
235
376
|
|
|
236
|
-
|
|
237
|
-
|
|
377
|
+
Returns
|
|
378
|
+
-------
|
|
379
|
+
str
|
|
380
|
+
Obfuscated code
|
|
238
381
|
"""
|
|
239
|
-
return "\n".join(self.
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
# Run
|
|
243
|
-
###########################################################################
|
|
244
|
-
if __name__ == "__main__":
|
|
245
|
-
logger.setLevel(10)
|
|
246
|
-
code = "print('Hello World')"
|
|
247
|
-
test = Obfuscator(code, fake_data=True)
|
|
248
|
-
print(test.obfuscate())
|
|
382
|
+
return "\n".join(self._make_obfuscate_output())
|
absfuyu/tools/passwordlib.py
CHANGED
|
@@ -3,34 +3,36 @@ Absfuyu: Passwordlib
|
|
|
3
3
|
--------------------
|
|
4
4
|
Password library
|
|
5
5
|
|
|
6
|
-
Version:
|
|
7
|
-
Date updated:
|
|
6
|
+
Version: 5.0.0
|
|
7
|
+
Date updated: 19/02/2025 (dd/mm/yyyy)
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
# Module level
|
|
11
|
-
|
|
12
|
-
__all__ = ["PasswordGenerator"]
|
|
11
|
+
# ---------------------------------------------------------------------------
|
|
12
|
+
__all__ = ["PasswordGenerator", "TOTP"]
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
# Library
|
|
16
|
-
|
|
16
|
+
# ---------------------------------------------------------------------------
|
|
17
17
|
import hashlib
|
|
18
|
-
import lzma
|
|
19
18
|
import os
|
|
20
19
|
import random
|
|
21
20
|
import re
|
|
22
|
-
from typing import
|
|
21
|
+
from typing import ClassVar, Literal, NamedTuple
|
|
22
|
+
from urllib.parse import quote, urlencode
|
|
23
23
|
|
|
24
|
-
from absfuyu.
|
|
24
|
+
from absfuyu.core import BaseClass, deprecated, versionadded
|
|
25
|
+
from absfuyu.dxt import DictExt, Text
|
|
25
26
|
from absfuyu.general.generator import Charset, Generator
|
|
26
27
|
from absfuyu.logger import logger
|
|
27
|
-
from absfuyu.pkg_data import DataList
|
|
28
|
+
from absfuyu.pkg_data import DataList, DataLoader
|
|
28
29
|
from absfuyu.util import set_min
|
|
29
|
-
from absfuyu.util.pkl import Pickler
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
# Function
|
|
33
|
-
|
|
33
|
+
# ---------------------------------------------------------------------------
|
|
34
|
+
@deprecated("5.0.0")
|
|
35
|
+
@versionadded("4.2.0")
|
|
34
36
|
def _password_check(password: str) -> bool:
|
|
35
37
|
"""
|
|
36
38
|
Verify the strength of ``password``.
|
|
@@ -84,21 +86,19 @@ def _password_check(password: str) -> bool:
|
|
|
84
86
|
|
|
85
87
|
|
|
86
88
|
# Class
|
|
87
|
-
|
|
89
|
+
# ---------------------------------------------------------------------------
|
|
88
90
|
class PasswordHash(NamedTuple):
|
|
89
91
|
salt: bytes
|
|
90
92
|
key: bytes
|
|
91
93
|
|
|
92
94
|
|
|
93
|
-
|
|
95
|
+
@versionadded("4.2.0")
|
|
96
|
+
class PasswordGenerator(BaseClass):
|
|
94
97
|
"""Password Generator"""
|
|
95
98
|
|
|
96
99
|
def __str__(self) -> str:
|
|
97
100
|
return f"{self.__class__.__name__}()"
|
|
98
101
|
|
|
99
|
-
def __repr__(self) -> str:
|
|
100
|
-
return self.__str__()
|
|
101
|
-
|
|
102
102
|
@staticmethod
|
|
103
103
|
def password_hash(password: str) -> PasswordHash:
|
|
104
104
|
"""
|
|
@@ -111,15 +111,12 @@ class PasswordGenerator:
|
|
|
111
111
|
salt=salt,
|
|
112
112
|
iterations=100000,
|
|
113
113
|
)
|
|
114
|
-
# out = {
|
|
115
|
-
# "salt": salt,
|
|
116
|
-
# "key": key,
|
|
117
|
-
# }
|
|
118
114
|
out = PasswordHash(salt, key)
|
|
119
115
|
return out
|
|
120
116
|
|
|
121
117
|
@staticmethod
|
|
122
118
|
def password_check(password: str) -> dict:
|
|
119
|
+
"""Check password's characteristic"""
|
|
123
120
|
data = Text(password).analyze()
|
|
124
121
|
data = DictExt(data).apply(lambda x: True if x > 0 else False) # type: ignore
|
|
125
122
|
data.__setitem__("length", len(password))
|
|
@@ -175,7 +172,7 @@ class PasswordGenerator:
|
|
|
175
172
|
check += 1
|
|
176
173
|
|
|
177
174
|
if include_special:
|
|
178
|
-
charset += r"[
|
|
175
|
+
charset += r"[!#$%&'()*+,-./]^_`{|}~\""
|
|
179
176
|
check += 1
|
|
180
177
|
|
|
181
178
|
while True:
|
|
@@ -196,7 +193,7 @@ class PasswordGenerator:
|
|
|
196
193
|
@staticmethod
|
|
197
194
|
def generate_passphrase(
|
|
198
195
|
num_of_blocks: int = 5,
|
|
199
|
-
block_divider:
|
|
196
|
+
block_divider: str | None = None,
|
|
200
197
|
first_letter_cap: bool = True,
|
|
201
198
|
include_number: bool = True,
|
|
202
199
|
*,
|
|
@@ -234,12 +231,12 @@ class PasswordGenerator:
|
|
|
234
231
|
Myomectomies7-Sully4-Torpedomen7-Netful2-Begaud8
|
|
235
232
|
"""
|
|
236
233
|
words: list[str] = (
|
|
237
|
-
(
|
|
234
|
+
DataLoader(DataList.PASSWORDLIB).load().decode().split(",")
|
|
238
235
|
if not custom_word_list
|
|
239
236
|
else custom_word_list
|
|
240
237
|
)
|
|
241
238
|
|
|
242
|
-
if
|
|
239
|
+
if block_divider is None:
|
|
243
240
|
block_divider = "-"
|
|
244
241
|
|
|
245
242
|
dat = [random.choice(words) for _ in range(num_of_blocks)]
|
|
@@ -248,13 +245,86 @@ class PasswordGenerator:
|
|
|
248
245
|
dat = list(map(lambda x: x.title(), dat))
|
|
249
246
|
|
|
250
247
|
if include_number:
|
|
251
|
-
idx = random.choice(range(
|
|
248
|
+
idx = random.choice(range(num_of_blocks))
|
|
252
249
|
dat[idx] += str(random.choice(range(10)))
|
|
253
250
|
|
|
254
251
|
return block_divider.join(dat)
|
|
255
252
|
|
|
256
253
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
254
|
+
@versionadded("5.0.0")
|
|
255
|
+
class TOTP(BaseClass):
|
|
256
|
+
"""
|
|
257
|
+
A class to represent a Time-based One-Time Password (TOTP) generator.
|
|
258
|
+
"""
|
|
259
|
+
|
|
260
|
+
URL_SCHEME: ClassVar[str] = "otpauth://totp/"
|
|
261
|
+
|
|
262
|
+
def __init__(
|
|
263
|
+
self,
|
|
264
|
+
secret: str,
|
|
265
|
+
name: str | None = None,
|
|
266
|
+
issuer: str | None = None,
|
|
267
|
+
algorithm: Literal["SHA1", "SHA256", "SHA512"] = "SHA1",
|
|
268
|
+
digit: int = 6,
|
|
269
|
+
period: int = 30,
|
|
270
|
+
) -> None:
|
|
271
|
+
"""
|
|
272
|
+
Initializes a TOTP instance.
|
|
273
|
+
|
|
274
|
+
Parameters
|
|
275
|
+
----------
|
|
276
|
+
secret : str
|
|
277
|
+
The shared secret key used to generate the TOTP.
|
|
278
|
+
|
|
279
|
+
name : str, optional
|
|
280
|
+
The name associated with the TOTP. If not provided, defaults to ``"None"``.
|
|
281
|
+
|
|
282
|
+
issuer : str, optional
|
|
283
|
+
The issuer of the TOTP.
|
|
284
|
+
|
|
285
|
+
algorithm : Literal["SHA1", "SHA256", "SHA512"], optional
|
|
286
|
+
The hashing algorithm used to generate the TOTP.
|
|
287
|
+
Must be one of ``"SHA1"``, ``"SHA256"``, or ``"SHA512"``.
|
|
288
|
+
Defaults to ``"SHA1"``.
|
|
289
|
+
|
|
290
|
+
digit : int, optional
|
|
291
|
+
The number of digits in the generated TOTP. Must be greater than 0.
|
|
292
|
+
Defaults to ``6``.
|
|
293
|
+
|
|
294
|
+
period : int, optional
|
|
295
|
+
The time step in seconds for TOTP generation. Must be greater than 0.
|
|
296
|
+
Defaults to ``30``.
|
|
297
|
+
"""
|
|
298
|
+
self.secret = secret.upper()
|
|
299
|
+
self.name = name if name else "None"
|
|
300
|
+
self.issuer = issuer
|
|
301
|
+
self.algorithm = algorithm.upper()
|
|
302
|
+
self.digit = max(digit, 1) # digit must be larger than 0
|
|
303
|
+
self.period = max(period, 1) # period must be larger than 0
|
|
304
|
+
|
|
305
|
+
def to_url(self) -> str:
|
|
306
|
+
"""
|
|
307
|
+
Generates a URL for the TOTP in the otpauth format.
|
|
308
|
+
|
|
309
|
+
The URL format is as follows:
|
|
310
|
+
``otpauth://totp/<name>?secret=<secret>&issuer=<issuer>&algorithm=<algorithm>&digit=<digit>&period=<period>``
|
|
311
|
+
|
|
312
|
+
Returns
|
|
313
|
+
-------
|
|
314
|
+
str
|
|
315
|
+
A URL representing the TOTP in otpauth format.
|
|
316
|
+
"""
|
|
317
|
+
params = {
|
|
318
|
+
"secret": self.secret,
|
|
319
|
+
"issuer": self.issuer,
|
|
320
|
+
"algorithm": self.algorithm,
|
|
321
|
+
"digit": self.digit,
|
|
322
|
+
"period": self.period,
|
|
323
|
+
}
|
|
324
|
+
# Filter out None values from the params dictionary
|
|
325
|
+
filtered_params = {k: v for k, v in params.items() if v is not None}
|
|
326
|
+
# filtered_params = {k: v for k, v in self.__dict__.items() if v is not None}
|
|
327
|
+
|
|
328
|
+
name = quote(self.name)
|
|
329
|
+
tail = urlencode(filtered_params, quote_via=quote)
|
|
330
|
+
return f"{self.URL_SCHEME}{name}?{tail}"
|