Skip to content

Commit e64ab1a

Browse files
authored
Add signature time interval when loading a license (#7)
* Add signature time interval when loading a license, closes #6 * Add example * Add support for floating
1 parent ca6dc2d commit e64ab1a

File tree

4 files changed

+69
-12
lines changed

4 files changed

+69
-12
lines changed

README.md

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ res = Key.activate(token="WyIyNTU1IiwiRjdZZTB4RmtuTVcrQlNqcSszbmFMMHB3aWFJTlBsWW
3131
product_id=3349, key="ICVLD-VVSZR-ZTICT-YKGXL", \
3232
machine_code=Helpers.GetMachineCode())
3333

34-
if res[0] == None not Helpers.IsOnRightMachine(res[0]):
34+
if res[0] == None or not Helpers.IsOnRightMachine(res[0]):
3535
print("An error occurred: {0}".format(res[1]))
3636
else:
3737
print("Success")
@@ -64,11 +64,53 @@ When loading it back, we can use the code below:
6464
```python
6565
# read license file from file
6666
with open('licensefile.skm', 'r') as f:
67-
license_key = LicenseKey.load_from_string(pubKey, f.read())
67+
license_key = LicenseKey.load_from_string(pubKey, f.read(), 30)
6868

69-
if not Helpers.IsOnRightMachine(license_key):
69+
if license_key != None not Helpers.IsOnRightMachine(license_key):
7070
print("NOTE: This license file does not belong to this machine.")
7171
else:
7272
print("Feature 1: " + str(license_key.f1))
7373
print("License expires: " + str(license_key.expires))
7474
```
75+
76+
If you want to make sure that the license file is not too old, you can specify the maximum number of days as shown below (after 30 days, this method will return NoneType).
77+
78+
```python
79+
# read license file from file
80+
with open('licensefile.skm', 'r') as f:
81+
license_key = LicenseKey.load_from_string(pubKey, f.read(), 30)
82+
83+
if license_key != None not Helpers.IsOnRightMachine(license_key):
84+
print("NOTE: This license file does not belong to this machine.")
85+
else:
86+
print("Feature 1: " + str(license_key.f1))
87+
print("License expires: " + str(license_key.expires))
88+
```
89+
90+
### Floating licenses
91+
[Floating licenses](https://help.cryptolens.io/licensing-models/floating) can be enabled by setting the floatingTimeInterval. Optionally, you can also allow customers to exceed the bound by specifying the maxOverdraft.
92+
93+
The code below has a floatingTimeInterval of 300 seconds and maxOverdraft set to 1. To support floating licenses with overdraft, the call to `Helpers.IsOnRightMachine(license, true, true)` needs two boolean flags to be set to true.
94+
95+
```python
96+
from licensing.models import *
97+
from licensing.methods import Key, Helpers
98+
99+
pubKey = "<RSAKeyValue><Modulus>sGbvxwdlDbqFXOMlVUnAF5ew0t0WpPW7rFpI5jHQOFkht/326dvh7t74RYeMpjy357NljouhpTLA3a6idnn4j6c3jmPWBkjZndGsPL4Bqm+fwE48nKpGPjkj4q/yzT4tHXBTyvaBjA8bVoCTnu+LiC4XEaLZRThGzIn5KQXKCigg6tQRy0GXE13XYFVz/x1mjFbT9/7dS8p85n8BuwlY5JvuBIQkKhuCNFfrUxBWyu87CFnXWjIupCD2VO/GbxaCvzrRjLZjAngLCMtZbYBALksqGPgTUN7ZM24XbPWyLtKPaXF2i4XRR9u6eTj5BfnLbKAU5PIVfjIS+vNYYogteQ==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>"
100+
101+
res = Key.activate(token="WyIyNjA1IiwiTjhZQUpIYXJPaVdBV0ozQUlKVC9tamdDbFZDRzhZRHpaU243L2R2eCJd",\
102+
rsa_pub_key=pubKey,\
103+
product_id=3349, key="MTMPW-VZERP-JZVNZ-SCPZM", \
104+
machine_code=Helpers.GetMachineCode(),\
105+
floating_time_interval=300,\
106+
max_overdraft=1)
107+
108+
if res[0] == None or not Helpers.IsOnRightMachine(res[0], is_floating_license=True, allow_overdraft=True):
109+
print("An error occured: {0}".format(res[1]))
110+
else:
111+
print("Success")
112+
113+
license_key = res[0]
114+
print("Feature 1: " + str(license_key.f1))
115+
print("License expires: " + str(license_key.expires))
116+
```

licensing/methods.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ def GetMachineCode():
7878

7979
return HelperMethods.get_SHA256(":".join(res))
8080

81-
def IsOnRightMachine(license_key):
81+
def IsOnRightMachine(license_key, is_floating_license = False, allow_overdraft=False):
8282

8383
"""
8484
Check if the device is registered with the license key.
@@ -89,10 +89,15 @@ def IsOnRightMachine(license_key):
8989
if license_key.activated_machines == None:
9090
return False
9191

92-
for act_machine in license_key.activated_machines:
93-
94-
if current_mid == act_machine.Mid:
92+
if is_floating_license:
93+
if len(license_key.activated_machines) == 1 and \
94+
(license_key.activated_machines[0].Mid[9:] == current_mid or \
95+
allow_overdraft and license_key.activated_machines[0].Mid[19:] == current_mid):
9596
return True
97+
else:
98+
for act_machine in license_key.activated_machines:
99+
if current_mid == act_machine.Mid:
100+
return True
96101

97102
return False
98103

licensing/models.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import base64
1010
import datetime
1111
import copy
12+
import time
1213

1314
from licensing.internal import HelperMethods
1415

@@ -60,8 +61,6 @@ def from_response(response):
6061

6162
obj = json.loads(base64.b64decode(response.license_key).decode('utf-8'))
6263

63-
64-
6564
return LicenseKey(obj["ProductId"], obj["ID"], obj["Key"], datetime.datetime.fromtimestamp(obj["Created"]),\
6665
datetime.datetime.fromtimestamp(obj["Expires"]), obj["Period"], obj["F1"], obj["F2"], \
6766
obj["F3"], obj["F4"],obj["F5"],obj["F6"], obj["F7"], \
@@ -79,12 +78,16 @@ def save_as_string(self):
7978
res.pop("license_key", None)
8079
return json.dumps(res)
8180

82-
def load_from_string(rsa_pub_key, string):
81+
def load_from_string(rsa_pub_key, string, signature_expiration_interval = -1):
8382
"""
8483
Loads a license from a string generated by save_as_string.
8584
Note: if an error occurs, None will be returned. An error can occur
8685
if the license string has been tampered with or if the public key is
8786
incorrectly formatted.
87+
88+
:param signature_expiration_interval: If the license key was signed,
89+
this method will check so that no more than "signatureExpirationInterval"
90+
days have passed since the last activation.
8891
"""
8992

9093
response = Response("","","","")
@@ -100,7 +103,14 @@ def load_from_string(rsa_pub_key, string):
100103
try:
101104
pubKey = RSAPublicKey.from_string(rsa_pub_key)
102105
if HelperMethods.verify_signature(response, pubKey):
103-
return LicenseKey.from_response(response)
106+
107+
licenseKey = LicenseKey.from_response(response)
108+
109+
if signature_expiration_interval > 0 and \
110+
(licenseKey.sign_date + datetime.timedelta(days=1*signature_expiration_interval) < datetime.datetime.utcnow()):
111+
return None
112+
113+
return licenseKey
104114
else:
105115
return None
106116
except Exception:

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
setup(
33
name = 'licensing', # How you named your package folder (MyLib)
44
packages = ['licensing'], # Chose the same as "name"
5-
version = '0.4', # Start with a small number and increase it with every change you make
5+
version = '0.5', # Start with a small number and increase it with every change you make
66
license='MIT', # Chose a license from here: https://help.github.com/articles/licensing-a-repository
77
description = 'Client library for Cryptolens licensing Web API.', # Give a short description about your library
88
author = 'Cryptolens AB', # Type in your name

0 commit comments

Comments
 (0)