13af6ab5fSopenharmony_ci/* 23af6ab5fSopenharmony_ci * Copyright (c) 2023-2024 Huawei Device Co., Ltd. 33af6ab5fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 43af6ab5fSopenharmony_ci * you may not use this file except in compliance with the License. 53af6ab5fSopenharmony_ci * You may obtain a copy of the License at 63af6ab5fSopenharmony_ci * 73af6ab5fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 83af6ab5fSopenharmony_ci * 93af6ab5fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 103af6ab5fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 113af6ab5fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 123af6ab5fSopenharmony_ci * See the License for the specific language governing permissions and 133af6ab5fSopenharmony_ci * limitations under the License. 143af6ab5fSopenharmony_ci */ 153af6ab5fSopenharmony_ci 163af6ab5fSopenharmony_ciimport { 173af6ab5fSopenharmony_ci factory, 183af6ab5fSopenharmony_ci isComputedPropertyName, 193af6ab5fSopenharmony_ci isConstructorDeclaration, 203af6ab5fSopenharmony_ci isElementAccessExpression, 213af6ab5fSopenharmony_ci isIdentifier, 223af6ab5fSopenharmony_ci isNumericLiteral, 233af6ab5fSopenharmony_ci isPrivateIdentifier, 243af6ab5fSopenharmony_ci isStringLiteralLike, 253af6ab5fSopenharmony_ci setParentRecursive, 263af6ab5fSopenharmony_ci visitEachChild, 273af6ab5fSopenharmony_ci isSourceFile 283af6ab5fSopenharmony_ci} from 'typescript'; 293af6ab5fSopenharmony_ci 303af6ab5fSopenharmony_ciimport type { 313af6ab5fSopenharmony_ci ComputedPropertyName, 323af6ab5fSopenharmony_ci Expression, 333af6ab5fSopenharmony_ci Identifier, 343af6ab5fSopenharmony_ci Node, 353af6ab5fSopenharmony_ci TransformationContext, 363af6ab5fSopenharmony_ci Transformer, 373af6ab5fSopenharmony_ci TransformerFactory, 383af6ab5fSopenharmony_ci} from 'typescript'; 393af6ab5fSopenharmony_ci 403af6ab5fSopenharmony_ciimport type {IOptions} from '../../configs/IOptions'; 413af6ab5fSopenharmony_ciimport type { INameObfuscationOption } from '../../configs/INameObfuscationOption'; 423af6ab5fSopenharmony_ciimport type {INameGenerator, NameGeneratorOptions} from '../../generator/INameGenerator'; 433af6ab5fSopenharmony_ciimport {getNameGenerator, NameGeneratorType} from '../../generator/NameFactory'; 443af6ab5fSopenharmony_ciimport type {TransformPlugin} from '../TransformPlugin'; 453af6ab5fSopenharmony_ciimport {TransformerOrder} from '../TransformPlugin'; 463af6ab5fSopenharmony_ciimport {NodeUtils} from '../../utils/NodeUtils'; 473af6ab5fSopenharmony_ciimport { ArkObfuscator, performancePrinter } from '../../ArkObfuscator'; 483af6ab5fSopenharmony_ciimport { EventList } from '../../utils/PrinterUtils'; 493af6ab5fSopenharmony_ciimport { 503af6ab5fSopenharmony_ci isInPropertyWhitelist, 513af6ab5fSopenharmony_ci isReservedProperty, 523af6ab5fSopenharmony_ci needToRecordProperty 533af6ab5fSopenharmony_ci} from '../../utils/TransformUtil'; 543af6ab5fSopenharmony_ciimport { 553af6ab5fSopenharmony_ci classInfoInMemberMethodCache, 563af6ab5fSopenharmony_ci nameCache 573af6ab5fSopenharmony_ci} from './RenameIdentifierTransformer'; 583af6ab5fSopenharmony_ciimport { UpdateMemberMethodName } from '../../utils/NameCacheUtil'; 593af6ab5fSopenharmony_ciimport { PropCollections, UnobfuscationCollections } from '../../utils/CommonCollections'; 603af6ab5fSopenharmony_ci 613af6ab5fSopenharmony_cinamespace secharmony { 623af6ab5fSopenharmony_ci /** 633af6ab5fSopenharmony_ci * Rename Properties Transformer 643af6ab5fSopenharmony_ci * 653af6ab5fSopenharmony_ci * @param option obfuscation options 663af6ab5fSopenharmony_ci */ 673af6ab5fSopenharmony_ci const createRenamePropertiesFactory = function (option: IOptions): TransformerFactory<Node> { 683af6ab5fSopenharmony_ci let profile: INameObfuscationOption | undefined = option?.mNameObfuscation; 693af6ab5fSopenharmony_ci 703af6ab5fSopenharmony_ci if (!profile || !profile.mEnable || !profile.mRenameProperties) { 713af6ab5fSopenharmony_ci return null; 723af6ab5fSopenharmony_ci } 733af6ab5fSopenharmony_ci 743af6ab5fSopenharmony_ci return renamePropertiesFactory; 753af6ab5fSopenharmony_ci 763af6ab5fSopenharmony_ci function renamePropertiesFactory(context: TransformationContext): Transformer<Node> { 773af6ab5fSopenharmony_ci let options: NameGeneratorOptions = {}; 783af6ab5fSopenharmony_ci let generator: INameGenerator = getNameGenerator(profile.mNameGeneratorType, options); 793af6ab5fSopenharmony_ci let currentConstructorParams: Set<string> = new Set<string>(); 803af6ab5fSopenharmony_ci 813af6ab5fSopenharmony_ci return renamePropertiesTransformer; 823af6ab5fSopenharmony_ci 833af6ab5fSopenharmony_ci function renamePropertiesTransformer(node: Node): Node { 843af6ab5fSopenharmony_ci if (isSourceFile(node) && ArkObfuscator.isKeptCurrentFile) { 853af6ab5fSopenharmony_ci return node; 863af6ab5fSopenharmony_ci } 873af6ab5fSopenharmony_ci 883af6ab5fSopenharmony_ci performancePrinter?.singleFilePrinter?.startEvent(EventList.PROPERTY_OBFUSCATION, performancePrinter.timeSumPrinter); 893af6ab5fSopenharmony_ci let ret: Node = renameProperties(node); 903af6ab5fSopenharmony_ci UpdateMemberMethodName(nameCache, PropCollections.globalMangledTable, classInfoInMemberMethodCache); 913af6ab5fSopenharmony_ci let parentNodes = setParentRecursive(ret, true); 923af6ab5fSopenharmony_ci performancePrinter?.singleFilePrinter?.endEvent(EventList.PROPERTY_OBFUSCATION, performancePrinter.timeSumPrinter); 933af6ab5fSopenharmony_ci return parentNodes; 943af6ab5fSopenharmony_ci } 953af6ab5fSopenharmony_ci 963af6ab5fSopenharmony_ci function renameProperties(node: Node): Node { 973af6ab5fSopenharmony_ci if (isConstructorDeclaration(node)) { 983af6ab5fSopenharmony_ci currentConstructorParams.clear(); 993af6ab5fSopenharmony_ci } 1003af6ab5fSopenharmony_ci 1013af6ab5fSopenharmony_ci if (NodeUtils.isClassPropertyInConstructorParams(node)) { 1023af6ab5fSopenharmony_ci currentConstructorParams.add((node as Identifier).escapedText.toString()); 1033af6ab5fSopenharmony_ci return renameProperty(node, false); 1043af6ab5fSopenharmony_ci } 1053af6ab5fSopenharmony_ci 1063af6ab5fSopenharmony_ci if (NodeUtils.isClassPropertyInConstructorBody(node, currentConstructorParams)) { 1073af6ab5fSopenharmony_ci if (currentConstructorParams.has((node as Identifier).escapedText.toString())) { 1083af6ab5fSopenharmony_ci return renameProperty(node, false); 1093af6ab5fSopenharmony_ci } 1103af6ab5fSopenharmony_ci } 1113af6ab5fSopenharmony_ci 1123af6ab5fSopenharmony_ci if (!NodeUtils.isPropertyNode(node)) { 1133af6ab5fSopenharmony_ci return visitEachChild(node, renameProperties, context); 1143af6ab5fSopenharmony_ci } 1153af6ab5fSopenharmony_ci 1163af6ab5fSopenharmony_ci if (isElementAccessExpression(node.parent)) { 1173af6ab5fSopenharmony_ci return renameElementAccessProperty(node); 1183af6ab5fSopenharmony_ci } 1193af6ab5fSopenharmony_ci 1203af6ab5fSopenharmony_ci if (isComputedPropertyName(node)) { 1213af6ab5fSopenharmony_ci return renameComputedProperty(node); 1223af6ab5fSopenharmony_ci } 1233af6ab5fSopenharmony_ci 1243af6ab5fSopenharmony_ci return renameProperty(node, false); 1253af6ab5fSopenharmony_ci } 1263af6ab5fSopenharmony_ci 1273af6ab5fSopenharmony_ci function renameElementAccessProperty(node: Node): Node { 1283af6ab5fSopenharmony_ci if (isStringLiteralLike(node)) { 1293af6ab5fSopenharmony_ci return renameProperty(node, false); 1303af6ab5fSopenharmony_ci } 1313af6ab5fSopenharmony_ci return visitEachChild(node, renameProperties, context); 1323af6ab5fSopenharmony_ci } 1333af6ab5fSopenharmony_ci 1343af6ab5fSopenharmony_ci function renameComputedProperty(node: ComputedPropertyName): ComputedPropertyName { 1353af6ab5fSopenharmony_ci if (isStringLiteralLike(node.expression) || isNumericLiteral(node.expression)) { 1363af6ab5fSopenharmony_ci let prop: Node = renameProperty(node.expression, true); 1373af6ab5fSopenharmony_ci if (prop !== node.expression) { 1383af6ab5fSopenharmony_ci return factory.createComputedPropertyName(prop as Expression); 1393af6ab5fSopenharmony_ci } 1403af6ab5fSopenharmony_ci } 1413af6ab5fSopenharmony_ci 1423af6ab5fSopenharmony_ci if (isIdentifier(node.expression)) { 1433af6ab5fSopenharmony_ci return node; 1443af6ab5fSopenharmony_ci } 1453af6ab5fSopenharmony_ci 1463af6ab5fSopenharmony_ci return visitEachChild(node, renameProperties, context); 1473af6ab5fSopenharmony_ci } 1483af6ab5fSopenharmony_ci 1493af6ab5fSopenharmony_ci function renameProperty(node: Node, computeName: boolean): Node { 1503af6ab5fSopenharmony_ci if (!isStringLiteralLike(node) && !isIdentifier(node) && !isPrivateIdentifier(node) && !isNumericLiteral(node)) { 1513af6ab5fSopenharmony_ci return visitEachChild(node, renameProperties, context); 1523af6ab5fSopenharmony_ci } 1533af6ab5fSopenharmony_ci 1543af6ab5fSopenharmony_ci if (isStringLiteralLike(node) && profile?.mKeepStringProperty) { 1553af6ab5fSopenharmony_ci if (UnobfuscationCollections.printKeptName) { 1563af6ab5fSopenharmony_ci needToRecordProperty(node.text, UnobfuscationCollections.unobfuscatedPropMap); 1573af6ab5fSopenharmony_ci } 1583af6ab5fSopenharmony_ci return node; 1593af6ab5fSopenharmony_ci } 1603af6ab5fSopenharmony_ci 1613af6ab5fSopenharmony_ci let original: string = node.text; 1623af6ab5fSopenharmony_ci if (isInPropertyWhitelist(original, UnobfuscationCollections.unobfuscatedPropMap)) { 1633af6ab5fSopenharmony_ci return node; 1643af6ab5fSopenharmony_ci } 1653af6ab5fSopenharmony_ci 1663af6ab5fSopenharmony_ci let mangledName: string = getPropertyName(original); 1673af6ab5fSopenharmony_ci 1683af6ab5fSopenharmony_ci if (isStringLiteralLike(node)) { 1693af6ab5fSopenharmony_ci return factory.createStringLiteral(mangledName); 1703af6ab5fSopenharmony_ci } 1713af6ab5fSopenharmony_ci 1723af6ab5fSopenharmony_ci /** 1733af6ab5fSopenharmony_ci * source demo: 1743af6ab5fSopenharmony_ci * class A { 1753af6ab5fSopenharmony_ci * 123 = 1; // it is NumericLiteral 1763af6ab5fSopenharmony_ci * [456] = 2; // it is NumericLiteral within ComputedPropertyName 1773af6ab5fSopenharmony_ci * } 1783af6ab5fSopenharmony_ci * obfuscation result: 1793af6ab5fSopenharmony_ci * class A { 1803af6ab5fSopenharmony_ci * a = 1; 1813af6ab5fSopenharmony_ci * ['b'] = 2; 1823af6ab5fSopenharmony_ci * } 1833af6ab5fSopenharmony_ci */ 1843af6ab5fSopenharmony_ci if (isNumericLiteral(node)) { 1853af6ab5fSopenharmony_ci return computeName ? factory.createStringLiteral(mangledName) : factory.createIdentifier(mangledName); 1863af6ab5fSopenharmony_ci } 1873af6ab5fSopenharmony_ci 1883af6ab5fSopenharmony_ci if (isIdentifier(node) || isNumericLiteral(node)) { 1893af6ab5fSopenharmony_ci return factory.createIdentifier(mangledName); 1903af6ab5fSopenharmony_ci } 1913af6ab5fSopenharmony_ci 1923af6ab5fSopenharmony_ci return factory.createPrivateIdentifier('#' + mangledName); 1933af6ab5fSopenharmony_ci } 1943af6ab5fSopenharmony_ci 1953af6ab5fSopenharmony_ci function getPropertyName(original: string): string { 1963af6ab5fSopenharmony_ci const historyName: string = PropCollections.historyMangledTable?.get(original); 1973af6ab5fSopenharmony_ci let mangledName: string = historyName ? historyName : PropCollections.globalMangledTable.get(original); 1983af6ab5fSopenharmony_ci while (!mangledName) { 1993af6ab5fSopenharmony_ci let tmpName = generator.getName(); 2003af6ab5fSopenharmony_ci if (isReservedProperty(tmpName) || 2013af6ab5fSopenharmony_ci tmpName === original) { 2023af6ab5fSopenharmony_ci continue; 2033af6ab5fSopenharmony_ci } 2043af6ab5fSopenharmony_ci 2053af6ab5fSopenharmony_ci if (PropCollections.newlyOccupiedMangledProps.has(tmpName) || PropCollections.mangledPropsInNameCache.has(tmpName)) { 2063af6ab5fSopenharmony_ci continue; 2073af6ab5fSopenharmony_ci } 2083af6ab5fSopenharmony_ci 2093af6ab5fSopenharmony_ci mangledName = tmpName; 2103af6ab5fSopenharmony_ci } 2113af6ab5fSopenharmony_ci PropCollections.globalMangledTable.set(original, mangledName); 2123af6ab5fSopenharmony_ci PropCollections.newlyOccupiedMangledProps.add(mangledName); 2133af6ab5fSopenharmony_ci return mangledName; 2143af6ab5fSopenharmony_ci } 2153af6ab5fSopenharmony_ci } 2163af6ab5fSopenharmony_ci }; 2173af6ab5fSopenharmony_ci 2183af6ab5fSopenharmony_ci export let transformerPlugin: TransformPlugin = { 2193af6ab5fSopenharmony_ci 'name': 'renamePropertiesPlugin', 2203af6ab5fSopenharmony_ci 'order': TransformerOrder.RENAME_PROPERTIES_TRANSFORMER, 2213af6ab5fSopenharmony_ci 'createTransformerFactory': createRenamePropertiesFactory 2223af6ab5fSopenharmony_ci }; 2233af6ab5fSopenharmony_ci} 2243af6ab5fSopenharmony_ci 2253af6ab5fSopenharmony_ciexport = secharmony; 226