1/* 2 * Copyright (c) 2024 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'; 19 20import type * as ts from 'typescript'; 21 22import { FileUtils } from '../utils/FileUtils'; 23import { 24 type ReservedNameInfo, 25 ApiExtractor, 26 containWildcards, 27 getMapFromJson, 28 performancePrinter, 29 PropCollections, 30 renameFileNameModule, 31 separateUniversalReservedItem, 32 wildcardTransformer, 33} from '../ArkObfuscator'; 34 35import { isDebug, isFileExist, sortAndDeduplicateStringArr, mergeSet, convertSetToArray } from './utils'; 36import { nameCacheMap, yellow, unobfuscationNamesObj } from './CommonObject'; 37import { historyUnobfuscatedPropMap } from './Initializer'; 38import { LocalVariableCollections, UnobfuscationCollections } from '../utils/CommonCollections'; 39import { INameObfuscationOption } from '../configs/INameObfuscationOption'; 40import { WhitelistType } from '../utils/TransformUtil'; 41 42enum OptionType { 43 NONE, 44 KEEP, 45 KEEP_DTS, 46 KEEP_GLOBAL_NAME, 47 KEEP_PROPERTY_NAME, 48 KEEP_FILE_NAME, 49 KEEP_COMMENTS, 50 DISABLE_OBFUSCATION, 51 ENABLE_PROPERTY_OBFUSCATION, 52 ENABLE_STRING_PROPERTY_OBFUSCATION, 53 ENABLE_TOPLEVEL_OBFUSCATION, 54 ENABLE_FILENAME_OBFUSCATION, 55 ENABLE_EXPORT_OBFUSCATION, 56 COMPACT, 57 REMOVE_LOG, 58 REMOVE_COMMENTS, 59 PRINT_NAMECACHE, 60 PRINT_KEPT_NAMES, 61 APPLY_NAMECACHE, 62} 63export { OptionType as OptionTypeForTest }; 64 65type SystemApiContent = { 66 ReservedPropertyNames?: string[]; 67 ReservedGlobalNames?: string[]; 68 ReservedLocalNames?: string[]; 69}; 70 71/* ObConfig's properties: 72 * ruleOptions: { 73 * enable: boolean 74 * rules: string[] 75 * } 76 * consumerRules: string[] 77 * 78 * ObfuscationConfig's properties: 79 * selfConfig: ObConfig 80 * dependencies: { libraries: ObConfig[], hars: string[] } 81 * sdkApis: string[] 82 * obfuscationCacheDir: string 83 * exportRulePath: string 84 */ 85class ObOptions { 86 disableObfuscation: boolean = false; 87 enablePropertyObfuscation: boolean = false; 88 enableStringPropertyObfuscation: boolean = false; 89 enableToplevelObfuscation: boolean = false; 90 enableFileNameObfuscation: boolean = false; 91 enableExportObfuscation: boolean = false; 92 printKeptNames: boolean = false; 93 removeComments: boolean = false; 94 compact: boolean = false; 95 removeLog: boolean = false; 96 printNameCache: string = ''; 97 printKeptNamesPath: string = ''; 98 applyNameCache: string = ''; 99 100 merge(other: ObOptions): void { 101 this.disableObfuscation = this.disableObfuscation || other.disableObfuscation; 102 this.enablePropertyObfuscation = this.enablePropertyObfuscation || other.enablePropertyObfuscation; 103 this.enableToplevelObfuscation = this.enableToplevelObfuscation || other.enableToplevelObfuscation; 104 this.enableStringPropertyObfuscation = 105 this.enableStringPropertyObfuscation || other.enableStringPropertyObfuscation; 106 this.removeComments = this.removeComments || other.removeComments; 107 this.compact = this.compact || other.compact; 108 this.removeLog = this.removeLog || other.removeLog; 109 this.enableFileNameObfuscation = this.enableFileNameObfuscation || other.enableFileNameObfuscation; 110 this.enableExportObfuscation = this.enableExportObfuscation || other.enableExportObfuscation; 111 if (other.printNameCache.length > 0) { 112 this.printNameCache = other.printNameCache; 113 } 114 if (other.printKeptNamesPath.length > 0) { 115 this.printKeptNamesPath = other.printKeptNamesPath; 116 } 117 if (other.applyNameCache.length > 0) { 118 this.applyNameCache = other.applyNameCache; 119 } 120 } 121} 122export const ObOptionsForTest = ObOptions; 123 124export class MergedConfig { 125 options: ObOptions = new ObOptions(); 126 reservedPropertyNames: string[] = []; 127 reservedGlobalNames: string[] = []; 128 reservedNames: string[] = []; 129 reservedFileNames: string[] = []; 130 keepComments: string[] = []; 131 keepSourceOfPaths: string[] = []; // The file path or folder path configured by the developer. 132 universalReservedPropertyNames: RegExp[] = []; // Support reserved property names contain wildcards. 133 universalReservedGlobalNames: RegExp[] = []; // Support reserved global names contain wildcards. 134 keepUniversalPaths: RegExp[] = []; // Support reserved paths contain wildcards. 135 excludeUniversalPaths: RegExp[] = []; // Support excluded paths contain wildcards. 136 excludePathSet: Set<string> = new Set(); 137 138 merge(other: MergedConfig): void { 139 this.options.merge(other.options); 140 this.reservedPropertyNames.push(...other.reservedPropertyNames); 141 this.reservedGlobalNames.push(...other.reservedGlobalNames); 142 this.reservedFileNames.push(...other.reservedFileNames); 143 this.keepComments.push(...other.keepComments); 144 this.keepSourceOfPaths.push(...other.keepSourceOfPaths); 145 this.keepUniversalPaths.push(...other.keepUniversalPaths); 146 this.excludeUniversalPaths.push(...other.excludeUniversalPaths); 147 other.excludePathSet.forEach((excludePath) => { 148 this.excludePathSet.add(excludePath); 149 }); 150 } 151 152 sortAndDeduplicate(): void { 153 this.reservedPropertyNames = sortAndDeduplicateStringArr(this.reservedPropertyNames); 154 this.reservedGlobalNames = sortAndDeduplicateStringArr(this.reservedGlobalNames); 155 this.reservedFileNames = sortAndDeduplicateStringArr(this.reservedFileNames); 156 this.keepComments = sortAndDeduplicateStringArr(this.keepComments); 157 this.keepSourceOfPaths = sortAndDeduplicateStringArr(this.keepSourceOfPaths); 158 } 159 160 serializeMergedConfig(): string { 161 let resultStr: string = ''; 162 const keys = Object.keys(this.options); 163 for (const key of keys) { 164 // skip the export of some switches. 165 if (this.options[key] === true && ObConfigResolver.exportedSwitchMap.has(String(key))) { 166 resultStr += ObConfigResolver.exportedSwitchMap.get(String(key)) + '\n'; 167 } 168 } 169 170 if (this.reservedGlobalNames.length > 0) { 171 resultStr += ObConfigResolver.KEEP_GLOBAL_NAME + '\n'; 172 this.reservedGlobalNames.forEach((item) => { 173 resultStr += item + '\n'; 174 }); 175 } 176 if (this.reservedPropertyNames.length > 0) { 177 resultStr += ObConfigResolver.KEEP_PROPERTY_NAME + '\n'; 178 this.reservedPropertyNames.forEach((item) => { 179 resultStr += item + '\n'; 180 }); 181 } 182 return resultStr; 183 } 184} 185 186export class ObConfigResolver { 187 sourceObConfig: any; 188 logger: any; 189 isHarCompiled: boolean | undefined; 190 isTerser: boolean; 191 192 constructor(projectConfig: any, logger: any, isTerser?: boolean) { 193 this.sourceObConfig = projectConfig.obfuscationOptions; 194 this.logger = logger; 195 this.isHarCompiled = projectConfig.compileHar; 196 this.isTerser = isTerser; 197 } 198 199 public resolveObfuscationConfigs(): MergedConfig { 200 let sourceObConfig = this.sourceObConfig; 201 if (!sourceObConfig) { 202 return new MergedConfig(); 203 } 204 let enableObfuscation: boolean = sourceObConfig.selfConfig.ruleOptions.enable; 205 206 let selfConfig: MergedConfig = new MergedConfig(); 207 if (enableObfuscation) { 208 this.getSelfConfigs(selfConfig); 209 enableObfuscation = !selfConfig.options.disableObfuscation; 210 } else { 211 selfConfig.options.disableObfuscation = true; 212 } 213 214 let needConsumerConfigs: boolean = 215 this.isHarCompiled && 216 sourceObConfig.selfConfig.consumerRules && 217 sourceObConfig.selfConfig.consumerRules.length > 0; 218 let needDependencyConfigs: boolean = enableObfuscation || needConsumerConfigs; 219 220 let dependencyConfigs: MergedConfig = new MergedConfig(); 221 const dependencyMaxLength: number = Math.max( 222 sourceObConfig.dependencies.libraries.length, 223 sourceObConfig.dependencies.hars.length, 224 ); 225 if (needDependencyConfigs && dependencyMaxLength > 0) { 226 dependencyConfigs = new MergedConfig(); 227 this.getDependencyConfigs(sourceObConfig, dependencyConfigs); 228 enableObfuscation = enableObfuscation && !dependencyConfigs.options.disableObfuscation; 229 } 230 const mergedConfigs: MergedConfig = this.getMergedConfigs(selfConfig, dependencyConfigs); 231 UnobfuscationCollections.printKeptName = mergedConfigs.options.printKeptNames; 232 this.handleReservedArray(mergedConfigs); 233 234 let needKeepSystemApi = 235 enableObfuscation && 236 (mergedConfigs.options.enablePropertyObfuscation || 237 (mergedConfigs.options.enableExportObfuscation && mergedConfigs.options.enableToplevelObfuscation)); 238 239 if (needKeepSystemApi && sourceObConfig.obfuscationCacheDir) { 240 const systemApiCachePath: string = path.join(sourceObConfig.obfuscationCacheDir, 'systemApiCache.json'); 241 if (isFileExist(systemApiCachePath)) { 242 this.getSystemApiConfigsByCache(systemApiCachePath); 243 } else { 244 performancePrinter?.iniPrinter?.startEvent(' Scan system api'); 245 this.getSystemApiCache(mergedConfigs, systemApiCachePath); 246 performancePrinter?.iniPrinter?.endEvent(' Scan system api'); 247 } 248 } 249 250 if (needConsumerConfigs) { 251 let selfConsumerConfig = new MergedConfig(); 252 this.getSelfConsumerConfig(selfConsumerConfig); 253 this.genConsumerConfigFiles(sourceObConfig, selfConsumerConfig, dependencyConfigs); 254 } 255 return mergedConfigs; 256 } 257 258 private getSelfConfigs(selfConfigs: MergedConfig): void { 259 if (this.sourceObConfig.selfConfig.ruleOptions.rules) { 260 const configPaths: string[] = this.sourceObConfig.selfConfig.ruleOptions.rules; 261 for (const path of configPaths) { 262 this.getConfigByPath(path, selfConfigs); 263 } 264 } 265 } 266 267 public getSelfConfigsForTest(selfConfigs: MergedConfig): void { 268 return this.getSelfConfigs(selfConfigs); 269 } 270 271 private getConfigByPath(path: string, configs: MergedConfig): void { 272 let fileContent = undefined; 273 try { 274 fileContent = fs.readFileSync(path, 'utf-8'); 275 } catch (err) { 276 this.logger.error(`Failed to open ${path}. Error message: ${err}`); 277 throw err; 278 } 279 this.handleConfigContent(fileContent, configs, path); 280 } 281 282 public getConfigByPathForTest(path: string, configs: MergedConfig): void { 283 return this.getConfigByPath(path, configs); 284 } 285 286 private handleReservedArray(mergedConfigs: MergedConfig): void { 287 if (mergedConfigs.options.enablePropertyObfuscation && mergedConfigs.reservedPropertyNames) { 288 const propertyReservedInfo: ReservedNameInfo = separateUniversalReservedItem(mergedConfigs.reservedPropertyNames); 289 mergedConfigs.universalReservedPropertyNames = propertyReservedInfo.universalReservedArray; 290 mergedConfigs.reservedPropertyNames = propertyReservedInfo.specificReservedArray; 291 } 292 293 if (mergedConfigs.options.enableToplevelObfuscation && mergedConfigs.reservedGlobalNames) { 294 const globalReservedInfo: ReservedNameInfo = separateUniversalReservedItem(mergedConfigs.reservedGlobalNames); 295 mergedConfigs.universalReservedGlobalNames = globalReservedInfo.universalReservedArray; 296 mergedConfigs.reservedGlobalNames = globalReservedInfo.specificReservedArray; 297 } 298 } 299 300 public handleReservedArrayForTest(mergedConfigs: MergedConfig): void { 301 return this.handleReservedArray(mergedConfigs); 302 } 303 304 // obfuscation options 305 static readonly KEEP = '-keep'; 306 static readonly KEEP_DTS = '-keep-dts'; 307 static readonly KEEP_GLOBAL_NAME = '-keep-global-name'; 308 static readonly KEEP_PROPERTY_NAME = '-keep-property-name'; 309 static readonly KEEP_FILE_NAME = '-keep-file-name'; 310 static readonly KEEP_COMMENTS = '-keep-comments'; 311 static readonly DISABLE_OBFUSCATION = '-disable-obfuscation'; 312 static readonly ENABLE_PROPERTY_OBFUSCATION = '-enable-property-obfuscation'; 313 static readonly ENABLE_STRING_PROPERTY_OBFUSCATION = '-enable-string-property-obfuscation'; 314 static readonly ENABLE_TOPLEVEL_OBFUSCATION = '-enable-toplevel-obfuscation'; 315 static readonly ENABLE_FILENAME_OBFUSCATION = '-enable-filename-obfuscation'; 316 static readonly ENABLE_EXPORT_OBFUSCATION = '-enable-export-obfuscation'; 317 static readonly REMOVE_COMMENTS = '-remove-comments'; 318 static readonly COMPACT = '-compact'; 319 static readonly REMOVE_LOG = '-remove-log'; 320 static readonly PRINT_NAMECACHE = '-print-namecache'; 321 static readonly PRINT_KEPT_NAMES = '-print-kept-names'; 322 static readonly APPLY_NAMECACHE = '-apply-namecache'; 323 324 // renameFileName, printNameCache, applyNameCache, removeComments and keepComments won't be reserved in obfuscation.txt file. 325 static exportedSwitchMap: Map<string, string> = new Map([ 326 ['disableObfuscation', ObConfigResolver.KEEP_DTS], 327 ['enablePropertyObfuscation', ObConfigResolver.ENABLE_PROPERTY_OBFUSCATION], 328 ['enableStringPropertyObfuscation', ObConfigResolver.ENABLE_STRING_PROPERTY_OBFUSCATION], 329 ['enableToplevelObfuscation', ObConfigResolver.ENABLE_TOPLEVEL_OBFUSCATION], 330 ['compact', ObConfigResolver.COMPACT], 331 ['removeLog', ObConfigResolver.REMOVE_LOG], 332 ]); 333 334 private getTokenType(token: string): OptionType { 335 switch (token) { 336 case ObConfigResolver.KEEP_DTS: 337 return OptionType.KEEP_DTS; 338 case ObConfigResolver.KEEP_GLOBAL_NAME: 339 return OptionType.KEEP_GLOBAL_NAME; 340 case ObConfigResolver.KEEP_PROPERTY_NAME: 341 return OptionType.KEEP_PROPERTY_NAME; 342 case ObConfigResolver.KEEP_FILE_NAME: 343 return OptionType.KEEP_FILE_NAME; 344 case ObConfigResolver.KEEP_COMMENTS: 345 return OptionType.KEEP_COMMENTS; 346 case ObConfigResolver.DISABLE_OBFUSCATION: 347 return OptionType.DISABLE_OBFUSCATION; 348 case ObConfigResolver.ENABLE_PROPERTY_OBFUSCATION: 349 return OptionType.ENABLE_PROPERTY_OBFUSCATION; 350 case ObConfigResolver.ENABLE_STRING_PROPERTY_OBFUSCATION: 351 return OptionType.ENABLE_STRING_PROPERTY_OBFUSCATION; 352 case ObConfigResolver.ENABLE_TOPLEVEL_OBFUSCATION: 353 return OptionType.ENABLE_TOPLEVEL_OBFUSCATION; 354 case ObConfigResolver.ENABLE_FILENAME_OBFUSCATION: 355 return OptionType.ENABLE_FILENAME_OBFUSCATION; 356 case ObConfigResolver.ENABLE_EXPORT_OBFUSCATION: 357 return OptionType.ENABLE_EXPORT_OBFUSCATION; 358 case ObConfigResolver.REMOVE_COMMENTS: 359 return OptionType.REMOVE_COMMENTS; 360 case ObConfigResolver.COMPACT: 361 return OptionType.COMPACT; 362 case ObConfigResolver.REMOVE_LOG: 363 return OptionType.REMOVE_LOG; 364 case ObConfigResolver.PRINT_NAMECACHE: 365 return OptionType.PRINT_NAMECACHE; 366 case ObConfigResolver.PRINT_KEPT_NAMES: 367 return OptionType.PRINT_KEPT_NAMES; 368 case ObConfigResolver.APPLY_NAMECACHE: 369 return OptionType.APPLY_NAMECACHE; 370 case ObConfigResolver.KEEP: 371 return OptionType.KEEP; 372 default: 373 return OptionType.NONE; 374 } 375 } 376 377 public getTokenTypeForTest(token: string): OptionType { 378 return this.getTokenType(token); 379 } 380 381 private handleConfigContent(data: string, configs: MergedConfig, configPath: string): void { 382 data = this.removeComments(data); 383 const tokens = data.split(/[',', '\t', ' ', '\n', '\r\n']/).filter((item) => item !== ''); 384 let type: OptionType = OptionType.NONE; 385 let tokenType: OptionType; 386 let dtsFilePaths: string[] = []; 387 let keepConfigs: string[] = []; 388 for (let i = 0; i < tokens.length; i++) { 389 const token = tokens[i]; 390 tokenType = this.getTokenType(token); 391 // handle switches cases 392 switch (tokenType) { 393 case OptionType.DISABLE_OBFUSCATION: { 394 configs.options.disableObfuscation = true; 395 continue; 396 } 397 case OptionType.ENABLE_PROPERTY_OBFUSCATION: { 398 configs.options.enablePropertyObfuscation = true; 399 continue; 400 } 401 case OptionType.ENABLE_STRING_PROPERTY_OBFUSCATION: { 402 configs.options.enableStringPropertyObfuscation = true; 403 continue; 404 } 405 case OptionType.ENABLE_TOPLEVEL_OBFUSCATION: { 406 configs.options.enableToplevelObfuscation = true; 407 continue; 408 } 409 case OptionType.REMOVE_COMMENTS: { 410 configs.options.removeComments = true; 411 continue; 412 } 413 case OptionType.ENABLE_FILENAME_OBFUSCATION: { 414 configs.options.enableFileNameObfuscation = true; 415 continue; 416 } 417 case OptionType.ENABLE_EXPORT_OBFUSCATION: { 418 configs.options.enableExportObfuscation = true; 419 continue; 420 } 421 case OptionType.COMPACT: { 422 configs.options.compact = true; 423 continue; 424 } 425 case OptionType.REMOVE_LOG: { 426 configs.options.removeLog = true; 427 continue; 428 } 429 case OptionType.PRINT_KEPT_NAMES: { 430 configs.options.printKeptNames = true; 431 type = tokenType; 432 continue; 433 } 434 case OptionType.KEEP: 435 case OptionType.KEEP_DTS: 436 case OptionType.KEEP_GLOBAL_NAME: 437 case OptionType.KEEP_PROPERTY_NAME: 438 case OptionType.KEEP_FILE_NAME: 439 case OptionType.KEEP_COMMENTS: 440 case OptionType.PRINT_NAMECACHE: 441 case OptionType.APPLY_NAMECACHE: 442 type = tokenType; 443 continue; 444 default: { 445 // fall-through 446 } 447 } 448 // handle 'keep' options and 'namecache' options 449 switch (type) { 450 case OptionType.KEEP: { 451 keepConfigs.push(token); 452 continue; 453 } 454 case OptionType.KEEP_DTS: { 455 dtsFilePaths.push(token); 456 continue; 457 } 458 case OptionType.KEEP_GLOBAL_NAME: { 459 configs.reservedGlobalNames.push(token); 460 continue; 461 } 462 case OptionType.KEEP_PROPERTY_NAME: { 463 configs.reservedPropertyNames.push(token); 464 continue; 465 } 466 case OptionType.KEEP_FILE_NAME: { 467 configs.reservedFileNames.push(token); 468 continue; 469 } 470 case OptionType.KEEP_COMMENTS: { 471 configs.keepComments.push(token); 472 continue; 473 } 474 case OptionType.PRINT_NAMECACHE: { 475 configs.options.printNameCache = this.resolvePath(configPath, token); 476 type = OptionType.NONE; 477 continue; 478 } 479 case OptionType.PRINT_KEPT_NAMES: { 480 configs.options.printKeptNamesPath = this.resolvePath(configPath, token); 481 type = OptionType.NONE; 482 continue; 483 } 484 case OptionType.APPLY_NAMECACHE: { 485 const absNameCachePath: string = this.resolvePath(configPath, token); 486 this.determineNameCachePath(absNameCachePath, configPath); 487 configs.options.applyNameCache = absNameCachePath; 488 type = OptionType.NONE; 489 continue; 490 } 491 default: 492 continue; 493 } 494 } 495 496 this.resolveDts(dtsFilePaths, configs); 497 this.resolveKeepConfig(keepConfigs, configs, configPath); 498 } 499 500 public handleConfigContentForTest(data: string, configs: MergedConfig, configPath: string): void { 501 return this.handleConfigContent(data, configs, configPath); 502 } 503 // get absolute path 504 private resolvePath(configPath: string, token: string): string { 505 if (path.isAbsolute(token)) { 506 return token; 507 } 508 const configDirectory = path.dirname(configPath); 509 return path.resolve(configDirectory, token); 510 } 511 512 public resolvePathForTest(configPath: string, token: string): string { 513 return this.resolvePath(configPath, token); 514 } 515 516 // get names in .d.ts files and add them into reserved list 517 private resolveDts(dtsFilePaths: string[], configs: MergedConfig): void { 518 ApiExtractor.mPropertySet.clear(); 519 dtsFilePaths.forEach((token) => { 520 ApiExtractor.traverseApiFiles(token, ApiExtractor.ApiType.PROJECT); 521 }); 522 configs.reservedNames = configs.reservedNames.concat([...ApiExtractor.mPropertySet]); 523 configs.reservedPropertyNames = configs.reservedPropertyNames.concat([...ApiExtractor.mPropertySet]); 524 configs.reservedGlobalNames = configs.reservedGlobalNames.concat([...ApiExtractor.mPropertySet]); 525 ApiExtractor.mPropertySet.clear(); 526 } 527 528 public resolveKeepConfig(keepConfigs: string[], configs: MergedConfig, configPath: string): void { 529 for (let keepPath of keepConfigs) { 530 let tempAbsPath: string; 531 const isExclude: boolean = keepPath.startsWith('!'); 532 // 1: remove '!' 533 tempAbsPath = FileUtils.getAbsPathBaseConfigPath(configPath, isExclude ? keepPath.substring(1) : keepPath); 534 535 // contains '*', '?' 536 if (containWildcards(tempAbsPath)) { 537 const regexPattern = wildcardTransformer(tempAbsPath, true); 538 const regexOperator = new RegExp(`^${regexPattern}$`); 539 if (isExclude) { 540 // start with '!' 541 configs.excludeUniversalPaths.push(regexOperator); 542 } else { 543 configs.keepUniversalPaths.push(regexOperator); 544 } 545 continue; 546 } 547 548 if (isExclude) { 549 // exclude specific path 550 configs.excludePathSet.add(tempAbsPath); 551 continue; 552 } 553 554 if (!fs.existsSync(tempAbsPath)) { 555 this.logger.warn(yellow + 'ArkTS: The path of obfuscation \'-keep\' configuration does not exist: ' + keepPath); 556 continue; 557 } 558 tempAbsPath = fs.realpathSync(tempAbsPath); 559 configs.keepSourceOfPaths.push(FileUtils.toUnixPath(tempAbsPath)); 560 } 561 } 562 563 // the content from '#' to '\n' are comments 564 private removeComments(data: string): string { 565 const commentStart = '#'; 566 const commentEnd = '\n'; 567 let tmpStr = ''; 568 let isInComments = false; 569 for (let i = 0; i < data.length; i++) { 570 if (isInComments) { 571 isInComments = data[i] !== commentEnd; 572 } else if (data[i] !== commentStart) { 573 tmpStr += data[i]; 574 } else { 575 isInComments = true; 576 } 577 } 578 return tmpStr; 579 } 580 581 /** 582 * systemConfigs includes the API directorys. 583 * component directory and pre_define.js file path needs to be concatenated 584 * @param systemConfigs 585 */ 586 private getSystemApiCache(systemConfigs: MergedConfig, systemApiCachePath: string): void { 587 ApiExtractor.mPropertySet.clear(); 588 ApiExtractor.mSystemExportSet.clear(); 589 590 interface ArkUIWhitelist { 591 ReservedPropertyNames: string[] 592 } 593 let arkUIWhitelist: ArkUIWhitelist = { ReservedPropertyNames: [] }; 594 const sdkApis: string[] = sortAndDeduplicateStringArr(this.sourceObConfig.sdkApis); 595 for (let apiPath of sdkApis) { 596 this.getSdkApiCache(apiPath); 597 const UIPath: string = path.join(apiPath, '../build-tools/ets-loader/lib/pre_define.js'); 598 if (fs.existsSync(UIPath)) { 599 this.getUIApiCache(UIPath); 600 } 601 const arkUIWhitelistPath: string = path.join(apiPath, '../build-tools/ets-loader/obfuscateWhiteList.json5'); 602 if (fs.existsSync(arkUIWhitelistPath)) { 603 arkUIWhitelist = JSON5.parse(fs.readFileSync(arkUIWhitelistPath, 'utf-8')); 604 } 605 } 606 let systemApiContent: SystemApiContent = {}; 607 608 if (systemConfigs.options.enablePropertyObfuscation) { 609 const savedNameAndPropertySet = new Set([...ApiExtractor.mPropertySet, ...arkUIWhitelist.ReservedPropertyNames]); 610 UnobfuscationCollections.reservedSdkApiForProp = savedNameAndPropertySet; 611 UnobfuscationCollections.reservedSdkApiForLocal = new Set(ApiExtractor.mPropertySet); 612 systemApiContent.ReservedPropertyNames = Array.from(savedNameAndPropertySet); 613 systemApiContent.ReservedLocalNames = Array.from(ApiExtractor.mPropertySet); 614 } 615 if (systemConfigs.options.enableToplevelObfuscation && systemConfigs.options.enableExportObfuscation) { 616 const savedExportNamesSet = new Set(ApiExtractor.mSystemExportSet); 617 UnobfuscationCollections.reservedSdkApiForGlobal = savedExportNamesSet; 618 systemApiContent.ReservedGlobalNames = Array.from(savedExportNamesSet); 619 } 620 621 if (!fs.existsSync(path.dirname(systemApiCachePath))) { 622 fs.mkdirSync(path.dirname(systemApiCachePath), { recursive: true }); 623 } 624 fs.writeFileSync(systemApiCachePath, JSON.stringify(systemApiContent, null, 2)); 625 ApiExtractor.mPropertySet.clear(); 626 ApiExtractor.mSystemExportSet.clear(); 627 } 628 629 public getSystemApiCacheForTest(systemConfigs: MergedConfig, systemApiCachePath: string): void { 630 return this.getSystemApiCache(systemConfigs, systemApiCachePath); 631 } 632 633 private getSdkApiCache(sdkApiPath: string): void { 634 ApiExtractor.traverseApiFiles(sdkApiPath, ApiExtractor.ApiType.API); 635 const componentPath: string = path.join(sdkApiPath, '../component'); 636 if (fs.existsSync(componentPath)) { 637 ApiExtractor.traverseApiFiles(componentPath, ApiExtractor.ApiType.COMPONENT); 638 } 639 } 640 641 private getUIApiCache(uiApiPath: string): void { 642 ApiExtractor.extractStringsFromFile(uiApiPath); 643 } 644 645 private getDependencyConfigs(sourceObConfig: any, dependencyConfigs: MergedConfig): void { 646 for (const lib of sourceObConfig.dependencies.libraries || []) { 647 if (lib.consumerRules && lib.consumerRules.length > 0) { 648 for (const path of lib.consumerRules) { 649 const thisLibConfigs = new MergedConfig(); 650 this.getConfigByPath(path, dependencyConfigs); 651 dependencyConfigs.merge(thisLibConfigs); 652 } 653 } 654 } 655 656 if ( 657 sourceObConfig.dependencies && 658 sourceObConfig.dependencies.hars && 659 sourceObConfig.dependencies.hars.length > 0 660 ) { 661 for (const path of sourceObConfig.dependencies.hars) { 662 const thisHarConfigs = new MergedConfig(); 663 this.getConfigByPath(path, dependencyConfigs); 664 dependencyConfigs.merge(thisHarConfigs); 665 } 666 } 667 } 668 669 public getDependencyConfigsForTest(sourceObConfig: any, dependencyConfigs: MergedConfig): void { 670 return this.getDependencyConfigs(sourceObConfig, dependencyConfigs); 671 } 672 673 private getSystemApiConfigsByCache(systemApiCachePath: string): void { 674 let systemApiContent: { 675 ReservedPropertyNames?: string[]; 676 ReservedGlobalNames?: string[]; 677 ReservedLocalNames?: string[]; 678 } = JSON.parse(fs.readFileSync(systemApiCachePath, 'utf-8')); 679 if (systemApiContent.ReservedPropertyNames) { 680 UnobfuscationCollections.reservedSdkApiForProp = new Set(systemApiContent.ReservedPropertyNames); 681 } 682 if (systemApiContent.ReservedGlobalNames) { 683 UnobfuscationCollections.reservedSdkApiForGlobal = new Set(systemApiContent.ReservedGlobalNames); 684 } 685 if (systemApiContent.ReservedLocalNames) { 686 UnobfuscationCollections.reservedSdkApiForLocal = new Set(systemApiContent.ReservedLocalNames); 687 } 688 } 689 690 public getSystemApiConfigsByCacheForTest(systemApiCachePath: string): void { 691 return this.getSystemApiConfigsByCache(systemApiCachePath); 692 } 693 694 private getSelfConsumerConfig(selfConsumerConfig: MergedConfig): void { 695 for (const path of this.sourceObConfig.selfConfig.consumerRules) { 696 this.getConfigByPath(path, selfConsumerConfig); 697 } 698 } 699 700 public getSelfConsumerConfigForTest(selfConsumerConfig: MergedConfig): void { 701 return this.getSelfConsumerConfig(selfConsumerConfig); 702 } 703 704 private getMergedConfigs(selfConfigs: MergedConfig, dependencyConfigs: MergedConfig): MergedConfig { 705 if (dependencyConfigs) { 706 selfConfigs.merge(dependencyConfigs); 707 } 708 selfConfigs.sortAndDeduplicate(); 709 return selfConfigs; 710 } 711 712 public getMergedConfigsForTest(selfConfigs: MergedConfig, dependencyConfigs: MergedConfig): MergedConfig { 713 return this.getMergedConfigs(selfConfigs, dependencyConfigs); 714 } 715 716 private genConsumerConfigFiles( 717 sourceObConfig: any, 718 selfConsumerConfig: MergedConfig, 719 dependencyConfigs: MergedConfig, 720 ): void { 721 selfConsumerConfig.merge(dependencyConfigs); 722 selfConsumerConfig.sortAndDeduplicate(); 723 this.writeConsumerConfigFile(selfConsumerConfig, sourceObConfig.exportRulePath); 724 } 725 726 public genConsumerConfigFilesForTest( 727 sourceObConfig: any, 728 selfConsumerConfig: MergedConfig, 729 dependencyConfigs: MergedConfig, 730 ): void { 731 return this.genConsumerConfigFiles(sourceObConfig, selfConsumerConfig, dependencyConfigs); 732 } 733 734 public writeConsumerConfigFile(selfConsumerConfig: MergedConfig, outpath: string): void { 735 const configContent: string = selfConsumerConfig.serializeMergedConfig(); 736 fs.writeFileSync(outpath, configContent); 737 } 738 739 private determineNameCachePath(nameCachePath: string, configPath: string): void { 740 if (!fs.existsSync(nameCachePath)) { 741 throw new Error(`The applied namecache file '${nameCachePath}' configured by '${configPath}' does not exist.`); 742 } 743 } 744} 745 746/** 747 * Collect reserved file name configured in oh-package.json5 and module.json5. 748 * @param ohPackagePath The 'main' and 'types' fileds in oh-package.json5 need to be reserved. 749 * @param projectConfig Several paths or file contents in projectconfig need to be reserved. 750 * 1: module.json's 'srcEntry' field 751 * 2: projectPath: /library/src/main/ets 752 * 3: cachePath: /library/build/default/cache/default/default@HarCompileArkTs/esmodules/release 753 * target reserved path: /library/build/default/cache/default/default@HarCompileArkTs/esmodules/release/src/main/ets 754 * 4: aceModuleBuild/etsFortgz directory: /library/build/default/intermediates/loader_out/etsFortgz 755 * If compile the hsp module, the declaration file will be written to the 'aceModuleBuild/etsFortgz' directory. 756 * @param modulePathMap packageName of local har package should be reserved as it is a fixed part of ohmUrl. 757 * example: modulePathMap: { packageName: path } 758 * @returns reservedFileNames 759 */ 760export function collectResevedFileNameInIDEConfig( 761 ohPackagePath: string, 762 projectConfig: any, 763 modulePathMap: Object | undefined, 764 entryArray: Array<string> | undefined, 765): string[] { 766 const reservedFileNames: string[] = []; 767 const moduleJsonPath: string = projectConfig.aceModuleJsonPath; 768 const projectPath: string = projectConfig.projectPath; 769 const cachePath: string = projectConfig.cachePath; 770 771 if (entryArray) { 772 entryArray.forEach((element) => { 773 FileUtils.collectPathReservedString(element, reservedFileNames); 774 }); 775 } 776 777 if (modulePathMap) { 778 const modulePaths = Object.values(modulePathMap); 779 const moduleNames = Object.keys(modulePathMap); 780 modulePaths.forEach((val) => { 781 FileUtils.collectPathReservedString(val, reservedFileNames); 782 }); 783 moduleNames.forEach((val) => { 784 FileUtils.collectPathReservedString(val, reservedFileNames); 785 }); 786 } 787 if (fs.existsSync(ohPackagePath)) { 788 const ohPackageContent = JSON5.parse(fs.readFileSync(ohPackagePath, 'utf-8')); 789 ohPackageContent.main && FileUtils.collectPathReservedString(ohPackageContent.main, reservedFileNames); 790 ohPackageContent.types && FileUtils.collectPathReservedString(ohPackageContent.types, reservedFileNames); 791 } 792 793 if (fs.existsSync(moduleJsonPath)) { 794 const moduleJsonContent = JSON5.parse(fs.readFileSync(moduleJsonPath, 'utf-8')); 795 moduleJsonContent.module?.srcEntry && 796 FileUtils.collectPathReservedString(moduleJsonContent.module?.srcEntry, reservedFileNames); 797 } 798 799 if (projectConfig.compileShared || projectConfig.byteCodeHar) { 800 FileUtils.collectPathReservedString(projectConfig.aceModuleBuild, reservedFileNames); 801 reservedFileNames.push('etsFortgz'); 802 } 803 804 FileUtils.collectPathReservedString(projectPath, reservedFileNames); 805 FileUtils.collectPathReservedString(cachePath, reservedFileNames); 806 return reservedFileNames; 807} 808 809export function readNameCache(nameCachePath: string, logger: any): void { 810 try { 811 const fileContent = fs.readFileSync(nameCachePath, 'utf-8'); 812 const nameCache: { 813 compileSdkVersion?: string; 814 [key: string]: Object; 815 PropertyCache?: Object; 816 FileNameCache?: Object; 817 } = JSON.parse(fileContent); 818 if (nameCache.PropertyCache) { 819 PropCollections.historyMangledTable = getMapFromJson(nameCache.PropertyCache); 820 } 821 if (nameCache.FileNameCache) { 822 renameFileNameModule.historyFileNameMangledTable = getMapFromJson(nameCache.FileNameCache); 823 } 824 825 const { compileSdkVersion, PropertyCache, FileNameCache, ...rest } = nameCache; 826 Object.keys(rest).forEach((key) => { 827 nameCacheMap.set(key, rest[key]); 828 }); 829 } catch (err) { 830 logger.error(`Failed to open ${nameCachePath}. Error message: ${err}`); 831 } 832} 833 834/** 835 * collect the reserved or excluded paths containing wildcards 836 */ 837export function handleUniversalPathInObf(mergedObConfig: MergedConfig, allSourceFilePaths: Set<string>): void { 838 if ( 839 !mergedObConfig || 840 (mergedObConfig.keepUniversalPaths.length === 0 && mergedObConfig.excludeUniversalPaths.length === 0) 841 ) { 842 return; 843 } 844 for (const realFilePath of allSourceFilePaths) { 845 let isReserved = false; 846 for (const universalPath of mergedObConfig.keepUniversalPaths) { 847 if (universalPath.test(realFilePath)) { 848 isReserved = true; 849 break; 850 } 851 } 852 for (const excludePath of mergedObConfig.excludeUniversalPaths) { 853 if (excludePath.test(realFilePath)) { 854 isReserved = false; 855 mergedObConfig.excludePathSet.add(realFilePath); 856 break; 857 } 858 } 859 if (isReserved) { 860 mergedObConfig.keepSourceOfPaths.push(realFilePath); 861 } 862 } 863} 864 865export function getArkguardNameCache( 866 enablePropertyObfuscation: boolean, 867 enableFileNameObfuscation: boolean, 868 enableExportObfuscation: boolean, 869 sdkVersion: string, 870 entryPackageInfo: string, 871): string { 872 let writeContent: string = ''; 873 let nameCacheCollection: { 874 compileSdkVersion?: string; 875 PropertyCache?: Object; 876 FileNameCache?: Object; 877 entryPackageInfo?: string; 878 } = Object.fromEntries(nameCacheMap.entries()); 879 nameCacheCollection.compileSdkVersion = sdkVersion; 880 nameCacheCollection.entryPackageInfo = entryPackageInfo; 881 882 if (enablePropertyObfuscation || enableExportObfuscation) { 883 const mergedPropertyNameCache: Map<string, string> = new Map(); 884 fillNameCache(PropCollections.historyMangledTable, mergedPropertyNameCache); 885 fillNameCache(PropCollections.globalMangledTable, mergedPropertyNameCache); 886 nameCacheCollection.PropertyCache = Object.fromEntries(mergedPropertyNameCache); 887 } 888 889 if (enableFileNameObfuscation) { 890 const mergedFileNameCache: Map<string, string> = new Map(); 891 fillNameCache(renameFileNameModule.historyFileNameMangledTable, mergedFileNameCache); 892 fillNameCache(renameFileNameModule.globalFileNameMangledTable, mergedFileNameCache); 893 nameCacheCollection.FileNameCache = Object.fromEntries(mergedFileNameCache); 894 } 895 896 writeContent += JSON.stringify(nameCacheCollection, null, 2); 897 return writeContent; 898} 899 900// export fillNameCache function 901export function fillNameCache(table: Map<string, string>, nameCache: Map<string, string>): void { 902 if (table) { 903 for (const [key, value] of table.entries()) { 904 nameCache.set(key, value); 905 } 906 } 907 return; 908} 909 910export function writeObfuscationNameCache( 911 projectConfig: any, 912 entryPackageInfo: string, 913 obfuscationCacheDir?: string, 914 printNameCache?: string, 915): void { 916 if (!projectConfig.arkObfuscator) { 917 return; 918 } 919 let options = projectConfig.obfuscationMergedObConfig.options; 920 let writeContent = getArkguardNameCache( 921 options.enablePropertyObfuscation, 922 options.enableFileNameObfuscation, 923 options.enableExportObfuscation, 924 projectConfig.etsLoaderVersion, 925 entryPackageInfo, 926 ); 927 if (obfuscationCacheDir && obfuscationCacheDir.length > 0) { 928 const defaultNameCachePath: string = path.join(obfuscationCacheDir, 'nameCache.json'); 929 if (!fs.existsSync(path.dirname(defaultNameCachePath))) { 930 fs.mkdirSync(path.dirname(defaultNameCachePath), { recursive: true }); 931 } 932 fs.writeFileSync(defaultNameCachePath, writeContent); 933 } 934 if (printNameCache && printNameCache.length > 0) { 935 fs.writeFileSync(printNameCache, writeContent); 936 } 937} 938 939// Print unobfuscation names, reasons and whitelist, if -print-kept-names is enabled. 940export function writeUnobfuscationContent(projectConfig: any): void { 941 let obfuscationOptions = projectConfig.obfuscationMergedObConfig.options; 942 let unobfuscationOptions = projectConfig.arkObfuscator.mCustomProfiles.mUnobfuscationOption; 943 let nameOptions = projectConfig.arkObfuscator.mCustomProfiles.mNameObfuscation; 944 if (!unobfuscationOptions.mPrintKeptNames) { 945 return; 946 } 947 948 let configPath = unobfuscationOptions.mPrintPath; 949 let printDir = projectConfig.obfuscationOptions.obfuscationCacheDir; 950 let printUnobfPath = path.join(printDir, 'keptNames.json'); 951 printUnobfuscationReasons(configPath, printUnobfPath); 952 let printWhitelistPath = path.join(printDir, 'whitelist.json'); 953 printWhitelist(obfuscationOptions, nameOptions, printWhitelistPath); 954} 955 956// Merge similar whitelists and output according to whether the corresponding options are enabled. 957export function printWhitelist(obfuscationOptions: ObOptions, nameOptions: INameObfuscationOption, defaultPath: string): void { 958 const enableToplevel = obfuscationOptions.enableToplevelObfuscation; 959 const enableProperty = obfuscationOptions.enablePropertyObfuscation; 960 const enableStringProp = obfuscationOptions.enableStringPropertyObfuscation; 961 const enableExport = obfuscationOptions.enableExportObfuscation; 962 const reservedConfToplevelArrary = nameOptions.mReservedToplevelNames ?? []; 963 const reservedConfPropertyArray = nameOptions.mReservedProperties ?? []; 964 let whitelistObj = { 965 lang: [], 966 conf: [], 967 struct: [], 968 exported: [], 969 strProp: [], 970 enum: [] 971 }; 972 973 let languareSet: Set<string>; 974 if (enableProperty) { 975 languareSet = mergeSet(UnobfuscationCollections.reservedLangForProperty, LocalVariableCollections.reservedLangForLocal); 976 } else { 977 languareSet = LocalVariableCollections.reservedLangForLocal; 978 } 979 whitelistObj.lang = convertSetToArray(languareSet); 980 981 let structSet: Set<string>; 982 if (enableProperty) { 983 structSet = mergeSet(UnobfuscationCollections.reservedStruct, LocalVariableCollections.reservedStruct); 984 } else { 985 structSet = LocalVariableCollections.reservedStruct; 986 } 987 whitelistObj.struct = convertSetToArray(structSet); 988 989 let exportedSet: Set<string>; 990 if (enableProperty) { 991 exportedSet = UnobfuscationCollections.reservedExportNameAndProp; 992 } else if (enableExport) { 993 exportedSet = UnobfuscationCollections.reservedExportName; 994 } 995 whitelistObj.exported = convertSetToArray(exportedSet); 996 997 let stringSet: Set<string>; 998 if (enableProperty && !enableStringProp) { 999 stringSet = UnobfuscationCollections.reservedStrProp; 1000 } 1001 whitelistObj.strProp = convertSetToArray(stringSet); 1002 1003 whitelistObj.conf = convertSetToArray(LocalVariableCollections.reservedConfig); 1004 const hasPropertyConfig = enableProperty && reservedConfPropertyArray?.length > 0; 1005 const hasTopLevelConfig = enableToplevel && reservedConfToplevelArrary?.length > 0; 1006 if (hasPropertyConfig) { 1007 whitelistObj.conf.push(...reservedConfPropertyArray); 1008 handleUniversalReservedList(nameOptions.mUniversalReservedProperties, whitelistObj.conf); 1009 } 1010 if (hasTopLevelConfig) { 1011 whitelistObj.conf.push(...reservedConfToplevelArrary); 1012 handleUniversalReservedList(nameOptions.mUniversalReservedToplevelNames, whitelistObj.conf); 1013 } 1014 1015 let enumSet: Set<string>; 1016 if (enableProperty) { 1017 enumSet = UnobfuscationCollections.reservedEnum; 1018 } 1019 whitelistObj.enum = convertSetToArray(enumSet); 1020 1021 let whitelistContent = JSON.stringify(whitelistObj, null, 2); // 2: indentation 1022 if (!fs.existsSync(path.dirname(defaultPath))) { 1023 fs.mkdirSync(path.dirname(defaultPath), { recursive: true }); 1024 } 1025 fs.writeFileSync(defaultPath, whitelistContent); 1026} 1027 1028function handleUniversalReservedList(universalList: RegExp[] | undefined, configArray: string[]): void { 1029 if (universalList?.length > 0) { 1030 universalList.forEach((value) => { 1031 const originalString = UnobfuscationCollections.reservedWildcardMap.get(value); 1032 if (originalString) { 1033 configArray.push(originalString); 1034 } 1035 }); 1036 } 1037} 1038 1039// Merge KeptReasons and KeptNames and output 1040export function printUnobfuscationReasons(configPath: string, defaultPath: string): void { 1041 let property: Record<string, string[]> = {}; 1042 let unobfuscationObj = { keptReasons: {}, keptNames: { property } }; 1043 type WhitelistObject = { 1044 [key in WhitelistType]: string; 1045 }; 1046 let keptReasons: WhitelistObject = { 1047 sdk: 'same as the system api names', 1048 lang: 'same as the language keywords', 1049 conf: 'same as the user-configured kept name', 1050 struct: 'same as the ArkUI struct property', 1051 strProp: 'same as the string property', 1052 exported: 'same as the exported names and properties', 1053 enum: 'same as the members in the enum' 1054 }; 1055 unobfuscationObj.keptReasons = keptReasons; 1056 1057 if (!historyUnobfuscatedPropMap) { 1058 // Full build 1059 UnobfuscationCollections.unobfuscatedPropMap.forEach((value: Set<string>, key: string) => { 1060 let array: string[] = Array.from(value); 1061 unobfuscationObj.keptNames.property[key] = array; 1062 }); 1063 } else { 1064 // Incremental build 1065 UnobfuscationCollections.unobfuscatedPropMap.forEach((value: Set<string>, key: string) => { 1066 let array: string[] = Array.from(value); 1067 historyUnobfuscatedPropMap.set(key, array); 1068 }); 1069 historyUnobfuscatedPropMap.forEach((value: string[], key: string) => { 1070 unobfuscationObj.keptNames.property[key] = value; 1071 }); 1072 } 1073 Object.assign(unobfuscationObj.keptNames, unobfuscationNamesObj); 1074 let unobfuscationContent = JSON.stringify(unobfuscationObj, null, 2); 1075 if (!fs.existsSync(path.dirname(defaultPath))) { 1076 fs.mkdirSync(path.dirname(defaultPath), { recursive: true }); 1077 } 1078 fs.writeFileSync(defaultPath, unobfuscationContent); 1079 1080 if (!fs.existsSync(path.dirname(configPath))) { 1081 fs.mkdirSync(path.dirname(configPath), { recursive: true }); 1082 } 1083 if (configPath) { 1084 fs.copyFileSync(defaultPath, configPath); 1085 } 1086} 1087 1088 1089export function generateConsumerObConfigFile(obfuscationOptions: any, logger: any): void { 1090 const projectConfig = { obfuscationOptions, compileHar: true }; 1091 const obConfig: ObConfigResolver = new ObConfigResolver(projectConfig, logger); 1092 obConfig.resolveObfuscationConfigs(); 1093} 1094 1095export function mangleFilePath(originalPath: string): string { 1096 const mangledFilePath = renameFileNameModule.getMangleCompletePath(originalPath); 1097 return mangledFilePath; 1098} 1099 1100export function enableObfuscatedFilePathConfig(isPackageModules: boolean, projectConfig: any): boolean { 1101 const isDebugMode = isDebug(projectConfig); 1102 const hasObfuscationConfig = projectConfig.obfuscationMergedObConfig; 1103 if (isDebugMode || !hasObfuscationConfig) { 1104 return false; 1105 } 1106 const disableObfuscation = hasObfuscationConfig.options.disableObfuscation; 1107 const enableFileNameObfuscation = hasObfuscationConfig.options.enableFileNameObfuscation; 1108 if (disableObfuscation || !enableFileNameObfuscation) { 1109 return false; 1110 } 1111 return true; 1112} 1113 1114export function handleObfuscatedFilePath(filePath: string, isPackageModules: boolean, projectConfig: Object): string { 1115 if (!enableObfuscatedFilePathConfig(isPackageModules, projectConfig)) { 1116 return filePath; 1117 } 1118 // Do not obfuscate the file path in dir oh_modules. 1119 if (!isPackageModules) { 1120 return mangleFilePath(filePath); 1121 } 1122 // When open the config 'enableFileNameObfuscation', keeping all paths in unix format. 1123 return FileUtils.toUnixPath(filePath); 1124} 1125 1126export function enableObfuscateFileName(isPackageModules: boolean, projectConfig: Object): boolean { 1127 if (!enableObfuscatedFilePathConfig(isPackageModules, projectConfig)) { 1128 return false; 1129 } 1130 1131 // Do not obfuscate the file path in dir oh_modules. 1132 if (!isPackageModules) { 1133 return true; 1134 } 1135 // When open the config 'enableFileNameObfuscation', keeping all paths in unix format. 1136 return false; 1137} 1138 1139/** 1140 * Get the relative path relative to the project based on the file's associated project 1141 */ 1142export function getRelativeSourcePath( 1143 filePath: string, 1144 projectRootPath: string, 1145 belongProjectPath: string | undefined, 1146): string { 1147 filePath = FileUtils.toUnixPath(filePath); 1148 1149 if (projectRootPath) { 1150 projectRootPath = FileUtils.toUnixPath(projectRootPath); 1151 } 1152 1153 if (belongProjectPath) { 1154 belongProjectPath = FileUtils.toUnixPath(belongProjectPath); 1155 } 1156 1157 let relativeFilePath: string = filePath; 1158 if (projectRootPath && filePath.startsWith(projectRootPath)) { 1159 relativeFilePath = filePath.replace(projectRootPath + '/', ''); 1160 } else if (belongProjectPath) { 1161 relativeFilePath = filePath.replace(belongProjectPath + '/', ''); 1162 } 1163 1164 return relativeFilePath; 1165} 1166