pyhwid-license
A secure, hardware-locked (HWID) licensing management system for Python applications. It features native, automated support for both MySQL and MongoDB databases, timezone-aware expiration checks, and license status toggling.
Key Features
- 🔐 Cross-Platform HWID Locking: Generates a secure, stable, and unique Hardware ID (HWID) based on machine characteristics (works on Windows, Linux, and macOS).
- 🗄️ Dual Database Support: Fully automated integration with MySQL/MariaDB (using
PyMySQL) and MongoDB (usingPyMongo). Databases, tables, collections, and unique indexes are created automatically on connect. - 🕒 Timezone-Aware Expiration: Automatically handles and compares all datetime records using timezone-aware UTC format to avoid
offset-naivevsoffset-awarecomparison exceptions. - 🛠️ Full License Lifecycle Actions: Easily create, validate, update, extend (+30 days, etc.), suspend/unsuspend, and delete licenses.
Installation
To install the package directly from PyPI:
pip install pyhwid-license
Or to install the package locally in developer/editable mode from the source directory:
pip install -e .
Quick Start Guide
1. Initializing LicenseManager
The LicenseManager is the primary entry point for managing licenses. It automatically creates the necessary database schema or collection indexes upon connection.
MySQL Connection
from pyhwid_license import LicenseManager
# Config dict matching pymysql.connect parameters
mysql_config = {
"host": "localhost",
"user": "root",
"password": "your_secure_password",
"database": "my_app_licenses",
"port": 3306
}
manager = LicenseManager(db_type="mysql", **mysql_config)
MongoDB Connection
from pyhwid_license import LicenseManager
manager = LicenseManager(
db_type="mongodb",
uri="mongodb://localhost:27017/",
database="my_app_licenses"
)
2. Basic Operations
Create a License Key
You can specify the maximum number of hardware bindings (max_hwids), validity duration, and client details.
res = manager.create_license(
client_name="John Doe",
client_email="john@example.com",
max_hwids=2, # Can be validated on up to 2 distinct machines
duration_days=30, # Expiration limit (Optional)
prefix="APP", # License key prefix (Optional, defaults to "LIC")
notes="Pro Plan Client"
)
if res["success"]:
license_data = res["license"]
print(f"Generated Key: {license_data['license_key']}")
Validate a License Key
When validating, the system reads the machine's HWID and binds it to the license automatically if there are open slots.
# Typically run inside your distributed client application
validation = manager.validate_license("APP-A93C-ML1L-NDOJ-784M", check_hwid=True)
if validation["status"] == "valid":
print("License is active and valid!")
print(f"Bound HWIDs: {validation['license']['used_hwids']}")
elif validation["status"] == "expired":
print("This license has expired.")
elif validation["status"] == "suspended":
print("This license was suspended by the administrator.")
elif validation["status"] == "hwid_limit_reached":
print("The maximum number of devices has been reached for this key.")
else:
print(f"Validation failed: {validation['message']}")
Manage and Update Licenses
# Suspend a license key
manager.update_license("LIC-KEY", {"status": "suspended"})
# Reset all bound Hardware IDs for a license (e.g., if client buys a new PC)
manager.reset_hwids("LIC-KEY")
# Extend expiration date by 30 days
from datetime import datetime, timezone, timedelta
lic = manager.get_license("LIC-KEY")
if lic["expires_at"]:
new_expiry = lic["expires_at"] + timedelta(days=30)
manager.update_license("LIC-KEY", {"expires_at": new_expiry, "status": "active"})
# Delete license
manager.delete_license("LIC-KEY")
API Reference
LicenseManager(db_type: Optional[str], db_instance: Optional[Any], **db_config)
Initializes database connections.
db_type:"mysql"or"mongodb".db_instance: Custom mock database adapter (useful for testing).**db_config: Connection settings matching the chosen database type.
create_license(client_name, client_email, max_hwids=1, duration_days=None, notes="", custom_key=None, prefix="LIC") -> dict
Creates a new license entry in the database.
validate_license(license_key, check_hwid=True, custom_hwid=None) -> dict
Performs status, expiration, and HWID validation. Returns a dictionary containing status ("valid", "expired", "suspended", "hwid_limit_reached", "invalid") and message.
list_licenses() -> list
Returns a list of all registered license records.
update_license(license_key, update_data) -> bool
Updates license attributes in the database.
delete_license(license_key) -> bool
Deletes a license record from the database.
reset_hwids(license_key) -> bool
Clears the list of registered HWIDs for the license.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Metadata
Release files for pyhwid-license 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pyhwid_license-1.0.0-cp313-cp313-win_amd64.whl | CPython 3.13 | CPython 3.13 | Windows x86-64 | Details |
Release files / pyhwid_license-1.0.0-cp313-cp313-win_amd64.whl
| Download URL | pyhwid_license-1.0.0-cp313-cp313-win_amd64.whl |
|---|---|
| Size | 547.2 kB |
| Tags | CPython 3.13 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
509e638a86d07f9c8c4d8c1cc91d94c617c11d0d1c697c9cd417c7636abce15d
|
|
BLAKE2b-256 checksum How to use checksums |
794d808291c72a657587eca799611ecc96da3b7c73a7274954767894b575f9c5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.1
|
Security for pyhwid-license 1.0.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.