__init__.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. # These module alos are used by protection code, so that protection
  2. # code needn't import anything
  3. import os
  4. import platform
  5. import sys
  6. import struct
  7. # Because ctypes is new from Python 2.5, so pytransform doesn't work
  8. # before Python 2.5
  9. #
  10. from ctypes import cdll, c_char, c_char_p, c_int, c_void_p, \
  11. pythonapi, py_object, PYFUNCTYPE, CFUNCTYPE
  12. from fnmatch import fnmatch
  13. #
  14. # Support Platforms
  15. #
  16. plat_path = 'platforms'
  17. plat_table = (
  18. ('windows', ('windows', 'cygwin-*')),
  19. ('darwin', ('darwin',)),
  20. ('ios', ('ios',)),
  21. ('linux', ('linux*',)),
  22. ('freebsd', ('freebsd*', 'openbsd*')),
  23. ('poky', ('poky',)),
  24. )
  25. arch_table = (
  26. ('x86', ('i?86', )),
  27. ('x86_64', ('x64', 'x86_64', 'amd64', 'intel')),
  28. ('arm', ('armv5',)),
  29. ('armv6', ('armv6l',)),
  30. ('armv7', ('armv7l',)),
  31. ('ppc64', ('ppc64le',)),
  32. ('mips32', ('mips',)),
  33. ('aarch32', ('aarch32',)),
  34. ('aarch64', ('aarch64', 'arm64'))
  35. )
  36. #
  37. # Hardware type
  38. #
  39. HT_HARDDISK, HT_IFMAC, HT_IPV4, HT_IPV6, HT_DOMAIN = range(5)
  40. #
  41. # Global
  42. #
  43. _pytransform = None
  44. class PytransformError(Exception):
  45. pass
  46. def dllmethod(func):
  47. def wrap(*args, **kwargs):
  48. return func(*args, **kwargs)
  49. return wrap
  50. @dllmethod
  51. def version_info():
  52. prototype = PYFUNCTYPE(py_object)
  53. dlfunc = prototype(('version_info', _pytransform))
  54. return dlfunc()
  55. @dllmethod
  56. def init_pytransform():
  57. major, minor = sys.version_info[0:2]
  58. # Python2.5 no sys.maxsize but sys.maxint
  59. # bitness = 64 if sys.maxsize > 2**32 else 32
  60. prototype = PYFUNCTYPE(c_int, c_int, c_int, c_void_p)
  61. init_module = prototype(('init_module', _pytransform))
  62. ret = init_module(major, minor, pythonapi._handle)
  63. if (ret & 0xF000) == 0x1000:
  64. raise PytransformError('Initialize python wrapper failed (%d)'
  65. % (ret & 0xFFF))
  66. return ret
  67. @dllmethod
  68. def init_runtime():
  69. prototype = PYFUNCTYPE(c_int, c_int, c_int, c_int, c_int)
  70. _init_runtime = prototype(('init_runtime', _pytransform))
  71. return _init_runtime(0, 0, 0, 0)
  72. @dllmethod
  73. def encrypt_code_object(pubkey, co, flags, suffix=''):
  74. _pytransform.set_option(6, suffix.encode())
  75. prototype = PYFUNCTYPE(py_object, py_object, py_object, c_int)
  76. dlfunc = prototype(('encrypt_code_object', _pytransform))
  77. return dlfunc(pubkey, co, flags)
  78. @dllmethod
  79. def generate_license_file(filename, priname, rcode, start=-1, count=1):
  80. prototype = PYFUNCTYPE(c_int, c_char_p, c_char_p, c_char_p, c_int, c_int)
  81. dlfunc = prototype(('generate_project_license_files', _pytransform))
  82. return dlfunc(filename.encode(), priname.encode(), rcode.encode(),
  83. start, count) if sys.version_info[0] == 3 \
  84. else dlfunc(filename, priname, rcode, start, count)
  85. @dllmethod
  86. def generate_license_key(prikey, keysize, rcode):
  87. prototype = PYFUNCTYPE(py_object, c_char_p, c_int, c_char_p)
  88. dlfunc = prototype(('generate_license_key', _pytransform))
  89. return dlfunc(prikey, keysize, rcode) if sys.version_info[0] == 2 \
  90. else dlfunc(prikey, keysize, rcode.encode())
  91. @dllmethod
  92. def get_registration_code():
  93. prototype = PYFUNCTYPE(py_object)
  94. dlfunc = prototype(('get_registration_code', _pytransform))
  95. return dlfunc()
  96. @dllmethod
  97. def get_expired_days():
  98. prototype = PYFUNCTYPE(py_object)
  99. dlfunc = prototype(('get_expired_days', _pytransform))
  100. return dlfunc()
  101. @dllmethod
  102. def clean_obj(obj, kind):
  103. prototype = PYFUNCTYPE(c_int, py_object, c_int)
  104. dlfunc = prototype(('clean_obj', _pytransform))
  105. return dlfunc(obj, kind)
  106. def clean_str(*args):
  107. tdict = {
  108. 'str': 0,
  109. 'bytearray': 1,
  110. 'unicode': 2
  111. }
  112. for obj in args:
  113. k = tdict.get(type(obj).__name__)
  114. if k is None:
  115. raise RuntimeError('Can not clean object: %s' % obj)
  116. clean_obj(obj, k)
  117. def get_hd_info(hdtype, name=None):
  118. if hdtype not in range(HT_DOMAIN + 1):
  119. raise RuntimeError('Invalid parameter hdtype: %s' % hdtype)
  120. size = 256
  121. t_buf = c_char * size
  122. buf = t_buf()
  123. cname = c_char_p(0 if name is None
  124. else name.encode('utf-8') if hasattr('name', 'encode')
  125. else name)
  126. if (_pytransform.get_hd_info(hdtype, buf, size, cname) == -1):
  127. raise PytransformError('Get hardware information failed')
  128. return buf.value.decode()
  129. def show_hd_info():
  130. return _pytransform.show_hd_info()
  131. def assert_armored(*names):
  132. prototype = PYFUNCTYPE(py_object, py_object)
  133. dlfunc = prototype(('assert_armored', _pytransform))
  134. def wrapper(func):
  135. def wrap_execute(*args, **kwargs):
  136. dlfunc(names)
  137. return func(*args, **kwargs)
  138. return wrap_execute
  139. return wrapper
  140. def check_armored(*names):
  141. try:
  142. prototype = PYFUNCTYPE(py_object, py_object)
  143. prototype(('assert_armored', _pytransform))(names)
  144. return True
  145. except RuntimeError:
  146. return False
  147. def get_license_info():
  148. info = {
  149. 'ISSUER': None,
  150. 'EXPIRED': None,
  151. 'HARDDISK': None,
  152. 'IFMAC': None,
  153. 'IFIPV4': None,
  154. 'DOMAIN': None,
  155. 'DATA': None,
  156. 'CODE': None,
  157. }
  158. rcode = get_registration_code().decode()
  159. if rcode.startswith('*VERSION:'):
  160. index = rcode.find('\n')
  161. info['ISSUER'] = rcode[9:index].split('.')[0].replace('-sn-1.txt', '')
  162. rcode = rcode[index+1:]
  163. index = 0
  164. if rcode.startswith('*TIME:'):
  165. from time import ctime
  166. index = rcode.find('\n')
  167. info['EXPIRED'] = ctime(float(rcode[6:index]))
  168. index += 1
  169. if rcode[index:].startswith('*FLAGS:'):
  170. index += len('*FLAGS:') + 1
  171. info['FLAGS'] = ord(rcode[index - 1])
  172. prev = None
  173. start = index
  174. for k in ['HARDDISK', 'IFMAC', 'IFIPV4', 'DOMAIN', 'FIXKEY', 'CODE']:
  175. index = rcode.find('*%s:' % k)
  176. if index > -1:
  177. if prev is not None:
  178. info[prev] = rcode[start:index]
  179. prev = k
  180. start = index + len(k) + 2
  181. info['CODE'] = rcode[start:]
  182. i = info['CODE'].find(';')
  183. if i > 0:
  184. info['DATA'] = info['CODE'][i+1:]
  185. info['CODE'] = info['CODE'][:i]
  186. return info
  187. def get_license_code():
  188. return get_license_info()['CODE']
  189. def get_user_data():
  190. return get_license_info()['DATA']
  191. def _match_features(patterns, s):
  192. for pat in patterns:
  193. if fnmatch(s, pat):
  194. return True
  195. def _gnu_get_libc_version():
  196. try:
  197. prototype = CFUNCTYPE(c_char_p)
  198. ver = prototype(('gnu_get_libc_version', cdll.LoadLibrary('')))()
  199. return ver.decode().split('.')
  200. except Exception:
  201. pass
  202. def format_platform(platid=None):
  203. if platid:
  204. return os.path.normpath(platid)
  205. plat = platform.system().lower()
  206. mach = platform.machine().lower()
  207. for alias, platlist in plat_table:
  208. if _match_features(platlist, plat):
  209. plat = alias
  210. break
  211. if plat == 'linux':
  212. cname, cver = platform.libc_ver()
  213. if cname == 'musl':
  214. plat = 'musl'
  215. elif cname == 'libc':
  216. plat = 'android'
  217. elif cname == 'glibc':
  218. v = _gnu_get_libc_version()
  219. if v and len(v) >= 2 and (int(v[0]) * 100 + int(v[1])) < 214:
  220. plat = 'centos6'
  221. for alias, archlist in arch_table:
  222. if _match_features(archlist, mach):
  223. mach = alias
  224. break
  225. if plat == 'windows' and mach == 'x86_64':
  226. bitness = struct.calcsize('P'.encode()) * 8
  227. if bitness == 32:
  228. mach = 'x86'
  229. return os.path.join(plat, mach)
  230. # Load _pytransform library
  231. def _load_library(path=None, is_runtime=0, platid=None, suffix='', advanced=0):
  232. path = os.path.dirname(__file__) if path is None \
  233. else os.path.normpath(path)
  234. plat = platform.system().lower()
  235. name = '_pytransform' + suffix
  236. if plat == 'linux':
  237. filename = os.path.abspath(os.path.join(path, name + '.so'))
  238. elif plat == 'darwin':
  239. filename = os.path.join(path, name + '.dylib')
  240. elif plat == 'windows':
  241. filename = os.path.join(path, name + '.dll')
  242. elif plat == 'freebsd':
  243. filename = os.path.join(path, name + '.so')
  244. else:
  245. raise PytransformError('Platform %s not supported' % plat)
  246. if platid is not None and os.path.isfile(platid):
  247. filename = platid
  248. elif platid is not None or not os.path.exists(filename) or not is_runtime:
  249. libpath = platid if platid is not None and os.path.isabs(platid) else \
  250. os.path.join(path, plat_path, format_platform(platid))
  251. filename = os.path.join(libpath, os.path.basename(filename))
  252. if not os.path.exists(filename):
  253. raise PytransformError('Could not find "%s"' % filename)
  254. try:
  255. m = cdll.LoadLibrary(filename)
  256. except Exception as e:
  257. if sys.flags.debug:
  258. print('Load %s failed:\n%s' % (filename, e))
  259. raise
  260. # Removed from v4.6.1
  261. # if plat == 'linux':
  262. # m.set_option(-1, find_library('c').encode())
  263. if not os.path.abspath('.') == os.path.abspath(path):
  264. m.set_option(1, path.encode() if sys.version_info[0] == 3 else path)
  265. # Required from Python3.6
  266. m.set_option(2, sys.byteorder.encode())
  267. if sys.flags.debug:
  268. m.set_option(3, c_char_p(1))
  269. m.set_option(4, c_char_p(not is_runtime))
  270. # Disable advanced mode by default
  271. m.set_option(5, c_char_p(not advanced))
  272. # Set suffix for private package
  273. if suffix:
  274. m.set_option(6, suffix.encode())
  275. return m
  276. def pyarmor_init(path=None, is_runtime=0, platid=None, suffix='', advanced=0):
  277. global _pytransform
  278. _pytransform = _load_library(path, is_runtime, platid, suffix, advanced)
  279. return init_pytransform()
  280. def pyarmor_runtime(path=None, suffix='', advanced=0):
  281. if _pytransform is not None:
  282. return
  283. try:
  284. pyarmor_init(path, is_runtime=1, suffix=suffix, advanced=advanced)
  285. init_runtime()
  286. except Exception as e:
  287. if sys.flags.debug or hasattr(sys, '_catch_pyarmor'):
  288. raise
  289. sys.stderr.write("%s\n" % str(e))
  290. sys.exit(1)
  291. # ----------------------------------------------------------
  292. # End of pytransform
  293. # ----------------------------------------------------------
  294. #
  295. # Not available from v5.6
  296. #
  297. def generate_capsule(licfile):
  298. prikey, pubkey, prolic = _generate_project_capsule()
  299. capkey, newkey = _generate_pytransform_key(licfile, pubkey)
  300. return prikey, pubkey, capkey, newkey, prolic
  301. @dllmethod
  302. def _generate_project_capsule():
  303. prototype = PYFUNCTYPE(py_object)
  304. dlfunc = prototype(('generate_project_capsule', _pytransform))
  305. return dlfunc()
  306. @dllmethod
  307. def _generate_pytransform_key(licfile, pubkey):
  308. prototype = PYFUNCTYPE(py_object, c_char_p, py_object)
  309. dlfunc = prototype(('generate_pytransform_key', _pytransform))
  310. return dlfunc(licfile.encode() if sys.version_info[0] == 3 else licfile,
  311. pubkey)
  312. #
  313. # Deprecated functions from v5.1
  314. #
  315. @dllmethod
  316. def encrypt_project_files(proname, filelist, mode=0):
  317. prototype = PYFUNCTYPE(c_int, c_char_p, py_object, c_int)
  318. dlfunc = prototype(('encrypt_project_files', _pytransform))
  319. return dlfunc(proname.encode(), filelist, mode)
  320. def generate_project_capsule(licfile):
  321. prikey, pubkey, prolic = _generate_project_capsule()
  322. capkey = _encode_capsule_key_file(licfile)
  323. return prikey, pubkey, capkey, prolic
  324. @dllmethod
  325. def _encode_capsule_key_file(licfile):
  326. prototype = PYFUNCTYPE(py_object, c_char_p, c_char_p)
  327. dlfunc = prototype(('encode_capsule_key_file', _pytransform))
  328. return dlfunc(licfile.encode(), None)
  329. @dllmethod
  330. def encrypt_files(key, filelist, mode=0):
  331. t_key = c_char * 32
  332. prototype = PYFUNCTYPE(c_int, t_key, py_object, c_int)
  333. dlfunc = prototype(('encrypt_files', _pytransform))
  334. return dlfunc(t_key(*key), filelist, mode)
  335. @dllmethod
  336. def generate_module_key(pubname, key):
  337. t_key = c_char * 32
  338. prototype = PYFUNCTYPE(py_object, c_char_p, t_key, c_char_p)
  339. dlfunc = prototype(('generate_module_key', _pytransform))
  340. return dlfunc(pubname.encode(), t_key(*key), None)
  341. #
  342. # Compatible for PyArmor v3.0
  343. #
  344. @dllmethod
  345. def old_init_runtime(systrace=0, sysprofile=1, threadtrace=0, threadprofile=1):
  346. '''Only for old version, before PyArmor 3'''
  347. pyarmor_init(is_runtime=1)
  348. prototype = PYFUNCTYPE(c_int, c_int, c_int, c_int, c_int)
  349. _init_runtime = prototype(('init_runtime', _pytransform))
  350. return _init_runtime(systrace, sysprofile, threadtrace, threadprofile)
  351. @dllmethod
  352. def import_module(modname, filename):
  353. '''Only for old version, before PyArmor 3'''
  354. prototype = PYFUNCTYPE(py_object, c_char_p, c_char_p)
  355. _import_module = prototype(('import_module', _pytransform))
  356. return _import_module(modname.encode(), filename.encode())
  357. @dllmethod
  358. def exec_file(filename):
  359. '''Only for old version, before PyArmor 3'''
  360. prototype = PYFUNCTYPE(c_int, c_char_p)
  361. _exec_file = prototype(('exec_file', _pytransform))
  362. return _exec_file(filename.encode())