passphera-core 0.30.2__py3-none-any.whl → 0.31.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.
- passphera_core/entities.py +20 -74
- passphera_core/exceptions.py +0 -18
- passphera_core/utilities.py +7 -18
- {passphera_core-0.30.2.dist-info → passphera_core-0.31.0.dist-info}/METADATA +3 -3
- passphera_core-0.31.0.dist-info/RECORD +8 -0
- passphera_core/application/__init__.py +0 -0
- passphera_core/application/generator.py +0 -70
- passphera_core/application/password.py +0 -73
- passphera_core/interfaces.py +0 -43
- passphera_core-0.30.2.dist-info/RECORD +0 -12
- {passphera_core-0.30.2.dist-info → passphera_core-0.31.0.dist-info}/WHEEL +0 -0
- {passphera_core-0.30.2.dist-info → passphera_core-0.31.0.dist-info}/top_level.txt +0 -0
passphera_core/entities.py
CHANGED
@@ -1,17 +1,12 @@
|
|
1
1
|
from dataclasses import dataclass, field
|
2
2
|
from datetime import datetime, timezone
|
3
|
-
from uuid import UUID, uuid4
|
4
|
-
|
5
|
-
from cryptography.fernet import Fernet
|
6
3
|
|
7
4
|
from cipherspy.cipher import *
|
8
5
|
from cipherspy.exceptions import InvalidAlgorithmException
|
9
|
-
from cipherspy.utilities import generate_salt, derive_key
|
10
|
-
|
11
|
-
from passphera_core.exceptions import InvalidPropertyNameException
|
12
6
|
|
7
|
+
from passphera_core.utilities import check_property_name
|
13
8
|
|
14
|
-
_cipher_registry: dict
|
9
|
+
_cipher_registry: dict = {
|
15
10
|
'caesar': CaesarCipherAlgorithm,
|
16
11
|
'affine': AffineCipherAlgorithm,
|
17
12
|
'playfair': PlayfairCipherAlgorithm,
|
@@ -27,63 +22,8 @@ _default_properties: dict[str, str] = {
|
|
27
22
|
}
|
28
23
|
|
29
24
|
|
30
|
-
@dataclass
|
31
|
-
class Password:
|
32
|
-
id: UUID = field(default_factory=uuid4)
|
33
|
-
created_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc).isoformat())
|
34
|
-
updated_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc).isoformat())
|
35
|
-
context: str = field(default_factory=str)
|
36
|
-
text: str = field(default_factory=str)
|
37
|
-
password: str = field(default_factory=str)
|
38
|
-
salt: bytes = field(default_factory=lambda: bytes)
|
39
|
-
|
40
|
-
def encrypt(self) -> None:
|
41
|
-
"""
|
42
|
-
Encrypts the password using Fernet symmetric encryption.
|
43
|
-
|
44
|
-
This method generates a new salt, derives an encryption key using the password
|
45
|
-
and salt, and then encrypts the password using Fernet encryption. The encrypted
|
46
|
-
password is stored back in the password field as a base64-encoded string.
|
47
|
-
:return: None
|
48
|
-
"""
|
49
|
-
self.salt = generate_salt()
|
50
|
-
key = derive_key(self.password, self.salt)
|
51
|
-
self.password = Fernet(key).encrypt(self.password.encode()).decode()
|
52
|
-
|
53
|
-
def decrypt(self) -> str:
|
54
|
-
"""
|
55
|
-
Decrypts the encrypted password using Fernet symmetric decryption.
|
56
|
-
|
57
|
-
This method uses the stored salt to derive the encryption key and then
|
58
|
-
decrypts the stored encrypted password using Fernet decryption.
|
59
|
-
:return: str: The decrypted original password
|
60
|
-
"""
|
61
|
-
key = derive_key(self.password, self.salt)
|
62
|
-
return Fernet(key).decrypt(self.password.encode()).decode()
|
63
|
-
|
64
|
-
def to_dict(self) -> dict:
|
65
|
-
"""Convert the Password entity to a dictionary."""
|
66
|
-
return {
|
67
|
-
"id": self.id,
|
68
|
-
"created_at": self.created_at,
|
69
|
-
"updated_at": self.updated_at,
|
70
|
-
"context": self.context,
|
71
|
-
"text": self.text,
|
72
|
-
"password": self.password,
|
73
|
-
"salt": self.salt,
|
74
|
-
}
|
75
|
-
|
76
|
-
def from_dict(self, data: dict) -> None:
|
77
|
-
"""Convert a dictionary to a Password entity."""
|
78
|
-
for key, value in data.items():
|
79
|
-
setattr(self, key, value)
|
80
|
-
|
81
|
-
|
82
25
|
@dataclass
|
83
26
|
class Generator:
|
84
|
-
id: UUID = field(default_factory=uuid4)
|
85
|
-
created_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc).isoformat())
|
86
|
-
updated_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc).isoformat())
|
87
27
|
shift: int = field(default=_default_properties["shift"])
|
88
28
|
multiplier: int = field(default=_default_properties["multiplier"])
|
89
29
|
key: str = field(default=_default_properties["key"])
|
@@ -133,6 +73,17 @@ class Generator:
|
|
133
73
|
"characters_replacements": self.characters_replacements,
|
134
74
|
}
|
135
75
|
|
76
|
+
@check_property_name
|
77
|
+
def get_property(self, prop: str):
|
78
|
+
"""
|
79
|
+
Get the value of a specific generator property
|
80
|
+
:param prop: The property name to retrieve; must be one of: shift, multiplier, key, algorithm, prefix, postfix
|
81
|
+
:raises InvalidPropertyNameException: If the property name is not one of the allowed properties
|
82
|
+
:return: The value of the requested property
|
83
|
+
"""
|
84
|
+
return getattr(self, prop)
|
85
|
+
|
86
|
+
@check_property_name
|
136
87
|
def set_property(self, prop: str, value: str):
|
137
88
|
"""
|
138
89
|
Update a generator property with a new value
|
@@ -141,24 +92,21 @@ class Generator:
|
|
141
92
|
:raises ValueError: If the property name is not one of the allowed properties
|
142
93
|
:return: None
|
143
94
|
"""
|
144
|
-
if prop not in {"id", "created_at", "updated_at", "shift", "multiplier", "key", "algorithm", "prefix", "postfix"}:
|
145
|
-
raise InvalidPropertyNameException(prop)
|
146
95
|
if prop in ["shift", "multiplier"]:
|
147
96
|
value = int(value)
|
148
97
|
setattr(self, prop, value)
|
149
98
|
if prop == "algorithm":
|
150
99
|
self.get_algorithm()
|
151
100
|
self.updated_at = datetime.now(timezone.utc)
|
152
|
-
|
153
|
-
|
101
|
+
|
102
|
+
@check_property_name
|
103
|
+
def reset_property(self, prop: str) -> None:
|
154
104
|
"""
|
155
105
|
Reset a generator property to its default value
|
156
106
|
:param prop: The property name to reset, it must be one of: shift, multiplier, key, algorithm, prefix, postfix
|
157
107
|
:raises ValueError: If the property name is not one of the allowed properties
|
158
108
|
:return: None
|
159
109
|
"""
|
160
|
-
if prop not in {"id", "created_at", "updated_at", "shift", "multiplier", "key", "algorithm", "prefix", "postfix"}:
|
161
|
-
raise InvalidPropertyNameException(prop)
|
162
110
|
setattr(self, prop, _default_properties[prop])
|
163
111
|
if prop == "algorithm":
|
164
112
|
self.get_algorithm()
|
@@ -172,7 +120,7 @@ class Generator:
|
|
172
120
|
"""
|
173
121
|
return self.characters_replacements.get(character, character)
|
174
122
|
|
175
|
-
def
|
123
|
+
def set_character_replacement(self, character: str, replacement: str) -> None:
|
176
124
|
"""
|
177
125
|
Replace a character with another character or set of characters
|
178
126
|
Eg: pg.replace_character('a', '@1')
|
@@ -183,7 +131,7 @@ class Generator:
|
|
183
131
|
self.characters_replacements[character[0]] = replacement
|
184
132
|
self.updated_at = datetime.now(timezone.utc)
|
185
133
|
|
186
|
-
def
|
134
|
+
def reset_character_replacement(self, character: str) -> None:
|
187
135
|
"""
|
188
136
|
Reset a character to its original value (remove its replacement from characters_replacements)
|
189
137
|
:param character: The character to be reset to its original value
|
@@ -201,22 +149,20 @@ class Generator:
|
|
201
149
|
main_algorithm: BaseCipherAlgorithm = self.get_algorithm()
|
202
150
|
secondary_algorithm: AffineCipherAlgorithm = AffineCipherAlgorithm(self.shift, self.multiplier)
|
203
151
|
intermediate: str = secondary_algorithm.encrypt(f"{self.prefix}{text}{self.postfix}")
|
204
|
-
password: str = main_algorithm.encrypt(
|
152
|
+
password: str = main_algorithm.encrypt(intermediate)
|
205
153
|
password = password.translate(str.maketrans(self.characters_replacements))
|
206
154
|
return ''.join(c.upper() if c in text else c for c in password)
|
207
155
|
|
208
156
|
def to_dict(self) -> dict:
|
209
157
|
"""Convert the Generator entity to a dictionary."""
|
210
158
|
return {
|
211
|
-
"id": self.id,
|
212
|
-
"created_at": self.created_at,
|
213
|
-
"updated_at": self.updated_at,
|
214
159
|
"shift": self.shift,
|
215
160
|
"multiplier": self.multiplier,
|
216
161
|
"key": self.key,
|
217
162
|
"algorithm": self.algorithm,
|
218
163
|
"prefix": self.prefix,
|
219
164
|
"postfix": self.postfix,
|
165
|
+
"character_replacements": self.characters_replacements,
|
220
166
|
}
|
221
167
|
|
222
168
|
def from_dict(self, data: dict) -> None:
|
passphera_core/exceptions.py
CHANGED
@@ -1,21 +1,3 @@
|
|
1
|
-
class PasswordNotFoundException(Exception):
|
2
|
-
def __init__(self) -> None:
|
3
|
-
super().__init__("Password not found")
|
4
|
-
|
5
|
-
|
6
|
-
class DuplicatePasswordException(Exception):
|
7
|
-
def __init__(self, password) -> None:
|
8
|
-
self.password = password
|
9
|
-
message = self._build_message(password)
|
10
|
-
super().__init__(message)
|
11
|
-
|
12
|
-
@staticmethod
|
13
|
-
def _build_message(password) -> str:
|
14
|
-
if hasattr(password, 'context') and password.context:
|
15
|
-
return f"Password for context '{password.context}' already exists"
|
16
|
-
return "Duplicate password detected"
|
17
|
-
|
18
|
-
|
19
1
|
class InvalidPropertyNameException(Exception):
|
20
2
|
def __init__(self, property_name: str) -> None:
|
21
3
|
self.property_name = property_name
|
passphera_core/utilities.py
CHANGED
@@ -1,20 +1,9 @@
|
|
1
|
-
from
|
1
|
+
from passphera_core.exceptions import InvalidPropertyNameException
|
2
2
|
|
3
|
-
from passphera_core.entities import Password, Generator
|
4
|
-
from passphera_core.exceptions import DuplicatePasswordException
|
5
|
-
from passphera_core.interfaces import VaultRepository
|
6
3
|
|
7
|
-
|
8
|
-
def
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
entity.encrypt()
|
14
|
-
|
15
|
-
|
16
|
-
def get_password(password_repository: VaultRepository, context: str) -> Password:
|
17
|
-
password_entity: Password = password_repository.get(context)
|
18
|
-
if password_entity:
|
19
|
-
raise DuplicatePasswordException(password_entity)
|
20
|
-
return password_entity
|
4
|
+
def check_property_name(func):
|
5
|
+
def wrapper(self, prop, value):
|
6
|
+
if prop not in {"shift", "multiplier", "key", "algorithm", "prefix", "postfix", "character_replacements"}:
|
7
|
+
raise InvalidPropertyNameException(prop)
|
8
|
+
return func(self, prop, value)
|
9
|
+
return wrapper
|
@@ -1,10 +1,10 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: passphera-core
|
3
|
-
Version: 0.
|
4
|
-
Summary: The core
|
3
|
+
Version: 0.31.0
|
4
|
+
Summary: The core of passphera project
|
5
5
|
Home-page: https://github.com/passphera/core
|
6
6
|
Author: Fathi Abdelmalek
|
7
|
-
Author-email:
|
7
|
+
Author-email: passphera@imfathi.com
|
8
8
|
Classifier: Development Status :: 4 - Beta
|
9
9
|
Classifier: License :: OSI Approved :: MIT License
|
10
10
|
Classifier: Operating System :: OS Independent
|
@@ -0,0 +1,8 @@
|
|
1
|
+
passphera_core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
+
passphera_core/entities.py,sha256=RXoSnJgLpij3zYSWN9JeybiujTz1IZgHIZh3MxW3Z58,6987
|
3
|
+
passphera_core/exceptions.py,sha256=nb0iWLaFpFHEUjCa5dQ8UnIn3tZs8gN5dy2URgqJf0g,211
|
4
|
+
passphera_core/utilities.py,sha256=O15lTSzT-kNUnPkx9Eufc_qET7uK-9cccPKzx2gHz0s,362
|
5
|
+
passphera_core-0.31.0.dist-info/METADATA,sha256=EFYOC1RNysf0UPMaYqjzNZBXdOjuHQz0b08_iLA9vVs,851
|
6
|
+
passphera_core-0.31.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
7
|
+
passphera_core-0.31.0.dist-info/top_level.txt,sha256=aDUX2iWGOyfzyf6XakLWTbgeWqNrypMHO074Qratyds,15
|
8
|
+
passphera_core-0.31.0.dist-info/RECORD,,
|
File without changes
|
@@ -1,70 +0,0 @@
|
|
1
|
-
from passphera_core.entities import Generator
|
2
|
-
from passphera_core.interfaces import GeneratorRepository
|
3
|
-
|
4
|
-
|
5
|
-
class GetGeneratorUseCase:
|
6
|
-
def __init__(self, generator_repository: GeneratorRepository):
|
7
|
-
self.generator_repository: GeneratorRepository = generator_repository
|
8
|
-
|
9
|
-
def __call__(self) -> Generator:
|
10
|
-
return self.generator_repository.get()
|
11
|
-
|
12
|
-
|
13
|
-
class GetPropertiesUseCase:
|
14
|
-
def __init__(self, generator_repository: GeneratorRepository):
|
15
|
-
self.generator_repository: GeneratorRepository = generator_repository
|
16
|
-
|
17
|
-
def __call__(self) -> dict:
|
18
|
-
return self.generator_repository.get().get_properties()
|
19
|
-
|
20
|
-
|
21
|
-
class SetPropertyUseCase:
|
22
|
-
def __init__(self, generator_repository: GeneratorRepository):
|
23
|
-
self.generator_repository: GeneratorRepository = generator_repository
|
24
|
-
|
25
|
-
def __call__(self, prop: str, value: str) -> Generator:
|
26
|
-
generator_entity: Generator = self.generator_repository.get()
|
27
|
-
generator_entity.set_property(prop, value)
|
28
|
-
self.generator_repository.update(generator_entity)
|
29
|
-
return generator_entity
|
30
|
-
|
31
|
-
|
32
|
-
class ResetPropertyUseCase:
|
33
|
-
def __init__(self, generator_repository: GeneratorRepository):
|
34
|
-
self.generator_repository: GeneratorRepository = generator_repository
|
35
|
-
|
36
|
-
def __call__(self, prop: str) -> Generator:
|
37
|
-
generator_entity: Generator = self.generator_repository.get()
|
38
|
-
generator_entity.reset_property(prop)
|
39
|
-
self.generator_repository.update(generator_entity)
|
40
|
-
return generator_entity
|
41
|
-
|
42
|
-
|
43
|
-
class GetCharacterReplacementUseCase:
|
44
|
-
def __init__(self, generator_repository: GeneratorRepository):
|
45
|
-
self.generator_repository: GeneratorRepository = generator_repository
|
46
|
-
|
47
|
-
def __call__(self, character: str) -> str:
|
48
|
-
return self.generator_repository.get().get_character_replacement(character)
|
49
|
-
|
50
|
-
|
51
|
-
class SetCharacterReplacementUseCase:
|
52
|
-
def __init__(self, generator_repository: GeneratorRepository):
|
53
|
-
self.generator_repository: GeneratorRepository = generator_repository
|
54
|
-
|
55
|
-
def __call__(self, character: str, replacement: str) -> Generator:
|
56
|
-
generator_entity: Generator = self.generator_repository.get()
|
57
|
-
generator_entity.replace_character(character, replacement)
|
58
|
-
self.generator_repository.update(generator_entity)
|
59
|
-
return generator_entity
|
60
|
-
|
61
|
-
|
62
|
-
class ResetCharacterReplacementUseCase:
|
63
|
-
def __init__(self, generator_repository: GeneratorRepository,):
|
64
|
-
self.generator_repository: GeneratorRepository = generator_repository
|
65
|
-
|
66
|
-
def __call__(self, character: str) -> Generator:
|
67
|
-
generator_entity: Generator = self.generator_repository.get()
|
68
|
-
generator_entity.reset_character(character)
|
69
|
-
self.generator_repository.update(generator_entity)
|
70
|
-
return generator_entity
|
@@ -1,73 +0,0 @@
|
|
1
|
-
from passphera_core.entities import Password, Generator
|
2
|
-
from passphera_core.exceptions import DuplicatePasswordException
|
3
|
-
from passphera_core.interfaces import VaultRepository, GeneratorRepository
|
4
|
-
from passphera_core.utilities import generate_password, get_password
|
5
|
-
|
6
|
-
|
7
|
-
class GeneratePasswordUseCase:
|
8
|
-
def __init__(
|
9
|
-
self,
|
10
|
-
password_repository: VaultRepository,
|
11
|
-
generator_repository: GeneratorRepository,
|
12
|
-
):
|
13
|
-
self.password_repository: VaultRepository = password_repository
|
14
|
-
self.generator_repository: GeneratorRepository = generator_repository
|
15
|
-
|
16
|
-
def __call__(self, context: str, text: str) -> Password:
|
17
|
-
password_entity: Password = self.password_repository.get(context)
|
18
|
-
if password_entity:
|
19
|
-
raise DuplicatePasswordException(password_entity)
|
20
|
-
password_entity: Password = Password(context=context, text=text)
|
21
|
-
generator_entity: Generator = self.generator_repository.get()
|
22
|
-
generate_password(password_entity, generator_entity)
|
23
|
-
self.password_repository.save(password_entity)
|
24
|
-
return password_entity
|
25
|
-
|
26
|
-
|
27
|
-
class GetPasswordUseCase:
|
28
|
-
def __init__(self, password_repository: VaultRepository):
|
29
|
-
self.password_repository: VaultRepository = password_repository
|
30
|
-
|
31
|
-
def __call__(self, context: str) -> Password:
|
32
|
-
return get_password(self.password_repository, context)
|
33
|
-
|
34
|
-
|
35
|
-
class UpdatePasswordUseCase:
|
36
|
-
def __init__(
|
37
|
-
self,
|
38
|
-
password_repository: VaultRepository,
|
39
|
-
generator_repository: GeneratorRepository,
|
40
|
-
):
|
41
|
-
self.password_repository: VaultRepository = password_repository
|
42
|
-
self.generator_repository: GeneratorRepository = generator_repository
|
43
|
-
|
44
|
-
def __call__(self, context: str, text: str) -> Password:
|
45
|
-
password_entity: Password = get_password(self.password_repository, context)
|
46
|
-
generator_entity: Generator = self.generator_repository.get()
|
47
|
-
generate_password(password_entity, generator_entity)
|
48
|
-
self.password_repository.update(password_entity)
|
49
|
-
return password_entity
|
50
|
-
|
51
|
-
|
52
|
-
class DeletePasswordUseCase:
|
53
|
-
def __init__(self, password_repository: VaultRepository):
|
54
|
-
self.password_repository: VaultRepository = password_repository
|
55
|
-
|
56
|
-
def __call__(self, context: str) -> None:
|
57
|
-
self.password_repository.delete(get_password(self.password_repository, context))
|
58
|
-
|
59
|
-
|
60
|
-
class ListPasswordsUseCase:
|
61
|
-
def __init__(self, password_repository: VaultRepository):
|
62
|
-
self.password_repository: VaultRepository = password_repository
|
63
|
-
|
64
|
-
def __call__(self) -> list[Password]:
|
65
|
-
return self.password_repository.list()
|
66
|
-
|
67
|
-
|
68
|
-
class FlushPasswordsUseCase:
|
69
|
-
def __init__(self, password_repository: VaultRepository):
|
70
|
-
self.password_repository: VaultRepository = password_repository
|
71
|
-
|
72
|
-
def __call__(self) -> None:
|
73
|
-
self.password_repository.flush()
|
passphera_core/interfaces.py
DELETED
@@ -1,43 +0,0 @@
|
|
1
|
-
from abc import ABC, abstractmethod
|
2
|
-
|
3
|
-
from passphera_core.entities import Password, Generator
|
4
|
-
|
5
|
-
|
6
|
-
class VaultRepository(ABC):
|
7
|
-
@abstractmethod
|
8
|
-
def save(self, password: Password) -> None:
|
9
|
-
pass
|
10
|
-
|
11
|
-
@abstractmethod
|
12
|
-
def get(self, context: str) -> Password:
|
13
|
-
pass
|
14
|
-
|
15
|
-
@abstractmethod
|
16
|
-
def update(self, password: Password) -> None:
|
17
|
-
pass
|
18
|
-
|
19
|
-
@abstractmethod
|
20
|
-
def delete(self, password: Password) -> None:
|
21
|
-
pass
|
22
|
-
|
23
|
-
@abstractmethod
|
24
|
-
def list(self) -> list[Password]:
|
25
|
-
pass
|
26
|
-
|
27
|
-
@abstractmethod
|
28
|
-
def flush(self) -> None:
|
29
|
-
pass
|
30
|
-
|
31
|
-
|
32
|
-
class GeneratorRepository(ABC):
|
33
|
-
@abstractmethod
|
34
|
-
def save(self, generator: Generator) -> None:
|
35
|
-
pass
|
36
|
-
|
37
|
-
@abstractmethod
|
38
|
-
def get(self) -> Generator:
|
39
|
-
pass
|
40
|
-
|
41
|
-
@abstractmethod
|
42
|
-
def update(self, generator: Generator) -> None:
|
43
|
-
pass
|
@@ -1,12 +0,0 @@
|
|
1
|
-
passphera_core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
-
passphera_core/entities.py,sha256=sZYUQC7yGwsQ4ughai_QG_-TN-sVEMCpaBi8SJ0uyts,9321
|
3
|
-
passphera_core/exceptions.py,sha256=Tqb-FKJ1_JfX5gSC8Wc0CP84AhwouvnP2gkg83xAlUY,786
|
4
|
-
passphera_core/interfaces.py,sha256=DpHFh_vnamORf69P1dwLrZ8AYZPcYIol0Lq_VKRBkXc,855
|
5
|
-
passphera_core/utilities.py,sha256=n7cAVox-yGd60595RjLvrGKSGqFQRm279YqKS3-R1X0,748
|
6
|
-
passphera_core/application/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
7
|
-
passphera_core/application/generator.py,sha256=hBSk6vktJ2KPxzKSRnH_WVnCvg7vOHVzN-TQ5GdgXEQ,2769
|
8
|
-
passphera_core/application/password.py,sha256=9wsSz3uMWEZCgfnX5V7WYiWp2OqjSmsn6OSWK4HIIfo,2876
|
9
|
-
passphera_core-0.30.2.dist-info/METADATA,sha256=5-jCeM8j_Yx0Q0EaWtc_knE22pK78rv7o9xIRc5Szc4,868
|
10
|
-
passphera_core-0.30.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
11
|
-
passphera_core-0.30.2.dist-info/top_level.txt,sha256=aDUX2iWGOyfzyf6XakLWTbgeWqNrypMHO074Qratyds,15
|
12
|
-
passphera_core-0.30.2.dist-info/RECORD,,
|
File without changes
|
File without changes
|