rtty-soda 0.1.6__py3-none-any.whl → 0.2.1__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 rtty-soda might be problematic. Click here for more details.
- rtty_soda/archivers.py +11 -3
- rtty_soda/cli_io.py +62 -28
- rtty_soda/cryptography/kdf.py +12 -5
- rtty_soda/cryptography/public.py +12 -12
- rtty_soda/cryptography/secret.py +13 -10
- rtty_soda/encoders/__init__.py +6 -2
- rtty_soda/encoders/base26_encoder.py +4 -3
- rtty_soda/encoders/base31_encoder.py +19 -0
- rtty_soda/encoders/base36_encoder.py +4 -3
- rtty_soda/encoders/base64_encoder.py +16 -0
- rtty_soda/encoders/base94_encoder.py +4 -2
- rtty_soda/encoders/encoder.py +13 -0
- rtty_soda/encoders/functions.py +3 -1
- rtty_soda/encoders/raw_encoder.py +15 -0
- rtty_soda/main.py +226 -101
- rtty_soda/main.pyi +45 -4
- rtty_soda-0.2.1.dist-info/METADATA +332 -0
- rtty_soda-0.2.1.dist-info/RECORD +23 -0
- {rtty_soda-0.1.6.dist-info → rtty_soda-0.2.1.dist-info}/WHEEL +1 -1
- rtty_soda-0.1.6.dist-info/METADATA +0 -254
- rtty_soda-0.1.6.dist-info/RECORD +0 -19
- {rtty_soda-0.1.6.dist-info → rtty_soda-0.2.1.dist-info}/entry_points.txt +0 -0
rtty_soda/archivers.py
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import bz2
|
|
2
|
-
import lzma
|
|
3
|
-
import zlib
|
|
4
1
|
from collections.abc import Callable
|
|
2
|
+
from compression import bz2, lzma, zlib, zstd
|
|
5
3
|
|
|
6
4
|
__all__ = ["ARCHIVERS", "UNARCHIVERS", "Archiver"]
|
|
7
5
|
|
|
@@ -9,6 +7,10 @@ __all__ = ["ARCHIVERS", "UNARCHIVERS", "Archiver"]
|
|
|
9
7
|
type Archiver = Callable[[bytes], bytes]
|
|
10
8
|
|
|
11
9
|
|
|
10
|
+
def compress_zstd(data: bytes) -> bytes:
|
|
11
|
+
return zstd.compress(data, level=20)
|
|
12
|
+
|
|
13
|
+
|
|
12
14
|
def compress_zlib(data: bytes) -> bytes:
|
|
13
15
|
return zlib.compress(data, level=9)
|
|
14
16
|
|
|
@@ -26,6 +28,10 @@ def compress_lzma(data: bytes) -> bytes:
|
|
|
26
28
|
)
|
|
27
29
|
|
|
28
30
|
|
|
31
|
+
def decompress_zstd(data: bytes) -> bytes:
|
|
32
|
+
return zstd.decompress(data)
|
|
33
|
+
|
|
34
|
+
|
|
29
35
|
def decompress_zlib(data: bytes) -> bytes:
|
|
30
36
|
return zlib.decompress(data)
|
|
31
37
|
|
|
@@ -43,6 +49,7 @@ def noop(data: bytes) -> bytes:
|
|
|
43
49
|
|
|
44
50
|
|
|
45
51
|
ARCHIVERS: dict[str, Archiver] = {
|
|
52
|
+
"zstd": compress_zstd,
|
|
46
53
|
"zlib": compress_zlib,
|
|
47
54
|
"bz2": compress_bz2,
|
|
48
55
|
"lzma": compress_lzma,
|
|
@@ -50,6 +57,7 @@ ARCHIVERS: dict[str, Archiver] = {
|
|
|
50
57
|
}
|
|
51
58
|
|
|
52
59
|
UNARCHIVERS: dict[str, Archiver] = {
|
|
60
|
+
"zstd": decompress_zstd,
|
|
53
61
|
"zlib": decompress_zlib,
|
|
54
62
|
"bz2": decompress_bz2,
|
|
55
63
|
"lzma": decompress_lzma,
|
rtty_soda/cli_io.py
CHANGED
|
@@ -1,21 +1,26 @@
|
|
|
1
1
|
import random
|
|
2
2
|
import re
|
|
3
3
|
import string
|
|
4
|
-
from
|
|
5
|
-
|
|
4
|
+
from typing import TYPE_CHECKING, TextIO, cast
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from pathlib import Path
|
|
6
8
|
|
|
7
9
|
import click
|
|
8
10
|
|
|
9
|
-
from rtty_soda.encoders import Encoder,
|
|
11
|
+
from rtty_soda.encoders import Encoder, decode_bytes, encode_str
|
|
10
12
|
|
|
11
13
|
__all__ = [
|
|
14
|
+
"format_output",
|
|
15
|
+
"pad_newlines",
|
|
12
16
|
"print_stats",
|
|
13
17
|
"read_bytes",
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
18
|
+
"read_encoded_stripped",
|
|
19
|
+
"read_key_bytes",
|
|
20
|
+
"read_password_bytes",
|
|
17
21
|
"read_str",
|
|
18
22
|
"remove_whitespace",
|
|
23
|
+
"split_groups",
|
|
19
24
|
"write_bytes_atomic",
|
|
20
25
|
"write_output",
|
|
21
26
|
]
|
|
@@ -23,35 +28,33 @@ __all__ = [
|
|
|
23
28
|
|
|
24
29
|
def read_str(source: Path) -> str:
|
|
25
30
|
with click.open_file(source, mode="rt", encoding="utf-8", errors="strict") as fd:
|
|
26
|
-
return cast("TextIO", fd).read()
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
def read_bytes(source: Path) -> bytes:
|
|
30
|
-
return encode_str(read_str(source))
|
|
31
|
+
return cast("TextIO", fd).read()
|
|
31
32
|
|
|
32
33
|
|
|
33
34
|
def remove_whitespace(data: str) -> str:
|
|
34
35
|
return re.sub(r"\s", "", data)
|
|
35
36
|
|
|
36
37
|
|
|
37
|
-
def
|
|
38
|
+
def read_encoded_stripped(source: Path) -> bytes:
|
|
38
39
|
data = read_str(source)
|
|
39
40
|
data = remove_whitespace(data)
|
|
40
41
|
return encode_str(data)
|
|
41
42
|
|
|
42
43
|
|
|
43
|
-
def
|
|
44
|
-
if
|
|
44
|
+
def read_bytes(source: Path, encoder: Encoder) -> bytes:
|
|
45
|
+
if encoder.is_binary:
|
|
45
46
|
return source.read_bytes()
|
|
46
47
|
|
|
47
|
-
return
|
|
48
|
+
return read_encoded_stripped(source)
|
|
48
49
|
|
|
49
50
|
|
|
50
|
-
def
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
def read_key_bytes(source: Path, encoder: Encoder) -> bytes:
|
|
52
|
+
key = read_bytes(source, encoder)
|
|
53
|
+
return encoder.decode(key)
|
|
54
|
+
|
|
53
55
|
|
|
54
|
-
|
|
56
|
+
def read_password_bytes(source: Path) -> bytes:
|
|
57
|
+
return encode_str(read_str(source).strip())
|
|
55
58
|
|
|
56
59
|
|
|
57
60
|
def write_bytes_atomic(target: Path, data: bytes) -> None:
|
|
@@ -61,16 +64,47 @@ def write_bytes_atomic(target: Path, data: bytes) -> None:
|
|
|
61
64
|
temp_path.replace(target)
|
|
62
65
|
|
|
63
66
|
|
|
64
|
-
def
|
|
65
|
-
if
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
def split_groups(data: str, group_len: int, line_len: int) -> str:
|
|
68
|
+
step = group_len if group_len > 0 else line_len - 1
|
|
69
|
+
groups = (data[i : i + step] for i in range(0, len(data), step))
|
|
70
|
+
result: list[str] = []
|
|
71
|
+
line: list[str] = []
|
|
72
|
+
i = 0
|
|
73
|
+
gpl = line_len // (step + 1)
|
|
74
|
+
for group in groups:
|
|
75
|
+
line.append(group)
|
|
76
|
+
i += 1
|
|
77
|
+
if i == gpl:
|
|
78
|
+
result.append(" ".join(line))
|
|
79
|
+
i = 0
|
|
80
|
+
line = []
|
|
81
|
+
|
|
82
|
+
if line:
|
|
83
|
+
result.append(" ".join(line))
|
|
70
84
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
85
|
+
return "\n".join(result)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def pad_newlines(data: str, count: int) -> str:
|
|
89
|
+
padding = "\n" * count
|
|
90
|
+
return padding + data.strip() + "\n" + padding
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def format_output(data: bytes, group_len: int, line_len: int, padding: int) -> bytes:
|
|
94
|
+
text = decode_bytes(data)
|
|
95
|
+
if group_len > 0 or line_len > 0:
|
|
96
|
+
text = split_groups(text, group_len, line_len)
|
|
97
|
+
|
|
98
|
+
if padding > 0:
|
|
99
|
+
text = pad_newlines(text, padding)
|
|
100
|
+
|
|
101
|
+
return encode_str(text)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def write_output(target: Path | None, data: bytes) -> None:
|
|
105
|
+
if target is None or target.stem == "-":
|
|
106
|
+
add_nl = not data.endswith(b"\n")
|
|
107
|
+
click.echo(data, nl=add_nl)
|
|
74
108
|
else:
|
|
75
109
|
if target.exists():
|
|
76
110
|
click.confirm(
|
rtty_soda/cryptography/kdf.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from nacl.encoding import RawEncoder
|
|
1
2
|
from nacl.hash import blake2b
|
|
2
3
|
from nacl.public import PrivateKey
|
|
3
4
|
from nacl.pwhash import argon2id
|
|
@@ -11,8 +12,6 @@ from nacl.pwhash.argon2id import (
|
|
|
11
12
|
SALTBYTES,
|
|
12
13
|
)
|
|
13
14
|
|
|
14
|
-
from rtty_soda.encoders import Encoder, RawEncoder
|
|
15
|
-
|
|
16
15
|
__all__ = ["KDF_PROFILES", "KdfProfile", "hash_salt", "kdf"]
|
|
17
16
|
|
|
18
17
|
type KdfProfile = tuple[int, int]
|
|
@@ -34,9 +33,17 @@ certainty;
|
|
|
34
33
|
|
|
35
34
|
|
|
36
35
|
def hash_salt(salt: bytes) -> bytes:
|
|
37
|
-
return blake2b(salt, digest_size=SALTBYTES, encoder=RawEncoder)
|
|
36
|
+
return blake2b(data=salt, digest_size=SALTBYTES, encoder=RawEncoder)
|
|
38
37
|
|
|
39
38
|
|
|
40
|
-
def kdf(password: bytes, profile: KdfProfile
|
|
39
|
+
def kdf(password: bytes, profile: KdfProfile) -> bytes:
|
|
41
40
|
salt = hash_salt(password + SALT_MOD)
|
|
42
|
-
|
|
41
|
+
ops, mem = profile
|
|
42
|
+
return argon2id.kdf(
|
|
43
|
+
size=PrivateKey.SIZE,
|
|
44
|
+
password=password,
|
|
45
|
+
salt=salt,
|
|
46
|
+
opslimit=ops,
|
|
47
|
+
memlimit=mem,
|
|
48
|
+
encoder=RawEncoder,
|
|
49
|
+
)
|
rtty_soda/cryptography/public.py
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING
|
|
2
|
+
|
|
3
|
+
from nacl.encoding import RawEncoder
|
|
1
4
|
from nacl.public import Box, PrivateKey, PublicKey
|
|
2
|
-
from nacl.utils import EncryptedMessage
|
|
3
5
|
|
|
4
|
-
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from nacl.utils import EncryptedMessage
|
|
8
|
+
|
|
5
9
|
|
|
6
10
|
__all__ = ["decrypt", "encrypt"]
|
|
7
11
|
|
|
8
12
|
|
|
9
|
-
def encrypt(
|
|
10
|
-
private
|
|
11
|
-
|
|
12
|
-
box = Box(private, public)
|
|
13
|
-
return box.encrypt(data, encoder=out_enc)
|
|
13
|
+
def encrypt(private: PrivateKey, public: PublicKey, data: bytes) -> EncryptedMessage:
|
|
14
|
+
box = Box(private_key=private, public_key=public)
|
|
15
|
+
return box.encrypt(plaintext=data, encoder=RawEncoder)
|
|
14
16
|
|
|
15
17
|
|
|
16
|
-
def decrypt(
|
|
17
|
-
private
|
|
18
|
-
|
|
19
|
-
box = Box(private, public)
|
|
20
|
-
return box.decrypt(data, encoder=in_enc)
|
|
18
|
+
def decrypt(private: PrivateKey, public: PublicKey, data: bytes) -> bytes:
|
|
19
|
+
box = Box(private_key=private, public_key=public)
|
|
20
|
+
return box.decrypt(ciphertext=data, encoder=RawEncoder)
|
rtty_soda/cryptography/secret.py
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
|
-
from
|
|
1
|
+
from typing import TYPE_CHECKING
|
|
2
|
+
|
|
3
|
+
from nacl.encoding import RawEncoder
|
|
2
4
|
from nacl.secret import SecretBox
|
|
3
|
-
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from nacl.utils import EncryptedMessage
|
|
8
|
+
|
|
4
9
|
|
|
5
10
|
__all__ = ["decrypt", "encrypt"]
|
|
6
11
|
|
|
7
12
|
|
|
8
|
-
def encrypt(
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
box = SecretBox(key, key_enc)
|
|
12
|
-
return box.encrypt(data, encoder=out_enc)
|
|
13
|
+
def encrypt(key: bytes, data: bytes) -> EncryptedMessage:
|
|
14
|
+
box = SecretBox(key=key, encoder=RawEncoder)
|
|
15
|
+
return box.encrypt(plaintext=data, encoder=RawEncoder)
|
|
13
16
|
|
|
14
17
|
|
|
15
|
-
def decrypt(key: bytes, data: bytes
|
|
16
|
-
box = SecretBox(key,
|
|
17
|
-
return box.decrypt(data, encoder=
|
|
18
|
+
def decrypt(key: bytes, data: bytes) -> bytes:
|
|
19
|
+
box = SecretBox(key=key, encoder=RawEncoder)
|
|
20
|
+
return box.decrypt(ciphertext=data, encoder=RawEncoder)
|
rtty_soda/encoders/__init__.py
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
from nacl.encoding import Base64Encoder, Encoder, RawEncoder
|
|
2
|
-
|
|
3
1
|
from .base26_encoder import Base26Encoder
|
|
2
|
+
from .base31_encoder import Base31Encoder
|
|
4
3
|
from .base36_encoder import Base36Encoder
|
|
4
|
+
from .base64_encoder import Base64Encoder
|
|
5
5
|
from .base94_encoder import Base94Encoder
|
|
6
|
+
from .encoder import Encoder
|
|
6
7
|
from .functions import decode_bytes, encode_str
|
|
8
|
+
from .raw_encoder import RawEncoder
|
|
7
9
|
|
|
8
10
|
__all__ = [
|
|
9
11
|
"ENCODERS",
|
|
10
12
|
"Base26Encoder",
|
|
13
|
+
"Base31Encoder",
|
|
11
14
|
"Base36Encoder",
|
|
12
15
|
"Base64Encoder",
|
|
13
16
|
"Base94Encoder",
|
|
@@ -19,6 +22,7 @@ __all__ = [
|
|
|
19
22
|
|
|
20
23
|
ENCODERS: dict[str, Encoder] = {
|
|
21
24
|
"base26": Base26Encoder,
|
|
25
|
+
"base31": Base31Encoder,
|
|
22
26
|
"base36": Base36Encoder,
|
|
23
27
|
"base64": Base64Encoder,
|
|
24
28
|
"base94": Base94Encoder,
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import string
|
|
2
|
-
|
|
3
|
-
from nacl.encoding import _Encoder as EncoderABC # pyright: ignore [reportPrivateUsage]
|
|
2
|
+
from typing import ClassVar
|
|
4
3
|
|
|
5
4
|
from .functions import base_to_bytes, bytes_to_base, decode_bytes, encode_str
|
|
6
5
|
|
|
@@ -9,7 +8,9 @@ __all__ = ["ALPHABET", "Base26Encoder"]
|
|
|
9
8
|
ALPHABET = string.ascii_uppercase
|
|
10
9
|
|
|
11
10
|
|
|
12
|
-
class Base26Encoder
|
|
11
|
+
class Base26Encoder:
|
|
12
|
+
is_binary: ClassVar = False
|
|
13
|
+
|
|
13
14
|
@staticmethod
|
|
14
15
|
def encode(data: bytes) -> bytes:
|
|
15
16
|
return encode_str(bytes_to_base(data, ALPHABET))
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from typing import ClassVar
|
|
2
|
+
|
|
3
|
+
from .functions import base_to_bytes, bytes_to_base, decode_bytes, encode_str
|
|
4
|
+
|
|
5
|
+
__all__ = ["ALPHABET", "Base31Encoder"]
|
|
6
|
+
|
|
7
|
+
ALPHABET = "АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЬЫЭЮЯ"
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Base31Encoder:
|
|
11
|
+
is_binary: ClassVar = False
|
|
12
|
+
|
|
13
|
+
@staticmethod
|
|
14
|
+
def encode(data: bytes) -> bytes:
|
|
15
|
+
return encode_str(bytes_to_base(data, ALPHABET))
|
|
16
|
+
|
|
17
|
+
@staticmethod
|
|
18
|
+
def decode(data: bytes) -> bytes:
|
|
19
|
+
return base_to_bytes(decode_bytes(data), ALPHABET)
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import string
|
|
2
|
-
|
|
3
|
-
from nacl.encoding import _Encoder as EncoderABC # pyright: ignore [reportPrivateUsage]
|
|
2
|
+
from typing import ClassVar
|
|
4
3
|
|
|
5
4
|
from .functions import base_to_bytes, bytes_to_base, decode_bytes, encode_str
|
|
6
5
|
|
|
@@ -9,7 +8,9 @@ __all__ = ["ALPHABET", "Base36Encoder"]
|
|
|
9
8
|
ALPHABET = string.digits + string.ascii_uppercase
|
|
10
9
|
|
|
11
10
|
|
|
12
|
-
class Base36Encoder
|
|
11
|
+
class Base36Encoder:
|
|
12
|
+
is_binary: ClassVar = False
|
|
13
|
+
|
|
13
14
|
@staticmethod
|
|
14
15
|
def encode(data: bytes) -> bytes:
|
|
15
16
|
return encode_str(bytes_to_base(data, ALPHABET))
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
from typing import ClassVar
|
|
3
|
+
|
|
4
|
+
__all__ = ["Base64Encoder"]
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Base64Encoder:
|
|
8
|
+
is_binary: ClassVar = False
|
|
9
|
+
|
|
10
|
+
@staticmethod
|
|
11
|
+
def encode(data: bytes) -> bytes:
|
|
12
|
+
return base64.b64encode(data)
|
|
13
|
+
|
|
14
|
+
@staticmethod
|
|
15
|
+
def decode(data: bytes) -> bytes:
|
|
16
|
+
return base64.b64decode(data)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from
|
|
1
|
+
from typing import ClassVar
|
|
2
2
|
|
|
3
3
|
from .functions import base_to_bytes, bytes_to_base, decode_bytes, encode_str
|
|
4
4
|
|
|
@@ -7,7 +7,9 @@ __all__ = ["ALPHABET", "Base94Encoder"]
|
|
|
7
7
|
ALPHABET = "".join([chr(i) for i in range(33, 127)])
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
class Base94Encoder
|
|
10
|
+
class Base94Encoder:
|
|
11
|
+
is_binary: ClassVar = False
|
|
12
|
+
|
|
11
13
|
@staticmethod
|
|
12
14
|
def encode(data: bytes) -> bytes:
|
|
13
15
|
return encode_str(bytes_to_base(data, ALPHABET))
|
rtty_soda/encoders/functions.py
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from typing import cast
|
|
2
|
+
|
|
1
3
|
__all__ = ["base_to_bytes", "bytes_to_base", "decode_bytes", "encode_str"]
|
|
2
4
|
|
|
3
5
|
|
|
@@ -27,7 +29,7 @@ def base_to_int(source: str, alphabet: str) -> int:
|
|
|
27
29
|
number = 0
|
|
28
30
|
base = len(alphabet)
|
|
29
31
|
for index, digit in enumerate(reversed(source)):
|
|
30
|
-
number += alphabet.index(digit) * (base**index)
|
|
32
|
+
number += alphabet.index(digit) * cast("int", base**index)
|
|
31
33
|
|
|
32
34
|
return number
|
|
33
35
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from typing import ClassVar
|
|
2
|
+
|
|
3
|
+
__all__ = ["RawEncoder"]
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class RawEncoder:
|
|
7
|
+
is_binary: ClassVar = True
|
|
8
|
+
|
|
9
|
+
@staticmethod
|
|
10
|
+
def encode(data: bytes) -> bytes:
|
|
11
|
+
return data
|
|
12
|
+
|
|
13
|
+
@staticmethod
|
|
14
|
+
def decode(data: bytes) -> bytes:
|
|
15
|
+
return data
|