rbeesoft 2.0.6__tar.gz → 2.0.7__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.
- {rbeesoft-2.0.6 → rbeesoft-2.0.7}/PKG-INFO +1 -1
- {rbeesoft-2.0.6 → rbeesoft-2.0.7}/pyproject.toml +1 -1
- {rbeesoft-2.0.6 → rbeesoft-2.0.7}/src/rbeesoft/app/main.py +5 -1
- {rbeesoft-2.0.6 → rbeesoft-2.0.7}/src/rbeesoft/app/ui/processes/processrunner.py +1 -1
- {rbeesoft-2.0.6 → rbeesoft-2.0.7}/src/rbeesoft/app/ui/rbeesoftmainwindow.py +7 -7
- {rbeesoft-2.0.6 → rbeesoft-2.0.7}/src/rbeesoft/common/__init__.py +2 -1
- rbeesoft-2.0.7/src/rbeesoft/common/license.py +38 -0
- {rbeesoft-2.0.6 → rbeesoft-2.0.7}/src/rbeesoft/common/licensemanager.py +13 -5
- {rbeesoft-2.0.6 → rbeesoft-2.0.7}/src/rbeesoft/common/logmanager.py +1 -1
- rbeesoft-2.0.6/src/rbeesoft/app/generatekeys.py +0 -37
- rbeesoft-2.0.6/src/rbeesoft/app/license.json +0 -15
- rbeesoft-2.0.6/src/rbeesoft/app/signlicense.py +0 -76
- {rbeesoft-2.0.6 → rbeesoft-2.0.7}/README.md +0 -0
- {rbeesoft-2.0.6 → rbeesoft-2.0.7}/src/rbeesoft/__init__.py +0 -0
- {rbeesoft-2.0.6 → rbeesoft-2.0.7}/src/rbeesoft/app/__init__.py +0 -0
- {rbeesoft-2.0.6 → rbeesoft-2.0.7}/src/rbeesoft/app/core/__init__.py +0 -0
- {rbeesoft-2.0.6 → rbeesoft-2.0.7}/src/rbeesoft/app/ui/__init__.py +0 -0
- {rbeesoft-2.0.6 → rbeesoft-2.0.7}/src/rbeesoft/app/ui/processes/__init__.py +0 -0
- {rbeesoft-2.0.6 → rbeesoft-2.0.7}/src/rbeesoft/app/ui/processes/dummyprocess.py +0 -0
- {rbeesoft-2.0.6 → rbeesoft-2.0.7}/src/rbeesoft/app/ui/processes/process.py +0 -0
- {rbeesoft-2.0.6 → rbeesoft-2.0.7}/src/rbeesoft/app/ui/settings.py +0 -0
- {rbeesoft-2.0.6 → rbeesoft-2.0.7}/src/rbeesoft/app/ui/widgets/__init__.py +0 -0
- {rbeesoft-2.0.6 → rbeesoft-2.0.7}/src/rbeesoft/app/ui/widgets/centraldockwidget.py +0 -0
- {rbeesoft-2.0.6 → rbeesoft-2.0.7}/src/rbeesoft/app/ui/widgets/logdockwidget.py +0 -0
- {rbeesoft-2.0.6 → rbeesoft-2.0.7}/src/rbeesoft/app/ui/widgets/pages/__init__.py +0 -0
- {rbeesoft-2.0.6 → rbeesoft-2.0.7}/src/rbeesoft/app/ui/widgets/pages/page.py +0 -0
- {rbeesoft-2.0.6 → rbeesoft-2.0.7}/src/rbeesoft/app/ui/widgets/pages/pagerouter.py +0 -0
- /rbeesoft-2.0.6/src/rbeesoft/common/singleton.py → /rbeesoft-2.0.7/src/rbeesoft/common/decorators.py +0 -0
- {rbeesoft-2.0.6 → rbeesoft-2.0.7}/src/rbeesoft/common/exceptions/__init__.py +0 -0
- {rbeesoft-2.0.6 → rbeesoft-2.0.7}/src/rbeesoft/common/exceptions/licenseexception.py +0 -0
- {rbeesoft-2.0.6 → rbeesoft-2.0.7}/src/rbeesoft/common/logmanagerlistener.py +0 -0
- {rbeesoft-2.0.6 → rbeesoft-2.0.7}/src/rbeesoft/webapp/__init__.py +0 -0
|
@@ -4,6 +4,7 @@ from rbeesoft.app.ui import RbeesoftMainWindow
|
|
|
4
4
|
from rbeesoft.app.ui.widgets.pages import Page
|
|
5
5
|
from rbeesoft.app.ui.processes import Process
|
|
6
6
|
from rbeesoft.app.ui.processes import ProcessRunner
|
|
7
|
+
from rbeesoft.common import LicenseManager
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
class MainWindow(RbeesoftMainWindow):
|
|
@@ -32,7 +33,10 @@ class HomePage(Page):
|
|
|
32
33
|
layout.setAlignment(QtCore.Qt.AlignmentFlag.AlignTop)
|
|
33
34
|
layout.addWidget(QtWidgets.QLabel(self.title()))
|
|
34
35
|
layout.addWidget(button)
|
|
35
|
-
|
|
36
|
+
manager = LicenseManager(settings)
|
|
37
|
+
license = manager.license()
|
|
38
|
+
if license.has_all_features('x'):
|
|
39
|
+
layout.addWidget(process_button)
|
|
36
40
|
self.setLayout(layout)
|
|
37
41
|
|
|
38
42
|
def handle_button(self):
|
|
@@ -3,11 +3,11 @@ from PySide6.QtCore import Qt, QByteArray
|
|
|
3
3
|
from PySide6.QtWidgets import QMainWindow, QStyle, QFileDialog
|
|
4
4
|
from PySide6.QtGui import QGuiApplication, QAction
|
|
5
5
|
from rbeesoft.app.ui.settings import Settings
|
|
6
|
-
from rbeesoft.app.ui.widgets import CentralDockWidget
|
|
7
|
-
from rbeesoft.app.ui.widgets import LogDockWidget
|
|
8
|
-
from rbeesoft.common import LicenseManager
|
|
9
|
-
from rbeesoft.common.exceptions import LicenseException
|
|
10
|
-
from rbeesoft.common import LogManager
|
|
6
|
+
from rbeesoft.app.ui.widgets.centraldockwidget import CentralDockWidget
|
|
7
|
+
from rbeesoft.app.ui.widgets.logdockwidget import LogDockWidget
|
|
8
|
+
from rbeesoft.common.licensemanager import LicenseManager
|
|
9
|
+
from rbeesoft.common.exceptions.licenseexception import LicenseException
|
|
10
|
+
from rbeesoft.common.logmanager import LogManager
|
|
11
11
|
|
|
12
12
|
LOG = LogManager()
|
|
13
13
|
|
|
@@ -87,7 +87,7 @@ class RbeesoftMainWindow(QMainWindow):
|
|
|
87
87
|
|
|
88
88
|
def license_manager(self):
|
|
89
89
|
if not self._license_manager:
|
|
90
|
-
self._license_manager = LicenseManager(self.settings()
|
|
90
|
+
self._license_manager = LicenseManager(self.settings())
|
|
91
91
|
return self._license_manager
|
|
92
92
|
|
|
93
93
|
def license(self):
|
|
@@ -116,7 +116,7 @@ class RbeesoftMainWindow(QMainWindow):
|
|
|
116
116
|
file_path = self.settings().get('mainwindow/license_file', None)
|
|
117
117
|
if file_path:
|
|
118
118
|
try:
|
|
119
|
-
self._license = self.license_manager().
|
|
119
|
+
self._license = self.license_manager().check_license(file_path)
|
|
120
120
|
LOG.info(f'License found at {file_path}')
|
|
121
121
|
LOG.info('License OK')
|
|
122
122
|
return True
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
from rbeesoft.common.logmanager import LogManager
|
|
2
2
|
from rbeesoft.common.logmanagerlistener import LogManagerListener
|
|
3
|
-
from rbeesoft.common.licensemanager import LicenseManager
|
|
3
|
+
from rbeesoft.common.licensemanager import LicenseManager
|
|
4
|
+
from rbeesoft.common.license import License
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import time
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class License:
|
|
5
|
+
def __init__(self, payload):
|
|
6
|
+
self._payload = payload
|
|
7
|
+
|
|
8
|
+
def customer(self):
|
|
9
|
+
return self._payload['customer']
|
|
10
|
+
|
|
11
|
+
def product(self):
|
|
12
|
+
return self._payload['product']
|
|
13
|
+
|
|
14
|
+
def feature_list(self):
|
|
15
|
+
return self._payload['features']
|
|
16
|
+
|
|
17
|
+
def expiry_days(self):
|
|
18
|
+
return int(self._payload['exp'])
|
|
19
|
+
|
|
20
|
+
def id(self):
|
|
21
|
+
return self._payload['license_id']
|
|
22
|
+
|
|
23
|
+
# CHECKS
|
|
24
|
+
|
|
25
|
+
def is_expired(self):
|
|
26
|
+
now = int(time.time())
|
|
27
|
+
if now > self.expiry_days():
|
|
28
|
+
return True
|
|
29
|
+
return False
|
|
30
|
+
|
|
31
|
+
def is_valid(self):
|
|
32
|
+
return not self.is_expired()
|
|
33
|
+
|
|
34
|
+
def has_all_features(self):
|
|
35
|
+
return 'all' in self.feature_list()
|
|
36
|
+
|
|
37
|
+
def has_feature(self, name):
|
|
38
|
+
return name in self.feature_list()
|
|
@@ -3,19 +3,26 @@ import time
|
|
|
3
3
|
import base64
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
|
|
6
|
-
from rbeesoft.common.exceptions
|
|
6
|
+
from rbeesoft.common.exceptions import LicenseException
|
|
7
|
+
from rbeesoft.common.license import License
|
|
8
|
+
from rbeesoft.common.decorators import singleton
|
|
7
9
|
|
|
8
10
|
|
|
11
|
+
@singleton
|
|
9
12
|
class LicenseManager:
|
|
10
|
-
def __init__(self,
|
|
13
|
+
def __init__(self, settings):
|
|
11
14
|
self._file_path = None
|
|
12
|
-
self._public_key = public_key
|
|
15
|
+
self._public_key = settings.get('public_key', None)
|
|
16
|
+
self._license = None
|
|
13
17
|
|
|
14
18
|
def file_path(self):
|
|
15
19
|
return self._file_path
|
|
16
20
|
|
|
17
21
|
def public_key(self):
|
|
18
22
|
return self._public_key
|
|
23
|
+
|
|
24
|
+
def license(self):
|
|
25
|
+
return self._license
|
|
19
26
|
|
|
20
27
|
def canonical_json_bytes(self, obj: dict) -> bytes:
|
|
21
28
|
return json.dumps(
|
|
@@ -25,7 +32,7 @@ class LicenseManager:
|
|
|
25
32
|
ensure_ascii=False
|
|
26
33
|
).encode("utf-8")
|
|
27
34
|
|
|
28
|
-
def
|
|
35
|
+
def check_license(self, file_path):
|
|
29
36
|
if isinstance(file_path, str):
|
|
30
37
|
file_path = Path(file_path)
|
|
31
38
|
if not file_path.exists():
|
|
@@ -44,6 +51,7 @@ class LicenseManager:
|
|
|
44
51
|
exp = int(payload["exp"])
|
|
45
52
|
if now > exp:
|
|
46
53
|
raise LicenseException('License expired')
|
|
47
|
-
|
|
54
|
+
self._license = License(payload)
|
|
55
|
+
return self._license
|
|
48
56
|
except Exception as e:
|
|
49
57
|
raise LicenseException(f'Invalid license: {e}')
|
|
@@ -1,37 +0,0 @@
|
|
|
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
|
-
|
|
@@ -1,15 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,76 +0,0 @@
|
|
|
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()
|
|
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
|
/rbeesoft-2.0.6/src/rbeesoft/common/singleton.py → /rbeesoft-2.0.7/src/rbeesoft/common/decorators.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|