• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 path from 'path';
17import fs from 'fs';
18import {FileUtils} from '../utils/FileUtils';
19import {ApiExtractor} from './ApiExtractor';
20import {ListUtil} from '../utils/ListUtil';
21import type {IOptions} from '../configs/IOptions';
22import { stringPropsSet, structPropsSet } from '../utils/OhsUtil';
23import { sys } from 'typescript';
24
25export const scanProjectConfig: {mKeepStringProperty?: boolean, mExportObfuscation?: boolean, isHarCompiled?: boolean} = {};
26
27/**
28 * if rename property is not open, api read and extract can be skipped
29 *
30 * init plugin, read api info of openHarmony sdk and generate file of reserved name, property and string.
31 * @param sdkDir absolute path like D:\\HuaweiApp\\ohsdk
32 * @param outputDir
33 */
34export function initPlugin(sdkDir: string, outputDir: string): void {
35  // create sdk api file if not exist
36  const ohSdkPath: string = path.resolve(sdkDir);
37  if (!ohSdkPath) {
38    console.error('SDK path is not found.');
39  }
40
41  const apiVersions: string[] = [''];
42
43  apiVersions.forEach((versionString) => {
44    ApiExtractor.parseOhSdk(ohSdkPath, versionString, true, outputDir);
45  });
46}
47
48/**
49 * need read api info or not
50 * @param customProfiles
51 */
52export function needReadApiInfo(customProfiles: IOptions): boolean {
53  return isEnabledPropertyObfuscation(customProfiles) || customProfiles.mExportObfuscation;
54}
55
56export function isEnabledPropertyObfuscation(customProfiles: IOptions): boolean {
57  return (customProfiles.mNameObfuscation &&
58    customProfiles.mNameObfuscation.mEnable &&
59    customProfiles.mNameObfuscation.mRenameProperties);
60}
61
62/**
63 * read project reserved properties
64 * @param projectPaths can be dir or file
65 * @param customProfiles
66 */
67export function readProjectProperties(projectPaths: string[], customProfiles: IOptions, isOHProject?: boolean):
68  {projectAndLibsReservedProperties: string[]; libExportNames: string[]} {
69
70  let scanningCommonType: ApiExtractor.ApiType = undefined;
71  let scanningLibsType: ApiExtractor.ApiType = undefined;
72  if (isEnabledPropertyObfuscation(customProfiles)) {
73    scanningCommonType = ApiExtractor.ApiType.PROJECT;
74    scanningLibsType = ApiExtractor.ApiType.PROJECT_DEPENDS;
75  } else {
76    scanningCommonType = ApiExtractor.ApiType.CONSTRUCTOR_PROPERTY;
77    scanningLibsType = ApiExtractor.ApiType.CONSTRUCTOR_PROPERTY;
78    ApiExtractor.mConstructorPropertySet = new Set();
79  }
80
81  scanProjectConfig.mKeepStringProperty = customProfiles.mNameObfuscation?.mKeepStringProperty;
82  scanProjectConfig.mExportObfuscation = customProfiles.mExportObfuscation;
83
84  for (const projectPath of projectPaths) {
85    if (!fs.existsSync(projectPath)) {
86      console.error(`File ${FileUtils.getFileName(projectPath)} is not found.`);
87      return {projectAndLibsReservedProperties:[], libExportNames: []};
88    }
89
90    const sourcPath = isOHProject ? path.join(projectPath, 'src', 'main') : projectPath;
91    const projProperties: string[] = ApiExtractor.parseCommonProject(sourcPath, customProfiles, scanningCommonType);
92    const libExportNamesAndReservedProps = readThirdPartyLibProperties(projectPath, scanningLibsType);
93    const sdkProperties = libExportNamesAndReservedProps?.reservedProperties;
94
95    if (isEnabledPropertyObfuscation(customProfiles)) {
96      // read project code export names
97      customProfiles.mNameObfuscation.mReservedProperties = ListUtil.uniqueMergeList(projProperties,
98        customProfiles.mNameObfuscation.mReservedProperties, [...structPropsSet]);
99
100      // read project lib export names
101      if (sdkProperties && sdkProperties.length > 0) {
102        customProfiles.mNameObfuscation.mReservedProperties = ListUtil.uniqueMergeList(sdkProperties,
103          customProfiles.mNameObfuscation.mReservedProperties);
104      }
105
106      if (scanProjectConfig.mKeepStringProperty && stringPropsSet.size > 0) {
107        customProfiles.mNameObfuscation.mReservedProperties = ListUtil.uniqueMergeList([...stringPropsSet],
108          customProfiles.mNameObfuscation.mReservedProperties);
109      }
110    }
111    structPropsSet.clear();
112    stringPropsSet.clear();
113    if (scanProjectConfig.mExportObfuscation && libExportNamesAndReservedProps?.reservedLibExportNames) {
114      customProfiles.mNameObfuscation.mReservedNames = ListUtil.uniqueMergeList(libExportNamesAndReservedProps.reservedLibExportNames,
115        customProfiles.mNameObfuscation.mReservedNames);
116    }
117  }
118
119  return {
120    projectAndLibsReservedProperties: customProfiles.mNameObfuscation.mReservedProperties ?? [],
121    libExportNames: customProfiles.mNameObfuscation.mReservedNames ?? []
122  };
123}
124
125/**
126 * read project reserved properties by collected paths
127 * @param filesForCompilation set collection of files
128 * @param customProfiles
129 */
130export function readProjectPropertiesByCollectedPaths(filesForCompilation: Set<string>, customProfiles: IOptions, isHarCompiled: boolean):
131  {projectAndLibsReservedProperties: string[]; libExportNames: string[]} {
132  const ApiType = ApiExtractor.ApiType;
133  let scanningCommonType = undefined;
134  let scanningLibsType = undefined;
135  if (isEnabledPropertyObfuscation(customProfiles)) {
136    scanningCommonType = ApiType.PROJECT;
137    scanningLibsType = ApiType.PROJECT_DEPENDS;
138  } else {
139    scanningCommonType = ApiType.CONSTRUCTOR_PROPERTY;
140    scanningLibsType = ApiType.CONSTRUCTOR_PROPERTY;
141    ApiExtractor.mConstructorPropertySet = new Set();
142  }
143
144  const nameObfuscationConfig = customProfiles.mNameObfuscation;
145  scanProjectConfig.mKeepStringProperty = nameObfuscationConfig?.mKeepStringProperty;
146  scanProjectConfig.mExportObfuscation = customProfiles.mExportObfuscation;
147  scanProjectConfig.isHarCompiled = isHarCompiled;
148
149  const sourcePaths: string[] = [];
150  const remoteHarParhs: string[] = [];
151
152  filesForCompilation.forEach(path => {
153    if (ApiExtractor.isRemoteHar(path)) {
154      remoteHarParhs.push(path);
155    } else {
156      sourcePaths.push(path);
157    }
158  });
159
160  stringPropsSet.clear();
161
162  const projProperties: string[] = ApiExtractor.parseProjectSourceByPaths(sourcePaths, customProfiles, scanningCommonType);
163  const libExportNamesAndReservedProps = ApiExtractor.parseThirdPartyLibsByPaths(remoteHarParhs, scanningLibsType);
164  let sdkProperties = libExportNamesAndReservedProps?.reservedProperties ?? [];
165
166  if (isEnabledPropertyObfuscation(customProfiles)) {
167    // read project code export names
168    nameObfuscationConfig.mReservedProperties = ListUtil.uniqueMergeList(projProperties,
169      nameObfuscationConfig.mReservedProperties, [...structPropsSet]);
170
171    // read project lib export names
172    if (sdkProperties && sdkProperties.length > 0) {
173      nameObfuscationConfig.mReservedProperties = ListUtil.uniqueMergeList(sdkProperties,
174        nameObfuscationConfig.mReservedProperties);
175    }
176
177    if (scanProjectConfig.mKeepStringProperty && stringPropsSet.size > 0) {
178      nameObfuscationConfig.mReservedProperties = ListUtil.uniqueMergeList([...stringPropsSet],
179        nameObfuscationConfig.mReservedProperties);
180    }
181  }
182  structPropsSet.clear();
183  stringPropsSet.clear();
184
185  if (scanProjectConfig.mExportObfuscation && libExportNamesAndReservedProps?.reservedLibExportNames) {
186    nameObfuscationConfig.mReservedNames = ListUtil.uniqueMergeList(libExportNamesAndReservedProps.reservedLibExportNames,
187      nameObfuscationConfig.mReservedNames);
188  }
189
190  return {
191    projectAndLibsReservedProperties: nameObfuscationConfig.mReservedProperties ?? [],
192    libExportNames: nameObfuscationConfig.mReservedNames ?? []
193  };
194}
195
196function readThirdPartyLibProperties(projectPath: string, scanningApiType: ApiExtractor.ApiType): {reservedProperties: string[];
197  reservedLibExportNames: string[] | undefined} {
198  if (!fs.lstatSync(projectPath).isDirectory()) {
199    return undefined;
200  }
201
202  // find third party lib and extract reserved names
203  const fileNames: string[] = fs.readdirSync(projectPath);
204  const hasNodeModules: boolean = fileNames.includes('node_modules');
205  const hasOHModules: boolean = fileNames.includes('oh_modules');
206  if (!hasNodeModules && !hasOHModules) {
207    return undefined;
208  }
209  if (hasNodeModules && hasOHModules) {
210    throw new Error(`There are both node_modules and oh_modules folders in ${projectPath}`);
211  }
212
213  let filePath: string = '';
214  if (hasNodeModules) {
215    filePath = path.join(projectPath, 'node_modules');
216  } else {
217    filePath = path.join(projectPath, 'oh_modules');
218  }
219
220  return ApiExtractor.parseThirdPartyLibs(filePath, scanningApiType);
221}
222