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