README-cn.md
1# Arkguard
2Arkguard 是Javascript和Typescript的源码混淆工具。
3
4# 在DevEco Studio中的用法
5Arkguard已经被集成了到SDK中。可以在DevEco Studio中很方便地使用。Arkguard只能用于Stage模型
6(不支持FA模型)。目前Arkguard只提供名称混淆的能力(因为其它混淆能力会劣化性能)。
7使用Arkguard可以混淆以下名称:
8* 参数名和局部变量名
9* 顶层作用域的名称
10* 属性名称
11
12Arkguard默认使能对参数名和局部变量名的混淆。顶层作用域名称和属性名称的混淆是默认关闭的,
13因为默认打开可能会导致运行时错误。你可以通过[混淆选项](#混淆选项)来开启它们。
14
15创建一个新工程的时候,配置文件`build-profile.json5`中会自动生成以下内容:
16```
17"arkOptions": {
18 "obfuscation": {
19 "ruleOptions": {
20 "enable": true,
21 "files": ["obfuscation-rules.txt"],
22 }
23 }
24}
25```
26创建一个新的library的时候,还会额外生成`consumerFiles`属性:
27```
28"arkOptions": {
29 "obfuscation": {
30 "ruleOptions": {
31 "enable": true,
32 "files": ["obfuscation-rules.txt"],
33 }
34 "consumerFiles": ["consumer-rules.txt"]
35 }
36}
37```
38
39要想开启混淆,需要满足下面的条件:
40* 属性`ruleOptions.enable`的值为`true`,并且所有依赖的library的`ruleOptions.enable`属性是`true`
41* 在release模式构建
42
43属性`ruleOptions.files`中指定的混淆配置文件会在构建HAP或HAR的时候被应用。
44
45属性`consumerFiles`中指定的混淆配置文件会在构建依赖这个library的工程或library时被应用。
46这些混淆配置文件的内容还会被合并到HAR包中的`obfuscation.txt`文件。
47
48当构建HAP或者HAR的时候,最终的混淆规则是自身的`ruleOptions.files`属性,依赖的library的`consumerFiles`属性,
49以及依赖的HAR包中的`obfuscation.txt`文件的合并。如果构建的是HAR,`obfuscation.txt`是自身的`consumerFiles`属性,
50依赖的library的`consumerFiles`属性,以及依赖的HAR包中的`obfuscation.txt`文件的合并。
51构建HAP不会生成`obfuscation.txt`。详细合并的策略可以查看[混淆规则合并策略](#混淆规则合并策略)。
52
53## 配置混淆规则
54在创建工程或library的时候,DevEco Studio会自动生成`obfuscation-rules.txt`和`consumer-rules.txt`文件,
55但是它们默认不会包含任何混淆规则。你可以在这些文件中写混淆规则,或者也可以将规则写在其它文件,
56然后将文件路径放到`ruleOptions.files`和`consumerFiles`中,如下面的例子所示。
57```
58"buildOption": {
59 "arkOptions": {
60 "obfuscation": {
61 "ruleOptions": {
62 "enable": true,
63 "files": ["obfuscation-rules.txt", "myrules.txt"],
64 }
65 "consumerFiles": ["consumer-rules.txt", "my-consumer-rules.txt"]
66 }
67 }
68}
69```
70
71在混淆规则文件中,你可以写[混淆选项](#混淆选项)和[保留选项](#保留选项)。
72
73### 混淆选项
74
75`-disable-obfuscation`
76
77关闭所有混淆。如果你使用这个选项,那么构建出来的HAP或HAR将不会被混淆。默认情况下,
78Arkguard只混淆参数名和局部变量名(通过将它们重新命名为随机的短名字)。
79
80`-enable-property-obfuscation`
81
82开启属性混淆。 如果你使用这个选项,那么所有的属性名都会被混淆,除了下面场景:
83* 被`import/export`直接导入或导出的类或对象的属性名不会被混淆。比如下面例子中的属性名`data`不会被混淆。
84 ```
85 export class MyClass {
86 data: string;
87 }
88 ```
89 对于间接导出的场景,比如`export MyClass`和`let a = MyClass; export {a};`,如果你不想混淆它们的属性名,那么你需要使用[保留选项](#保留选项)来保留这些属性名。另外,对于直接导出的类或对象的属性的属性名,比如下面例子中的`name`和`age`, 如果你不想混淆它们,那么你也需要使用[保留选项](#保留选项)来保留这些属性名。
90 ```
91 export class MyClass {
92 person = {name: "123", age: 100};
93 }
94 ```
95* ArkUI组件中的属性名不会被混淆。比如下面例子中的`message`和`data`不会被混淆。
96 ```
97 @Component struct MyExample {
98 @State message: string = "hello";
99 data: number[] = [];
100 ...
101 }
102 ```
103* 被[保留选项](#保留选项)指定的属性名不会被混淆。
104* 系统API列表中的属性名不会被混淆。系统API列表是构建时从SDK中自动提取出来的一个名称列表,其缓存文件为systemApiCache.json,路径为工程目录下build/cache/{...}/release/obfuscation中
105* 在Native API场景中,在so的d.ts文件中声明的API不会被混淆。
106* 字符串字面量属性名不会被混淆。比如下面例子中的`"name"`和`"age"`不会被混淆。
107 ```
108 let person = {"name": "abc"};
109 person["age"] = 22;
110 ```
111 如果你想混淆字符串字面量属性名,你需要在该选项的基础上再使用`-enable-string-property-obfuscation`选项。比如
112 ```
113 -enable-property-obfuscation
114 -enable-string-property-obfuscation
115 ```
116 **注意**:
117 **1.** 如果代码里面有字符串属性名包含特殊字符(除了`a-z, A-Z, 0-9, _`之外的字符),比如`let obj = {"\n": 123, "": 4, " ": 5}`,建议不要开启`-enable-string-property-obfuscation`选项,因为当不想混淆这些名字时,可能无法通过[保留选项](#保留选项)来指定保留这些名字。
118 **2.** 系统API的属性白名单中不包含声明文件中使用的字符串常量值,比如示例中的字符串'ohos.want.action.home'不被包含在属性白名单中
119 ```
120 // 系统API文件@ohos.app.ability.wantConstant片段:
121 export enum Params {
122 ACTION_HOME = 'ohos.want.action.home'
123 }
124 // 开发者源码示例:
125 let params = obj['ohos.want.action.home'];
126 ```
127 因此在开启了`-enable-string-property-obfuscation`选项时,如果想保留代码中使用的系统API字符串常量的属性不被混淆,比如obj['ohos.want.action.home'], 那么需要使用keep选项保留。
128
129`-enable-toplevel-obfuscation`
130
131开启顶层作用域名称混淆。如果你使用这个选项,那么所有的顶层作用域的名称都会被混淆,除了下面场景:
132* 被`import/export`的名称不会被混淆。
133* 当前文件找不到声明的名称不会被混淆。
134* 被[保留选项](#保留选项)指定的顶层作用域名称不会被混淆。
135* 系统API列表中的顶层作用域名称不会被混淆。
136
137`-enable-filename-obfuscation`
138
139开启文件/文件夹名称混淆。这个选项只在闭源HAR场景下生效,如果你使用这个选项,那么闭源HAR所有的文件/文件夹名称都会被混淆,除了下面场景:
140* oh-package.json5文件中'main'、'types'字段配置的文件/文件夹名称不会被混淆。
141* 模块内module.json5文件中'srcEntry'字段配置的文件/文件夹名称不会被混淆。
142* 被[保留选项](#keep-file-name-link)指定的文件/文件夹名称不会被混淆。
143* 非ECMAScript模块引用方式(ECMAScript模块示例:`import {foo} from './filename'`)
144* 非路径引用方式,比如例子中的json5不会被混淆 `import module from 'json5'`
145
146`-compact`
147
148去除不必要的空格符和所有的换行符。如果使用这个选项,那么所有代码会被压缩到一行。
149**注意**:release模式构建的应用栈信息仅包含代码行号,不包含列号,因此compact功能开启后无法依据报错栈中的行号定位到源码具体位置。
150
151`-remove-log`
152
153删除以下场景中对 console.* 语句的调用,要求console.*语句返回值未被调用。
1541. 文件顶层的调用
1552. 代码块Block中的调用
1563. 模块Module中的调用
1574. switch语句中的调用
158
159`-print-namecache` filepath
160
161将名称缓存保存到指定的文件路径。名称缓存包含名称混淆前后的映射。
162注意:每次全量构建工程时都会生成新的namecache.json文件,因此您每次发布新版本时都要注意保存一个该文件的副本。
163
164`-apply-namecache` filepath
165
166复用指定的名称缓存文件。名字将会被混淆成缓存映射对应的名字,如果没有对应,将会被混淆成新的随机段名字。
167该选项应该在增量编译场景中被使用。
168
169默认情况下,DevEco Studio会在临时的缓存目录中保存缓存文件,并且在增量编译场景中自动应用该缓存文件。
170缓存目录:build/cache/{...}/release/obfuscation
171
172`-remove-comments`
173
174删除文件中的所有注释,包括单行、多行,及JsDoc注释。以下场景除外:
175声明文件中,在`-keep-comments`中配置的类、方法、struct、枚举等名称上方的JsDoc注释。
176**注意**:编译生成的源码文件中的注释默认会被全部删除,不支持配置保留。
177### 保留选项
178
179#### `-keep-property-name` [,identifiers,...]
180指定你想保留的属性名。比如下面的例子:
181```
182-keep-property-name
183age
184firstName
185lastName
186```
187**注意**:该选项在开启`-enable-property-obfuscation`时生效
188
189`-keep-comments`
190保留声明文件中元素上方的JsDoc注释。比如想保留声明文件中Human类上方的JsDoc注释,可进行以下配置:
191```
192-keep-comments
193Human
194```
195**注意**:
1961. 该选项在开启`-remove-comments`时生效
1972. 当声明文件中某个元素名称被混淆时,该元素上方的JsDoc注释无法通过`-keep-comments`保留。比如当在`-keep-comments`中配置了
198exportClass时,如果下面的类名被混淆,其JsDoc注释无法被保留:
199```
200/**
201** @class exportClass
202*/
203export class exportClass {}
204```
205
206**哪些属性名应该被保留?**
207
208为了保障混淆的正确性,我们建议你保留所有不通过点语法访问的属性。
209
210例子:
211```
212var obj = {x0: 0, x1: 0, x2: 0};
213for (var i = 0; i <= 2; i++) {
214 console.log(obj['x' + i]); // x0, x1, x2 应该被保留
215}
216
217Object.defineProperty(obj, 'y', {}); // y 应该被保留
218console.log(obj.y);
219
220obj.s = 0;
221let key = 's';
222console.log(obj[key]); // s 应该被保留
223
224obj.u = 0;
225console.log(obj.u); // u 可以被正确地混淆
226
227obj.t = 0;
228console.log(obj['t']); // 在开启字符串字面量属性名混淆时t和't'会被正确地混淆,但是我们建议保留
229
230obj['v'] = 0;
231console.log(obj['v']); // 在开启字符串字面量属性名混淆时'v'会被正确地混淆,但是我们建议保留
232```
233在Native API场景中,没有在so的d.ts文件中声明的API,如果要在ets/ts/js文件中使用需要手动保留。
234
235
236`-keep-global-name` [,identifiers,...]
237
238指定要保留的顶层作用域的名称。比如,
239```
240-keep-global-name
241Person
242printPersonName
243```
244
245**哪些顶层作用域的名称应该被保留?**
246
247在Javascript中全局变量是`globalThis`的属性。如果在代码中使用`globalThis`去访问全局变量,那么该变量名应该被保留。
248
249例子:
250```
251var a = 0;
252console.log(globalThis.a); // a 应该被保留
253
254function foo(){}
255globalThis.foo(); // foo 应该被保留
256
257var c = 0;
258console.log(c); // c 可以被正确地混淆
259
260function bar(){}
261bar(); // bar 可以被正确地混淆
262
263class MyClass {}
264let d = new MyClass(); // MyClass 可以被正确地混淆
265```
266
267<a id="keep-file-name-link">`-keep-file-name` [,identifiers,...]</a>
268
269指定要保留的文件/文件夹的名称(不需要写文件后缀)。比如,
270```
271-keep-file-name
272index
273entry
274```
275**哪些文件名应该被保留?**
276```
277const module1 = require('./file1') // ARKTs不支持CommonJS语法,这种路径引用应该被保留
278const moduleName = './file2'
279const module2 = import(moduleName) // 动态引用方式无法识别moduleName是否是路径,应该被保留
280```
281
282`-keep-dts` filepath
283
284保留指定路径的`.d.ts`文件中的名称。这里的文件路径可以是一个目录,这种情况下目录中所有`.d.ts`文件中的名称都会被保留。
285如果在构建HAR时使用了这个选项,那么文件中的名称会被合并到最后的`obfuscation.txt`文件中。
286
287### 注释
288
289可以使用`#`在混淆规则文件中进行注释。每行以`#`开头的文本会被当做是注释,比如下面的例子:
290```
291# white list for MainAbility.ets
292-keep-global-name
293MyComponent
294GlobalFunction
295
296-keep-property-name # white list for dynamic property names
297firstName
298lastName
299age
300```
301构建HAR时,注释不会被合并到最后的`obfuscation.txt`文件中。
302
303### 混淆规则合并策略
304一个工程中经常会有许多混淆规则文件,这些文件来自于:
305* 主工程的`ruleOptions.files` (这里主工程我们指的是正在构建的工程)
306* 本地依赖的library中的`consumerFiles`选项中指定的文件
307* 远程依赖的HAR包中的`obfuscate.txt`文件
308
309当构建主工程的时候,这些文件中的混淆规则会按照下面的合并策略(伪代码)进行合并:
310```
311let `listRules` 表示上面提到的所有混淆规则文件的列表
312let finalRule = {
313 disableObfuscation: false,
314 enablePropertyObfuscation: false,
315 enableToplevelObfuscation: false,
316 compact: false,
317 removeLog: false,
318 keepPropertyName: [],
319 keepGlobalName: [],
320 keepDts: [],
321 printNamecache: string,
322 applyNamecache: string
323}
324for each file in `listRules`:
325 for each option in file:
326 switch(option) {
327 case -disable-obfuscation:
328 finalRule.disableObfuscation = true;
329 continue;
330 case -enable-property-obfuscation:
331 finalRule.enablePropertyObfuscation = true;
332 continue;
333 case -enable-toplevel-obfuscation:
334 finalRule.enableToplevelObfuscation = true;
335 continue;
336 case -compact:
337 finalRule.compact = true;
338 continue;
339 case -remove-log:
340 finalRule.removeLog = true;
341 continue;
342 case -print-namecache:
343 finalRule.printNamecache = #{指定的路径名};
344 continue;
345 case -apply-namecache:
346 finalRule.applyNamecache = #{指定的路径名};
347 continue;
348 case -keep-property-name:
349 finalRule.keepPropertyName.push(#{指定的名称});
350 continue;
351 case -keep-global-name:
352 finalRule.keepGlobalName.push(#{指定的名称});
353 continue;
354 case -keep-dts:
355 finalRule.keepDts.push(#{指定的路径});
356 continue;
357 }
358 end-for
359end-for
360```
361最后使用的混淆规则来自于对象`finalRule`。
362
363如果构建的是HAR,那么最终的`obfuscate.txt`文件内容来自于主工程和本地依赖的library的`consumerFiles`选项,
364以及依赖的HAR的`obfuscate.txt`文件的合并。合并策略和上面一样,除了以下的不同:
365* `-keep-dts`选项会被转换成`-keep-global-name`和`-keep-property-name`。
366* `-print-namecache`和`apply-namecache`选项会被忽略,不会出现在最后的`obfuscate.txt`文件中。
367
README.md
1# Arkguard
2Arkguard is a javascript and typescript obfuscation tool.
3For Chinese version please read [README-cn.md](README-cn.md)
4(中文版说明请查看[README-cn.md](README-cn.md)).
5
6# Usage in DevEco Studio
7Arkguard has been integrated into SDK. It is convenient to use Arkguard in DevEco Studio.
8In DevEco Studio, Arkguard can be enabled only in Stage Model (FA Model is not supported).
9For now only name obfuscations can be used in DevEco Studio (because other obfuscation
10abilities of Arkguard may hurt execution performance).
11You can obfuscate the following names:
12* parameter names and local variable names
13* names in global scope
14* property names
15
16We enable the obfuscation of parameter names and local variable names by default. However,
17global names obfuscation and property names obfuscation are disabled by default, as they may
18cause runtime error if they are enabled by default.
19You can enable them by [obfuscation options](#obfuscation-options).
20
21When you create a new project, the following config will be generated in `build-profile.json5`.
22```
23"arkOptions": {
24 "obfuscation": {
25 "ruleOptions": {
26 "enable": true,
27 "files": ["obfuscation-rules.txt"],
28 }
29 }
30}
31```
32When you create a new library, additional property `consumerFiles` will be added.
33```
34"arkOptions": {
35 "obfuscation": {
36 "ruleOptions": {
37 "enable": true,
38 "files": ["obfuscation-rules.txt"],
39 }
40 "consumerFiles": ["consumer-rules.txt"]
41 }
42}
43```
44
45To enable obfuscation, the following conditions should be satisfied:
46* the property `ruleOptions.enable` is `true` and the property `ruleOptions.enable` of every dependent library is `true`.
47* build in release mode
48
49The files in the property `ruleOptions.files` will be applied when you build HAP or HAR.
50
51The files in the property `consumerFiles` will be applied when you build the project or library which
52depends on this library. They will also be merged into a file `obfuscation.txt` in the resulting HAR.
53
54When you are building HAP or HAR, the final obfucation rules are combination of self's `ruleOptions.files`
55property, dependent libraries' `consumerFiles` properties and dependent HAR's `obfuscation.txt`.
56If you are building HAR, the content of `obfuscation.txt` is the combination of self's `consumerFiles` property,
57dependent libraries' `consumerFiles` properties and dependent HAR's `obfuscation.txt`. If you are building
58HAP, `obfuscation.txt` will not be generated. For more details, please jump to
59"[How Arkguard merges rules](#how-arkguard-merges-rules)".
60
61## Write rules
62
63The files `obfuscation-rules.txt` and `consumer-rules.txt` are created by DevEco Studio automatically, but they do not
64contain any rule by default. You can write rules in these files or include rules from other files, as the following
65example shows.
66```
67"buildOption": {
68 "arkOptions": {
69 "obfuscation": {
70 "ruleOptions": {
71 "enable": true,
72 "files": ["obfuscation-rules.txt", "myrules.txt"],
73 }
74 "consumerFiles": ["consumer-rules.txt", "my-consumer-rules.txt"]
75 }
76 }
77}
78```
79
80In rule files, you can write [obfuscation options](#obfuscation-options) and [keep options](#keep-options).
81
82### Obfuscation options
83
84`-disable-obfuscation`
85
86Specifies to disable all obfuscations. If you use this option, the resulting HAP or HAR will not be obfuscated. By default,
87Arkguard only obfuscates the parameter names and local variable names by assigning random short names to them.
88
89`-enable-property-obfuscation`
90
91Specifies to obfuscate the property names. If you use this option, all property names will be obfuscated except the
92following:
93* the property names of classes or objects directly imported or exported by `import/export` will be kept. For example, the property name `data` in
94 ```
95 export class MyClass {
96 data: string;
97 }
98 ```
99 will not be obfuscated.
100For 'indirectly export' cases such as `export MyClass` and `let a = MyClass; export {a};`, if you do not want to obfuscate
101their property names, you need to use [keep options](#keep-options) to keep them. Besides, for the property names of properties of directly exported classes or objects, like `name` and `age` in the following example, if you do not want to obfuscate them, then you also need [keep options](#keep-options) to keep them.
102 ```
103 export class MyClass {
104 person = {name: "123", age: 100};
105 }
106 ```
107* the property names defined in UI components. For example, the property names `message` and `data` in
108 ```
109 @Component struct MyExample {
110 @State message: string = "hello";
111 data: number[] = [];
112 ...
113 }
114 ```
115 will not be obfuscated.
116* the property names that are specified by [keep options](#keep-options).
117* the property names in system API list. System API list is a name set which is extracted from SDK automatically by default. The cache file is systemApiCache.json, and the path is build/cache/{...}/release/obfuscation in the module directory.
118* in the Native API scenario, the APIs in the d.ts file of so library will not be obfuscated.
119* the property names that are string literals. For example, the property names "name" and "age" in the following code will not be obfuscated.
120 ```
121 let person = {"name": "abc"};
122 person["age"] = 22;
123 ```
124 If you want to obfuscate these string literal property names, you should addtionally use the option `-enable-toplevel-obfuscation`. For example,
125 ```
126 -enable-property-obfuscation
127 -enable-string-property-obfuscation
128 ```
129 **Note**:
130 **1.** If there are string literal property names which contain special characters (that is, all characters except
131 `a-z, A-Z, 0-9, _`, for example `let obj = {"\n": 123, "": 4, " ": 5}` then we would not suggest to enable the
132 option `-enable-string-property-obfuscation`, because [keep options](#keep-options) may not allow to keep these
133 names when you do not want to obfuscate them.
134 **2.** The property white list of the system API does not include the string constant in the declaration file. For example, the string `'ohos.want.action.home'` in the example is not included in the white list.
135 ```
136 // System Api @ohos.app.ability.wantConstant snippet:
137 export enum Params {
138 DLP_PARAM_SANDBOX = 'ohos.dlp.param.sandbox'
139 }
140 // Developer source example:
141 let params = obj['ohos.want.action.home'];
142 ```
143 Therefore, when `-enable-string-property-obfuscation` is enabled, if you don't want to obfuscate the property like `'ohos.dlp.param.sandbox'`, which is a string constant in system api. you should keep it manually.
144
145Specifies to obfuscate the names in the global scope. If you use this option, all global names will be obfuscated
146except the following:
147* the `import/export` global names.
148* the global names that are not declared in the current file.
149* the global names that are specified by [keep options](#keep-options).
150* the global names in system API list.
151
152`-enable-filename-obfuscation`
153
154Specifies to obfuscate the file/folder names. This option only takes effect in OpenHarmony Archive(HAR) scenarios. If you use this option, all file/folder names will be obfuscated except the following:
155* the file/folder names configured in the 'main' and 'types' fields in the oh-package.json5.
156* the file/folder names configured in the 'srcEntry' field in the module.json5.
157* the file/folder names that are specified by [keep options](#keep-file-name-link).
158* non-ECMAScript module reference (ECMAScript module example: `import {foo} from './filename'`)
159* non-path reference, such as json5 will not be obfuscated `import module from 'json5'`
160
161`-compact`
162
163Specifies to remove unnecessary blank spaces and all line feeds. If you use this option, all code will be compressed into
164one line.
165**Note**: The stack information in release mode only includes the line number of code, not the column number. Therefore, when the compact is enabled, the specific location of the source code cannot be located based on the line number of stack information.
166
167`-remove-log`
168
169Delete the expressions involving direct calls to console.* statements in the following scenarios:
1701. Calls at the toplevel level of a file.
1712. Calls within a block.
1723. Calls within a module.
1734. Calls within a switch statement.
174and the return value of console.* should not be called
175
176`-print-namecache` filepath
177
178Specifies to print the name cache that contains the mapping from the old names to new names.
179Note: The namecache.json file will be generated every time the module is fully built, so you should save a copy each time you publish a new version.
180
181`-apply-namecache` filepath
182
183Specifies to reuse the given cache file. The old names in the cache will receive the corresponding new names specified in
184the cache. Other names will receive new random short names. This option should be used in incremental obfuscation.
185
186By default, DevEco Studio will keep and update the namecache file in the temporary cache directory and apply the cache for
187incremental compilation.
188Cache directory: build/cache/{...}/release/obfuscation
189
190`-remove-comments`
191
192Remove all comments including single line, multi line and JsDoc comments, in a project except:
193* Those names of JsDoc comments above class, function, struct, enum ... in declaration files are in `-keep-comments`.
194**Note**: `-keep-comments` doesn't work for comments in generated source files, which will be deleted.
195### Keep options
196
197#### `-keep-property-name` [,identifiers,...]
198
199Specifies property names that you want to keep. For example,
200```
201-keep-property-name
202age
203firstName
204lastName
205```
206**Note**: This option is avaliable when `-enable-property-obfuscation` is enabled.
207
208`-keep-comments`
209To retain JsDoc comments above elements in declaration files, such as preserving the JsDoc comment above the Human class,
210you can make the following configuration:
211```
212-keep-comments
213Human
214```
215**Note**:
2161. This option is avaliable when `-remove-comments` is enabled.
2172. If the name of an element is obfuscated, the JsDoc comments
218above that element cannot be kept using `-keep-comments`. For example, when you have exportClass in `-keep-comments`,
219you should make sure that the following class will not be obfuscated, or the JsDoc comments above the class will still be removed:
220```
221/**
222** @class exportClass
223*/
224export class exportClass {}
225```
226
227**What property names should be kept?**
228
229For safety, we would suggest keeping all property names that are not accessed through dot syntax.
230
231Example:
232```
233var obj = {x0: 0, x1: 0, x2: 0};
234for (var i = 0; i <= 2; i++) {
235 console.log(obj['x' + i]); // x0, x1, x2 should be kept
236}
237
238Object.defineProperty(obj, 'y', {}); // y should be kept
239console.log(obj.y);
240
241obj.s = 0;
242let key = 's';
243console.log(obj[key]); // s should be kept
244
245obj.u = 0;
246console.log(obj.u); // u can be safely obfuscated
247
248obj.t = 0;
249console.log(obj['t']); // t and 't' can be safely obfuscated when `-enable-string-property-obfuscation`, but we suggest keeping t
250
251obj['v'] = 0;
252console.log(obj['v']); // 'v' can be safely obfuscated when `-enable-string-property-obfuscation`, but we suggest keeping v
253```
254In the native API scenario, if in the ets/ts/js file you want to use APIs that are not declared in d.ts file, you need to keep these APIs.
255
256`-keep-global-name` [,identifiers,...]
257
258Specifies names that you want to keep in the global scope. For example,
259```
260-keep-global-name
261Person
262printPersonName
263```
264
265**What global names should be kept?**
266
267It is known that in javascript the variables in the global scope are properties of `globalThis`. So if in your code
268you access a global variable as a property, then the global name should be kept.
269
270Example:
271```
272var a = 0;
273console.log(globalThis.a); // a should be kept
274
275function foo(){}
276globalThis.foo(); // foo should be kept
277
278var c = 0;
279console.log(c); // c can be safely obfuscated
280
281function bar(){}
282bar(); // bar can be safely obfuscated
283
284class MyClass {}
285let d = new MyClass(); // MyClass can be safely obfuscated
286```
287
288<a id="keep-file-name-link">`-keep-file-name` [,identifiers,...]</a>
289
290Specify the name of files/folders to keep (no need to write the file suffix). for example,
291```
292-keep-file-name
293index
294entry
295```
296**What file names should be kept?**
297```
298const module1 = require('./file1') // ARKTs doesn't support CommonJS, this path reference should be kept.
299const moduleName = './file2'
300const module2 = import(moduleName) // dynamic reference cannot identify whether moduleName is a path and should be retained.
301```
302
303`-keep-dts` filepath
304
305Specifies to keep names in the given `.d.ts` file. Here filepath can be also a directory. If so, then the names in all
306`d.ts` files under the given directory will be kept.
307If your are building HAR with this option, then the kept names will be merged into the resulting `obfuscation.txt`.
308
309### Comments
310
311You can write comments in obfuscation rule file by using `#`. The line begins with `#` is treated as comment.
312For example,
313```
314# white list for MainAbility.ets
315-keep-global-name
316MyComponent
317GlobalFunction
318
319-keep-property-name # white list for dynamic property names
320firstName
321lastName
322age
323```
324If your are building HAR, comments will not be merged into the resulting `obfuscation.txt`.
325
326### How Arkguard merges rules
327Typically there may be serveral rule files in your project. These rule files come from:
328* `ruleOptions.files` in main project (Here by main project we mean the project you are building)
329* `consumerFiles` in local dependent libraries
330* `obfuscate.txt` in remote dependent HARs
331When building your main project, all these rules will be merged by the following strategy (in pseudo code):
332```
333let `listRules` be the list of all rule files that are mentioned above.
334let finalRule = {
335 disableObfuscation: false,
336 enablePropertyObfuscation: false,
337 enableToplevelObfuscation: false,
338 compact: false,
339 removeLog: false,
340 keepPropertyName: [],
341 keepGlobalName: [],
342 keepDts: [],
343 printNamecache: string,
344 applyNamecache: string
345}
346for each file in `listRules`:
347 for each option in file:
348 switch(option) {
349 case -disable-obfuscation:
350 finalRule.disableObfuscation = true;
351 continue;
352 case -enable-property-obfuscation:
353 finalRule.enablePropertyObfuscation = true;
354 continue;
355 case -enable-toplevel-obfuscation:
356 finalRule.enableToplevelObfuscation = true;
357 continue;
358 case -compact:
359 finalRule.compact = true;
360 continue;
361 case -remove-log:
362 finalRule.removeLog = true;
363 continue;
364 case -print-namecache:
365 finalRule.printNamecache = #{specified path};
366 continue;
367 case -apply-namecache:
368 finalRule.applyNamecache = #{specified path};
369 continue;
370 case -keep-property-name:
371 finalRule.keepPropertyName.push(#{specified names});
372 continue;
373 case -keep-global-name:
374 finalRule.keepGlobalName.push(#{specified names});
375 continue;
376 case -keep-dts:
377 finalRule.keepDts.push(#{specified file path});
378 continue;
379 }
380 end-for
381end-for
382```
383The final obfuscation rules are in the object `finalRule`.
384
385If you are building HAR, the resulting `obfuscate.txt` are obtained by merging the rules from `consumerFiles` in main
386project and local dependent libraries, and `obfuscate.txt` in remote dependent HARs. The merging strategy is the same
387except:
388* The `-keep-dts` option will be converted to `-keep-global-name` and `-keep-property-name` options in the resulting
389`obfuscate.txt`.
390* The options `-print-namecache` and `apply-namecache` will be omitted and will not appear in the resulting
391`obfuscate.txt`.
392