Skip to main content

Secure cryptographic offline-first licensing client library for Icare Licensing Service

Project description

Icare Licensing Client

icare-liecensing-client is an offline-first, cryptographically secure licensing client library for Python applications. It integrates seamlessly with the Icare licensing server using RSA-SHA256 signatures, device hardware bindings, and automated offline-resilient sync policies.


Features

  • Stable Hardware Binding (HWID): Generates a stable machine signature.
  • Offline Cryptographic Validation: Validates license state offline using RSA-SHA256.
  • Automated Sync Daemon: Runs in the background and pings the verification endpoint every 24 hours.
  • 3-Day Offline Grace Period: Remains fully functional offline for up to 3 days before requiring internet.
  • Instant Revocation Purge: Deletes local signatures and metadata immediately upon server-side license revocation or deletion to prevent offline bypass.

1. Installation

Install the package from your PyPI registry:

pip install icare-licensing

2. License Storage & File Location Policy

By default, the client library writes license.lic and license_metadata.json relative to the Current Working Directory (CWD) of the executing process.

Critical Production Guidelines

For desktop deployments or system-wide CLI tools, running relative to the CWD can lead to:

  1. Permission Denials (PermissionError): If the app is run from a read-only directory (e.g. Program Files or /usr/local/bin).
  2. Missing Licenses: If the user starts the application from a different terminal directory, the client will look in the wrong path and report the license is missing.

Recommendation: Use Absolute Paths

Always initialize the client with an absolute path pointing to a user-writable application directory (such as the user's home folder or standard application data directory).

import os
from icare_licensing import LicensingClient

# Determine a safe system path (e.g., ~/.config/my_app/ or %APPDATA%/my_app/)
app_folder = os.path.join(os.path.expanduser("~"), ".my_app")
os.makedirs(app_folder, exist_ok=True)

license_path = os.path.join(app_folder, "license.lic")

# Initialize client
client = LicensingClient(
    server_url="https://licensing.mycompany.com",
    license_file_path=license_path
)

Note: The metadata file (license_metadata.json) will automatically be generated in the same target folder.


3. Core Developer API

Licensing States

The library exposes six core status constants:

  • STATUS_VALID: License signature is cryptographically valid, matches machine HWID, is not expired, and is synced.
  • STATUS_MISSING: No license.lic file is present (Device needs activation).
  • STATUS_EXPIRED: The local or server expiration date has been exceeded.
  • STATUS_INVALID: The license cryptographic signature is corrupt, has been modified, or has been actively revoked/deleted on the server.
  • STATUS_REQUIRES_SYNC: The application has been running offline for more than 3 days and requires internet to refresh.
  • STATUS_UNKNOWN: State is not yet resolved.

4. Integration Template

Copy this robust integration template into your project's main entry point:

import os
import sys
from icare_licensing import (
    LicensingClient,
    STATUS_VALID,
    STATUS_REQUIRES_SYNC,
    STATUS_MISSING,
    STATUS_INVALID,
    STATUS_EXPIRED
)

def on_license_status_change(new_status):
    """
    Callback triggered when the license status transitions.
    NOTE: If running a GUI application (e.g., Tkinter/PyQt), make sure 
    to route UI-altering updates safely to the main thread.
    """
    print(f"[Licensing] Status changed to: {new_status}")
    
    if new_status == STATUS_VALID:
        print("Premium features unlocked!")
        # Proceed to launch normal application logic
        
    elif new_status == STATUS_REQUIRES_SYNC:
        print("Warning: internet connection required to verify license.")
        # Optional: Show a warning banner, but keep standard features unlocked
        
    elif new_status in (STATUS_MISSING, STATUS_INVALID, STATUS_EXPIRED):
        print("Security Lock: No valid license active.")
        # Action: Redirect user to your license activation overlay/screen
        # Lock down core software capabilities

def main():
    # 1. Setup secure storage paths
    app_folder = os.path.join(os.path.expanduser("~"), ".my_app")
    os.makedirs(app_folder, exist_ok=True)
    license_path = os.path.join(app_folder, "license.lic")

    # 2. Instantiate Client
    # max_offline_days determines how long the app can run offline (default: 3 days)
    client = LicensingClient(
        server_url="http://localhost:8081",
        license_file_path=license_path,
        status_callback=on_license_status_change,
        max_offline_days=3
    )

    # 3. Handle Initial State
    # Force a check immediately on startup
    client._run_check()

    if client.current_status == STATUS_MISSING:
        print("Application is unactivated.")
        # Example: prompt user for activation key in CLI
        # key = input("Enter Activation Key: ")
        # success, msg = client.activate_device(key)

    # 4. Start Background Protection Thread
    # Validates locally and checks online every 5 minutes (300 seconds)
    client.start_monitoring(interval_seconds=300)

if __name__ == "__main__":
    main()

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

icare_licensing-1.1.0.tar.gz (10.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

icare_licensing-1.1.0-py3-none-any.whl (8.7 kB view details)

Uploaded Python 3

File details

Details for the file icare_licensing-1.1.0.tar.gz.

File metadata

  • Download URL: icare_licensing-1.1.0.tar.gz
  • Upload date:
  • Size: 10.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for icare_licensing-1.1.0.tar.gz
Algorithm Hash digest
SHA256 04de05d25f05705f5002a0a205ea5dd3dc9b322f84f15662f619bfe4bc5c4b2d
MD5 a7de4ed0c4fd5e6c241ade40c6b74b49
BLAKE2b-256 2bc1197a130fdeaa6b30cccc6921809b85460c9cc4dc351936471a5af3d4d139

See more details on using hashes here.

File details

Details for the file icare_licensing-1.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for icare_licensing-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ccd90628c6fb5518f4843461395d880a55e42ec8d23f3e5390d2bff6a3214f51
MD5 a9041aa7ca5e3a36f2ba528f43220a90
BLAKE2b-256 44b41d22e87d71f74aff53d58994c2e941585a1e13886fe22b62a3d8af90357b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page