rbeesoft 2.0.2__py3-none-any.whl → 2.0.4__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.
- rbeesoft/app/generatekeys.py +37 -0
- rbeesoft/app/license.json +15 -0
- rbeesoft/app/main.py +2 -2
- rbeesoft/app/signlicense.py +76 -0
- rbeesoft/app/ui/rbeesoftmainwindow.py +87 -17
- rbeesoft/app/ui/settings.py +6 -0
- rbeesoft/app/ui/widgets/pages/page.py +5 -1
- rbeesoft/common/licenseexception.py +2 -0
- rbeesoft/common/licensemanager.py +47 -0
- {rbeesoft-2.0.2.dist-info → rbeesoft-2.0.4.dist-info}/METADATA +1 -1
- {rbeesoft-2.0.2.dist-info → rbeesoft-2.0.4.dist-info}/RECORD +12 -7
- {rbeesoft-2.0.2.dist-info → rbeesoft-2.0.4.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import base64
|
|
3
|
+
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
|
|
4
|
+
from cryptography.hazmat.primitives import serialization
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
# RUN THIS ONLY ONCE!!! You can distribute the public key to clients
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def main():
|
|
11
|
+
output_dir = Path.home() / 'keys'
|
|
12
|
+
os.makedirs(output_dir, exist_ok=True)
|
|
13
|
+
priv = Ed25519PrivateKey.generate()
|
|
14
|
+
pub = priv.public_key()
|
|
15
|
+
priv_bytes = priv.private_bytes(
|
|
16
|
+
encoding=serialization.Encoding.Raw,
|
|
17
|
+
format=serialization.PrivateFormat.Raw,
|
|
18
|
+
encryption_algorithm=serialization.NoEncryption(),
|
|
19
|
+
)
|
|
20
|
+
pub_bytes = pub.public_bytes(
|
|
21
|
+
encoding=serialization.Encoding.Raw,
|
|
22
|
+
format=serialization.PublicFormat.Raw,
|
|
23
|
+
)
|
|
24
|
+
priv_file = output_dir / 'ed25519_private.key'
|
|
25
|
+
priv_file.write_bytes(priv_bytes)
|
|
26
|
+
pub_file = output_dir / 'ed25519_public.key'
|
|
27
|
+
pub_file.write_bytes(pub_bytes)
|
|
28
|
+
print("Wrote:")
|
|
29
|
+
print(" - $HOME/keys/ed25519_private.key (KEEP SECRET)")
|
|
30
|
+
print(" - $HOME/keys/ed25519_public.key (embed in app)")
|
|
31
|
+
print("\nPublic key (base64) to embed:")
|
|
32
|
+
print(base64.b64encode(pub_bytes).decode("ascii"))
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
if __name__ == '__main__':
|
|
36
|
+
main()
|
|
37
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"payload": {
|
|
3
|
+
"customer": "Ralph Example",
|
|
4
|
+
"product": "MyPySideApp Pro",
|
|
5
|
+
"features": [
|
|
6
|
+
"pro",
|
|
7
|
+
"export_pdf"
|
|
8
|
+
],
|
|
9
|
+
"issued_at": 1770031472,
|
|
10
|
+
"exp": 1772623472,
|
|
11
|
+
"license_id": "LIC-1770031472"
|
|
12
|
+
},
|
|
13
|
+
"signature": "2NPw5sb9zeOF3b6Sm5hrxWcne/cX0G0vJwVJ+bG+0i7/WY6SJyCNcmN5v+2eBe7WZjs+E+c33JOA7mX8BLTmBA==",
|
|
14
|
+
"alg": "Ed25519"
|
|
15
|
+
}
|
rbeesoft/app/main.py
CHANGED
|
@@ -12,8 +12,8 @@ class MainWindow(RbeesoftMainWindow):
|
|
|
12
12
|
bundle_identifier='rbeesoft.nl',
|
|
13
13
|
app_name='example',
|
|
14
14
|
app_title='Rbeesoft App Example',
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
app_width=800,
|
|
16
|
+
app_height=600,
|
|
17
17
|
app_icon=app_icon,
|
|
18
18
|
)
|
|
19
19
|
self.add_page(HomePage(self.settings()), home_page=True)
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
import argparse
|
|
3
|
+
import json
|
|
4
|
+
import time
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
|
|
7
|
+
|
|
8
|
+
def canonical_json_bytes(obj: dict) -> bytes:
|
|
9
|
+
# Deterministic JSON -> same bytes everywhere
|
|
10
|
+
return json.dumps(
|
|
11
|
+
obj,
|
|
12
|
+
sort_keys=True,
|
|
13
|
+
separators=(",", ":"),
|
|
14
|
+
ensure_ascii=False
|
|
15
|
+
).encode("utf-8")
|
|
16
|
+
|
|
17
|
+
def load_private_key(path: Path) -> Ed25519PrivateKey:
|
|
18
|
+
key_bytes = path.read_bytes()
|
|
19
|
+
return Ed25519PrivateKey.from_private_bytes(key_bytes)
|
|
20
|
+
|
|
21
|
+
def make_license_payload(
|
|
22
|
+
customer: str,
|
|
23
|
+
product: str,
|
|
24
|
+
expires_days_from_now: int,
|
|
25
|
+
features: list[str],
|
|
26
|
+
machine_fp: str | None = None,
|
|
27
|
+
) -> dict:
|
|
28
|
+
now = int(time.time())
|
|
29
|
+
exp = now + expires_days_from_now * 24 * 3600
|
|
30
|
+
payload = {
|
|
31
|
+
"customer": customer,
|
|
32
|
+
"product": product,
|
|
33
|
+
"features": features,
|
|
34
|
+
"issued_at": now,
|
|
35
|
+
"exp": exp,
|
|
36
|
+
"license_id": f"LIC-{now}",
|
|
37
|
+
}
|
|
38
|
+
# Optional machine binding (keep None for portable)
|
|
39
|
+
if machine_fp:
|
|
40
|
+
payload["machine_fp"] = machine_fp
|
|
41
|
+
return payload
|
|
42
|
+
|
|
43
|
+
def sign_license(payload: dict, priv: Ed25519PrivateKey) -> dict:
|
|
44
|
+
msg = canonical_json_bytes(payload)
|
|
45
|
+
sig = priv.sign(msg)
|
|
46
|
+
return {
|
|
47
|
+
"payload": payload,
|
|
48
|
+
"signature": base64.b64encode(sig).decode("ascii"),
|
|
49
|
+
"alg": "Ed25519",
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
def main():
|
|
53
|
+
parser = argparse.ArgumentParser()
|
|
54
|
+
parser.add_argument('private_key_path', help='Path to private key file')
|
|
55
|
+
parser.add_argument('output_dir', help='Path to output directory where license.json is written')
|
|
56
|
+
parser.add_argument('product', help='Name of product')
|
|
57
|
+
parser.add_argument('expires_days_from_now', help='Number of days to expire', type=int)
|
|
58
|
+
parser.add_argument('--features', help='Feature list', default='')
|
|
59
|
+
args = parser.parse_args()
|
|
60
|
+
priv_path = Path(args.private_key_path) # Path.home() / 'keys/ed25519_private.key'
|
|
61
|
+
out_path = Path(args.output_dir) / 'license.json'
|
|
62
|
+
priv = load_private_key(priv_path)
|
|
63
|
+
payload = make_license_payload(
|
|
64
|
+
customer='Default customer',
|
|
65
|
+
product=args.product,
|
|
66
|
+
expires_days_from_now=args.expires_days_from_now,
|
|
67
|
+
features=[x.strip() for x in args.features.split(',')],
|
|
68
|
+
machine_fp=None, # set to a fingerprint to bind to a device
|
|
69
|
+
)
|
|
70
|
+
signed = sign_license(payload, priv)
|
|
71
|
+
out_path.write_text(json.dumps(signed, indent=2, ensure_ascii=False), encoding="utf-8")
|
|
72
|
+
print(f"Wrote signed license to: {out_path.resolve()}")
|
|
73
|
+
print(f"Expires at (unix): {payload['exp']}")
|
|
74
|
+
|
|
75
|
+
if __name__ == "__main__":
|
|
76
|
+
main()
|
|
@@ -1,60 +1,130 @@
|
|
|
1
|
+
import os
|
|
1
2
|
from PySide6.QtCore import Qt, QByteArray
|
|
2
|
-
from PySide6.QtWidgets import QMainWindow, QStyle
|
|
3
|
+
from PySide6.QtWidgets import QMainWindow, QStyle, QFileDialog
|
|
3
4
|
from PySide6.QtGui import QGuiApplication, QAction
|
|
4
5
|
from rbeesoft.app.ui.settings import Settings
|
|
5
6
|
from rbeesoft.app.ui.widgets.centraldockwidget import CentralDockWidget
|
|
6
7
|
from rbeesoft.app.ui.widgets.logdockwidget import LogDockWidget
|
|
8
|
+
from rbeesoft.common.licensemanager import LicenseManager
|
|
9
|
+
from rbeesoft.common.licenseexception import LicenseException
|
|
7
10
|
from rbeesoft.common.logmanager import LogManager
|
|
8
11
|
|
|
9
12
|
LOG = LogManager()
|
|
10
13
|
|
|
14
|
+
PUBLIC_KEY_B64 = 'C7yBmGtvBkvnvGtWiey4PKXZWo7Lza61+FwV2UyAu34='
|
|
15
|
+
|
|
11
16
|
|
|
12
17
|
class RbeesoftMainWindow(QMainWindow):
|
|
13
|
-
def __init__(self, bundle_identifier, app_name, app_title,
|
|
18
|
+
def __init__(self, bundle_identifier, app_name, app_title, app_width=1024, app_height=1024, app_icon=None):
|
|
14
19
|
super(RbeesoftMainWindow, self).__init__()
|
|
15
20
|
self._settings = Settings(bundle_identifier, app_name)
|
|
21
|
+
self._settings.set('public_key', PUBLIC_KEY_B64)
|
|
16
22
|
self._app_title = app_title
|
|
17
|
-
self.
|
|
18
|
-
self.
|
|
23
|
+
self._app_width = app_width
|
|
24
|
+
self._app_height = app_height
|
|
19
25
|
self._app_icon = app_icon
|
|
20
|
-
self._central_dockwidget =
|
|
21
|
-
self._log_dockwidget =
|
|
26
|
+
self._central_dockwidget = None
|
|
27
|
+
self._log_dockwidget = None
|
|
28
|
+
self._license_manager = None
|
|
29
|
+
self._license = None
|
|
22
30
|
self.init()
|
|
23
31
|
|
|
24
32
|
# INITIALIZATION
|
|
25
33
|
|
|
26
34
|
def init(self):
|
|
27
|
-
self.setWindowTitle(self.
|
|
28
|
-
self.addDockWidget(Qt.DockWidgetArea.TopDockWidgetArea, self.
|
|
29
|
-
self.addDockWidget(Qt.DockWidgetArea.BottomDockWidgetArea, self.
|
|
30
|
-
|
|
31
|
-
|
|
35
|
+
self.setWindowTitle(self.app_title())
|
|
36
|
+
self.addDockWidget(Qt.DockWidgetArea.TopDockWidgetArea, self.central_dockwidget())
|
|
37
|
+
self.addDockWidget(Qt.DockWidgetArea.BottomDockWidgetArea, self.log_dockwidget())
|
|
38
|
+
LOG.info(f'Settings path: {self.settings().fileName()}')
|
|
39
|
+
if self.app_icon():
|
|
40
|
+
self.setWindowIcon(self.app_icon())
|
|
32
41
|
self.load_geometry_and_state()
|
|
33
42
|
self.init_default_menus()
|
|
43
|
+
self.check_license()
|
|
34
44
|
self.statusBar().showMessage('Ready')
|
|
35
|
-
LOG.info(f'Settings path: {self.settings().fileName()}')
|
|
36
45
|
|
|
37
46
|
def init_default_menus(self):
|
|
38
|
-
|
|
39
|
-
|
|
47
|
+
# Application menu
|
|
48
|
+
icon = self.style().standardIcon(QStyle.StandardPixmap.SP_MessageBoxCritical)
|
|
49
|
+
exit_action = QAction(icon, 'E&xit', self)
|
|
40
50
|
exit_action.triggered.connect(self.close)
|
|
41
51
|
application_menu = self.menuBar().addMenu('Application')
|
|
42
52
|
application_menu.addAction(exit_action)
|
|
53
|
+
# Settings menu
|
|
54
|
+
icon = self.style().standardIcon(QStyle.StandardPixmap.SP_VistaShield)
|
|
55
|
+
open_license_file_action = QAction(icon, 'Open license file...', self)
|
|
56
|
+
open_license_file_action.triggered.connect(self.handle_open_license_file_action)
|
|
57
|
+
settings_menu = self.menuBar().addMenu('Settings')
|
|
58
|
+
settings_menu.addAction(open_license_file_action)
|
|
43
59
|
|
|
44
60
|
# GETTERS
|
|
45
61
|
|
|
46
62
|
def settings(self):
|
|
47
63
|
return self._settings
|
|
48
64
|
|
|
65
|
+
def app_title(self):
|
|
66
|
+
return self._app_title
|
|
67
|
+
|
|
68
|
+
def app_width(self):
|
|
69
|
+
return self._app_width
|
|
70
|
+
|
|
71
|
+
def app_height(self):
|
|
72
|
+
return self._app_height
|
|
73
|
+
|
|
74
|
+
def app_icon(self):
|
|
75
|
+
return self._app_icon
|
|
76
|
+
|
|
77
|
+
def central_dockwidget(self):
|
|
78
|
+
if not self._central_dockwidget:
|
|
79
|
+
self._central_dockwidget = CentralDockWidget(self, self.settings())
|
|
80
|
+
return self._central_dockwidget
|
|
81
|
+
|
|
82
|
+
def log_dockwidget(self):
|
|
83
|
+
if not self._log_dockwidget:
|
|
84
|
+
self._log_dockwidget = LogDockWidget(self)
|
|
85
|
+
LOG.add_listener(self._log_dockwidget)
|
|
86
|
+
return self._log_dockwidget
|
|
87
|
+
|
|
88
|
+
def license_manager(self):
|
|
89
|
+
if not self._license_manager:
|
|
90
|
+
self._license_manager = LicenseManager(self.settings().get('public_key', None))
|
|
91
|
+
return self._license_manager
|
|
92
|
+
|
|
93
|
+
def license(self):
|
|
94
|
+
return self._license
|
|
95
|
+
|
|
49
96
|
# EVENT HANDLERS
|
|
50
97
|
|
|
51
|
-
def closeEvent(self,
|
|
98
|
+
def closeEvent(self, event):
|
|
52
99
|
self.save_geometry_and_state()
|
|
100
|
+
return super().closeEvent(event)
|
|
101
|
+
|
|
102
|
+
def handle_open_license_file_action(self):
|
|
103
|
+
last_directory = self.settings().get('mainwindow/last_directory', None)
|
|
104
|
+
file_path, _ = QFileDialog.getOpenFileName(dir=last_directory)
|
|
105
|
+
if file_path:
|
|
106
|
+
self.settings().set('mainwindow/last_directory', os.path.split(file_path)[0])
|
|
107
|
+
self.settings().set('mainwindow/license_file', file_path)
|
|
108
|
+
self.check_license()
|
|
53
109
|
|
|
54
110
|
# HELPERS
|
|
55
111
|
|
|
56
112
|
def add_page(self, page, home_page=False):
|
|
57
|
-
self.
|
|
113
|
+
self.central_dockwidget().add_page(page, home_page)
|
|
114
|
+
|
|
115
|
+
def check_license(self):
|
|
116
|
+
file_path = self.settings().get('mainwindow/license_file', None)
|
|
117
|
+
if file_path:
|
|
118
|
+
try:
|
|
119
|
+
self._license = self.license_manager().verify(file_path)
|
|
120
|
+
LOG.info(f'License found at {file_path}')
|
|
121
|
+
LOG.info('License OK')
|
|
122
|
+
return True
|
|
123
|
+
except LicenseException as e:
|
|
124
|
+
LOG.error(e)
|
|
125
|
+
return False
|
|
126
|
+
LOG.warning('No license found')
|
|
127
|
+
return False
|
|
58
128
|
|
|
59
129
|
def load_geometry_and_state(self):
|
|
60
130
|
geometry = self.settings().get('mainwindow/geometry')
|
|
@@ -63,7 +133,7 @@ class RbeesoftMainWindow(QMainWindow):
|
|
|
63
133
|
if isinstance(state, QByteArray):
|
|
64
134
|
self.restoreState(state)
|
|
65
135
|
return
|
|
66
|
-
self.resize(self.
|
|
136
|
+
self.resize(self.app_width(), self.app_height())
|
|
67
137
|
self.center_window()
|
|
68
138
|
|
|
69
139
|
def save_geometry_and_state(self):
|
rbeesoft/app/ui/settings.py
CHANGED
|
@@ -12,6 +12,12 @@ class Settings(QSettings):
|
|
|
12
12
|
self._bundle_identifier = bundle_identifier
|
|
13
13
|
self._app_name = app_name
|
|
14
14
|
|
|
15
|
+
def bundle_identifier(self):
|
|
16
|
+
return self._bundle_identifier
|
|
17
|
+
|
|
18
|
+
def app_name(self):
|
|
19
|
+
return self._app_name
|
|
20
|
+
|
|
15
21
|
def _prepend_bundle_identifier_and_name(self, name):
|
|
16
22
|
return '{}.{}.{}'.format(self._bundle_identifier, self._app_name, name)
|
|
17
23
|
|
|
@@ -5,11 +5,12 @@ from PySide6.QtWidgets import QWidget
|
|
|
5
5
|
class Page(QWidget):
|
|
6
6
|
page_changed = Signal(str)
|
|
7
7
|
|
|
8
|
-
def __init__(self, name, title, settings):
|
|
8
|
+
def __init__(self, name, title, settings, license=None):
|
|
9
9
|
super(Page, self).__init__()
|
|
10
10
|
self._name = name
|
|
11
11
|
self._title = title
|
|
12
12
|
self._settings = settings
|
|
13
|
+
self._license = license
|
|
13
14
|
|
|
14
15
|
def name(self):
|
|
15
16
|
return self._name
|
|
@@ -20,5 +21,8 @@ class Page(QWidget):
|
|
|
20
21
|
def settings(self):
|
|
21
22
|
return self._settings
|
|
22
23
|
|
|
24
|
+
def license(self):
|
|
25
|
+
return self._license
|
|
26
|
+
|
|
23
27
|
def switch_to_page(self, name):
|
|
24
28
|
self.page_changed.emit(name)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import time
|
|
3
|
+
import base64
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
|
|
6
|
+
from rbeesoft.common.licenseexception import LicenseException
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class LicenseManager:
|
|
10
|
+
def __init__(self, public_key):
|
|
11
|
+
self._file_path = None
|
|
12
|
+
self._public_key = public_key
|
|
13
|
+
|
|
14
|
+
def file_path(self):
|
|
15
|
+
return self._file_path
|
|
16
|
+
|
|
17
|
+
def public_key(self):
|
|
18
|
+
return self._public_key
|
|
19
|
+
|
|
20
|
+
def canonical_json_bytes(self, obj: dict) -> bytes:
|
|
21
|
+
return json.dumps(
|
|
22
|
+
obj,
|
|
23
|
+
sort_keys=True,
|
|
24
|
+
separators=(",", ":"),
|
|
25
|
+
ensure_ascii=False
|
|
26
|
+
).encode("utf-8")
|
|
27
|
+
|
|
28
|
+
def verify(self, file_path):
|
|
29
|
+
if isinstance(file_path, str):
|
|
30
|
+
file_path = Path(file_path)
|
|
31
|
+
try:
|
|
32
|
+
signed = json.loads(file_path.read_text(encoding='utf-8'))
|
|
33
|
+
payload = signed['payload']
|
|
34
|
+
sig_b64 = signed['signature']
|
|
35
|
+
sig = base64.b64decode(sig_b64)
|
|
36
|
+
msg = self.canonical_json_bytes(payload)
|
|
37
|
+
pub_bytes = base64.b64decode(self.public_key())
|
|
38
|
+
pub = Ed25519PublicKey.from_public_bytes(pub_bytes)
|
|
39
|
+
pub.verify(sig, msg)
|
|
40
|
+
# expiry check
|
|
41
|
+
now = int(time.time())
|
|
42
|
+
exp = int(payload["exp"])
|
|
43
|
+
if now > exp:
|
|
44
|
+
raise LicenseException('License expired')
|
|
45
|
+
return payload
|
|
46
|
+
except Exception as e:
|
|
47
|
+
raise LicenseException(f'Invalid license: {e}')
|
|
@@ -1,25 +1,30 @@
|
|
|
1
1
|
rbeesoft/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
2
|
rbeesoft/app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
3
|
rbeesoft/app/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
-
rbeesoft/app/
|
|
4
|
+
rbeesoft/app/generatekeys.py,sha256=YVxIhKhyo0JY6HFxCTNZdD5bU_K6Vb1zkRKdsYQ80Ew,1243
|
|
5
|
+
rbeesoft/app/license.json,sha256=m8ukgKJdiJ3fU4nsFIrE2fm6Qk_SdIdwoqkapM2MnlI,374
|
|
6
|
+
rbeesoft/app/main.py,sha256=AsDayu8MZoLnd9ODZmHL-AA-dqS8exodKv4LcHKw44o,2886
|
|
7
|
+
rbeesoft/app/signlicense.py,sha256=Zp5bZOnmtHsFOACgU3iGRwy0Ko0nb4GZ97lB4BKTWMw,2704
|
|
5
8
|
rbeesoft/app/ui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
9
|
rbeesoft/app/ui/processes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
10
|
rbeesoft/app/ui/processes/dummyprocess.py,sha256=4r97xwHv7ZaoK85zBxR00zzYnYpoFAxZfBPmxFJYDkM,470
|
|
8
11
|
rbeesoft/app/ui/processes/process.py,sha256=qMrXKvT06oRe1yRSe3DLO9ObhV2qzzZLI5R-PwryOYs,1694
|
|
9
12
|
rbeesoft/app/ui/processes/processrunner.py,sha256=HqDQ3ZMlqCqQkyuEgV5sJCkzD35ENvp58z9D-TtnVdA,1170
|
|
10
|
-
rbeesoft/app/ui/rbeesoftmainwindow.py,sha256=
|
|
11
|
-
rbeesoft/app/ui/settings.py,sha256=
|
|
13
|
+
rbeesoft/app/ui/rbeesoftmainwindow.py,sha256=p-tO7YG39DEQ_15ijLGKSG1MFWnPBWR8CGR7nl971jA,5713
|
|
14
|
+
rbeesoft/app/ui/settings.py,sha256=JeUBdQgah9s2XbSqsgEEYzFN2yvUwFMk8L7KFsa55WM,2200
|
|
12
15
|
rbeesoft/app/ui/widgets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
16
|
rbeesoft/app/ui/widgets/centraldockwidget.py,sha256=kK0x-Sz4yz7D4icaIepWpAtct7ZQ9BNroi9EccAvABA,1376
|
|
14
17
|
rbeesoft/app/ui/widgets/logdockwidget.py,sha256=DZkQQitarE5B82qvNCSnUWDWXxhWsuTauboULFoh7eI,1810
|
|
15
18
|
rbeesoft/app/ui/widgets/pages/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
|
-
rbeesoft/app/ui/widgets/pages/page.py,sha256=
|
|
19
|
+
rbeesoft/app/ui/widgets/pages/page.py,sha256=huzUrbvyx8qZmeelKRhLimB9RFfuj9bK_EsG_56AK_E,661
|
|
17
20
|
rbeesoft/app/ui/widgets/pages/pagerouter.py,sha256=L5EKEMWVibSI7IpabQBkLsCDw1xBt1wfYY50iR56VZA,1460
|
|
18
21
|
rbeesoft/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
|
+
rbeesoft/common/licenseexception.py,sha256=oapxaf0e9Fbl3iAa5e3c2EYxNhD0e1im1mwJfimsZ3Q,44
|
|
23
|
+
rbeesoft/common/licensemanager.py,sha256=UxsEvWbzXHTAI5sqI-MsZZP-aG1GK14YBY_ky2M5JyE,1554
|
|
19
24
|
rbeesoft/common/logmanager.py,sha256=K_qCbPjrzoV5le3KSvLOSSXYa-_MWLJ3FdFNTEGYSxg,1391
|
|
20
25
|
rbeesoft/common/logmanagerlistener.py,sha256=Gaig07yjBnyQq9I8sN85olTEeDCDyCFQnEJdwzvmgvc,99
|
|
21
26
|
rbeesoft/common/singleton.py,sha256=FV0k_LlOCmFhlWN6gf1c2x7YXWyd8-7DsIMvOKrI6NY,224
|
|
22
27
|
rbeesoft/webapp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
23
|
-
rbeesoft-2.0.
|
|
24
|
-
rbeesoft-2.0.
|
|
25
|
-
rbeesoft-2.0.
|
|
28
|
+
rbeesoft-2.0.4.dist-info/METADATA,sha256=5JpIKhEMZamX4jm6keezUXIph6r5mfHTzOAp8jt7RDw,378
|
|
29
|
+
rbeesoft-2.0.4.dist-info/WHEEL,sha256=3ny-bZhpXrU6vSQ1UPG34FoxZBp3lVcvK0LkgUz6VLk,88
|
|
30
|
+
rbeesoft-2.0.4.dist-info/RECORD,,
|
|
File without changes
|