1#!/usr/bin/env python 2# coding=utf-8 3############################################## 4# Copyright (c) 2021-2022 Huawei Device Co., Ltd. 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16############################################## 17import json 18import os 19import re 20import sys 21from subprocess import Popen 22from subprocess import PIPE 23 24global_config = {} 25 26templates = { 27 'generate-keypair': { 28 'required': ['keyAlias', 'keyAlg', 'keySize', 'keystoreFile'], 29 'others': ['keyPwd', 'keystorePwd'] 30 }, 31 'generate-csr': { 32 'required': ['keyAlias', 'signAlg', 'subject', 'keystoreFile', 'outFile'], 33 'others': ['keyPwd', 'keystorePwd'] 34 }, 35 'generate-ca': { 36 'required': ['keyAlias', 'signAlg', 'keyAlg', 'keySize', 'subject', 'keystoreFile', 'outFile'], 37 'others': ['keyPwd', 'keystorePwd', 'issuer', 'issuerKeyAlias', 'issuerKeyPwd', 'validity', 38 'basicConstraintsPathLen'] 39 }, 40 'generate-app-cert': { 41 'required': ['keyAlias', 'signAlg', 'issuer', 'issuerKeyAlias', 'subject', 'keystoreFile', 42 'subCaCertFile', 'rootCaCertFile', 'outForm', 'outFile'], 43 'others': ['keyPwd', 'keystorePwd', 'issuerKeyPwd', 'validity', 44 'basicConstraintsPathLen'] 45 }, 46 'generate-profile-cert': { 47 'required': ['keyAlias', 'signAlg', 'issuer', 'issuerKeyAlias', 'subject', 'keystoreFile', 48 'subCaCertFile', 'rootCaCertFile', 'outForm', 'outFile'], 49 'others': ['keyPwd', 'keystorePwd', 'issuerKeyPwd', 'validity', 50 'basicConstraintsPathLen'] 51 }, 52 'sign-profile': { 53 'required': ['keyAlias', 'signAlg', 'mode', 'profileCertFile', 'inFile', 'keystoreFile', 'outFile'], 54 'others': ['keyPwd', 'keystorePwd'] 55 }, 56 'sign-app': { 57 'required': ['keyAlias', 'signAlg', 'mode', 'appCertFile', 'profileFile', 'inFile', 'keystoreFile', 'outFile'], 58 'others': ['keyPwd', 'keystorePwd'] 59 }, 60} 61 62 63def print_help(): 64 content = "\n" \ 65 "Usage:python autosign.py <generate|sign> \n" \ 66 " signtool.jar : Main progress jar file\n" \ 67 "\n" \ 68 "Example: \n" \ 69 " python autosign.py createAppCertAndProfile \n" \ 70 " python autosign.py signHap" \ 71 "\n" 72 print(content) 73 74 75def get_from_single_config(config_key, item_key, required=False): 76 param = global_config.get(config_key, {}).get(item_key, None) 77 if not param: 78 param = global_config.get('common', {}).get(item_key, None) 79 if not param: 80 if required: 81 print('Prepare loading: {}, config: {}'.format(config_key, global_config.get(config_key))) 82 print("Params {} is required.".format(item_key)) 83 exit(1) 84 return param 85 86 87def prepare_dir(dir_name): 88 if not os.path.exists(dir_name): 89 os.mkdir(dir_name) 90 91 92def load_engine(engine_config): 93 tar_dir = global_config.get('config', {}).get('targetDir') 94 prepare_dir(tar_dir) 95 96 cmds = [] 97 for eng_k, eng_v in engine_config.items(): 98 template = templates.get(eng_v) 99 cmd = eng_v 100 for required_key in template.get('required'): 101 param = get_from_single_config(eng_k, required_key, True) 102 if required_key.endswith('File') and required_key != 'inFile' and os.path.basename(param) == param: 103 param = os.path.join(tar_dir, param) 104 cmd = '{} -{} "{}"'.format(cmd, required_key, param) 105 106 for others_key in template.get('others'): 107 param = get_from_single_config(eng_k, others_key, False) 108 if param: 109 cmd = '{} -{} "{}"'.format(cmd, others_key, param) 110 cmds.append(cmd) 111 return cmds 112 113 114def run_target(cmd): 115 command = Popen(cmd, stdout=PIPE, stderr=PIPE, stdin=PIPE, shell=True) 116 out = command.stdout.readlines() 117 with open("log.txt", mode='a+', encoding='utf-8') as f: 118 if len(out) > 0: 119 f.writelines(cmd + "\r\n") 120 for line in out: 121 f.writelines(str(line.strip()) + "\r\n") 122 123 success = True 124 error = command.stderr.readlines() 125 with open("error.txt", mode='a+', encoding='utf-8') as f: 126 if len(error) > 0: 127 f.writelines(cmd + "\r\n") 128 129 for line in error: 130 success = False 131 f.writelines(str(line.strip()) + "\r\n") 132 133 command.wait() 134 return success 135 136 137def run_with_engine(engine, jar): 138 cmds = load_engine(engine) 139 for cmd in cmds: 140 result = run_target('java -jar {} {}'.format(jar, cmd)) 141 if not result: 142 print("Command error on executing cmd, please check error.txt") 143 print(cmd) 144 exit(1) 145 print("Success!") 146 pass 147 148 149def do_sign(jar): 150 sign_engine_config = { 151 'sign.profile': 'sign-profile', 152 'sign.app': 'sign-app' 153 } 154 run_with_engine(sign_engine_config, jar) 155 156 157def do_sign_hap(jar): 158 sign_hap_engine_config = { 159 'sign.app': 'sign-app' 160 } 161 run_with_engine(sign_hap_engine_config, jar) 162 163 164def do_generate(jar): 165 cert_engine_config = { 166 'app.keypair': 'generate-keypair', 167 'profile.keypair': 'generate-keypair', 168 'csr': 'generate-csr', 169 'root-ca': 'generate-ca', 170 'sub-ca.app': 'generate-ca', 171 'sub-ca.profile': 'generate-ca', 172 'cert.app': 'generate-app-cert', 173 'cert.profile': 'generate-profile-cert', 174 } 175 run_with_engine(cert_engine_config, jar) 176 177 178def do_generate_root_cert(jar): 179 root_engine_config = { 180 'profile.keypair': 'generate-keypair', 181 'root-ca': 'generate-ca', 182 'sub-ca.app': 'generate-ca', 183 'sub-ca.profile': 'generate-ca', 184 'cert.profile': 'generate-profile-cert', 185 } 186 run_with_engine(root_engine_config, jar) 187 188 189def do_generate_app_cert(jar): 190 app_cert_engine_config = { 191 'app.keypair': 'generate-keypair', 192 'cert.app': 'generate-app-cert', 193 } 194 run_with_engine(app_cert_engine_config, jar) 195 196 197def do_sign_profile(jar): 198 app_cert_engine_config = { 199 'sign.profile': 'sign-profile', 200 } 201 run_with_engine(app_cert_engine_config, jar) 202 203 204def convert_to_map(line, temp_map): 205 line = line.strip('\n') 206 strs = line.split('=', 1) 207 208 if len(strs) == 2: 209 if strs[1].startswith('$'): 210 temp_map[strs[0]] = temp_map[strs[1][1:]] 211 else: 212 temp_map[strs[0]] = strs[1] 213 214 215def load_config(config): 216 config_file = config 217 temp_map = {} 218 with open(config_file, 'r', encoding='utf-8') as f: 219 for line in f.readlines(): 220 if not re.match(r'\s*//[\s\S]*', line): 221 convert_to_map(line, temp_map) 222 223 for mk, mv in temp_map.items(): 224 strs = mk.rsplit('.', 1) 225 if not global_config.get(strs[0]): 226 global_config[strs[0]] = {} 227 global_config[strs[0]][strs[-1]] = mv 228 229 230def process_cmd(): 231 args = sys.argv 232 if len(args) <= 1 or '--help' == args[1] or '-h' == args[1]: 233 print_help() 234 exit(0) 235 236 action = args[1] 237 if action not in ['createRootAndSubCert', 'createAppCertAndProfile', 'signHap']: 238 print("Not support cmd") 239 print_help() 240 exit(1) 241 return action 242 243 244def process_jar(): 245 read_jar_file = global_config.get('config', {}).get('signtool') 246 if not os.path.exists(read_jar_file): 247 print("Jar file '{}' not found".format(read_jar_file)) 248 exit(1) 249 return read_jar_file 250 251 252def replace_cert_in_profile(): 253 profile_file = global_config.get('sign.profile', {}).get('inFile') 254 app_cert_file = global_config.get('cert.app', {}).get('outFile') 255 tar_dir = global_config.get('config', {}).get('targetDir') 256 app_cert_file = os.path.join(tar_dir, app_cert_file) 257 if not os.path.exists(profile_file): 258 print("profile file '{}' not found".format(jar_file)) 259 exit(1) 260 if not os.path.exists(app_cert_file): 261 print("app cert file '{}' not found".format(jar_file)) 262 exit(1) 263 264 app_cert = '' 265 # read app cert 266 with open(app_cert_file, 'r', encoding='utf-8') as f: 267 app_cert_temp = f.read() 268 app_cert = app_cert_temp.split("-----END CERTIFICATE-----")[0] + "-----END CERTIFICATE-----\n" 269 270 profile = {} 271 # read profile 272 with open(profile_file, 'r', encoding='utf-8') as f: 273 profile = json.load(f) 274 275 profile["bundle-info"]["distribution-certificate"] = app_cert 276 277 # save profile 278 with open(profile_file, 'w', encoding='utf-8') as profile_write: 279 json.dump(profile, profile_write) 280 281 282if __name__ == '__main__': 283 act = process_cmd() 284 if act == 'createRootAndSubCert': 285 load_config('createRootAndSubCert.config') 286 jar_file = process_jar() 287 do_generate_root_cert(jar_file) 288 elif act == 'createAppCertAndProfile': 289 load_config('createAppCertAndProfile.config') 290 jar_file = process_jar() 291 do_generate_app_cert(jar_file) 292 replace_cert_in_profile() 293 do_sign_profile(jar_file) 294 elif act == 'signHap': 295 load_config('signHap.config') 296 jar_file = process_jar() 297 do_sign_hap(jar_file) 298