13af6ab5fSopenharmony_ci/* 23af6ab5fSopenharmony_ci * Copyright (c) 2023-2024 Huawei Device Co., Ltd. 33af6ab5fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 43af6ab5fSopenharmony_ci * you may not use this file except in compliance with the License. 53af6ab5fSopenharmony_ci * You may obtain a copy of the License at 63af6ab5fSopenharmony_ci * 73af6ab5fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 83af6ab5fSopenharmony_ci * 93af6ab5fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 103af6ab5fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 113af6ab5fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 123af6ab5fSopenharmony_ci * See the License for the specific language governing permissions and 133af6ab5fSopenharmony_ci * limitations under the License. 143af6ab5fSopenharmony_ci */ 153af6ab5fSopenharmony_ci 163af6ab5fSopenharmony_ciimport { 173af6ab5fSopenharmony_ci createPrinter, 183af6ab5fSopenharmony_ci createTextWriter, 193af6ab5fSopenharmony_ci transform, 203af6ab5fSopenharmony_ci createObfTextSingleLineWriter, 213af6ab5fSopenharmony_ci} from 'typescript'; 223af6ab5fSopenharmony_ci 233af6ab5fSopenharmony_ciimport type { 243af6ab5fSopenharmony_ci CompilerOptions, 253af6ab5fSopenharmony_ci EmitTextWriter, 263af6ab5fSopenharmony_ci Node, 273af6ab5fSopenharmony_ci Printer, 283af6ab5fSopenharmony_ci PrinterOptions, 293af6ab5fSopenharmony_ci RawSourceMap, 303af6ab5fSopenharmony_ci SourceFile, 313af6ab5fSopenharmony_ci SourceMapGenerator, 323af6ab5fSopenharmony_ci TransformationResult, 333af6ab5fSopenharmony_ci TransformerFactory, 343af6ab5fSopenharmony_ci} from 'typescript'; 353af6ab5fSopenharmony_ci 363af6ab5fSopenharmony_ciimport path from 'path'; 373af6ab5fSopenharmony_ci 383af6ab5fSopenharmony_ciimport { LocalVariableCollections, PropCollections } from './utils/CommonCollections'; 393af6ab5fSopenharmony_ciimport type { IOptions } from './configs/IOptions'; 403af6ab5fSopenharmony_ciimport { FileUtils } from './utils/FileUtils'; 413af6ab5fSopenharmony_ciimport { TransformerManager } from './transformers/TransformerManager'; 423af6ab5fSopenharmony_ciimport { getSourceMapGenerator } from './utils/SourceMapUtil'; 433af6ab5fSopenharmony_ciimport { 443af6ab5fSopenharmony_ci decodeSourcemap, 453af6ab5fSopenharmony_ci ExistingDecodedSourceMap, 463af6ab5fSopenharmony_ci Source, 473af6ab5fSopenharmony_ci SourceMapLink, 483af6ab5fSopenharmony_ci SourceMapSegmentObj, 493af6ab5fSopenharmony_ci mergeSourceMap 503af6ab5fSopenharmony_ci} from './utils/SourceMapMergingUtil'; 513af6ab5fSopenharmony_ciimport { 523af6ab5fSopenharmony_ci deleteLineInfoForNameString, 533af6ab5fSopenharmony_ci getMapFromJson, 543af6ab5fSopenharmony_ci IDENTIFIER_CACHE, 553af6ab5fSopenharmony_ci MEM_METHOD_CACHE 563af6ab5fSopenharmony_ci} from './utils/NameCacheUtil'; 573af6ab5fSopenharmony_ciimport { ListUtil } from './utils/ListUtil'; 583af6ab5fSopenharmony_ciimport { needReadApiInfo, readProjectPropertiesByCollectedPaths } from './common/ApiReader'; 593af6ab5fSopenharmony_ciimport type { ReseverdSetForArkguard } from './common/ApiReader'; 603af6ab5fSopenharmony_ciimport { ApiExtractor } from './common/ApiExtractor'; 613af6ab5fSopenharmony_ciimport esInfo from './configs/preset/es_reserved_properties.json'; 623af6ab5fSopenharmony_ciimport { EventList, TimeSumPrinter, TimeTracker } from './utils/PrinterUtils'; 633af6ab5fSopenharmony_ciimport { Extension, type ProjectInfo, type FilePathObj } from './common/type'; 643af6ab5fSopenharmony_ciexport { FileUtils } from './utils/FileUtils'; 653af6ab5fSopenharmony_ciexport { MemoryUtils } from './utils/MemoryUtils'; 663af6ab5fSopenharmony_ciimport { TypeUtils } from './utils/TypeUtils'; 673af6ab5fSopenharmony_ciimport { handleReservedConfig } from './utils/TransformUtil'; 683af6ab5fSopenharmony_ciimport { UnobfuscationCollections } from './utils/CommonCollections'; 693af6ab5fSopenharmony_ciimport { historyAllUnobfuscatedNamesMap } from './initialization/Initializer'; 703af6ab5fSopenharmony_ciexport { UnobfuscationCollections } from './utils/CommonCollections'; 713af6ab5fSopenharmony_ciexport { separateUniversalReservedItem, containWildcards, wildcardTransformer } from './utils/TransformUtil'; 723af6ab5fSopenharmony_ciexport type { ReservedNameInfo } from './utils/TransformUtil'; 733af6ab5fSopenharmony_ciexport type { ReseverdSetForArkguard } from './common/ApiReader'; 743af6ab5fSopenharmony_ci 753af6ab5fSopenharmony_ciexport { initObfuscationConfig } from './initialization/Initializer'; 763af6ab5fSopenharmony_ciexport { nameCacheMap, unobfuscationNamesObj } from './initialization/CommonObject'; 773af6ab5fSopenharmony_ciexport { 783af6ab5fSopenharmony_ci collectResevedFileNameInIDEConfig, // For running unit test. 793af6ab5fSopenharmony_ci enableObfuscatedFilePathConfig, 803af6ab5fSopenharmony_ci enableObfuscateFileName, 813af6ab5fSopenharmony_ci generateConsumerObConfigFile, 823af6ab5fSopenharmony_ci getRelativeSourcePath, 833af6ab5fSopenharmony_ci handleObfuscatedFilePath, 843af6ab5fSopenharmony_ci handleUniversalPathInObf, 853af6ab5fSopenharmony_ci mangleFilePath, 863af6ab5fSopenharmony_ci MergedConfig, 873af6ab5fSopenharmony_ci ObConfigResolver, 883af6ab5fSopenharmony_ci readNameCache, 893af6ab5fSopenharmony_ci writeObfuscationNameCache, 903af6ab5fSopenharmony_ci writeUnobfuscationContent 913af6ab5fSopenharmony_ci} from './initialization/ConfigResolver'; 923af6ab5fSopenharmony_ciexport { 933af6ab5fSopenharmony_ci collectReservedNameForObf 943af6ab5fSopenharmony_ci} from './utils/NodeUtils'; 953af6ab5fSopenharmony_ci 963af6ab5fSopenharmony_ciexport const renameIdentifierModule = require('./transformers/rename/RenameIdentifierTransformer'); 973af6ab5fSopenharmony_ciexport const renameFileNameModule = require('./transformers/rename/RenameFileNameTransformer'); 983af6ab5fSopenharmony_ci 993af6ab5fSopenharmony_ciexport { getMapFromJson, readProjectPropertiesByCollectedPaths, deleteLineInfoForNameString, ApiExtractor, PropCollections }; 1003af6ab5fSopenharmony_ciexport let orignalFilePathForSearching: string | undefined; 1013af6ab5fSopenharmony_ciexport let cleanFileMangledNames: boolean = false; 1023af6ab5fSopenharmony_ciexport interface PerformancePrinter { 1033af6ab5fSopenharmony_ci filesPrinter?: TimeTracker; 1043af6ab5fSopenharmony_ci singleFilePrinter?: TimeTracker; 1053af6ab5fSopenharmony_ci timeSumPrinter?: TimeSumPrinter; 1063af6ab5fSopenharmony_ci iniPrinter: TimeTracker; 1073af6ab5fSopenharmony_ci} 1083af6ab5fSopenharmony_ciexport let performancePrinter: PerformancePrinter = { 1093af6ab5fSopenharmony_ci iniPrinter: new TimeTracker(), 1103af6ab5fSopenharmony_ci}; 1113af6ab5fSopenharmony_ci 1123af6ab5fSopenharmony_ci// When the module is compiled, call this function to clear global collections. 1133af6ab5fSopenharmony_ciexport function clearGlobalCaches(): void { 1143af6ab5fSopenharmony_ci PropCollections.clearPropsCollections(); 1153af6ab5fSopenharmony_ci UnobfuscationCollections.clear(); 1163af6ab5fSopenharmony_ci LocalVariableCollections.clear(); 1173af6ab5fSopenharmony_ci renameFileNameModule.clearCaches(); 1183af6ab5fSopenharmony_ci} 1193af6ab5fSopenharmony_ci 1203af6ab5fSopenharmony_ciexport type ObfuscationResultType = { 1213af6ab5fSopenharmony_ci content: string; 1223af6ab5fSopenharmony_ci sourceMap?: RawSourceMap; 1233af6ab5fSopenharmony_ci nameCache?: { [k: string]: string | {} }; 1243af6ab5fSopenharmony_ci filePath?: string; 1253af6ab5fSopenharmony_ci unobfuscationNameMap?: Map<string, Set<string>>; 1263af6ab5fSopenharmony_ci}; 1273af6ab5fSopenharmony_ci 1283af6ab5fSopenharmony_ciconst JSON_TEXT_INDENT_LENGTH: number = 2; 1293af6ab5fSopenharmony_ciexport class ArkObfuscator { 1303af6ab5fSopenharmony_ci // Used only for testing 1313af6ab5fSopenharmony_ci protected mWriteOriginalFile: boolean = false; 1323af6ab5fSopenharmony_ci 1333af6ab5fSopenharmony_ci // A text writer of Printer 1343af6ab5fSopenharmony_ci private mTextWriter: EmitTextWriter; 1353af6ab5fSopenharmony_ci 1363af6ab5fSopenharmony_ci // Compiler Options for typescript,use to parse ast 1373af6ab5fSopenharmony_ci private readonly mCompilerOptions: CompilerOptions; 1383af6ab5fSopenharmony_ci 1393af6ab5fSopenharmony_ci // User custom obfuscation profiles. 1403af6ab5fSopenharmony_ci protected mCustomProfiles: IOptions; 1413af6ab5fSopenharmony_ci 1423af6ab5fSopenharmony_ci private mTransformers: TransformerFactory<Node>[]; 1433af6ab5fSopenharmony_ci 1443af6ab5fSopenharmony_ci static mProjectInfo: ProjectInfo | undefined; 1453af6ab5fSopenharmony_ci 1463af6ab5fSopenharmony_ci // If isKeptCurrentFile is true, both identifier and property obfuscation are skipped. 1473af6ab5fSopenharmony_ci static mIsKeptCurrentFile: boolean = false; 1483af6ab5fSopenharmony_ci 1493af6ab5fSopenharmony_ci public constructor() { 1503af6ab5fSopenharmony_ci this.mCompilerOptions = {}; 1513af6ab5fSopenharmony_ci this.mTransformers = []; 1523af6ab5fSopenharmony_ci } 1533af6ab5fSopenharmony_ci 1543af6ab5fSopenharmony_ci public setWriteOriginalFile(flag: boolean): void { 1553af6ab5fSopenharmony_ci this.mWriteOriginalFile = flag; 1563af6ab5fSopenharmony_ci } 1573af6ab5fSopenharmony_ci 1583af6ab5fSopenharmony_ci // Pass the collected whitelists related to property obfuscation to Arkguard. 1593af6ab5fSopenharmony_ci public addReservedSetForPropertyObf(properties: ReseverdSetForArkguard): void { 1603af6ab5fSopenharmony_ci if (properties.structPropertySet && properties.structPropertySet.size > 0) { 1613af6ab5fSopenharmony_ci for (let reservedProperty of properties.structPropertySet) { 1623af6ab5fSopenharmony_ci UnobfuscationCollections.reservedStruct.add(reservedProperty); 1633af6ab5fSopenharmony_ci } 1643af6ab5fSopenharmony_ci } 1653af6ab5fSopenharmony_ci 1663af6ab5fSopenharmony_ci if (properties.stringPropertySet && properties.stringPropertySet.size > 0) { 1673af6ab5fSopenharmony_ci UnobfuscationCollections.reservedStrProp = properties.stringPropertySet; 1683af6ab5fSopenharmony_ci } 1693af6ab5fSopenharmony_ci 1703af6ab5fSopenharmony_ci if (properties.exportNameAndPropSet && properties.exportNameAndPropSet.size > 0) { 1713af6ab5fSopenharmony_ci UnobfuscationCollections.reservedExportNameAndProp = properties.exportNameAndPropSet; 1723af6ab5fSopenharmony_ci } 1733af6ab5fSopenharmony_ci 1743af6ab5fSopenharmony_ci if (properties.enumPropertySet && properties.enumPropertySet.size > 0) { 1753af6ab5fSopenharmony_ci for (let reservedEnum of properties.enumPropertySet) { 1763af6ab5fSopenharmony_ci UnobfuscationCollections.reservedEnum.add(reservedEnum); 1773af6ab5fSopenharmony_ci } 1783af6ab5fSopenharmony_ci } 1793af6ab5fSopenharmony_ci } 1803af6ab5fSopenharmony_ci 1813af6ab5fSopenharmony_ci public addReservedSetForDefaultObf(properties: ReseverdSetForArkguard): void { 1823af6ab5fSopenharmony_ci if (properties.exportNameSet && properties.exportNameSet.size > 0) { 1833af6ab5fSopenharmony_ci UnobfuscationCollections.reservedExportName = properties.exportNameSet; 1843af6ab5fSopenharmony_ci } 1853af6ab5fSopenharmony_ci } 1863af6ab5fSopenharmony_ci 1873af6ab5fSopenharmony_ci public setKeepSourceOfPaths(mKeepSourceOfPaths: Set<string>): void { 1883af6ab5fSopenharmony_ci this.mCustomProfiles.mKeepFileSourceCode.mKeepSourceOfPaths = mKeepSourceOfPaths; 1893af6ab5fSopenharmony_ci } 1903af6ab5fSopenharmony_ci 1913af6ab5fSopenharmony_ci public handleTsHarComments(sourceFile: SourceFile, originalPath: string | undefined): void { 1923af6ab5fSopenharmony_ci if (ArkObfuscator.projectInfo?.useTsHar && (originalPath?.endsWith(Extension.ETS) && !originalPath?.endsWith(Extension.DETS))) { 1933af6ab5fSopenharmony_ci // @ts-ignore 1943af6ab5fSopenharmony_ci sourceFile.writeTsHarComments = true; 1953af6ab5fSopenharmony_ci } 1963af6ab5fSopenharmony_ci } 1973af6ab5fSopenharmony_ci 1983af6ab5fSopenharmony_ci public get customProfiles(): IOptions { 1993af6ab5fSopenharmony_ci return this.mCustomProfiles; 2003af6ab5fSopenharmony_ci } 2013af6ab5fSopenharmony_ci 2023af6ab5fSopenharmony_ci public static get isKeptCurrentFile(): boolean { 2033af6ab5fSopenharmony_ci return ArkObfuscator.mIsKeptCurrentFile; 2043af6ab5fSopenharmony_ci } 2053af6ab5fSopenharmony_ci 2063af6ab5fSopenharmony_ci public static set isKeptCurrentFile(isKeptFile: boolean) { 2073af6ab5fSopenharmony_ci ArkObfuscator.mIsKeptCurrentFile = isKeptFile; 2083af6ab5fSopenharmony_ci } 2093af6ab5fSopenharmony_ci 2103af6ab5fSopenharmony_ci public static get projectInfo(): ProjectInfo { 2113af6ab5fSopenharmony_ci return ArkObfuscator.mProjectInfo; 2123af6ab5fSopenharmony_ci } 2133af6ab5fSopenharmony_ci 2143af6ab5fSopenharmony_ci public static set projectInfo(projectInfo: ProjectInfo) { 2153af6ab5fSopenharmony_ci ArkObfuscator.mProjectInfo = projectInfo; 2163af6ab5fSopenharmony_ci } 2173af6ab5fSopenharmony_ci 2183af6ab5fSopenharmony_ci private isCurrentFileInKeepPaths(customProfiles: IOptions, originalFilePath: string): boolean { 2193af6ab5fSopenharmony_ci const keepFileSourceCode = customProfiles.mKeepFileSourceCode; 2203af6ab5fSopenharmony_ci if (keepFileSourceCode === undefined || keepFileSourceCode.mKeepSourceOfPaths.size === 0) { 2213af6ab5fSopenharmony_ci return false; 2223af6ab5fSopenharmony_ci } 2233af6ab5fSopenharmony_ci const keepPaths: Set<string> = keepFileSourceCode.mKeepSourceOfPaths; 2243af6ab5fSopenharmony_ci const originalPath = FileUtils.toUnixPath(originalFilePath); 2253af6ab5fSopenharmony_ci return keepPaths.has(originalPath); 2263af6ab5fSopenharmony_ci } 2273af6ab5fSopenharmony_ci 2283af6ab5fSopenharmony_ci /** 2293af6ab5fSopenharmony_ci * init ArkObfuscator according to user config 2303af6ab5fSopenharmony_ci * should be called after constructor 2313af6ab5fSopenharmony_ci */ 2323af6ab5fSopenharmony_ci public init(config: IOptions | undefined): boolean { 2333af6ab5fSopenharmony_ci if (!config) { 2343af6ab5fSopenharmony_ci console.error('obfuscation config file is not found and no given config.'); 2353af6ab5fSopenharmony_ci return false; 2363af6ab5fSopenharmony_ci } 2373af6ab5fSopenharmony_ci 2383af6ab5fSopenharmony_ci handleReservedConfig(config, 'mRenameFileName', 'mReservedFileNames', 'mUniversalReservedFileNames'); 2393af6ab5fSopenharmony_ci handleReservedConfig(config, 'mRemoveDeclarationComments', 'mReservedComments', 'mUniversalReservedComments', 'mEnable'); 2403af6ab5fSopenharmony_ci this.mCustomProfiles = config; 2413af6ab5fSopenharmony_ci 2423af6ab5fSopenharmony_ci if (this.mCustomProfiles.mCompact) { 2433af6ab5fSopenharmony_ci this.mTextWriter = createObfTextSingleLineWriter(); 2443af6ab5fSopenharmony_ci } else { 2453af6ab5fSopenharmony_ci this.mTextWriter = createTextWriter('\n'); 2463af6ab5fSopenharmony_ci } 2473af6ab5fSopenharmony_ci 2483af6ab5fSopenharmony_ci if (this.mCustomProfiles.mEnableSourceMap) { 2493af6ab5fSopenharmony_ci this.mCompilerOptions.sourceMap = true; 2503af6ab5fSopenharmony_ci } 2513af6ab5fSopenharmony_ci 2523af6ab5fSopenharmony_ci const enableTopLevel: boolean = this.mCustomProfiles.mNameObfuscation?.mTopLevel; 2533af6ab5fSopenharmony_ci const exportObfuscation: boolean = this.mCustomProfiles.mExportObfuscation; 2543af6ab5fSopenharmony_ci const propertyObfuscation: boolean = this.mCustomProfiles.mNameObfuscation?.mRenameProperties; 2553af6ab5fSopenharmony_ci /** 2563af6ab5fSopenharmony_ci * clean mangledNames in case skip name check when generating names 2573af6ab5fSopenharmony_ci */ 2583af6ab5fSopenharmony_ci cleanFileMangledNames = enableTopLevel && !exportObfuscation && !propertyObfuscation; 2593af6ab5fSopenharmony_ci 2603af6ab5fSopenharmony_ci this.initPerformancePrinter(); 2613af6ab5fSopenharmony_ci // load transformers 2623af6ab5fSopenharmony_ci this.mTransformers = new TransformerManager(this.mCustomProfiles).getTransformers(); 2633af6ab5fSopenharmony_ci 2643af6ab5fSopenharmony_ci if (needReadApiInfo(this.mCustomProfiles)) { 2653af6ab5fSopenharmony_ci // if -enable-property-obfuscation or -enable-export-obfuscation, collect language reserved keywords. 2663af6ab5fSopenharmony_ci let languageSet: Set<string> = new Set(); 2673af6ab5fSopenharmony_ci for (const key of Object.keys(esInfo)) { 2683af6ab5fSopenharmony_ci const valueArray = esInfo[key]; 2693af6ab5fSopenharmony_ci valueArray.forEach((element: string) => { 2703af6ab5fSopenharmony_ci languageSet.add(element); 2713af6ab5fSopenharmony_ci }); 2723af6ab5fSopenharmony_ci } 2733af6ab5fSopenharmony_ci UnobfuscationCollections.reservedLangForProperty = languageSet; 2743af6ab5fSopenharmony_ci } 2753af6ab5fSopenharmony_ci 2763af6ab5fSopenharmony_ci return true; 2773af6ab5fSopenharmony_ci } 2783af6ab5fSopenharmony_ci 2793af6ab5fSopenharmony_ci private initPerformancePrinter(): void { 2803af6ab5fSopenharmony_ci if (this.mCustomProfiles.mPerformancePrinter) { 2813af6ab5fSopenharmony_ci const printConfig = this.mCustomProfiles.mPerformancePrinter; 2823af6ab5fSopenharmony_ci const printPath = printConfig.mOutputPath; 2833af6ab5fSopenharmony_ci 2843af6ab5fSopenharmony_ci if (printConfig.mFilesPrinter) { 2853af6ab5fSopenharmony_ci performancePrinter.filesPrinter = performancePrinter.iniPrinter; 2863af6ab5fSopenharmony_ci performancePrinter.filesPrinter.setOutputPath(printPath); 2873af6ab5fSopenharmony_ci } else { 2883af6ab5fSopenharmony_ci performancePrinter.iniPrinter = undefined; 2893af6ab5fSopenharmony_ci } 2903af6ab5fSopenharmony_ci 2913af6ab5fSopenharmony_ci if (printConfig.mSingleFilePrinter) { 2923af6ab5fSopenharmony_ci performancePrinter.singleFilePrinter = new TimeTracker(printPath); 2933af6ab5fSopenharmony_ci } 2943af6ab5fSopenharmony_ci 2953af6ab5fSopenharmony_ci if (printConfig.mSumPrinter) { 2963af6ab5fSopenharmony_ci performancePrinter.timeSumPrinter = new TimeSumPrinter(printPath); 2973af6ab5fSopenharmony_ci } 2983af6ab5fSopenharmony_ci } else { 2993af6ab5fSopenharmony_ci performancePrinter = undefined; 3003af6ab5fSopenharmony_ci } 3013af6ab5fSopenharmony_ci } 3023af6ab5fSopenharmony_ci 3033af6ab5fSopenharmony_ci /** 3043af6ab5fSopenharmony_ci * A Printer to output obfuscated codes. 3053af6ab5fSopenharmony_ci */ 3063af6ab5fSopenharmony_ci public createObfsPrinter(isDeclarationFile: boolean): Printer { 3073af6ab5fSopenharmony_ci // set print options 3083af6ab5fSopenharmony_ci let printerOptions: PrinterOptions = {}; 3093af6ab5fSopenharmony_ci let removeOption = this.mCustomProfiles.mRemoveDeclarationComments; 3103af6ab5fSopenharmony_ci let hasReservedList = removeOption?.mReservedComments?.length || removeOption?.mUniversalReservedComments?.length; 3113af6ab5fSopenharmony_ci let keepDeclarationComments = hasReservedList || !removeOption?.mEnable; 3123af6ab5fSopenharmony_ci 3133af6ab5fSopenharmony_ci if (isDeclarationFile && keepDeclarationComments) { 3143af6ab5fSopenharmony_ci printerOptions.removeComments = false; 3153af6ab5fSopenharmony_ci } 3163af6ab5fSopenharmony_ci if ((!isDeclarationFile && this.mCustomProfiles.mRemoveComments) || (isDeclarationFile && !keepDeclarationComments)) { 3173af6ab5fSopenharmony_ci printerOptions.removeComments = true; 3183af6ab5fSopenharmony_ci } 3193af6ab5fSopenharmony_ci 3203af6ab5fSopenharmony_ci return createPrinter(printerOptions); 3213af6ab5fSopenharmony_ci } 3223af6ab5fSopenharmony_ci 3233af6ab5fSopenharmony_ci protected isObfsIgnoreFile(fileName: string): boolean { 3243af6ab5fSopenharmony_ci let suffix: string = FileUtils.getFileExtension(fileName); 3253af6ab5fSopenharmony_ci 3263af6ab5fSopenharmony_ci return suffix !== 'js' && suffix !== 'ts' && suffix !== 'ets'; 3273af6ab5fSopenharmony_ci } 3283af6ab5fSopenharmony_ci 3293af6ab5fSopenharmony_ci private convertLineBasedOnSourceMap(targetCache: string, sourceMapLink?: SourceMapLink): Map<string, string> { 3303af6ab5fSopenharmony_ci let originalCache: Map<string, string> = renameIdentifierModule.nameCache.get(targetCache); 3313af6ab5fSopenharmony_ci let updatedCache: Map<string, string> = new Map<string, string>(); 3323af6ab5fSopenharmony_ci for (const [key, value] of originalCache) { 3333af6ab5fSopenharmony_ci if (!key.includes(':')) { 3343af6ab5fSopenharmony_ci // No need to save line info for identifier which is not function-like, i.e. key without ':' here. 3353af6ab5fSopenharmony_ci updatedCache[key] = value; 3363af6ab5fSopenharmony_ci continue; 3373af6ab5fSopenharmony_ci } 3383af6ab5fSopenharmony_ci const [scopeName, oldStartLine, oldStartColumn, oldEndLine, oldEndColumn] = key.split(':'); 3393af6ab5fSopenharmony_ci let newKey: string = key; 3403af6ab5fSopenharmony_ci if (!sourceMapLink) { 3413af6ab5fSopenharmony_ci // In Arkguard, we save line info of source code, so do not need to use sourcemap mapping. 3423af6ab5fSopenharmony_ci newKey = `${scopeName}:${oldStartLine}:${oldEndLine}`; 3433af6ab5fSopenharmony_ci updatedCache[newKey] = value; 3443af6ab5fSopenharmony_ci continue; 3453af6ab5fSopenharmony_ci } 3463af6ab5fSopenharmony_ci const startPosition: SourceMapSegmentObj | null = sourceMapLink.traceSegment( 3473af6ab5fSopenharmony_ci // 1: The line number in originalCache starts from 1 while in source map starts from 0. 3483af6ab5fSopenharmony_ci Number(oldStartLine) - 1, Number(oldStartColumn) - 1, ''); // Minus 1 to get the correct original position. 3493af6ab5fSopenharmony_ci if (!startPosition) { 3503af6ab5fSopenharmony_ci // Do not save methods that do not exist in the source code, e.g. 'build' in ArkUI. 3513af6ab5fSopenharmony_ci continue; 3523af6ab5fSopenharmony_ci } 3533af6ab5fSopenharmony_ci const endPosition: SourceMapSegmentObj | null = sourceMapLink.traceSegment( 3543af6ab5fSopenharmony_ci Number(oldEndLine) - 1, Number(oldEndColumn) - 1, ''); // 1: Same as above. 3553af6ab5fSopenharmony_ci if (!endPosition) { 3563af6ab5fSopenharmony_ci // Do not save methods that do not exist in the source code, e.g. 'build' in ArkUI. 3573af6ab5fSopenharmony_ci continue; 3583af6ab5fSopenharmony_ci } 3593af6ab5fSopenharmony_ci const startLine = startPosition.line + 1; // 1: The final line number in updatedCache should starts from 1. 3603af6ab5fSopenharmony_ci const endLine = endPosition.line + 1; // 1: Same as above. 3613af6ab5fSopenharmony_ci newKey = `${scopeName}:${startLine}:${endLine}`; 3623af6ab5fSopenharmony_ci updatedCache[newKey] = value; 3633af6ab5fSopenharmony_ci } 3643af6ab5fSopenharmony_ci return updatedCache; 3653af6ab5fSopenharmony_ci } 3663af6ab5fSopenharmony_ci 3673af6ab5fSopenharmony_ci /** 3683af6ab5fSopenharmony_ci * Obfuscate ast of a file. 3693af6ab5fSopenharmony_ci * @param content ast or source code of a source file 3703af6ab5fSopenharmony_ci * @param sourceFilePathObj 3713af6ab5fSopenharmony_ci * @param previousStageSourceMap 3723af6ab5fSopenharmony_ci * @param historyNameCache 3733af6ab5fSopenharmony_ci * @param originalFilePath When filename obfuscation is enabled, it is used as the source code path. 3743af6ab5fSopenharmony_ci */ 3753af6ab5fSopenharmony_ci public async obfuscate( 3763af6ab5fSopenharmony_ci content: SourceFile | string, 3773af6ab5fSopenharmony_ci sourceFilePathObj: FilePathObj, 3783af6ab5fSopenharmony_ci previousStageSourceMap?: RawSourceMap, 3793af6ab5fSopenharmony_ci historyNameCache?: Map<string, string>, 3803af6ab5fSopenharmony_ci originalFilePath?: string, 3813af6ab5fSopenharmony_ci projectInfo?: ProjectInfo, 3823af6ab5fSopenharmony_ci ): Promise<ObfuscationResultType> { 3833af6ab5fSopenharmony_ci ArkObfuscator.projectInfo = projectInfo; 3843af6ab5fSopenharmony_ci let result: ObfuscationResultType = { content: undefined }; 3853af6ab5fSopenharmony_ci if (this.isObfsIgnoreFile(sourceFilePathObj.buildFilePath)) { 3863af6ab5fSopenharmony_ci // need add return value 3873af6ab5fSopenharmony_ci return result; 3883af6ab5fSopenharmony_ci } 3893af6ab5fSopenharmony_ci 3903af6ab5fSopenharmony_ci let ast: SourceFile = this.createAst(content, sourceFilePathObj.buildFilePath); 3913af6ab5fSopenharmony_ci if (ast.statements.length === 0) { 3923af6ab5fSopenharmony_ci return result; 3933af6ab5fSopenharmony_ci } 3943af6ab5fSopenharmony_ci 3953af6ab5fSopenharmony_ci if (historyNameCache && historyNameCache.size > 0 && this.mCustomProfiles.mNameObfuscation) { 3963af6ab5fSopenharmony_ci renameIdentifierModule.historyNameCache = historyNameCache; 3973af6ab5fSopenharmony_ci } 3983af6ab5fSopenharmony_ci 3993af6ab5fSopenharmony_ci if (this.mCustomProfiles.mUnobfuscationOption?.mPrintKeptNames) { 4003af6ab5fSopenharmony_ci let historyUnobfuscatedNames = historyAllUnobfuscatedNamesMap.get(sourceFilePathObj.relativeFilePath); 4013af6ab5fSopenharmony_ci if (historyUnobfuscatedNames) { 4023af6ab5fSopenharmony_ci renameIdentifierModule.historyUnobfuscatedNamesMap = new Map(Object.entries(historyUnobfuscatedNames)); 4033af6ab5fSopenharmony_ci } 4043af6ab5fSopenharmony_ci } 4053af6ab5fSopenharmony_ci 4063af6ab5fSopenharmony_ci originalFilePath = originalFilePath ?? ast.fileName; 4073af6ab5fSopenharmony_ci if (this.mCustomProfiles.mRenameFileName?.mEnable) { 4083af6ab5fSopenharmony_ci orignalFilePathForSearching = originalFilePath; 4093af6ab5fSopenharmony_ci } 4103af6ab5fSopenharmony_ci ArkObfuscator.isKeptCurrentFile = this.isCurrentFileInKeepPaths(this.mCustomProfiles, originalFilePath); 4113af6ab5fSopenharmony_ci 4123af6ab5fSopenharmony_ci this.handleDeclarationFile(ast); 4133af6ab5fSopenharmony_ci 4143af6ab5fSopenharmony_ci ast = this.obfuscateAst(ast); 4153af6ab5fSopenharmony_ci 4163af6ab5fSopenharmony_ci this.writeObfuscationResult(ast, sourceFilePathObj.buildFilePath, result, previousStageSourceMap, originalFilePath); 4173af6ab5fSopenharmony_ci 4183af6ab5fSopenharmony_ci this.clearCaches(); 4193af6ab5fSopenharmony_ci return result; 4203af6ab5fSopenharmony_ci } 4213af6ab5fSopenharmony_ci 4223af6ab5fSopenharmony_ci private createAst(content: SourceFile | string, sourceFilePath: string): SourceFile { 4233af6ab5fSopenharmony_ci performancePrinter?.singleFilePrinter?.startEvent(EventList.CREATE_AST, performancePrinter.timeSumPrinter, sourceFilePath); 4243af6ab5fSopenharmony_ci let ast: SourceFile; 4253af6ab5fSopenharmony_ci if (typeof content === 'string') { 4263af6ab5fSopenharmony_ci ast = TypeUtils.createObfSourceFile(sourceFilePath, content); 4273af6ab5fSopenharmony_ci } else { 4283af6ab5fSopenharmony_ci ast = content; 4293af6ab5fSopenharmony_ci } 4303af6ab5fSopenharmony_ci performancePrinter?.singleFilePrinter?.endEvent(EventList.CREATE_AST, performancePrinter.timeSumPrinter); 4313af6ab5fSopenharmony_ci 4323af6ab5fSopenharmony_ci return ast; 4333af6ab5fSopenharmony_ci } 4343af6ab5fSopenharmony_ci 4353af6ab5fSopenharmony_ci private obfuscateAst(ast: SourceFile): SourceFile { 4363af6ab5fSopenharmony_ci performancePrinter?.singleFilePrinter?.startEvent(EventList.OBFUSCATE_AST, performancePrinter.timeSumPrinter); 4373af6ab5fSopenharmony_ci let transformedResult: TransformationResult<Node> = transform(ast, this.mTransformers, this.mCompilerOptions); 4383af6ab5fSopenharmony_ci performancePrinter?.singleFilePrinter?.endEvent(EventList.OBFUSCATE_AST, performancePrinter.timeSumPrinter); 4393af6ab5fSopenharmony_ci ast = transformedResult.transformed[0] as SourceFile; 4403af6ab5fSopenharmony_ci return ast; 4413af6ab5fSopenharmony_ci } 4423af6ab5fSopenharmony_ci 4433af6ab5fSopenharmony_ci private handleDeclarationFile(ast: SourceFile): void { 4443af6ab5fSopenharmony_ci if (ast.isDeclarationFile) { 4453af6ab5fSopenharmony_ci if (!this.mCustomProfiles.mRemoveDeclarationComments || !this.mCustomProfiles.mRemoveDeclarationComments.mEnable) { 4463af6ab5fSopenharmony_ci //@ts-ignore 4473af6ab5fSopenharmony_ci ast.reservedComments = undefined; 4483af6ab5fSopenharmony_ci //@ts-ignore 4493af6ab5fSopenharmony_ci ast.universalReservedComments = undefined; 4503af6ab5fSopenharmony_ci } else { 4513af6ab5fSopenharmony_ci //@ts-ignore 4523af6ab5fSopenharmony_ci ast.reservedComments ??= this.mCustomProfiles.mRemoveDeclarationComments.mReservedComments ? 4533af6ab5fSopenharmony_ci this.mCustomProfiles.mRemoveDeclarationComments.mReservedComments : []; 4543af6ab5fSopenharmony_ci //@ts-ignore 4553af6ab5fSopenharmony_ci ast.universalReservedComments = this.mCustomProfiles.mRemoveDeclarationComments.mUniversalReservedComments ?? []; 4563af6ab5fSopenharmony_ci } 4573af6ab5fSopenharmony_ci } else { 4583af6ab5fSopenharmony_ci //@ts-ignore 4593af6ab5fSopenharmony_ci ast.reservedComments = this.mCustomProfiles.mRemoveComments ? [] : undefined; 4603af6ab5fSopenharmony_ci //@ts-ignore 4613af6ab5fSopenharmony_ci ast.universalReservedComments = this.mCustomProfiles.mRemoveComments ? [] : undefined; 4623af6ab5fSopenharmony_ci } 4633af6ab5fSopenharmony_ci } 4643af6ab5fSopenharmony_ci 4653af6ab5fSopenharmony_ci /** 4663af6ab5fSopenharmony_ci * write obfuscated code, sourcemap and namecache 4673af6ab5fSopenharmony_ci */ 4683af6ab5fSopenharmony_ci private writeObfuscationResult(ast: SourceFile, sourceFilePath: string, result: ObfuscationResultType, 4693af6ab5fSopenharmony_ci previousStageSourceMap?: RawSourceMap, originalFilePath?: string): void { 4703af6ab5fSopenharmony_ci // convert ast to output source file and generate sourcemap if needed. 4713af6ab5fSopenharmony_ci let sourceMapGenerator: SourceMapGenerator = undefined; 4723af6ab5fSopenharmony_ci if (this.mCustomProfiles.mEnableSourceMap) { 4733af6ab5fSopenharmony_ci sourceMapGenerator = getSourceMapGenerator(sourceFilePath); 4743af6ab5fSopenharmony_ci } 4753af6ab5fSopenharmony_ci 4763af6ab5fSopenharmony_ci if (sourceFilePath.endsWith('.js')) { 4773af6ab5fSopenharmony_ci TypeUtils.tsToJs(ast); 4783af6ab5fSopenharmony_ci } 4793af6ab5fSopenharmony_ci this.handleTsHarComments(ast, originalFilePath); 4803af6ab5fSopenharmony_ci performancePrinter?.singleFilePrinter?.startEvent(EventList.CREATE_PRINTER, performancePrinter.timeSumPrinter); 4813af6ab5fSopenharmony_ci this.createObfsPrinter(ast.isDeclarationFile).writeFile(ast, this.mTextWriter, sourceMapGenerator); 4823af6ab5fSopenharmony_ci performancePrinter?.singleFilePrinter?.endEvent(EventList.CREATE_PRINTER, performancePrinter.timeSumPrinter); 4833af6ab5fSopenharmony_ci 4843af6ab5fSopenharmony_ci result.filePath = ast.fileName; 4853af6ab5fSopenharmony_ci result.content = this.mTextWriter.getText(); 4863af6ab5fSopenharmony_ci 4873af6ab5fSopenharmony_ci if (this.mCustomProfiles.mUnobfuscationOption?.mPrintKeptNames) { 4883af6ab5fSopenharmony_ci this.handleUnobfuscationNames(result); 4893af6ab5fSopenharmony_ci } 4903af6ab5fSopenharmony_ci 4913af6ab5fSopenharmony_ci if (this.mCustomProfiles.mEnableSourceMap && sourceMapGenerator) { 4923af6ab5fSopenharmony_ci this.handleSourceMapAndNameCache(sourceMapGenerator, sourceFilePath, result, previousStageSourceMap); 4933af6ab5fSopenharmony_ci } 4943af6ab5fSopenharmony_ci } 4953af6ab5fSopenharmony_ci 4963af6ab5fSopenharmony_ci private handleUnobfuscationNames(result: ObfuscationResultType): void { 4973af6ab5fSopenharmony_ci result.unobfuscationNameMap = new Map(UnobfuscationCollections.unobfuscatedNamesMap); 4983af6ab5fSopenharmony_ci } 4993af6ab5fSopenharmony_ci 5003af6ab5fSopenharmony_ci private handleSourceMapAndNameCache(sourceMapGenerator: SourceMapGenerator, sourceFilePath: string, 5013af6ab5fSopenharmony_ci result: ObfuscationResultType, previousStageSourceMap?: RawSourceMap): void { 5023af6ab5fSopenharmony_ci let sourceMapJson: RawSourceMap = sourceMapGenerator.toJSON(); 5033af6ab5fSopenharmony_ci sourceMapJson.sourceRoot = ''; 5043af6ab5fSopenharmony_ci sourceMapJson.file = path.basename(sourceFilePath); 5053af6ab5fSopenharmony_ci if (previousStageSourceMap) { 5063af6ab5fSopenharmony_ci sourceMapJson = mergeSourceMap(previousStageSourceMap as RawSourceMap, sourceMapJson); 5073af6ab5fSopenharmony_ci } 5083af6ab5fSopenharmony_ci result.sourceMap = sourceMapJson; 5093af6ab5fSopenharmony_ci let nameCache = renameIdentifierModule.nameCache; 5103af6ab5fSopenharmony_ci if (this.mCustomProfiles.mEnableNameCache) { 5113af6ab5fSopenharmony_ci let newIdentifierCache!: Object; 5123af6ab5fSopenharmony_ci let newMemberMethodCache!: Object; 5133af6ab5fSopenharmony_ci if (previousStageSourceMap) { 5143af6ab5fSopenharmony_ci // The process in sdk, need to use sourcemap mapping. 5153af6ab5fSopenharmony_ci // 1: Only one file in the source map; 0: The first and the only one. 5163af6ab5fSopenharmony_ci const sourceFileName = previousStageSourceMap.sources?.length === 1 ? previousStageSourceMap.sources[0] : ''; 5173af6ab5fSopenharmony_ci const source: Source = new Source(sourceFileName, null); 5183af6ab5fSopenharmony_ci const decodedSourceMap: ExistingDecodedSourceMap = decodeSourcemap(previousStageSourceMap); 5193af6ab5fSopenharmony_ci let sourceMapLink: SourceMapLink = new SourceMapLink(decodedSourceMap, [source]); 5203af6ab5fSopenharmony_ci newIdentifierCache = this.convertLineBasedOnSourceMap(IDENTIFIER_CACHE, sourceMapLink); 5213af6ab5fSopenharmony_ci newMemberMethodCache = this.convertLineBasedOnSourceMap(MEM_METHOD_CACHE, sourceMapLink); 5223af6ab5fSopenharmony_ci } else { 5233af6ab5fSopenharmony_ci // The process in Arkguard. 5243af6ab5fSopenharmony_ci newIdentifierCache = this.convertLineBasedOnSourceMap(IDENTIFIER_CACHE); 5253af6ab5fSopenharmony_ci newMemberMethodCache = this.convertLineBasedOnSourceMap(MEM_METHOD_CACHE); 5263af6ab5fSopenharmony_ci } 5273af6ab5fSopenharmony_ci nameCache.set(IDENTIFIER_CACHE, newIdentifierCache); 5283af6ab5fSopenharmony_ci nameCache.set(MEM_METHOD_CACHE, newMemberMethodCache); 5293af6ab5fSopenharmony_ci result.nameCache = { [IDENTIFIER_CACHE]: newIdentifierCache, [MEM_METHOD_CACHE]: newMemberMethodCache }; 5303af6ab5fSopenharmony_ci } 5313af6ab5fSopenharmony_ci } 5323af6ab5fSopenharmony_ci 5333af6ab5fSopenharmony_ci private clearCaches(): void { 5343af6ab5fSopenharmony_ci // clear cache of text writer 5353af6ab5fSopenharmony_ci this.mTextWriter.clear(); 5363af6ab5fSopenharmony_ci renameIdentifierModule.clearCaches(); 5373af6ab5fSopenharmony_ci if (cleanFileMangledNames) { 5383af6ab5fSopenharmony_ci PropCollections.globalMangledTable.clear(); 5393af6ab5fSopenharmony_ci PropCollections.newlyOccupiedMangledProps.clear(); 5403af6ab5fSopenharmony_ci } 5413af6ab5fSopenharmony_ci UnobfuscationCollections.unobfuscatedNamesMap.clear(); 5423af6ab5fSopenharmony_ci } 5433af6ab5fSopenharmony_ci} 544