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