!3119 Support keeping the source code of specific file [ets-loader]

Merge pull request !3119 from zhangchen168/0227-file-white-list
This commit is contained in:
openharmony_ci 2024-03-10 11:16:32 +00:00 committed by Gitee
commit df1cbdbf76
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
4 changed files with 137 additions and 10 deletions

View File

@ -649,7 +649,8 @@ export function resolveTypeReferenceDirectives(typeDirectiveNames: string[] | ts
return resolvedTypeReferenceCache; return resolvedTypeReferenceCache;
} }
const resolvedModulesCache: Map<string, ts.ResolvedModuleFull[]> = new Map(); // resolvedModulesCache records the files and their dependencies of program.
export const resolvedModulesCache: Map<string, ts.ResolvedModuleFull[]> = new Map();
export function resolveModuleNames(moduleNames: string[], containingFile: string): ts.ResolvedModuleFull[] { export function resolveModuleNames(moduleNames: string[], containingFile: string): ts.ResolvedModuleFull[] {
startTimeStatisticsLocation(resolveModuleNamesTime); startTimeStatisticsLocation(resolveModuleNamesTime);

View File

@ -16,14 +16,20 @@
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
import JSON5 from 'json5'; import JSON5 from 'json5';
import * as ts from 'typescript';
import { import {
ArkObfuscator,
ApiExtractor, ApiExtractor,
renamePropertyModule, renamePropertyModule,
getMapFromJson, getMapFromJson,
renameFileNameModule renameFileNameModule,
FileUtils
} from 'arkguard'; } from 'arkguard';
import { nameCacheObj } from '../../../ark_utils'; import { nameCacheObj } from '../../../ark_utils';
import { performancePrinter } from 'arkguard/lib/ArkObfuscator'; import { performancePrinter } from 'arkguard/lib/ArkObfuscator';
import { isWindows, toUnixPath } from '../../../utils';
import { allSourceFilePaths } from '../../../ets_checker';
import { yellow } from './ark_define';
/* ObConfig's properties: /* ObConfig's properties:
* ruleOptions: { * ruleOptions: {
@ -42,6 +48,7 @@ import { performancePrinter } from 'arkguard/lib/ArkObfuscator';
enum OptionType { enum OptionType {
NONE, NONE,
KEEP,
KEEP_DTS, KEEP_DTS,
KEEP_GLOBAL_NAME, KEEP_GLOBAL_NAME,
KEEP_PROPERTY_NAME, KEEP_PROPERTY_NAME,
@ -127,6 +134,7 @@ export class MergedConfig {
reservedNames: string[] = []; reservedNames: string[] = [];
reservedFileNames: string[] = []; reservedFileNames: string[] = [];
keepComments: string[] = []; keepComments: string[] = [];
keepSourceOfPaths: string[] = []; // The file path or folder path configured by the developer.
merge(other: MergedConfig) { merge(other: MergedConfig) {
this.options.merge(other.options); this.options.merge(other.options);
@ -134,6 +142,7 @@ export class MergedConfig {
this.reservedGlobalNames.push(...other.reservedGlobalNames); this.reservedGlobalNames.push(...other.reservedGlobalNames);
this.reservedFileNames.push(...other.reservedFileNames); this.reservedFileNames.push(...other.reservedFileNames);
this.keepComments.push(...other.keepComments); this.keepComments.push(...other.keepComments);
this.keepSourceOfPaths.push(...other.keepSourceOfPaths);
} }
sortAndDeduplicate() { sortAndDeduplicate() {
@ -143,6 +152,7 @@ export class MergedConfig {
this.reservedGlobalNames = sortAndDeduplicateStringArr(this.reservedGlobalNames); this.reservedGlobalNames = sortAndDeduplicateStringArr(this.reservedGlobalNames);
this.reservedFileNames = sortAndDeduplicateStringArr(this.reservedFileNames); this.reservedFileNames = sortAndDeduplicateStringArr(this.reservedFileNames);
this.keepComments = sortAndDeduplicateStringArr(this.keepComments); this.keepComments = sortAndDeduplicateStringArr(this.keepComments);
this.keepSourceOfPaths = sortAndDeduplicateStringArr(this.keepSourceOfPaths);
} }
serializeMergedConfig(): string { serializeMergedConfig(): string {
@ -254,6 +264,7 @@ export class ObConfigResolver {
} }
// obfuscation options // obfuscation options
static readonly KEEP = '-keep';
static readonly KEEP_DTS = '-keep-dts'; static readonly KEEP_DTS = '-keep-dts';
static readonly KEEP_GLOBAL_NAME = '-keep-global-name'; static readonly KEEP_GLOBAL_NAME = '-keep-global-name';
static readonly KEEP_PROPERTY_NAME = '-keep-property-name'; static readonly KEEP_PROPERTY_NAME = '-keep-property-name';
@ -315,6 +326,8 @@ export class ObConfigResolver {
return OptionType.PRINT_NAMECACHE; return OptionType.PRINT_NAMECACHE;
case ObConfigResolver.APPLY_NAMECACHE: case ObConfigResolver.APPLY_NAMECACHE:
return OptionType.APPLY_NAMECACHE; return OptionType.APPLY_NAMECACHE;
case ObConfigResolver.KEEP:
return OptionType.KEEP;
default: default:
return OptionType.NONE; return OptionType.NONE;
} }
@ -331,6 +344,7 @@ export class ObConfigResolver {
let type: OptionType = OptionType.NONE; let type: OptionType = OptionType.NONE;
let tokenType: OptionType; let tokenType: OptionType;
let dtsFilePaths: string[] = []; let dtsFilePaths: string[] = [];
let keepConfigs: string[] = [];
for (let i = 0; i < tokens.length; i++) { for (let i = 0; i < tokens.length; i++) {
const token = tokens[i]; const token = tokens[i];
tokenType = this.getTokenType(token); tokenType = this.getTokenType(token);
@ -371,6 +385,7 @@ export class ObConfigResolver {
configs.options.removeLog = true; configs.options.removeLog = true;
continue; continue;
} }
case OptionType.KEEP:
case OptionType.KEEP_DTS: case OptionType.KEEP_DTS:
case OptionType.KEEP_GLOBAL_NAME: case OptionType.KEEP_GLOBAL_NAME:
case OptionType.KEEP_PROPERTY_NAME: case OptionType.KEEP_PROPERTY_NAME:
@ -386,6 +401,10 @@ export class ObConfigResolver {
} }
// handle 'keep' options and 'namecache' options // handle 'keep' options and 'namecache' options
switch (type) { switch (type) {
case OptionType.KEEP: {
keepConfigs.push(token);
continue;
}
case OptionType.KEEP_DTS: { case OptionType.KEEP_DTS: {
dtsFilePaths.push(token); dtsFilePaths.push(token);
continue; continue;
@ -423,6 +442,7 @@ export class ObConfigResolver {
} }
this.resolveDts(dtsFilePaths, configs); this.resolveDts(dtsFilePaths, configs);
this.resolveKeepConfig(keepConfigs, configs, configPath);
} }
// get names in .d.ts files and add them into reserved list // get names in .d.ts files and add them into reserved list
@ -440,6 +460,18 @@ export class ObConfigResolver {
ApiExtractor.mPropertySet.clear(); ApiExtractor.mPropertySet.clear();
} }
private resolveKeepConfig(keepConfigs: string[], configs: MergedConfig, configPath: string): void {
for (let keepPath of keepConfigs) {
let tempAbsPath = FileUtils.getAbsPathBaseConfigPath(configPath, keepPath);
if (!fs.existsSync(tempAbsPath)) {
this.logger.warn(yellow + 'ArkTS: The path of obfuscation \'-keep\' configuration does not exist: ' + keepPath);
continue;
}
tempAbsPath = fs.realpathSync(tempAbsPath);
configs.keepSourceOfPaths.push(toUnixPath(tempAbsPath));
}
}
// the content from '#' to '\n' are comments // the content from '#' to '\n' are comments
private removeComments(data: string) { private removeComments(data: string) {
const commentStart = '#'; const commentStart = '#';
@ -681,4 +713,80 @@ export function resetObfuscation(): void {
renameFileNameModule.globalFileNameMangledTable?.clear(); renameFileNameModule.globalFileNameMangledTable?.clear();
renameFileNameModule.historyFileNameMangledTable?.clear(); renameFileNameModule.historyFileNameMangledTable?.clear();
ApiExtractor.mPropertySet?.clear(); ApiExtractor.mPropertySet?.clear();
} }
// 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.
function collectAllKeepFiles(startPaths: string[]): Set<string> {
const allKeepFiles: Set<string> = new Set();
const keepFolders: string[] = [];
startPaths.forEach(filePath => {
if (fs.statSync(filePath).isDirectory()) {
keepFolders.push(filePath);
} else {
allKeepFiles.add(filePath);
}
});
if (keepFolders.length === 0) {
return allKeepFiles;
}
allSourceFilePaths.forEach(filePath => {
if (keepFolders.some(folderPath => filePath.startsWith(folderPath))) {
allKeepFiles.add(filePath);
}
});
return allKeepFiles;
}
// Collect all keep files and then collect their dependency files.
export function handleKeepFilesAndGetDependencies(resolvedModulesCache: Map<string, ts.ResolvedModuleFull[]>, mergedObConfig: MergedConfig, projectRootPath: string,
arkObfuscator: ArkObfuscator) {
if (mergedObConfig === undefined || mergedObConfig.keepSourceOfPaths.length === 0 ) {
return new Set();
}
const keepPaths = mergedObConfig.keepSourceOfPaths;
let allKeepFiles: Set<string> = collectAllKeepFiles(keepPaths);
arkObfuscator.setKeepSourceOfPaths(allKeepFiles);
const keepFilesAndDependencies: Set<string> = getFileNamesForScanningWhitelist(resolvedModulesCache, mergedObConfig, allKeepFiles, projectRootPath);
return keepFilesAndDependencies;
}
/**
* Use tsc's dependency collection to collect the dependency files of the keep files.
* Risk: The files resolved by typescript are different from the files resolved by rollup. For example, the two entry files have different priorities.
* Tsc looks for files in the types field in oh-packagek.json5 first, and rollup looks for files in the main field.
*/
function getFileNamesForScanningWhitelist(resolvedModulesCache: Map<string, ts.ResolvedModuleFull[]>, mergedObConfig: MergedConfig, allKeepFiles: Set<string>,
projectRootPath: string): Set<string> {
const keepFilesAndDependencies: Set<string> = new Set<string>();
if (!mergedObConfig.options.enableExportObfuscation) {
return keepFilesAndDependencies;
}
let stack: string[] = Array.from(allKeepFiles);
projectRootPath = toUnixPath(projectRootPath);
while (stack.length > 0) {
const filePath = stack.pop();
if (keepFilesAndDependencies.has(filePath)) {
continue;
}
keepFilesAndDependencies.add(filePath);
const resolvedModules = resolvedModulesCache[path.resolve(filePath)];
if (!resolvedModules) {
continue;
}
for (const resolvedModule of resolvedModules) {
// For `import moduleName form 'xx.so'`, when the xx.so cannot be resolved, resolvedModules is [null]
if (!resolvedModule) {
continue;
}
let tempPath = toUnixPath(resolvedModule.resolvedFileName)
// resolvedModule can record system API declaration files and ignore them.
if (tempPath.startsWith(projectRootPath)) {
stack.push(tempPath);
}
}
}
return keepFilesAndDependencies;
}

View File

@ -263,7 +263,11 @@ function initArkGuardConfig(obfuscationCacheDir: string | undefined, logger: any
mEnableNameCache: true, mEnableNameCache: true,
mRenameFileName: undefined, mRenameFileName: undefined,
mExportObfuscation: mergedObConfig.options.enableExportObfuscation, mExportObfuscation: mergedObConfig.options.enableExportObfuscation,
mPerformancePrinter: printerConfig mPerformancePrinter: printerConfig,
mKeepFileSourceCode: {
mKeepSourceOfPaths: new Set(),
mkeepFilesAndDependencies: new Set(),
}
} }
if (isHarCompiled) { if (isHarCompiled) {
@ -289,7 +293,9 @@ function initArkGuardConfig(obfuscationCacheDir: string | undefined, logger: any
return arkObfuscator; return arkObfuscator;
} }
export function readProjectAndLibsSource(allFiles: Set<string>, mergedObConfig: MergedConfig, arkObfuscator: ArkObfuscator, isHarCompiled: boolean): void { // Scan the source code of project and libraries to collect whitelists.
export function readProjectAndLibsSource(allFiles: Set<string>, mergedObConfig: MergedConfig, arkObfuscator: ArkObfuscator, isHarCompiled: boolean,
keepFilesAndDependencies: Set<string>): void {
if (mergedObConfig?.options === undefined || mergedObConfig.options.disableObfuscation || allFiles.size === 0) { if (mergedObConfig?.options === undefined || mergedObConfig.options.disableObfuscation || allFiles.size === 0) {
return; return;
} }
@ -303,7 +309,11 @@ export function readProjectAndLibsSource(allFiles: Set<string>, mergedObConfig:
mRenameProperties: obfOptions.enablePropertyObfuscation, mRenameProperties: obfOptions.enablePropertyObfuscation,
mKeepStringProperty: !obfOptions.enableStringPropertyObfuscation mKeepStringProperty: !obfOptions.enableStringPropertyObfuscation
}, },
mExportObfuscation: obfOptions.enableExportObfuscation mExportObfuscation: obfOptions.enableExportObfuscation,
mKeepFileSourceCode: {
mKeepSourceOfPaths: new Set(),
mkeepFilesAndDependencies: keepFilesAndDependencies,
}
}, isHarCompiled); }, isHarCompiled);
if (obfOptions.enablePropertyObfuscation && projectAndLibs.projectAndLibsReservedProperties) { if (obfOptions.enablePropertyObfuscation && projectAndLibs.projectAndLibsReservedProperties) {
arkObfuscator.addReservedProperties(projectAndLibs.projectAndLibsReservedProperties); arkObfuscator.addReservedProperties(projectAndLibs.projectAndLibsReservedProperties);

View File

@ -41,7 +41,11 @@ import {
stopEvent stopEvent
} from '../../../ark_utils'; } from '../../../ark_utils';
import { newSourceMaps } from '../transform'; import { newSourceMaps } from '../transform';
import { writeObfuscationNameCache } from '../common/ob_config_resolver'; import {
MergedConfig,
handleKeepFilesAndGetDependencies,
writeObfuscationNameCache
} from '../common/ob_config_resolver';
import { ORIGIN_EXTENTION } from '../process_mock'; import { ORIGIN_EXTENTION } from '../process_mock';
import { import {
ESMODULE, ESMODULE,
@ -49,7 +53,7 @@ import {
USER_DEFINE_MOCK_CONFIG USER_DEFINE_MOCK_CONFIG
} from '../../../pre_define'; } from '../../../pre_define';
import { readProjectAndLibsSource } from '../common/process_ark_config'; import { readProjectAndLibsSource } from '../common/process_ark_config';
import { allSourceFilePaths, collectAllFiles } from '../../../ets_checker'; import { allSourceFilePaths, collectAllFiles, resolvedModulesCache } from '../../../ets_checker';
import { projectConfig } from '../../../../main'; import { projectConfig } from '../../../../main';
import { performancePrinter } from 'arkguard/lib/ArkObfuscator'; import { performancePrinter } from 'arkguard/lib/ArkObfuscator';
import { EventList } from 'arkguard/lib/utils/PrinterUtils'; import { EventList } from 'arkguard/lib/utils/PrinterUtils';
@ -212,8 +216,12 @@ export class ModuleSourceFile {
collectAllFiles(undefined, rollupObject.getModuleIds()); collectAllFiles(undefined, rollupObject.getModuleIds());
performancePrinter?.iniPrinter?.startEvent('Scan source files'); performancePrinter?.iniPrinter?.startEvent('Scan source files');
readProjectAndLibsSource(allSourceFilePaths, ModuleSourceFile.projectConfig.obfuscationMergedObConfig, // obfuscation initialization, include collect file, resolve denpendency, read source
ModuleSourceFile.projectConfig.arkObfuscator, ModuleSourceFile.projectConfig.compileHar); const obfuscationConfig: MergedConfig = ModuleSourceFile.projectConfig.obfuscationMergedObConfig;
const keepFilesAndDependencies = handleKeepFilesAndGetDependencies(resolvedModulesCache, obfuscationConfig, ModuleSourceFile.projectConfig.projectRootPath,
ModuleSourceFile.projectConfig.arkObfuscator);
readProjectAndLibsSource(allSourceFilePaths, obfuscationConfig, ModuleSourceFile.projectConfig.arkObfuscator,ModuleSourceFile.projectConfig.compileHar,
keepFilesAndDependencies);
performancePrinter?.iniPrinter?.endEvent('Scan source files'); performancePrinter?.iniPrinter?.endEvent('Scan source files');
performancePrinter?.filesPrinter?.startEvent(EventList.ALL_FILES_OBFUSCATION); performancePrinter?.filesPrinter?.startEvent(EventList.ALL_FILES_OBFUSCATION);