• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import path from 'path';
17import fs from 'fs';
18import {
19  ArkObfuscator,
20  initObfuscationConfig,
21  readProjectPropertiesByCollectedPaths,
22  performancePrinter
23} from 'arkguard';
24import {
25  EventList
26} from 'arkguard/lib/utils/PrinterUtils';
27
28import {
29  TS2ABC,
30  ESMODULE,
31  NODE_MODULES,
32  OH_MODULES,
33  OBFUSCATION_TOOL
34} from './ark_define';
35import {
36  isAotMode,
37  isDebug,
38  isBranchElimination
39} from '../utils';
40import {
41  isHarmonyOs,
42  isLinux,
43  isMac,
44  isWindows,
45  toUnixPath
46} from '../../../utils';
47import { getArkBuildDir } from '../../../ark_utils';
48import { checkAotConfig } from '../../../gen_aot';
49import { projectConfig as mainProjectConfig } from '../../../../main';
50import type { MergedConfig } from './ob_config_resolver';
51
52type ArkConfig = {
53  arkRootPath: string;
54  ts2abcPath: string;
55  js2abcPath: string;
56  mergeAbcPath: string;
57  es2abcPath: string;
58  aotCompilerPath: string;
59  nodePath: string;
60  isDebug: boolean;
61  isBranchElimination: boolean;
62  optTryCatchFunc: boolean;
63};
64
65export function initArkConfig(projectConfig: Object): ArkConfig {
66  let arkRootPath: string = path.join(__dirname, '..', '..', '..', '..', 'bin', 'ark');
67  if (projectConfig.arkFrontendDir) {
68    arkRootPath = projectConfig.arkFrontendDir;
69  }
70  let arkConfig: ArkConfig = {
71    arkRootPath: '',
72    ts2abcPath: '',
73    js2abcPath: '',
74    mergeAbcPath: '',
75    es2abcPath: '',
76    aotCompilerPath: '',
77    nodePath: '',
78    isDebug: false,
79    isBranchElimination: false,
80    optTryCatchFunc: false
81  };
82  arkConfig.nodePath = 'node';
83  if (projectConfig.nodeJs) {
84    arkConfig.nodePath = projectConfig.nodePath;
85  }
86  arkConfig.isDebug = isDebug(projectConfig);
87  arkConfig.isBranchElimination = isBranchElimination(projectConfig);
88  arkConfig.optTryCatchFunc = mainProjectConfig.optTryCatchFunc;
89  arkConfig.arkRootPath = arkRootPath;
90  processPlatformInfo(arkConfig);
91  processCompatibleVersion(projectConfig, arkConfig);
92  return arkConfig;
93}
94
95export function initArkProjectConfig(share: Object): Object {
96  let projectConfig: Object = share.projectConfig;
97  let arkProjectConfig: Object = {};
98  let entryPackageName: string = share.projectConfig.entryPackageName || '';
99  let entryModuleVersion: string = share.projectConfig.entryModuleVersion || '';
100  arkProjectConfig.entryPackageInfo = `${entryPackageName}|${entryModuleVersion}`;
101  arkProjectConfig.projectRootPath = share.projectConfig.projectTopDir;
102  if (projectConfig.aceBuildJson && fs.existsSync(projectConfig.aceBuildJson)) {
103    const buildJsonInfo = JSON.parse(fs.readFileSync(projectConfig.aceBuildJson).toString());
104    arkProjectConfig.projectRootPath = buildJsonInfo.projectRootPath;
105    arkProjectConfig.modulePathMap = buildJsonInfo.modulePathMap;
106    arkProjectConfig.isOhosTest = buildJsonInfo.isOhosTest;
107    arkProjectConfig.arkRouterMap = buildJsonInfo.routerMap;
108    // Collect bytecode har's declaration files entries include dynamic import and workers, use
109    // by es2abc for dependency resolution.
110    arkProjectConfig.declarationEntry = buildJsonInfo.declarationEntry;
111    if (buildJsonInfo.patchConfig) {
112      arkProjectConfig.oldMapFilePath = buildJsonInfo.patchConfig.oldMapFilePath;
113    }
114    if (checkAotConfig(projectConfig.compileMode, buildJsonInfo,
115      (error: string) => { share.throwArkTsCompilerError(error) })) {
116      arkProjectConfig.processTs = true;
117      arkProjectConfig.pandaMode = TS2ABC;
118      arkProjectConfig.anBuildOutPut = buildJsonInfo.anBuildOutPut;
119      arkProjectConfig.anBuildMode = buildJsonInfo.anBuildMode;
120      arkProjectConfig.apPath = buildJsonInfo.apPath;
121    } else {
122      arkProjectConfig.processTs = false;
123      arkProjectConfig.pandaMode = buildJsonInfo.pandaMode;
124    }
125
126    if (projectConfig.compileMode === ESMODULE) {
127      arkProjectConfig.nodeModulesPath = buildJsonInfo.nodeModulesPath;
128      // harNameOhmMap stores har packages that are dependent for bytecode har when compile bytecode har.
129      arkProjectConfig.harNameOhmMap = buildJsonInfo.harNameOhmMap;
130      arkProjectConfig.hspNameOhmMap = buildJsonInfo.hspNameOhmMap;
131      projectConfig.packageDir = buildJsonInfo.packageManagerType === 'ohpm' ? OH_MODULES : NODE_MODULES;
132    }
133    if (buildJsonInfo.dynamicImportLibInfo) {
134      arkProjectConfig.dynamicImportLibInfo = buildJsonInfo.dynamicImportLibInfo;
135    }
136    if (buildJsonInfo.byteCodeHarInfo) {
137      arkProjectConfig.byteCodeHarInfo = buildJsonInfo.byteCodeHarInfo;
138    }
139  }
140  if (projectConfig.aceManifestPath && fs.existsSync(projectConfig.aceManifestPath)) {
141    const manifestJsonInfo = JSON.parse(fs.readFileSync(projectConfig.aceManifestPath).toString());
142    if (manifestJsonInfo.minPlatformVersion) {
143      arkProjectConfig.minPlatformVersion = manifestJsonInfo.minPlatformVersion;
144    }
145  }
146  if (projectConfig.aceModuleJsonPath && fs.existsSync(projectConfig.aceModuleJsonPath)) {
147    const moduleJsonInfo = JSON.parse(fs.readFileSync(projectConfig.aceModuleJsonPath).toString());
148    if (moduleJsonInfo.app.minAPIVersion) {
149      arkProjectConfig.minPlatformVersion = moduleJsonInfo.app.minAPIVersion;
150    }
151    if (moduleJsonInfo.module) {
152      arkProjectConfig.moduleName = moduleJsonInfo.module.name;
153    }
154    if (moduleJsonInfo.app) {
155      arkProjectConfig.bundleName = moduleJsonInfo.app.bundleName;
156    }
157  }
158
159  // Hotreload attributes are initialized by arkui in main.js, just copy them.
160  arkProjectConfig.hotReload = mainProjectConfig.hotReload;
161  arkProjectConfig.coldReload = mainProjectConfig.coldReload;
162  arkProjectConfig.isFirstBuild = mainProjectConfig.isFirstBuild;
163  arkProjectConfig.patchAbcPath = mainProjectConfig.patchAbcPath;
164  arkProjectConfig.changedFileList = mainProjectConfig.changedFileList;
165
166  if (mainProjectConfig.es2abcCompileTsInAotMode || mainProjectConfig.es2abcCompileTsInNonAotMode) {
167    arkProjectConfig.pandaMode = mainProjectConfig.pandaMode;
168    arkProjectConfig.processTs = mainProjectConfig.processTs;
169  }
170  arkProjectConfig.compileMode = projectConfig.compileMode;
171  arkProjectConfig.entryObj = mainProjectConfig.entryObj;
172  arkProjectConfig.entryArrayForObf = mainProjectConfig.entryArrayForObf;
173  arkProjectConfig.cardEntryObj = mainProjectConfig.cardEntryObj;
174  if (mainProjectConfig.updateVersionInfo) {
175    arkProjectConfig.updateVersionInfo = mainProjectConfig.updateVersionInfo;
176  }
177  if (!isDebug(projectConfig)) {
178    arkProjectConfig.useTsHar = mainProjectConfig.useTsHar;
179    const logger: any = share.getLogger(OBFUSCATION_TOOL);
180    performancePrinter?.iniPrinter?.startEvent(EventList.OBFUSCATION_INITIALIZATION);
181    initObfuscationConfig(projectConfig, arkProjectConfig, logger);
182    performancePrinter?.iniPrinter?.endEvent(EventList.OBFUSCATION_INITIALIZATION);
183  }
184  return arkProjectConfig;
185}
186
187function initTerserConfig(projectConfig: any, logger: any, mergedObConfig: MergedConfig, isHarCompiled: boolean): any {
188  const isCompact = projectConfig.obfuscationOptions ? mergedObConfig.options.compact : isHarCompiled;
189  const minifyOptions = {
190    format: {
191      beautify: !isCompact,
192      indent_level: 2
193    },
194    compress: {
195      join_vars: false,
196      sequences: 0,
197      directives: false,
198      drop_console: mergedObConfig.options.removeLog
199    },
200    mangle: {
201      reserved: mergedObConfig.reservedNames,
202      toplevel: mergedObConfig.options.enableToplevelObfuscation
203    }
204  };
205  const applyNameCache: string | undefined = mergedObConfig.options.applyNameCache;
206  if (applyNameCache && applyNameCache.length > 0) {
207    if (fs.existsSync(applyNameCache)) {
208      minifyOptions.nameCache = JSON.parse(fs.readFileSync(applyNameCache, 'utf-8'));
209    } else {
210      logger.error(`ArkTS:ERROR Namecache file ${applyNameCache} does not exist`);
211    }
212  } else {
213    if (projectConfig.obfuscationOptions && projectConfig.obfuscationOptions.obfuscationCacheDir) {
214      const defaultNameCachePath: string = path.join(projectConfig.obfuscationOptions.obfuscationCacheDir, 'nameCache.json');
215      if (fs.existsSync(defaultNameCachePath)) {
216        minifyOptions.nameCache = JSON.parse(fs.readFileSync(defaultNameCachePath, 'utf-8'));
217      } else {
218        minifyOptions.nameCache = {};
219      }
220    }
221  }
222
223  if (mergedObConfig.options.enablePropertyObfuscation) {
224    minifyOptions.mangle.properties = {
225      reserved: mergedObConfig.reservedPropertyNames,
226      keep_quoted: !mergedObConfig.options.enableStringPropertyObfuscation
227    };
228  }
229  return minifyOptions;
230}
231
232// Scan the source code of project and libraries to collect whitelists.
233export function readProjectAndLibsSource(allFiles: Set<string>, mergedObConfig: MergedConfig, arkObfuscator: ArkObfuscator, isHarCompiled: boolean,
234  keepFilesAndDependencies: Set<string>): void {
235  if (mergedObConfig?.options === undefined || mergedObConfig.options.disableObfuscation || allFiles.size === 0) {
236    return;
237  }
238  const obfOptions = mergedObConfig.options;
239  let projectAndLibs: {projectAndLibsReservedProperties: string[]; libExportNames: string[]};
240  projectAndLibs = readProjectPropertiesByCollectedPaths(allFiles,
241    {
242      mNameObfuscation: {
243        mEnable: true,
244        mReservedProperties: [],
245        mRenameProperties: obfOptions.enablePropertyObfuscation,
246        mKeepStringProperty: !obfOptions.enableStringPropertyObfuscation
247      },
248      mExportObfuscation: obfOptions.enableExportObfuscation,
249      mKeepFileSourceCode: {
250        mKeepSourceOfPaths: new Set(),
251        mkeepFilesAndDependencies: keepFilesAndDependencies,
252      }
253    }, isHarCompiled);
254  if (obfOptions.enablePropertyObfuscation && projectAndLibs.projectAndLibsReservedProperties) {
255    arkObfuscator.addReservedProperties(projectAndLibs.projectAndLibsReservedProperties);
256  }
257  if (obfOptions.enableExportObfuscation && projectAndLibs.libExportNames) {
258    arkObfuscator.addReservedNames(projectAndLibs.libExportNames);
259    arkObfuscator.addReservedToplevelNames(projectAndLibs.libExportNames);
260  }
261}
262
263function processPlatformInfo(arkConfig: ArkConfig): void {
264  const arkPlatformPath: string = getArkBuildDir(arkConfig.arkRootPath);
265  if (isWindows()) {
266    arkConfig.es2abcPath = path.join(arkPlatformPath, 'bin', 'es2abc.exe');
267    arkConfig.ts2abcPath = path.join(arkPlatformPath, 'src', 'index.js');
268    arkConfig.mergeAbcPath = path.join(arkPlatformPath, 'bin', 'merge_abc.exe');
269    arkConfig.js2abcPath = path.join(arkPlatformPath, 'bin', 'js2abc.exe');
270    arkConfig.aotCompilerPath = path.join(arkPlatformPath, 'bin', 'ark_aot_compiler.exe');
271    return;
272  }
273  if (isLinux() || isMac()) {
274    arkConfig.es2abcPath = path.join(arkPlatformPath, 'bin', 'es2abc');
275    arkConfig.ts2abcPath = path.join(arkPlatformPath, 'src', 'index.js');
276    arkConfig.mergeAbcPath = path.join(arkPlatformPath, 'bin', 'merge_abc');
277    arkConfig.js2abcPath = path.join(arkPlatformPath, 'bin', 'js2abc');
278    arkConfig.aotCompilerPath = path.join(arkPlatformPath, 'bin', 'ark_aot_compiler');
279    return;
280  }
281  if (isHarmonyOs()) {
282    arkConfig.es2abcPath = path.join(arkPlatformPath, 'bin', 'es2abc');
283    return;
284  }
285}
286
287function processCompatibleVersion(projectConfig: Object, arkConfig: ArkConfig): void {
288  const platformPath: string = getArkBuildDir(arkConfig.arkRootPath);
289  if (projectConfig.minPlatformVersion && projectConfig.minPlatformVersion.toString() === '8') {
290    // use ts2abc to compile apps with 'CompatibleSdkVersion' set to 8
291    arkConfig.ts2abcPath = path.join(platformPath, 'legacy_api8', 'src', 'index.js');
292    projectConfig.pandaMode = TS2ABC;
293  }
294}
295
296export const utProcessArkConfig = {
297  processCompatibleVersion,
298  initTerserConfig
299};
300