pyarmor 8.2.8__zip → 8.2.9__zip
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pyarmor-8.2.8 → pyarmor-8.2.9}/PKG-INFO +1 -1
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/cli/__init__.py +1 -1
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/cli/__main__.py +3 -4
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/cli/default.cfg +3 -3
- pyarmor-8.2.9/pyarmor/cli/docker.py +148 -0
- pyarmor-8.2.8/src/cli/docker.py → pyarmor-8.2.9/pyarmor/cli/group.py +2 -54
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/cli/register.py +3 -1
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/config.py +1 -1
- pyarmor-8.2.9/pyarmor/pyarmor-deprecated.py +843 -0
- pyarmor-8.2.9/pyarmor/pyimcore.py +65 -0
- {pyarmor-8.2.8 → pyarmor-8.2.9}/pyarmor.egg-info/PKG-INFO +1 -1
- pyarmor-8.2.9/pyarmor.egg-info/SOURCES.txt +115 -0
- {pyarmor-8.2.8 → pyarmor-8.2.9}/pyarmor.egg-info/entry_points.txt +1 -0
- pyarmor-8.2.9/pyarmor.egg-info/requires.txt +1 -0
- {pyarmor-8.2.8 → pyarmor-8.2.9}/setup.py +3 -2
- pyarmor-8.2.8/pyarmor.egg-info/SOURCES.txt +0 -112
- pyarmor-8.2.8/pyarmor.egg-info/requires.txt +0 -1
- {pyarmor-8.2.8 → pyarmor-8.2.9}/MANIFEST.in +0 -0
- {pyarmor-8.2.8 → pyarmor-8.2.9}/README.md +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/README.rst +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/__init__.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/benchmark.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/build_meta.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/cli/bootstrap.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/cli/config.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/cli/context.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/cli/generate.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/cli/merge.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/cli/mixer.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/cli/plugin.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/cli/public_capsule.zip +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/cli/repack.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/cli/resource.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/cli/shell.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/cobuilder.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/README-ZH.md +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/README.md +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/build-for-exe.bat +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/build-for-freeze.bat +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/build-with-project.bat +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/build-with-project.sh +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/cx_Freeze/hello.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/cx_Freeze/queens.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/cx_Freeze/setup.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/helloworld/foo.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/obfuscate-app.bat +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/obfuscate-app.sh +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/obfuscate-pkg.bat +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/obfuscate-pkg.sh +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/pack-obfuscated-scripts.bat +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/pack-obfuscated-scripts.sh +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/py2exe/hello.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/py2exe/queens.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/py2exe/setup.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/pybench/Arithmetic.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/pybench/Calls.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/pybench/CommandLine.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/pybench/Constructs.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/pybench/Dict.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/pybench/Exceptions.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/pybench/Imports.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/pybench/Instances.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/pybench/Lists.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/pybench/Lookups.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/pybench/NewInstances.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/pybench/Numbers.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/pybench/Setup.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/pybench/Strings.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/pybench/Tuples.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/pybench/With.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/pybench/clockres.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/pybench/package/__init__.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/pybench/package/submodule.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/pybench/pybench.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/pybench/systimes.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/simple/queens.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/testmod/hello.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/testmod/queens.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/testpkg/main.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/testpkg/mypkg/__init__.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/examples/testpkg/mypkg/foo.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/helper/__init__.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/helper/build_data_module.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/helper/buildext.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/helper/get_bind_key.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/helper/get_license_info.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/helper/get_platform_name.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/helper/merge.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/helper/repack.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/helper/superuntime.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/license.tri +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/packer.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/platforms/darwin/x86_64/_pytransform.dylib +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/platforms/linux/x86/_pytransform.so +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/platforms/linux/x86_64/_pytransform.so +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/platforms/windows/x86/_pytransform.dll +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/platforms/windows/x86_64/_pytransform.dll +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/plugins/README.md +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/plugins/check_ntp_time.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/polyfills/__init__.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/polyfills/argparse.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/product.key +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/project.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/protect_code.pt +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/protect_code2.pt +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/public.key +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/public_capsule.zip +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/pyarmor-webui.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/pyarmor.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/pyshield.key +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/pyshield.lic +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/pytransform.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/reform.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/register.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/sppmode.py +0 -0
- {pyarmor-8.2.8/src → pyarmor-8.2.9/pyarmor}/utils.py +0 -0
- {pyarmor-8.2.8 → pyarmor-8.2.9}/pyarmor.egg-info/dependency_links.txt +0 -0
- {pyarmor-8.2.8 → pyarmor-8.2.9}/pyarmor.egg-info/top_level.txt +0 -0
- {pyarmor-8.2.8 → pyarmor-8.2.9}/setup.cfg +0 -0
|
@@ -0,0 +1,843 @@
|
|
|
1
|
+
#! /usr/bin/env python
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
#
|
|
4
|
+
#############################################################
|
|
5
|
+
# #
|
|
6
|
+
# Copyright @ 2013 - 2017 Dashingsoft corp. #
|
|
7
|
+
# All rights reserved. #
|
|
8
|
+
# #
|
|
9
|
+
# pyarmor #
|
|
10
|
+
# #
|
|
11
|
+
# Version: 1.7.0 - 3.3.0 #
|
|
12
|
+
# #
|
|
13
|
+
#############################################################
|
|
14
|
+
#
|
|
15
|
+
# DEPRECATED from v3.4. It will be replaced by pyarmor2.py
|
|
16
|
+
# from v4.
|
|
17
|
+
#
|
|
18
|
+
# @File: pyarmor.py
|
|
19
|
+
#
|
|
20
|
+
# @Author: Jondy Zhao(jondy.zhao@gmail.com)
|
|
21
|
+
#
|
|
22
|
+
# @Create Date: 2013/07/24
|
|
23
|
+
#
|
|
24
|
+
# @Description:
|
|
25
|
+
#
|
|
26
|
+
# A tool used to import or un encrypted python scripts.
|
|
27
|
+
#
|
|
28
|
+
from distutils.filelist import FileList
|
|
29
|
+
from distutils.text_file import TextFile
|
|
30
|
+
from distutils.util import get_platform
|
|
31
|
+
|
|
32
|
+
import fnmatch
|
|
33
|
+
import getopt
|
|
34
|
+
import glob
|
|
35
|
+
import imp
|
|
36
|
+
import logging
|
|
37
|
+
import os
|
|
38
|
+
import shutil
|
|
39
|
+
import sys
|
|
40
|
+
import tempfile
|
|
41
|
+
import time
|
|
42
|
+
from zipfile import ZipFile
|
|
43
|
+
|
|
44
|
+
try:
|
|
45
|
+
unhexlify = bytes.fromhex
|
|
46
|
+
except Exception:
|
|
47
|
+
from binascii import a2b_hex as unhexlify
|
|
48
|
+
|
|
49
|
+
from config import (version, version_info)
|
|
50
|
+
|
|
51
|
+
dll_name = '_pytransform'
|
|
52
|
+
dll_ext = '.dylib' if sys.platform == 'darwin' \
|
|
53
|
+
else '.dll' if sys.platform in ('win32', 'cygwin') else '.so'
|
|
54
|
+
|
|
55
|
+
# Extra suffix char for encrypted python scripts
|
|
56
|
+
ext_char = 'e'
|
|
57
|
+
|
|
58
|
+
wrap_runner = '''import pyimcore
|
|
59
|
+
from pytransform import exec_file
|
|
60
|
+
exec_file('%s')
|
|
61
|
+
'''
|
|
62
|
+
|
|
63
|
+
trial_info = '''
|
|
64
|
+
You're using trail version. Free trial version never expires,
|
|
65
|
+
the limitations are
|
|
66
|
+
|
|
67
|
+
- The maximum size of code object is 35728 bytes in trial version
|
|
68
|
+
- The scripts obfuscated by trial version are not private. It means
|
|
69
|
+
anyone could generate the license file which works for these
|
|
70
|
+
obfuscated scripts.
|
|
71
|
+
|
|
72
|
+
A registration code is required to obfuscate big code object or
|
|
73
|
+
generate private obfuscated scripts.
|
|
74
|
+
|
|
75
|
+
If PyArmor is helpful for you, please purchase one by visiting
|
|
76
|
+
|
|
77
|
+
https://order.shareit.com/cart/add?vendorid=200089125&PRODUCT[300871197]=1
|
|
78
|
+
|
|
79
|
+
If you have received a registration code, run the following command to
|
|
80
|
+
make it effective::
|
|
81
|
+
|
|
82
|
+
pyarmor register REGISTRATION_CODE
|
|
83
|
+
|
|
84
|
+
Enjoy it!
|
|
85
|
+
|
|
86
|
+
'''
|
|
87
|
+
|
|
88
|
+
help_footer = '''
|
|
89
|
+
For more information, refer to http://pyarmor.dashingsoft.com
|
|
90
|
+
'''
|
|
91
|
+
|
|
92
|
+
# The last three components of the filename before the extension are
|
|
93
|
+
# called "compatibility tags." The compatibility tags express the
|
|
94
|
+
# package's basic interpreter requirements and are detailed in PEP
|
|
95
|
+
# 425(https://www.python.org/dev/peps/pep-0425).
|
|
96
|
+
plat_name = get_platform().split('-')
|
|
97
|
+
plat_name = '_'.join(plat_name if len(plat_name) < 3 else plat_name[0:3:2])
|
|
98
|
+
plat_name = plat_name.replace('i586', 'i386') \
|
|
99
|
+
.replace('i686', 'i386') \
|
|
100
|
+
.replace('armv7l', 'armv7') \
|
|
101
|
+
.replace('intel', 'x86_64')
|
|
102
|
+
|
|
103
|
+
def _import_pytransform():
|
|
104
|
+
try:
|
|
105
|
+
m = __import__('pytransform')
|
|
106
|
+
if hasattr(m, 'plat_path'):
|
|
107
|
+
m.plat_path = 'platforms'
|
|
108
|
+
m.pyarmor_init(is_runtime=1)
|
|
109
|
+
return m
|
|
110
|
+
except Exception:
|
|
111
|
+
pass
|
|
112
|
+
logging.info('Searching pytransform library ...')
|
|
113
|
+
path = sys.rootdir
|
|
114
|
+
pname = plat_name.replace('i586', 'i386').replace('i686', 'i386')
|
|
115
|
+
src = os.path.join(path, 'platforms', pname, dll_name + dll_ext)
|
|
116
|
+
if os.path.exists(src):
|
|
117
|
+
logging.info('Find pytransform library "%s"', src)
|
|
118
|
+
logging.info('Copy %s to %s', src, path)
|
|
119
|
+
shutil.copy(src, path)
|
|
120
|
+
m = __import__('pytransform')
|
|
121
|
+
if hasattr(m, 'plat_path'):
|
|
122
|
+
m.plat_path = 'platforms'
|
|
123
|
+
m.pyarmor_init(is_runtime=1)
|
|
124
|
+
logging.info('Load pytransform OK.')
|
|
125
|
+
return m
|
|
126
|
+
logging.error('No library %s found', src)
|
|
127
|
+
|
|
128
|
+
def _get_registration_code():
|
|
129
|
+
try:
|
|
130
|
+
code = pytransform.get_registration_code()
|
|
131
|
+
except Exception:
|
|
132
|
+
code = ''
|
|
133
|
+
return code
|
|
134
|
+
|
|
135
|
+
def checklicense(func):
|
|
136
|
+
# Fix python25 no "as" keyword in statement "except"
|
|
137
|
+
exc_msg = lambda : str(sys.exc_info()[1])
|
|
138
|
+
def wrap(*arg, **kwargs):
|
|
139
|
+
code = _get_registration_code()
|
|
140
|
+
if code == '':
|
|
141
|
+
sys.stderr.write('PyArmor Trial Version %s\n' % version)
|
|
142
|
+
sys.stderr.write(trial_info)
|
|
143
|
+
else:
|
|
144
|
+
sys.stderr.write('PyArmor Version %s\n' % version)
|
|
145
|
+
try:
|
|
146
|
+
func(*arg, **kwargs)
|
|
147
|
+
except RuntimeError:
|
|
148
|
+
logging.error(exc_msg())
|
|
149
|
+
except getopt.GetoptError:
|
|
150
|
+
logging.error(exc_msg())
|
|
151
|
+
except pytransform.PytransformError:
|
|
152
|
+
logging.error(exc_msg())
|
|
153
|
+
wrap.__doc__ = func.__doc__
|
|
154
|
+
return wrap
|
|
155
|
+
|
|
156
|
+
def show_version_info(verbose=True):
|
|
157
|
+
code = _get_registration_code()
|
|
158
|
+
trial = ' Trial' if code == '' else ''
|
|
159
|
+
print('PyArmor%s Version %s' % (trial, version))
|
|
160
|
+
if verbose:
|
|
161
|
+
print(version_info)
|
|
162
|
+
if code == '':
|
|
163
|
+
print(trial_info)
|
|
164
|
+
print(help_footer)
|
|
165
|
+
|
|
166
|
+
def show_hd_info():
|
|
167
|
+
pytransform.show_hd_info()
|
|
168
|
+
|
|
169
|
+
def usage(command=None):
|
|
170
|
+
'''
|
|
171
|
+
Usage: pyarmor [command name] [options]
|
|
172
|
+
|
|
173
|
+
Command name can be one of the following list
|
|
174
|
+
|
|
175
|
+
help Show this usage
|
|
176
|
+
version Show version information
|
|
177
|
+
capsule Generate project capsule used to encrypted files
|
|
178
|
+
encrypt Encrypt the scripts
|
|
179
|
+
license Generate registration code
|
|
180
|
+
|
|
181
|
+
If you want to know the usage of each command, type the
|
|
182
|
+
following command:
|
|
183
|
+
|
|
184
|
+
pyarmor help [command name]
|
|
185
|
+
|
|
186
|
+
and you can type the left match command, such as
|
|
187
|
+
|
|
188
|
+
pyarmor c
|
|
189
|
+
or pyarmor cap
|
|
190
|
+
or pyarmor capsule
|
|
191
|
+
|
|
192
|
+
'''
|
|
193
|
+
show_version_info(verbose=False)
|
|
194
|
+
|
|
195
|
+
if command is None:
|
|
196
|
+
print(usage.__doc__)
|
|
197
|
+
else:
|
|
198
|
+
funcname = 'do_' + command
|
|
199
|
+
func = globals().get(funcname, usage)
|
|
200
|
+
print(func.__doc__)
|
|
201
|
+
print(help_footer)
|
|
202
|
+
|
|
203
|
+
def make_capsule(rootdir=None, filename='project.zip'):
|
|
204
|
+
'''Generate all the files used by running encrypted scripts, pack all
|
|
205
|
+
of them to a zip file.
|
|
206
|
+
|
|
207
|
+
rootdir pyarmor root dir, where you can find license files,
|
|
208
|
+
auxiliary library and pyshield extension module.
|
|
209
|
+
|
|
210
|
+
filename output filename, the default value is project.zip
|
|
211
|
+
|
|
212
|
+
Return True if sucess, otherwise False or raise exception
|
|
213
|
+
'''
|
|
214
|
+
try:
|
|
215
|
+
if rootdir is None:
|
|
216
|
+
rootdir = sys.rootdir
|
|
217
|
+
except AttributeError:
|
|
218
|
+
rootdir = os.path.dirname(os.path.abspath(sys.argv[0]))
|
|
219
|
+
logging.info('Rootdir is %s', rootdir)
|
|
220
|
+
filelist = 'public.key', 'pyimcore.py', 'pytransform.py'
|
|
221
|
+
for x in filelist:
|
|
222
|
+
src = os.path.join(rootdir, x)
|
|
223
|
+
if not os.path.exists(src):
|
|
224
|
+
raise RuntimeError('No %s found in the rootdir' % src)
|
|
225
|
+
|
|
226
|
+
licfile = os.path.join(rootdir, 'license.lic')
|
|
227
|
+
if not os.path.exists(licfile):
|
|
228
|
+
raise RuntimeError('Missing license file %s' % licfile)
|
|
229
|
+
|
|
230
|
+
logging.info('Generating project key ...')
|
|
231
|
+
pri, pubx, capkey, lic = pytransform.generate_project_capsule(licfile)
|
|
232
|
+
logging.info('Generating project OK.')
|
|
233
|
+
logging.info('Writing capsule to %s ...', filename)
|
|
234
|
+
myzip = ZipFile(filename, 'w')
|
|
235
|
+
try:
|
|
236
|
+
myzip.write(os.path.join(rootdir, 'public.key'), 'pyshield.key')
|
|
237
|
+
myzip.writestr('pyshield.lic', capkey)
|
|
238
|
+
myzip.write(os.path.join(rootdir, 'pyimcore.py'), 'pyimcore.py')
|
|
239
|
+
myzip.write(os.path.join(rootdir, 'pytransform.py'), 'pytransform.py')
|
|
240
|
+
myzip.writestr('private.key', pri)
|
|
241
|
+
myzip.writestr('product.key', pubx)
|
|
242
|
+
myzip.writestr('license.lic', lic)
|
|
243
|
+
finally:
|
|
244
|
+
myzip.close()
|
|
245
|
+
logging.info('Write project capsule OK.')
|
|
246
|
+
|
|
247
|
+
def encrypt_files(files, prokey, mode=8, output=None):
|
|
248
|
+
'''Encrypt all the files, all the encrypted scripts will be plused with
|
|
249
|
+
a suffix 'e', for example, hello.py -> hello.pye
|
|
250
|
+
|
|
251
|
+
files list all the scripts
|
|
252
|
+
prokey project key file used to encrypt scripts
|
|
253
|
+
output output directory. If None, the output file will be saved
|
|
254
|
+
in the same path as the original script
|
|
255
|
+
|
|
256
|
+
Return None if sucess, otherwise raise exception
|
|
257
|
+
'''
|
|
258
|
+
ext = '.py' if mode in (7, 8, 9, 10, 11, 12, 13, 14) else \
|
|
259
|
+
'.pyc' if mode in (1, 3, 4, 5, 6) else '.py' + ext_char
|
|
260
|
+
if output is None:
|
|
261
|
+
fn = lambda a, b: b[1] + ext
|
|
262
|
+
else:
|
|
263
|
+
# fn = lambda a, b : os.path.join(a, os.path.basename(b) + ch)
|
|
264
|
+
# fn = lambda a, b: os.path.join(a, b[1] + ext)
|
|
265
|
+
if not os.path.exists(output):
|
|
266
|
+
os.makedirs(output)
|
|
267
|
+
def _get_path(a, b):
|
|
268
|
+
p = os.path.join(a, b[1] + ext)
|
|
269
|
+
d = os.path.dirname(p)
|
|
270
|
+
if not os.path.exists(d):
|
|
271
|
+
os.makedirs(d)
|
|
272
|
+
return p
|
|
273
|
+
fn = _get_path
|
|
274
|
+
flist = []
|
|
275
|
+
for x in files:
|
|
276
|
+
flist.append((x[0], fn(output, x)))
|
|
277
|
+
logging.info('Encrypt %s to %s', *flist[-1])
|
|
278
|
+
|
|
279
|
+
if len(flist[:1]) == 0:
|
|
280
|
+
logging.info('No any script specified')
|
|
281
|
+
else:
|
|
282
|
+
if not os.path.exists(prokey):
|
|
283
|
+
raise RuntimeError('Missing project key "%s"' % prokey)
|
|
284
|
+
pytransform.encrypt_project_files(prokey, tuple(flist), mode)
|
|
285
|
+
logging.info('Encrypt all scripts OK.')
|
|
286
|
+
|
|
287
|
+
def make_license(capsule, filename, code):
|
|
288
|
+
myzip = ZipFile(capsule, 'r')
|
|
289
|
+
myzip.extract('private.key', tempfile.gettempdir())
|
|
290
|
+
prikey = os.path.join(tempfile.tempdir, 'private.key')
|
|
291
|
+
try:
|
|
292
|
+
pytransform.generate_license_file(filename, prikey, code)
|
|
293
|
+
finally:
|
|
294
|
+
os.remove(prikey)
|
|
295
|
+
|
|
296
|
+
@checklicense
|
|
297
|
+
def do_capsule(argv):
|
|
298
|
+
'''Usage: pyarmor capsule [OPTIONS] [NAME]
|
|
299
|
+
|
|
300
|
+
Generate a capsule which used to encrypt/decrypt python scripts later,
|
|
301
|
+
it will generate random capsule when run this command again. Note that
|
|
302
|
+
the trial version of PyArmor will always generate same project capsule
|
|
303
|
+
|
|
304
|
+
Generately, one project, one capsule.
|
|
305
|
+
|
|
306
|
+
Available options:
|
|
307
|
+
|
|
308
|
+
-O, --output=DIR [option] The path used to save license file.
|
|
309
|
+
|
|
310
|
+
-f, --force [option] Overwrite output file even it exists.
|
|
311
|
+
|
|
312
|
+
For example,
|
|
313
|
+
|
|
314
|
+
- Generate default capsule "project.zip":
|
|
315
|
+
|
|
316
|
+
pyarmor capsule project
|
|
317
|
+
|
|
318
|
+
- Generate a capsule "mycapsules/foo.zip":
|
|
319
|
+
|
|
320
|
+
pyarmor capsule --output mycapsules foo
|
|
321
|
+
|
|
322
|
+
'''
|
|
323
|
+
opts, args = getopt.getopt(argv, 'fO:', ['force', 'output='])
|
|
324
|
+
|
|
325
|
+
output = os.getcwd()
|
|
326
|
+
overwrite = False
|
|
327
|
+
for o, a in opts:
|
|
328
|
+
if o in ('-O', '--output'):
|
|
329
|
+
output = a
|
|
330
|
+
elif o in ('-f', '--force'):
|
|
331
|
+
overwrite = True
|
|
332
|
+
|
|
333
|
+
if len(args) == 0:
|
|
334
|
+
filename = os.path.join(output, 'project.zip')
|
|
335
|
+
else:
|
|
336
|
+
filename = os.path.join(output, '%s.zip' % args[0])
|
|
337
|
+
|
|
338
|
+
if os.path.exists(filename) and not overwrite:
|
|
339
|
+
logging.info("Specify -f to overwrite it if you really want to do")
|
|
340
|
+
raise RuntimeError("Capsule %s already exists" % filename)
|
|
341
|
+
|
|
342
|
+
if not os.path.exists(output):
|
|
343
|
+
logging.info("Make output path %s", output)
|
|
344
|
+
os.makedirs(output)
|
|
345
|
+
|
|
346
|
+
logging.info('Output filename is %s', filename)
|
|
347
|
+
make_capsule(sys.rootdir, filename)
|
|
348
|
+
logging.info('Generate capsule OK.')
|
|
349
|
+
|
|
350
|
+
def _parse_template_file(filename, path=None):
|
|
351
|
+
template = TextFile(filename,
|
|
352
|
+
strip_comments=1,
|
|
353
|
+
skip_blanks=1,
|
|
354
|
+
join_lines=1,
|
|
355
|
+
lstrip_ws=1,
|
|
356
|
+
rstrip_ws=1,
|
|
357
|
+
collapse_join=1)
|
|
358
|
+
lines = template.readlines()
|
|
359
|
+
|
|
360
|
+
filelist = FileList()
|
|
361
|
+
try:
|
|
362
|
+
if path is not None and not path == os.getcwd():
|
|
363
|
+
oldpath = os.getcwd()
|
|
364
|
+
os.chdir(path)
|
|
365
|
+
else:
|
|
366
|
+
oldpath = None
|
|
367
|
+
|
|
368
|
+
for line in lines:
|
|
369
|
+
filelist.process_template_line(line)
|
|
370
|
+
finally:
|
|
371
|
+
if oldpath is not None:
|
|
372
|
+
os.chdir(oldpath)
|
|
373
|
+
return filelist.files
|
|
374
|
+
|
|
375
|
+
def _parse_file_args(args, srcpath=None):
|
|
376
|
+
filelist = []
|
|
377
|
+
|
|
378
|
+
if srcpath is None:
|
|
379
|
+
path, n = '', 0
|
|
380
|
+
else:
|
|
381
|
+
path, n = srcpath, len(srcpath) + 1
|
|
382
|
+
|
|
383
|
+
if len(args) == 1 and args[0][0] == '@' and args[0].endswith('MANIFEST.in'):
|
|
384
|
+
for x in _parse_template_file(args[0][1:], path=srcpath):
|
|
385
|
+
filelist.append((os.path.join(path, x), os.path.splitext(x)[0]))
|
|
386
|
+
return filelist
|
|
387
|
+
|
|
388
|
+
patterns = []
|
|
389
|
+
for arg in args:
|
|
390
|
+
if arg[0] == '@':
|
|
391
|
+
f = open(arg[1:], 'r')
|
|
392
|
+
for pattern in f.read().splitlines():
|
|
393
|
+
if not pattern.strip() == '':
|
|
394
|
+
patterns.append(pattern.strip())
|
|
395
|
+
f.close()
|
|
396
|
+
else:
|
|
397
|
+
patterns.append(arg)
|
|
398
|
+
|
|
399
|
+
for pat in patterns:
|
|
400
|
+
for name in glob.glob(os.path.join(path, pat)):
|
|
401
|
+
p = os.path.splitext(name)
|
|
402
|
+
filelist.append((name, p[0][n:]))
|
|
403
|
+
|
|
404
|
+
return filelist
|
|
405
|
+
|
|
406
|
+
@checklicense
|
|
407
|
+
def do_encrypt(argv):
|
|
408
|
+
'''Usage: pyarmor encrypt [OPTIONS] [File Patterns or @Filename]
|
|
409
|
+
|
|
410
|
+
Encrpty the files list in the command line, you can use a specified
|
|
411
|
+
pattern according to the rules used by the Unix shell. No tilde
|
|
412
|
+
expansion is done, but *, ?, and character ranges expressed with []
|
|
413
|
+
will be correctly matched.
|
|
414
|
+
|
|
415
|
+
You can either list file patterns in one file, one pattern one line,
|
|
416
|
+
then add a prefix '@' to the filename.
|
|
417
|
+
|
|
418
|
+
All the files will be encrypted and saved as orginal file name plus
|
|
419
|
+
'e'. By default, the encrypted scripts and all the auxiliary files
|
|
420
|
+
used to run the encrypted scripts are save in the path "dist".
|
|
421
|
+
|
|
422
|
+
Available options:
|
|
423
|
+
|
|
424
|
+
-O, --output=DIR Output path for runtime files and encrypted
|
|
425
|
+
files (if no --in-place)
|
|
426
|
+
|
|
427
|
+
The default value is "build".
|
|
428
|
+
|
|
429
|
+
-C, --with-capsule=FILENAME Specify the filename of capsule generated
|
|
430
|
+
before.
|
|
431
|
+
|
|
432
|
+
The default value is "project.zip".
|
|
433
|
+
|
|
434
|
+
-i, --in-place [option], the encrypted scripts will be
|
|
435
|
+
saved in the original path (same as source).
|
|
436
|
+
Otherwise, save to --output specified.
|
|
437
|
+
|
|
438
|
+
-s, --src=DIR [option], the source path of python scripts.
|
|
439
|
+
The default value is current path.
|
|
440
|
+
|
|
441
|
+
-p, --plat-name [option] platform name to run encrypted
|
|
442
|
+
scripts. Only used when encrypted scripts
|
|
443
|
+
will be run in different platform.
|
|
444
|
+
|
|
445
|
+
-m, --main=NAME Generate wrapper file to run encrypted script
|
|
446
|
+
|
|
447
|
+
-e, --mode=MODE Encrypt mode, available value:
|
|
448
|
+
0 Encrypt both source and bytecode
|
|
449
|
+
1 Encrypt bytecode only.
|
|
450
|
+
2 Encrypt source code only.
|
|
451
|
+
3 Obfuscate bytecodes.
|
|
452
|
+
5 Obfuscate code object of module.
|
|
453
|
+
6 Combine mode 3 and 4
|
|
454
|
+
7 Obfuscate code object of module,
|
|
455
|
+
output wrapper scripts
|
|
456
|
+
8 Obfuscate both code object and bytecode,
|
|
457
|
+
output wrapper scripts
|
|
458
|
+
Mode 0, 1, 2 is deprecated from v3.2.0, this
|
|
459
|
+
option can be ignored in general.
|
|
460
|
+
|
|
461
|
+
-d, --clean Clean output path at start.
|
|
462
|
+
|
|
463
|
+
--manifest FILENAME Write file list to FILENAME
|
|
464
|
+
|
|
465
|
+
For examples:
|
|
466
|
+
|
|
467
|
+
- Encrypt a.py and b.py as a.pyx and b.pyx, saved in the path "dist":
|
|
468
|
+
|
|
469
|
+
pyarmor encrypt a.py b.py
|
|
470
|
+
|
|
471
|
+
- Use file pattern to specify files:
|
|
472
|
+
|
|
473
|
+
pyarmor encrypt a.py *.py src/*.py lib/*.pyc
|
|
474
|
+
|
|
475
|
+
- Save encrypted files in the directory "/tmp/build" other than "dist":
|
|
476
|
+
|
|
477
|
+
pyarmor encrypt --output=/tmp/build a.py
|
|
478
|
+
|
|
479
|
+
- Encrypt python scripts by project capsule "project.zip" in the
|
|
480
|
+
current directory:
|
|
481
|
+
|
|
482
|
+
pyarmor encrypt --with-capsule=project.zip src/*.py
|
|
483
|
+
|
|
484
|
+
- Encrypt python scripts to run in different platform:
|
|
485
|
+
|
|
486
|
+
pyarmor encrypt --plat-name=linux_x86_64 a.py b.py
|
|
487
|
+
|
|
488
|
+
Use MANIFEST.in to list files
|
|
489
|
+
|
|
490
|
+
pyarmor encrypt --with-capsule=project.zip @myproject/MANIFEST.in
|
|
491
|
+
|
|
492
|
+
It's Following the Distutils’ own manifest template
|
|
493
|
+
|
|
494
|
+
'''
|
|
495
|
+
opts, args = getopt.getopt(
|
|
496
|
+
argv, 'C:de:im:O:p:s:',
|
|
497
|
+
['in-place', 'output=', 'src=', 'with-capsule=', 'plat-name=',
|
|
498
|
+
'main=', 'clean', 'mode=', 'manifest=']
|
|
499
|
+
)
|
|
500
|
+
|
|
501
|
+
output = 'build'
|
|
502
|
+
srcpath = None
|
|
503
|
+
capsule = 'project.zip'
|
|
504
|
+
inplace = False
|
|
505
|
+
pname = None
|
|
506
|
+
extfile = None
|
|
507
|
+
mainname = []
|
|
508
|
+
clean = False
|
|
509
|
+
mode = 8
|
|
510
|
+
manifest = None
|
|
511
|
+
|
|
512
|
+
for o, a in opts:
|
|
513
|
+
if o in ('-O', '--output'):
|
|
514
|
+
output = a
|
|
515
|
+
elif o in ('-s', '--src'):
|
|
516
|
+
srcpath = a
|
|
517
|
+
elif o in ('-i', '--in-place'):
|
|
518
|
+
inplace = True
|
|
519
|
+
elif o in ('-C', '--with-capsule'):
|
|
520
|
+
capsule = a
|
|
521
|
+
elif o in ('-p', '--plat-name'):
|
|
522
|
+
pname = a
|
|
523
|
+
elif o in ('-d', '--clean'):
|
|
524
|
+
clean = True
|
|
525
|
+
elif o in ('-e', '--mode'):
|
|
526
|
+
if a not in ('0', '1', '2', '3', '5', '6',
|
|
527
|
+
'7', '8', '9', '10', '11', '12',
|
|
528
|
+
'13', '14'):
|
|
529
|
+
raise RuntimeError('Invalid mode "%s"' % a)
|
|
530
|
+
mode = int(a)
|
|
531
|
+
elif o in ('-m', '--main'):
|
|
532
|
+
mainname.append(a)
|
|
533
|
+
elif o in ('--manifest', ):
|
|
534
|
+
manifest = a
|
|
535
|
+
|
|
536
|
+
if srcpath is not None and not os.path.exists(srcpath):
|
|
537
|
+
raise RuntimeError('No found specified source path "%s"' % srcpath)
|
|
538
|
+
|
|
539
|
+
if capsule is None or not os.path.exists(capsule):
|
|
540
|
+
raise RuntimeError('No found capsule file %s' % capsule)
|
|
541
|
+
|
|
542
|
+
# Maybe user specify an empty path
|
|
543
|
+
if output == '':
|
|
544
|
+
output = 'build'
|
|
545
|
+
|
|
546
|
+
logging.info('Output path is %s' % output)
|
|
547
|
+
if os.path.exists(output) and clean:
|
|
548
|
+
logging.info('Removing output path %s', output)
|
|
549
|
+
shutil.rmtree(output)
|
|
550
|
+
logging.info('Remove output path OK.')
|
|
551
|
+
if not os.path.exists(output):
|
|
552
|
+
logging.info('Make output path %s', output)
|
|
553
|
+
os.makedirs(output)
|
|
554
|
+
|
|
555
|
+
if pname is None:
|
|
556
|
+
extfile = os.path.join(sys.rootdir, dll_name + dll_ext)
|
|
557
|
+
else:
|
|
558
|
+
logging.info("Cross publish, target platform is %s", pname)
|
|
559
|
+
name = dll_name + ('.so' if pname.startswith('linux') else '.dll')
|
|
560
|
+
extfile = os.path.join(sys.rootdir, 'platforms', pname, name)
|
|
561
|
+
if not os.path.exists(extfile):
|
|
562
|
+
# Need to download platforms/... from pyarmor homepage
|
|
563
|
+
logging.info('You need download prebuilt library files '
|
|
564
|
+
'from pyarmor homepage first.')
|
|
565
|
+
raise RuntimeError('Missing cross platform library %s' % extfile)
|
|
566
|
+
logging.info('Copy %s to %s' % (extfile, output))
|
|
567
|
+
shutil.copy(extfile, output)
|
|
568
|
+
|
|
569
|
+
logging.info('Extract capsule %s ...', capsule)
|
|
570
|
+
ZipFile(capsule).extractall(path=output)
|
|
571
|
+
logging.info('Extract capsule to %s OK.', output)
|
|
572
|
+
|
|
573
|
+
# Fix bootstrap restrict issue from v5.7.0
|
|
574
|
+
make_license(capsule, os.path.join(output, 'license.lic'),
|
|
575
|
+
'*FLAGS:A*CODE:PyArmor')
|
|
576
|
+
|
|
577
|
+
if mode >= 3:
|
|
578
|
+
logging.info('Encrypt mode: %s', mode)
|
|
579
|
+
with open(os.path.join(output, 'pyimcore.py'), 'w') as f:
|
|
580
|
+
lines = 'from pytransform import old_init_runtime', \
|
|
581
|
+
'old_init_runtime(0, 0, 0, 0)', ''
|
|
582
|
+
f.write('\n'.join(lines))
|
|
583
|
+
elif mode:
|
|
584
|
+
logging.info('Encrypt mode: %s', mode)
|
|
585
|
+
with open(os.path.join(output, 'pyimcore.py'), 'r') as f:
|
|
586
|
+
lines = f.read()
|
|
587
|
+
with open(os.path.join(output, 'pyimcore.py'), 'w') as f:
|
|
588
|
+
i = lines.rfind('\n\n')
|
|
589
|
+
if i == -1:
|
|
590
|
+
raise RuntimeError('Invalid pyimcore.py')
|
|
591
|
+
f.write(lines[:i])
|
|
592
|
+
if mode == 1:
|
|
593
|
+
f.write('\n\nold_init_runtime()\n')
|
|
594
|
+
elif mode == 2:
|
|
595
|
+
f.write('\n\nsys.meta_path.append(PyshieldImporter())\n'
|
|
596
|
+
'old_init_runtime(0, 0, 0, 0)\n')
|
|
597
|
+
|
|
598
|
+
prikey = os.path.join(output, 'private.key')
|
|
599
|
+
if os.path.exists(prikey):
|
|
600
|
+
logging.info('Remove private key %s in the output', prikey)
|
|
601
|
+
os.remove(prikey)
|
|
602
|
+
|
|
603
|
+
if mode not in (7, 8, 9, 10, 11, 12, 13, 14):
|
|
604
|
+
for name in mainname:
|
|
605
|
+
n = name.find(':')
|
|
606
|
+
if n == -1:
|
|
607
|
+
script = os.path.join(output, name + '.py')
|
|
608
|
+
else:
|
|
609
|
+
script = os.path.join(output, name[n+1:])
|
|
610
|
+
name = name[:n]
|
|
611
|
+
logging.info('Writing script wrapper %s ...', script)
|
|
612
|
+
ch = 'c' if mode == 1 or mode == 3 else ext_char
|
|
613
|
+
with open(script, 'w') as f:
|
|
614
|
+
f.write(wrap_runner % (name + '.py' + ch))
|
|
615
|
+
logging.info('Write script wrapper OK.')
|
|
616
|
+
|
|
617
|
+
filelist = _parse_file_args(args, srcpath=srcpath)
|
|
618
|
+
if manifest is not None:
|
|
619
|
+
logging.info('Write filelist to %s', manifest)
|
|
620
|
+
with open(manifest, 'w') as fp:
|
|
621
|
+
fp.write('\n'.join([x[0] for x in filelist]))
|
|
622
|
+
|
|
623
|
+
if len(filelist[:1]) == 0:
|
|
624
|
+
logging.info('Generate extra files OK.')
|
|
625
|
+
else:
|
|
626
|
+
prokey = os.path.join(output, 'product.key')
|
|
627
|
+
if not os.path.exists(prokey):
|
|
628
|
+
raise RuntimeError('Missing project key %s' % prokey)
|
|
629
|
+
logging.info('Encrypt files ...')
|
|
630
|
+
encrypt_files(filelist, prokey, mode, None if inplace else output)
|
|
631
|
+
if mode in (7, 8, 9, 10, 11, 12, 13, 14):
|
|
632
|
+
for name in mainname:
|
|
633
|
+
script = os.path.join(
|
|
634
|
+
output, name + ('' if name.endswith('.py') else '.py'))
|
|
635
|
+
with open(script, 'r') as f:
|
|
636
|
+
source = f.read()
|
|
637
|
+
logging.info('Patch entry script %s.', script)
|
|
638
|
+
with open(script, 'w') as f:
|
|
639
|
+
f.write('import pyimcore\n')
|
|
640
|
+
f.write(source)
|
|
641
|
+
logging.info('Encrypt files OK.')
|
|
642
|
+
|
|
643
|
+
@checklicense
|
|
644
|
+
def do_license(argv):
|
|
645
|
+
'''
|
|
646
|
+
Usage: pyarmor license [Options] [CODE]
|
|
647
|
+
|
|
648
|
+
Generate a registration code for project capsule, save it to "license.txt"
|
|
649
|
+
by default.
|
|
650
|
+
|
|
651
|
+
Available options:
|
|
652
|
+
|
|
653
|
+
-O, --output=DIR Path used to save license file.
|
|
654
|
+
|
|
655
|
+
-B, --bind-disk="XX" [optional] Generate license file bind to
|
|
656
|
+
harddisk of one machine.
|
|
657
|
+
|
|
658
|
+
--bind-mac="XX:YY" [optional] Generate license file bind to
|
|
659
|
+
mac address of one machine.
|
|
660
|
+
|
|
661
|
+
--bind-ip="a.b.c.d" [optional] Generate license file bind to
|
|
662
|
+
ipv4 of one machine.
|
|
663
|
+
|
|
664
|
+
--bind-domain="domain" [optional] Generate license file bind to
|
|
665
|
+
domain of one machine.
|
|
666
|
+
|
|
667
|
+
-F, --bind-file=FILENAME [option] Generate license file bind to
|
|
668
|
+
fixed file, for example, ssh private key.
|
|
669
|
+
|
|
670
|
+
-e, --expired-date=YYYY-MM-NN [option] Generate expired license file.
|
|
671
|
+
It could be combined with "--bind"
|
|
672
|
+
|
|
673
|
+
-C, --with-capsule=FILENAME [required] Specify the filename of capsule
|
|
674
|
+
generated before.
|
|
675
|
+
|
|
676
|
+
For example,
|
|
677
|
+
|
|
678
|
+
- Generate a license file "license.lic" for project capsule "project.zip":
|
|
679
|
+
|
|
680
|
+
pyarmor license --wth-capsule=project.zip MYPROJECT-0001
|
|
681
|
+
|
|
682
|
+
- Generate a license file "license.lic" expired in 05/30/2015:
|
|
683
|
+
|
|
684
|
+
pyarmor license --wth-capsule=project.zip -e 2015-05-30 MYPROJECT-0001
|
|
685
|
+
|
|
686
|
+
- Generate a license file "license.lic" bind to machine whose harddisk's
|
|
687
|
+
serial number is "PBN2081SF3NJ5T":
|
|
688
|
+
|
|
689
|
+
pyarmor license --wth-capsule=project.zip --bind-disk PBN2081SF3NJ5T
|
|
690
|
+
|
|
691
|
+
- Generate a license file "license.lic" bind to ssh key file id_rsa:
|
|
692
|
+
|
|
693
|
+
pyarmor license --wth-capsule=project.zip \
|
|
694
|
+
--bind-file src/id_rsa ~/.ssh/my_id_rsa
|
|
695
|
+
|
|
696
|
+
File "src/id_rsa" is in the develop machine, pyarmor will read data
|
|
697
|
+
from this file when generating license file.
|
|
698
|
+
|
|
699
|
+
Argument "~/.ssh/id_rsa" means full path filename in target machine,
|
|
700
|
+
pyarmor will find this file as key file when decrypting python scripts.
|
|
701
|
+
|
|
702
|
+
You shuold copy "license.lic" to target machine, at the same time,
|
|
703
|
+
copy "src/id_rsa" to target machine as "~/.ssh/my_id_rsa"
|
|
704
|
+
|
|
705
|
+
'''
|
|
706
|
+
opts, args = getopt.getopt(
|
|
707
|
+
argv, 'B:C:e:F:O:',
|
|
708
|
+
['bind-disk=', 'bind-mac=', 'bind-ip=', 'bind-domain=',
|
|
709
|
+
'expired-date=', 'bind-file=', 'with-capsule=', 'output=']
|
|
710
|
+
)
|
|
711
|
+
|
|
712
|
+
filename = 'license.lic.txt'
|
|
713
|
+
bindfile = None
|
|
714
|
+
capsule = 'project.zip'
|
|
715
|
+
bindfileflag = False
|
|
716
|
+
binddisk = None
|
|
717
|
+
bindip = None
|
|
718
|
+
bindmac = None
|
|
719
|
+
binddomain = None
|
|
720
|
+
expired = None
|
|
721
|
+
for o, a in opts:
|
|
722
|
+
if o in ('-C', '--with-capsule'):
|
|
723
|
+
capsule = a
|
|
724
|
+
elif o in ('-B', '--bind-disk'):
|
|
725
|
+
binddisk = a
|
|
726
|
+
elif o in ('-B', '--bind-mac'):
|
|
727
|
+
bindmac = a
|
|
728
|
+
elif o in ('-B', '--bind-ip'):
|
|
729
|
+
bindip = a
|
|
730
|
+
elif o in ('-B', '--bind-domain'):
|
|
731
|
+
binddomain = a
|
|
732
|
+
elif o in ('-F', '--bind-file'):
|
|
733
|
+
bindfileflag = True
|
|
734
|
+
bindfile = a
|
|
735
|
+
elif o in ('-e', '--expired-date'):
|
|
736
|
+
expired = a
|
|
737
|
+
elif o in ('-O', '--output'):
|
|
738
|
+
if os.path.exists(a) and os.path.isdir(a):
|
|
739
|
+
filename = os.path.join(a, 'license.lic.txt')
|
|
740
|
+
else:
|
|
741
|
+
filename = a
|
|
742
|
+
|
|
743
|
+
if len(args) == 0:
|
|
744
|
+
key = 'POWERD-BY-PYARMOR'
|
|
745
|
+
else:
|
|
746
|
+
key = args[0]
|
|
747
|
+
|
|
748
|
+
if expired is None:
|
|
749
|
+
fmt = ''
|
|
750
|
+
else:
|
|
751
|
+
logging.info('License file expired at %s', expired)
|
|
752
|
+
fmt = '*TIME:%.0f\n' % time.mktime(time.strptime(expired, '%Y-%m-%d'))
|
|
753
|
+
|
|
754
|
+
# Fix bootstrap restrict issue from v5.7.0
|
|
755
|
+
if key.find('FLAGS') == -1:
|
|
756
|
+
fmt = '%s*FLAGS:A' % fmt
|
|
757
|
+
|
|
758
|
+
if binddisk:
|
|
759
|
+
logging.info('License file bind to harddisk "%s"', binddisk)
|
|
760
|
+
fmt = '%s*HARDDISK:%s' % (fmt, binddisk)
|
|
761
|
+
|
|
762
|
+
if bindmac:
|
|
763
|
+
logging.info('License file bind to mac addr "%s"', key)
|
|
764
|
+
fmt = '%s*IFMAC:%s' % (fmt, bindmac)
|
|
765
|
+
|
|
766
|
+
if bindip:
|
|
767
|
+
logging.info('License file bind to ip "%s"', key)
|
|
768
|
+
fmt = '%s*IFIPV4:%s' % (fmt, bindip)
|
|
769
|
+
|
|
770
|
+
if binddomain:
|
|
771
|
+
logging.info('License file bind to domain "%s"', key)
|
|
772
|
+
fmt = '%s*DOMAIN:%s' % (fmt, binddomain)
|
|
773
|
+
|
|
774
|
+
if bindfileflag:
|
|
775
|
+
if os.path.exists(bindfile):
|
|
776
|
+
logging.info('You need copy %s to target machine as %s '
|
|
777
|
+
'with license file.', bindfile, key)
|
|
778
|
+
f = open(bindfile, 'rb')
|
|
779
|
+
s = f.read()
|
|
780
|
+
f.close()
|
|
781
|
+
if sys.version_info[0] == 3:
|
|
782
|
+
fmt = '%s*FIXKEY:%s;%s' % (fmt, key, s.decode())
|
|
783
|
+
else:
|
|
784
|
+
fmt = '%s*FIXKEY:%s;%s' % (fmt, key, s)
|
|
785
|
+
else:
|
|
786
|
+
raise RuntimeError('Bind file %s not found' % bindfile)
|
|
787
|
+
|
|
788
|
+
logging.info('Output filename is %s', filename)
|
|
789
|
+
make_license(capsule, filename, fmt if fmt else key)
|
|
790
|
+
logging.info('Generate license file "%s" OK.', filename)
|
|
791
|
+
|
|
792
|
+
if __name__ == '__main__':
|
|
793
|
+
sys.rootdir = os.path.dirname(os.path.abspath(sys.argv[0]))
|
|
794
|
+
|
|
795
|
+
logging.basicConfig(
|
|
796
|
+
level=logging.INFO,
|
|
797
|
+
format='%(levelname)-8s %(message)s',
|
|
798
|
+
# filename=os.path.join(sys.rootdir, 'pyarmor.log'),
|
|
799
|
+
# filemode='w',
|
|
800
|
+
)
|
|
801
|
+
|
|
802
|
+
# if (len(sys.argv) == 1 or
|
|
803
|
+
# sys.argv[1] not in ('help', 'encrypt', 'capsule', 'license')):
|
|
804
|
+
# from pyarmor import main as main2
|
|
805
|
+
# main2(sys.argv[1:])
|
|
806
|
+
# sys.exit(0)
|
|
807
|
+
|
|
808
|
+
if len(sys.argv) == 1:
|
|
809
|
+
usage()
|
|
810
|
+
sys.exit(0)
|
|
811
|
+
|
|
812
|
+
command = sys.argv[1]
|
|
813
|
+
if len(sys.argv) >= 3 and sys.argv[2] == 'help':
|
|
814
|
+
usage(command)
|
|
815
|
+
sys.exit(0)
|
|
816
|
+
|
|
817
|
+
pytransform = _import_pytransform()
|
|
818
|
+
if pytransform is None:
|
|
819
|
+
sys.exit(1)
|
|
820
|
+
|
|
821
|
+
if 'help'.startswith(command) or sys.argv[1].startswith('-h'):
|
|
822
|
+
try:
|
|
823
|
+
usage(sys.argv[2])
|
|
824
|
+
except IndexError:
|
|
825
|
+
usage()
|
|
826
|
+
|
|
827
|
+
elif 'version'.startswith(command) or sys.argv[1].startswith('-v'):
|
|
828
|
+
show_version_info()
|
|
829
|
+
|
|
830
|
+
elif 'capsule'.startswith(command):
|
|
831
|
+
do_capsule(sys.argv[2:])
|
|
832
|
+
|
|
833
|
+
elif 'encrypt'.startswith(command):
|
|
834
|
+
do_encrypt(sys.argv[2:])
|
|
835
|
+
|
|
836
|
+
elif 'license'.startswith(command):
|
|
837
|
+
do_license(sys.argv[2:])
|
|
838
|
+
|
|
839
|
+
elif 'hdinfo'.startswith(command):
|
|
840
|
+
show_hd_info()
|
|
841
|
+
|
|
842
|
+
else:
|
|
843
|
+
usage(command)
|