{"id":22271158,"url":"https://github.com/cryptolens/cryptolens-python","last_synced_at":"2025-05-15T20:07:14.825Z","repository":{"id":40680559,"uuid":"167148609","full_name":"Cryptolens/cryptolens-python","owner":"Cryptolens","description":"Cryptolens Client API for Python","archived":false,"fork":false,"pushed_at":"2024-12-17T18:01:26.000Z","size":144,"stargazers_count":199,"open_issues_count":4,"forks_count":38,"subscribers_count":15,"default_branch":"master","last_synced_at":"2025-04-19T02:15:38.099Z","etag":null,"topics":["license-checking","licensing-as-a-service","licensing-library","offline-licensing","python"],"latest_commit_sha":null,"homepage":"https://cryptolens.io/support-cycle/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Cryptolens.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-01-23T08:45:48.000Z","updated_at":"2025-04-16T06:55:18.000Z","dependencies_parsed_at":"2024-02-07T11:25:39.998Z","dependency_job_id":"7d280a7d-4716-4533-97c2-5e1fbc6e842a","html_url":"https://github.com/Cryptolens/cryptolens-python","commit_stats":null,"previous_names":[],"tags_count":50,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Cryptolens%2Fcryptolens-python","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Cryptolens%2Fcryptolens-python/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Cryptolens%2Fcryptolens-python/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Cryptolens%2Fcryptolens-python/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Cryptolens","download_url":"https://codeload.github.com/Cryptolens/cryptolens-python/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254414499,"owners_count":22067272,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["license-checking","licensing-as-a-service","licensing-library","offline-licensing","python"],"created_at":"2024-12-03T12:10:52.344Z","updated_at":"2025-05-15T20:07:09.690Z","avatar_url":"https://github.com/Cryptolens.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Cryptolens Client API for Python\n\n[![Downloads](https://pepy.tech/badge/licensing)](https://pepy.tech/project/licensing)\n[![Downloads](https://pepy.tech/badge/licensing/month)](https://pepy.tech/project/licensing)\n[![Downloads](https://pepy.tech/badge/licensing/week)](https://pepy.tech/project/licensing)\n\nThis library contains helper methods to verify license keys in Python.\n\nPython docs can be found here: https://help.cryptolens.io/api/python/\n\n**Autodesk Maya**: The Python2 version needs to be used, as described [here](https://cryptolens.io/2019/07/autodesk-maya-plugin-software-licensing/).\n\n**Autodesk Revit / Iron Python 2.7.3**: The Python2 version needs to be used with `HelperMethods.ironpython2730_legacy = True`.\n\n\u003e Please check out our guide about common errors and how to solve them: https://help.cryptolens.io/faq/index#troubleshooting-api-errors. For Python specific errors, please review [this section](#possible-errors).\n\n## Installation\n\n### Python 3\n```\npip install licensing\n```\n\n### Python 2\nPlease copy `cryptolens_python2.py` file into your project folder. The entire library is contained in that file.\n\u003e In the examples below, please disregard the imports and use only the following one:\n\n```python\nfrom cryptolens_python2 import *\n```\n\nIf you create a plugin for Autodesk Revit or use IronPython 2.7.3 or earlier, please also add the line below right after the import:\n\n```python\nHelperMethods.ironpython2730_legacy = True\n```\n\n## Example\n\n### Key verification\n\nThe code below will work exactly as the one explained in the [key verification tutorial](https://help.cryptolens.io/examples/key-verification).\n\nFirst, we need to add the namespaces:\n\nIn Python 3:\n```python\nfrom licensing.models import *\nfrom licensing.methods import Key, Helpers\n```\n\nIn Python 2:\n\n```python\nfrom cryptolens_python2 import *\n```\n\nNow we can perform the actual key verification:\n\n```python\nRSAPubKey = \"\u003cRSAKeyValue\u003e\u003cModulus\u003esGbvxwdlDbqFXOMlVUnAF5ew0t0WpPW7rFpI5jHQOFkht/326dvh7t74RYeMpjy357NljouhpTLA3a6idnn4j6c3jmPWBkjZndGsPL4Bqm+fwE48nKpGPjkj4q/yzT4tHXBTyvaBjA8bVoCTnu+LiC4XEaLZRThGzIn5KQXKCigg6tQRy0GXE13XYFVz/x1mjFbT9/7dS8p85n8BuwlY5JvuBIQkKhuCNFfrUxBWyu87CFnXWjIupCD2VO/GbxaCvzrRjLZjAngLCMtZbYBALksqGPgTUN7ZM24XbPWyLtKPaXF2i4XRR9u6eTj5BfnLbKAU5PIVfjIS+vNYYogteQ==\u003c/Modulus\u003e\u003cExponent\u003eAQAB\u003c/Exponent\u003e\u003c/RSAKeyValue\u003e\"\nauth = \"WyIyNTU1IiwiRjdZZTB4RmtuTVcrQlNqcSszbmFMMHB3aWFJTlBsWW1Mbm9raVFyRyJd==\"\n\nresult = Key.activate(token=auth,\\\n                   rsa_pub_key=RSAPubKey,\\\n                   product_id=3349, \\\n                   key=\"ICVLD-VVSZR-ZTICT-YKGXL\",\\\n                   machine_code=Helpers.GetMachineCode(v=2))\n\nif result[0] == None or not Helpers.IsOnRightMachine(result[0], v=2):\n    # an error occurred or the key is invalid or it cannot be activated\n    # (eg. the limit of activated devices was achieved)\n    print(\"The license does not work: {0}\".format(result[1]))\nelse:\n    # everything went fine if we are here!\n    print(\"The license is valid!\")\n    license_key = result[0]\n    print(\"Feature 1: \" + str(license_key.f1))\n    print(\"License expires: \" + str(license_key.expires))\n```\n\n* `RSAPubKey` - the RSA public key (can be found [here](https://app.cryptolens.io/docs/api/v3/QuickStart#api-keys), in *API Keys* section).\n* `token` - the access token (can be found [here](https://app.cryptolens.io/docs/api/v3/QuickStart#api-keys), in *API Keys* section).\n* `product_id` - the id of the product can be found on the product page.\n* `key` - the license key to be verified\n* `machine_code` - the unique id of the device.\n\n**Note:** The code above assumes that node-locking is enabled. By default, license keys are created with _Maximum Number of Machines_ set to zero, which deactivates node-locking. As a result, machines will not be registered and the call to `Helpers.IsOnRightMachine(result[0])` will return `False`. You can read more about this behaviour [here](https://help.cryptolens.io/faq/index#maximum-number-of-machines).\n\n### Offline activation (saving/loading licenses)\n\nAssuming the license key verification was successful, we can save the result in a file so that we can use it instead of contacting Cryptolens.\n\n```python\n# res is obtained from the code above\nif result[0] != None:\n    # saving license file to disk\n    with open('licensefile.skm', 'w') as f:\n        f.write(result[0].save_as_string())\n```\n\nWhen loading it back, we can use the code below:\n\n```python\n# read license file from file\nwith open('licensefile.skm', 'r') as f:\n    license_key = LicenseKey.load_from_string(pubKey, f.read())\n    \n    if license_key == None or not Helpers.IsOnRightMachine(license_key, v=2):\n        print(\"NOTE: This license file does not belong to this machine.\")\n    else:\n        print(\"Feature 1: \" + str(license_key.f1))\n        print(\"License expires: \" + str(license_key.expires))\n```\n\nIf 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).\n\n```python\n# read license file from file\nwith open('licensefile.skm', 'r') as f:\n    license_key = LicenseKey.load_from_string(pubKey, f.read(), 30)\n    \n    if license_key == None or not Helpers.IsOnRightMachine(license_key, v=2):\n        print(\"NOTE: This license file does not belong to this machine.\")\n    else:\n        print(\"Feature 1: \" + str(license_key.f1))\n        print(\"License expires: \" + str(license_key.expires))\n```\n\n### Floating licenses\n[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.\n\nThe 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.\n\n```python\nfrom licensing.models import *\nfrom licensing.methods import Key, Helpers\n\nRSAPubKey = \"\u003cRSAKeyValue\u003e\u003cModulus\u003esGbvxwdlDbqFXOMlVUnAF5ew0t0WpPW7rFpI5jHQOFkht/326dvh7t74RYeMpjy357NljouhpTLA3a6idnn4j6c3jmPWBkjZndGsPL4Bqm+fwE48nKpGPjkj4q/yzT4tHXBTyvaBjA8bVoCTnu+LiC4XEaLZRThGzIn5KQXKCigg6tQRy0GXE13XYFVz/x1mjFbT9/7dS8p85n8BuwlY5JvuBIQkKhuCNFfrUxBWyu87CFnXWjIupCD2VO/GbxaCvzrRjLZjAngLCMtZbYBALksqGPgTUN7ZM24XbPWyLtKPaXF2i4XRR9u6eTj5BfnLbKAU5PIVfjIS+vNYYogteQ==\u003c/Modulus\u003e\u003cExponent\u003eAQAB\u003c/Exponent\u003e\u003c/RSAKeyValue\u003e\"\nauth = \"WyIyNTU1IiwiRjdZZTB4RmtuTVcrQlNqcSszbmFMMHB3aWFJTlBsWW1Mbm9raVFyRyJd==\"\n\nresult = Key.activate(token=auth,\\\n                   rsa_pub_key=RSAPubKey,\\\n                   product_id=3349, \\\n                   key=\"ICVLD-VVSZR-ZTICT-YKGXL\",\\\n                   machine_code=Helpers.GetMachineCode(v=2),\\\n                   floating_time_interval=300,\\\n                   max_overdraft=1)\n\nif result[0] == None or not Helpers.IsOnRightMachine(result[0], is_floating_license=True, allow_overdraft=True, v=2):\n    print(\"An error occurred: {0}\".format(result[1]))\nelse:\n    print(\"Success\")\n    \n    license_key = result[0]\n    print(\"Feature 1: \" + str(license_key.f1))\n    print(\"License expires: \" + str(license_key.expires))\n```\n\n### Create Trial Key (verified trial)\n\n#### Idea\n\nA [trial key](https://help.cryptolens.io/examples/verified-trials) allows your users to evaluate some or all parts of your software for a limited period of time. The goal of trial keys is to set it up in such a way that you don’t need to manually create them, while still keeping everything secure.\n\nIn Cryptolens, all trial keys are bound to the device that requested them, which helps to prevent users from using the trial after reinstalling their device.\n\nYou can define which features should count as trial by [editing feature definitions](https://help.cryptolens.io/web-interface/feature-definitions) on the product page.\n\n#### Implementation\n\nThe code below shows how to create trial key. If the trial key is successful, `trial_key[0]` will contain the license key string. We then need to call `Key.Activate` (as shown in the earlier examples) with the obtained license key to verify the license.\n\n```python\nfrom licensing.models import *\nfrom licensing.methods import Key, Helpers\n\ntrial_key = Key.create_trial_key(\"WyIzODQ0IiwiempTRWs4SnBKTTArYUh3WkwyZ0VwQkVyeTlUVkRWK2ZTOS8wcTBmaCJd\", 3941, Helpers.GetMachineCode(v=2))\n\nif trial_key[0] == None:\n    print(\"An error occurred: {0}\".format(trial_key[1]))\n\n\nRSAPubKey = \"\u003cRSAKeyValue\u003e\u003cModulus\u003esGbvxwdlDbqFXOMlVUnAF5ew0t0WpPW7rFpI5jHQOFkht/326dvh7t74RYeMpjy357NljouhpTLA3a6idnn4j6c3jmPWBkjZndGsPL4Bqm+fwE48nKpGPjkj4q/yzT4tHXBTyvaBjA8bVoCTnu+LiC4XEaLZRThGzIn5KQXKCigg6tQRy0GXE13XYFVz/x1mjFbT9/7dS8p85n8BuwlY5JvuBIQkKhuCNFfrUxBWyu87CFnXWjIupCD2VO/GbxaCvzrRjLZjAngLCMtZbYBALksqGPgTUN7ZM24XbPWyLtKPaXF2i4XRR9u6eTj5BfnLbKAU5PIVfjIS+vNYYogteQ==\u003c/Modulus\u003e\u003cExponent\u003eAQAB\u003c/Exponent\u003e\u003c/RSAKeyValue\u003e\"\nauth = \"WyIyNTU1IiwiRjdZZTB4RmtuTVcrQlNqcSszbmFMMHB3aWFJTlBsWW1Mbm9raVFyRyJd==\"\n\nresult = Key.activate(token=auth,\\\n                   rsa_pub_key=RSAPubKey,\\\n                   product_id=3349, \\\n                   key=trial_key[0],\\\n                   machine_code=Helpers.GetMachineCode(v=2))\n\n\nif result[0] == None or not Helpers.IsOnRightMachine(result[0], v=2):\n    print(\"An error occurred: {0}\".format(result[1]))\nelse:\n    print(\"Success\")\n    \n    license_key = result[0]\n    print(\"Feature 1: \" + str(license_key.f1))\n    print(\"License expires: \" + str(license_key.expires))\n```\n\n### License server or custom endpoint\n\nTo forward requests to a local license server or a different API, you can set it using the `server_address` in HelperMethods, i.e.,\n\n```python\nHelperMethods.server_address = \"http://localhost:8080/api/\";\n```\nIt is important to include one */* in the end of the address as well as to attach the \"api\" suffix.\n\n### Other settings\n\n#### Proxy\n\nIf you have customers who want to use a proxy server, we recommend enabling the following setting before calling any other API method, such as Key.Activate.\n\n```python\nHelperMethods.proxy_experimental = True\n```\n\nThis will ensure that the underlying HTTP library (urllib) used by Cryptolens Python SDK will use the proxy configured on the OS level. The goal is to make this default behaviour in future versions of the library, once enough feedback is collected.\n\n#### SSL verification\nSSL verification can temporarily be disabled by adding the line below before any call to Key.Activate.\n\n```python\nHelperMethods.verify_SSL = False\n```\n\nThe Cryptolens Python SDK will verify that the license information has not changed since it left the server using your RSA Public Key. However, we recommend to keep this value unchanged.\n\n### Possible errors\n\n#### The expiration date cannot be converted to a datetime object. Please try setting the period to a lower value.\nThis error occurs when the timestamp for the expiration date received from the server exceeds the limit in Python. This typically occurs when the **Period** is set to a excessively large value, often to prevent the license from expiring. \n\nWhile Cryptolens requires a period (defaulted to 30) during the creation of a new license, this does not mark the license as time-limited. You can learn more about it [here](https://help.cryptolens.io/web-interface/keys-that-dont-expire). In essence, a license is treated as time-limited by either enforcing this in the Python code (e.g. if F1=true, the license is time-limited and so we check the expiration date against the current date, to see that it is still valid) or on the server side. On the server side, you can, for example, set up a feature that will automatically block expired licenses. You can read more about it [here](https://help.cryptolens.io/faq/index#blocking-expired-licenses).\n\nIn sum, to solve this issue, you can either follow one of the methods described above or set the period to a smaller value.\n\n#### Could not contact the server. Error message: \u003curlopen error [SSL: CERTIFICATE_VERIFY _FAILED] certificate verify failed: unable to get local issuer certificate (ssl.c:1125)\u003e\n\nThis error is thrown when the urllib library (a built in library in Python that we use to send HTTP requests) is unable to locate the CA files on the client machine. From our experience, this error occurs exclusively on Macs where the Python environment is incorrectly installed.\n\nTo solve this temporarily for **testing purposes**, you could temporary disable SSL verifications as described in [here](#ssl-verification), however, we do not recommend this in a production scenario. Instead, a better solution is to fix the underlying issue preventing the Python environment from finding the CA files.\n\nThis can be accomplished in at least two ways:\n\n##### Using certifi\nBefore calling any of the API methods (e.g. Key.activate), you can add the following code:\n\n```python\nimport certifi\nos.environ['SSL_CERT_FILE'] = certifi.where()\n```\n\nPlease note that this requires `certifi` package to be installed.\n\n##### Running a script in the Python environment\nAn alternative is to run script in their environment that should fix the issue. You can read more about it in this thread: https://github.com/Cryptolens/cryptolens-python/issues/65\n\n##### Summary\nThe key takeaway is that it is better to address the issue with missing CA on the user side, since this issue will typically be user-specific. If that is not possible, you can use the code above to manually set the path to CA files. Although we have mentioned turning off SSL verification temporarily, it should not be used in production. `Key.activate` takes care of signature verification internally, but some other methods do not. \n\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcryptolens%2Fcryptolens-python","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcryptolens%2Fcryptolens-python","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcryptolens%2Fcryptolens-python/lists"}