def licenses(name='reg-001', expired=None, bind_disk=None, bind_mac=None, bind_ipv4=None, bind_data=None, key=None): pytransform_bootstrap() capsule = DEFAULT_CAPSULE if not os.path.exists(capsule): make_capsule(capsule) fmt = '' if expired is None else '*TIME:%.0f\n' % ( expired if isinstance(expired, (int, float)) else float(expired) if expired.find('-') == -1 else time.mktime(time.strptime(expired, '%Y-%m-%d'))) if bind_disk: fmt = '%s*HARDDISK:%s' % (fmt, bind_disk) if bind_mac: fmt = '%s*IFMAC:%s' % (fmt, bind_mac) if bind_ipv4: fmt = '%s*IFIPV4:%s' % (fmt, bind_ipv4) fmt = fmt + '*CODE:' extra_data = '' if bind_data is None else (';' + bind_data) return make_license_key(capsule, fmt + name + extra_data, key=key)
def _obfuscate(args): '''Obfuscate scripts without project''' path = args.src logging.info('Obfuscate scripts in path "%s" ...', path) capsule = os.path.join(path, capsule_filename) if not os.path.exists(capsule): logging.info('Generate capsule %s', capsule) make_capsule(capsule) output = args.output files = Project.build_globfiles(args.patterns, path) filepairs = [(os.path.join(path, x), os.path.join(output, x)) for x in files] mode = Project.map_obfuscate_mode(default_obf_module_mode, default_obf_code_mode) logging.info('Obfuscate scripts with mode %s', mode) logging.info('Save obfuscated scripts to "%s"', output) for a, b in filepairs: logging.info('\t%s -> %s', a, b) obfuscate_scripts(filepairs, mode, capsule, output) logging.info('Make runtime files') make_runtime(capsule, output) for entry in args.entry.split(','): filename = os.path.join(output, entry.strip()) if not os.path.exists(filename): shutil.copy(os.path.join(path, entry.strip()), filename) logging.info('Update entry script %s', filename) make_entry(filename) logging.info('Obfuscate %d scripts OK.', len(files))
def _capsule(args): '''Make capsule separately''' capsule = os.path.join(args.path, capsule_filename) logging.info('Generating capsule %s ...', capsule) if os.path.exists(capsule): logging.info('Do nothing, capsule %s has been exists', capsule) else: make_capsule(capsule)
def _capsule(args): '''Generate public capsule explicitly.''' capsule = os.path.join(args.path, capsule_filename) if args.force or not os.path.exists(capsule): logging.info('Generating public capsule ...') make_capsule(capsule) else: logging.info('Do nothing, capsule %s has been exists', capsule)
def _capsule(args): '''Make project capsule used to obfuscate scripts''' capsule = os.path.join(args.path, capsule_filename) logging.info('Generating capsule %s ...', capsule) if os.path.exists(capsule): logging.info('Do nothing, capsule %s has been exists', capsule) else: make_capsule(capsule)
def _init(args): '''Create an empty project or reinitialize an existing one EXAMPLES pyarmor init --src=examples/simple --entry=queens.py project1 ''' if args.clone: logging.info( 'Warning: option --clone is deprecated, use --capsule instead ') _clone(args) return path = args.project logging.info('Create project in %s ...', path) if not os.path.exists(path): logging.info('Make project directory %s', path) os.makedirs(path) src = os.path.abspath(args.src) logging.info('Python scripts base path: %s', src) name = os.path.basename(os.path.abspath(path)) if (args.type == 'pkg') or \ (args.type == 'auto' and os.path.exists(os.path.join(src, '__init__.py'))): logging.info('Project is configured as package') project = Project(name=name, title=name, src=src, entry=args.entry if args.entry else '__init__.py', is_package=1, obf_code_mode='wrap') else: logging.info('Project is configured as standalone application.') project = Project(name=name, title=name, src=src, entry=args.entry) if args.capsule: capsule = os.path.abspath(args.capsule) logging.info('Share capsule with %s', capsule) project._update(dict(capsule=capsule)) else: logging.info('Create project capsule ...') filename = os.path.join(path, capsule_filename) make_capsule(filename) logging.info('Project capsule %s created', filename) logging.info('Create configure file ...') filename = os.path.join(path, config_filename) project.save(path) logging.info('Configure file %s created', filename) logging.info('Create pyarmor command ...') script = make_command(plat_name, sys.executable, sys.argv[0], path) logging.info('Pyarmor command %s created', script) logging.info('Project init successfully.')
def _init(args): '''Create an empty project or reinitialize an existing one This command creates an empty project in the specified path - basically a configure file .pyarmor_config, a project capsule .pyarmor_capsule.zip, and a shell script "pyarmor" will be created (in windows, it called "pyarmor.bat"). Option --src specifies where to find python source files. By default, all .py files in this directory will be included in this project. Option --entry specifies main script, which could be run directly after obfuscated. Option --clone specifies another project path. It it is set, no new project capsule is generated, just copy capsule from this project. EXAMPLES python pyarmor.py init --src=examples --entry=queens.py project1 cd project1/ ./pyarmor info ''' if args.clone: _clone(args) return path = args.project logging.info('Create project in %s ...', path) if not os.path.exists(path): logging.info('Make project directory %s', path) os.makedirs(path) src = os.path.abspath(args.src) logging.info('Python scripts base path: %s', src) name = os.path.basename(os.path.abspath(path)) project = Project(name=name, title=name, src=src, entry=args.entry) logging.info('Create configure file ...') filename = os.path.join(path, config_filename) project.save(path) logging.info('Configure file %s created', filename) logging.info('Create project capsule ...') filename = os.path.join(path, capsule_filename) make_capsule(filename) logging.info('Project capsule %s created', filename) logging.info('Create pyarmor command ...') script = make_command(plat_name, sys.executable, sys.argv[0], path) logging.info('Pyarmor command %s created', script) logging.info('Project init successfully.')
def _obfuscate(args): '''Obfuscate scripts without project''' if args.src is None and args.entry is None and not args.scripts: raise RuntimeError('No entry script') entry = args.entry or args.scripts[0] path = os.path.abspath( os.path.dirname(entry) if args.src is None else args.src) logging.info('Obfuscate scripts in path "%s" ...', path) capsule = args.capsule if args.capsule else DEFAULT_CAPSULE if os.path.exists(capsule) and check_capsule(capsule): logging.info('Use cached capsule %s', capsule) else: logging.info('Generate capsule %s', capsule) make_capsule(capsule) output = args.output if args.recursive: pats = ['global-include *.py', 'prune build', 'prune dist'] if hasattr('', 'decode'): pats = [p.decode() for p in pats] files = Project.build_manifest(pats, path) else: files = Project.build_globfiles(['*.py'], path) filepairs = [(os.path.join(path, x), os.path.join(output, x)) for x in files] if args.restrict: logging.info('Restrict mode is eanbled') mode = Project.map_obfuscate_mode(default_obf_module_mode, default_obf_code_mode) else: logging.info('Restrict mode is disabled') mode = Project.map_obfuscate_mode(default_obf_module_mode, 'wrap') logging.info('Obfuscate scripts with mode %s', mode) logging.info('Save obfuscated scripts to "%s"', output) for a, b in filepairs: logging.info('\t%s -> %s', a, b) obfuscate_scripts(filepairs, mode, capsule, output) logging.info('Make runtime files') make_runtime(capsule, output) if not args.restrict: licode = '*FLAGS:%c*CODE:Pyarmor-Project' % chr(1) licfile = os.path.join(output, license_filename) logging.info('Generate no restrict mode license file: %s', licfile) make_project_license(capsule, licode, licfile) make_entry(os.path.basename(entry), path, output) for script in args.scripts[1:]: make_entry(os.path.basename(script), path, output) logging.info('Obfuscate %d scripts OK.', len(files))
def _capsule(args): '''Generate the capsule explicitly.''' capsule = os.path.join(args.path, capsule_filename) if args.upgrade: logging.info('Preparing to upgrade the capsule %s ...', capsule) upgrade_capsule(capsule) return if os.path.exists(capsule): logging.info('Do nothing, capsule %s has been exists', capsule) else: logging.info('Generating capsule %s ...', capsule) make_capsule(capsule)
def _capsule(args): '''Make capsule separately''' if args.upgrade: capsule = os.path.join(args.path, capsule_filename) if args.path \ else DEFAULT_CAPSULE logging.info('Preparing to upgrade the capsule %s ...', capsule) upgrade_capsule(capsule) return capsule = os.path.join(args.path, capsule_filename) logging.info('Generating capsule %s ...', capsule) if os.path.exists(capsule): logging.info('Do nothing, capsule %s has been exists', capsule) else: make_capsule(capsule)
def _obfuscate(args): '''Obfuscate scripts without project''' path = args.src logging.info('Obfuscate scripts in path "%s" ...', path) capsule = args.capsule if args.capsule else capsule_filename if os.path.exists(capsule): logging.info('Use cached capsule %s', capsule) else: logging.info('Generate capsule %s', capsule) make_capsule(capsule) output = args.output if args.recursive: pat = 'global-include *.py'.decode() if hasattr('', 'decode') \ else 'global-include *.py' files = Project.build_manifest([pat], path) else: files = Project.build_globfiles(args.patterns, path) filepairs = [(os.path.join(path, x), os.path.join(output, x)) for x in files] if args.no_restrict: logging.info('Restrict mode is disabled') mode = Project.map_obfuscate_mode(default_obf_module_mode, 'wrap') else: mode = Project.map_obfuscate_mode(default_obf_module_mode, default_obf_code_mode) logging.info('Obfuscate scripts with mode %s', mode) logging.info('Save obfuscated scripts to "%s"', output) for a, b in filepairs: logging.info('\t%s -> %s', a, b) obfuscate_scripts(filepairs, mode, capsule, output) logging.info('Make runtime files') make_runtime(capsule, output) if args.no_restrict: licode = '*FLAGS:%c*CODE:Pyarmor-Project' % chr(1) licfile = os.path.join(output, license_filename) logging.info('Generate no restrict mode license file: %s', licfile) make_project_license(capsule, licode, licfile) if args.entry: make_entry(args.entry, path, output) logging.info('Obfuscate %d scripts OK.', len(files))
def main_entry(): logging.basicConfig( level=logging.INFO, format='%(levelname)-8s %(message)s', ) try: if 'download' not in sys.argv[1:2]: pytransform_bootstrap() capsule = DEFAULT_CAPSULE if not (os.path.exists(capsule) and check_capsule(capsule)): logging.info('Generate global capsule %s', capsule) make_capsule(capsule) main(sys.argv[1:]) except Exception as e: if sys.flags.debug: raise logging.error('%s', e) sys.exit(1)
def _licenses(args): '''Generate licenses for obfuscated scripts. Examples, * Expired license for global capsule pyarmor licenses --expired=2018-05-12 Customer-Jordan * Bind license to fixed harddisk and expired someday for project cd projects/myproject ./pyarmor licenses -e 2018-05-12 \\ --bind-disk '100304PBN2081SF3NJ5T' Customer-Tom ''' if os.path.exists(os.path.join(args.project, config_filename)): logging.info('Generate licenses for project %s ...', args.project) project = Project() project.open(args.project) capsule = build_path(project.capsule, args.project) \ if args.capsule is None else args.capsule else: if args.project != '': logging.warning('Ignore option --project, no project in %s', args.project) capsule = DEFAULT_CAPSULE if args.capsule is None else args.capsule if not (os.path.exists(capsule) and check_capsule(capsule)): logging.info('Generate capsule %s', capsule) make_capsule(capsule) logging.info('Generate licenses with capsule %s ...', capsule) project = { 'disable_restrict_mode': 0 if args.restrict else 1, } licpath = os.path.join( args.project if args.output is None else args.output, 'licenses') if os.path.exists(licpath): logging.info('Output path of licenses: %s', licpath) else: logging.info('Make output path of licenses: %s', licpath) os.mkdir(licpath) if args.expired is None: fmt = '' else: fmt = '*TIME:%.0f\n' % \ time.mktime(time.strptime(args.expired, '%Y-%m-%d')) if project.get('disable_restrict_mode'): logging.info('The license files generated is in disable restrict mode') fmt = '%s*FLAGS:%c' % (fmt, 1) else: logging.info('The license files generated is in restrict mode') if args.bind_disk: fmt = '%s*HARDDISK:%s' % (fmt, args.bind_disk) if args.bind_mac: fmt = '%s*IFMAC:%s' % (fmt, args.bind_mac) if args.bind_ipv4: fmt = '%s*IFIPV4:%s' % (fmt, args.bind_ipv4) # if args.bind_ipv6: # fmt = '%s*IFIPV6:%s' % (fmt, args.bind_ipv6) if args.bind_domain: fmt = '%s*DOMAIN:%s' % (fmt, args.bind_domain) if args.bind_file: bind_file, bind_key = args.bind_file.split(';', 2) if os.path.exists(bind_file): f = open(bind_file, 'rb') s = f.read() f.close() if sys.version_info[0] == 3: fmt = '%s*FIXKEY:%s;%s' % (fmt, bind_key, s.decode()) else: fmt = '%s*FIXKEY:%s;%s' % (fmt, bind_key, s) else: raise RuntimeError('Bind file %s not found' % bindfile) # Prefix of registration code fmt = fmt + '*CODE:' for rcode in args.codes: output = os.path.join(licpath, rcode) if not os.path.exists(output): logging.info('Make path: %s', output) os.mkdir(output) licfile = os.path.join(output, license_filename) licode = fmt + rcode txtinfo = licode.replace('\n', r'\n') if args.expired: txtinfo = '"Expired:%s%s"' % (args.expired, txtinfo[txtinfo.find(r'\n') + 2:]) logging.info('Generate license: %s', txtinfo) make_project_license(capsule, licode, licfile) logging.info('Write license file: %s', licfile) logging.info('Write information to %s.txt', licfile) with open(os.path.join(licfile + '.txt'), 'w') as f: f.write(txtinfo) logging.info('Generate %d licenses OK.', len(args.codes))
def _init(args): '''Create an empty project or reinitialize an existing one This command creates an empty project in the specified path - basically a configure file .pyarmor_config, a project capsule .pyarmor_capsule.zip, and a shell script "pyarmor" will be created (in windows, it called "pyarmor.bat"). Option --src specifies where to find python source files. By default, all .py files in this directory will be included in this project. Option --entry specifies main script, which could be run directly after obfuscated. Option --capsule specifies project capsule file which has been created. If it is set, no new project capsule is generated, just link to this capsule. EXAMPLES python pyarmor.py init --src=examples --entry=queens.py project1 cd project1/ ./pyarmor info ''' if args.clone: logging.info( 'Warning: option --clone is deprecated, use --capsule instead ') _clone(args) return path = args.project logging.info('Create project in %s ...', path) if not os.path.exists(path): logging.info('Make project directory %s', path) os.makedirs(path) src = os.path.abspath(args.src) logging.info('Python scripts base path: %s', src) name = os.path.basename(os.path.abspath(path)) if (args.type == 'package') or (args.type == 'pkg') or \ (args.type == 'auto' and os.path.exists(os.path.join(src, '__init__.py'))): logging.info('Project is configured as package') project = Project(name=name, title=name, src=src, entry=args.entry, is_package=1, obf_code_mode='wrap', disable_restrict_mode=1) else: logging.info('Project is configured as standalone application.') project = Project(name=name, title=name, src=src, entry=args.entry) if args.capsule: capsule = os.path.abspath(args.capsule) logging.info('Share capsule with %s', capsule) project._update(dict(capsule=capsule)) else: logging.info('Create project capsule ...') filename = os.path.join(path, capsule_filename) make_capsule(filename) logging.info('Project capsule %s created', filename) logging.info('Create configure file ...') filename = os.path.join(path, config_filename) project.save(path) logging.info('Configure file %s created', filename) logging.info('Create pyarmor command ...') script = make_command(plat_name, sys.executable, sys.argv[0], path) logging.info('Pyarmor command %s created', script) logging.info('Project init successfully.')
def _obfuscate(args): '''Obfuscate scripts without project.''' platforms = compatible_platform_names(args.platforms) if platforms: logging.info('Target platforms: %s', platforms) if check_cross_platform(platforms) is not False: return for x in ('entry', 'cross-protection'): if getattr(args, x.replace('-', '_')) is not None: logging.warning('Option --%s has been deprecated', x) if args.src is None: if args.scripts[0].lower().endswith('.py'): path = os.path.abspath(os.path.dirname(args.scripts[0])) else: path = os.path.abspath(args.scripts[0]) args.src = path if len(args.scripts) > 1: raise RuntimeError('Only one path is allowed') args.scripts = [] else: for s in args.scripts: if not s.lower().endswith('.py'): raise RuntimeError('Only one path is allowed') path = os.path.abspath(args.src) if not args.exact and len(args.scripts) > 1: raise RuntimeError('Two many entry scripts, only one is allowed') if not os.path.exists(path): raise RuntimeError('Not found source path: %s' % path) logging.info('Source path is "%s"', path) entries = [args.entry] if args.entry else args.scripts logging.info('Entry scripts are %s', entries) capsule = args.capsule if args.capsule else DEFAULT_CAPSULE if os.path.exists(capsule): logging.info('Use cached capsule %s', capsule) else: logging.info('Generate capsule %s', capsule) make_capsule(capsule) output = args.output if os.path.abspath(output) == path: raise RuntimeError('Output path can not be same as src') suffix = get_name_suffix() if args.enable_suffix else '' if args.recursive: logging.info('Recursive mode is on') pats = ['global-include *.py'] if args.exclude: for item in args.exclude: for x in item.split(','): if x.endswith('.py'): logging.info('Exclude pattern "%s"', x) pats.append('exclude %s' % x) else: logging.info('Exclude path "%s"', x) pats.append('prune %s' % x) if os.path.abspath(output).startswith(path): x = os.path.abspath(output)[len(path):].strip('/\\') pats.append('prune %s' % x) logging.info('Auto exclude output path "%s"', x) if hasattr('', 'decode'): pats = [p.decode() for p in pats] files = Project.build_manifest(pats, path) elif args.exact: logging.info('Exact mode is on') files = [os.path.abspath(x) for x in args.scripts] else: logging.info('Normal mode is on') files = Project.build_globfiles(['*.py'], path) logging.info('Save obfuscated scripts to "%s"', output) if not os.path.exists(output): os.makedirs(output) logging.info('Read public key from capsule') prokey = get_product_key(capsule) logging.info('Obfuscate scripts with default mode') cross_protection = 0 if args.no_cross_protection else \ 1 if args.cross_protection is None else args.cross_protection advanced = 1 if args.advanced else 0 logging.info('Advanced mode is %d', advanced) restrict = args.restrict logging.info('Restrict mode is %d', restrict) n = args.bootstrap_code relative = True if n == 3 else False if n == 2 else None bootstrap = (not args.no_bootstrap) and n elist = [os.path.abspath(x) for x in entries] for x in sorted(files): if os.path.isabs(x): a, b = x, os.path.join(output, os.path.basename(x)) else: a, b = os.path.join(path, x), os.path.join(output, x) logging.info('\t%s -> %s', x, relpath(b)) is_entry = os.path.abspath(a) in elist protection = is_entry and cross_protection plugins = search_plugins(args.plugins) d = os.path.dirname(b) if not os.path.exists(d): os.makedirs(d) vmode = advanced | (8 if is_entry else 0) encrypt_script(prokey, a, b, adv_mode=vmode, rest_mode=restrict, protection=protection, platforms=platforms, plugins=plugins, suffix=suffix) if is_entry and bootstrap: name = os.path.abspath(a)[len(path)+1:] make_entry(name, path, output, relative=relative, suffix=suffix) logging.info('%d scripts have been obfuscated', len(files)) if args.no_runtime: logging.info('Obfuscate %d scripts OK.', len(files)) return package = args.package_runtime make_runtime(capsule, output, platforms=platforms, package=package, suffix=suffix) logging.info('Obfuscate scripts with restrict mode %s', 'on' if args.restrict else 'off') if not args.restrict: licode = '*FLAGS:%c*CODE:PyArmor-Project' % chr(1) licpath = (os.path.join(output, 'pytransform' + suffix) if package else output) licfile = os.path.join(licpath, license_filename) logging.info('Generate no restrict mode license file: %s', licfile) make_license_key(capsule, licode, licfile) logging.info('Obfuscate %d scripts OK.', len(files))
def _licenses(args): '''Generate licenses for obfuscated scripts.''' for x in ('bind-file',): if getattr(args, x.replace('-', '_')) is not None: logging.warning('Option --%s has been deprecated', x) if os.path.exists(os.path.join(args.project, config_filename)): logging.info('Generate licenses for project %s ...', args.project) project = Project() project.open(args.project) capsule = build_path(project.capsule, args.project) \ if args.capsule is None else args.capsule else: if args.project != '': logging.warning('Ignore option --project, there is no project') capsule = DEFAULT_CAPSULE if args.capsule is None else args.capsule if not os.path.exists(capsule): logging.info('Generating public capsule ...') make_capsule(capsule) logging.info('Generate licenses with capsule %s ...', capsule) project = dict(restrict_mode=args.restrict) restrict_mode = 0 if args.disable_restrict_mode else args.restrict licpath = os.path.join( args.project if args.output is None else args.output, 'licenses') if os.path.exists(licpath): logging.info('Output path of licenses: %s', licpath) else: logging.info('Make output path of licenses: %s', licpath) os.mkdir(licpath) if args.expired is None: fmt = '' else: fmt = '*TIME:%.0f\n' % \ time.mktime(time.strptime(args.expired, '%Y-%m-%d')) if not restrict_mode: logging.info('The license file generated is in disable restrict mode') fmt = '%s*FLAGS:%c' % (fmt, 1) else: logging.info('The license file generated is in restrict mode') if args.bind_disk: fmt = '%s*HARDDISK:%s' % (fmt, args.bind_disk) if args.bind_mac: fmt = '%s*IFMAC:%s' % (fmt, args.bind_mac) if args.bind_ipv4: fmt = '%s*IFIPV4:%s' % (fmt, args.bind_ipv4) # if args.bind_ipv6: # fmt = '%s*IFIPV6:%s' % (fmt, args.bind_ipv6) if args.bind_domain: fmt = '%s*DOMAIN:%s' % (fmt, args.bind_domain) if args.bind_file: bind_file, bind_key = args.bind_file.split(';', 2) if os.path.exists(bind_file): f = open(bind_file, 'rb') s = f.read() f.close() if sys.version_info[0] == 3: fmt = '%s*FIXKEY:%s;%s' % (fmt, bind_key, s.decode()) else: fmt = '%s*FIXKEY:%s;%s' % (fmt, bind_key, s) else: raise RuntimeError('Bind file %s not found' % bind_file) # Prefix of registration code fmt = fmt + '*CODE:' extra_data = '' if args.bind_data is None else (';' + args.bind_data) for rcode in args.codes: output = os.path.join(licpath, rcode) if not os.path.exists(output): logging.info('Make path: %s', output) os.mkdir(output) licfile = os.path.join(output, license_filename) licode = fmt + rcode + extra_data txtinfo = licode.replace('\n', r'\n') if args.expired: txtinfo = '"Expired:%s%s"' % (args.expired, txtinfo[txtinfo.find(r'\n')+2:]) logging.info('Generate license: %s', txtinfo) make_project_license(capsule, licode, licfile) logging.info('Write license file: %s', licfile) logging.info('Write information to %s.txt', licfile) with open(os.path.join(licfile + '.txt'), 'w') as f: f.write(txtinfo) logging.info('Generate %d licenses OK.', len(args.codes))
def _obfuscate(args): '''Obfuscate scripts without project''' if args.src is None and args.entry is None and not args.scripts: raise RuntimeError('No entry script') entry = args.entry or (args.scripts and args.scripts[0]) path = os.path.abspath( os.path.dirname(entry) if args.src is None else args.src) logging.info('Obfuscate scripts in path "%s"', path) capsule = args.capsule if args.capsule else DEFAULT_CAPSULE if os.path.exists(capsule) and check_capsule(capsule): logging.info('Use cached capsule %s', capsule) else: logging.info('Generate capsule %s', capsule) make_capsule(capsule) output = args.output if os.path.abspath(output) == path: raise RuntimeError('Output path can not be same as src') if args.recursive: pats = ['global-include *.py', 'prune build', 'prune dist'] if os.path.abspath(output).startswith(path): x = os.path.abspath(output)[len(path):].strip('/\\') pats.append('prune %s' % x) if hasattr('', 'decode'): pats = [p.decode() for p in pats] files = Project.build_manifest(pats, path) else: files = Project.build_globfiles(['*.py'], path) logging.info('Save obfuscated scripts to "%s"', output) if not os.path.exists(output): os.makedirs(output) logging.info('Read public key from capsule') prokey = get_product_key(capsule) logging.info('Obfuscate scripts with default mode') for x in files: a, b = os.path.join(path, x), os.path.join(output, x) logging.info('\t%s -> %s', x, b) protection = args.cross_protection and entry \ and (os.path.abspath(a) == os.path.abspath(entry)) d = os.path.dirname(b) if not os.path.exists(d): os.makedirs(d) encrypt_script(prokey, a, b, protection=protection) logging.info('%d scripts have been obfuscated', len(files)) make_runtime(capsule, output) if entry and entry.endswith('__init__.py') and args.restrict is None: logging.info('Disable restrict mode for package by default') restrict = 0 else: restrict = 1 if args.restrict is None else args.restrict logging.info('Obfuscate scripts with restrict mode %s', 'on' if restrict else 'off') if not restrict: licode = '*FLAGS:%c*CODE:PyArmor-Project' % chr(1) licfile = os.path.join(output, license_filename) logging.info('Generate no restrict mode license file: %s', licfile) make_project_license(capsule, licode, licfile) if entry: make_entry(os.path.basename(entry), path, output) for script in args.scripts[1:]: make_entry(os.path.basename(script), path, output) logging.info('Obfuscate %d scripts OK.', len(files))
def _obfuscate(args): '''Obfuscate scripts without project.''' check_cross_platform(args.platform) for x in ('entry', 'cross-protection'): if getattr(args, x.replace('-', '_')) is not None: logging.warning('Option --%s has been deprecated', x) if args.src is None and not args.scripts: args.src = '.' if args.src is None: if args.scripts[0].lower().endswith('.py'): path = os.path.abspath(os.path.dirname(args.scripts[0])) else: path = os.path.abspath(args.scripts[0]) args.src = path if len(args.scripts) > 1: raise RuntimeError('Only one path is allowed') args.scripts = [] else: path = os.path.abspath(args.src) if not os.path.exists(path): raise RuntimeError('Not found source path: %s' % path) logging.info('Source path is "%s"', path) entry = args.entry or (args.scripts and args.scripts[0]) logging.info('Entry script is %s', entry) capsule = args.capsule if args.capsule else DEFAULT_CAPSULE if os.path.exists(capsule): logging.info('Use cached capsule %s', capsule) else: logging.info('Generate capsule %s', capsule) make_capsule(capsule) output = args.output if os.path.abspath(output) == path: raise RuntimeError('Output path can not be same as src') if args.recursive: logging.info('Recursive mode is on') pats = ['global-include *.py'] if args.exclude: for item in args.exclude: for x in item.split(','): logging.info('Exclude path "%s"', x) pats.append('prune %s' % x) if os.path.abspath(output).startswith(path): x = os.path.abspath(output)[len(path):].strip('/\\') pats.append('prune %s' % x) logging.info('Auto exclude output path "%s"', x) if hasattr('', 'decode'): pats = [p.decode() for p in pats] files = Project.build_manifest(pats, path) elif args.exact: logging.info('Exact mode is on') files = [os.path.abspath(x) for x in args.scripts] else: logging.info('Normal mode is on') files = Project.build_globfiles(['*.py'], path) logging.info('Save obfuscated scripts to "%s"', output) if not os.path.exists(output): os.makedirs(output) logging.info('Read public key from capsule') prokey = get_product_key(capsule) logging.info('Obfuscate scripts with default mode') cross_protection = 0 if args.no_cross_protection else \ 1 if args.cross_protection is None else args.cross_protection if args.platform: logging.info('Target platform is %s', args.platform) if cross_protection == 1: cross_protection = args.platform elif isinstance(cross_protection, str): cross_protection = ','.join([cross_protection, args.platform]) advanced = 1 if args.advanced else 0 logging.info('Advanced mode is %d', advanced) restrict = args.restrict logging.info('Restrict mode is %d', restrict) for x in files: if os.path.isabs(x): a, b = x, os.path.join(output, os.path.basename(x)) else: a, b = os.path.join(path, x), os.path.join(output, x) logging.info('\t%s -> %s', x, b) is_entry = entry and (os.path.abspath(a) == os.path.abspath(entry)) protection = is_entry and cross_protection plugins = protection and args.plugins d = os.path.dirname(b) if not os.path.exists(d): os.makedirs(d) vmode = advanced | (8 if is_entry else 0) encrypt_script(prokey, a, b, adv_mode=vmode, rest_mode=restrict, protection=protection, plugins=plugins) logging.info('%d scripts have been obfuscated', len(files)) if (not args.no_bootstrap) and entry and os.path.exists(entry): inner = args.package_runtime != 2 entryname = entry if args.src else os.path.basename(entry) if os.path.exists(os.path.join(output, entryname)): make_entry(entryname, path, output, inner=inner) else: logging.info('Use outer entry script "%s"', entry) make_entry(entry, path, output, inner=inner) if args.no_runtime: logging.info('Obfuscate %d scripts OK.', len(files)) return make_runtime(capsule, output, platform=args.platform, package=args.package_runtime) logging.info('Obfuscate scripts with restrict mode %s', 'on' if args.restrict else 'off') if not args.restrict: licode = '*FLAGS:%c*CODE:PyArmor-Project' % chr(1) licpath = os.path.join(output, 'pytransform') if args.package_runtime \ else output licfile = os.path.join(licpath, license_filename) logging.info('Generate no restrict mode license file: %s', licfile) make_project_license(capsule, licode, licfile) logging.info('Obfuscate %d scripts OK.', len(files))
def main(args): parser = argparse.ArgumentParser( prog='pyarmor', formatter_class=argparse.RawDescriptionHelpFormatter, description='PyArmor is a command line tool used to obfuscate ' 'python scripts, bind obfuscated scripts to fixed ' 'machine or expire obfuscated scripts.', epilog=__doc__, ) parser.add_argument('-v', '--version', action='version', version=_version_info()) parser.add_argument('-q', '--silent', action='store_true', help='Suppress all normal output') subparsers = parser.add_subparsers( title='The most commonly used pyarmor commands are', metavar='<command>') # # Command: capsule # cparser = subparsers.add_parser( 'capsule', epilog=_capsule.__doc__, formatter_class=argparse.RawDescriptionHelpFormatter, help='Generate or upgrade the capsule explicitly ') cparser.add_argument('--upgrade', action='store_true', help='Upgrade the capsule to latest version') cparser.add_argument('path', nargs='?', default=os.path.expanduser('~'), help='Path to save capsule, default is home path') cparser.set_defaults(func=_capsule) # # Command: obfuscate # cparser = subparsers.add_parser( 'obfuscate', epilog=_obfuscate.__doc__, formatter_class=argparse.RawDescriptionHelpFormatter, help='Obfuscate python scripts') cparser.add_argument('-O', '--output', default='dist', metavar='PATH') cparser.add_argument('-e', '--entry', metavar='SCRIPT', help='Entry script [DEPRECATED]') cparser.add_argument('-r', '--recursive', action='store_true', help='Match files recursively') cparser.add_argument('-s', '--src', metavar='PATH', help='Base path for search python scripts') cparser.add_argument('--restrict', type=int, choices=(0, 1), help='Set restrict mode') cparser.add_argument('--cross-protection', type=int, choices=(0, 1), default=1, help='Enable/disable to insert protection code') cparser.add_argument('--capsule', help='Use this capsule other than global capsule') cparser.add_argument('scripts', metavar='SCRIPT', nargs='*', help='Scripts to obfuscted') cparser.set_defaults(func=_obfuscate) # # Command: init # cparser = subparsers.add_parser( 'init', epilog=_init.__doc__, formatter_class=argparse.RawDescriptionHelpFormatter, help='Create a project to manage obfuscated scripts') cparser.add_argument('-t', '--type', default='auto', choices=('auto', 'app', 'pkg')) cparser.add_argument('-e', '--entry', help='Entry script of this project') cparser.add_argument('-s', '--src', required=True, help='Base path of python scripts') cparser.add_argument('--capsule', help='Use this capsule other than global capsule') cparser.add_argument('project', nargs='?', help='Project path') cparser.set_defaults(func=_init) # # Command: config # cparser = subparsers.add_parser( 'config', epilog=_update.__doc__, formatter_class=argparse.RawDescriptionHelpFormatter, help='Update project settings') cparser.add_argument('project', nargs='?', metavar='PATH', default='', help='Project path') cparser.add_argument('--name') cparser.add_argument('--title') cparser.add_argument('--src') cparser.add_argument('--output') cparser.add_argument('--capsule', help='Project capsule') cparser.add_argument('--manifest', metavar='TEMPLATE', help='Manifest template string') cparser.add_argument('--entry', metavar='SCRIPT', help='Entry script of this project') cparser.add_argument('--is-package', type=int, choices=(0, 1)) cparser.add_argument('--disable-restrict-mode', type=int, choices=(0, 1)) cparser.add_argument('--obf-module-mode', choices=Project.OBF_MODULE_MODE, help='[DEPRECATED] Use --obf-mod instead') cparser.add_argument('--obf-code-mode', choices=Project.OBF_CODE_MODE, help='[DEPRECATED] Use --obf-code and --wrap-mode' ' instead') cparser.add_argument('--obf-mod', type=int, choices=(0, 1)) cparser.add_argument('--obf-code', type=int, choices=(0, 1)) cparser.add_argument('--wrap-mode', type=int, choices=(0, 1)) cparser.add_argument('--cross-protection', type=int, choices=(0, 1)) cparser.add_argument('--runtime-path', metavar="RPATH") cparser.set_defaults(func=_update) # # Command: info # cparser = subparsers.add_parser( 'info', epilog=_info.__doc__, formatter_class=argparse.RawDescriptionHelpFormatter, help='Show project information') cparser.add_argument('project', nargs='?', metavar='PATH', default='', help='Project path') cparser.set_defaults(func=_info) # # Command: check # cparser = subparsers.add_parser( 'check', epilog=_check.__doc__, formatter_class=argparse.RawDescriptionHelpFormatter, help='Check consistency of project') cparser.add_argument('project', nargs='?', metavar='PATH', default='', help='Project path') cparser.set_defaults(func=_check) # # Command: build # cparser = subparsers.add_parser( 'build', epilog=_build.__doc__, formatter_class=argparse.RawDescriptionHelpFormatter, help='Obfuscate all the scripts in the project') cparser.add_argument('project', nargs='?', metavar='PATH', default='', help='Project path') cparser.add_argument( '-B', '--force', action='store_true', help='Obfuscate all scripts even if it\'s not updated') cparser.add_argument('-r', '--only-runtime', action='store_true', help='Generate extra runtime files only') cparser.add_argument('-n', '--no-runtime', action='store_true', help='DO NOT generate extra runtime files') cparser.add_argument('-O', '--output', help='Output path, override project configuration') cparser.set_defaults(func=_build) # # Command: target # # cparser = subparsers.add_parser('target', help='Manage target for project') # cparser.add_argument('name', metavar='NAME', nargs=1, # help='Target name') # group = cparser.add_argument_group('Target definition') # group.add_argument('-p', '--platform', metavar='PLATFORM', # help='Target platform to run obfuscated scripts') # group.add_argument('-c', '--license', metavar='CODE', # help='License code for this target') # cparser.add_argument('--remove', action='store_true', # help='Remove target from project') # cparser.add_argument('-P', '--project', required=True, default='', # help='Project path or configure file') # cparser.set_defaults(func=_target) # # Command: license # cparser = subparsers.add_parser( 'licenses', epilog=_licenses.__doc__, formatter_class=argparse.RawDescriptionHelpFormatter, help='Generate new licenses for obfuscated scripts') cparser.add_argument('codes', nargs='+', metavar='CODE', help='Registration code for this license') group = cparser.add_argument_group('Bind license to hardware') group.add_argument('-e', '--expired', metavar='YYYY-MM-DD', help='Expired date for this license') group.add_argument('-d', '--bind-disk', metavar='SN', help='Bind license to serial number of harddisk') group.add_argument('-4', '--bind-ipv4', metavar='a.b.c.d', help='Bind license to ipv4 addr') # group.add_argument('-6', '--bind-ipv6', metavar='a:b:c:d', # help='Bind license to ipv6 addr') group.add_argument('-m', '--bind-mac', metavar='x:x:x:x', help='Bind license to mac addr') group.add_argument('--bind-domain', metavar='DOMAIN', help='Bind license to domain name') group.add_argument('--bind-file', metavar='filename;target_filename', help='Bind license to fixed file') cparser.add_argument('-P', '--project', default='', help='Project path') cparser.add_argument('-C', '--capsule', help='Project capsule') cparser.add_argument('-O', '--output', help='Output path') cparser.add_argument('--restrict', type=int, default=1, choices=(0, 1), help='Generate license for restrict mode') cparser.set_defaults(func=_licenses) # # Command: hdinfo # cparser = subparsers.add_parser( 'hdinfo', epilog=_hdinfo.__doc__, formatter_class=argparse.RawDescriptionHelpFormatter, help='Show hardware information') cparser.set_defaults(func=_hdinfo) # # Command: benchmark # cparser = subparsers.add_parser( 'benchmark', epilog=_benchmark.__doc__, formatter_class=argparse.RawDescriptionHelpFormatter, help='Run benchmark test in current machine') cparser.add_argument('-m', '--obf-mod', choices=(0, 1), default=1, type=int) cparser.add_argument('-c', '--obf-code', choices=(0, 1), default=1, type=int) cparser.add_argument('-w', '--wrap-mode', choices=(0, 1), default=1, type=int) cparser.set_defaults(func=_benchmark) # # Command: pack # cparser = subparsers.add_parser( 'pack', epilog=packer.__doc__, formatter_class=argparse.RawDescriptionHelpFormatter, help='Pack obfuscated scripts to one bundle') packer.add_arguments(cparser) cparser.set_defaults(func=packer.packer) args = parser.parse_args(args) if args.silent: logging.getLogger().setLevel(100) if not hasattr(args, 'func'): parser.print_help() return logging.info(_version_info(short=True)) logging.debug('PyArmor install path: %s', PYARMOR_PATH) capsule = DEFAULT_CAPSULE if not (os.path.exists(capsule) and check_capsule(capsule)): logging.info('Generate global capsule %s', capsule) make_capsule(capsule) args.func(args)