• 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  readProjectPropertiesByCollectedPaths
21} from "arkguard"
22
23import {
24  TS2ABC,
25  ESMODULE,
26  NODE_MODULES,
27  OH_MODULES,
28  OBFUSCATION_TOOL
29} from './ark_define';
30import { isAotMode, isDebug } from '../utils';
31import {
32  isLinux,
33  isMac,
34  isWindows
35} from '../../../utils';
36import { getArkBuildDir } from '../../../ark_utils';
37import { checkAotConfig } from '../../../gen_aot';
38import { projectConfig as mainProjectConfig } from '../../../../main';
39import {
40  ObConfigResolver,
41  collectResevedFileNameInIDEConfig,
42  readNameCache,
43} from './ob_config_resolver';
44import type { MergedConfig } from './ob_config_resolver';
45
46type ArkConfig = {
47  arkRootPath: string;
48  ts2abcPath: string;
49  js2abcPath: string;
50  mergeAbcPath: string;
51  es2abcPath: string;
52  aotCompilerPath: string;
53  nodePath: string;
54  isDebug: boolean;
55};
56
57export function initArkConfig(projectConfig: Object): ArkConfig {
58  let arkRootPath: string = path.join(__dirname, '..', '..', '..', '..', 'bin', 'ark');
59  if (projectConfig.arkFrontendDir) {
60    arkRootPath = projectConfig.arkFrontendDir;
61  }
62  let arkConfig: ArkConfig = {
63    arkRootPath: '',
64    ts2abcPath: '',
65    js2abcPath: '',
66    mergeAbcPath: '',
67    es2abcPath: '',
68    aotCompilerPath: '',
69    nodePath: '',
70    isDebug: false
71  };
72  arkConfig.nodePath = 'node';
73  if (projectConfig.nodeJs) {
74    arkConfig.nodePath = projectConfig.nodePath;
75  }
76  arkConfig.isDebug = isDebug(projectConfig);
77  arkConfig.arkRootPath = arkRootPath;
78  processPlatformInfo(arkConfig);
79  processCompatibleVersion(projectConfig, arkConfig);
80  return arkConfig;
81}
82
83export function initArkProjectConfig(share: Object): Object {
84  let projectConfig: Object = share.projectConfig;
85  let arkProjectConfig: Object = {};
86  if (projectConfig.aceBuildJson && fs.existsSync(projectConfig.aceBuildJson)) {
87    const buildJsonInfo = JSON.parse(fs.readFileSync(projectConfig.aceBuildJson).toString());
88    arkProjectConfig.projectRootPath = buildJsonInfo.projectRootPath;
89    arkProjectConfig.modulePathMap = buildJsonInfo.modulePathMap;
90    arkProjectConfig.isOhosTest = buildJsonInfo.isOhosTest;
91    if (buildJsonInfo.patchConfig) {
92      arkProjectConfig.oldMapFilePath = buildJsonInfo.patchConfig.oldMapFilePath;
93    }
94    if (checkAotConfig(projectConfig.compileMode, buildJsonInfo,
95      (error: string) => { share.throwArkTsCompilerError(error) })) {
96      arkProjectConfig.processTs = true;
97      arkProjectConfig.pandaMode = TS2ABC;
98      arkProjectConfig.anBuildOutPut = buildJsonInfo.anBuildOutPut;
99      arkProjectConfig.anBuildMode = buildJsonInfo.anBuildMode;
100      arkProjectConfig.apPath = buildJsonInfo.apPath;
101    } else {
102      arkProjectConfig.processTs = false;
103      arkProjectConfig.pandaMode = buildJsonInfo.pandaMode;
104    }
105
106    if (projectConfig.compileMode === ESMODULE) {
107      arkProjectConfig.nodeModulesPath = buildJsonInfo.nodeModulesPath;
108      arkProjectConfig.harNameOhmMap = buildJsonInfo.harNameOhmMap;
109      projectConfig.packageDir = buildJsonInfo.packageManagerType === 'ohpm' ? OH_MODULES : NODE_MODULES;
110    }
111    if (buildJsonInfo.dynamicImportLibInfo) {
112      arkProjectConfig.dynamicImportLibInfo = buildJsonInfo.dynamicImportLibInfo;
113    }
114  }
115  if (projectConfig.aceManifestPath && fs.existsSync(projectConfig.aceManifestPath)) {
116    const manifestJsonInfo = JSON.parse(fs.readFileSync(projectConfig.aceManifestPath).toString());
117    if (manifestJsonInfo.minPlatformVersion) {
118      arkProjectConfig.minPlatformVersion = manifestJsonInfo.minPlatformVersion;
119    }
120  }
121  if (projectConfig.aceModuleJsonPath && fs.existsSync(projectConfig.aceModuleJsonPath)) {
122    const moduleJsonInfo = JSON.parse(fs.readFileSync(projectConfig.aceModuleJsonPath).toString());
123    if (moduleJsonInfo.app.minAPIVersion) {
124      arkProjectConfig.minPlatformVersion = moduleJsonInfo.app.minAPIVersion;
125    }
126    if (moduleJsonInfo.module) {
127      arkProjectConfig.moduleName = moduleJsonInfo.module.name;
128    }
129    if (moduleJsonInfo.app) {
130      arkProjectConfig.bundleName = moduleJsonInfo.app.bundleName;
131    }
132  }
133
134  // Hotreload attributes are initialized by arkui in main.js, just copy them.
135  arkProjectConfig.hotReload = mainProjectConfig.hotReload;
136  arkProjectConfig.patchAbcPath = mainProjectConfig.patchAbcPath;
137  arkProjectConfig.changedFileList = mainProjectConfig.changedFileList;
138
139  if(mainProjectConfig.es2abcCompileTsInAotMode || mainProjectConfig.es2abcCompileTsInNonAotMode) {
140    arkProjectConfig.pandaMode = mainProjectConfig.pandaMode;
141    arkProjectConfig.processTs = mainProjectConfig.processTs;
142  }
143  arkProjectConfig.compileMode = projectConfig.compileMode;
144
145  if (projectConfig.compileHar || !isDebug(projectConfig))  {
146    const logger: any = share.getLogger(OBFUSCATION_TOOL);
147    initObfuscationConfig(projectConfig, arkProjectConfig, logger);
148  }
149  return arkProjectConfig;
150}
151
152function initObfuscationConfig(projectConfig: any, arkProjectConfig: any, logger: any): void {
153  const obConfig: ObConfigResolver =  new ObConfigResolver(projectConfig, logger, true);
154  const mergedObConfig: MergedConfig = obConfig.resolveObfuscationConfigs();
155  const isHarCompiled: boolean = projectConfig.compileHar;
156  if (mergedObConfig.options.disableObfuscation) {
157    return;
158  }
159
160  if (!isHarCompiled) {
161    mergedObConfig.options.enableFileNameObfuscation = false;
162    mergedObConfig.reservedFileNames = [];
163  }
164
165  if (mergedObConfig.options.enableFileNameObfuscation) {
166    const ohPackagePath = path.join(projectConfig.modulePath, 'oh-package.json5');
167    const reservedFileNamesInIDEconfig = collectResevedFileNameInIDEConfig(ohPackagePath, projectConfig.aceModuleJsonPath,
168      projectConfig.projectPath, projectConfig.cachePath);
169    mergedObConfig.reservedFileNames.push(...reservedFileNamesInIDEconfig);
170  }
171  arkProjectConfig.obfuscationMergedObConfig = mergedObConfig;
172
173  if (isAotMode(arkProjectConfig) || isHarCompiled) {
174    arkProjectConfig.arkObfuscator = initArkGuardConfig(projectConfig.obfuscationOptions?.obfuscationCacheDir, logger, mergedObConfig, isHarCompiled);
175    return;
176  }
177  arkProjectConfig.terserConfig = initTerserConfig(projectConfig, logger, mergedObConfig, isHarCompiled);
178}
179
180function initTerserConfig(projectConfig: any, logger: any, mergedObConfig: MergedConfig, isHarCompiled: boolean): any {
181  const isCompact = projectConfig.obfuscationOptions ? mergedObConfig.options.compact : isHarCompiled;
182  const minifyOptions = {
183    format: {
184      beautify: !isCompact,
185      indent_level: 2
186    },
187    compress: {
188      join_vars: false,
189      sequences: 0,
190      directives: false,
191      drop_console: mergedObConfig.options.removeLog
192    },
193    mangle: {
194      reserved: mergedObConfig.reservedNames,
195      toplevel: mergedObConfig.options.enableToplevelObfuscation
196    }
197  }
198  const applyNameCache: string | undefined = mergedObConfig.options.applyNameCache;
199  if (applyNameCache &&  applyNameCache.length > 0) {
200    if (fs.existsSync(applyNameCache)) {
201      minifyOptions.nameCache = JSON.parse(fs.readFileSync(applyNameCache, 'utf-8'));
202    } else {
203      logger.error(`ArkTS:ERROR Namecache file ${applyNameCache} does not exist`);
204    }
205  } else {
206    if (projectConfig.obfuscationOptions && projectConfig.obfuscationOptions.obfuscationCacheDir) {
207      const defaultNameCachePath: string = path.join(projectConfig.obfuscationOptions.obfuscationCacheDir,"nameCache.json");
208      if (fs.existsSync(defaultNameCachePath)) {
209        minifyOptions.nameCache = JSON.parse(fs.readFileSync(defaultNameCachePath, 'utf-8'));
210      } else {
211        minifyOptions.nameCache = {};
212      }
213    }
214  }
215
216  if (mergedObConfig.options.enablePropertyObfuscation) {
217    minifyOptions.mangle.properties = {
218      reserved: mergedObConfig.reservedPropertyNames,
219      keep_quoted: !mergedObConfig.options.enableStringPropertyObfuscation
220    };
221  }
222  return minifyOptions;
223}
224
225function initArkGuardConfig(obfuscationCacheDir: string | undefined, logger: any, mergedObConfig: MergedConfig, isHarCompiled: boolean): ArkObfuscator {
226  const arkguardConfig = {
227    mCompact: mergedObConfig.options.compact,
228    mDisableHilog: false,
229    mDisableConsole: mergedObConfig.options.removeLog,
230    mSimplify: false,
231    mRemoveComments: true,
232    mNameObfuscation: {
233      mEnable: true,
234      mNameGeneratorType: 1,
235      mReservedNames: mergedObConfig.reservedNames,
236      mRenameProperties: mergedObConfig.options.enablePropertyObfuscation,
237      mReservedProperties: mergedObConfig.reservedPropertyNames,
238      mKeepStringProperty: !mergedObConfig.options.enableStringPropertyObfuscation,
239      mTopLevel: mergedObConfig.options.enableToplevelObfuscation,
240      mReservedToplevelNames: mergedObConfig.reservedGlobalNames,
241    },
242    mRemoveDeclarationComments: {
243      mEnable: mergedObConfig.options.removeComments,
244      mReservedComments: mergedObConfig.keepComments
245    },
246    mEnableSourceMap: true,
247    mEnableNameCache: true,
248    mRenameFileName: undefined,
249    mExportObfuscation: mergedObConfig.options.enableExportObfuscation
250  }
251
252  if (isHarCompiled) {
253    arkguardConfig.mRenameFileName = {
254      mEnable: mergedObConfig.options.enableFileNameObfuscation,
255      mNameGeneratorType: 1,
256      mReservedFileNames: mergedObConfig.reservedFileNames,
257    }
258  }
259
260  const arkObfuscator: ArkObfuscator = new ArkObfuscator();
261  arkObfuscator.init(arkguardConfig);
262  if (mergedObConfig.options.applyNameCache && mergedObConfig.options.applyNameCache.length > 0) {
263    readNameCache(mergedObConfig.options.applyNameCache, logger);
264  } else {
265    if (obfuscationCacheDir) {
266      const defaultNameCachePath: string = path.join(obfuscationCacheDir,"nameCache.json");
267      if (fs.existsSync(defaultNameCachePath)) {
268        readNameCache(defaultNameCachePath, logger);
269      }
270    }
271  }
272  return arkObfuscator;
273}
274
275export function readProjectAndLibsSource(allFiles: Set<string>, mergedObConfig: MergedConfig, arkObfuscator: ArkObfuscator, isHarCompiled: boolean): void {
276  if (mergedObConfig?.options === undefined || mergedObConfig.options.disableObfuscation || allFiles.size === 0) {
277    return;
278  }
279  const obfOptions = mergedObConfig.options;
280  let projectAndLibs: {projectAndLibsReservedProperties: string[]; libExportNames: string[]};
281  projectAndLibs = readProjectPropertiesByCollectedPaths(allFiles,
282    {
283      mNameObfuscation: {
284        mEnable: true,
285        mReservedProperties: [],
286        mRenameProperties: obfOptions.enablePropertyObfuscation,
287        mKeepStringProperty: !obfOptions.enableStringPropertyObfuscation
288      },
289      mExportObfuscation: obfOptions.enableExportObfuscation
290    }, isHarCompiled);
291  if (obfOptions.enablePropertyObfuscation && projectAndLibs.projectAndLibsReservedProperties) {
292    arkObfuscator.addReservedProperties(projectAndLibs.projectAndLibsReservedProperties);
293  }
294  if (obfOptions.enableExportObfuscation && projectAndLibs.libExportNames) {
295    arkObfuscator.addReservedNames(projectAndLibs.libExportNames);
296  }
297}
298
299function processPlatformInfo(arkConfig: ArkConfig): void {
300  const arkPlatformPath: string = getArkBuildDir(arkConfig.arkRootPath);
301  if (isWindows()) {
302    arkConfig.es2abcPath = path.join(arkPlatformPath, 'bin', 'es2abc.exe');
303    arkConfig.ts2abcPath = path.join(arkPlatformPath, 'src', 'index.js');
304    arkConfig.mergeAbcPath = path.join(arkPlatformPath, 'bin', 'merge_abc.exe');
305    arkConfig.js2abcPath = path.join(arkPlatformPath, 'bin', 'js2abc.exe');
306    arkConfig.aotCompilerPath = path.join(arkPlatformPath, 'bin', 'ark_aot_compiler.exe');
307    return;
308  }
309  if (isLinux() || isMac()) {
310    arkConfig.es2abcPath = path.join(arkPlatformPath, 'bin', 'es2abc');
311    arkConfig.ts2abcPath = path.join(arkPlatformPath, 'src', 'index.js');
312    arkConfig.mergeAbcPath = path.join(arkPlatformPath, 'bin', 'merge_abc');
313    arkConfig.js2abcPath = path.join(arkPlatformPath, 'bin', 'js2abc');
314    arkConfig.aotCompilerPath = path.join(arkPlatformPath, 'bin', 'ark_aot_compiler');
315    return;
316  }
317}
318
319function processCompatibleVersion(projectConfig: Object, arkConfig: ArkConfig): void {
320  const platformPath: string = getArkBuildDir(arkConfig.arkRootPath);
321  if (projectConfig.minPlatformVersion && projectConfig.minPlatformVersion.toString() === '8') {
322    // use ts2abc to compile apps with 'CompatibleSdkVersion' set to 8
323    arkConfig.ts2abcPath = path.join(platformPath, 'legacy_api8', 'src', 'index.js');
324    projectConfig.pandaMode = TS2ABC;
325  }
326}
327
328export const utProcessArkConfig = {
329  processCompatibleVersion,
330  initTerserConfig
331};
332