156 lines
5.0 KiB
Python
156 lines
5.0 KiB
Python
|
import os
|
||
|
import shutil
|
||
|
import plistlib
|
||
|
import subprocess
|
||
|
|
||
|
import tempfile
|
||
|
import stat
|
||
|
|
||
|
joinp = os.path.join
|
||
|
|
||
|
wrapper_folder = os.path.expanduser("~/bcell/ios-wrapper-stable/bin")
|
||
|
sdk_root_folder = os.path.expanduser("~/bcell/ios-sdk")
|
||
|
|
||
|
class Worker:
|
||
|
@property
|
||
|
def __backup_folder(self):
|
||
|
# return tempfile.TemporaryDirectory(prefix="ios-wrapper")
|
||
|
return "/tmp/ios-wrapper-backup"
|
||
|
|
||
|
@property
|
||
|
def ios_wrapper(self):
|
||
|
return joinp(wrapper_folder, "ios-wrapper")
|
||
|
|
||
|
@property
|
||
|
def bcell_framework(self):
|
||
|
if self.encryption_required:
|
||
|
return joinp(sdk_root_folder, "release", "bazel-bin",
|
||
|
"bcell", "bcell.framework_archive-root", "bcell.framework/")
|
||
|
else:
|
||
|
return joinp(sdk_root_folder, "bazel-bin",
|
||
|
"bcell", "bcell.framework_archive-root", "bcell.framework/")
|
||
|
|
||
|
@property
|
||
|
def encryptor(self):
|
||
|
return joinp(sdk_root_folder, "release", "generated", "encryptor/encryptor.py")
|
||
|
|
||
|
@property
|
||
|
def binary_modified(self):
|
||
|
return joinp(self.__backup_folder, self.binary_name + "_modified")
|
||
|
|
||
|
@property
|
||
|
def bcell_raw(self):
|
||
|
return joinp(self.__backup_folder, "bcell_raw.dat")
|
||
|
|
||
|
@property
|
||
|
def bcell_unencrypted(self):
|
||
|
return joinp(self.__backup_folder, "bcell_unencrypted.dat")
|
||
|
|
||
|
@property
|
||
|
def bcell_encrypted(self):
|
||
|
return joinp(self.__backup_folder, "bcell_encrypted.dat")
|
||
|
|
||
|
def __load_binary(self):
|
||
|
self.binary = self.infile
|
||
|
self.binary_name = os.path.basename(self.infile)
|
||
|
|
||
|
def __init__(self, **kwargs):
|
||
|
for key in kwargs:
|
||
|
setattr(self, key, kwargs[key])
|
||
|
|
||
|
# prepare backup folder
|
||
|
shutil.rmtree(self.__backup_folder, ignore_errors=True)
|
||
|
os.mkdir(self.__backup_folder)
|
||
|
|
||
|
# load file based on file type
|
||
|
self.__load_binary()
|
||
|
if self.binary_name is None:
|
||
|
raise Exception("Cannot determine binary name")
|
||
|
|
||
|
def wrap(self):
|
||
|
if self.encryption_required:
|
||
|
subprocess.run([self.ios_wrapper, "wrap",
|
||
|
"-c", self.config,
|
||
|
"-s", "-b", self.bcell_raw,
|
||
|
"-o", self.binary_modified,
|
||
|
self.binary])
|
||
|
else:
|
||
|
subprocess.run([self.ios_wrapper, "wrap",
|
||
|
"-c", self.config,
|
||
|
"-b", self.bcell_raw,
|
||
|
"-o", self.binary_modified,
|
||
|
self.binary])
|
||
|
return
|
||
|
|
||
|
print("ENCRYPT BCELL FILE")
|
||
|
subprocess.run(["python3", self.encryptor,
|
||
|
"--infile", self.bcell_unencrypted,
|
||
|
"--outfile", self.bcell_encrypted])
|
||
|
|
||
|
def finish(self):
|
||
|
bcell_out = os.path.dirname(self.binary)
|
||
|
os.makedirs(joinp(bcell_out, "Frameworks"), exist_ok=True)
|
||
|
|
||
|
bcell_file = (self.bcell_raw, self.bcell_encrypted)[self.encryption_required]
|
||
|
shutil.copy(bcell_file, joinp(bcell_out, "bcell.dat"))
|
||
|
shutil.copy(self.binary_modified, joinp(bcell_out, self.binary_name))
|
||
|
|
||
|
shutil.rmtree(joinp(bcell_out, "Frameworks", "bcell.framework"), ignore_errors=True)
|
||
|
shutil.copytree(self.bcell_framework, joinp(bcell_out, "Frameworks", "bcell.framework"))
|
||
|
|
||
|
st = os.stat(joinp(bcell_out, self.binary_name))
|
||
|
os.chmod(joinp(bcell_out, self.binary_name), st.st_mode | stat.S_IEXEC)
|
||
|
|
||
|
self.info(joinp(bcell_out, self.binary_name))
|
||
|
|
||
|
def cleanup(self):
|
||
|
shutil.rmtree(self.__backup_folder, ignore_errors=True)
|
||
|
|
||
|
def info(self, file):
|
||
|
subprocess.run([self.ios_wrapper, "info", file])
|
||
|
|
||
|
|
||
|
def check_files(file_path):
|
||
|
if not os.path.isfile(file_path):
|
||
|
raise Exception("The file %s does not exist" % file_path)
|
||
|
return
|
||
|
|
||
|
def is_encryption_required():
|
||
|
return os.environ.get("REQUIRE_ENCRYPTION", None) is not None
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
import argparse
|
||
|
description = """
|
||
|
A test tool made for use with Xcode, paths to wrapper and bcell.framework
|
||
|
are hard-coded in this script, modify them if needed.
|
||
|
|
||
|
Pass in Xcode Build Phase a Run script:
|
||
|
|
||
|
```
|
||
|
python3 /path/to/cloud-shield.py \
|
||
|
-c ${PROJECT_DIR}/bcell_config.json \
|
||
|
-i ${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}
|
||
|
```
|
||
|
"""
|
||
|
parser = argparse.ArgumentParser(description=description,
|
||
|
formatter_class=argparse.RawTextHelpFormatter)
|
||
|
|
||
|
parser.add_argument("-i", "--infile", metavar="input-file",
|
||
|
required=True, help="Input binary built by Xcode Run script")
|
||
|
parser.add_argument("-c", "--config", metavar="config-file",
|
||
|
required=True, help="Config JSON file")
|
||
|
|
||
|
options = parser.parse_args()
|
||
|
|
||
|
check_files(options.infile)
|
||
|
check_files(options.config)
|
||
|
|
||
|
encryption_required = is_encryption_required()
|
||
|
|
||
|
worker = Worker(encryption_required=encryption_required,
|
||
|
infile=options.infile,
|
||
|
config=options.config)
|
||
|
worker.wrap()
|
||
|
worker.finish()
|
||
|
worker.cleanup()
|