A command-line tool for obfuscating Python scripts, binding obfuscated scripts to specific machines, and setting expiration dates
—
PyArmor provides comprehensive license management for controlling access to obfuscated scripts through hardware binding, time-based restrictions, and custom user data. The licensing system enables software vendors to protect their applications and control distribution with flexible restriction mechanisms.
Generate license files with custom restrictions and hardware binding for obfuscated scripts.
def make_license_key(capsule, code: str, filename: str, **kwargs) -> None:
"""
Generate license key file with specified restrictions.
Args:
capsule: Protection capsule path or object
code (str): License registration code
filename (str): Output license file path
**kwargs: License options
- expired (str): Expiration date in YYYY-MM-DD format
- bind_disk (str): Bind to hard disk serial number
- bind_mac (str): Bind to MAC address
- bind_ipv4 (str): Bind to IPv4 address
- bind_domain (str): Bind to domain name
- bind_file (str): Bind to specific file checksum
- enable_period_mode (bool): Enable periodic validation
- period (int): Validation period in days
- data (str): Custom user data to embed
Raises:
LicenseError: If license generation fails
ValueError: If code format is invalid
BindingError: If hardware binding fails
"""
def generate_group_license(code: str, count: int, **kwargs) -> list:
"""
Generate multiple license files for group licensing.
Args:
code (str): Base license code
count (int): Number of licenses to generate
**kwargs: Group license options
- prefix (str): License file name prefix
- output (str): Output directory
- bind_template (str): Hardware binding template
Returns:
list: List of generated license file paths
"""
def make_trial_license(capsule, days: int, **kwargs) -> str:
"""
Generate time-limited trial license.
Args:
capsule: Protection capsule
days (int): Trial period in days
**kwargs: Trial options
- features (list): Enabled features for trial
- bind_data (str): Custom trial data
Returns:
str: Path to generated trial license
"""Handle PyArmor registration codes and license activation for commercial usage.
def get_registration_code() -> str:
"""
Get current PyArmor registration code.
Returns:
str: Current registration code or empty string if unregistered
"""
def query_keyinfo(key: str) -> dict:
"""
Query registration key information from server.
Args:
key (str): Registration key to query
Returns:
dict: Key information including features, expiration, device limits
- product (str): Product name
- version (str): License version
- lictype (str): License type (TRIAL, BASIC, PRO, etc.)
- features (list): Enabled features
- expired (str): Expiration date
- devices (int): Maximum device count
- platform (str): Platform restrictions
Raises:
NetworkError: If unable to connect to server
KeyError: If key is invalid or not found
"""
def activate_regcode(ucode: str) -> dict:
"""
Activate PyArmor registration code.
Args:
ucode (str): Registration code from purchase
Returns:
dict: Activation result with license information
Raises:
ActivationError: If activation fails
NetworkError: If server communication fails
"""
def register_keyfile(keyfile: str, upgrade: bool = None, legency: bool = False) -> None:
"""
Register PyArmor using license keyfile.
Args:
keyfile (str): Path to license keyfile (.zip or .txt)
upgrade (bool, optional): Upgrade existing license
legency (bool): Handle legacy license format
Raises:
RegistrationError: If registration fails
FileNotFoundError: If keyfile doesn't exist
FormatError: If keyfile format is invalid
"""
def upgrade_license(filename: str) -> dict:
"""
Upgrade existing license to newer version.
Args:
filename (str): License file to upgrade
Returns:
dict: Upgrade result information
"""Enhanced registration management with web integration and group licensing.
class Register:
"""
Modern license registration management.
"""
def __init__(self, ctx):
"""
Initialize register with context.
Args:
ctx (Context): PyArmor context instance
"""
def register_regfile(self, regfile: str) -> None:
"""
Register using registration file.
Args:
regfile (str): Registration file path
"""
def generate_group_device(self, device_id: int) -> None:
"""
Generate device file for group licensing.
Args:
device_id (int): Device ID (1-100)
"""
def check_group_license(self) -> dict:
"""
Check group license status and device allocation.
Returns:
dict: Group license information
"""
class WebRegister:
"""
Web-based registration with online validation.
"""
def check_request_interval(self) -> None:
"""
Check if sufficient time has passed since last request.
Raises:
RateLimitError: If too many requests made recently
"""
def register_group_device(self, regfile: str, device: int) -> None:
"""
Register device in group license online.
Args:
regfile (str): Group registration file
device (int): Device ID to register
"""
def request_ci_regfile(self, regfile: str) -> None:
"""
Request CI/CD pipeline registration file.
Args:
regfile (str): Base registration file
"""
def prepare(self, regfile: str, product: str, upgrade: bool = False) -> tuple:
"""
Prepare registration with validation.
Args:
regfile (str): Registration file path
product (str): Product name
upgrade (bool): Upgrade existing registration
Returns:
tuple: (registration_info, confirmation_message)
"""
def register(self, regfile: str, product: str, group: bool = False) -> None:
"""
Complete registration process.
Args:
regfile (str): Registration file
product (str): Product name
group (bool): Group license registration
"""
def upgrade_to_pro(self, regfile: str, product: str) -> None:
"""
Upgrade license to professional version.
Args:
regfile (str): Registration file
product (str): Product name
"""def show_hd_info(name: str = None) -> str:
"""
Display hardware information for binding configuration.
Args:
name (str, optional): Specific hardware component name
- 'disk': Hard disk serial numbers
- 'mac': MAC addresses
- 'ipv4': IPv4 addresses
- 'domain': Domain name
- 'cpu': CPU information
Returns:
str: Formatted hardware information
Example output:
Hardware information:
Disk serial number: ABCD1234567890
MAC address: 00:11:22:33:44:55
IPv4 address: 192.168.1.100
Domain name: example.com
"""
def get_bind_key(hdtype: str, name: str = None) -> str:
"""
Get hardware binding key for specific device.
Args:
hdtype (str): Hardware type ('disk', 'mac', 'ipv4', 'domain')
name (str, optional): Specific device name
Returns:
str: Hardware binding key
"""
def validate_bind_key(key: str, hdtype: str) -> bool:
"""
Validate hardware binding key against current system.
Args:
key (str): Hardware binding key to validate
hdtype (str): Expected hardware type
Returns:
bool: True if key matches current hardware
"""def check_license(license_file: str) -> dict:
"""
Validate license file and return restrictions.
Args:
license_file (str): Path to license file
Returns:
dict: License validation result
- valid (bool): License validity
- expired (str): Expiration date
- devices (list): Bound device information
- features (list): Enabled features
- data (str): Custom user data
Raises:
LicenseError: If license is invalid or corrupted
ExpiredError: If license has expired
BindingError: If hardware binding fails
"""
def enable_period_mode(license_file: str, period: int) -> None:
"""
Enable periodic license validation.
Args:
license_file (str): License file to modify
period (int): Validation period in days
"""
def validate_periodic_license() -> bool:
"""
Perform periodic license validation check.
Returns:
bool: True if validation passes
Raises:
ValidationError: If periodic validation fails
NetworkError: If unable to contact validation server
"""from pyarmor import utils
# Generate capsule
capsule = utils.make_capsule()
# Create basic license
utils.make_license_key(
capsule,
"MYAPP-USER001",
"licenses/user001.lic"
)
# Create time-limited license
utils.make_license_key(
capsule,
"MYAPP-TRIAL",
"licenses/trial.lic",
expired="2024-12-31"
)# Show available hardware information
print(utils.show_hd_info())
# Create MAC-bound license
utils.make_license_key(
capsule,
"MYAPP-MACHINE001",
"licenses/machine001.lic",
bind_mac="00:11:22:33:44:55"
)
# Create disk-bound license with expiration
utils.make_license_key(
capsule,
"MYAPP-WORKSTATION",
"licenses/workstation.lic",
bind_disk="ABCD1234567890",
expired="2025-06-30"
)
# Multiple binding constraints
utils.make_license_key(
capsule,
"MYAPP-SECURE",
"licenses/secure.lic",
bind_mac="00:11:22:33:44:55",
bind_ipv4="192.168.1.100",
bind_domain="company.com",
expired="2024-12-31"
)from pyarmor.register import generate_group_license
# Generate 10 licenses for group deployment
licenses = generate_group_license(
"MYAPP-GROUP001",
10,
prefix="dept_license_",
output="licenses/group/",
expired="2025-12-31"
)
for lic_path in licenses:
print(f"Generated: {lic_path}")# Create license with periodic checking
utils.make_license_key(
capsule,
"MYAPP-SUBSCRIPTION",
"licenses/subscription.lic",
enable_period_mode=True,
period=30, # Check every 30 days
expired="2025-12-31"
)
# Enable periodic mode on existing license
utils.enable_period_mode("licenses/subscription.lic", 7) # Weekly checksfrom pyarmor import register
# Check current registration
reg_code = register.get_registration_code()
if reg_code:
print(f"Registered with: {reg_code}")
else:
print("PyArmor is not registered")
# Query key information
try:
key_info = register.query_keyinfo("PYARMOR-KEY-XXXX")
print(f"Product: {key_info['product']}")
print(f"License Type: {key_info['lictype']}")
print(f"Features: {key_info['features']}")
print(f"Expires: {key_info['expired']}")
except Exception as e:
print(f"Key query failed: {e}")
# Register PyArmor
register.register_keyfile("pyarmor-regfile-xxxx.zip")from pyarmor.cli.register import Register, WebRegister
from pyarmor.cli.context import Context
ctx = Context()
# Local registration
reg = Register(ctx)
reg.register_regfile("pyarmor-regfile-xxxx.zip")
# Web registration
web_reg = WebRegister(ctx)
web_reg.check_request_interval() # Rate limiting
# Register with product binding
info, msg = web_reg.prepare("pyarmor-regcode-xxxx.txt", "MyProduct")
print(msg)
web_reg.register("pyarmor-regcode-xxxx.txt", "MyProduct")from pyarmor.utils import check_license
try:
# Validate license at application startup
license_info = check_license("app.lic")
if license_info['valid']:
print("License valid")
print(f"Expires: {license_info['expired']}")
# Check custom data
if 'data' in license_info:
print(f"User data: {license_info['data']}")
else:
print("Invalid license")
exit(1)
except Exception as e:
print(f"License validation failed: {e}")
exit(1)
# Periodic validation
if not validate_periodic_license():
print("Periodic validation failed")
exit(1)from pyarmor.utils import LicenseError, BindingError, ExpiredError
from pyarmor.register import RegistrationError, NetworkError
try:
# License operations
utils.make_license_key(capsule, "CODE", "license.lic",
bind_mac="invalid-mac")
except LicenseError as e:
print(f"License generation failed: {e}")
except BindingError as e:
print(f"Hardware binding failed: {e}")
try:
# Registration operations
register.register_keyfile("keyfile.zip")
except RegistrationError as e:
print(f"Registration failed: {e}")
except NetworkError as e:
print(f"Network error during registration: {e}")
try:
# License validation
license_info = check_license("app.lic")
except ExpiredError as e:
print(f"License expired: {e}")
except BindingError as e:
print(f"Hardware binding mismatch: {e}")Install with Tessl CLI
npx tessl i tessl/pypi-pyarmor