pyarmor 8.5.6__zip → 8.5.8__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.
Files changed (123) hide show
  1. {pyarmor-8.5.6 → pyarmor-8.5.8}/PKG-INFO +1 -1
  2. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/cli/__init__.py +1 -1
  3. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/cli/__main__.py +7 -12
  4. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/cli/bug.py +2 -2
  5. pyarmor-8.5.8/pyarmor/cli/core.data.1 +0 -0
  6. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/cli/core.data.2 +0 -0
  7. pyarmor-8.5.8/pyarmor/cli/core.data.3 +0 -0
  8. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/cli/default.cfg +1 -1
  9. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/cli/generate.py +5 -11
  10. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/cli/repack.py +369 -195
  11. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/config.py +1 -1
  12. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor.egg-info/PKG-INFO +1 -1
  13. pyarmor-8.5.6/pyarmor/cli/core.data.1 +0 -0
  14. pyarmor-8.5.6/pyarmor/cli/core.data.3 +0 -0
  15. {pyarmor-8.5.6 → pyarmor-8.5.8}/MANIFEST.in +0 -0
  16. {pyarmor-8.5.6 → pyarmor-8.5.8}/README.md +0 -0
  17. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/README.rst +0 -0
  18. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/__init__.py +0 -0
  19. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/benchmark.py +0 -0
  20. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/build_meta.py +0 -0
  21. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/cli/bootstrap.py +0 -0
  22. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/cli/config.py +0 -0
  23. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/cli/context.py +0 -0
  24. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/cli/docker.py +0 -0
  25. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/cli/hdinfo.py +0 -0
  26. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/cli/merge.py +0 -0
  27. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/cli/mixer.py +0 -0
  28. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/cli/plugin.py +0 -0
  29. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/cli/public_capsule.zip +0 -0
  30. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/cli/register.py +0 -0
  31. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/cli/resource.py +0 -0
  32. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/cli/shell.py +0 -0
  33. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/cobuilder.py +0 -0
  34. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/README-ZH.md +0 -0
  35. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/README.md +0 -0
  36. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/build-for-exe.bat +0 -0
  37. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/build-for-freeze.bat +0 -0
  38. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/build-with-project.bat +0 -0
  39. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/build-with-project.sh +0 -0
  40. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/cx_Freeze/hello.py +0 -0
  41. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/cx_Freeze/queens.py +0 -0
  42. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/cx_Freeze/setup.py +0 -0
  43. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/helloworld/foo.py +0 -0
  44. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/obfuscate-app.bat +0 -0
  45. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/obfuscate-app.sh +0 -0
  46. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/obfuscate-pkg.bat +0 -0
  47. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/obfuscate-pkg.sh +0 -0
  48. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pack-obfuscated-scripts.bat +0 -0
  49. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pack-obfuscated-scripts.sh +0 -0
  50. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/py2exe/hello.py +0 -0
  51. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/py2exe/queens.py +0 -0
  52. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/py2exe/setup.py +0 -0
  53. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/Arithmetic.py +0 -0
  54. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/Calls.py +0 -0
  55. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/CommandLine.py +0 -0
  56. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/Constructs.py +0 -0
  57. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/Dict.py +0 -0
  58. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/Exceptions.py +0 -0
  59. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/Imports.py +0 -0
  60. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/Instances.py +0 -0
  61. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/Lists.py +0 -0
  62. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/Lookups.py +0 -0
  63. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/NewInstances.py +0 -0
  64. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/Numbers.py +0 -0
  65. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/Setup.py +0 -0
  66. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/Strings.py +0 -0
  67. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/Tuples.py +0 -0
  68. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/With.py +0 -0
  69. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/clockres.py +0 -0
  70. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/package/__init__.py +0 -0
  71. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/package/submodule.py +0 -0
  72. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/pybench.py +0 -0
  73. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/pybench/systimes.py +0 -0
  74. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/simple/queens.py +0 -0
  75. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/testmod/hello.py +0 -0
  76. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/testmod/queens.py +0 -0
  77. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/testpkg/main.py +0 -0
  78. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/testpkg/mypkg/__init__.py +0 -0
  79. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/examples/testpkg/mypkg/foo.py +0 -0
  80. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/helper/__init__.py +0 -0
  81. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/helper/build_data_module.py +0 -0
  82. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/helper/buildext.py +0 -0
  83. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/helper/get_bind_key.py +0 -0
  84. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/helper/get_license_info.py +0 -0
  85. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/helper/get_platform_name.py +0 -0
  86. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/helper/merge.py +0 -0
  87. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/helper/repack.py +0 -0
  88. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/helper/superuntime.py +0 -0
  89. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/license.tri +0 -0
  90. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/packer.py +0 -0
  91. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/platforms/darwin/x86_64/_pytransform.dylib +0 -0
  92. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/platforms/linux/x86/_pytransform.so +0 -0
  93. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/platforms/linux/x86_64/_pytransform.so +0 -0
  94. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/platforms/windows/x86/_pytransform.dll +0 -0
  95. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/platforms/windows/x86_64/_pytransform.dll +0 -0
  96. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/plugins/README.md +0 -0
  97. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/plugins/check_ntp_time.py +0 -0
  98. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/polyfills/__init__.py +0 -0
  99. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/polyfills/argparse.py +0 -0
  100. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/product.key +0 -0
  101. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/project.py +0 -0
  102. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/protect_code.pt +0 -0
  103. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/protect_code2.pt +0 -0
  104. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/public.key +0 -0
  105. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/public_capsule.zip +0 -0
  106. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/pyarmor-deprecated.py +0 -0
  107. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/pyarmor-webui.py +0 -0
  108. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/pyarmor.py +0 -0
  109. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/pyimcore.py +0 -0
  110. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/pyshield.key +0 -0
  111. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/pyshield.lic +0 -0
  112. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/pytransform.py +0 -0
  113. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/reform.py +0 -0
  114. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/register.py +0 -0
  115. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/sppmode.py +0 -0
  116. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor/utils.py +0 -0
  117. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor.egg-info/SOURCES.txt +0 -0
  118. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor.egg-info/dependency_links.txt +0 -0
  119. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor.egg-info/entry_points.txt +0 -0
  120. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor.egg-info/requires.txt +0 -0
  121. {pyarmor-8.5.6 → pyarmor-8.5.8}/pyarmor.egg-info/top_level.txt +0 -0
  122. {pyarmor-8.5.6 → pyarmor-8.5.8}/setup.cfg +0 -0
  123. {pyarmor-8.5.6 → pyarmor-8.5.8}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 1.1
2
2
  Name: pyarmor
3
- Version: 8.5.6
3
+ Version: 8.5.8
4
4
  Summary: A tool used to obfuscate python scripts, bind obfuscated scripts to fixed machine or expire obfuscated scripts.
5
5
  Home-page: https://github.com/dashingsoft/pyarmor
6
6
  Author: Jondy Zhao
@@ -1,6 +1,6 @@
1
1
  import logging
2
2
 
3
- __VERSION__ = '8.5.6'
3
+ __VERSION__ = '8.5.8'
4
4
 
5
5
  logger = logging.getLogger('cli')
6
6
 
@@ -209,10 +209,10 @@ def check_gen_context(ctx, args):
209
209
  raise CliError('--outer conflicts with any -e, --period, -b')
210
210
 
211
211
  if args.pack:
212
- choices = 'auto', 'onefile', 'onedir', 'F', 'D', 'FC', 'DC'
212
+ choices = 'onefile', 'onedir', 'F', 'D', 'FC', 'DC'
213
213
  if args.pack not in choices and not os.path.isfile(args.pack):
214
- raise CliError('--pack must be an executable file, '
215
- '"auto", "onefile" or "onedir"')
214
+ raise CliError('--pack must be an executable file, specfile, '
215
+ '"onefile" or "onedir"')
216
216
  if args.no_runtime:
217
217
  raise CliError('--pack conficts with --no-runtime, --use-runtime')
218
218
  if ctx.import_prefix:
@@ -232,18 +232,13 @@ def cmd_gen(ctx, args):
232
232
  return _cmd_gen_key(builder, options)
233
233
  elif args.inputs[0].lower() in ('runtime', 'run', 'r'):
234
234
  _cmd_gen_runtime(builder, options)
235
- elif args.pack in ('auto', 'onefile', 'onedir', 'F', 'D', 'FC', 'DC'):
236
- from .repack import Repacker6
237
- packer = Repacker6(ctx, args.pack, options['inputs'], args.output)
238
- packer.check()
239
- builder.process(options, packer)
240
- Plugin.post_build(ctx, pack=args.pack)
241
235
  elif args.pack:
242
- from .repack import Repacker
243
- codesign = ctx.cfg['pack'].get('codesign_identify', None)
244
- packer = Repacker(args.pack, ctx.pack_basepath, codesign=codesign)
236
+ from .repack import find_packer
237
+ Repacker = find_packer(args.pack)
238
+ packer = Repacker(ctx, args.pack, options['inputs'], args.output)
245
239
  packer.check()
246
240
  builder.process(options, packer=packer)
241
+ packer.build()
247
242
  Plugin.post_build(ctx, pack=args.pack)
248
243
  else:
249
244
  builder.process(options)
@@ -36,7 +36,7 @@ $tracelog
36
36
  $tb
37
37
  ''')
38
38
 
39
- ENABLE_DEBUG_HINTS = '''somthing is wrong
39
+ ENABLE_DEBUG_HINTS = '''something is wrong
40
40
  *=============================================================*
41
41
  * Please enable debug option `-d` to run it again *
42
42
  * pyarmor -d gen options ... *
@@ -49,7 +49,7 @@ ENABLE_DEBUG_HINTS = '''somthing is wrong
49
49
  *=============================================================*
50
50
  '''
51
51
 
52
- SOLUTION_HINTS = Template('''somthing is wrong
52
+ SOLUTION_HINTS = Template('''something is wrong
53
53
  *=============================================================*
54
54
  * Please check *
55
55
  * https://pyarmor.readthedocs.io/en/latest/questions.html *
Binary file
Binary file
@@ -3,7 +3,7 @@
3
3
  ;; Pyarmor version
4
4
  major = 8
5
5
  minor = 5
6
- patch = 6
6
+ patch = 8
7
7
 
8
8
  ;; Compatible core version
9
9
  cli.core = 6.5.1
@@ -67,7 +67,7 @@ class Finder(object):
67
67
  for res in self._build_resource(resources):
68
68
  if res.pkgname not in resnames:
69
69
  self.ctx.obfuscated_modules.add(res.pkgname)
70
- self.ctx.extra_resources.append(res)
70
+ self.ctx.resources.append(res)
71
71
 
72
72
  def process(self):
73
73
  logger.info('search inputs ...')
@@ -156,13 +156,10 @@ class Builder(object):
156
156
  finder = Finder(self.ctx)
157
157
  finder.process()
158
158
 
159
- if packer:
160
- if options.get('self_contained'):
161
- finder.process_extra(packer.contents)
162
- if hasattr(packer, 'analysis'):
163
- auto_resources = packer.analysis()
164
- logger.info('find extra resources: %s', auto_resources)
165
- finder.append(auto_resources)
159
+ if packer and hasattr(packer, 'analysis'):
160
+ auto_resources = packer.analysis()
161
+ logger.info('find extra resources: %s', auto_resources)
162
+ finder.append(auto_resources)
166
163
 
167
164
  Pytransform3.pre_build(self.ctx)
168
165
 
@@ -177,6 +174,3 @@ class Builder(object):
177
174
  logger.info('obfuscate scripts OK')
178
175
 
179
176
  Pytransform3.post_build(self.ctx)
180
-
181
- if packer:
182
- packer.repack(output, self.ctx.runtime_package_name)
@@ -6,19 +6,363 @@ import struct
6
6
  import sys
7
7
  import tempfile
8
8
 
9
- from importlib._bootstrap_external import _code_to_timestamp_pyc
10
- from subprocess import check_call, check_output, DEVNULL
9
+ from fnmatch import fnmatch
10
+ from subprocess import check_call, DEVNULL
11
11
 
12
+ # Only used by BundleRepacker, they could be removed with deprecated routines
13
+ from importlib._bootstrap_external import _code_to_timestamp_pyc
12
14
  from PyInstaller.archive.writers import ZlibArchiveWriter, CArchiveWriter
13
15
  from PyInstaller.archive.readers import CArchiveReader
14
- try:
15
- from PyInstaller.loader.pyimod02_archive import ZlibArchiveReader
16
- except ModuleNotFoundError:
17
- # Since 5.3
18
- from PyInstaller.loader.pyimod01_archive import ZlibArchiveReader
19
16
  from PyInstaller.compat import is_darwin, is_linux, is_win
20
17
 
21
18
 
19
+ logger = logging.getLogger('repack')
20
+
21
+
22
+ def find_packer(mode):
23
+ if mode in ('onefile', 'onedir', 'F', 'D', 'FC', 'DC'):
24
+ return AutoRepacker
25
+
26
+ if isinstance(mode, str) and mode.endswith('.spec'):
27
+ return SpecRepacker
28
+
29
+ return BundleRepacker
30
+
31
+
32
+ def autoclean_output(output, autoclean=True):
33
+ if os.path.exists(output) and autoclean:
34
+ n = len(os.path.abspath(output).split(os.sep))
35
+ if n < 3:
36
+ prompt = 'Are you sure to remove path "%s" (y/n)? '
37
+ choice = input(prompt % output).lower()[:1]
38
+ if not choice == 'y':
39
+ return
40
+ logger.info('clean output path "%s"', output)
41
+ shutil.rmtree(output)
42
+
43
+
44
+ # This patch is used to modify the specfile generate by PyInstaller
45
+ #
46
+ # It mainly does:
47
+ #
48
+ # 1. Find all the imported modules and packages, save to hook script
49
+ #
50
+ # 2. Find imported modules and packages in the same path of main
51
+ # script, and save their names to one list (all of them will be
52
+ # obfuscated automatically)
53
+ #
54
+ spec_patch_code = '''
55
+ import marshal
56
+ import os
57
+
58
+ from PyInstaller.compat import base_prefix, EXTENSION_SUFFIXES
59
+ from sys import prefix, exec_prefix
60
+ from fnmatch import fnmatch
61
+
62
+ exlist = set([base_prefix, prefix, exec_prefix])
63
+ expats = [os.path.join(os.path.normpath(x), '*') for x in exlist]
64
+
65
+ src = {src!r}
66
+ resfile = {resfile!r}
67
+ hookscript = {hookscript!r}
68
+
69
+ nsrc = len(src) + 1
70
+ rsrc = os.path.relpath(src)
71
+ rsrc = '' if rsrc == '.' else rsrc
72
+ psrc = os.path.join(src, '*')
73
+
74
+ hiddenimports = set([])
75
+ plist = set([])
76
+ mlist = []
77
+
78
+ for name, path, kind in a.pure:
79
+ if name.startswith('pyi_rth'):
80
+ continue
81
+ hiddenimports.add(name)
82
+ if fnmatch(path, psrc) and not any([fnmatch(path, x) for x in expats]):
83
+ if name.find('.') == -1 and os.path.basename(path) != '__init__.py':
84
+ mlist.append(os.path.join(rsrc, path[nsrc:]))
85
+ else:
86
+ pkgname = os.path.dirname(path[nsrc:]).split(os.sep)[0]
87
+ plist.add(os.path.join(rsrc, pkgname))
88
+
89
+ for name, path, kind in a.binaries:
90
+ if kind == 'EXTENSION':
91
+ for x in EXTENSION_SUFFIXES:
92
+ if fnmatch(name, '*' + x):
93
+ name = name[:-len(x)]
94
+ break
95
+ hiddenimports.add(name.replace(os.sep, '.'))
96
+
97
+ with open(resfile, 'wb') as f:
98
+ marshal.dump(mlist + list(plist), f)
99
+ with open(hookscript, 'w') as f:
100
+ f.write("hiddenimports=[%s]" % ", ".join([repr(x) for x in hiddenimports]))
101
+ '''
102
+
103
+
104
+ class AutoRepacker:
105
+ """New repacker to support PyInstaller 6.0+
106
+
107
+ Args:
108
+ ctx: build context
109
+ mode: onefile or onedir
110
+ inputs: main script to pack
111
+ output: path to store final bundle, default is `dist`
112
+ """
113
+
114
+ def __init__(self, ctx, mode, inputs, output):
115
+ self.ctx = ctx
116
+ self.script = inputs[0]
117
+ self.output = os.path.normpath(output) if output else 'dist'
118
+
119
+ self.name = os.path.splitext(os.path.basename(self.script))[0]
120
+ self.obfpath = os.path.normpath(self.ctx.pack_obfpath)
121
+ self.packpath = os.path.normpath(self.ctx.pack_basepath)
122
+ self.workpath = os.path.join(self.packpath, 'build')
123
+ self.pyicmd = [sys.executable, '-m', 'PyInstaller']
124
+ self.autoclean = mode in ('FC', 'DC')
125
+ self.modeopt = '-F' if mode in ('onefile', 'F', 'FC') else '-D'
126
+ self.init_opts()
127
+
128
+ def init_opts(self):
129
+ self.pyiopts = []
130
+
131
+ opts = self.ctx.pyi_options
132
+ exopts = '--noconfirm', '-y', '--onefile', '-F', '--onedir', '-D'
133
+ exvalues = '--distpath', '--specpath', '--workpath'
134
+
135
+ n = 0
136
+ while n < len(opts):
137
+ x = opts[n]
138
+ if x in ('--name', '-n'):
139
+ self.name = opts[n+1]
140
+
141
+ if x in ('--noconfirm', '-y'):
142
+ self.autoclean = True
143
+
144
+ if x in exvalues:
145
+ n += 1
146
+ elif x not in exopts:
147
+ self.pyiopts.append(x)
148
+ n += 1
149
+
150
+ def analysis(self):
151
+ """Got imported modules and packages by PyInstaller
152
+
153
+ Generate hook script
154
+ Return file/dir list need to be obfuscated
155
+ """
156
+ cmdspec = [sys.executable, '-m', 'PyInstaller.utils.cliutils.makespec']
157
+ cmdspec.extend(self.pyiopts)
158
+ cmdspec.append(self.script)
159
+ logger.debug('%s', ' '.join(cmdspec))
160
+ logger.info('call PyInstaller to generate specfile')
161
+ check_call(cmdspec, stdout=DEVNULL, stderr=DEVNULL)
162
+
163
+ specfile = self.name + '.spec'
164
+ rtname = self.ctx.runtime_package_name
165
+ resfile = os.path.join(self.packpath, 'resources.list')
166
+ hookscript = os.path.join(self.packpath, 'hook-%s.py' % rtname)
167
+ self.patch_specfile(specfile, hookscript, resfile)
168
+
169
+ cmdlist = self.pyicmd + ['--clean', '--workpath', self.workpath]
170
+ cmdlist.append(specfile)
171
+ logger.debug('%s', ' '.join(cmdlist))
172
+ logger.info('call PyInstaller to analysis, '
173
+ 'it may take several minutes ...')
174
+ check_call(cmdlist, stdout=DEVNULL, stderr=DEVNULL)
175
+
176
+ with open(resfile, 'rb') as f:
177
+ reslist = marshal.load(f)
178
+
179
+ resoptions = self.ctx.get_res_options('')
180
+ excludes = resoptions.get('excludes', '').split()
181
+ if excludes:
182
+ reslist = [x for x in reslist
183
+ if not any([fnmatch(x, pat) for pat in excludes])]
184
+ return reslist
185
+
186
+ def build(self):
187
+ """Generate final bundle to output"""
188
+ obfscript = os.path.join(self.obfpath, os.path.basename(self.script))
189
+ cmdlist = self.pyicmd + [
190
+ '--clean',
191
+ '--distpath', self.output,
192
+ '--workpath', self.workpath,
193
+ '--additional-hooks-dir', self.packpath,
194
+ self.modeopt
195
+ ]
196
+ cmdlist.extend(self.pyiopts)
197
+ cmdlist.append(obfscript)
198
+
199
+ logger.debug('%s', ' '.join(cmdlist))
200
+ logger.info('call PyInstaller to generate final bundle ...\n')
201
+ check_call(cmdlist)
202
+ logger.info('')
203
+ logger.info('the final bundle has been generated to "%s" successfully',
204
+ self.output)
205
+
206
+ def patch_specfile(self, specfile, hookscript, resfile):
207
+ lines = []
208
+ with open(specfile, 'r', encoding='utf-8') as f:
209
+ for line in f:
210
+ if line.startswith('pyz = PYZ'):
211
+ break
212
+ lines.append(line)
213
+ else:
214
+ logger.error('no found line starts with "pyz = PYZ"')
215
+ raise RuntimeError('unsupported specfile "%s"' % specfile)
216
+
217
+ lines.append(spec_patch_code.format(
218
+ src=os.path.abspath(os.path.dirname(self.script)),
219
+ hookscript=os.path.abspath(hookscript),
220
+ resfile=os.path.abspath(resfile)))
221
+
222
+ with open(specfile, 'w', encoding='utf-8') as f:
223
+ f.write(''.join(lines))
224
+
225
+ def check(self):
226
+ autoclean_output(self.output, self.autoclean)
227
+
228
+
229
+ manual_spec_patch = '''
230
+ # Pyarmor patch start:
231
+
232
+ def apply_pyarmor_patch():
233
+
234
+ srcpath = {srcpath!r}
235
+ obfpath = {obfpath!r}
236
+ pkgname = {rtname!r}
237
+ pkgpath = os.path.join(obfpath, pkgname)
238
+ extpath = os.path.join(pkgname, {extname!r})
239
+
240
+ if hasattr(a.pure, '_code_cache'):
241
+ code_cache = a.pure._code_cache
242
+ else:
243
+ from PyInstaller.config import CONF
244
+ code_cache = CONF['code_cache'].get(id(a.pure))
245
+
246
+ srclist = [os.path.normcase(x) for x in srcpath]
247
+ def match_obfuscated_script(orgpath):
248
+ for x in srclist:
249
+ if os.path.normcase(orgpath).startswith(x):
250
+ return os.path.join(obfpath, orgpath[len(x)+1:])
251
+
252
+ count = 0
253
+ for i in range(len(a.scripts)):
254
+ x = match_obfuscated_script(a.scripts[i][1])
255
+ if x and os.path.exists(x):
256
+ a.scripts[i] = a.scripts[i][0], x, a.scripts[i][2]
257
+ count += 1
258
+ if count == 0:
259
+ raise RuntimeError('No obfuscated script found')
260
+
261
+ for i in range(len(a.pure)):
262
+ x = match_obfuscated_script(a.pure[i][1])
263
+ if x and os.path.exists(x):
264
+ code_cache.pop(a.pure[i][0], None)
265
+ a.pure[i] = a.pure[i][0], x, a.pure[i][2]
266
+
267
+ a.pure.append((pkgname, os.path.join(pkgpath, '__init__.py'), 'PYMODULE'))
268
+ a.binaries.append((extpath, os.path.join(obfpath, extpath), 'EXTENSION'))
269
+
270
+ apply_pyarmor_patch()
271
+
272
+ # Pyarmor patch end.
273
+ '''
274
+
275
+
276
+ class SpecRepacker:
277
+ """Patch specfile and use it to pack obfuscated scripts
278
+
279
+ Args:
280
+ ctx: build context
281
+ specfile: specfile need to be patched
282
+ inputs: main script to pack
283
+ output: path to store final bundle, default is `dist`
284
+ """
285
+
286
+ def __init__(self, ctx, specfile, inputs, output):
287
+ self.ctx = ctx
288
+ self.specfile = specfile
289
+ self.script = inputs[0]
290
+ self.output = os.path.normpath(output) if output else 'dist'
291
+
292
+ self.pyicmd = [sys.executable, '-m', 'PyInstaller']
293
+ self.obfpath = os.path.normpath(self.ctx.pack_obfpath)
294
+
295
+ def build(self):
296
+ """Generate patched specfile and pack obfuscated scripts"""
297
+ specfile = self.specfile[:-5] + '.patched.spec'
298
+ logger.info('generate patched specfile "%s"', specfile)
299
+
300
+ rtpkg = self.ctx.runtime_package_name
301
+ for x in os.listdir(os.path.join(self.obfpath, rtpkg)):
302
+ if x.startswith('pyarmor_runtime'):
303
+ extname = x
304
+ break
305
+ else:
306
+ raise RuntimeError('no found extension `pyarmor_runtime`')
307
+
308
+ patch = manual_spec_patch.format(
309
+ srcpath=[os.path.abspath(os.path.dirname(self.script))],
310
+ obfpath=os.path.abspath(self.obfpath),
311
+ rtname=self.ctx.runtime_package_name,
312
+ extname=extname)
313
+
314
+ with open(self.specfile, 'r', encoding='utf-8') as f:
315
+ lines = f.readlines()
316
+
317
+ n = 0
318
+ for line in lines:
319
+ if line.startswith('pyz = PYZ'):
320
+ lines[n:n] = [patch]
321
+ break
322
+ n += 1
323
+ else:
324
+ logger.error('no found line starts with "pyz = PYZ"')
325
+ raise RuntimeError('unsupported specfile "%s"' % self.specfile)
326
+
327
+ with open(specfile, 'w', encoding='utf-8') as f:
328
+ f.write(''.join(lines))
329
+
330
+ cmdlist = self.pyicmd + [
331
+ '--clean',
332
+ '--distpath', self.output,
333
+ '--workpath', os.path.join(self.ctx.pack_basepath, 'build'),
334
+ specfile
335
+ ]
336
+ logger.info('call PyInstaller to generate final bundle ...'
337
+ '\n\n%s\n', ' '.join(cmdlist))
338
+ check_call(cmdlist)
339
+ logger.info('')
340
+ logger.info('the final bundle has been generated to "%s" successfully',
341
+ self.output)
342
+
343
+ def check(self):
344
+ options = self.ctx.pyi_options
345
+ autoclean = '-y' in options or '--noconfirm' in options
346
+ autoclean_output(self.output, autoclean)
347
+
348
+
349
+ ##############################################################
350
+ #
351
+ # Deprecated routines
352
+ #
353
+ # This is the old method to repack executable generated by PyInstaller
354
+ #
355
+ # Why is it deprecated?
356
+ #
357
+ # 1. It need hack PyInstaller bundle structure which may be changed in
358
+ # different PyInstaller version.
359
+ #
360
+ # Actually, it doesn't work for PyInstaller 5.13+ because of this
361
+ #
362
+ # 2. Not friend to junior users
363
+ #
364
+ ##
365
+
22
366
  # Type codes for PYZ PYZ entries
23
367
  PYZ_ITEM_MODULE = 0
24
368
  PYZ_ITEM_PKG = 1
@@ -41,9 +385,6 @@ PKG_ITEM_SPLASH = 'l' # splash resources
41
385
  EXTRACT_SUFFIX = '_extracted'
42
386
 
43
387
 
44
- logger = logging.getLogger('repack')
45
-
46
-
47
388
  class CArchiveReader2(CArchiveReader):
48
389
 
49
390
  def find_magic_pattern(self, fp, magic_pattern):
@@ -93,6 +434,12 @@ class CArchiveReader2(CArchiveReader):
93
434
  if hasattr(self, 'open_embedded_archive'):
94
435
  return self.open_embedded_archive(name)
95
436
 
437
+ try:
438
+ from PyInstaller.loader.pyimod02_archive import ZlibArchiveReader
439
+ except ModuleNotFoundError:
440
+ # Since 5.3
441
+ from PyInstaller.loader.pyimod01_archive import ZlibArchiveReader
442
+
96
443
  ndx = self.toc.find(name)
97
444
  (dpos, dlen, ulen, flag, typcd, nm) = self.toc.get(ndx)
98
445
  return ZlibArchiveReader(self.path, self.pkg_start + dpos)
@@ -306,13 +653,16 @@ def repack_executable(executable, buildpath, obfpath, rtentry, codesign=None):
306
653
  logger.info('generate patched bundle "%s" successfully', executable)
307
654
 
308
655
 
309
- class Repacker:
656
+ class BundleRepacker:
657
+ """Deprecated method since v8.5.8"""
310
658
 
311
- def __init__(self, executable, buildpath, codesign=None):
659
+ def __init__(self, ctx, executable, inputs, output):
660
+ self.ctx = ctx
312
661
  self.executable = executable
313
- self.buildpath = buildpath
314
- self.codesign = codesign
315
- self.extract_carchive(executable, buildpath)
662
+ self.output = os.path.normpath(output) if output else 'dist'
663
+ self.buildpath = ctx.pack_basepath
664
+ self.codesign = ctx.cfg['pack'].get('codesign_identify', None)
665
+ self.extract_carchive(executable, self.buildpath)
316
666
 
317
667
  def check(self):
318
668
  try:
@@ -360,6 +710,9 @@ class Repacker:
360
710
  for x in os.scandir(os.path.dirname(executable))])
361
711
  logger.debug('one file mode is %s', bool(self.one_file_mode))
362
712
 
713
+ def build(self):
714
+ self.repack(self.output, self.ctx.runtime_package_name)
715
+
363
716
  def repack(self, obfpath, rtname, entry=None):
364
717
  buildpath = self.buildpath
365
718
  executable = self.executable
@@ -414,6 +767,7 @@ class Repacker:
414
767
  def _fixup_darwin_rtbinary(self, rtbinary, pylib_name):
415
768
  '''Unused since Pyarmor 8.3.0'''
416
769
  from sys import version_info as pyver
770
+ from subprocess import check_output
417
771
  pylib = os.path.normpath(os.path.join('@rpath', pylib_name))
418
772
  output = check_output(['otool', '-L', rtbinary])
419
773
  for line in output.splitlines():
@@ -436,183 +790,3 @@ class Repacker:
436
790
  check_call(cmdlist, stdout=DEVNULL, stderr=DEVNULL)
437
791
  except Exception as e:
438
792
  logger.warning('%s', e)
439
-
440
-
441
- # This patch is used to modify the specfile generate by PyInstaller
442
- #
443
- # It has 2 goals:
444
- #
445
- # 1. Find all the imported modules and packages
446
- #
447
- # Save them to hook script
448
- #
449
- # 2. Search scripts and packages in the path of entry script
450
- #
451
- # All of them will be obfuscated automatically
452
- #
453
- spec_patch_code = '''
454
- from PyInstaller.compat import base_prefix
455
- import marshal
456
- import os
457
-
458
- hiddenimports = set([])
459
- plist = set([])
460
- mlist = []
461
- src = {src}
462
- sn = len(src) + 1
463
- prefix = os.path.relpath(src)
464
- prefix = '' if prefix == '.' else prefix
465
-
466
- for name, path, kind in a.pure:
467
- if name.startswith('pyi_rth'):
468
- continue
469
- if path.startswith(src) and not path.startswith(base_prefix):
470
- hiddenimports.add(name)
471
- if name.find('.') == -1 and os.path.basename(path) != '__init__.py':
472
- mlist.append(os.path.join(prefix, path[sn:]))
473
- else:
474
- pkgname = os.path.dirname(path[sn:]).split(os.sep)[0]
475
- plist.add(os.path.join(prefix, pkgname))
476
- else:
477
- hiddenimports.add(name.split('.')[0])
478
-
479
- with open({resfile}, 'wb') as f:
480
- marshal.dump(mlist + list(plist), f)
481
- with open({hookscript}, 'w') as f:
482
- f.write("hiddenimports=[%s]" % ", ".join([repr(x) for x in hiddenimports]))
483
- '''
484
-
485
-
486
- class Repacker6:
487
- """New repacker to support PyInstaller 6.0+
488
-
489
- Args:
490
- ctx: build context
491
- mode: onefile or onefolder
492
- inputs: main script to pack
493
- """
494
-
495
- def __init__(self, ctx, mode, inputs, output):
496
- self.ctx = ctx
497
- self.inputs = inputs
498
- self.output = 'dist' if output is None else os.path.normpath(output)
499
-
500
- self.script = self.inputs[0]
501
- self.obfpath = os.path.normpath(self.ctx.pack_obfpath)
502
- self.packpath = os.path.normpath(self.ctx.pack_basepath)
503
- self.workpath = os.path.join(self.packpath, 'build')
504
- self.pyicmd = [sys.executable, '-m', 'PyInstaller']
505
- self.pyiopts = self.init_opts(mode)
506
- self.autoclean = mode in ('FC', 'DC')
507
-
508
- def init_opts(self, mode):
509
- opts = []
510
- exopts = '--noconfirm', '-y'
511
- if mode == 'auto':
512
- exopts += ('--onefile', '-F', '--onefolder', '-D')
513
- else:
514
- opts.append('-F' if mode in ('onefile', 'F', 'FC') else '-D')
515
- opts.extend(self.ctx.pyi_options)
516
-
517
- exvalues = '--distpath', '--specpath', '--workpath'
518
- return self.filter_opts(opts, exvalues, exopts)
519
-
520
- def filter_opts(self, opts, exvalues, exopts=None):
521
- result = []
522
- isvalue = False
523
- for x in opts:
524
- if isvalue:
525
- isvalue = False
526
- elif x in exvalues:
527
- isvalue = True
528
- elif exopts is None or x not in exopts:
529
- result.append(x)
530
- return result
531
-
532
- def analysis(self):
533
- """Got imported modules and packages by PyInstaller
534
-
535
- Generate hook script
536
- Return file/dir list need to be obfuscated
537
- """
538
- cmdspec = [
539
- sys.executable, '-m', 'PyInstaller.utils.cliutils.makespec',
540
- '--specpath', self.packpath
541
- ]
542
- exvalues = '--name', '-N'
543
- exopts = '-F', '--onefile', '-D', '--onefolder'
544
- cmdspec.extend(self.filter_opts(self.pyiopts, exvalues, exopts))
545
- cmdspec.append(self.script)
546
- logger.debug('%s', ' '.join(cmdspec))
547
- logger.info('call PyInstaller to generate specfile')
548
- check_call(cmdspec, stdout=DEVNULL, stderr=DEVNULL)
549
-
550
- name = os.path.splitext(os.path.basename(self.script))[0]
551
- rtname = self.ctx.runtime_package_name
552
- specfile = os.path.join(self.packpath, name + '.spec')
553
- resfile = os.path.join(self.packpath, 'resources.list')
554
- hookscript = os.path.join(self.packpath, 'hook-%s.py' % rtname)
555
- self.patch_specfile(specfile, hookscript, resfile)
556
-
557
- cmdlist = self.pyicmd + ['--clean', '--workpath', self.workpath]
558
- cmdlist.extend(self.filter_opts(self.pyiopts, exvalues, exopts))
559
- cmdlist.append(specfile)
560
- logger.debug('%s', ' '.join(cmdlist))
561
- logger.info('call PyInstaller to analysis, '
562
- 'it may take several minutes ...')
563
- check_call(cmdlist, stdout=DEVNULL, stderr=DEVNULL)
564
-
565
- with open(resfile, 'rb') as f:
566
- return marshal.load(f)
567
-
568
- def build(self):
569
- """Generate final bundle to output"""
570
- script = os.path.join(self.obfpath, os.path.basename(self.inputs[0]))
571
- cmdlist = self.pyicmd + [
572
- '--clean',
573
- '--distpath', self.output,
574
- '--workpath', self.workpath,
575
- '--specpath', self.packpath,
576
- '--additional-hooks-dir', self.packpath,
577
- ]
578
- cmdlist.extend(self.pyiopts)
579
- cmdlist.append(script)
580
-
581
- logger.debug('%s', ' '.join(cmdlist))
582
- logger.info('call PyInstaller to generate final bundle ...\n')
583
- check_call(cmdlist)
584
- logger.info('')
585
- logger.info('the final bundle "%s" has been generate successfully',
586
- self.output)
587
-
588
- def repack(self, *unused):
589
- """Only for compatible with Repacker"""
590
- self.build()
591
-
592
- def patch_specfile(self, specfile, hookscript, resfile):
593
- # TODO: non-ascii need specify encoding to open file
594
- lines = []
595
- with open(specfile, 'r') as f:
596
- for line in f:
597
- if line.startswith('pyz = PYZ'):
598
- break
599
- lines.append(line)
600
-
601
- lines.append(spec_patch_code.format(
602
- src=repr(os.path.abspath(os.path.dirname(self.script))),
603
- hookscript=repr(os.path.abspath(hookscript)),
604
- resfile=repr(os.path.abspath(resfile))))
605
-
606
- with open(specfile, 'w') as f:
607
- f.write(''.join(lines))
608
-
609
- def check(self):
610
- if os.path.exists(self.output) and self.autoclean:
611
- n = len(os.path.abspath(self.output).split(os.sep))
612
- if n < 3:
613
- prompt = 'Are you sure to remove path "%s" (y/n)? '
614
- choice = input(prompt % self.output).lower()[:1]
615
- if not choice == 'y':
616
- return
617
- logger.info('clean output path "%s"', self.output)
618
- shutil.rmtree(self.output)
@@ -1,6 +1,6 @@
1
1
  from sys import platform
2
2
 
3
- version = '8.5.6'
3
+ version = '8.5.8'
4
4
 
5
5
  # The corresponding version of pytransform.so
6
6
  core_version = 'r52.6'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 1.1
2
2
  Name: pyarmor
3
- Version: 8.5.6
3
+ Version: 8.5.8
4
4
  Summary: A tool used to obfuscate python scripts, bind obfuscated scripts to fixed machine or expire obfuscated scripts.
5
5
  Home-page: https://github.com/dashingsoft/pyarmor
6
6
  Author: Jondy Zhao
Binary file
Binary file
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes