license
CLI
There’s a CLI tool to create and parse licenses called confirm-license
included in this package:
usage: confirm-license [-h] [-d] [-k KEY] {create,parse} ...
The CLI tool to create a confirm license.
positional arguments:
{create,parse}
optional arguments:
-h, --help show this help message and exit
-d, --debug activate the debug logging
-k KEY, --key KEY the key for the license hashing (defaults to confirm)
Classes
The classes for handling confirm licenses.
- exception confirm.utils.license.ExpiredLicense
Error which is thrown when the license is expired.
- exception confirm.utils.license.InvalidLicense
Error which is thrown when the license is invalid.
- class confirm.utils.license.License(key)
The license class which can be used to create and parse licenses.
- Parameters:
key (str) – The encryption key
Note
The data format of the license is properitary and is designed like this:
{Header} {Base64-Data} {Footer}
The
Header
&Footer
are fixed, while theBase64-Data
is a Base64 encoded string of the following data structure:{Optional-Data} {Expiry} {Hash}
The
Optional-Data
is unencoded/unencrypted data block which can include any custom data.The
Expiry
is an ISO 8601 expiration timestamp of the license in form of aExpiry: YYYY-MM-DDTHH:MM:SS
key-value pair. TheHash
is a SHA-2 hash of theOptional-Data
&Expiry
strings.Hint
A new license can be created like this:
>>> from datetime import datetime >>> lic_str = License(key='test').create(expiry=datetime(2021, 8, 5)) >>> print(lic_str) -----START LICENSE----- RXhwaXJ5OiAyMDIxLTA4LTA1VDAwOjAwOjAwCmQ4YWEzYjJjOWNlNjVhYTk1YmQ1 MTE2NzliZjFhMTI4NjU3NzY5N2M4NjNkYjk5NGEwZDYxMGZmNjk5OTI4NmE= -----END LICENSE-----
Additional data can be added like this:
>>> from datetime import datetime >>> lic_str = License(key='test').create(expiry=datetime(2021, 8, 5), data='spam') >>> print(lic_str) -----START LICENSE----- c3BhbQpFeHBpcnk6IDIwMjEtMDgtMDVUMDA6MDA6MDAKYTllNWIyMDVhMzljNzQ0 M2U3MGY1ZTcyZDAyMWZiNjRmZTg3NWFjYWQ3MDc1NGM2YTMwZTU2OWE2OTEzNTcy Nw== -----END LICENSE-----
A license can then be parsed like this:
>>> lic_str = ''' ... -----START LICENSE----- ... RXhwaXJ5OiAyMDk5LTA4LTA1VDAwOjAwOjAwCjA2ZGFhYWRlYjM3YjUzOGE0YmVj ... Yzg2NzVlYmI5NjJlYjhkZjQ0MDRjMmVmNjA4YTBhNWZlNmE0NmIxODcxZDU= ... -----END LICENSE----- ... ''' >>> License('test').parse(lic_str) 'Expiry: 2099-08-05T00:00:00'
An expired license will raise a
ExpiredLicense
exception:>>> lic_str = ''' ... -----START LICENSE----- ... RXhwaXJ5OiAyMDIxLTA4LTA1VDAwOjAwOjAwCmQ4YWEzYjJjOWNlNjVhYTk1YmQ1 ... MTE2NzliZjFhMTI4NjU3NzY5N2M4NjNkYjk5NGEwZDYxMGZmNjk5OTI4NmE= ... -----END LICENSE----- ... ''' >>> License('test').parse(lic_str) Traceback (most recent call last): ... confirm.utils.license.ExpiredLicense: License is expired since 2021-08-05 00:00:00
If the expiry timestamp is missing, a
InvalidLicense
exception is raised:>>> lic_str = ''' ... -----START LICENSE----- ... CmFkNzExNDhjNzlmMjFhYjllZWM1MWVhNWM3ZGQyYjY2ODc5MmY3YzBkMzUzNGFl ... NjZiMjJmNzFjNjE1MjNmYjM= ... -----END LICENSE----- ... ''' >>> License('test').parse(lic_str) Traceback (most recent call last): ... confirm.utils.license.InvalidLicense: No expiry timestamp found
An invalid hash will also result in a raised
InvalidLicense
exception:>>> lic_str = ''' ... -----START LICENSE----- ... RXhwaXJ5OiAyMDk5LTA4LTA1VDAwOjAwOjAwCjAwZGFhYWRlYjM3YjUzOGE0YmVj ... YzgwNzVlYmI5MDJlYjhkZjQ0MDRjMmVmMDA4YTBhNWZlMGE0MGIxODcxZDU= ... -----END LICENSE----- ... ''' >>> License('test').parse(lic_str) Traceback (most recent call last): ... confirm.utils.license.InvalidLicense: License hash is invalid
And finally, a completly missing license will also raise a
InvalidLicense
exception:>>> License('test').parse('no valid license') Traceback (most recent call last): ... confirm.utils.license.InvalidLicense: No valid license string found
- create(expiry, data=None)
Create a new license.
- Parameters:
expiry (datetime.datetime) – The expiration date
data (str) – Additional license data
- Returns:
The license string
- Return type:
str
- create_hash(data)
Create the hash for the data string.
- Parameters:
data (str) – The data string
- Returns:
The hash
- Return type:
str
- parse(license_string, verify=True)
Parse a license and unpack the data.
- Parameters:
license_string (str) – The license string
verify (bool) – Verify the license & expiry
- Returns:
The license data
- Return type:
- Raises:
InvalidLicense – When a parsing error occurs
ExpiredLicense – When the license is expired
- class confirm.utils.license.LicenseData
License data which acts like a string but will add an additional helper method which can be used to fetch values of colon-separated (
:
) key-value pairs.Hint
This string class works like this:
>>> input_str = ''' ... spam: eggs 1 ... spam: eggs 2 ... foo: bar 1 ... foo: bar 2 ... ''' >>> lic_str = LicenseData(input_str) >>> lic_str.get_values('spam') ['eggs 1', 'eggs 2'] >>> lic_str.get_values('FOO') ['bar 1', 'bar 2'] >>> lic_str.get_values('unavailable') []
The white space after the colon (
:
) is optional and superfluous white spaces will automatically be stripped:>>> input_str = ''' ... spam:eggs 1 ... spam: eggs 2 ... spam: eggs 3 ... ''' >>> lic_str = LicenseData(input_str) >>> lic_str.get_values('spam') ['eggs 1', 'eggs 2', 'eggs 3']
- get_values(key)
The values.
- Parameters:
key (str) – The key
- Returns:
The values matching the key
- Return type:
list
- exception confirm.utils.license.LicenseError
Error which is thrown when a license error occurs.