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.2.0.tar.gz (10.7 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.2.0-py3-none-any.whl (8.8 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: icare_licensing-1.2.0.tar.gz
  • Upload date:
  • Size: 10.7 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.2.0.tar.gz
Algorithm Hash digest
SHA256 b72f88632779f7f4a9aef814b5e09585bbda24a94bc3a9e420fc7f7a7f9e9313
MD5 7ffd431c0f5857407bd74d4d7af14d9c
BLAKE2b-256 0a4afef59673506906a787af29ee6a66627f21bd9965039ef332068b6d298cbe

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for icare_licensing-1.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8c1c5a7b2b687bbb1de9619db5a155537d98a5eeb93a36e64cdde1dce2b7edd0
MD5 b908211b89104565df7362bdbd374f4a
BLAKE2b-256 0fa46fc713e2098058045a25b8522aab3ee721ca504aeeff2804caebb950290a

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