pyarmor.cli 9.2.6__3-py3-none-any.whl

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/cli/shell.py ADDED
@@ -0,0 +1,481 @@
1
+ #! /usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+ #
4
+ #############################################################
5
+ # #
6
+ # Copyright @ 2024 - Dashingsoft corp. #
7
+ # All rights reserved. #
8
+ # #
9
+ # Pyarmor #
10
+ # #
11
+ # Version: 9.1.0 - #
12
+ # #
13
+ #############################################################
14
+ #
15
+ #
16
+ # @File: cli/shell.py
17
+ #
18
+ # @Author: Jondy Zhao (pyarmor@163.com)
19
+ #
20
+ # @Create Date: Fri Nov 15 10:52:00 CST 2024
21
+ #
22
+ import configparser
23
+ import cmd
24
+ import shlex
25
+
26
+ from .model import SECTIONS, GROUPS
27
+
28
+
29
+ class CfgEntity:
30
+ """Store option to cfg file"""
31
+
32
+ def __init__(self, cfgfiles, encoding=None):
33
+ self._cfgfiles = cfgfiles
34
+ self._reader = None
35
+ self._writer = None
36
+ self._index = -1
37
+ self._encoding = encoding
38
+
39
+ def _load_cfg(self, filenames):
40
+ cfg = configparser.ConfigParser(
41
+ empty_lines_in_values=False,
42
+ interpolation=configparser.ExtendedInterpolation(),
43
+ )
44
+ cfg.read(filenames, encoding=self._encoding)
45
+ return cfg
46
+
47
+ @property
48
+ def cfgfile(self):
49
+ return self._cfgfiles[self._index]
50
+
51
+ @property
52
+ def reader(self):
53
+ if self._reader is None:
54
+ self._reader = self._load_cfg(self._cfgfiles)
55
+ return self._reader
56
+
57
+ @property
58
+ def writer(self):
59
+ if self._writer is None:
60
+ self._writer = self._load_cfg(self.cfgfile)
61
+ return self._writer
62
+
63
+ def store(self, sect, opt, value):
64
+ for cfg in (self.writer, self.reader):
65
+ if not cfg.has_section(sect):
66
+ cfg.add_section(sect)
67
+ cfg.set(sect, opt, value)
68
+
69
+ def fetch(self, sect, opt):
70
+ cfg = self.reader
71
+ if cfg.has_section(sect):
72
+ return cfg[sect].get(opt, None)
73
+
74
+ def remove(self, sect, opt=None):
75
+ for cfg in (self.writer, self.reader):
76
+ if cfg.has_section(sect):
77
+ if opt is None:
78
+ cfg.remove_section(sect)
79
+ else:
80
+ cfg.remove_option(sect, opt)
81
+
82
+ def reset(self, index):
83
+ if self._index == index:
84
+ return
85
+ self._index = index
86
+ self._reader = self._writer = None
87
+
88
+ def save(self):
89
+ with open(self.cfgfile, 'w', encoding=self._encoding) as f:
90
+ self.writer.write(f)
91
+
92
+
93
+ class Domain:
94
+
95
+ def __init__(self, name, default='pyarmor'):
96
+ self.name = name
97
+ self._dirty = False
98
+
99
+ self._sections = []
100
+ self._groups = []
101
+
102
+ self._default = Section(default, parent=self)
103
+ self._cfgentity = None
104
+ self._children = None
105
+
106
+ @property
107
+ def qualname(self):
108
+ return self.name
109
+
110
+ @property
111
+ def title(self):
112
+ return '(%s) ' % self.name
113
+
114
+ @property
115
+ def dirty(self):
116
+ return self._dirty
117
+
118
+ @dirty.setter
119
+ def dirty(self, value):
120
+ self._dirty = value
121
+
122
+ @property
123
+ def groups(self):
124
+ for x in self._groups:
125
+ yield x
126
+
127
+ @property
128
+ def sections(self):
129
+ for x in self._sections:
130
+ yield x
131
+
132
+ @property
133
+ def options(self):
134
+ if self._default:
135
+ for x in self._default.options:
136
+ yield x
137
+
138
+ @property
139
+ def children(self):
140
+ if self._children is None:
141
+ items = {x.name: x for x in self.groups}
142
+ items.update({x.name: x for x in self.sections})
143
+ self._children = items
144
+ return self._children
145
+
146
+ @property
147
+ def cfgentity(self):
148
+ return self._cfgentity
149
+
150
+ def link(self, cfgentity):
151
+ self._cfgentity = cfgentity
152
+
153
+ def save(self, force=False):
154
+ cfgentity = self._cfgentity
155
+ if (self.dirty or force) and cfgentity:
156
+ cfgentity.save()
157
+ self._dirty = False
158
+
159
+ def add_section(self, name):
160
+ if self._default and self._default.name == name:
161
+ return
162
+ self._sections.append(Section(name, parent=self))
163
+
164
+ def add_group(self, name, sections):
165
+ group = Group(name, parent=self)
166
+ group.add_sections(sections)
167
+ self._groups.append(group)
168
+
169
+
170
+ class Section:
171
+
172
+ def __init__(self, name, parent=None):
173
+ self.parent = parent
174
+ self.name = name
175
+ self.models = SECTIONS.get(name, [])
176
+ self._options = None
177
+ self._children = {}
178
+
179
+ @property
180
+ def qualname(self):
181
+ parent = self.parent
182
+ name = self.name
183
+ return ':'.join([parent.qualname, name])
184
+
185
+ @property
186
+ def title(self):
187
+ return '({0})[{1}] '.format(*self.qualname.split(':', 1))
188
+
189
+ @property
190
+ def options(self):
191
+ if self._options is None:
192
+ self._options = [x.factory(self) for x in self.models]
193
+
194
+ for x in self._options:
195
+ yield x
196
+
197
+ @property
198
+ def children(self):
199
+ return self._children
200
+
201
+ @property
202
+ def cfgentity(self):
203
+ return self.parent.cfgentity
204
+
205
+ def store(self, opt, value):
206
+ self.cfgentity.store(self.name, opt, value)
207
+
208
+ def fetch(self, opt):
209
+ return self.cfgentity.fetch(self.name, opt)
210
+
211
+ def remove(self, opt):
212
+ self.cfgentity.remove(self.name, opt)
213
+
214
+
215
+ class Group(Section):
216
+
217
+ def __init__(self, name, parent=None, sections=None):
218
+ super().__init__(name, parent=parent)
219
+ self._groups = []
220
+ self._sections = []
221
+
222
+ @property
223
+ def group(self):
224
+ for x in self._group:
225
+ yield x
226
+
227
+ @property
228
+ def sections(self):
229
+ for x in self._sections:
230
+ yield x
231
+
232
+ @property
233
+ def children(self):
234
+ if self._children is None:
235
+ items = {x.name: x for x in self.groups}
236
+ items.update({x.name: x for x in self.sections})
237
+ self._children = items
238
+ return self._children
239
+
240
+ def add_group(self, name, sections):
241
+ group = Group(name, parent=self)
242
+ group.add_sections(sections)
243
+ self._group.append(group)
244
+
245
+ def add_sections(self, sections):
246
+ self._sections.extend([
247
+ Section(x, parent=self) for x in sections
248
+ ])
249
+
250
+
251
+ class PyarmorShell(cmd.Cmd):
252
+
253
+ intro = 'Type help or ? to list commands.\n'
254
+ col = 60
255
+
256
+ def __init__(self, ctx, domain='local'):
257
+ super().__init__()
258
+ self.ctx = ctx
259
+ self._entity = CfgEntity([
260
+ ctx.default_config,
261
+ ctx.global_config,
262
+ ctx.local_config
263
+ ], encoding=ctx.encoding)
264
+ self._domains = self._init_domains()
265
+ self._domain = self._section = self._domains[domain]
266
+
267
+ def _init_domains(self):
268
+ gs = Domain('global')
269
+ ls = Domain('local')
270
+ ps = Domain('project', default='project')
271
+
272
+ gs.link(self._entity)
273
+ ls.link(self._entity)
274
+ ps.link(self._entity)
275
+
276
+ sections = 'finder', 'builder', 'runtime', 'pack'
277
+ [(gs.add_section(x), ls.add_section(x)) for x in sections]
278
+
279
+ for domain in (gs, ls):
280
+ for name in ('filter', 'bcc'):
281
+ domain.add_group(name, GROUPS[name])
282
+
283
+ ps.add_section('rft')
284
+ ps.add_section('mini')
285
+ ps.add_section('vmc')
286
+ ps.add_section('ecc')
287
+
288
+ return {'global': gs, 'local': ls, 'project': ps}
289
+
290
+ @property
291
+ def section(self):
292
+ return self._section
293
+
294
+ @property
295
+ def prompt(self):
296
+ return self.section.title
297
+
298
+ def get_sections(self, name=''):
299
+ obj = self.section
300
+ sects = [x for x in getattr(obj, 'groups', [])]
301
+ sects.extend([x for x in getattr(obj, 'sections', [])])
302
+ return (sects if name in ('-a', '*', '') else
303
+ [x for x in sects if x.name.startswith(name)])
304
+
305
+ def get_options(self, name=''):
306
+ options = [x for x in self.section.options]
307
+ return (options if name in ('-a', '*', '') else
308
+ [x for x in options if x.name.startswith(name)])
309
+
310
+ def printf(self, *args):
311
+ print(*args)
312
+
313
+ def find(self, opt):
314
+ for item in self.section.options:
315
+ if item.name == opt:
316
+ return item
317
+
318
+ def save(self):
319
+ self._domain.save()
320
+
321
+ def do_exit(self, arg=None):
322
+ """Finish config and exit"""
323
+ self.save()
324
+ self.printf('')
325
+ self.printf('Thank you for using Pyarmor')
326
+ return True
327
+ do_EOF = do_q = do_exit
328
+
329
+ def do_use(self, arg):
330
+ """Switch domain: global, local, project"""
331
+ names = list(self._domains.keys())
332
+ if arg not in names:
333
+ self.printf('Invalid name: ', arg)
334
+ self.printf('Please type one of', str(names))
335
+ elif self._domain.name == arg:
336
+ pass
337
+ else:
338
+ self._domain.save()
339
+ if arg == 'global':
340
+ self._entity.reset(index=1)
341
+ elif self._domain.name == 'global':
342
+ self._entity.reset(index=-1)
343
+ self._domain = self._domains[arg]
344
+ self._section = self._domain
345
+
346
+ def do_ls(self, arg):
347
+ """List all the available items in current domain"""
348
+ sections = self.get_sections(arg)
349
+ if sections:
350
+ self.printf('Sections:')
351
+ self.columnize([x.name for x in sections], self.col)
352
+ self.printf('')
353
+
354
+ options = self.get_options(arg)
355
+ if options:
356
+ self.printf('Options:')
357
+ self.columnize([x.name for x in options], self.col)
358
+ self.printf('')
359
+
360
+ def do_cd(self, arg):
361
+ """Switch to section, .. to parent, blank to top"""
362
+ if arg == '..':
363
+ if self._section is not self._domain:
364
+ self._section = self._section.parent
365
+ elif arg:
366
+ item = self.section.children.get(arg)
367
+ if item:
368
+ self._section = item
369
+ else:
370
+ self.printf('No item', repr(arg))
371
+ else:
372
+ self._section = self._domain
373
+
374
+ def do_get(self, arg):
375
+ """Show option value"""
376
+ options = self.get_options(arg)
377
+ if not options:
378
+ self.printf('No found any', repr(arg))
379
+ return
380
+ for opt in options:
381
+ value = opt.value
382
+ if value is not None:
383
+ self.printf('%-20s= %s' % (opt.name, value))
384
+
385
+ def do_info(self, arg):
386
+ """List sections, options, and all the values"""
387
+ if arg == '':
388
+ self.do_ls('')
389
+ self.do_get('')
390
+ return
391
+ item = self.section.children.get(arg)
392
+ if item:
393
+ self.do_cd(arg)
394
+ self.do_ls('')
395
+ self.do_get('')
396
+ self.do_cd('..')
397
+ else:
398
+ item = self.find(arg)
399
+ if item:
400
+ self.printf(item.usage())
401
+ self.do_get(arg)
402
+ else:
403
+ self.printf('No found', arg)
404
+
405
+ def do_set(self, arg):
406
+ """Set option value"""
407
+ if arg.find(' ') == -1:
408
+ self.printf('Missing value')
409
+ return
410
+ name, value = arg.split(None, 1)
411
+ item = self.find(name)
412
+ if item:
413
+ c = value[:1]
414
+ if c in ('"', "'"):
415
+ value = value.strip(c)
416
+ try:
417
+ item.value = value
418
+ self._domain.dirty = True
419
+ except ValueError as e:
420
+ self.printf(str(e))
421
+ else:
422
+ self.printf('No found', name)
423
+
424
+ def do_reset(self, arg):
425
+ """Reset option in the domain"""
426
+ if arg in ('', '*'):
427
+ self.printf('Please specify one option')
428
+ return
429
+ item = self.find(arg)
430
+ if item:
431
+ item.reset()
432
+ self._domain.dirty = True
433
+ else:
434
+ self.printf('No found', arg)
435
+
436
+ def do_push(self, arg, silent=False):
437
+ """Append new value to option"""
438
+ if arg.find(' ') == -1:
439
+ self.printf('Missing value')
440
+ return
441
+ name, value = arg.split(None, 1)
442
+ item = self.find(name)
443
+ if item:
444
+ for x in shlex.split(value):
445
+ try:
446
+ item.push(x)
447
+ except ValueError as e:
448
+ self.printf(str(e))
449
+ break
450
+ else:
451
+ self._domain.dirty = True
452
+ self.do_get(name)
453
+ else:
454
+ self.printf('No found', name)
455
+
456
+ def do_pop(self, arg):
457
+ """Remove one choice from option"""
458
+ if arg.find(' ') == -1:
459
+ self.printf('Missing value')
460
+ return
461
+ name, value = arg.split(None, 1)
462
+ item = self.find(name)
463
+ if item:
464
+ for x in shlex.split(value):
465
+ item.pop(x)
466
+ self._domain.dirty = True
467
+ self.do_get(name)
468
+ else:
469
+ self.printf('No found', name)
470
+
471
+
472
+ if __name__ == '__main__':
473
+ from os.path import join as joinpath, abspath, expanduser
474
+
475
+ from .context import Context
476
+
477
+ home = joinpath('~', '.pyarmor')
478
+ home = abspath(expanduser(home))
479
+
480
+ ctx = Context(home)
481
+ PyarmorShell(ctx).cmdloop()
@@ -0,0 +1,74 @@
1
+ Metadata-Version: 2.1
2
+ Name: pyarmor.cli
3
+ Version: 9.2.6
4
+ Summary: A comand line tool to obfuscate python scripts
5
+ Home-page: https://github.com/dashingsoft/pyarmor
6
+ Author: Jondy Zhao
7
+ Author-email: pyarmor@163.com
8
+ License: Free To Use But Restricted
9
+ Keywords: protect obfuscate encrypt obfuscation distribute
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: License :: Free To Use But Restricted
12
+ Classifier: Operating System :: MacOS
13
+ Classifier: Operating System :: Microsoft :: Windows
14
+ Classifier: Operating System :: POSIX
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Topic :: Software Development :: Build Tools
17
+ Classifier: Topic :: Utilities
18
+ Classifier: Topic :: Security
19
+ Classifier: Topic :: System :: Software Distribution
20
+ Requires-Dist: pyarmor.cli.core ~=8.1.1
21
+
22
+ Protect Python Scripts By Pyarmor
23
+ =================================
24
+
25
+ Pyarmor is a command line tool used to obfuscate python scripts, bind obfuscated scripts to fixed machine or expire obfuscated scripts.
26
+
27
+ Key Features
28
+ ------------
29
+
30
+ * The obfuscated script is still a normal `.py` script, in most of cases the original python scripts can be replaced with obfuscated scripts seamlessly.
31
+ * Provide many ways to obfuscate the scripts to balance security and performance
32
+ * Rename functions/methods/classes/variables/arguments, irreversible obfuscation
33
+ * Convert part of Python functions to C function, compile to binary by high optimize option, irreversible obfuscation
34
+ * Bind obfuscated scripts to fixed machine or expire obfuscted scripts
35
+ * Protect obfuscated scripts by Themida (Only for Windows)
36
+
37
+ Support Platforms
38
+ -----------------
39
+
40
+ * Python 3.7~3.15
41
+ * Windows
42
+ * Many linuxs, include embedded systems
43
+ * Apple Intel and Apple Silicon
44
+
45
+ Quick Start
46
+ -----------
47
+
48
+ Install::
49
+
50
+ pip install pyarmor
51
+
52
+ Obfuscate the script `foo.py`::
53
+
54
+ pyarmor gen foo.py
55
+
56
+ This command generates an obfuscated script `dist/foo.py` like this:
57
+
58
+ .. code:: python
59
+
60
+ from pyarmor_runtime import __pyarmor__
61
+ __pyarmor__(__name__, __file__, b'\x28\x83\x20\x58....')
62
+
63
+ Run it::
64
+
65
+ python dist/foo.py
66
+
67
+ More Resources
68
+ --------------
69
+
70
+ - `Home <https://github.com/dashingsoft/pyarmor>`_
71
+ - `Website <http://pyarmor.dashingsoft.com>`_
72
+ - `中文网站 <http://pyarmor.dashingsoft.com/index-zh.html>`_
73
+ - `Issues <https://github.com/dashingsoft/pyarmor/issues>`_
74
+ - `Documentation <https://pyarmor.readthedocs.io/>`_
@@ -0,0 +1,30 @@
1
+ pyarmor/cli/__init__.py,sha256=hsPY2kypxxO4MlApFlgRoO1rRjzUr2r8jZxWZxibXrc,1153
2
+ pyarmor/cli/__main__.py,sha256=0IhOmOhs91SSYOALE-hz84LjAVxfe0XtokLSn3xxUvU,26604
3
+ pyarmor/cli/batch.py,sha256=51uBFWRdQk3Fa1l1EdLj-KwN7fwY9D6tfJXpR2WRSg8,1671
4
+ pyarmor/cli/bootstrap.py,sha256=C0RIl-PxJVEVISMGMgotZo8Q-jZQ8ztN7-IYxu4O-C0,7189
5
+ pyarmor/cli/bug.py,sha256=fwT_2oPi4rcLN5ziYEuZS2IKLljt05hKEbQM1fjkM88,4872
6
+ pyarmor/cli/command.py,sha256=n2j0Luwm5WXf5wt_NBmmbhzi7fmwnr9X_tgw7fhcSXg,18212
7
+ pyarmor/cli/config.py,sha256=Roti0bOPzUELm3zp_XLCUphZ_eFzhTGTZVcN_dJ1_lc,10795
8
+ pyarmor/cli/context.py,sha256=TogVCF9-jDyYJgLn9YQVlIYgtzB50OC5dOSKvOsHcww,24388
9
+ pyarmor/cli/core.data.1,sha256=TwImKy17vfR04b_Za6rN6DPDGtx8fdHz1ANAbDUllho,299632
10
+ pyarmor/cli/core.data.2,sha256=43qFFxPg_50oMcx1GETBMOZqKYKy1le8bsE1VeJz2wg,231091
11
+ pyarmor/cli/core.data.3,sha256=So9jEsfw2H3QEMkzR6IffB1fWPCAhxMtP1wuPl160G8,171453
12
+ pyarmor/cli/default.cfg,sha256=xG-o3LgzIrZpwWumaWsuizdqTP_xpEfBQ9tTKUtz4YE,14080
13
+ pyarmor/cli/docker.py,sha256=f82zF2LgLXtCLI0w_EtMGoKDuejJFDQbSb_zhoHDSss,6469
14
+ pyarmor/cli/generate.py,sha256=zLp5bqYffrRA_uEJzcXsydaWvVIadiZoEXzRzAvSmrM,9445
15
+ pyarmor/cli/hdinfo.py,sha256=JK9i-4UrU-4bljzi3Z_0pKKHqHlT9sZde8wx4SP8BG8,2537
16
+ pyarmor/cli/merge.py,sha256=0QqQ8idac5OVvzw6tOtdx5qWlSdD1NzvmWeCiLkvLns,7282
17
+ pyarmor/cli/mixer.py,sha256=i4IrXukoG5L3V3Wv5BgDSTkNU5NB03-Q4bgsWwug6LY,3956
18
+ pyarmor/cli/model.py,sha256=K6Fec0tgRYtoXZgsmoaEq-k0-ZOg1YQPQS6ahTUFsDE,10933
19
+ pyarmor/cli/plugin.py,sha256=Nxm249i9UbwUhLuirwIlKw9k_FnVzd0mlo4_ATPYjz4,11117
20
+ pyarmor/cli/project.py,sha256=FNNxKI4dHliW6ziPDrYILeOM9-gQW89rY72GE2ixI70,37463
21
+ pyarmor/cli/public_capsule.zip,sha256=1r4u42ixfocGPMQc0OklpoHF3nvVW6GA1f4SwcEJWVI,2487
22
+ pyarmor/cli/register.py,sha256=OuBjyD8uxGRJhs2ke29zqKW3ee3_JR5FqbkSufkbdkM,39973
23
+ pyarmor/cli/repack.py,sha256=J9okR-1NdgROcRvpsvDTir11eDAH0JXfbiOGl51gphE,28679
24
+ pyarmor/cli/resource.py,sha256=NVVkn2VNfv8K55pRPWaGfvchl3Nu9JLaoifm6qohcWw,8630
25
+ pyarmor/cli/shell.py,sha256=W5fcMbYXdTKB77loHsPeg2vEVoWJPHLfNYHG-4DT-Y4,13268
26
+ pyarmor_cli-9.2.6.dist-info/METADATA,sha256=gy2eI0LKdxZVRIcjHQ2sZKZ6sPwP0hGZ23EDoy1LsS8,2375
27
+ pyarmor_cli-9.2.6.dist-info/WHEEL,sha256=kaMOOuGDRs3OZA3I9YTs0dJFtrnzzh8BHRx5jSb3e54,100
28
+ pyarmor_cli-9.2.6.dist-info/entry_points.txt,sha256=QDU0TXJn8QG3tkLK4_hoSVW7bvbrMca8hDkIMyIDwow,93
29
+ pyarmor_cli-9.2.6.dist-info/top_level.txt,sha256=UE1ovZ_90YzwF_lZ3LV7o8HKLe-RgzUaUUvdH5UTUus,8
30
+ pyarmor_cli-9.2.6.dist-info/RECORD,,
@@ -0,0 +1,6 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (75.3.0)
3
+ Root-Is-Purelib: true
4
+ Build: 3
5
+ Tag: py3-none-any
6
+
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ pyarmor = pyarmor.cli.__main__:main
3
+ pyarmor-auth = pyarmor.cli.docker:main
@@ -0,0 +1 @@
1
+ pyarmor