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