• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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