Skip to main content

Secure cryptographic offline-first licensing client library for Icare licensing system

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 licensing_client 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 licensing_client 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.0.0.tar.gz (9.0 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.0.0-py3-none-any.whl (9.3 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: icare_licensing-1.0.0.tar.gz
  • Upload date:
  • Size: 9.0 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.0.0.tar.gz
Algorithm Hash digest
SHA256 78356d40b281fd0734e545cfdac45bdc2b4dac889f97bc68abfa3a1a9f577a89
MD5 a1f88a74d15495983d0206a01a46882a
BLAKE2b-256 64693523440b241b4f8aae0d5a6344c65c11ba1651f5d5a0028999282d797344

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for icare_licensing-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 28bbe2968dcd3c1f3ea63ad5a106cc30cf2981d10264e9c9a426f82f37b1f606
MD5 876318a002987ce393d051c63fdf98aa
BLAKE2b-256 7d3fd101899cf6b6d8aa8fb0920baf68522a49cfdd6c64a163ec4a34f6d46612

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