You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ORPA-pyOpenRPA/Tools/SafeSource/pyRobotName_Safe.py

203 lines
9.1 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#coding=utf-8
import os
import sys
import imp
import base64
from pyOpenRPA.Tools.SafeSource import Crypter # Crypto functions
import datetime #Datetime
import hashlib #Get hash of the word
import pyautogui
import os
import glob # list files
EXT = '.cry'
gExtensionName = "cry"
# How to run
# sys.meta_path.append(Base64Importer(root_pkg_path))
# Init cryptographer
def CryptographerInit(inFolderPathList, inKey):
#sys.meta_path.append(Base64Importer(inFolderPath))
# Flag add subfolder, which contains extension files
#path = 'c:\\projects\\hc2\\'
#folders = []
# Recursive walk throught the tree
# r=root, d=directories, f = files
#import pdb
#pdb.set_trace()
for lItem in inFolderPathList:
sys.meta_path.append(Base64Importer(os.path.abspath(lItem), inKey=inKey))
#for r, d, f in os.walk(lItem):
# for folder in d:
#folders.append(os.path.join(r, folder))
#sys.meta_path.append(Base64Importer(os.path.join(r, folder), inKey=inKey))
# pass
#for f in folders:
# print(f)
#===============================================================================
class Base64Importer(object):
"""Служит для поиска и импорта python-модулей, кодированных в base64
Класс реализует Import Protocol (PEP 302) для возможности импортирования
модулей, зашифрованных в base64 из указанного пакета.
"""
#---------------------------------------------------------------------------
def __init__(self, root_package_path, inKey):
self.mKeyStr = inKey
self.__modules_info = self.__collect_modules_info(root_package_path)
# Create list of cry files when run
#for lItem in root_package_path_list:
# lCryptedFileList = [f for f in glob.glob(os.path.join(lItem,f"**/*.{EXT}"), recursive=True)]
#---------------------------------------------------------------------------
def find_module(self, fullname, path=None):
"""Метод будет вызван при импорте модулей
Если модуль с именем fullname является base64 и находится в заданной
папке, данный метод вернёт экземпляр импортёра (finder), либо None, если
модуль не является base64.
"""
#print(f"find_module:: Fullname: {fullname}, path: {path}")
#print(f"modules info: {self.__modules_info}")
if fullname in self.__modules_info:
return self
return None
#---------------------------------------------------------------------------
def load_module(self, fullname):
"""Метод загружает base64 модуль
Если модуль с именем fullname является base64, то метод попытается его
загрузить. Возбуждает исключение ImportError в случае любой ошибки.
"""
#print(f"load_module:: Fullname: {fullname}")
if not fullname in self.__modules_info:
raise ImportError(fullname)
# Для потокобезопасности
imp.acquire_lock()
try:
mod = sys.modules.setdefault(fullname, imp.new_module(fullname))
mod.__file__ = "<{}>".format(self.__class__.__name__)
mod.__file__ = self.__modules_info[fullname]['filename'] #Hotfix
#print(f"MODFILE::{mod.__file__}")
mod.__loader__ = self
if self.is_package(fullname):
mod.__path__ = []
mod.__package__ = fullname
else:
mod.__package__ = fullname.rpartition('.')[0]
src = self.get_source(fullname)
try:
#__name__ = "pyRobotName"
#print(f"MODNAME:: {mod.__name__}")
#exec(src) in mod.__dict__
exec(src,mod.__dict__)
except:
del sys.modules[fullname]
raise ImportError(fullname)
finally:
imp.release_lock()
return mod
#---------------------------------------------------------------------------
def is_package(self, fullname):
"""Возвращает True если fullname является пакетом
"""
return self.__modules_info[fullname]['ispackage']
#---------------------------------------------------------------------------
def get_source(self, fullname):
"""Возвращает исходный код модуля fullname в виде строки
Метод декодирует исходные коды из base64
"""
filename = self.__modules_info[fullname]['filename']
try:
src = Crypter.decrypt_file_bytes(key = self.mKeyStr, in_filename = filename).decode("utf-8")
#with open(filename, 'r') as ifile:
# src = base64.decodestring(ifile.read())
except IOError:
src = ''
return src
# for __main__
def get_code(self, inModName):
return self.get_source(inModName)
#---------------------------------------------------------------------------
def __collect_modules_info(self, root_package_path):
"""Собирает информацию о модулях из указанного пакета
"""
modules = {}
"""
p = os.path.abspath(root_package_path)
dir_name = os.path.dirname(p) + os.sep
#dir_name = "" # Hotfix 2020 03 19
#print(f"__collect_modules_info:: root_package_path: {root_package_path}")
for root, _, files in os.walk(p):
# Информация о текущем пакете
filename = os.path.join(root, '__init__' + EXT)
p_fullname = root.rpartition(dir_name)[2].replace(os.sep, '.')
modules[p_fullname] = {
'filename': filename,
'ispackage': True
}
# Информация о модулях в текущем пакете
for f in files:
if not f.endswith(EXT):
continue
filename = os.path.join(root, f)
fullname = '.'.join([p_fullname, os.path.splitext(f)[0]])
fullname = os.path.splitext(f)[0]
modules[fullname] = {
'filename': filename,
'ispackage': False
}
"""
# # # # # # # # # # #
# New way of collection
lRootAbsPath = os.path.abspath(root_package_path)
#print(lRootAbsPath)
lNewPathIndex = len(lRootAbsPath)+len(os.sep) # Len of the root path + len sep
lCryptedFileList = [f for f in glob.glob(os.path.join(lRootAbsPath,f"**/*.{gExtensionName}"), recursive=True)]
#print(lCryptedFileList)
for lCryptedItemFullPath in lCryptedFileList:
# Get Module name
lModuleName = lCryptedItemFullPath[lNewPathIndex:-(1+len(gExtensionName))].replace(os.sep, '.')
# Check if file is not __init__.{EXT} - This is package
if f"__init__.{EXT}" in lCryptedItemFullPath:
# Add package
lModuleName = lModuleName.replace(f"{os.sep}__init__.{gExtensionName}","")
modules[lModuleName] = {
'filename': lCryptedItemFullPath,
'ispackage': True
}
else:
# Add item
modules[lModuleName] = {
'filename': lCryptedItemFullPath,
'ispackage': False
}
return modules
# Settings
gInUncryptedExtension = "py" # cry for filename.cry
gOutCryptedExtension = "cry" # cry for filename.cry
gFileMaskToDelete = "pyc" #Remove all .pyc files
print(f"{str(datetime.datetime.now())}: Run decryptography")
############# Step 5 - Ask and confirm the secret word
lKeyHashStr_1 = hashlib.sha256(pyautogui.password('Please enter the key to protect source code').encode("utf-8")).digest()
lKeyHashStr_2 = hashlib.sha256(pyautogui.password('Please repeat the key to protect source code').encode("utf-8")).digest()
if lKeyHashStr_1 == lKeyHashStr_2:
#sys.meta_path.append(Base64Importer("TestPackage",inKey = lKeyHashStr_1))
CryptographerInit(sys.argv[1:], inKey = lKeyHashStr_1)
print(f"{str(datetime.datetime.now())}: Cryprography module has been successfully initialized")
if __name__ == "__main__":
import pyRobotName_Settings
pyRobotName_Settings.pyRobotName_Settings()
else:
raise Exception("User set different secret key 1 and key 2")
############ Step 6 - Final stage
#Init the functions
#import runpy
#runpy.run_module(**gSettings["run_module"])
#runpy.run_path("pyRobotName_Settings", init_globals=None, run_name=None)
#src = Crypter.decrypt_file_bytes(key = lKeyHashStr_1, in_filename = "pyRobotName_Settings.cry").decode("utf-8")
#exec(src) in mod.__dict__
#import pyRobotName_Settings
#pyRobotName_Settings.