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 { describe, it } from 'mocha'; 17import { assert, expect } from 'chai'; 18import { ArkObfuscator, FileUtils, UnobfuscationCollections, wildcardTransformer } from '../../../src/ArkObfuscator'; 19import { ArkObfuscatorForTest } from '../../../src/ArkObfuscatorForTest' 20import path from 'path'; 21import { TransformerFactory, Node, SourceFile, createSourceFile, ScriptTarget, Printer, createTextWriter, RawSourceMap } from 'typescript'; 22import { IOptions } from '../../../src/configs/IOptions'; 23import { getSourceMapGenerator } from '../../../src/utils/SourceMapUtil'; 24import fs from 'fs'; 25import esInfo from '../../../src/configs/preset/es_reserved_properties.json'; 26import optimizeEsInfo from '../../../src/configs/preset/es_reserved_properties_optimized.json' 27 28describe('Tester Cases for <ArkObfuscatorForTest>.', function () { 29 describe('Tester Cases for <ArkObfuscatorForTest>.', function () { 30 let etsSourceFile: SourceFile; 31 let dEtsSourceFile: SourceFile; 32 let tsSourceFile: SourceFile; 33 let etsSourceFilePath: string = 'demo.ets'; 34 let dEtsSourceFilePath: string = 'demo.d.ets'; 35 let tsSourceFilePath: string = 'demo.ts'; 36 37 before('init sourceFile', function () { 38 const etsfileContent = `//This is a comment 39//This is a comment 40//This is a comment 41//This is a comment 42class Demo{ 43 constructor(public title: string, public content: string, public mark: number) { 44 this.title = title 45 this.content = content 46 this.mark = mark 47 } 48} 49`; 50 const dEtsFileContent = ` 51 /** 52 * This is a comment 53 */ 54 55 class Demo{ 56 constructor(public title: string, public content: string, public mark: number) { 57 this.title = title 58 this.content = content 59 this.mark = mark 60 } 61 } 62 `; 63 64 const tsFileContent = ` 65 //This is a comment 66 class Demo{ 67 constructor(public title: string, public content: string, public mark: number) { 68 this.title = title 69 this.content = content 70 this.mark = mark 71 } 72 } 73 `; 74 75 etsSourceFile = createSourceFile('demo.ts', etsfileContent, ScriptTarget.ES2015, true); 76 dEtsSourceFile = createSourceFile(dEtsSourceFilePath, dEtsFileContent, ScriptTarget.ES2015, true); 77 tsSourceFile = createSourceFile(tsSourceFilePath, tsFileContent, ScriptTarget.ES2015, true); 78 }); 79 80 it('Tester: test case for handleTsHarComments for ets file', function () { 81 let mCustomProfiles: IOptions | undefined = FileUtils.readFileAsJson(path.join(__dirname, "default_config.json")); 82 let arkobfuscator = new ArkObfuscatorForTest(); 83 arkobfuscator.init(mCustomProfiles); 84 let originalFilePath = 'demo.ets'; 85 ArkObfuscatorForTest.projectInfo = { packageDir: '', projectRootPath: '', localPackageSet: new Set<string>(), useNormalized: false, useTsHar: true }; 86 arkobfuscator.handleTsHarComments(etsSourceFile, originalFilePath); 87 let sourceMapGenerator = getSourceMapGenerator(originalFilePath); 88 const textWriter = createTextWriter('\n'); 89 arkobfuscator.createObfsPrinter(etsSourceFile.isDeclarationFile).writeFile(etsSourceFile, textWriter, sourceMapGenerator); 90 const actualContent = textWriter.getText(); 91 const expectContent = ` 92 // @keepTs 93 // @ts-nocheck 94 class Demo { 95 constructor(public title: string, public content: string, public mark: number) { 96 this.title = title; 97 this.content = content; 98 this.mark = mark; 99 } 100 }`; 101 102 let actualSourceMap: RawSourceMap = sourceMapGenerator.toJSON(); 103 actualSourceMap.sourceRoot = ""; 104 let expectSourceMap = { 105 "version": 3, 106 "file": "demo.ets", 107 "sourceRoot": "", 108 "sources": [ 109 "demo.ts" 110 ], 111 "names": [], 112 "mappings": ";;AAIA,MAAM,IAAI;IACR,YAAY,MAAM,CAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAE,IAAI,EAAE,MAAM;QAC5E,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;QAClB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;QACtB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;IACpB,CAAC;CACF" 113 } 114 assert.strictEqual(compareStringsIgnoreNewlines(actualContent, expectContent), true); 115 assert.strictEqual(compareStringsIgnoreNewlines(JSON.stringify(actualSourceMap, null, 2), JSON.stringify(expectSourceMap, null, 2)), true); 116 }); 117 118 it('Tester: test case for handleTsHarComments for d.ets file', function () { 119 let mCustomProfiles: IOptions | undefined = FileUtils.readFileAsJson(path.join(__dirname, "default_config.json")); 120 let arkobfuscator = new ArkObfuscatorForTest(); 121 arkobfuscator.init(mCustomProfiles); 122 ArkObfuscatorForTest.projectInfo = { packageDir: '', projectRootPath: '', localPackageSet: new Set<string>(), useNormalized: false, useTsHar: true }; 123 arkobfuscator.handleTsHarComments(dEtsSourceFile, dEtsSourceFilePath); 124 let sourceMapGenerator = getSourceMapGenerator(dEtsSourceFilePath); 125 const textWriter = createTextWriter('\n'); 126 arkobfuscator.createObfsPrinter(dEtsSourceFile.isDeclarationFile).writeFile(dEtsSourceFile, textWriter, sourceMapGenerator); 127 const actualContent = textWriter.getText(); 128 const expectContent = ` 129 /** 130 * This is a comment 131 */ 132 class Demo { 133 constructor(public title: string, public content: string, public mark: number) { 134 this.title = title; 135 this.content = content; 136 this.mark = mark; 137 } 138 }`; 139 assert.strictEqual(compareStringsIgnoreNewlines(actualContent, expectContent), true); 140 }); 141 142 it('Tester: test case for handleTsHarComments for ts file', function () { 143 let mCustomProfiles: IOptions | undefined = FileUtils.readFileAsJson(path.join(__dirname, "default_config.json")); 144 let arkobfuscator = new ArkObfuscatorForTest(); 145 arkobfuscator.init(mCustomProfiles); 146 ArkObfuscatorForTest.projectInfo = { packageDir: '', projectRootPath: '', localPackageSet: new Set<string>(), useNormalized: false, useTsHar: true }; 147 arkobfuscator.handleTsHarComments(tsSourceFile, tsSourceFilePath); 148 let sourceMapGenerator = getSourceMapGenerator(tsSourceFilePath); 149 const textWriter = createTextWriter('\n'); 150 arkobfuscator.createObfsPrinter(tsSourceFile.isDeclarationFile).writeFile(tsSourceFile, textWriter, sourceMapGenerator); 151 const actualContent = textWriter.getText(); 152 const expectContent = ` 153 class Demo { 154 constructor(public title: string, public content: string, public mark: number) { 155 this.title = title; 156 this.content = content; 157 this.mark = mark; 158 } 159 }`; 160 assert.strictEqual(compareStringsIgnoreNewlines(actualContent, expectContent), true); 161 }); 162 }); 163 164 describe('Tester Cases for <ArkObfuscatorForTest>.', function () { 165 it('Tester: test case for ArkObfuscatorForTest.ini', function (){ 166 let configPath = "test/ut/arkobfuscator/iniTestObfConfig.json" 167 let obfuscator: ArkObfuscatorForTest = new ArkObfuscatorForTest(); 168 const originalConfig: IOptions | undefined = FileUtils.readFileAsJson(configPath); 169 obfuscator.init(originalConfig); 170 let config = obfuscator.customProfiles; 171 let reservedTopelevelNames = config.mNameObfuscation?.mReservedToplevelNames; 172 let reservedProperty = config.mNameObfuscation?.mReservedProperties; 173 let universalReservedToplevelNames = config.mNameObfuscation?.mUniversalReservedToplevelNames as RegExp[]; 174 let universalReservedProperties = config.mNameObfuscation?.mUniversalReservedProperties as RegExp[]; 175 assert.isTrue(reservedTopelevelNames?.includes("func2")); 176 assert.isTrue(reservedProperty?.includes("prop")); 177 assert.equal(universalReservedToplevelNames[0].toString(), new RegExp(`^${wildcardTransformer("a*")}$`).toString()); 178 assert.equal(universalReservedToplevelNames[1].toString(), new RegExp(`^${wildcardTransformer("*shoul?keep*")}$`).toString()); 179 assert.equal(universalReservedProperties[0].toString(), new RegExp(`^${wildcardTransformer("prop?")}$`).toString()); 180 assert.equal(universalReservedProperties[2].toString(), new RegExp(`^${wildcardTransformer("*pro?")}$`).toString()); 181 assert.equal(universalReservedProperties[1].toString(), new RegExp(`^${wildcardTransformer("function*")}$`).toString()); 182 }); 183 184 it('Tester: test case for ArkObfuscator.ini', function (){ 185 let configPath = "test/ut/arkobfuscator/iniTestObfConfig.json" 186 let obfuscator: ArkObfuscator = new ArkObfuscator(); 187 let config = FileUtils.readFileAsJson(configPath) as IOptions; 188 obfuscator.init(config); 189 let reservedTopelevelNames = config.mNameObfuscation?.mReservedToplevelNames; 190 let reservedProperty = config.mNameObfuscation?.mReservedProperties; 191 let universalReservedToplevelNames = config.mNameObfuscation?.mUniversalReservedToplevelNames; 192 let universalReservedProperties = config.mNameObfuscation?.mUniversalReservedProperties; 193 assert.isTrue(reservedTopelevelNames?.includes("func2")); 194 assert.isTrue(reservedTopelevelNames?.includes("a*")); 195 assert.isTrue(reservedTopelevelNames?.includes("*shoul?keep*")); 196 assert.isTrue(reservedProperty?.includes("prop")); 197 assert.isTrue(reservedProperty?.includes("prop?")); 198 assert.isTrue(reservedProperty?.includes("*pro?")); 199 assert.isTrue(reservedProperty?.includes("function*")); 200 assert.equal(universalReservedToplevelNames, undefined); 201 assert.equal(universalReservedProperties, undefined); 202 }); 203 204 it('Tester: test case for use default preset language whitelist', function (){ 205 let obfuscator: ArkObfuscator = new ArkObfuscator(); 206 let config: IOptions = { 207 "mNameObfuscation": { 208 "mEnable": true, 209 "mNameGeneratorType": 1, 210 "mDictionaryList": [], 211 "mRenameProperties": true, 212 "mReservedProperties": [], 213 "mKeepStringProperty": false, 214 "mTopLevel": true, 215 "mReservedToplevelNames": [] 216 }, 217 "mEnableSourceMap": false, 218 "mEnableNameCache": false, 219 "mStripLanguageDefaultWhitelist": false 220 }; 221 222 obfuscator.init(config); 223 let languageSet: Set<string> = new Set(); 224 let presetLanguageWhitelist = esInfo; 225 for (const key of Object.keys(presetLanguageWhitelist)) { 226 const valueArray = presetLanguageWhitelist[key]; 227 valueArray.forEach((element: string) => { 228 languageSet.add(element); 229 }); 230 } 231 expect(languageSet).to.deep.equal(UnobfuscationCollections.reservedLangForProperty); 232 }); 233 234 it('Tester: test case for use optimized preset language whitelist', function (){ 235 let obfuscator: ArkObfuscator = new ArkObfuscator(); 236 let config: IOptions = { 237 "mNameObfuscation": { 238 "mEnable": true, 239 "mNameGeneratorType": 1, 240 "mDictionaryList": [], 241 "mRenameProperties": true, 242 "mReservedProperties": [], 243 "mKeepStringProperty": false, 244 "mTopLevel": true, 245 "mReservedToplevelNames": [] 246 }, 247 "mEnableSourceMap": false, 248 "mEnableNameCache": false, 249 "mStripLanguageDefaultWhitelist": true 250 }; 251 252 obfuscator.init(config); 253 let languageSet: Set<string> = new Set(); 254 let presetLanguageWhitelist = optimizeEsInfo; 255 for (const key of Object.keys(presetLanguageWhitelist)) { 256 const valueArray = presetLanguageWhitelist[key]; 257 valueArray.forEach((element: string) => { 258 languageSet.add(element); 259 }); 260 } 261 expect(languageSet).to.deep.equal(UnobfuscationCollections.reservedLangForProperty); 262 }); 263 }); 264}); 265 266function compareStringsIgnoreNewlines(str1: string, str2: string): boolean { 267 const normalize = (str: string) => str.replace(/[\n\r\s]+/g, ''); 268 return normalize(str1) === normalize(str2); 269}