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 fs from 'fs'; 17import path from 'path'; 18import JSON5 from 'json5'; 19import { 20 ApiExtractor, 21 renamePropertyModule, 22 getMapFromJson, 23 renameFileNameModule 24} from 'arkguard'; 25import { identifierCaches } from '../../../ark_utils'; 26 27/* ObConfig's properties: 28 * ruleOptions: { 29* enable: boolean 30 * rules: string[] 31 * } 32 * consumerRules: string[] 33 * 34 * ObfuscationConfig's properties: 35 * selfConfig: ObConfig 36 * dependencies: { libraries: ObConfig[], hars: string[] } 37 * sdkApis: string[] 38 * obfuscationCacheDir: string 39 * exportRulePath: string 40 */ 41 42enum OptionType { 43 NONE, 44 KEEP_DTS, 45 KEEP_GLOBAL_NAME, 46 KEEP_PROPERTY_NAME, 47 KEEP_FILE_NAME, 48 KEEP_COMMENTS, 49 DISABLE_OBFUSCATION, 50 ENABLE_PROPERTY_OBFUSCATION, 51 ENABLE_STRING_PROPERTY_OBFUSCATION, 52 ENABLE_TOPLEVEL_OBFUSCATION, 53 ENABLE_FILENAME_OBFUSCATION, 54 ENABLE_EXPORT_OBFUSCATION, 55 COMPACT, 56 REMOVE_LOG, 57 REMOVE_COMMENTS, 58 PRINT_NAMECACHE, 59 APPLY_NAMECACHE, 60} 61 62function isFileExist(filePath: string): boolean { 63 let exist = false; 64 try { 65 fs.accessSync(filePath, fs.constants.F_OK); 66 } catch (err) { 67 exist = !err; 68 } 69 return exist; 70} 71 72function sortAndDeduplicateStringArr(arr: string[]) { 73 if (arr.length == 0) { 74 return arr; 75 } 76 77 arr.sort((a, b) => { 78 return a.localeCompare(b); 79 }); 80 81 let tmpArr: string[] = [arr[0]]; 82 for (let i = 1; i < arr.length; i++) { 83 if (arr[i] != arr[i - 1]) { 84 tmpArr.push(arr[i]); 85 } 86 } 87 return tmpArr; 88} 89 90class ObOptions { 91 disableObfuscation: boolean = false; 92 enablePropertyObfuscation: boolean = false; 93 enableStringPropertyObfuscation: boolean = false; 94 enableToplevelObfuscation: boolean = false; 95 enableFileNameObfuscation: boolean = false; 96 enableExportObfuscation: boolean = false; 97 removeComments: boolean = false; 98 compact: boolean = false; 99 removeLog: boolean = false; 100 printNameCache: string = ''; 101 applyNameCache: string = ''; 102 103 merge(other: ObOptions) { 104 this.disableObfuscation = this.disableObfuscation || other.disableObfuscation; 105 this.enablePropertyObfuscation = this.enablePropertyObfuscation || other.enablePropertyObfuscation; 106 this.enableToplevelObfuscation = this.enableToplevelObfuscation || other.enableToplevelObfuscation; 107 this.enableStringPropertyObfuscation = this.enableStringPropertyObfuscation || other.enableStringPropertyObfuscation; 108 this.removeComments = this.removeComments || other.removeComments; 109 this.compact = this.compact || other.compact; 110 this.removeLog = this.removeLog || other.removeLog; 111 this.enableFileNameObfuscation = this.enableFileNameObfuscation || other.enableFileNameObfuscation; 112 this.enableExportObfuscation = this.enableExportObfuscation || other.enableExportObfuscation; 113 if (other.printNameCache.length > 0) { 114 this.printNameCache = other.printNameCache; 115 } 116 if (other.applyNameCache.length > 0) { 117 this.applyNameCache = other.applyNameCache; 118 } 119 } 120} 121 122export class MergedConfig { 123 options: ObOptions = new ObOptions(); 124 reservedPropertyNames: string[] = []; 125 reservedGlobalNames: string[] = []; 126 reservedNames: string[] = []; 127 reservedFileNames: string[] = []; 128 keepComments: string[] = []; 129 130 merge(other: MergedConfig) { 131 this.options.merge(other.options); 132 this.reservedPropertyNames.push(...other.reservedPropertyNames); 133 this.reservedGlobalNames.push(...other.reservedGlobalNames); 134 this.reservedFileNames.push(...other.reservedFileNames); 135 this.keepComments.push(...other.keepComments); 136 } 137 138 sortAndDeduplicate() { 139 this.reservedPropertyNames = sortAndDeduplicateStringArr( 140 this.reservedPropertyNames 141 ); 142 this.reservedGlobalNames = sortAndDeduplicateStringArr(this.reservedGlobalNames); 143 this.reservedFileNames = sortAndDeduplicateStringArr(this.reservedFileNames); 144 this.keepComments = sortAndDeduplicateStringArr(this.keepComments); 145 } 146 147 serializeMergedConfig(): string { 148 let resultStr: string = ''; 149 const keys = Object.keys(this.options); 150 for (const key of keys) { 151 // skip the export of some switches. 152 if (this.options[key] === true && ObConfigResolver.exportedSwitchMap.has(String(key))) { 153 resultStr += ObConfigResolver.exportedSwitchMap.get(String(key)) + '\n'; 154 } 155 } 156 157 if (this.reservedGlobalNames.length > 0) { 158 resultStr += ObConfigResolver.KEEP_GLOBAL_NAME + '\n'; 159 this.reservedGlobalNames.forEach((item) => { 160 resultStr += item + '\n'; 161 }); 162 } 163 if (this.reservedPropertyNames.length > 0) { 164 resultStr += ObConfigResolver.KEEP_PROPERTY_NAME + '\n'; 165 this.reservedPropertyNames.forEach((item) => { 166 resultStr += item + '\n'; 167 }); 168 } 169 return resultStr; 170 } 171} 172 173 174export class ObConfigResolver { 175 sourceObConfig: any; 176 logger: any; 177 isHarCompiled: boolean | undefined; 178 isTerser: boolean; 179 180 constructor(projectConfig: any, logger: any, isTerser?: boolean) { 181 this.sourceObConfig = projectConfig.obfuscationOptions; 182 this.logger = logger; 183 this.isHarCompiled = projectConfig.compileHar; 184 this.isTerser = isTerser; 185 } 186 187 public resolveObfuscationConfigs(): MergedConfig { 188 let sourceObConfig = this.sourceObConfig; 189 if (!sourceObConfig) { 190 return new MergedConfig(); 191 } 192 let enableObfuscation: boolean = sourceObConfig.selfConfig.ruleOptions.enable; 193 194 let selfConfig: MergedConfig = new MergedConfig(); 195 if (enableObfuscation) { 196 this.getSelfConfigs(selfConfig); 197 enableObfuscation = !selfConfig.options.disableObfuscation; 198 } else { 199 selfConfig.options.disableObfuscation = true; 200 } 201 202 let needConsumerConfigs: boolean = this.isHarCompiled && sourceObConfig.selfConfig.consumerRules && 203 sourceObConfig.selfConfig.consumerRules.length > 0; 204 let needDependencyConfigs: boolean = enableObfuscation || needConsumerConfigs; 205 206 let dependencyConfigs: MergedConfig = new MergedConfig(); 207 const dependencyMaxLength: number = Math.max(sourceObConfig.dependencies.libraries.length, sourceObConfig.dependencies.hars.length) 208 if (needDependencyConfigs && dependencyMaxLength > 0) { 209 dependencyConfigs = new MergedConfig(); 210 this.getDependencyConfigs(sourceObConfig, dependencyConfigs); 211 enableObfuscation = enableObfuscation && !dependencyConfigs.options.disableObfuscation; 212 } 213 const mergedConfigs: MergedConfig = this.getMergedConfigs(selfConfig, dependencyConfigs); 214 215 if (enableObfuscation && mergedConfigs.options.enablePropertyObfuscation) { 216 const systemApiCachePath: string = path.join(sourceObConfig.obfuscationCacheDir, 'systemApiCache.json'); 217 if (isFileExist(systemApiCachePath)) { 218 this.getSystemApiConfigsByCache(selfConfig, systemApiCachePath); 219 } else { 220 this.getSystemApiCache(selfConfig, systemApiCachePath); 221 } 222 } 223 224 if (needConsumerConfigs) { 225 let selfConsumerConfig = new MergedConfig(); 226 this.getSelfConsumerConfig(selfConsumerConfig); 227 this.genConsumerConfigFiles(sourceObConfig, selfConsumerConfig, dependencyConfigs); 228 } 229 230 return mergedConfigs; 231 } 232 233 private getSelfConfigs(selfConfigs: MergedConfig) { 234 if (this.sourceObConfig.selfConfig.ruleOptions.rules) { 235 const configPaths: string[] = this.sourceObConfig.selfConfig.ruleOptions.rules; 236 for (const path of configPaths) { 237 this.getConfigByPath(path, selfConfigs); 238 } 239 } 240 } 241 242 private getConfigByPath(path: string, configs: MergedConfig) { 243 let fileContent = undefined; 244 try { 245 fileContent = fs.readFileSync(path, 'utf-8'); 246 } catch (err) { 247 this.logger.error(`Failed to open ${path}. Error message: ${err}`); 248 throw err; 249 } 250 this.handleConfigContent(fileContent, configs, path); 251 } 252 253 // obfuscation options 254 static readonly KEEP_DTS = '-keep-dts'; 255 static readonly KEEP_GLOBAL_NAME = '-keep-global-name'; 256 static readonly KEEP_PROPERTY_NAME = '-keep-property-name'; 257 static readonly KEPP_FILE_NAME = '-keep-file-name'; 258 static readonly KEEP_COMMENTS = '-keep-comments'; 259 static readonly DISABLE_OBFUSCATION = '-disable-obfuscation'; 260 static readonly ENABLE_PROPERTY_OBFUSCATION = '-enable-property-obfuscation'; 261 static readonly ENABLE_STRING_PROPERTY_OBFUSCATION = '-enable-string-property-obfuscation'; 262 static readonly ENABLE_TOPLEVEL_OBFUSCATION = '-enable-toplevel-obfuscation'; 263 static readonly ENABLE_FILENAME_OBFUSCATION = '-enable-filename-obfuscation'; 264 static readonly ENABLE_EXPORT_OBFUSCATION = '-enable-export-obfuscation'; 265 static readonly REMOVE_COMMENTS = '-remove-comments'; 266 static readonly COMPACT = '-compact'; 267 static readonly REMOVE_LOG = '-remove-log'; 268 static readonly PRINT_NAMECACHE = '-print-namecache'; 269 static readonly APPLY_NAMECACHE = '-apply-namecache'; 270 271 // renameFileName, printNameCache, applyNameCache, removeComments and keepComments won't be reserved in obfuscation.txt file. 272 static exportedSwitchMap: Map<string, string> = new Map([ 273 ['disableObfuscation', ObConfigResolver.KEEP_DTS], 274 ['enablePropertyObfuscation', ObConfigResolver.ENABLE_PROPERTY_OBFUSCATION], 275 ['enableStringPropertyObfuscation', ObConfigResolver.ENABLE_STRING_PROPERTY_OBFUSCATION], 276 ['enableToplevelObfuscation', ObConfigResolver.ENABLE_TOPLEVEL_OBFUSCATION], 277 ['compact', ObConfigResolver.COMPACT], 278 ['removeLog', ObConfigResolver.REMOVE_LOG], 279 ]); 280 281 private getTokenType(token: string): OptionType { 282 switch (token) { 283 case ObConfigResolver.KEEP_DTS: 284 return OptionType.KEEP_DTS; 285 case ObConfigResolver.KEEP_GLOBAL_NAME: 286 return OptionType.KEEP_GLOBAL_NAME; 287 case ObConfigResolver.KEEP_PROPERTY_NAME: 288 return OptionType.KEEP_PROPERTY_NAME; 289 case ObConfigResolver.KEPP_FILE_NAME: 290 return OptionType.KEEP_FILE_NAME; 291 case ObConfigResolver.KEEP_COMMENTS: 292 return OptionType.KEEP_COMMENTS; 293 case ObConfigResolver.DISABLE_OBFUSCATION: 294 return OptionType.DISABLE_OBFUSCATION; 295 case ObConfigResolver.ENABLE_PROPERTY_OBFUSCATION: 296 return OptionType.ENABLE_PROPERTY_OBFUSCATION; 297 case ObConfigResolver.ENABLE_STRING_PROPERTY_OBFUSCATION: 298 return OptionType.ENABLE_STRING_PROPERTY_OBFUSCATION; 299 case ObConfigResolver.ENABLE_TOPLEVEL_OBFUSCATION: 300 return OptionType.ENABLE_TOPLEVEL_OBFUSCATION; 301 case ObConfigResolver.ENABLE_FILENAME_OBFUSCATION: 302 return OptionType.ENABLE_FILENAME_OBFUSCATION; 303 case ObConfigResolver.ENABLE_EXPORT_OBFUSCATION: 304 return OptionType.ENABLE_EXPORT_OBFUSCATION; 305 case ObConfigResolver.REMOVE_COMMENTS: 306 return OptionType.REMOVE_COMMENTS; 307 case ObConfigResolver.COMPACT: 308 return OptionType.COMPACT; 309 case ObConfigResolver.REMOVE_LOG: 310 return OptionType.REMOVE_LOG; 311 case ObConfigResolver.PRINT_NAMECACHE: 312 return OptionType.PRINT_NAMECACHE; 313 case ObConfigResolver.APPLY_NAMECACHE: 314 return OptionType.APPLY_NAMECACHE; 315 default: 316 return OptionType.NONE; 317 } 318 } 319 320 private handleConfigContent(data: string, configs: MergedConfig, configPath: string) { 321 data = this.removeComments(data); 322 const tokens = data.split(/[',', '\t', ' ', '\n', '\r\n']/).filter((item) => { 323 if (item !== '') { 324 return item; 325 } 326 }); 327 328 let type: OptionType = OptionType.NONE; 329 let tokenType: OptionType; 330 let dtsFilePaths: string[] = []; 331 for (let i = 0; i < tokens.length; i++) { 332 const token = tokens[i]; 333 tokenType = this.getTokenType(token); 334 // handle switches cases 335 switch (tokenType) { 336 case OptionType.DISABLE_OBFUSCATION: { 337 configs.options.disableObfuscation = true; 338 continue; 339 } 340 case OptionType.ENABLE_PROPERTY_OBFUSCATION: { 341 configs.options.enablePropertyObfuscation = true; 342 continue; 343 } 344 case OptionType.ENABLE_STRING_PROPERTY_OBFUSCATION: { 345 configs.options.enableStringPropertyObfuscation = true; 346 } 347 case OptionType.ENABLE_TOPLEVEL_OBFUSCATION: { 348 configs.options.enableToplevelObfuscation = true; 349 continue; 350 } 351 case OptionType.REMOVE_COMMENTS: { 352 configs.options.removeComments = true; 353 continue; 354 } 355 case OptionType.ENABLE_FILENAME_OBFUSCATION: { 356 configs.options.enableFileNameObfuscation = true; 357 continue; 358 } 359 case OptionType.ENABLE_EXPORT_OBFUSCATION: { 360 configs.options.enableExportObfuscation = true; 361 continue; 362 } 363 case OptionType.COMPACT: { 364 configs.options.compact = true; 365 continue; 366 } 367 case OptionType.REMOVE_LOG: { 368 configs.options.removeLog = true; 369 continue; 370 } 371 case OptionType.KEEP_DTS: 372 case OptionType.KEEP_GLOBAL_NAME: 373 case OptionType.KEEP_PROPERTY_NAME: 374 case OptionType.KEEP_FILE_NAME: 375 case OptionType.KEEP_COMMENTS: 376 case OptionType.PRINT_NAMECACHE: 377 case OptionType.APPLY_NAMECACHE: 378 type = tokenType; 379 continue; 380 default: { 381 // fall-through 382 } 383 } 384 // handle 'keep' options and 'namecache' options 385 switch (type) { 386 case OptionType.KEEP_DTS: { 387 dtsFilePaths.push(token); 388 continue; 389 } 390 case OptionType.KEEP_GLOBAL_NAME: { 391 configs.reservedGlobalNames.push(token); 392 continue; 393 } 394 case OptionType.KEEP_PROPERTY_NAME: { 395 configs.reservedPropertyNames.push(token); 396 continue; 397 } 398 case OptionType.KEEP_FILE_NAME: { 399 configs.reservedFileNames.push(token); 400 continue; 401 } 402 case OptionType.KEEP_COMMENTS: { 403 configs.keepComments.push(token); 404 continue; 405 } 406 case OptionType.PRINT_NAMECACHE: { 407 configs.options.printNameCache = token; 408 type = OptionType.NONE; 409 continue; 410 } 411 case OptionType.APPLY_NAMECACHE: { 412 configs.options.applyNameCache = token; 413 type = OptionType.NONE; 414 this.determineNameCachePath(token, configPath); 415 continue; 416 } 417 default: 418 continue; 419 } 420 } 421 422 this.resolveDts(dtsFilePaths, configs); 423 } 424 425 // get names in .d.ts files and add them into reserved list 426 private resolveDts(dtsFilePaths: string[], configs: MergedConfig) { 427 ApiExtractor.mPropertySet.clear(); 428 dtsFilePaths.forEach((token) => { 429 ApiExtractor.traverseApiFiles(token, ApiExtractor.ApiType.PROJECT); 430 }); 431 configs.reservedNames = configs.reservedNames.concat( 432 [...ApiExtractor.mPropertySet] 433 ); 434 configs.reservedPropertyNames = configs.reservedPropertyNames.concat( 435 [...ApiExtractor.mPropertySet] 436 ); 437 ApiExtractor.mPropertySet.clear(); 438 } 439 440 // the content from '#' to '\n' are comments 441 private removeComments(data: string) { 442 const commentStart = '#'; 443 const commentEnd = '\n'; 444 let tmpStr = ''; 445 var isInComments = false; 446 for (let i = 0; i < data.length; i++) { 447 if (isInComments) { 448 isInComments = data[i] != commentEnd; 449 } else if (data[i] != commentStart) { 450 tmpStr += data[i]; 451 } else { 452 isInComments = true; 453 } 454 } 455 return tmpStr; 456 } 457 458 /** 459 * systemConfigs includes the API directorys. 460 * component directory and pre_define.js file path needs to be concatenated 461 * @param systemConfigs 462 */ 463 private getSystemApiCache(systemConfigs: MergedConfig, systemApiCachePath: string) { 464 ApiExtractor.mPropertySet.clear(); 465 const sdkApis: string[] = sortAndDeduplicateStringArr(this.sourceObConfig.sdkApis); 466 for (let apiPath of sdkApis) { 467 this.getSdkApiCache(apiPath); 468 const UIPath: string = path.join(apiPath,'../build-tools/ets-loader/lib/pre_define.js'); 469 if (fs.existsSync(UIPath)) { 470 this.getUIApiCache(UIPath); 471 } 472 } 473 const savedNameAndPropertyList: string[] = sortAndDeduplicateStringArr([...ApiExtractor.mPropertySet]) 474 const systemApiContent = { 475 ReservedNames: savedNameAndPropertyList, 476 ReservedPropertyNames: savedNameAndPropertyList, 477 }; 478 systemConfigs.reservedPropertyNames.push(...savedNameAndPropertyList); 479 systemConfigs.reservedNames.push(...savedNameAndPropertyList); 480 if (!fs.existsSync(path.dirname(systemApiCachePath))) { 481 fs.mkdirSync(path.dirname(systemApiCachePath), {recursive: true}); 482 } 483 fs.writeFileSync(systemApiCachePath, JSON.stringify(systemApiContent, null, 2)); 484 ApiExtractor.mPropertySet.clear(); 485 } 486 487 private getSdkApiCache(sdkApiPath: string) { 488 ApiExtractor.traverseApiFiles(sdkApiPath, ApiExtractor.ApiType.API); 489 const componentPath: string = path.join(sdkApiPath,'../component'); 490 if (fs.existsSync(componentPath)) { 491 ApiExtractor.traverseApiFiles(componentPath, ApiExtractor.ApiType.COMPONENT); 492 } 493 } 494 495 private getUIApiCache(uiApiPath: string) { 496 ApiExtractor.extractStringsFromFile(uiApiPath); 497 } 498 499 private getDependencyConfigs(sourceObConfig: any, dependencyConfigs: MergedConfig): void { 500 for (const lib of sourceObConfig.dependencies.libraries || []) { 501 if(lib.consumerRules && lib.consumerRules.length > 0) { 502 for (const path of lib.consumerRules) { 503 const thisLibConfigs = new MergedConfig(); 504 this.getConfigByPath(path, dependencyConfigs); 505 dependencyConfigs.merge(thisLibConfigs); 506 } 507 } 508 } 509 510 if (sourceObConfig.dependencies && sourceObConfig.dependencies.hars && sourceObConfig.dependencies.hars.length > 0) { 511 for (const path of sourceObConfig.dependencies.hars) { 512 const thisHarConfigs = new MergedConfig(); 513 this.getConfigByPath(path, dependencyConfigs); 514 dependencyConfigs.merge(thisHarConfigs); 515 } 516 } 517 } 518 519 private getSystemApiConfigsByCache(systemConfigs: MergedConfig, systemApiCachePath: string) { 520 let systemApiContent: { ReservedPropertyNames?: string[], ReservedNames?: string[] } = JSON.parse(fs.readFileSync(systemApiCachePath, 'utf-8')); 521 if (systemApiContent.ReservedPropertyNames) { 522 systemConfigs.reservedPropertyNames = systemApiContent.ReservedPropertyNames; 523 } 524 if (systemApiContent.ReservedNames) { 525 systemConfigs.reservedNames = systemApiContent.ReservedNames; 526 } 527 } 528 529 private getSelfConsumerConfig(selfConsumerConfig: MergedConfig) { 530 for (const path of this.sourceObConfig.selfConfig.consumerRules) { 531 this.getConfigByPath(path, selfConsumerConfig); 532 } 533 } 534 535 private getMergedConfigs(selfConfigs: MergedConfig, dependencyConfigs: MergedConfig): MergedConfig { 536 if (dependencyConfigs) { 537 selfConfigs.merge(dependencyConfigs); 538 } 539 selfConfigs.sortAndDeduplicate(); 540 return selfConfigs; 541 } 542 543 private genConsumerConfigFiles(sourceObConfig: any, selfConsumerConfig: MergedConfig, dependencyConfigs: MergedConfig) { 544 selfConsumerConfig.merge(dependencyConfigs); 545 selfConsumerConfig.sortAndDeduplicate(); 546 this.writeConsumerConfigFile(selfConsumerConfig, sourceObConfig.exportRulePath); 547 } 548 549 public writeConsumerConfigFile(selfConsumerConfig: MergedConfig, outpath: string) { 550 const configContent: string = selfConsumerConfig.serializeMergedConfig(); 551 fs.writeFileSync(outpath, configContent); 552 } 553 554 private determineNameCachePath(nameCachePath: string, configPath: string): void { 555 if (!fs.existsSync(nameCachePath)) { 556 throw new Error(`The applied namecache file '${nameCachePath}' configured by '${configPath}' does not exist.`); 557 } 558 } 559} 560 561export function readNameCache(nameCachePath: string, logger: any): void { 562 try { 563 const fileContent = fs.readFileSync(nameCachePath, 'utf-8'); 564 const nameCache: { IdentifierCache?: Object, PropertyCache?: Object, FileNameCache?: Object } = JSON.parse(fileContent); 565 if (nameCache.PropertyCache) { 566 renamePropertyModule.historyMangledTable = getMapFromJson(nameCache.PropertyCache); 567 } 568 if (nameCache.FileNameCache) { 569 renameFileNameModule.historyFileNameMangledTable = getMapFromJson(nameCache.FileNameCache); 570 } 571 572 Object.assign(identifierCaches, nameCache.IdentifierCache); 573 } catch (err) { 574 logger.error(`Failed to open ${nameCachePath}. Error message: ${err}`); 575 } 576} 577 578export function getArkguardNameCache(enablePropertyObfuscation: boolean, enableFileNameObfuscation: boolean): string { 579 let writeContent: string = ''; 580 const nameCacheCollection: { IdentifierCache?: Object, PropertyCache?: Object, FileNameCache?: Object } = {}; 581 nameCacheCollection.IdentifierCache = identifierCaches; 582 583 if (enablePropertyObfuscation) { 584 const mergedPropertyNameCache: Map<string, string> = new Map(); 585 fillNameCache(renamePropertyModule.historyMangledTable, mergedPropertyNameCache); 586 fillNameCache(renamePropertyModule.globalMangledTable, mergedPropertyNameCache); 587 nameCacheCollection.PropertyCache = Object.fromEntries(mergedPropertyNameCache); 588 } 589 590 if (enableFileNameObfuscation) { 591 const mergedFileNameCache: Map<string, string> = new Map(); 592 fillNameCache(renameFileNameModule.historyFileNameMangledTable, mergedFileNameCache); 593 fillNameCache(renameFileNameModule.globalFileNameMangledTable, mergedFileNameCache); 594 nameCacheCollection.FileNameCache = Object.fromEntries(mergedFileNameCache); 595 } 596 597 writeContent += JSON.stringify(nameCacheCollection, null, 2); 598 return writeContent; 599} 600 601function fillNameCache(table: Map<string, string>, nameCache: Map<string, string>): void { 602 if (table) { 603 for (const [key, value] of table.entries()) { 604 nameCache.set(key, value); 605 } 606 } 607 return; 608} 609 610export function writeObfuscationNameCache(projectConfig:any, obfuscationCacheDir?: string, printNameCache?: string): void { 611 let writeContent: string = ''; 612 if (projectConfig.arkObfuscator) { 613 writeContent = getArkguardNameCache(projectConfig.obfuscationMergedObConfig.options.enablePropertyObfuscation, 614 projectConfig.obfuscationMergedObConfig.options.enableFileNameObfuscation); 615 } else if (projectConfig.terserConfig) { 616 writeContent = JSON.stringify(projectConfig.terserConfig.nameCache, null, 2); 617 } else { 618 return; 619 } 620 if (obfuscationCacheDir && obfuscationCacheDir.length > 0) { 621 const defaultNameCachePath: string = path.join(obfuscationCacheDir, 'nameCache.json'); 622 if (!fs.existsSync(path.dirname(defaultNameCachePath))) { 623 fs.mkdirSync(path.dirname(defaultNameCachePath), {recursive: true}); 624 } 625 fs.writeFileSync(defaultNameCachePath, writeContent); 626 } 627 if (printNameCache && printNameCache.length > 0) { 628 fs.writeFileSync(printNameCache, writeContent); 629 } 630} 631 632export function generateConsumerObConfigFile(obfuscationOptions: any, logger: any) { 633 const projectConfig = { obfuscationOptions, compileHar: true }; 634 const obConfig: ObConfigResolver = new ObConfigResolver(projectConfig, logger); 635 obConfig.resolveObfuscationConfigs(); 636} 637 638/** 639 * Collect reserved file name configured in oh-package.json5 and module.json5. 640 * @param ohPackagePath The 'main' and 'types' fileds in oh-package.json5 need to be reserved. 641 * @param moduleJsonPath The 'srcEntry' filed in module.json5 needs to be reserved. 642 * @returns reservedFileNames 643 */ 644export function collectResevedFileNameInIDEConfig(ohPackagePath: string, moduleJsonPath: string, projectPath: string, cachePath: string): string[] { 645 const reservedFileNames: string[] = []; 646 if (fs.existsSync(ohPackagePath)) { 647 const ohPackageContent = JSON5.parse(fs.readFileSync(ohPackagePath, 'utf-8')); 648 ohPackageContent.main && reservedFileNames.push(ohPackageContent.main); 649 ohPackageContent.types && reservedFileNames.push(ohPackageContent.types); 650 } 651 652 if (fs.existsSync(moduleJsonPath)) { 653 const moduleJsonContent = JSON5.parse(fs.readFileSync(moduleJsonPath, 'utf-8')); 654 moduleJsonContent.module?.srcEntry && reservedFileNames.push(moduleJsonContent.module?.srcEntry); 655 } 656 657 /* Get the reserved file name 658 * projectPath: /library/src/main/ets 659 * cachePath: /library/build/default/cache/default/default@HarCompileArkTs/esmodules/release 660 * target reserved path: /library/build/default/cache/default/default@HarCompileArkTs/esmodules/release/src/main/ets 661 */ 662 reservedFileNames.push(projectPath); 663 reservedFileNames.push(cachePath); 664 return reservedFileNames; 665} 666 667export function mangleFilePath(originalPath: string): string { 668 const mangledFilePath = renameFileNameModule.getMangleCompletePath(originalPath); 669 return mangledFilePath; 670} 671 672export function resetObfuscation(): void { 673 renamePropertyModule.globalMangledTable?.clear(); 674 renamePropertyModule.historyMangledTable?.clear(); 675 renameFileNameModule.globalFileNameMangledTable?.clear(); 676 renameFileNameModule.historyFileNameMangledTable?.clear(); 677 ApiExtractor.mPropertySet?.clear(); 678}