import json
import os
import re
import stat
import sys
from subprocess import Popen
from subprocess import PIPE
global_config = {}
templates = {
'generate-keypair': {
'required': ['keyAlias', 'keyAlg', 'keySize', 'keystoreFile'],
'others': ['keyPwd', 'keystorePwd']
},
'generate-csr': {
'required': ['keyAlias', 'signAlg', 'subject', 'keystoreFile', 'outFile'],
'others': ['keyPwd', 'keystorePwd']
},
'generate-ca': {
'required': ['keyAlias', 'signAlg', 'keyAlg', 'keySize', 'subject', 'keystoreFile', 'outFile'],
'others': ['keyPwd', 'keystorePwd', 'issuer', 'issuerKeyAlias', 'issuerKeyPwd', 'validity',
'basicConstraintsPathLen']
},
'generate-app-cert': {
'required': ['keyAlias', 'signAlg', 'issuer', 'issuerKeyAlias', 'subject', 'keystoreFile',
'subCaCertFile', 'rootCaCertFile', 'outForm', 'outFile'],
'others': ['keyPwd', 'keystorePwd', 'issuerKeyPwd', 'validity',
'basicConstraintsPathLen']
},
'generate-profile-cert': {
'required': ['keyAlias', 'signAlg', 'issuer', 'issuerKeyAlias', 'subject', 'keystoreFile',
'subCaCertFile', 'rootCaCertFile', 'outForm', 'outFile'],
'others': ['keyPwd', 'keystorePwd', 'issuerKeyPwd', 'validity',
'basicConstraintsPathLen']
},
'sign-profile': {
'required': ['keyAlias', 'signAlg', 'mode', 'profileCertFile', 'inFile', 'keystoreFile', 'outFile'],
'others': ['keyPwd', 'keystorePwd']
},
'sign-app': {
'required': ['keyAlias', 'signAlg', 'mode', 'appCertFile', 'profileFile', 'inFile', 'keystoreFile', 'outFile'],
'others': ['keyPwd', 'keystorePwd', 'inForm', 'signCode']
},
}
def print_help():
content = "\n" \
"Usage:python autosign.py <generate|sign> \n" \
" signtool.jar : Main progress jar file\n" \
"\n" \
"Example: \n" \
" python autosign.py createAppCertAndProfile \n" \
" python autosign.py signHap" \
"\n"
print(content)
def get_from_single_config(config_key, item_key, required=False):
param = global_config.get(config_key, {}).get(item_key, None)
if not param:
param = global_config.get('common', {}).get(item_key, None)
if not param:
if required:
print('Prepare loading: {}, config: {}'.format(config_key, global_config.get(config_key)))
print("Params {} is required.".format(item_key))
exit(1)
return param
def prepare_dir(dir_name):
if not os.path.exists(dir_name):
os.mkdir(dir_name)
def load_engine(engine_config):
tar_dir = global_config.get('config', {}).get('targetDir')
prepare_dir(tar_dir)
cmds = []
for eng_k, eng_v in engine_config.items():
template = templates.get(eng_v)
cmd = [eng_v]
for required_key in template.get('required'):
param = get_from_single_config(eng_k, required_key, True)
if required_key.endswith('File') and required_key != 'inFile' and os.path.basename(param) == param:
param = os.path.join(tar_dir, param)
cmd.append('-{}'.format(required_key))
cmd.append(param)
for others_key in template.get('others'):
param = get_from_single_config(eng_k, others_key, False)
if param:
cmd.append('-{}'.format(others_key))
cmd.append(param)
cmds.append(cmd)
return cmds
def run_target(cmd):
command = Popen(cmd, stdout=PIPE, stderr=PIPE, stdin=PIPE, shell=False)
out = command.stdout.readlines()
with open("log.txt", mode='a+', encoding='utf-8') as f:
if len(out) > 0:
f.writelines(' '.join(cmd) + "\r\n")
for line in out:
f.writelines(str(line.strip()) + "\r\n")
success = True
error = command.stderr.readlines()
with open("error.txt", mode='a+', encoding='utf-8') as f:
if len(error) > 0:
f.writelines(' '.join(cmd) + "\r\n")
for line in error:
success = False
f.writelines(str(line.strip()) + "\r\n")
command.wait()
return success
def run_with_engine(engine, jar):
cmds = load_engine(engine)
for cmd in cmds:
cmd.insert(0, jar)
cmd.insert(0, '-jar')
cmd.insert(0, 'java')
result = run_target(cmd)
if not result:
print("Command error on executing cmd, please check error.txt")
print(' '.join(cmd))
exit(1)
print("Success!")
pass
def do_sign(jar):
sign_engine_config = {
'sign.profile': 'sign-profile',
'sign.app': 'sign-app'
}
run_with_engine(sign_engine_config, jar)
def do_sign_hap(jar):
sign_hap_engine_config = {
'sign.app': 'sign-app'
}
run_with_engine(sign_hap_engine_config, jar)
def do_sign_elf(jar):
sign_elf_engine_config = {
'sign.app': 'sign-app'
}
run_with_engine(sign_elf_engine_config, jar)
def do_generate(jar):
cert_engine_config = {
'app.keypair': 'generate-keypair',
'profile.keypair': 'generate-keypair',
'csr': 'generate-csr',
'root-ca': 'generate-ca',
'sub-ca.app': 'generate-ca',
'sub-ca.profile': 'generate-ca',
'cert.app': 'generate-app-cert',
'cert.profile': 'generate-profile-cert',
}
run_with_engine(cert_engine_config, jar)
def do_generate_root_cert(jar):
root_engine_config = {
'profile.keypair': 'generate-keypair',
'root-ca': 'generate-ca',
'sub-ca.app': 'generate-ca',
'sub-ca.profile': 'generate-ca',
'cert.profile': 'generate-profile-cert',
}
run_with_engine(root_engine_config, jar)
def do_generate_app_cert(jar):
app_cert_engine_config = {
'app.keypair': 'generate-keypair',
'cert.app': 'generate-app-cert',
}
run_with_engine(app_cert_engine_config, jar)
def do_sign_profile(jar):
app_cert_engine_config = {
'sign.profile': 'sign-profile',
}
run_with_engine(app_cert_engine_config, jar)
def convert_to_map(line, temp_map):
line = line.strip('\n')
strs = line.split('=', 1)
if len(strs) == 2:
if strs[1].startswith('$'):
temp_map[strs[0]] = temp_map[strs[1][1:]]
else:
temp_map[strs[0]] = strs[1]
def load_config(config):
config_file = config
temp_map = {}
with open(config_file, 'r', encoding='utf-8') as f:
for line in f.readlines():
if not re.match(r'\s*//[\s\S]*', line):
convert_to_map(line, temp_map)
for mk, mv in temp_map.items():
strs = mk.rsplit('.', 1)
if not global_config.get(strs[0]):
global_config[strs[0]] = {}
global_config[strs[0]][strs[-1]] = mv
def process_cmd():
args = sys.argv
if len(args) <= 1 or '--help' == args[1] or '-h' == args[1]:
print_help()
exit(0)
action = args[1]
if action not in ['createRootAndSubCert', 'createAppCertAndProfile', 'signHap', 'signElf']:
print("Not support cmd")
print_help()
exit(1)
return action
def process_jar():
read_jar_file = global_config.get('config', {}).get('signtool')
if not os.path.exists(read_jar_file):
print("Jar file '{}' not found".format(read_jar_file))
exit(1)
return read_jar_file
def replace_cert_in_profile():
profile_file = global_config.get('sign.profile', {}).get('inFile')
app_cert_file = global_config.get('cert.app', {}).get('outFile')
tar_dir = global_config.get('config', {}).get('targetDir')
app_cert_file = os.path.join(tar_dir, app_cert_file)
if not os.path.exists(profile_file):
print("profile file '{}' not found".format(jar_file))
exit(1)
if not os.path.exists(app_cert_file):
print("app cert file '{}' not found".format(jar_file))
exit(1)
app_cert = ''
with open(app_cert_file, 'r', encoding='utf-8') as f:
app_cert_temp = f.read()
app_cert = app_cert_temp.split("-----END CERTIFICATE-----")[0] + "-----END CERTIFICATE-----\n"
profile = {}
with open(profile_file, 'r', encoding='utf-8') as f:
profile = json.load(f)
try:
profile["bundle-info"]["distribution-certificate"] = app_cert
except KeyError:
print("could not find distribution-certificate key in profile")
flags = os.O_WRONLY | os.O_TRUNC
modes = stat.S_IWUSR
with os.fdopen(os.open(profile_file, flags, modes), 'w') as profile_write:
json.dump(profile, profile_write)
if __name__ == '__main__':
act = process_cmd()
if act == 'createRootAndSubCert':
load_config('createRootAndSubCert.config')
jar_file = process_jar()
do_generate_root_cert(jar_file)
elif act == 'createAppCertAndProfile':
load_config('createAppCertAndProfile.config')
jar_file = process_jar()
do_generate_app_cert(jar_file)
replace_cert_in_profile()
do_sign_profile(jar_file)
elif act == 'signHap':
load_config('signHap.config')
jar_file = process_jar()
do_sign_hap(jar_file)
elif act == 'signElf':
load_config('signElf.config')
jar_file = process_jar()
do_sign_elf(jar_file)