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';
18
19import { ArkObfuscator, renameIdentifierModule } from '../ArkObfuscator';
20import { collectResevedFileNameInIDEConfig, MergedConfig, ObConfigResolver, readNameCache } from './ConfigResolver';
21import { type IOptions } from '../configs/IOptions';
22
23// Record all unobfuscated properties and reasons.
24export let historyUnobfuscatedPropMap: Map<string, string[]> | undefined;
25export let historyAllUnobfuscatedNamesMap: Map<string, Object> = new Map();
26
27export const printerConfig = {
28  // Print obfuscation time&memory usage of all files and obfuscation processes
29  mFilesPrinter: false,
30  // Print time&memory usage of a single file obfuscation in transform processes
31  mSingleFilePrinter: false,
32  // Print sum up time of transform processes during obfuscation
33  mSumPrinter: false,
34  // Output path of printer
35  mOutputPath: '',
36};
37
38export function initObfuscationConfig(projectConfig: any, arkProjectConfig: any, logger: any): void {
39  const obConfig: ObConfigResolver = new ObConfigResolver(projectConfig, logger, true);
40  const mergedObConfig: MergedConfig = obConfig.resolveObfuscationConfigs();
41  const isHarCompiled: boolean = projectConfig.compileHar;
42  if (mergedObConfig.options.disableObfuscation) {
43    return;
44  }
45
46  if (mergedObConfig.options.enableFileNameObfuscation) {
47    const ohPackagePath = path.join(projectConfig.modulePath, 'oh-package.json5');
48    const entryArray = arkProjectConfig.entryArrayForObf;
49    const reservedFileNamesInIDEconfig = collectResevedFileNameInIDEConfig(
50      ohPackagePath,
51      projectConfig,
52      arkProjectConfig.modulePathMap,
53      entryArray,
54    );
55    mergedObConfig.reservedFileNames.push(...reservedFileNamesInIDEconfig);
56  }
57  arkProjectConfig.obfuscationMergedObConfig = mergedObConfig;
58
59  arkProjectConfig.arkObfuscator = initArkGuardConfig(
60    projectConfig.obfuscationOptions?.obfuscationCacheDir,
61    logger,
62    mergedObConfig,
63    isHarCompiled,
64  );
65}
66
67function initArkGuardConfig(
68  obfuscationCacheDir: string | undefined,
69  logger: any,
70  mergedObConfig: MergedConfig,
71  isHarCompiled: boolean,
72): ArkObfuscator {
73  const arkguardConfig: IOptions = {
74    mCompact: mergedObConfig.options.compact,
75    mDisableConsole: mergedObConfig.options.removeLog,
76    mSimplify: false,
77    mRemoveComments: true,
78    mNameObfuscation: {
79      mEnable: true,
80      mNameGeneratorType: 1,
81      mReservedNames: mergedObConfig.reservedNames,
82      mRenameProperties: mergedObConfig.options.enablePropertyObfuscation,
83      mReservedProperties: mergedObConfig.reservedPropertyNames,
84      mKeepStringProperty: !mergedObConfig.options.enableStringPropertyObfuscation,
85      mTopLevel: mergedObConfig.options.enableToplevelObfuscation,
86      mReservedToplevelNames: mergedObConfig.reservedGlobalNames,
87      mUniversalReservedProperties: mergedObConfig.universalReservedPropertyNames,
88      mUniversalReservedToplevelNames: mergedObConfig.universalReservedGlobalNames
89    },
90    mUnobfuscationOption: {
91      mPrintKeptNames: mergedObConfig.options.printKeptNames,
92      mPrintPath: mergedObConfig.options.printKeptNamesPath
93    },
94    mRemoveDeclarationComments: {
95      mEnable: mergedObConfig.options.removeComments,
96      mReservedComments: mergedObConfig.keepComments,
97    },
98    mEnableSourceMap: true,
99    mEnableNameCache: true,
100    mRenameFileName: {
101      mEnable: mergedObConfig.options.enableFileNameObfuscation,
102      mNameGeneratorType: 1,
103      mReservedFileNames: mergedObConfig.reservedFileNames,
104    },
105    mExportObfuscation: mergedObConfig.options.enableExportObfuscation,
106    mPerformancePrinter: printerConfig,
107    mKeepFileSourceCode: {
108      mKeepSourceOfPaths: new Set(),
109      mkeepFilesAndDependencies: new Set(),
110    },
111  };
112
113  const arkObfuscator: ArkObfuscator = new ArkObfuscator();
114  arkObfuscator.init(arkguardConfig);
115  if (mergedObConfig.options.applyNameCache && mergedObConfig.options.applyNameCache.length > 0) {
116    readNameCache(mergedObConfig.options.applyNameCache, logger);
117  } else {
118    if (obfuscationCacheDir) {
119      const defaultNameCachePath: string = path.join(obfuscationCacheDir, 'nameCache.json');
120      if (fs.existsSync(defaultNameCachePath)) {
121        readNameCache(defaultNameCachePath, logger);
122      }
123    }
124  }
125  if (mergedObConfig.options.printKeptNames && obfuscationCacheDir) {
126    const defaultUnobfuscationPath: string = path.join(obfuscationCacheDir, 'keptNames.json');
127    if (fs.existsSync(defaultUnobfuscationPath)) {
128      readUnobfuscationContent(defaultUnobfuscationPath, logger);
129    }
130  }
131  return arkObfuscator;
132}
133
134function readUnobfuscationContent(defaultUnobfuscationPath: string, logger: any): void {
135  try {
136    const unobfuscationContent = fs.readFileSync(defaultUnobfuscationPath, 'utf-8');
137    const unobfuscationObj: {
138      keptReasons: Object;
139      keptNames: {
140        property: Object;
141        [key: string]: Object;
142      };
143    } = JSON.parse(unobfuscationContent);
144
145    if (Object.keys(unobfuscationObj.keptNames.property).length !== 0) {
146      historyUnobfuscatedPropMap = new Map<string, string[]>(Object.entries(unobfuscationObj.keptNames.property));
147    }
148    const { property, ...rest } = unobfuscationObj.keptNames;
149    Object.keys(rest).forEach((key) => {
150      historyAllUnobfuscatedNamesMap.set(key, rest[key]);
151    });
152  } catch (err) {
153    logger.error(`Failed to open ${defaultUnobfuscationPath}. Error message: ${err}`);
154  }
155}
156