dictature 0.9.1__py3-none-any.whl → 0.9.3__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.
@@ -71,7 +71,8 @@ class DictatureTableDirectory(DictatureTableMock):
71
71
  def _filename_encode(name: str, suffix: str = '.txt') -> str:
72
72
  if name == sub(r'[^\w_. -]', '_', name):
73
73
  return f"d_{name}{suffix}"
74
- return f'e_{name.encode('utf-8').hex()}{suffix}'
74
+ name = name.encode('utf-8').hex()
75
+ return f'e_{name}{suffix}'
75
76
 
76
77
  @staticmethod
77
78
  def _filename_decode(name: str, suffix: str = '.txt') -> str:
dictature/dictature.py CHANGED
@@ -15,11 +15,13 @@ class Dictature:
15
15
  backend: DictatureBackendMock,
16
16
  name_transformer: MockTransformer = PassthroughTransformer(),
17
17
  value_transformer: MockTransformer = PassthroughTransformer(),
18
+ table_name_transformer: Optional[MockTransformer] = None,
18
19
  ) -> None:
19
20
  self.__backend = backend
20
21
  self.__table_cache: Dict[str, "DictatureTable"] = {}
21
22
  self.__name_transformer = name_transformer
22
23
  self.__value_transformer = value_transformer
24
+ self.__table_name_transformer = table_name_transformer or name_transformer
23
25
 
24
26
  def keys(self) -> Set[str]:
25
27
  return set(map(self.__name_transformer.backward, self.__backend.keys()))
@@ -70,7 +72,7 @@ class DictatureTable:
70
72
  self.__backend = backend
71
73
  self.__name_transformer = name_transformer
72
74
  self.__value_transformer = value_transformer
73
- self.__table = self.__backend.table(self.__name_transformer.forward(table_name))
75
+ self.__table = self.__backend.table(self.__table_key(table_name))
74
76
  self.__table_created = False
75
77
 
76
78
  def get(self, item: str, default: Optional[Any] = None) -> Any:
@@ -106,16 +108,15 @@ class DictatureTable:
106
108
 
107
109
  def __getitem__(self, item: str) -> Any:
108
110
  self.__create_table()
109
- saved_value = self.__table.get(self.__name_transformer.forward(item))
111
+ saved_value = self.__table.get(self.__item_key(item))
110
112
  mode = ValueMode(saved_value.mode)
111
113
  value = self.__value_transformer.backward(saved_value.value)
112
- match mode:
113
- case ValueMode.string:
114
- return value
115
- case ValueMode.json:
116
- return json.loads(value)
117
- case ValueMode.pickle:
118
- return pickle.loads(decompress(b64decode(value.encode('ascii'))))
114
+ if mode == ValueMode.string:
115
+ return value
116
+ elif mode == ValueMode.json:
117
+ return json.loads(value)
118
+ elif mode == ValueMode.pickle:
119
+ return pickle.loads(decompress(b64decode(value.encode('ascii'))))
119
120
  raise ValueError(f"Unknown mode '{mode}'")
120
121
 
121
122
  def __setitem__(self, key: str, value: Any) -> None:
@@ -130,12 +131,12 @@ class DictatureTable:
130
131
  value = b64encode(compress(pickle.dumps(value))).decode('ascii')
131
132
  value_mode = value_mode.pickle
132
133
 
133
- key = self.__name_transformer.forward(key)
134
+ key = self.__item_key(key)
134
135
  value = self.__value_transformer.forward(value)
135
136
  self.__table.set(key, Value(value=value, mode=value_mode.value))
136
137
 
137
138
  def __delitem__(self, key: str) -> None:
138
- self.__table.delete(self.__name_transformer.forward(key))
139
+ self.__table.delete(self.__item_key(key))
139
140
 
140
141
  def __contains__(self, item: str):
141
142
  return item in self.keys()
@@ -148,3 +149,17 @@ class DictatureTable:
148
149
  return
149
150
  self.__table.create()
150
151
  self.__table_created = True
152
+
153
+ def __item_key(self, item: str) -> str:
154
+ if not self.__name_transformer.static:
155
+ for key in self.__table.keys():
156
+ if self.__name_transformer.backward(key) == item:
157
+ return key
158
+ return self.__name_transformer.forward(item)
159
+
160
+ def __table_key(self, table_name: str) -> str:
161
+ if not self.__name_transformer.static:
162
+ for key in self.__backend.keys():
163
+ if self.__name_transformer.backward(key) == table_name:
164
+ return key
165
+ return self.__name_transformer.forward(table_name)
@@ -1,2 +1,3 @@
1
1
  from .mock import MockTransformer
2
2
  from .passthrough import PassthroughTransformer
3
+ from .pipeline import PipelineTransformer
@@ -12,9 +12,10 @@ class AESTransformer(MockTransformer):
12
12
  def __init__(self, passphrase: str, static_names_mode: bool, salt: str = 'dictature') -> None:
13
13
  self.__key = scrypt(passphrase, salt, 16, N=2 ** 14, r=8, p=1)
14
14
  self.__mode = AES.MODE_GCM if not static_names_mode else AES.MODE_ECB
15
+ self.__static = static_names_mode
15
16
 
16
17
  def forward(self, text: str) -> str:
17
- cipher = self.__cipher
18
+ cipher = self.__cipher()
18
19
  if self.__mode == AES.MODE_GCM:
19
20
  ciphertext, tag = cipher.encrypt_and_digest(pad(text.encode('utf8'), AES.block_size))
20
21
  return (cipher.nonce + tag + ciphertext).hex()
@@ -23,16 +24,16 @@ class AESTransformer(MockTransformer):
23
24
 
24
25
  def backward(self, text: str) -> str:
25
26
  data = bytes.fromhex(text)
26
- cipher = self.__cipher
27
27
  if self.__mode == AES.MODE_GCM:
28
28
  nonce, tag, ciphertext = data[:16], data[16:32], data[32:]
29
- # noinspection PyTypeChecker
30
- cipher = AES.new(self.__key, self.__mode, nonce=nonce)
31
- return unpad(cipher.decrypt_and_verify(ciphertext, tag), AES.block_size).decode('utf8')
29
+ return unpad(self.__cipher(nonce=nonce).decrypt_and_verify(ciphertext, tag), AES.block_size).decode('utf8')
32
30
  else:
33
- return unpad(cipher.decrypt(data), AES.block_size).decode('utf8')
31
+ return unpad(self.__cipher().decrypt(data), AES.block_size).decode('utf8')
34
32
 
35
- @property
36
- def __cipher(self) -> AES:
33
+ def __cipher(self, **kwargs) -> AES:
37
34
  # noinspection PyTypeChecker
38
- return AES.new(self.__key, self.__mode)
35
+ return AES.new(self.__key, self.__mode, **kwargs)
36
+
37
+ @property
38
+ def static(self) -> bool:
39
+ return self.__static
@@ -0,0 +1,24 @@
1
+ import hmac
2
+ from hashlib import sha256
3
+ from .mock import MockTransformer
4
+
5
+
6
+ class HmacTransformer(MockTransformer):
7
+ def __init__(self, secret: str = 'dictature') -> None:
8
+ self.__secret = secret
9
+
10
+ def forward(self, text: str) -> str:
11
+ return f"{self.__hmac(text)}-{text}"
12
+
13
+ def backward(self, text: str) -> str:
14
+ mac, text = text.split('-', 1)
15
+ if mac != self.__hmac(text):
16
+ raise ValueError('Invalid HMAC')
17
+ return text
18
+
19
+ def __hmac(self, text: str) -> str:
20
+ return hmac.new(self.__secret.encode('utf8'), text.encode('utf8'), sha256).hexdigest()
21
+
22
+ @property
23
+ def static(self) -> bool:
24
+ return True
@@ -4,3 +4,6 @@ class MockTransformer:
4
4
  raise NotImplementedError("This method should be implemented by the child class")
5
5
  def backward(self, text: str) -> str:
6
6
  raise NotImplementedError("This method should be implemented by the child class")
7
+ @property
8
+ def static(self) -> bool:
9
+ raise NotImplementedError("This method should be implemented by the child class")
@@ -5,3 +5,6 @@ class PassthroughTransformer(MockTransformer):
5
5
  return text
6
6
  def backward(self, text: str) -> str:
7
7
  return text
8
+ @property
9
+ def static(self) -> bool:
10
+ return True
@@ -0,0 +1,22 @@
1
+ from typing import List
2
+
3
+ from .mock import MockTransformer
4
+
5
+
6
+ class PipelineTransformer(MockTransformer):
7
+ def __init__(self, transformers: List[MockTransformer]) -> None:
8
+ self.__transformers = transformers
9
+
10
+ def forward(self, text: str) -> str:
11
+ for transformer in self.__transformers:
12
+ text = transformer.forward(text)
13
+ return text
14
+
15
+ def backward(self, text: str) -> str:
16
+ for transformer in reversed(self.__transformers):
17
+ text = transformer.backward(text)
18
+ return text
19
+
20
+ @property
21
+ def static(self) -> bool:
22
+ return all(t.static for t in self.__transformers)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dictature
3
- Version: 0.9.1
3
+ Version: 0.9.3
4
4
  Summary: dictature -- A generic wrapper around dict-like interface with mulitple backends
5
5
  Author-email: Adam Hlavacek <git@adamhlavacek.com>
6
6
  Project-URL: Homepage, https://github.com/esoadamo/dictature
@@ -0,0 +1,17 @@
1
+ dictature/__init__.py,sha256=UCPJKHeyirRZ0pCYoyeat-rwXa8pDezOJ3UWCipDdyc,33
2
+ dictature/dictature.py,sha256=eFjUc5Q1DUXLNqk-UeHzFqWgCZppTsoK3TXCJ1UuCS8,5666
3
+ dictature/backend/__init__.py,sha256=d5s6QCJOUzFglVNg8Cqqx_8b61S-AOTGjEUIF6FS69U,149
4
+ dictature/backend/directory.py,sha256=KVbKS1CibXmY1NsZRWuTE0uC4DXRLOXqYEHxyHJidCc,3266
5
+ dictature/backend/mock.py,sha256=Qd7KSh-qM763Jc7biDf5xYFWdgDax30dUHh2gXWwTZE,1266
6
+ dictature/backend/sqlite.py,sha256=aExNxDtx1kiPrZn-jfCzbpV4alEXyGc6f12tuCJK1tk,5130
7
+ dictature/transformer/__init__.py,sha256=JIFJpXU6iB9hIUM8L7HL2o9Nqjm_YbMEuQBQC8ZJ6b4,124
8
+ dictature/transformer/aes.py,sha256=6H3jNkUpgWBX88BduMzbi9MDSRxMHnWmZZEIJ70BLi0,1601
9
+ dictature/transformer/hmac.py,sha256=pYw6ybUIMoNdU2JFI9ffePr-33ails-CN9J6rFt7RVE,677
10
+ dictature/transformer/mock.py,sha256=osETvYZjlgos0trJy0YvXcmtNy0L6x2h2099t1aHMFc,421
11
+ dictature/transformer/passthrough.py,sha256=63hZCPQMUJa-G6ZKdv_xt2fMiMZpmPoL84PY5eb2ueE,269
12
+ dictature/transformer/pipeline.py,sha256=-2r9FxLXEnk3qpCfXC0qp0KqNC2qkpChCJYEbZAQRYM,642
13
+ dictature-0.9.3.dist-info/LICENSE,sha256=n1U9DKr8sM5EY2QHcvxSGiKTDWUT8MyXsOC79w94MT0,1072
14
+ dictature-0.9.3.dist-info/METADATA,sha256=BPA99McqtwhQxjALGLwrWvaZiqRx3XHnjYZ5tEfxYIk,2478
15
+ dictature-0.9.3.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
16
+ dictature-0.9.3.dist-info/top_level.txt,sha256=-RO39WWCF44lqiXhSUcACVqbk6SkgReZTz7ZmHKH3-U,10
17
+ dictature-0.9.3.dist-info/RECORD,,
@@ -1,15 +0,0 @@
1
- dictature/__init__.py,sha256=UCPJKHeyirRZ0pCYoyeat-rwXa8pDezOJ3UWCipDdyc,33
2
- dictature/dictature.py,sha256=-RQhAy_GNUK2oMzuS-Wk8n4yqCjxqlx_fgcQVAUNQ2k,5005
3
- dictature/backend/__init__.py,sha256=d5s6QCJOUzFglVNg8Cqqx_8b61S-AOTGjEUIF6FS69U,149
4
- dictature/backend/directory.py,sha256=u_AIJnwjytTqwdjSz7DPp5aU3qX4kJyNp8dkzupSn_0,3246
5
- dictature/backend/mock.py,sha256=Qd7KSh-qM763Jc7biDf5xYFWdgDax30dUHh2gXWwTZE,1266
6
- dictature/backend/sqlite.py,sha256=aExNxDtx1kiPrZn-jfCzbpV4alEXyGc6f12tuCJK1tk,5130
7
- dictature/transformer/__init__.py,sha256=H3-ySHD-yZz9Zin2H9P619IdQiXh1e-yma669K4V_go,82
8
- dictature/transformer/aes.py,sha256=RyvkrqOIeM7NX7QqdKIJID-jd7kuKZnC6_Lp05IfY3k,1587
9
- dictature/transformer/mock.py,sha256=p1yqlF-3igYDe_4JPZaqivOmOVTxU1xYiY16Mv73Aw8,287
10
- dictature/transformer/passthrough.py,sha256=EhYPMwPHyWyjCzFjENunsZDuR9rb-4O7GB__rRgBMBA,205
11
- dictature-0.9.1.dist-info/LICENSE,sha256=n1U9DKr8sM5EY2QHcvxSGiKTDWUT8MyXsOC79w94MT0,1072
12
- dictature-0.9.1.dist-info/METADATA,sha256=gYo1CpukwPRh97y16IPYsdJkblF_Z_nFPC6HBpZUulM,2478
13
- dictature-0.9.1.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
14
- dictature-0.9.1.dist-info/top_level.txt,sha256=-RO39WWCF44lqiXhSUcACVqbk6SkgReZTz7ZmHKH3-U,10
15
- dictature-0.9.1.dist-info/RECORD,,