hashsmith-cli 1.0.0

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,317 @@
1
+ import base64
2
+ import binascii
3
+ from urllib.parse import unquote
4
+
5
+ from .morse import decode_morse
6
+
7
+
8
+ def decode_base64(text: str) -> str:
9
+ try:
10
+ return base64.b64decode(text.encode("utf-8"), validate=True).decode("utf-8")
11
+ except (binascii.Error, UnicodeDecodeError):
12
+ raise ValueError("Invalid Base64 format provided")
13
+
14
+
15
+ def decode_hex(text: str) -> str:
16
+ try:
17
+ return binascii.unhexlify(text.encode("utf-8")).decode("utf-8")
18
+ except (binascii.Error, UnicodeDecodeError):
19
+ raise ValueError("Invalid Hex format provided")
20
+
21
+
22
+ def decode_binary(text: str) -> str:
23
+ bits = text.strip().split()
24
+ try:
25
+ return bytes(int(chunk, 2) for chunk in bits).decode("utf-8")
26
+ except (ValueError, UnicodeDecodeError):
27
+ raise ValueError("Invalid Binary format provided")
28
+
29
+
30
+ def decode_url(text: str) -> str:
31
+ return unquote(text)
32
+
33
+
34
+ def decode_base32(text: str) -> str:
35
+ try:
36
+ return base64.b32decode(text.encode("utf-8"), casefold=True).decode("utf-8")
37
+ except (binascii.Error, UnicodeDecodeError):
38
+ raise ValueError("Invalid Base32 format provided")
39
+
40
+
41
+ def decode_base85(text: str) -> str:
42
+ try:
43
+ return base64.a85decode(text.encode("utf-8")).decode("utf-8")
44
+ except (binascii.Error, UnicodeDecodeError, ValueError):
45
+ raise ValueError("Invalid Base85 format provided")
46
+
47
+
48
+ def decode_base64url(text: str) -> str:
49
+ try:
50
+ padding = "=" * ((4 - len(text) % 4) % 4)
51
+ return base64.urlsafe_b64decode((text + padding).encode("utf-8")).decode("utf-8")
52
+ except (binascii.Error, UnicodeDecodeError):
53
+ raise ValueError("Invalid Base64URL format provided")
54
+
55
+
56
+ def decode_base58(text: str) -> str:
57
+ alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
58
+ num = 0
59
+ for ch in text:
60
+ if ch not in alphabet:
61
+ raise ValueError("Invalid Base58 format provided")
62
+ num = num * 58 + alphabet.index(ch)
63
+ # handle leading ones
64
+ pad = 0
65
+ for ch in text:
66
+ if ch == "1":
67
+ pad += 1
68
+ else:
69
+ break
70
+ data = num.to_bytes((num.bit_length() + 7) // 8, "big") if num > 0 else b""
71
+ return (b"\x00" * pad + data).decode("utf-8")
72
+
73
+
74
+ def decode_decimal(text: str) -> str:
75
+ parts = text.strip().split()
76
+ try:
77
+ values = [int(p) for p in parts]
78
+ if any(v < 0 or v > 255 for v in values):
79
+ raise ValueError
80
+ return bytes(values).decode("utf-8")
81
+ except (ValueError, UnicodeDecodeError):
82
+ raise ValueError("Invalid Decimal format provided")
83
+
84
+
85
+ def decode_octal(text: str) -> str:
86
+ parts = text.strip().split()
87
+ try:
88
+ values = [int(p, 8) for p in parts]
89
+ if any(v < 0 or v > 255 for v in values):
90
+ raise ValueError
91
+ return bytes(values).decode("utf-8")
92
+ except (ValueError, UnicodeDecodeError):
93
+ raise ValueError("Invalid Octal format provided")
94
+
95
+
96
+ def decode_caesar(text: str, shift: int) -> str:
97
+ return encode_caesar(text, -shift)
98
+
99
+
100
+ def decode_rot13(text: str) -> str:
101
+ return encode_caesar(text, 13)
102
+
103
+
104
+ def decode_morse_code(text: str) -> str:
105
+ return decode_morse(text)
106
+
107
+
108
+ def decode_vigenere(text: str, key: str) -> str:
109
+ if not key or not key.isalpha():
110
+ raise ValueError("Vigenere key must be alphabetic")
111
+ key = key.lower()
112
+ result = []
113
+ key_index = 0
114
+ for ch in text:
115
+ if ch.isalpha():
116
+ shift = ord(key[key_index % len(key)]) - 97
117
+ if "a" <= ch <= "z":
118
+ result.append(chr(((ord(ch) - 97 - shift) % 26) + 97))
119
+ else:
120
+ result.append(chr(((ord(ch) - 65 - shift) % 26) + 65))
121
+ key_index += 1
122
+ else:
123
+ result.append(ch)
124
+ return "".join(result)
125
+
126
+
127
+ def decode_xor(text: str, key: str) -> str:
128
+ if not key:
129
+ raise ValueError("XOR key is required")
130
+ try:
131
+ data = binascii.unhexlify(text.encode("utf-8"))
132
+ except (binascii.Error, ValueError):
133
+ raise ValueError("Invalid XOR hex format provided")
134
+ key_bytes = key.encode("utf-8")
135
+ out = bytes(b ^ key_bytes[i % len(key_bytes)] for i, b in enumerate(data))
136
+ try:
137
+ return out.decode("utf-8")
138
+ except UnicodeDecodeError:
139
+ raise ValueError("Invalid XOR output for UTF-8")
140
+
141
+
142
+ def decode_atbash(text: str) -> str:
143
+ result = []
144
+ for ch in text:
145
+ if "a" <= ch <= "z":
146
+ result.append(chr(122 - (ord(ch) - 97)))
147
+ elif "A" <= ch <= "Z":
148
+ result.append(chr(90 - (ord(ch) - 65)))
149
+ else:
150
+ result.append(ch)
151
+ return "".join(result)
152
+
153
+
154
+ def decode_baconian(text: str) -> str:
155
+ tokens = text.strip().split()
156
+ result = []
157
+ for token in tokens:
158
+ if token == "/":
159
+ result.append(" ")
160
+ continue
161
+ if len(token) != 5 or any(ch not in "ABab" for ch in token):
162
+ raise ValueError("Invalid Baconian format provided")
163
+ value = 0
164
+ for ch in token.upper():
165
+ value = (value << 1) | (1 if ch == "B" else 0)
166
+ if value < 0 or value > 25:
167
+ raise ValueError("Invalid Baconian format provided")
168
+ result.append(chr(65 + value))
169
+ return "".join(result)
170
+
171
+
172
+ def decode_leet_speak(text: str) -> str:
173
+ mapping = {
174
+ "0": "O",
175
+ "1": "I",
176
+ "3": "E",
177
+ "4": "A",
178
+ "5": "S",
179
+ "7": "T",
180
+ }
181
+ return "".join(mapping.get(ch, ch) for ch in text)
182
+
183
+
184
+ def decode_reverse(text: str) -> str:
185
+ return text[::-1]
186
+
187
+
188
+ def decode_brainfuck(code: str) -> str:
189
+ valid = set("+-<>[],.")
190
+ if any(ch not in valid for ch in code):
191
+ raise ValueError("Invalid Brainfuck format provided")
192
+
193
+ tape = [0]
194
+ ptr = 0
195
+ output = []
196
+ # Precompute bracket pairs
197
+ stack = []
198
+ pairs = {}
199
+ for i, ch in enumerate(code):
200
+ if ch == "[":
201
+ stack.append(i)
202
+ elif ch == "]":
203
+ if not stack:
204
+ raise ValueError("Invalid Brainfuck format provided")
205
+ j = stack.pop()
206
+ pairs[i] = j
207
+ pairs[j] = i
208
+ if stack:
209
+ raise ValueError("Invalid Brainfuck format provided")
210
+
211
+ i = 0
212
+ while i < len(code):
213
+ ch = code[i]
214
+ if ch == "+":
215
+ tape[ptr] = (tape[ptr] + 1) % 256
216
+ elif ch == "-":
217
+ tape[ptr] = (tape[ptr] - 1) % 256
218
+ elif ch == ">":
219
+ ptr += 1
220
+ if ptr == len(tape):
221
+ tape.append(0)
222
+ elif ch == "<":
223
+ ptr -= 1
224
+ if ptr < 0:
225
+ raise ValueError("Invalid Brainfuck format provided")
226
+ elif ch == ".":
227
+ output.append(chr(tape[ptr]))
228
+ elif ch == ",":
229
+ # no input stream; treat as zero
230
+ tape[ptr] = 0
231
+ elif ch == "[":
232
+ if tape[ptr] == 0:
233
+ i = pairs[i]
234
+ elif ch == "]":
235
+ if tape[ptr] != 0:
236
+ i = pairs[i]
237
+ i += 1
238
+
239
+ return "".join(output)
240
+
241
+
242
+ def decode_rail_fence(text: str, rails: int) -> str:
243
+ if rails < 2:
244
+ raise ValueError("Rails must be >= 2")
245
+ length = len(text)
246
+ # Determine rail pattern
247
+ pattern = []
248
+ rail = 0
249
+ direction = 1
250
+ for _ in range(length):
251
+ pattern.append(rail)
252
+ rail += direction
253
+ if rail == 0 or rail == rails - 1:
254
+ direction *= -1
255
+ # Count characters per rail
256
+ counts = [pattern.count(r) for r in range(rails)]
257
+ rails_data = []
258
+ idx = 0
259
+ for count in counts:
260
+ rails_data.append(list(text[idx:idx + count]))
261
+ idx += count
262
+ # Reconstruct
263
+ result = []
264
+ rail_positions = [0] * rails
265
+ for r in pattern:
266
+ result.append(rails_data[r][rail_positions[r]])
267
+ rail_positions[r] += 1
268
+ return "".join(result)
269
+
270
+
271
+ def decode_polybius(text: str) -> str:
272
+ alphabet = "ABCDEFGHIKLMNOPQRSTUVWXYZ"
273
+ tokens = text.strip().split()
274
+ result = []
275
+ for token in tokens:
276
+ if token == "/":
277
+ result.append(" ")
278
+ continue
279
+ if len(token) != 2 or not token.isdigit():
280
+ raise ValueError("Invalid Polybius format provided")
281
+ row = int(token[0]) - 1
282
+ col = int(token[1]) - 1
283
+ if row not in range(5) or col not in range(5):
284
+ raise ValueError("Invalid Polybius format provided")
285
+ result.append(alphabet[row * 5 + col])
286
+ return "".join(result)
287
+
288
+
289
+ def decode_unicode_escaped(text: str) -> str:
290
+ if len(text) % 6 != 0:
291
+ raise ValueError("Invalid Unicode escaped format provided")
292
+ result = []
293
+ i = 0
294
+ while i < len(text):
295
+ chunk = text[i:i + 6]
296
+ if not chunk.startswith("\\u"):
297
+ raise ValueError("Invalid Unicode escaped format provided")
298
+ hex_part = chunk[2:]
299
+ try:
300
+ result.append(chr(int(hex_part, 16)))
301
+ except ValueError:
302
+ raise ValueError("Invalid Unicode escaped format provided")
303
+ i += 6
304
+ return "".join(result)
305
+
306
+
307
+ def encode_caesar(text: str, shift: int) -> str:
308
+ shift = shift % 26
309
+ result = []
310
+ for ch in text:
311
+ if "a" <= ch <= "z":
312
+ result.append(chr(((ord(ch) - 97 + shift) % 26) + 97))
313
+ elif "A" <= ch <= "Z":
314
+ result.append(chr(((ord(ch) - 65 + shift) % 26) + 65))
315
+ else:
316
+ result.append(ch)
317
+ return "".join(result)
@@ -0,0 +1,203 @@
1
+ import base64
2
+ import binascii
3
+ from urllib.parse import quote
4
+
5
+ from .morse import encode_morse
6
+
7
+
8
+ def encode_base64(text: str) -> str:
9
+ return base64.b64encode(text.encode("utf-8")).decode("utf-8")
10
+
11
+
12
+ def encode_hex(text: str) -> str:
13
+ return binascii.hexlify(text.encode("utf-8")).decode("utf-8")
14
+
15
+
16
+ def encode_binary(text: str) -> str:
17
+ return " ".join(format(byte, "08b") for byte in text.encode("utf-8"))
18
+
19
+
20
+ def encode_url(text: str) -> str:
21
+ return quote(text, safe="")
22
+
23
+
24
+ def encode_base32(text: str) -> str:
25
+ return base64.b32encode(text.encode("utf-8")).decode("utf-8")
26
+
27
+
28
+ def encode_base85(text: str) -> str:
29
+ return base64.a85encode(text.encode("utf-8")).decode("utf-8")
30
+
31
+
32
+ def encode_base64url(text: str) -> str:
33
+ return base64.urlsafe_b64encode(text.encode("utf-8")).decode("utf-8").rstrip("=")
34
+
35
+
36
+ def encode_base58(text: str) -> str:
37
+ alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
38
+ data = text.encode("utf-8")
39
+ num = int.from_bytes(data, "big")
40
+ enc = []
41
+ while num > 0:
42
+ num, rem = divmod(num, 58)
43
+ enc.append(alphabet[rem])
44
+ # handle leading zeros
45
+ pad = 0
46
+ for b in data:
47
+ if b == 0:
48
+ pad += 1
49
+ else:
50
+ break
51
+ return "1" * pad + "".join(reversed(enc or [alphabet[0]]))
52
+
53
+
54
+ def encode_decimal(text: str) -> str:
55
+ return " ".join(str(byte) for byte in text.encode("utf-8"))
56
+
57
+
58
+ def encode_octal(text: str) -> str:
59
+ return " ".join(format(byte, "o") for byte in text.encode("utf-8"))
60
+
61
+
62
+ def encode_brainfuck(text: str) -> str:
63
+ # Simple encoder: adjust current cell with +/- and output with .
64
+ current = 0
65
+ output = []
66
+ for ch in text:
67
+ target = ord(ch)
68
+ delta = target - current
69
+ if delta > 0:
70
+ output.append("+" * delta)
71
+ elif delta < 0:
72
+ output.append("-" * (-delta))
73
+ output.append(".")
74
+ current = target
75
+ return "".join(output)
76
+
77
+
78
+ def encode_rail_fence(text: str, rails: int) -> str:
79
+ if rails < 2:
80
+ raise ValueError("Rails must be >= 2")
81
+ fence = ["" for _ in range(rails)]
82
+ rail = 0
83
+ direction = 1
84
+ for ch in text:
85
+ fence[rail] += ch
86
+ rail += direction
87
+ if rail == 0 or rail == rails - 1:
88
+ direction *= -1
89
+ return "".join(fence)
90
+
91
+
92
+ def encode_polybius(text: str) -> str:
93
+ alphabet = "ABCDEFGHIKLMNOPQRSTUVWXYZ" # I/J combined
94
+ pairs = []
95
+ for ch in text.upper():
96
+ if ch == "J":
97
+ ch = "I"
98
+ if ch in alphabet:
99
+ idx = alphabet.index(ch)
100
+ row = idx // 5 + 1
101
+ col = idx % 5 + 1
102
+ pairs.append(f"{row}{col}")
103
+ elif ch == " ":
104
+ pairs.append("/")
105
+ return " ".join(pairs)
106
+
107
+
108
+ def encode_unicode_escaped(text: str) -> str:
109
+ return "".join(f"\\u{ord(ch):04x}" for ch in text)
110
+
111
+
112
+ def encode_caesar(text: str, shift: int) -> str:
113
+ shift = shift % 26
114
+ result = []
115
+ for ch in text:
116
+ if "a" <= ch <= "z":
117
+ result.append(chr(((ord(ch) - 97 + shift) % 26) + 97))
118
+ elif "A" <= ch <= "Z":
119
+ result.append(chr(((ord(ch) - 65 + shift) % 26) + 65))
120
+ else:
121
+ result.append(ch)
122
+ return "".join(result)
123
+
124
+
125
+ def encode_rot13(text: str) -> str:
126
+ return encode_caesar(text, 13)
127
+
128
+
129
+ def encode_morse_code(text: str) -> str:
130
+ return encode_morse(text)
131
+
132
+
133
+ def encode_vigenere(text: str, key: str) -> str:
134
+ if not key or not key.isalpha():
135
+ raise ValueError("Vigenere key must be alphabetic")
136
+ key = key.lower()
137
+ result = []
138
+ key_index = 0
139
+ for ch in text:
140
+ if ch.isalpha():
141
+ shift = ord(key[key_index % len(key)]) - 97
142
+ if "a" <= ch <= "z":
143
+ result.append(chr(((ord(ch) - 97 + shift) % 26) + 97))
144
+ else:
145
+ result.append(chr(((ord(ch) - 65 + shift) % 26) + 65))
146
+ key_index += 1
147
+ else:
148
+ result.append(ch)
149
+ return "".join(result)
150
+
151
+
152
+ def encode_xor(text: str, key: str) -> str:
153
+ if not key:
154
+ raise ValueError("XOR key is required")
155
+ data = text.encode("utf-8")
156
+ key_bytes = key.encode("utf-8")
157
+ out = bytes(b ^ key_bytes[i % len(key_bytes)] for i, b in enumerate(data))
158
+ return binascii.hexlify(out).decode("utf-8")
159
+
160
+
161
+ def encode_atbash(text: str) -> str:
162
+ result = []
163
+ for ch in text:
164
+ if "a" <= ch <= "z":
165
+ result.append(chr(122 - (ord(ch) - 97)))
166
+ elif "A" <= ch <= "Z":
167
+ result.append(chr(90 - (ord(ch) - 65)))
168
+ else:
169
+ result.append(ch)
170
+ return "".join(result)
171
+
172
+
173
+ def encode_baconian(text: str) -> str:
174
+ tokens = []
175
+ for ch in text:
176
+ if ch == " ":
177
+ tokens.append("/")
178
+ continue
179
+ if ch.isalpha():
180
+ idx = ord(ch.upper()) - 65
181
+ if 0 <= idx < 26:
182
+ code = "".join("B" if (idx >> bit) & 1 else "A" for bit in range(4, -1, -1))
183
+ tokens.append(code)
184
+ return " ".join(tokens)
185
+
186
+
187
+ def encode_leet_speak(text: str) -> str:
188
+ mapping = {
189
+ "A": "4",
190
+ "E": "3",
191
+ "S": "5",
192
+ "T": "7",
193
+ "O": "0",
194
+ }
195
+ result = []
196
+ for ch in text:
197
+ repl = mapping.get(ch.upper())
198
+ result.append(repl if repl else ch)
199
+ return "".join(result)
200
+
201
+
202
+ def encode_reverse(text: str) -> str:
203
+ return text[::-1]