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 type * as ts from 'typescript'; 19import { 20 ApiExtractor, 21 clearGlobalCaches 22} from 'arkguard'; 23import type { 24 ArkObfuscator, 25} from 'arkguard'; 26 27import { toUnixPath } from '../../../utils'; 28import { allSourceFilePaths, localPackageSet } from '../../../ets_checker'; 29import { isCurrentProjectFiles } from '../utils'; 30import { sourceFileBelongProject } from '../module/module_source_file'; 31 32export { 33 collectResevedFileNameInIDEConfig, // For running unit test. 34 enableObfuscatedFilePathConfig, 35 enableObfuscateFileName, 36 generateConsumerObConfigFile, 37 getRelativeSourcePath, 38 handleObfuscatedFilePath, 39 handleUniversalPathInObf, 40 mangleFilePath, 41 MergedConfig, 42 nameCacheMap, 43 ObConfigResolver, 44 readNameCache, 45 writeObfuscationNameCache 46} from 'arkguard'; 47 48export function resetObfuscation(): void { 49 clearGlobalCaches(); 50 sourceFileBelongProject.clear(); 51 ApiExtractor.mPropertySet?.clear(); 52 ApiExtractor.mSystemExportSet?.clear(); 53 localPackageSet?.clear(); 54} 55 56// Collect all keep files. If the path configured by the developer is a folder, all files in the compilation will be used to match this folder. 57function collectAllKeepFiles(startPaths: string[], excludePathSet: Set<string>): Set<string> { 58 const allKeepFiles: Set<string> = new Set(); 59 const keepFolders: string[] = []; 60 startPaths.forEach(filePath => { 61 if (excludePathSet.has(filePath)) { 62 return; 63 } 64 if (fs.statSync(filePath).isDirectory()) { 65 keepFolders.push(filePath); 66 } else { 67 allKeepFiles.add(filePath); 68 } 69 }); 70 if (keepFolders.length === 0) { 71 return allKeepFiles; 72 } 73 74 allSourceFilePaths.forEach(filePath => { 75 if (keepFolders.some(folderPath => filePath.startsWith(folderPath)) && !excludePathSet.has(filePath)) { 76 allKeepFiles.add(filePath); 77 } 78 }); 79 return allKeepFiles; 80} 81 82// Collect all keep files and then collect their dependency files. 83export function handleKeepFilesAndGetDependencies(resolvedModulesCache: Map<string, ts.ResolvedModuleFull[]>, 84 mergedObConfig: MergedConfig, projectRootPath: string, arkObfuscator: ArkObfuscator, projectConfig: Object): Set<string> { 85 if (mergedObConfig === undefined || mergedObConfig.keepSourceOfPaths.length === 0) { 86 return new Set<string>(); 87 } 88 const keepPaths = mergedObConfig.keepSourceOfPaths; 89 const excludePaths = mergedObConfig.excludePathSet; 90 let allKeepFiles: Set<string> = collectAllKeepFiles(keepPaths, excludePaths); 91 arkObfuscator.setKeepSourceOfPaths(allKeepFiles); 92 const keepFilesAndDependencies: Set<string> = getFileNamesForScanningWhitelist(resolvedModulesCache, mergedObConfig, 93 allKeepFiles, projectRootPath, projectConfig); 94 return keepFilesAndDependencies; 95} 96 97/** 98 * Use tsc's dependency collection to collect the dependency files of the keep files. 99 * Risk: The files resolved by typescript are different from the files resolved by rollup. For example, the two entry files have different priorities. 100 * Tsc looks for files in the types field in oh-packagek.json5 first, and rollup looks for files in the main field. 101 */ 102function getFileNamesForScanningWhitelist( 103 resolvedModulesCache: Map<string, ts.ResolvedModuleFull[]>, 104 mergedObConfig: MergedConfig, 105 allKeepFiles: Set<string>, 106 projectRootPath: string, 107 projectConfig: Object): Set<string> { 108 const keepFilesAndDependencies: Set<string> = new Set<string>(); 109 if (!mergedObConfig.options.enableExportObfuscation) { 110 return keepFilesAndDependencies; 111 } 112 let stack: string[] = Array.from(allKeepFiles); 113 projectRootPath = toUnixPath(projectRootPath); 114 while (stack.length > 0) { 115 const filePath = stack.pop(); 116 if (keepFilesAndDependencies.has(filePath)) { 117 continue; 118 } 119 120 keepFilesAndDependencies.add(filePath); 121 const resolvedModules = resolvedModulesCache.get(path.resolve(filePath)); 122 if (!resolvedModules) { 123 continue; 124 } 125 126 for (const resolvedModule of resolvedModules) { 127 // For `import moduleName form 'xx.so'`, when the xx.so cannot be resolved, resolvedModules is [null] 128 if (!resolvedModule) { 129 continue; 130 } 131 let tempPath = toUnixPath(resolvedModule.resolvedFileName); 132 // resolvedModule can record system API declaration files and ignore them. 133 if (isCurrentProjectFiles(tempPath, projectConfig)) { 134 stack.push(tempPath); 135 } 136 } 137 } 138 return keepFilesAndDependencies; 139}