p3lib 1.1.100__tar.gz → 1.1.102__tar.gz
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.
- {p3lib-1.1.100 → p3lib-1.1.102}/PKG-INFO +2 -2
- {p3lib-1.1.100 → p3lib-1.1.102}/setup.cfg +1 -1
- p3lib-1.1.102/src/p3lib/file_io.py +154 -0
- p3lib-1.1.102/src/p3lib/gnome_desktop_app.py +132 -0
- {p3lib-1.1.100 → p3lib-1.1.102}/src/p3lib.egg-info/PKG-INFO +2 -2
- {p3lib-1.1.100 → p3lib-1.1.102}/src/p3lib.egg-info/SOURCES.txt +2 -0
- {p3lib-1.1.100 → p3lib-1.1.102}/LICENSE +0 -0
- {p3lib-1.1.100 → p3lib-1.1.102}/README.md +0 -0
- {p3lib-1.1.100 → p3lib-1.1.102}/pyproject.toml +0 -0
- {p3lib-1.1.100 → p3lib-1.1.102}/src/p3lib/__init__.py +0 -0
- {p3lib-1.1.100 → p3lib-1.1.102}/src/p3lib/ate.py +0 -0
- {p3lib-1.1.100 → p3lib-1.1.102}/src/p3lib/bokeh_auth.py +0 -0
- {p3lib-1.1.100 → p3lib-1.1.102}/src/p3lib/bokeh_gui.py +0 -0
- {p3lib-1.1.100 → p3lib-1.1.102}/src/p3lib/boot_manager.py +0 -0
- {p3lib-1.1.100 → p3lib-1.1.102}/src/p3lib/conduit.py +0 -0
- {p3lib-1.1.100 → p3lib-1.1.102}/src/p3lib/database_if.py +0 -0
- {p3lib-1.1.100 → p3lib-1.1.102}/src/p3lib/helper.py +0 -0
- {p3lib-1.1.100 → p3lib-1.1.102}/src/p3lib/json_networking.py +0 -0
- {p3lib-1.1.100 → p3lib-1.1.102}/src/p3lib/mqtt_rpc.py +0 -0
- {p3lib-1.1.100 → p3lib-1.1.102}/src/p3lib/netif.py +0 -0
- {p3lib-1.1.100 → p3lib-1.1.102}/src/p3lib/netplotly.py +0 -0
- {p3lib-1.1.100 → p3lib-1.1.102}/src/p3lib/ngt.py +0 -0
- {p3lib-1.1.100 → p3lib-1.1.102}/src/p3lib/pconfig.py +0 -0
- {p3lib-1.1.100 → p3lib-1.1.102}/src/p3lib/ssh.py +0 -0
- {p3lib-1.1.100 → p3lib-1.1.102}/src/p3lib/table_plot.py +0 -0
- {p3lib-1.1.100 → p3lib-1.1.102}/src/p3lib/uio.py +0 -0
- {p3lib-1.1.100 → p3lib-1.1.102}/src/p3lib.egg-info/dependency_links.txt +0 -0
- {p3lib-1.1.100 → p3lib-1.1.102}/src/p3lib.egg-info/requires.txt +0 -0
- {p3lib-1.1.100 → p3lib-1.1.102}/src/p3lib.egg-info/top_level.txt +0 -0
- {p3lib-1.1.100 → p3lib-1.1.102}/tests/test_conduit.py +0 -0
- {p3lib-1.1.100 → p3lib-1.1.102}/tests/test_json_networking.py +0 -0
- {p3lib-1.1.100 → p3lib-1.1.102}/tests/test_netif.py +0 -0
- {p3lib-1.1.100 → p3lib-1.1.102}/tests/test_ssh.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.2
|
2
2
|
Name: p3lib
|
3
|
-
Version: 1.1.
|
3
|
+
Version: 1.1.102
|
4
4
|
Summary: A group of python modules for networking, plotting data, config storage, automating boot scripts, ssh access and user input output.
|
5
5
|
Home-page: https://github.com/pjaos/p3lib
|
6
6
|
Author: Paul Austen
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[metadata]
|
2
2
|
name = p3lib
|
3
|
-
version = 1.1.
|
3
|
+
version = 1.1.102
|
4
4
|
author = Paul Austen
|
5
5
|
author_email = pausten.os@gmail.com
|
6
6
|
description = A group of python modules for networking, plotting data, config storage, automating boot scripts, ssh access and user input output.
|
@@ -0,0 +1,154 @@
|
|
1
|
+
import json
|
2
|
+
import os
|
3
|
+
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
|
4
|
+
from cryptography.hazmat.primitives.hashes import SHA256
|
5
|
+
from cryptography.hazmat.backends import default_backend
|
6
|
+
from cryptography.fernet import Fernet
|
7
|
+
from base64 import urlsafe_b64encode
|
8
|
+
|
9
|
+
class CryptFile(object):
|
10
|
+
"""@brief Responsible for encrypting and decrypting data to/from files using a password."""
|
11
|
+
|
12
|
+
def __init__(self,
|
13
|
+
filename: str,
|
14
|
+
password: str,
|
15
|
+
add_enc_extension: bool = True,
|
16
|
+
dict_data: bool = True):
|
17
|
+
"""@brief Constructor
|
18
|
+
@param filename The filename to save the data into.
|
19
|
+
@param password The password to used encrypt data to and load encrypted data from file.
|
20
|
+
@param add_enc_extension If True then the .enc extension is added to the filename
|
21
|
+
supplied.
|
22
|
+
@param dict_data If True the data is a python dictionary."""
|
23
|
+
self._filename = filename
|
24
|
+
self._password = password
|
25
|
+
self._add_enc_extension = add_enc_extension
|
26
|
+
self._dict_data = dict_data
|
27
|
+
|
28
|
+
if not self._filename:
|
29
|
+
raise Exception("No filename defined to save data to.")
|
30
|
+
|
31
|
+
if len(self._filename) < 1:
|
32
|
+
raise Exception("No filename defined. String length = 0.")
|
33
|
+
|
34
|
+
if not self._password:
|
35
|
+
raise Exception("No password defined to encrypt/decrypt data.")
|
36
|
+
|
37
|
+
if len(self._password) < 1:
|
38
|
+
raise Exception("No password defined. String length = 0.")
|
39
|
+
|
40
|
+
self._add_extension()
|
41
|
+
|
42
|
+
def save(self,
|
43
|
+
data):
|
44
|
+
"""@brief Save the data to an encrypted file.
|
45
|
+
@param data The data to be encrypted.
|
46
|
+
"""
|
47
|
+
encrypted_data = self._encrypt_data(data)
|
48
|
+
with open(self._filename, "wb") as file:
|
49
|
+
file.write(encrypted_data)
|
50
|
+
|
51
|
+
def load(self):
|
52
|
+
"""@brief Load data from an encrypted file.
|
53
|
+
@return The decrypted data.
|
54
|
+
"""
|
55
|
+
with open(self._filename, "rb") as file:
|
56
|
+
data_bytes = file.read()
|
57
|
+
return self._decrypt_data(data_bytes)
|
58
|
+
|
59
|
+
def _decrypt_data(self, encrypted_data):
|
60
|
+
# Extract the salt (first 16 bytes) from the encrypted data
|
61
|
+
salt = encrypted_data[:16]
|
62
|
+
encrypted_content = encrypted_data[16:]
|
63
|
+
key = self._derive_key_from_password(salt)
|
64
|
+
fernet = Fernet(key)
|
65
|
+
decrypted_data = fernet.decrypt(encrypted_content)
|
66
|
+
if self._dict_data:
|
67
|
+
# Convert bytes back to a dict
|
68
|
+
data = json.loads(decrypted_data.decode())
|
69
|
+
|
70
|
+
else:
|
71
|
+
data = decrypted_data
|
72
|
+
|
73
|
+
return data
|
74
|
+
|
75
|
+
def get_file(self):
|
76
|
+
"""@return Get the name of the encrypted file."""
|
77
|
+
return self._filename
|
78
|
+
|
79
|
+
def _add_extension(self):
|
80
|
+
"""@brief Add the enc extension to the filename if required."""
|
81
|
+
if self._add_enc_extension and self._filename and not self._filename.endswith('.enc') :
|
82
|
+
self._filename = self._filename + ".enc"
|
83
|
+
|
84
|
+
def _derive_key_from_password(self,
|
85
|
+
salt: bytes) -> bytes:
|
86
|
+
kdf = PBKDF2HMAC(
|
87
|
+
algorithm=SHA256(),
|
88
|
+
length=32,
|
89
|
+
salt=salt,
|
90
|
+
iterations=100_000,
|
91
|
+
backend=default_backend(),
|
92
|
+
)
|
93
|
+
return urlsafe_b64encode(kdf.derive(self._password.encode()))
|
94
|
+
|
95
|
+
def _encrypt_data(self,
|
96
|
+
data):
|
97
|
+
# Generate a random salt for key derivation
|
98
|
+
salt = os.urandom(16)
|
99
|
+
key = self._derive_key_from_password(salt)
|
100
|
+
fernet = Fernet(key)
|
101
|
+
# If we expect a dict
|
102
|
+
if self._dict_data:
|
103
|
+
data_bytes = json.dumps(data).encode() # Convert JSON to bytes
|
104
|
+
|
105
|
+
# else check we have bytes
|
106
|
+
elif isinstance(data, bytes):
|
107
|
+
data_bytes = data
|
108
|
+
|
109
|
+
else:
|
110
|
+
raise Exception("data to be stored is not a bytes instance.")
|
111
|
+
|
112
|
+
encrypted_data = fernet.encrypt(data_bytes)
|
113
|
+
return salt + encrypted_data # Store the salt with the encrypted data
|
114
|
+
|
115
|
+
# Example usage
|
116
|
+
if __name__ == "__main__":
|
117
|
+
|
118
|
+
password = input("Enter a password for encryption: ")
|
119
|
+
|
120
|
+
# JSON data to encrypt
|
121
|
+
json_data = {
|
122
|
+
"name": "Alice",
|
123
|
+
"age": 30,
|
124
|
+
"is_admin": True,
|
125
|
+
"preferences": {
|
126
|
+
"theme": "dark",
|
127
|
+
"language": "English"
|
128
|
+
}
|
129
|
+
}
|
130
|
+
|
131
|
+
filename = "afile.txt"
|
132
|
+
|
133
|
+
# Save and load a python dict
|
134
|
+
cjf = CryptFile(filename=filename,
|
135
|
+
password=password)
|
136
|
+
cjf.save(json_data)
|
137
|
+
print(f"Saved {cjf.get_file()}")
|
138
|
+
|
139
|
+
decrypted_data = cjf.load()
|
140
|
+
print(f"Decrypted data: {decrypted_data}")
|
141
|
+
|
142
|
+
|
143
|
+
# Save and load data bytes
|
144
|
+
data_bytes = "123".encode()
|
145
|
+
cjf = CryptFile(filename=filename,
|
146
|
+
password=password,
|
147
|
+
dict_data=False)
|
148
|
+
cjf.save(data_bytes)
|
149
|
+
print(f"Saved {cjf.get_file()}")
|
150
|
+
|
151
|
+
decrypted_data = cjf.load()
|
152
|
+
print("Decrypted data:")
|
153
|
+
for _byte in decrypted_data:
|
154
|
+
print(f"_byte={_byte}")
|
@@ -0,0 +1,132 @@
|
|
1
|
+
#!/bin/env python3
|
2
|
+
|
3
|
+
import os
|
4
|
+
import sys
|
5
|
+
import platform
|
6
|
+
|
7
|
+
class GnomeDesktopApp(object):
|
8
|
+
"""@brief Responsible for adding and removing gnome desktop files for launching applications on a Linux system."""
|
9
|
+
|
10
|
+
@staticmethod
|
11
|
+
def IsLinux():
|
12
|
+
"""@return True if running on a Linux platform."""
|
13
|
+
linux = False
|
14
|
+
if platform.system() == "Linux":
|
15
|
+
linux = True
|
16
|
+
return linux
|
17
|
+
|
18
|
+
def __init__(self, icon_file, app_name=None, comment='', categories='Utility;Application;'):
|
19
|
+
"""@brief Constructor.
|
20
|
+
@param icon_file The name of the icon file. This can be an absolute file name the filename on it's own.
|
21
|
+
If just a filename is passed then the icon file must sit in a folder named 'assets'.
|
22
|
+
This assets folder must be in the same folder as the startup file or it's parent.
|
23
|
+
@param app_name The name of the application.
|
24
|
+
If not defined then the name of the program executed at startup is used.
|
25
|
+
This name has _ and - character replace with space characters and each
|
26
|
+
word starts with a capital letter.
|
27
|
+
@param comment This comment should detail what the program does and is stored
|
28
|
+
in the gnome desktop file that is created.
|
29
|
+
@param categories The debian app categories. default='Utility;Application;'.
|
30
|
+
"""
|
31
|
+
if not GnomeDesktopApp.IsLinux():
|
32
|
+
raise Exception("The GnomeDesktopApp() class cannot be instantiated on a non Linux platform")
|
33
|
+
self._startup_file = self._get_startup_file()
|
34
|
+
self._gnome_desktop_file = None
|
35
|
+
self._app_name = self._get_app_name()
|
36
|
+
self._check_icon(icon_file)
|
37
|
+
self._comment = comment
|
38
|
+
self._categories = categories
|
39
|
+
self._gnome_desktop_file = self._get_gnome_desktop_file()
|
40
|
+
|
41
|
+
def _get_startup_file(self):
|
42
|
+
"""@return Get the abs name of the program first started."""
|
43
|
+
return os.path.abspath(sys.argv[0])
|
44
|
+
|
45
|
+
def _get_app_name(self, app_name=None):
|
46
|
+
"""@brief Get the name of the app.
|
47
|
+
@param app_name The name of the app or None. If None then the name of the app is the
|
48
|
+
basename of the startup file minus it's extension.
|
49
|
+
@return The name of the app."""
|
50
|
+
if not app_name:
|
51
|
+
# Get just the name of the file
|
52
|
+
app_name = os.path.basename(self._startup_file)
|
53
|
+
# Remove file extension
|
54
|
+
app_name = os.path.splitext(app_name)[0]
|
55
|
+
app_name = app_name.replace('_', ' ')
|
56
|
+
app_name = app_name.replace('-', ' ')
|
57
|
+
app_name = app_name.title()
|
58
|
+
return app_name
|
59
|
+
|
60
|
+
def _check_icon(self, icon_file):
|
61
|
+
"""@brief Check that the icon file exists as this is required for the gnome desktop entry.
|
62
|
+
@param icon_file The name of the icon file.
|
63
|
+
return None"""
|
64
|
+
self._abs_icon_file = os.path.abspath(icon_file)
|
65
|
+
if not os.path.isfile(self._abs_icon_file):
|
66
|
+
startup_path = os.path.dirname(self._startup_file)
|
67
|
+
path1 = os.path.join(startup_path, 'assets')
|
68
|
+
self._abs_icon_file = os.path.join(path1, icon_file)
|
69
|
+
if not os.path.isfile(self._abs_icon_file):
|
70
|
+
startup_parent_path = os.path.join(startup_path, '..')
|
71
|
+
path2 = os.path.join(startup_parent_path, 'assets')
|
72
|
+
self._abs_icon_file = os.path.join(path2, icon_file)
|
73
|
+
if not os.path.isfile(self._abs_icon_file):
|
74
|
+
raise Exception(f"{self._app_name} icon file ({icon_file}) not found.")
|
75
|
+
|
76
|
+
def _get_gnome_desktop_file(self):
|
77
|
+
"""@brief Determine and return the name of the gnome desktop file.
|
78
|
+
@return The gnome desktop file."""
|
79
|
+
# Get just the name of the file
|
80
|
+
desktop_file_name = os.path.basename(self._startup_file)
|
81
|
+
# Remove file extension
|
82
|
+
desktop_file_name = os.path.splitext(desktop_file_name)[0]
|
83
|
+
if not desktop_file_name.endswith('.desktop'):
|
84
|
+
desktop_file_name = desktop_file_name + '.desktop'
|
85
|
+
home_folder = os.path.expanduser("~")
|
86
|
+
gnome_desktop_apps_folder = os.path.join(home_folder, '.local/share/applications')
|
87
|
+
gnome_desktop_file = os.path.join(gnome_desktop_apps_folder, desktop_file_name)
|
88
|
+
return gnome_desktop_file
|
89
|
+
|
90
|
+
def _create_gnome_desktop_file(self):
|
91
|
+
"""@brief Create the gnome desktop file for this app."""
|
92
|
+
if os.path.isfile(self._gnome_desktop_file):
|
93
|
+
raise Exception(f"{self._gnome_desktop_file} file already exists.")
|
94
|
+
lines = []
|
95
|
+
lines.append('[Desktop Entry]')
|
96
|
+
lines.append('Version=1.0')
|
97
|
+
lines.append('Type=Application')
|
98
|
+
lines.append('Encoding=UTF-8')
|
99
|
+
lines.append(f'Name={self._app_name}')
|
100
|
+
lines.append(f'Comment={self._comment}')
|
101
|
+
lines.append(f'Icon={self._abs_icon_file}')
|
102
|
+
lines.append(f'Exec=python3 {self._startup_file}')
|
103
|
+
lines.append('Terminal=false')
|
104
|
+
lines.append(f'Categories={self._categories}')
|
105
|
+
|
106
|
+
with open(self._gnome_desktop_file, "w", encoding="utf-8") as fd:
|
107
|
+
fd.write("\n".join(lines))
|
108
|
+
|
109
|
+
def create(self, overwrite=False):
|
110
|
+
"""@brief Create a desktop icon.
|
111
|
+
@param overwrite If True overwrite any existing file. If False raise an error if the file is already present."""
|
112
|
+
# If this file not found error
|
113
|
+
if not os.path.isfile(self._startup_file):
|
114
|
+
raise Exception(f"{self._startup_file} file not found.")
|
115
|
+
if overwrite:
|
116
|
+
self.delete()
|
117
|
+
self._create_gnome_desktop_file()
|
118
|
+
|
119
|
+
def delete(self):
|
120
|
+
"""@brief Delete the gnome desktop file if present"""
|
121
|
+
if os.path.isfile(self._gnome_desktop_file):
|
122
|
+
os.remove(self._gnome_desktop_file)
|
123
|
+
|
124
|
+
"""
|
125
|
+
Example usage
|
126
|
+
gda = GnomeDesktopApp('savings.png')
|
127
|
+
gda.create(overwrite=True)
|
128
|
+
"""
|
129
|
+
|
130
|
+
|
131
|
+
|
132
|
+
|
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.2
|
2
2
|
Name: p3lib
|
3
|
-
Version: 1.1.
|
3
|
+
Version: 1.1.102
|
4
4
|
Summary: A group of python modules for networking, plotting data, config storage, automating boot scripts, ssh access and user input output.
|
5
5
|
Home-page: https://github.com/pjaos/p3lib
|
6
6
|
Author: Paul Austen
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|