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 { 17 factory, 18 isBindingElement, 19 isObjectBindingPattern, 20 isShorthandPropertyAssignment, 21 isSourceFile, 22 isStructDeclaration, 23 setParentRecursive, 24 visitEachChild, 25 isConstructorDeclaration 26} from 'typescript'; 27 28import type { 29 BindingElement, 30 ClassElement, 31 Expression, 32 Identifier, 33 Node, 34 SourceFile, 35 StructDeclaration, 36 TransformationContext, 37 Transformer, 38 TransformerFactory 39} from 'typescript'; 40 41import type {INameObfuscationOption} from '../../configs/INameObfuscationOption'; 42import type {TransformPlugin} from '../TransformPlugin'; 43import {TransformerOrder} from '../TransformPlugin'; 44import type {IOptions} from '../../configs/IOptions'; 45import {NodeUtils} from '../../utils/NodeUtils'; 46import {ArkObfuscator, performancePrinter} from '../../ArkObfuscator'; 47import { endSingleFileEvent, startSingleFileEvent } from '../../utils/PrinterUtils'; 48import { EventList } from '../../utils/PrinterTimeAndMemUtils'; 49import { MemoryDottingDefine } from '../../utils/MemoryDottingDefine'; 50 51namespace secharmony { 52 const createShorthandPropertyTransformerFactory = function (option: IOptions): TransformerFactory<Node> | null { 53 let profile: INameObfuscationOption = option.mNameObfuscation; 54 if (!profile || !profile.mEnable) { 55 return null; 56 } 57 58 return shorthandPropertyTransformFactory; 59 60 function shorthandPropertyTransformFactory(context: TransformationContext): Transformer<Node> { 61 return shorthandPropertyTransformer; 62 63 function shorthandPropertyTransformer(node: Node): Node { 64 if (isSourceFile(node) && ArkObfuscator.isKeptCurrentFile) { 65 return node; 66 } 67 68 const recordInfo = ArkObfuscator.recordStage(MemoryDottingDefine.SHORTHAND_OBFUSCATION); 69 startSingleFileEvent(EventList.SHORT_HAND_OBFUSCATION, performancePrinter.timeSumPrinter); 70 startSingleFileEvent(EventList.TRANSFORM_SHORT_HAND_PROPERTY); 71 let ret = transformShortHandProperty(node); 72 endSingleFileEvent(EventList.TRANSFORM_SHORT_HAND_PROPERTY); 73 let parentNodes = setParentRecursive(ret, true); 74 endSingleFileEvent(EventList.SHORT_HAND_OBFUSCATION, performancePrinter.timeSumPrinter); 75 ArkObfuscator.stopRecordStage(recordInfo); 76 return parentNodes; 77 } 78 79 function transformShortHandProperty(node: Node): Node { 80 /** 81 * example: 82 * `let name1 = 'hello';` 83 * `let info = {name1};` 84 * obfuscated example: 85 * `let name1 = 'hello';`; 86 * `let info = {name1: name1};` 87 */ 88 if (isShorthandPropertyAssignment((node))) { 89 let initializer = node.objectAssignmentInitializer; 90 let expression: Expression = node.name; 91 if (initializer) { 92 expression = factory.createBinaryExpression(node.name, node.equalsToken, initializer); 93 } 94 95 let identifier = factory.createIdentifier(node.name.text); 96 return factory.createPropertyAssignment(identifier, expression); 97 } 98 99 /** 100 * exclude grammar instance: let [name2, age2] = ['akira', 22]; 101 * 102 * grammar: {name1, ...rest}= {'name1': 'akira', age : 22}; 103 * an alias will be created for name1. 104 * no alias will be created for rest. 105 * 106 * include grammars: 107 * orinal ObjectBinding(): 108 * const { name3, age3 } = foo3(); 109 * const { name4, addr4: { contry, place} } = foo4(); 110 * obfuscated ObjectBinding: 111 * `const { name3: name3, age3: age3 } = foo3();` 112 * `const { name4: name4, addr4: { contry: contry, place: place} } = { name4: 4, addr4: { contry:5, place:6} };` 113 */ 114 if (isElementsInObjectBindingPattern(node) && !node.propertyName && !node.dotDotDotToken) { 115 return factory.createBindingElement(node.dotDotDotToken, factory.createIdentifier((node.name as Identifier).text), 116 node.name, node.initializer); 117 } 118 119 return visitEachChild(node, transformShortHandProperty, context); 120 } 121 122 function isElementsInObjectBindingPattern(node: Node): node is BindingElement { 123 return node.parent && isObjectBindingPattern(node.parent) && isBindingElement(node); 124 } 125 } 126 }; 127 128 export let transformerPlugin: TransformPlugin = { 129 'name': 'ShortHandPropertyTransformer', 130 'order': TransformerOrder.SHORTHAND_PROPERTY_TRANSFORMER, 131 'createTransformerFactory': createShorthandPropertyTransformerFactory, 132 }; 133} 134 135export = secharmony; 136