pyarmor 8.5.11__zip → 9.0.0__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 (125) hide show
  1. {pyarmor-8.5.11 → pyarmor-9.0.0}/PKG-INFO +1 -1
  2. {pyarmor-8.5.11 → pyarmor-9.0.0}/README.md +8 -55
  3. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/cli/__init__.py +1 -1
  4. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/cli/__main__.py +20 -5
  5. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/cli/bug.py +3 -3
  6. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/cli/context.py +1 -0
  7. pyarmor-9.0.0/pyarmor/cli/core.data.1 +0 -0
  8. pyarmor-9.0.0/pyarmor/cli/core.data.2 +0 -0
  9. pyarmor-9.0.0/pyarmor/cli/core.data.3 +0 -0
  10. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/cli/default.cfg +6 -5
  11. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/cli/register.py +337 -102
  12. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/config.py +2 -2
  13. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor.egg-info/PKG-INFO +1 -1
  14. pyarmor-9.0.0/pyarmor.egg-info/requires.txt +1 -0
  15. {pyarmor-8.5.11 → pyarmor-9.0.0}/setup.py +1 -1
  16. pyarmor-8.5.11/pyarmor/cli/core.data.1 +0 -0
  17. pyarmor-8.5.11/pyarmor/cli/core.data.2 +0 -0
  18. pyarmor-8.5.11/pyarmor/cli/core.data.3 +0 -0
  19. pyarmor-8.5.11/pyarmor.egg-info/requires.txt +0 -1
  20. {pyarmor-8.5.11 → pyarmor-9.0.0}/MANIFEST.in +0 -0
  21. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/README.rst +0 -0
  22. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/__init__.py +0 -0
  23. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/benchmark.py +0 -0
  24. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/build_meta.py +0 -0
  25. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/cli/bootstrap.py +0 -0
  26. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/cli/config.py +0 -0
  27. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/cli/docker.py +0 -0
  28. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/cli/generate.py +0 -0
  29. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/cli/hdinfo.py +0 -0
  30. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/cli/merge.py +0 -0
  31. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/cli/mixer.py +0 -0
  32. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/cli/plugin.py +0 -0
  33. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/cli/public_capsule.zip +0 -0
  34. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/cli/repack.py +0 -0
  35. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/cli/resource.py +0 -0
  36. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/cli/shell.py +0 -0
  37. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/cobuilder.py +0 -0
  38. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/README-ZH.md +0 -0
  39. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/README.md +0 -0
  40. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/build-for-exe.bat +0 -0
  41. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/build-for-freeze.bat +0 -0
  42. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/build-with-project.bat +0 -0
  43. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/build-with-project.sh +0 -0
  44. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/cx_Freeze/hello.py +0 -0
  45. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/cx_Freeze/queens.py +0 -0
  46. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/cx_Freeze/setup.py +0 -0
  47. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/helloworld/foo.py +0 -0
  48. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/obfuscate-app.bat +0 -0
  49. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/obfuscate-app.sh +0 -0
  50. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/obfuscate-pkg.bat +0 -0
  51. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/obfuscate-pkg.sh +0 -0
  52. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/pack-obfuscated-scripts.bat +0 -0
  53. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/pack-obfuscated-scripts.sh +0 -0
  54. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/py2exe/hello.py +0 -0
  55. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/py2exe/queens.py +0 -0
  56. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/py2exe/setup.py +0 -0
  57. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/pybench/Arithmetic.py +0 -0
  58. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/pybench/Calls.py +0 -0
  59. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/pybench/CommandLine.py +0 -0
  60. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/pybench/Constructs.py +0 -0
  61. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/pybench/Dict.py +0 -0
  62. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/pybench/Exceptions.py +0 -0
  63. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/pybench/Imports.py +0 -0
  64. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/pybench/Instances.py +0 -0
  65. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/pybench/Lists.py +0 -0
  66. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/pybench/Lookups.py +0 -0
  67. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/pybench/NewInstances.py +0 -0
  68. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/pybench/Numbers.py +0 -0
  69. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/pybench/Setup.py +0 -0
  70. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/pybench/Strings.py +0 -0
  71. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/pybench/Tuples.py +0 -0
  72. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/pybench/With.py +0 -0
  73. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/pybench/clockres.py +0 -0
  74. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/pybench/package/__init__.py +0 -0
  75. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/pybench/package/submodule.py +0 -0
  76. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/pybench/pybench.py +0 -0
  77. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/pybench/systimes.py +0 -0
  78. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/simple/queens.py +0 -0
  79. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/testmod/hello.py +0 -0
  80. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/testmod/queens.py +0 -0
  81. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/testpkg/main.py +0 -0
  82. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/testpkg/mypkg/__init__.py +0 -0
  83. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/examples/testpkg/mypkg/foo.py +0 -0
  84. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/helper/__init__.py +0 -0
  85. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/helper/build_data_module.py +0 -0
  86. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/helper/buildext.py +0 -0
  87. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/helper/get_bind_key.py +0 -0
  88. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/helper/get_license_info.py +0 -0
  89. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/helper/get_platform_name.py +0 -0
  90. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/helper/merge.py +0 -0
  91. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/helper/repack.py +0 -0
  92. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/helper/superuntime.py +0 -0
  93. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/license.tri +0 -0
  94. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/packer.py +0 -0
  95. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/platforms/darwin/x86_64/_pytransform.dylib +0 -0
  96. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/platforms/linux/x86/_pytransform.so +0 -0
  97. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/platforms/linux/x86_64/_pytransform.so +0 -0
  98. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/platforms/windows/x86/_pytransform.dll +0 -0
  99. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/platforms/windows/x86_64/_pytransform.dll +0 -0
  100. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/plugins/README.md +0 -0
  101. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/plugins/check_ntp_time.py +0 -0
  102. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/polyfills/__init__.py +0 -0
  103. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/polyfills/argparse.py +0 -0
  104. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/product.key +0 -0
  105. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/project.py +0 -0
  106. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/protect_code.pt +0 -0
  107. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/protect_code2.pt +0 -0
  108. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/public.key +0 -0
  109. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/public_capsule.zip +0 -0
  110. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/pyarmor-deprecated.py +0 -0
  111. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/pyarmor-webui.py +0 -0
  112. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/pyarmor.py +0 -0
  113. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/pyimcore.py +0 -0
  114. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/pyshield.key +0 -0
  115. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/pyshield.lic +0 -0
  116. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/pytransform.py +0 -0
  117. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/reform.py +0 -0
  118. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/register.py +0 -0
  119. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/sppmode.py +0 -0
  120. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor/utils.py +0 -0
  121. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor.egg-info/SOURCES.txt +0 -0
  122. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor.egg-info/dependency_links.txt +0 -0
  123. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor.egg-info/entry_points.txt +0 -0
  124. {pyarmor-8.5.11 → pyarmor-9.0.0}/pyarmor.egg-info/top_level.txt +0 -0
  125. {pyarmor-8.5.11 → pyarmor-9.0.0}/setup.cfg +0 -0
@@ -21,7 +21,7 @@
21
21
  #
22
22
  import os
23
23
 
24
- from base64 import b64decode, urlsafe_b64encode
24
+ from base64 import b64decode, b64encode, urlsafe_b64encode
25
25
  from json import loads as json_loads
26
26
  from string import Template
27
27
 
@@ -31,11 +31,51 @@ from . import logger, CliError
31
31
  # All supported machine flags for group license: [11, 26)
32
32
  MACHFLAGS = 22, 21, 18, 20, 16, 11
33
33
 
34
+ # Upgrade notes for Pyarmor 9
35
+ URL_UPGRADE_V9 = 'https://github.com/dashingsoft/pyarmor/issues/1958'
36
+
37
+ # Template for license info
38
+ LICENSE_INFO_TEMPLATE = '''$advanced
39
+
40
+ $notes
41
+ '''
42
+
34
43
 
35
44
  def parse_token(data):
36
45
  from struct import unpack
37
46
 
38
- if not data or data.find(b' ') == -1:
47
+ if data and data.find(b' ') > 0:
48
+ try:
49
+ buf = b64decode(data.split()[0])
50
+
51
+ token, value = unpack('II', buf[:8])
52
+ rev, features = value & 0xff, value >> 8
53
+ licno = buf[16:34].decode('utf-8')
54
+
55
+ pstr = []
56
+ i = 64
57
+ for k in range(4):
58
+ n = buf[i]
59
+ i += 1
60
+ pstr.append(buf[i:i+n].decode('utf-8') if n
61
+ else '')
62
+ i += n
63
+
64
+ product = ('non-profits(TBD)' if pstr[2] in ('', 'TBD')
65
+ else pstr[2])
66
+ return {
67
+ 'token': token,
68
+ 'rev': rev,
69
+ 'features': features,
70
+ 'licno': licno,
71
+ 'machine': pstr[0],
72
+ 'regname': pstr[1],
73
+ 'product': product,
74
+ 'note': pstr[3],
75
+ }
76
+ except Exception as e:
77
+ logger.warning('bad token: %s', str(e))
78
+
39
79
  return {
40
80
  'token': 0,
41
81
  'rev': 0,
@@ -46,31 +86,50 @@ def parse_token(data):
46
86
  'note': 'This is trial license'
47
87
  }
48
88
 
49
- buf = b64decode(data.split()[0])
50
-
51
- token, value = unpack('II', buf[:8])
52
- rev, features = value & 0xff, value >> 8
53
- licno = buf[16:34].decode('utf-8')
54
-
55
- pstr = []
56
- i = 64
57
- for k in range(4):
58
- n = buf[i]
59
- i += 1
60
- pstr.append(buf[i:i+n].decode('utf-8') if n else '')
61
- i += n
62
-
63
- product = 'non-profits(TBD)' if pstr[2] in ('', 'TBD') else pstr[2]
64
- return {
65
- 'token': token,
66
- 'rev': rev,
67
- 'features': features,
68
- 'licno': licno,
69
- 'machine': pstr[0],
70
- 'regname': pstr[1],
71
- 'product': product,
72
- 'note': pstr[3],
73
- }
89
+
90
+ def show_help_page(prompt, url):
91
+ choice = input('\n'.join(prompt)).lower()[:1]
92
+ if choice == 'h':
93
+ import webbrowser
94
+ webbrowser.open(url)
95
+ return choice
96
+
97
+
98
+ def check_license_version(ctx, silent=False):
99
+ licinfo = ctx.license_info
100
+ rev = licinfo.get('rev', 0)
101
+ token = licinfo.get('token', 0)
102
+ features = licinfo.get('features', 0)
103
+ if rev == 1 and features > 0 and token > 0:
104
+ logger.warning('this license is not ready for Pyarmor 9')
105
+ if silent:
106
+ return False
107
+
108
+ # Group License
109
+ if features == 15:
110
+ prompt = (
111
+ '',
112
+ 'Pyarmor 9 has some changes on license policy',
113
+ 'This group license is still available',
114
+ 'But it need request new device regfile as before',
115
+ 'Press "h" to check Pyarmor 9 Upgrade Notes',
116
+ '',
117
+ 'Help (h), Quit (q): '
118
+ )
119
+ show_help_page(prompt, URL_UPGRADE_V9)
120
+ raise SystemExit('Quit')
121
+
122
+ prompt = (
123
+ '',
124
+ 'Pyarmor 9 has big change on CI/CD pipeline',
125
+ 'If not using Pyarmor License in CI/CD pipeline',
126
+ 'Press "c" to continue',
127
+ 'Otherwise press "h" to check Pyarmor 9.0 Upgrade Notes',
128
+ '',
129
+ 'Continue (c), Help (h), Quit (q): '
130
+ )
131
+ if not show_help_page(prompt, URL_UPGRADE_V9) == 'c':
132
+ raise SystemExit('Quit')
74
133
 
75
134
 
76
135
  class Register(object):
@@ -124,6 +183,7 @@ class Register(object):
124
183
  return 'basic' if info['features'] == 1 else \
125
184
  'pro' if info['features'] == 7 else \
126
185
  'group' if info['features'] == 15 else \
186
+ 'ci' if info['features'] == 23 else \
127
187
  'trial' if info['token'] == 0 else 'unknown'
128
188
 
129
189
  def _license_to(self, info):
@@ -148,13 +208,89 @@ class Register(object):
148
208
 
149
209
  raise CliError('no registration code found in %s' % filename)
150
210
 
211
+ def _register_offline_license(self, fzip, namelist):
212
+ logger.info('machine id in group license: %s', ', '.join(
213
+ [x[7:] for x in namelist if x.startswith('tokens')]))
214
+ for idver in MACHFLAGS:
215
+ machid = self._get_machine_id(idver).decode('utf-8')
216
+ logger.debug('got machine id: %s', machid)
217
+ name = '/'.join(['tokens', machid])
218
+ if name in namelist:
219
+ logger.info('this machine id matchs group license')
220
+ break
221
+ else:
222
+ logger.info('no machine id matchs this group license')
223
+ logger.info('take this machine as docker container, and '
224
+ 'connect to docker host for authentication...')
225
+ mlist = self._get_docker_hostname()
226
+ if not mlist:
227
+ logger.info(
228
+ 'could not get docker host machine id\n%s',
229
+ '\n'.join([
230
+ '',
231
+ 'if this machine is docker container, please '
232
+ 'run command `pyarmor-auth` in docker host, '
233
+ 'and try it again', '',
234
+ 'otherwise please generate new group '
235
+ 'device license for this machine', '',
236
+ 'more information please check section '
237
+ '"using group license" in documentation '
238
+ '"how-to register" guide', ''
239
+ ]))
240
+ raise CliError('this group device license is not for '
241
+ 'this machine')
242
+ for machid in mlist:
243
+ hostname = '/'.join(['tokens', machid])
244
+ if hostname in namelist:
245
+ name = hostname
246
+ break
247
+ else:
248
+ logger.debug('docker host machine ids: %s', mlist)
249
+ raise CliError('this group device license is not for '
250
+ 'this docker host')
251
+
252
+ logger.debug('extracting %s', name)
253
+ self.ctx.save_group_token(fzip.read(name))
254
+
255
+ def _init_token(self, reginfo):
256
+ from struct import pack
257
+ rev, licno, lictp, regname, product = (
258
+ reginfo['rev'], reginfo['rcode'], reginfo['type'],
259
+ reginfo['name'], reginfo['product']
260
+ )
261
+
262
+ token = 0
263
+ old_license = self.license_info
264
+ if old_license['licno'] == licno:
265
+ token = old_license['token']
266
+
267
+ features = (1 if lictp == 'J' else 7 if lictp == 'Z' else
268
+ 15 if lictp == 'G' else 23 if lictp == 'C' else
269
+ 0)
270
+ notes = (
271
+ '* Do not use this file in CI/CD pipeline directly\n'
272
+ '* Only use it to request CI regfile '
273
+ '"pyarmor-ci-%s.zip"' % licno[:6].lstrip('0')
274
+ if lictp == 'C' else ''
275
+ )
276
+
277
+ regname = regname.encode('utf-8')
278
+ product = product.encode('utf-8')
279
+ notes = notes.encode('utf-8')
280
+ data = pack('<II8x20s28xBB2sB2sB2s', token,
281
+ rev | features << 8,
282
+ licno.encode('utf-8'),
283
+ 0,
284
+ len(regname), b'%s',
285
+ len(product), b'%s',
286
+ len(notes), b'%s') % (regname, product, notes)
287
+ return b64encode(data) + b' *=='
288
+
151
289
  def register_regfile(self, regfile, clean=True):
152
290
  from zipfile import ZipFile
153
291
 
154
- for x in (self.ctx.license_group_token, self.ctx.license_token):
155
- if os.path.exists(x):
156
- logger.info('remove old token "%s"', x)
157
- os.remove(x)
292
+ if os.path.exists(self.ctx.license_group_token):
293
+ os.remove(self.ctx.license_group_token)
158
294
 
159
295
  path = self.ctx.reg_path
160
296
  with ZipFile(regfile, 'r') as f:
@@ -163,56 +299,36 @@ class Register(object):
163
299
  f.extract(item, path=path)
164
300
  namelist = f.namelist()
165
301
  if 'group.tokens' in namelist:
166
- logger.info('machine id in group license: %s', ', '.join([
167
- x[7:] for x in namelist if x.startswith('tokens')
168
- ]))
169
- for idver in MACHFLAGS:
170
- machid = self._get_machine_id(idver).decode('utf-8')
171
- logger.info('got machine id: %s', machid)
172
- name = '/'.join(['tokens', machid])
173
- if name in namelist:
174
- logger.info('this machine id matchs group license')
175
- break
176
- else:
177
- logger.info('no machine id matchs this group license')
178
- logger.info('take this machine as docker container, and '
179
- 'connect to docker host for authentication...')
180
- mlist = self._get_docker_hostname()
181
- if not mlist:
182
- logger.info(
183
- 'could not get docker host machine id\n%s',
184
- '\n'.join([
185
- '',
186
- 'if this machine is docker container, please '
187
- 'run command `pyarmor-auth` in docker host, '
188
- 'and try it again', '',
189
- 'otherwise please generate new group '
190
- 'device license for this machine', '',
191
- 'more information please check section '
192
- '"using group license" in documentation '
193
- '"how-to register" guide', ''
194
- ]))
195
- raise CliError('this group device license is not for '
196
- 'this machine')
197
- for machid in mlist:
198
- hostname = '/'.join(['tokens', machid])
199
- if hostname in namelist:
200
- name = hostname
201
- break
202
- else:
203
- logger.debug('docker host machine ids: %s', mlist)
204
- raise CliError('this group device license is not for '
205
- 'this docker host')
302
+ self._register_offline_license(f, namelist)
303
+ elif 'ci.token' in namelist:
304
+ name = 'ci.token'
206
305
  logger.debug('extracting %s', name)
207
- self.ctx.save_group_token(f.read(name))
208
- return
209
- if 'group.info' in namelist:
210
- logger.info('refer to http://pyarmor.readthedocs.io/en/stable/how-to/register.html'
211
- '#using-group-license')
212
- raise CliError('wrong usage for group license')
213
-
214
- logger.info('update license token')
215
- self.update_token()
306
+ self.ctx.save_token(f.read(name))
307
+ elif 'group.info' in namelist:
308
+ logger.info('this file is only used to '
309
+ 'request device regfile:\n\n'
310
+ '\tpyarmor reg -g 1 %s\n', regfile)
311
+ raise CliError('wrong usage for Group License')
312
+ elif 'reg.info' in namelist:
313
+ data = f.read('reg.info')
314
+ info = json_loads(data, encoding='utf-8')
315
+ if info.get('type', '') == 'C':
316
+ logger.info('this file is only used to '
317
+ 'request ci regfile:\n\n'
318
+ '\tpyarmor reg -C %s\n', regfile)
319
+ raise CliError('wrong usage for CI License')
320
+ self.ctx.save_token(self._init_token(info))
321
+ else:
322
+ logger.error('this license is not ready for Pyarmor 9')
323
+ prompt = (
324
+ '',
325
+ 'Pyarmor 9 has big change on CI/CD pipeline',
326
+ 'Press "h" to check Pyarmor 9.0 Upgrade Notes',
327
+ '',
328
+ 'Help (h), Quit (q): '
329
+ )
330
+ show_help_page(prompt, URL_UPGRADE_V9)
331
+ raise SystemExit()
216
332
 
217
333
  def _get_docker_hostname(self):
218
334
  try:
@@ -270,7 +386,7 @@ class Register(object):
270
386
  return path
271
387
 
272
388
  def check_group_license(self, silent=False):
273
- licinfo = self.ctx.license_info
389
+ licinfo = self.license_info
274
390
  if licinfo['features'] & 8:
275
391
  licmach = licinfo.get('machine', '')
276
392
  if not licmach:
@@ -299,12 +415,6 @@ class Register(object):
299
415
  'this group license is not for this machine')
300
416
 
301
417
  def __str__(self):
302
- '''$advanced
303
-
304
- Notes
305
- $notes
306
- '''
307
-
308
418
  info = self.license_info
309
419
  lictype = self._license_type(info)
310
420
 
@@ -319,9 +429,11 @@ $notes
319
429
 
320
430
  bccmode = info['features'] & 2
321
431
  rftmode = info['features'] & 4
432
+ cidmode = info.get('machine', '').startswith('CITK')
322
433
  advanced = [
323
434
  fmt % ('BCC Mode', 'Yes' if bccmode else 'No'),
324
435
  fmt % ('RFT Mode', 'Yes' if rftmode else 'No'),
436
+ fmt % ('CI/CD Mode', 'Yes' if cidmode else 'No'),
325
437
  ]
326
438
  if lictype == 'trial':
327
439
  self.notes.append('* Can\'t obfuscate big script and mix str')
@@ -331,7 +443,13 @@ $notes
331
443
  elif lictype == 'group':
332
444
  self.notes.append('* Offline obfuscation')
333
445
 
334
- lines.append(Template(self.__str__.__doc__).substitute(
446
+ if info['note']:
447
+ self.notes.extend(info['note'].splitlines())
448
+
449
+ if self.notes:
450
+ self.notes.insert(0, 'Notes')
451
+
452
+ lines.append(Template(LICENSE_INFO_TEMPLATE).substitute(
335
453
  advanced='\n'.join(advanced),
336
454
  notes='\n'.join(self.notes),
337
455
  ))
@@ -362,6 +480,24 @@ class WebRegister(Register):
362
480
  conn.request("GET", url[k:])
363
481
  return conn.getresponse()
364
482
 
483
+ def check_request_interval(self, delta=30.0):
484
+ """Make sure no more than 2 requests in 1 minute"""
485
+ tspath = os.path.join(self.ctx.reg_path, 'last_register')
486
+ try:
487
+ st = os.stat(tspath)
488
+ except FileNotFoundError:
489
+ os.makedirs(tspath)
490
+ else:
491
+ from time import sleep, time
492
+ d = delta - (time() - st.st_mtime)
493
+ if d > 0:
494
+ logger.info('last register was within %d seconds, '
495
+ 'waiting for %d seconds', delta, d)
496
+ while time() - st.st_mtime < delta:
497
+ logger.info('waiting ...')
498
+ sleep(3.0)
499
+ os.utime(tspath)
500
+
365
501
  def _send_request(self, url, timeout=6.0):
366
502
  try:
367
503
  return self._request(url)
@@ -418,16 +554,13 @@ class WebRegister(Register):
418
554
  lines = []
419
555
  if upgrade:
420
556
  if rcode and not rcode.startswith('pyarmor-vax-'):
421
- logger.error('please check Pyarmor 8 EULA')
422
557
  raise CliError('old license "%s" can not be upgraded' % rcode)
423
558
  if info['upgrade']:
424
559
  lines.append(upgrade_to_pro_info.substitute(rcode=rcode))
425
560
  else:
426
561
  lines.append(upgrade_to_basic_info.substitute())
427
562
  else:
428
- if info['lictype'] not in ('BASIC', 'PRO', 'GROUP'):
429
- logger.error('this license does not work in Pyarmor 8')
430
- logger.error('please check Pyarmor 8.0 EULA')
563
+ if info['lictype'] not in ('BASIC', 'PRO', 'GROUP', 'CI'):
431
564
  raise CliError('unknown license type %s' % info['lictype'])
432
565
  lines.append('This license registration information will be')
433
566
 
@@ -492,6 +625,8 @@ class WebRegister(Register):
492
625
  reginfo = self.parse_keyfile(keyfile)
493
626
 
494
627
  url = self.regurl(reginfo[1], product=product)
628
+ # Request license file with extra info by rev 2
629
+ url += '&rev=2'
495
630
  if upgrade:
496
631
  url += '&upgrade_to_basic=1'
497
632
  logger.debug('url: %s', url)
@@ -500,23 +635,37 @@ class WebRegister(Register):
500
635
  res = self._send_request(url)
501
636
  regfile = self._handle_response(res)
502
637
 
638
+ logger.info('')
639
+ logger.info('the registration file "%s" has been generated', regfile)
640
+ logger.info('this license has been activated sucessfully')
641
+
503
642
  notes = [
504
- '* Please backup regfile "%s" carefully, and '
505
- 'use this file for subsequent registration' % regfile,
506
- '* Do not use "%s" again' % os.path.basename(keyfile),
643
+ '* Please backup "%s", but do not use it to '
644
+ 'register Pyarmor' % os.path.basename(keyfile),
645
+ '* Please backup regfile "%s", and '
646
+ 'use this file for next any registration' % regfile,
647
+ '* Do not use this file in docker and CI/CD pipeline',
507
648
  ]
508
649
 
509
650
  if group:
510
- logger.info('This group license has been activated sucessfully')
511
651
  notes.append('* Please check `pyarmor reg` in Man page for '
512
652
  'how to register Pyarmor on offline device')
513
- else:
653
+ logger.info('\n\nImport Notes:\n%s\n', '\n'.join(notes))
654
+ return
655
+
656
+ notes.append('')
657
+ notes.append('Next register Pyarmor in build device by this command:')
658
+
659
+ notes.append('\tpyarmor reg %s' % regfile)
660
+ notes.append('')
661
+ logger.info('\n\nImport Notes:\n%s\n', '\n'.join(notes))
662
+
663
+ prompt = 'Do you want register Pyarmor in this machine? (Y/n) '
664
+ choice = input(prompt).lower()[:1]
665
+ if choice == 'y':
514
666
  logger.info('register "%s"', regfile)
515
667
  self.register_regfile(regfile)
516
- logger.info('This license code has been %s successfully',
517
- 'upgraded' if upgrade else 'activated')
518
-
519
- logger.info('Import Notes:\n\n%s\n', '\n'.join(notes))
668
+ logger.info('This license registration information:\n\n%s', self)
520
669
 
521
670
  def _handle_response(self, res):
522
671
  if res and res.code == 200:
@@ -529,16 +678,39 @@ class WebRegister(Register):
529
678
  with open(filename, 'wb') as f:
530
679
  f.write(data[n:])
531
680
  self._write_group_info(filename, data[:n])
681
+ elif data.startswith(b'REGINFO:'):
682
+ i = len(b'REGINFO:')
683
+ n = data[i] + (data[i+1] << 8)
684
+ i += 2
685
+ n += i
686
+ with open(filename, 'wb') as f:
687
+ f.write(data[n:])
688
+ self._write_reg_info(filename, data[i:n])
532
689
  else:
690
+ # TBD: it should not happened
691
+ logger.warning('no REGINFO found')
533
692
  with open(filename, 'wb') as f:
534
693
  f.write(data)
535
694
  return filename
536
695
 
537
696
  elif res:
538
- raise CliError(res.read().decode('utf-8'))
697
+ data = res.read()
698
+ logger.debug('server return(%d): %s', res.code, data)
699
+ try:
700
+ msg = data.decode('utf-8')
701
+ except Exception as e:
702
+ logger.debug('decode server data error "%s"', e)
703
+ msg = data
704
+ raise CliError(msg)
539
705
 
540
706
  raise CliError('no response from license server')
541
707
 
708
+ def _write_reg_info(self, filename, data):
709
+ from zipfile import ZipFile
710
+ logger.info('write reg information')
711
+ with ZipFile(filename, 'a') as f:
712
+ f.writestr('reg.info', data)
713
+
542
714
  def _write_group_info(self, filename, data):
543
715
  from zipfile import ZipFile
544
716
  logger.info('write group information')
@@ -607,3 +779,66 @@ class WebRegister(Register):
607
779
 
608
780
  logger.info('please copy deivce regfile to offline device and run')
609
781
  logger.info(' pyarmor reg %s', filename)
782
+
783
+ def _write_ci_info(self, filename, data):
784
+ from zipfile import ZipFile
785
+ logger.info('write ci information')
786
+ with ZipFile(filename, 'a') as f:
787
+ f.writestr('ci.token', data)
788
+
789
+ def request_ci_regfile(self, regfile, rev=2):
790
+ logger.info('request ci regfile by "%s"', regfile)
791
+ from zipfile import ZipFile
792
+
793
+ with ZipFile(regfile, 'r') as f:
794
+ if 'reg.info' not in f.namelist():
795
+ logger.error('missing reg.info in regfile')
796
+ raise CliError('can not request CI license')
797
+ reginfo = json_loads(f.read('reg.info'))
798
+
799
+ ucode = reginfo['ucode']
800
+ rcode = reginfo['rcode']
801
+ if len(ucode) != 192:
802
+ raise CliError('invalid registration file "%s"', regfile)
803
+
804
+ url = self.regurl('ci/%s' % ucode)
805
+ paras = (('rev', str(rev)),)
806
+ url += '&'.join(['='.join(x) for x in paras])
807
+ logger.debug('url: %s', url)
808
+
809
+ logger.info('send request to server')
810
+ res = self._send_request(url)
811
+
812
+ logger.info('handle response')
813
+ if res is None:
814
+ raise CliError('no response from license server')
815
+
816
+ elif res.code != 200:
817
+ raise CliError(res.read().decode('utf-8'))
818
+
819
+ data = res.read()
820
+ if not data.startswith(b'CITOKEN:'):
821
+ raise CliError('wrong server data: "%s"' % data)
822
+
823
+ i = len(b'CITOKEN:') + 2
824
+ n = data[i-2] + (data[i-1] << 8)
825
+ token = data[i:i+n]
826
+
827
+ rn = rcode[-6:].lstrip('0')
828
+ cifile = 'pyarmor-ci-%s.zip' % rn
829
+
830
+ with ZipFile(regfile, 'r') as src:
831
+ with ZipFile(cifile, 'w') as dst:
832
+ for x in src.namelist():
833
+ dst.writestr(x, src.read(x))
834
+ dst.writestr('ci.token', token)
835
+
836
+ logger.info('generate CI regfile "%s" successfully', cifile)
837
+
838
+ ver = '.'.join([str(x) for x in self.ctx.version])
839
+ logger.info('\n\nCheck CI license in local machine by:\n'
840
+ '\n\tpyarmor reg %s\n\n'
841
+ 'Register Pyarmor in CI/CD pipeline by:\n'
842
+ '\n\tpip install pyarmor==%s\n'
843
+ '\tpyarmor reg %s\n',
844
+ cifile, ver, cifile)
@@ -1,6 +1,6 @@
1
1
  from sys import platform
2
2
 
3
- version = '8.5.11'
3
+ version = '9.0.0'
4
4
 
5
5
  # The corresponding version of pytransform.so
6
6
  core_version = 'r52.6'
@@ -43,7 +43,7 @@ platform_url = 'https://pyarmor.dashingsoft.com/files/{version}'
43
43
 
44
44
  key_url = 'https://api.dashingsoft.com/product/key/%s/query'
45
45
  reg_url = 'https://api.dashingsoft.com/product/key/activate/%s/'
46
- buy_url = 'https://order.shareit.com/cart/add?vendorid=200089125&PRODUCT[300871197]=1'
46
+ buy_url = 'https://jondy.github.io/paypal/index.html'
47
47
  help_url = 'https://pyarmor.readthedocs.io/{lang}/v%s/{page}' % version
48
48
 
49
49
  sppmode_info = {
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 1.1
2
2
  Name: pyarmor
3
- Version: 8.5.11
3
+ Version: 9.0.0
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
@@ -0,0 +1 @@
1
+ pyarmor.cli.core~=7.6.0
@@ -113,7 +113,7 @@ setup(
113
113
  },
114
114
 
115
115
  install_requires=[
116
- 'pyarmor.cli.core~=6.5.3'
116
+ 'pyarmor.cli.core~=7.6.0'
117
117
  ],
118
118
 
119
119
  entry_points={
Binary file
Binary file
Binary file
@@ -1 +0,0 @@
1
- pyarmor.cli.core~=6.5.3
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