diff --git a/OAT.xml b/OAT.xml index 4b367e99e643623db481d37410d810620a587119..daadca047a5d8ede81f09a65e8edb7f116ad80be 100644 --- a/OAT.xml +++ b/OAT.xml @@ -60,6 +60,7 @@ Note:If the text contains special characters, please escape them according to th + diff --git a/arkguard/.gitignore b/arkguard/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..c18ed016a7f867069687a82a35d5d592f56c6d30 --- /dev/null +++ b/arkguard/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +lib/ \ No newline at end of file diff --git a/arkguard/.vscode/launch.json b/arkguard/.vscode/launch.json new file mode 100644 index 0000000000000000000000000000000000000000..d365f5d3677a1ce5983754bd4880017617962ce4 --- /dev/null +++ b/arkguard/.vscode/launch.json @@ -0,0 +1,35 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Arkguard Debug", + "program": "--loader=ts-node/esm", + "args": [ + "./src/cli/SecHarmony.ts", + "${workspaceFolder}/test/test.ts", + "--config-path", + "${workspaceFolder}/test/config.json" + ], + "sourceMaps": true, + "smartStep": true, + "console": "integratedTerminal", + "stopOnEntry": true + }, + + { + "type": "node", + "request": "launch", + "name": "Launch Program", + "skipFiles": [ + "/**" + ], + "program": "${workspaceFolder}/lib/ArkObfuscator.js", + "preLaunchTask": "tsc: build - tsconfig.json", + "outFiles": [ + "${workspaceFolder}/lib/**/*.js" + ] + } + ] +} \ No newline at end of file diff --git a/arkguard/LICENSE b/arkguard/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..563750d672e448ef552ceffafa4c43d197493f1b --- /dev/null +++ b/arkguard/LICENSE @@ -0,0 +1,196 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + The "ts2panda\scripts\diagnosticMessages.json" file may contain + some information or content from the following software: + TypeScript + /*! ***************************************************************************** + Copyright (c) Microsoft Corporation. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use + this file except in compliance with the License. You may obtain a copy of the + License at http://www.apache.org/licenses/LICENSE-2.0 + + THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED + WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, + MERCHANTABLITY OR NON-INFRINGEMENT. + + See the Apache Version 2.0 License for specific language governing permissions + and limitations under the License. + ***************************************************************************** */ + Apache License 2.0 \ No newline at end of file diff --git a/arkguard/OAT.xml b/arkguard/OAT.xml new file mode 100644 index 0000000000000000000000000000000000000000..e51df6495fd4c51b3a18868e6d7ba0f3f3522818 --- /dev/null +++ b/arkguard/OAT.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + diff --git a/arkguard/README.md b/arkguard/README.md new file mode 100644 index 0000000000000000000000000000000000000000..ebf73869dbd9e06c60fc0abfca7ab9663ea752c9 --- /dev/null +++ b/arkguard/README.md @@ -0,0 +1,236 @@ +# Arkguard +Arkguard is a javascript and typescript obfuscation tool. + +# Usage in DevEco Studio +Arkguard has been integrated into SDK. It is convenient to use Arkguard in DevEco Studio. +In DevEco Studio, Arkguard can be enabled only in Stage Model (FA Model is not supported). +For now only name obfuscations can be used in DevEco Studio (because other obfuscation +abilities of Arkguard may hurt execution performance). +You can obfuscate the following names: +* parameter names and local variable names +* names in global scope +* property names + +We enable the obfuscation of parameter names and local variable names by default. However, +global names obfuscation and property names obfuscation are disabled by default, as they may +cause runtime error if they are enabled by default. +You can enable them by [obfuscation options](#obfuscation-options). + +When you create a new project, the following config will be generated in `build-profile.json5`. +``` +"buildOption": { + "arkOptions": { + "obfuscation": { + "ruleOptions": { + "enable": true, + "rules": ["obfusation-rules.txt"], + } + } + } +} +``` +When you create a new library, additional property `consumerRules` will be added. +``` +"buildOption": { + "arkOptions": { + "obfuscation": { + "ruleOptions": { + "enable": true, + "rules": ["obfusation-rules.txt"], + } + "consumerRules": ["consumer-rules.txt"] + } + } +} +``` + +To enable obfuscation, the following conditions should be satisfied: +* the property `ruleOptions.enable` is `true` and the property `ruleOptions.enable` of every dependency library is `true`. +* build in release mode + +The rules in the property `ruleOptions.rules` will be applied when you build HAP or HAR. + +The rules in the property `consumerRules` will be applied when you build the project or library which +depends on this library. They will also be merged into a file `obfuscation.txt` in the resulting HAR. + +When you are building HAP or HAR, the final obfucation rules are combination of self's `ruleOptions.rules` +property, dependency libraries' `consumerRules` properties and dependency HAR's `obfuscation.txt`. +If your building HAR, the content of `obfuscation.txt` are the combination of self's `consumerRules` property, +dependency libraries' `consumerRules` properties and dependency HAR's `obfuscation.txt`. If you are building +HAP, `obfuscation.txt` will not be generated. + +## Write rules + +The files `obfusation-rules.txt` and `consumer-rules.txt` are created by DevEco Studio automatically, but they do not +contain any rule by default. You can write rules in these files or include rules from other files, as the following +example shows. +``` +"buildOption": { + "arkOptions": { + "obfuscation": { + "ruleOptions": { + "enable": true, + "rules": ["obfusation-rules.txt", "myrules.txt"], + } + "consumerRules": ["consumer-rules.txt", "my-consumer-rules.txt"] + } + } +} +``` + +In rule files, you can write [obfuscation options](#obfuscation-options) and [keep options](#keep-options). + +### Obfuscation options + +`-disable-obfusation` + +Specifies to disable all obfuscations. If you use this option, the resulting HAP or HAR will not be obfuscated. By default, +Arkguard only obfuscates the parameter names and local variable names by assigning random short names to them. + +`-enable-property-obfuscation` + +Specifies to obfuscate the property names. If you use this option, all property names will be obfuscated except the +following: +* the property names of `import/export` classes or objects. +* the property names defined in UI components. For example, the property names `message` and `data` in + ``` + @Component struct MyExample { + @State message: string = "hello"; + data: number[] = []; + ... + } + ``` + will not be obfuscated. +* the property names that are specified by [keep options](#keep-options). +* the property names in system API list. System API list is a name set which is extracted from SDK automatically by default. + +`-enable-toplevel-obfuscation` + +Specifies to obfuscate the names in the global scope. If you use this option, all global names will be obfuscated +except the following: +* the `import/export` global names. +* the global names that are not declared in the current file. +* the global names that are specified by [keep options](#keep-options). +* the global names in system API list. + +`-compact` + +Specifies to remove unnecessary blank spaces and all line feeds. If you use this option, all code will be compressed into +one line. + +`-remove-log` + +Specifies to remove all `console.*` statements. + +`-print-namecache` filepath + +Specifies to print the name cache that contains the mapping from the old names to new names. The cache will printed to +the given file. If you use `-enable-property-obfuscation` or `-enable-toplevel-obfuscation`, and you want incremental +obfuscation in the future (for example, hot fix), then you should use this option and keep the resulting cache file +carefully. + +`-apply-namecache` filepath + +Specifies to reuse the given cache file. The old names in the cache will receive the corresponding new names specified in +the cache. Other names will receive new random short names. This option should be used in incremental obfuscation. + +By default, DevEco Studio will keep and update the namecache file in the temporary cache directory and apply the cache for +incremental compilation. + +### Keep options + +Keep options are useful only when you use `enable-property-obfuscation` or `enable-toplevel-obfuscation`. + +`-keep-property-name` [,modifiers,...] + +Specifies property names that you want to keep. For example, +``` +-keep-property-name +age +firstName +lastName +``` + +**What property names should be kept?** + +Property obfuscation will not obfuscate the string literals and properties that are accessed dynamically. +So for safety, we would suggest keeping all property names that are accessed dynamically. + +Example: +``` +var obj = {x0: 0, x1: 0, x2: 0}; +for (var i = 0; i < 2; i++) { + console.log(obj['x' + i]); // x0, x1, x2 should be kept +} + +Object.defineProperty(obj, 'y', {}); +console.log(obj.y); // y should be kept + +obj.s = 0; +let key = 's'; +console.log(obj[key]); // s should be kept + +obj.u = 0; +console.log(obj.u); // u can be safely obfuscated + +obj.t = 0; +console.log(obj['t']); // t and 't' can be safely obfuscated, but we suggest keeping t + +obj.['v'] = 0; +console.log(obj['v']); // 'v' can be safely obfuscated, but we suggest keeping v +``` + +`-keep-global-name` [,modifiers,...] + +Specifies names that you want to keep in the global scope. For example, +``` +-keep-global-name +Person +printPersonName +``` + +**What global names should be kept?** + +It is known that in javascript the variables in the global scope are properties of `globalThis`. So if in your code +you access a global variable as a property, then the global name should be kept. + +Example: +``` +var a = 0; +console.log(globalThis.a); // a should be kept + +function foo(){} +globalThis.foo(); // foo should be kept + +var c = 0; +console.log(c); // c can be safely obfuscated + +function bar(){} +bar(); // bar can be safely obfuscated + +class MyClass {} +let d = new MyClass(); // MyClass can be safely obfuscated +``` + +`-keep-dts` filepath + +Specifies to keep names in the given `.d.ts` file. Here filepath can be also a directory. If so, then the names in all +`d.ts` files under the given directory will be kept. +If your are building HAR with this option, then the kept names will be merged into the resulting `obfuscation.txt`. + +### Comments + +You can write comments in rules file by using `#`. For each line, the content beginning with `#` and ending with the +line feed will be treated as comment. For example, +``` +# white list for MainAbility.ets +-keep-global-name +MyComponent +GlobalFunction + +-keep-property-name # white list for dynamic property names +firstName +lastName +age +``` +If your are building HAR, comments will not be merged into the resulting `obfuscation.txt`. \ No newline at end of file diff --git a/arkguard/bin/secharmony b/arkguard/bin/secharmony new file mode 100644 index 0000000000000000000000000000000000000000..ad2d3a2587cad7a9a03354f1a753749526f14a10 --- /dev/null +++ b/arkguard/bin/secharmony @@ -0,0 +1,18 @@ +#!/usr/bin/env node + +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +require("../lib/cli/SecHarmony.js"); \ No newline at end of file diff --git a/arkguard/build_package/arkguard-1.0.0.tgz b/arkguard/build_package/arkguard-1.0.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..d23c627d5838f5c1ebe6885b8a9c43f8beccc6bf Binary files /dev/null and b/arkguard/build_package/arkguard-1.0.0.tgz differ diff --git a/arkguard/package-lock.json b/arkguard/package-lock.json new file mode 100644 index 0000000000000000000000000000000000000000..d01c500b16a836374da1b78c16f7cf97412ffc7e --- /dev/null +++ b/arkguard/package-lock.json @@ -0,0 +1,1184 @@ +{ + "name": "arkguard", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "arkguard", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@ampproject/remapping": "2.2.0", + "commander": "^9.3.0", + "fs-extra": "^10.1.0" + }, + "bin": { + "arkguard": "bin/secharmony" + }, + "devDependencies": { + "@types/chai": "^4.3.1", + "@types/commander": "^2.12.2", + "@types/fs-extra": "^9.0.13", + "@types/mocha": "^9.1.1", + "@types/node": "^17.0.45", + "chai": "^4.3.6", + "mocha": "^10.0.0", + "ts-node": "^10.9.1" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://repo.huaweicloud.com/repository/npm/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://repo.huaweicloud.com/repository/npm/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://repo.huaweicloud.com/repository/npm/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/chai": { + "version": "4.3.5", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/commander": { + "version": "2.12.2", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "*" + } + }, + "node_modules/@types/fs-extra": { + "version": "9.0.13", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/mocha": { + "version": "9.1.1", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "17.0.45", + "dev": true, + "license": "MIT" + }, + "node_modules/acorn": { + "version": "8.8.2", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "dev": true, + "license": "ISC" + }, + "node_modules/camelcase": { + "version": "6.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chai": { + "version": "4.3.7", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^4.1.2", + "get-func-name": "^2.0.0", + "loupe": "^2.3.1", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/check-error": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "9.5.0", + "license": "MIT", + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/create-require": { + "version": "1.1.1", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.3.4", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/decamelize": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-eql": { + "version": "4.1.3", + "dev": true, + "license": "MIT", + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/diff": { + "version": "5.0.0", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/escalade": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "dev": true, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-func-name": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/glob": { + "version": "7.2.0", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/he": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "dev": true, + "license": "ISC" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/loupe": { + "version": "2.3.6", + "dev": true, + "license": "MIT", + "dependencies": { + "get-func-name": "^2.0.0" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "dev": true, + "license": "ISC" + }, + "node_modules/minimatch": { + "version": "5.0.1", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha": { + "version": "10.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.3", + "dev": true, + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pathval": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-node": { + "version": "10.9.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/diff": { + "version": "4.0.2", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/typescript": { + "version": "5.0.4", + "resolved": "https://repo.huaweicloud.com/repository/npm/typescript/-/typescript-5.0.4.tgz", + "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=12.20" + } + }, + "node_modules/universalify": { + "version": "2.0.0", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/workerpool": { + "version": "6.2.1", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "dev": true, + "license": "ISC" + }, + "node_modules/y18n": { + "version": "5.0.8", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "16.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.4", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/arkguard/package.json b/arkguard/package.json new file mode 100644 index 0000000000000000000000000000000000000000..5b3496dd120f0f2ccc6ddf0220a39f059bcf5aa7 --- /dev/null +++ b/arkguard/package.json @@ -0,0 +1,51 @@ +{ + "name": "arkguard", + "version": "1.0.0", + "description": "An obfuscator tools for open harmony apps.", + "bin": { + "arkguard": "bin/secharmony" + }, + "main": "lib/ArkObfuscator.js", + "types": "lib/ArkObfuscator.d.ts", + "scripts": { + "clean": "rm -rf lib/*", + "build": "npm run clean && node node_modules/typescript/lib/tsc.js", + "test": "npm run test:ut && npm run test:grammar", + "test:ut": "node ./node_modules/mocha/bin/mocha --require ts-node/register ./test/ut/**/*.ts", + "test:grammar": "node --loader=ts-node/esm ./src/cli/SecHarmony.ts ./test/grammar --config-path ./scripts/grammarTestConfig.json && node ./scripts/grammarTestScript.js" + }, + "repository": { + "type": "git", + "url": "https://codehub-dg-y.huawei.com/Jotun/secDroid/SecHarmony.git" + }, + "keywords": [ + "obfuscator", + "javascript", + "typescript" + ], + "author": "", + "license": "ISC", + "devDependencies": { + "@types/chai": "^4.3.1", + "@types/commander": "^2.12.2", + "@types/fs-extra": "^9.0.13", + "@types/mocha": "^9.1.1", + "@types/node": "^17.0.45", + "chai": "^4.3.6", + "mocha": "^10.0.0", + "ts-node": "^10.9.1" + }, + "dependencies": { + "commander": "^9.3.0", + "fs-extra": "^10.1.0", + "source-map":"0.7.4" + }, + "files": [ + "bin", + "lib", + "package.json", + "tsconfig.base.json", + "tsconfig.json", + "README.md" + ] +} diff --git a/arkguard/scripts/grammarTestConfig.json b/arkguard/scripts/grammarTestConfig.json new file mode 100644 index 0000000000000000000000000000000000000000..ae6aa84637b7132fdcfc7424a846003eec9cba50 --- /dev/null +++ b/arkguard/scripts/grammarTestConfig.json @@ -0,0 +1,16 @@ +{ + "mCompact": false, + "mRemoveComments": true, + "mOutputDir": "../test/local/", + "mDisableHilog": true, + "mDisableConsole":true, + "mNameObfuscation": { + "mEnable": true, + "mNameGeneratorType": 1, + "mRenameProperties": true, + "mReservedNames": [] + }, + "mEnableSourceMap": true, + "mEnableNameCache": false, + "mTopLevel":true +} \ No newline at end of file diff --git a/arkguard/scripts/grammarTestScript.js b/arkguard/scripts/grammarTestScript.js new file mode 100644 index 0000000000000000000000000000000000000000..9a416b5b74339316f79ae3876eafc18527f28269 --- /dev/null +++ b/arkguard/scripts/grammarTestScript.js @@ -0,0 +1,51 @@ +const fs = require('fs'); +const path = require('path'); +const { execSync } = require('child_process'); + +const testDirectory = path.resolve('./test/local'); + +function runTest(filePath) { + try { + const command = `node ./node_modules/ts-node/dist/bin.js ${filePath}`; + execSync(command); + return true; + } catch (error) { + console.error(`Test case ${filePath} failed:`, error); + return false; + } +} +let successCount = 0; +let failureCount = 0; +const failedFiles = []; + +function runTestsInDirectory(directoryPath) { + const files = fs.readdirSync(directoryPath); + + for (const file of files) { + const filePath = path.join(directoryPath, file); + + if (fs.statSync(filePath).isDirectory()) { + runTestsInDirectory(filePath); + } else if (path.extname(filePath) === '.ts') { + const isSuccess = runTest(filePath); + if (isSuccess) { + successCount++; + } else { + failureCount++; + failedFiles.push(filePath); + } + } + } +} + +runTestsInDirectory(testDirectory); + +console.log('--- Grammar Test Results ---'); +console.log(`Success count: ${successCount}`); +console.log(`Failure count: ${failureCount}`); +if (failureCount > 0) { + console.log('Failed files:'); + for (const failedFile of failedFiles) { + console.log(failedFile); + } +} \ No newline at end of file diff --git a/arkguard/src/ArkObfuscator.ts b/arkguard/src/ArkObfuscator.ts new file mode 100644 index 0000000000000000000000000000000000000000..cf20c9b9594267afef1b7b000cf62c118f7b4f5a --- /dev/null +++ b/arkguard/src/ArkObfuscator.ts @@ -0,0 +1,402 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + createPrinter, + createProgram, + createSourceFile, createTextWriter, + forEachChild, + isIdentifier, + isTypePredicateNode, + ScriptTarget, + transform, + createObfTextSingleLineWriter, +} from 'typescript'; + +import type { + CompilerOptions, + EmitTextWriter, + JSDocReturnTag, + JSDocSignature, + Node, + Printer, + PrinterOptions, + Program, + Signature, + SignatureDeclaration, + SourceFile, + SourceMapGenerator, + TransformationResult, + TransformerFactory, + TypeChecker, + TypeNode +} from 'typescript'; + +import * as fs from 'fs'; +import path from 'path'; +import sourceMap from 'source-map'; + +import type {IOptions} from './configs/IOptions'; +import {FileUtils} from './utils/FileUtils'; +import {TransformerManager} from './transformers/TransformerManager'; +import {getSourceMapGenerator} from './utils/SourceMapUtil'; + +import { + getMapFromJson, + NAME_CACHE_SUFFIX, + PROPERTY_CACHE_FILE, + readCache, writeCache +} from './utils/NameCacheUtil'; +import {ListUtil} from './utils/ListUtil'; +import {needReadApiInfo, getReservedProperties, readProjectProperties} from './common/ApiReader'; +import {ApiExtractor} from './common/ApiExtractor'; +import es6Info from './configs/preset/es6_reserved_properties.json'; + +export const renameIdentifierModule = require('./transformers/rename/RenameIdentifierTransformer'); +export const renamePropertyModule = require('./transformers/rename/RenamePropertiesTransformer'); + +export { getMapFromJson, readProjectProperties }; +export class ArkObfuscator { + // A text writer of Printer + private mTextWriter: EmitTextWriter; + + // A list of source file path + private readonly mSourceFiles: string[]; + + // Path of obfuscation configuration file. + private readonly mConfigPath: string; + + // Compiler Options for typescript,use to parse ast + private readonly mCompilerOptions: CompilerOptions; + + // User custom obfuscation profiles. + private mCustomProfiles: IOptions; + + private mTransformers: TransformerFactory[]; + + private mNeedCollectNarrowFunction: boolean; + + public constructor(sourceFiles?: string[], configPath?: string) { + this.mSourceFiles = sourceFiles; + this.mConfigPath = configPath; + this.mCompilerOptions = {}; + this.mTransformers = []; + } + + /** + * init ArkObfuscator according to user config + * should be called after constructor + */ + public init(config?: any): boolean { + if (!this.mConfigPath && !config) { + return false; + } + + if (this.mConfigPath) { + config = FileUtils.readFileAsJson(this.mConfigPath); + } + + this.mCustomProfiles = config as IOptions; + + + + if (this.mCustomProfiles.mCompact) { + this.mTextWriter = createObfTextSingleLineWriter(); + } else { + this.mTextWriter = createTextWriter('\n'); + } + + if (this.mCustomProfiles.mEnableSourceMap) { + this.mCompilerOptions.sourceMap = true; + } + + + // load transformers + this.mTransformers = TransformerManager.getInstance().loadTransformers(this.mCustomProfiles); + + // check need collect narrow function names + this.mNeedCollectNarrowFunction = this.checkNeedCollectNarrowFunction(); + + if (needReadApiInfo(this.mCustomProfiles)) { + this.mCustomProfiles.mNameObfuscation.mReservedProperties = ListUtil.uniqueMergeList( + this.mCustomProfiles.mNameObfuscation.mReservedProperties, + this.mCustomProfiles.mNameObfuscation.mReservedNames, + es6Info); + } + + return true; + } + + /** + * Obfuscate all the source files. + */ + public async obfuscateFiles() { + if (!path.isAbsolute(this.mCustomProfiles.mOutputDir)) { + this.mCustomProfiles.mOutputDir = path.join(path.dirname(this.mConfigPath), this.mCustomProfiles.mOutputDir); + } + if (this.mCustomProfiles.mOutputDir && !fs.existsSync(this.mCustomProfiles.mOutputDir)) { + fs.mkdirSync(this.mCustomProfiles.mOutputDir); + } + + readProjectProperties(this.mSourceFiles, this.mCustomProfiles); + + this.readPropertyCache(this.mCustomProfiles.mOutputDir); + // support directory and file obfuscate + for (const sourcePath of this.mSourceFiles) { + if (!fs.existsSync(sourcePath)) { + console.error(`File ${FileUtils.getFileName(sourcePath)} is not found.`); + return; + } + + if (fs.lstatSync(sourcePath).isFile()) { + await this.obfuscateFile(sourcePath, this.mCustomProfiles.mOutputDir); + continue; + } + + const dirPrefix: string = FileUtils.getPrefix(sourcePath); + await this.obfuscateDir(sourcePath, dirPrefix); + } + this.producePropertyCache(this.mCustomProfiles.mOutputDir); + } + + /** + * obfuscate directory + * @private + */ + private async obfuscateDir(dirName: string, dirPrefix: string): Promise { + const currentDir: string = FileUtils.getPathWithoutPrefix(dirName, dirPrefix); + const newDir: string = path.join(this.mCustomProfiles.mOutputDir, currentDir); + if (!fs.existsSync(newDir)) { + fs.mkdirSync(newDir); + } + + const fileNames: string[] = fs.readdirSync(dirName); + for (let fileName of fileNames) { + const filePath: string = path.join(dirName, fileName); + if (fs.lstatSync(filePath).isFile()) { + await this.obfuscateFile(filePath, newDir); + continue; + } + + if (fileName === 'node_modules' || fileName === 'oh_modules') { + continue; + } + + await this.obfuscateDir(filePath, dirPrefix); + } + } + + private checkNeedCollectNarrowFunction(): boolean { + return this.mCustomProfiles.mControlFlowFlattening && + this.mCustomProfiles.mControlFlowFlattening.mEnable && + this.mCustomProfiles.mInstructionObfuscation && + this.mCustomProfiles.mInstructionObfuscation.mEnable; + } + + private collectNarrowFunctions(file: string): void { + if (!this.mNeedCollectNarrowFunction) { + return; + } + + let results: Set = new Set(); + + let program: Program = createProgram([file], this.mCompilerOptions); + let checker: TypeChecker = program.getTypeChecker(); + let visit = (node: Node): void => { + if (!node) { + return; + } + + if (isIdentifier(node)) { + let type: Signature = checker.getTypeAtLocation(node).getCallSignatures()[0]; + let declaration: SignatureDeclaration | JSDocSignature = type?.declaration; + let retType: TypeNode | JSDocReturnTag = declaration?.type; + if (retType && isTypePredicateNode(retType)) { + results.add(node.text); + } + } + + forEachChild(node, visit); + }; + + let ast: SourceFile = program.getSourceFile(file); + visit(ast); + + this.mCustomProfiles.mNarrowFunctionNames = [...results]; + } + + private readNameCache(sourceFile: string, outputDir: string): void { + if (!this.mCustomProfiles.mNameObfuscation.mEnable || !this.mCustomProfiles.mEnableNameCache) { + return; + } + + const nameCachePath: string = path.join(outputDir, FileUtils.getFileName(sourceFile) + NAME_CACHE_SUFFIX); + const nameCache: Object = readCache(nameCachePath); + + renameIdentifierModule.historyNameCache = getMapFromJson(nameCache); + } + + private readPropertyCache(outputDir: string): void { + const propertyCachePath: string = path.join(outputDir, PROPERTY_CACHE_FILE); + const propertyCache: Object = readCache(propertyCachePath); + if (!propertyCache) { + return; + } + + if (this.mCustomProfiles.mNameObfuscation.mRenameProperties) { + renamePropertyModule.historyMangledTable = getMapFromJson(propertyCache); + } + } + + private produceNameCache(namecache: any, sourceFile: string, outputDir: string): void { + const nameCachePath: string = path.join(outputDir, FileUtils.getFileName(sourceFile) + NAME_CACHE_SUFFIX); + fs.writeFileSync(nameCachePath, JSON.stringify(namecache, null, 2)); + } + + private producePropertyCache(outputDir: string): void { + if (this.mCustomProfiles.mNameObfuscation.mRenameProperties) { + const propertyCachePath: string = path.join(outputDir, PROPERTY_CACHE_FILE); + writeCache(renamePropertyModule.globalMangledTable, propertyCachePath); + } + } + + async mergeSourcrMap(originMap: sourceMap.RawSourceMap, newMap: sourceMap.RawSourceMap): Promise { + if (!originMap) { + return newMap; + } + if (!newMap) { + return originMap; + } + const originConsumer: sourceMap.SourceMapConsumer = await new sourceMap.SourceMapConsumer(originMap); + const newConsumer: sourceMap.SourceMapConsumer = await new sourceMap.SourceMapConsumer(newMap); + const newMappingList: sourceMap.MappingItem[] = []; + newConsumer.eachMapping((mapping: sourceMap.MappingItem) => { + if (mapping.originalLine == null) { + return; + } + const originalPos = originConsumer.originalPositionFor({line: mapping.originalLine, column: mapping.originalColumn}); + if (originalPos.source == null) { + return; + } + mapping.originalLine = originalPos.line; + mapping.originalColumn = originalPos.column; + newMappingList.push(mapping); + }); + const updatedGenerator: sourceMap.SourceMapGenerator = sourceMap.SourceMapGenerator.fromSourceMap(newConsumer); + updatedGenerator['_file'] = originMap.file; + updatedGenerator['_mappings']['_array'] = newMappingList; + return JSON.parse(updatedGenerator.toString()); + } + + /** + * A Printer to output obfuscated codes. + */ + public createObfsPrinter(): Printer { + // set print options + let printerOptions: PrinterOptions = {}; + if (this.mCustomProfiles.mRemoveComments) { + printerOptions.removeComments = true; + } + return createPrinter(printerOptions); + } + + /** + * Obfuscate single source file + * + * @param sourceFile single source file path + * @param outputDir + */ + public async obfuscateFile(sourceFilePath: string, outputDir: string): Promise { + const fileName: string = FileUtils.getFileName(sourceFilePath); + let suffix: string = FileUtils.getFileExtension(sourceFilePath); + + if ((suffix !== 'js' && suffix !== 'ts') || fileName.endsWith('.d.ts')) { + fs.copyFileSync(sourceFilePath, path.join(outputDir, fileName)); + return; + } + + // Advanced confusion requires calling this function + this.collectNarrowFunctions(sourceFilePath); + + let content: string = FileUtils.readFile(sourceFilePath); + this.readNameCache(sourceFilePath, outputDir); + const mixedInfo: {content: string, sourceMap, nameCache: Map} = await this.obfuscate(content, sourceFilePath); + + if (outputDir) { + fs.writeFileSync(path.join(outputDir, FileUtils.getFileName(sourceFilePath)), mixedInfo.content); + if (this.mCustomProfiles.mEnableSourceMap && mixedInfo.sourceMap) { + fs.writeFileSync(path.join(outputDir, FileUtils.getFileName(sourceFilePath) + '.map'), JSON.stringify(mixedInfo.sourceMap, null, 2)); + } + if (this.mCustomProfiles.mEnableNameCache && this.mCustomProfiles.mEnableNameCache) { + this.produceNameCache(mixedInfo.nameCache, sourceFilePath, outputDir); + } + } + + } + + /** + * Obfuscate ast of a file. + * @param ast ast of a source file + */ + public async obfuscate(content: SourceFile | string, sourceFilePath: string, previousStageSourceMap?: any, + historyNameCache?: Map): Promise { + let ast: SourceFile; + if (typeof content === 'string') { + ast = createSourceFile(sourceFilePath, content, ScriptTarget.ES2015, true); + } + else { + ast = content; + } + + if (ast.statements.length === 0) { + return ast; + } + + if (historyNameCache && this.mCustomProfiles.mNameObfuscation) { + renameIdentifierModule.historyNameCache = historyNameCache; + } + + let transformedResult: TransformationResult = transform(ast, this.mTransformers, this.mCompilerOptions); + ast = transformedResult.transformed[0] as SourceFile; + + // convert ast to output source file and generate sourcemap if needed. + let sourceMapGenerator: SourceMapGenerator = undefined; + if (this.mCustomProfiles.mEnableSourceMap) { + sourceMapGenerator = getSourceMapGenerator(sourceFilePath); + } + + this.createObfsPrinter().writeFile(ast, this.mTextWriter, sourceMapGenerator); + + const result = { content: this.mTextWriter.getText() }; + + if (this.mCustomProfiles.mEnableSourceMap) { + let sourceMapJson = sourceMapGenerator.toJSON(); + sourceMapJson['sourceRoot'] = ''; + sourceMapJson.file = path.basename(sourceFilePath); + if (previousStageSourceMap) { + sourceMapJson = await this.mergeSourcrMap(previousStageSourceMap, sourceMapJson as sourceMap.RawSourceMap); + } + result['sourceMap'] = sourceMapJson; + } + if (this.mCustomProfiles.mEnableNameCache) { + result['nameCache'] = Object.fromEntries(renameIdentifierModule.nameCache); + } + // clear cache of text writer + this.mTextWriter.clear(); + renameIdentifierModule.nameCache.clear(); + return result; + } +} +export {ApiExtractor}; \ No newline at end of file diff --git a/arkguard/src/IObfuscator.ts b/arkguard/src/IObfuscator.ts new file mode 100644 index 0000000000000000000000000000000000000000..712fb10dcdfb0efaee9436529fdd26cfc35dec4f --- /dev/null +++ b/arkguard/src/IObfuscator.ts @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface IObfuscator { + /** + * interface for obfuscating source code + * + * @param code string sequence of source code + */ + obfuscate(code: string): string; + + /** + * interface for obfuscating source file + * + * @param file path of single source file. + */ + obfuscateFile(file: string): string; + + /** + * interface for obfuscating source files; + * + * @param files a list of source files + */ + obfuscateFiles(files: string[]): string[]; +} diff --git a/arkguard/src/cli/SecHarmony.ts b/arkguard/src/cli/SecHarmony.ts new file mode 100644 index 0000000000000000000000000000000000000000..9ec44cfa9f4d8df9eb21827aa3a7bef52deb83d6 --- /dev/null +++ b/arkguard/src/cli/SecHarmony.ts @@ -0,0 +1,62 @@ +#!/usr/bin/env node + +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {program} from 'commander'; +import * as path from 'path'; + +import {ArkObfuscator} from '../ArkObfuscator'; + +/** + * Main Entry of Obfuscation in + */ +const minParametersNum: number = 3; +(function (): void { + if (process.argv.length < minParametersNum) { + console.error('Too few input parameters.'); + console.error('Usage: SecHarmony [input files] [options]'); + return; + } + + initOptionsSetting(); + + let configPath: string = program.opts()?.configPath; + configPath = path.resolve(configPath); + let fileList: Array = []; + program.args.forEach((value) => { + const resolved: string = path.resolve(value); + fileList.push(resolved); + }); + + let obfuscator: ArkObfuscator = new ArkObfuscator(fileList, configPath); + const initSuccess: boolean = obfuscator.init(); + if (!initSuccess) { + console.error('init from config file error.'); + return; + } + + obfuscator.obfuscateFiles(); +})(); + +function initOptionsSetting(): void { + program.name('SecHarmony') + .version('1.0.0') + .description('A tool to obfuscate open harmony application written by Javascript or Typescript.') + .usage('Usage: SecHarmony [input files] [options]') + .option('-v, --version', 'show version information.') + .option('-cp, --config-path ', 'obfuscation configuration for open harmony application.') + .parse(); +} diff --git a/arkguard/src/common/ApiExtractor.ts b/arkguard/src/common/ApiExtractor.ts new file mode 100644 index 0000000000000000000000000000000000000000..9d15871324d52d613011a1b734eeb2e64706bdc5 --- /dev/null +++ b/arkguard/src/common/ApiExtractor.ts @@ -0,0 +1,435 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + createSourceFile, + forEachChild, + isBinaryExpression, + isClassDeclaration, + isEnumDeclaration, + isEnumMember, + isExportAssignment, + isExportDeclaration, + isExportSpecifier, + isFunctionDeclaration, + isInterfaceDeclaration, + isMethodDeclaration, + isMethodSignature, + isModuleDeclaration, + isPropertyDeclaration, + isPropertySignature, + isTypeAliasDeclaration, + isVariableDeclaration, + isVariableStatement, + Node, + ScriptKind, + ScriptTarget, + SyntaxKind +} from 'typescript'; + +import type { + ModifiersArray, + SourceFile +} from 'typescript'; + +import fs from 'fs'; +import path from 'path'; + +export namespace ApiExtractor { + interface KeywordInfo { + hasExport: boolean, + hasDeclare: boolean + } + + export enum ApiType { + API = 1, + COMPONENT = 2, + PROJECTDEPENDENCY = 3, + PROJECT = 4 + } + + let mExportNameList: string[] = []; + let mCurrentExportNameList: string[] = []; + export let mPropertyList: string[] = []; + export let mNameList: string[] = []; + + /** + * filter classes or interfaces with export, default, etc + */ + const getKeyword = function (modifiers: ModifiersArray): KeywordInfo { + let hasExport: boolean = false; + let hasDeclare: boolean = false; + + for (const modifier of modifiers) { + if (modifier.kind === SyntaxKind.ExportKeyword) { + hasExport = true; + } + + if (modifier.kind === SyntaxKind.DeclareKeyword) { + hasDeclare = true; + } + } + + return {hasExport: hasExport, hasDeclare: hasDeclare}; + }; + + /** + * get export name list + * @param astNode + */ + const visitExport = function (astNode): void { + if (isExportAssignment(astNode)) { + if (!mCurrentExportNameList.includes(astNode.expression.getText())) { + mCurrentExportNameList.push(astNode.expression.getText()); + } + + return; + } + + if (astNode.modifiers === undefined) { + return; + } + + let {hasExport, hasDeclare} = getKeyword(astNode.modifiers); + if (!hasExport) { + return; + } + + if (astNode.name) { + if (!mCurrentExportNameList.includes(astNode.name.getText())) { + mCurrentExportNameList.push(astNode.name.getText()); + } + + return; + } + + if (hasDeclare && astNode.declarationList && + !mCurrentExportNameList.includes(astNode.declarationList.declarations[0].name.getText())) { + mCurrentExportNameList.push(astNode.declarationList.declarations[0].name.getText()); + } + }; + + const checkPropertyNeedVisit = function (astNode): boolean { + if (astNode.name && !mCurrentExportNameList.includes(astNode.name.getText())) { + return false; + } + + if (astNode.name === undefined) { + if (astNode.modifiers === undefined) { + return false; + } + let {hasDeclare} = getKeyword(astNode.modifiers); + if (hasDeclare && astNode.declarationList && + !mCurrentExportNameList.includes(astNode.declarationList.declarations[0].name.getText())) { + return false; + } + } + + return true; + }; + + const visitChildNode = function (astNode): void { + if (isClassDeclaration(astNode) || + isInterfaceDeclaration(astNode) || + isEnumDeclaration(astNode) || + isTypeAliasDeclaration(astNode) || + isPropertySignature(astNode) || + isMethodSignature(astNode) || + isFunctionDeclaration(astNode) || + isMethodDeclaration(astNode) || + isPropertyDeclaration(astNode) || + isEnumMember(astNode) || + isExportSpecifier(astNode) || + isVariableDeclaration(astNode)) { + if (astNode.name !== undefined ) { + const name = astNode.name.getText(); + if (!mPropertyList.includes(name)) { + mPropertyList.push(name); + } + if (!mNameList.includes(name)) { + mNameList.push(name); + } + } + } + + astNode.forEachChild((childNode) => { + visitChildNode(childNode); + }); + }; + + /** + * visit ast of a file and collect api list + * @param astNode node of ast + */ + const visitPropertyAndName = function (astNode): void { + if (!checkPropertyNeedVisit(astNode)) { + return; + } + + visitChildNode(astNode); + }; + + const visitProjectNode = function (astNode): void { + if (astNode.modifiers) { + let {hasExport} = getKeyword(astNode.modifiers); + if (!hasExport) { + return; + } + + if (astNode.name !== undefined) { + if (!mPropertyList.includes(astNode.name.getText())) { + mPropertyList.push(astNode.name.getText()); + } + + if (isModuleDeclaration(astNode)) { + astNode.forEachChild((childNode) => { + visitProjectNode(childNode); + }); + } + return; + } + + if (isVariableStatement(astNode)) { + astNode.declarationList.forEachChild((child) => { + if (isVariableDeclaration(child) && !mPropertyList.includes(child.name.getText())) { + mPropertyList.push(child.name.getText()); + } + }); + } + + return; + } + + if (isExportAssignment(astNode)) { + if (isBinaryExpression(astNode.expression)) { + if (!mPropertyList.includes(astNode.expression.left.getText())) { + mPropertyList.push(astNode.expression.left.getText()); + } + } + return; + } + + if (isExportDeclaration(astNode)) { + if (astNode.exportClause && astNode.exportClause.kind === SyntaxKind.NamedExports) { + astNode.exportClause.forEachChild((child) => { + if (!isExportSpecifier(child)) { + return; + } + + if (!mPropertyList.includes(child.name.getText())) { + mPropertyList.push(child.name.getText()); + } + }); + } + + return; + } + + astNode.forEachChild((childNode) => { + visitProjectNode(childNode); + }); + }; + + const visitProjectProperty = function (astNode): void { + visitProjectNode(astNode); + }; + + /** + * parse file to api list and save to json object + * @param fileName file name of api file + * @param apiType + * @private + */ + const parseFile = function (fileName: string, apiType: ApiType): void { + const scriptKind: ScriptKind = fileName.endsWith('.ts') ? ScriptKind.TS : ScriptKind.JS; + const sourceFile: SourceFile = createSourceFile(fileName, fs.readFileSync(fileName).toString(), ScriptTarget.ES2015, true, scriptKind); + + // get export name list + switch (apiType) { + case ApiType.PROJECTDEPENDENCY: + case ApiType.COMPONENT: + forEachChild(sourceFile, visitChildNode); + break; + case ApiType.API: + mCurrentExportNameList.length = 0; + forEachChild(sourceFile, visitExport); + + mCurrentExportNameList.forEach((value) => { + if (!mExportNameList.includes(value)) { + mExportNameList.push(value); + mNameList.push(value); + } + }); + + forEachChild(sourceFile, visitPropertyAndName); + mCurrentExportNameList.length = 0; + break; + case ApiType.PROJECT: + if (fileName.endsWith('.d.ts')) { + forEachChild(sourceFile, visitChildNode); + break; + } + + mCurrentExportNameList.length = 0; + forEachChild(sourceFile, visitProjectProperty); + mCurrentExportNameList.length = 0; + break; + default: + break; + } + }; + + /** + * traverse files of api directory + * @param apiPath api directory path + * @param apiType + * @private + */ + export const traverseApiFiles = function (apiPath: string, apiType: ApiType): void { + let fileNames: string[] = []; + if (fs.lstatSync(apiPath).isDirectory()) { + fileNames = fs.readdirSync(apiPath); + for (let fileName of fileNames) { + let filePath: string = path.join(apiPath, fileName); + if (fs.lstatSync(filePath).isDirectory()) { + if (fileName === 'node_modules' || fileName === 'oh_modules') { + continue; + } + + traverseApiFiles(filePath, apiType); + continue; + } + + if (fs.lstatSync(filePath).isSymbolicLink()) { + filePath = fs.readlinkSync(filePath); + if (fs.lstatSync(filePath).isDirectory()) { + traverseApiFiles(filePath, apiType); + continue; + } + } + + if ((apiType !== ApiType.PROJECT) && !filePath.endsWith('.d.ts')) { + continue; + } + + if (apiType === ApiType.PROJECT && !filePath.endsWith('.ts') && !filePath.endsWith('.js')) { + continue; + } + + parseFile(filePath, apiType); + } + } + else { + parseFile(apiPath, apiType); + } + }; + + /** + * desc: parse openHarmony sdk to get api list + * @param version version of api, e.g. version 5.0.1.0 for api 9 + * @param sdkPath sdk real path of openHarmony + * @param isEts true for ets, false for js + * @param outputDir: sdk api output directory + */ + export function parseOhSdk(sdkPath: string, version: string, isEts: boolean, outputDir: string): void { + mExportNameList.length = 0; + mPropertyList.length = 0; + + // visit api directory + const apiPath: string = path.join(sdkPath, (isEts ? 'ets' : 'js'), version, 'api'); + traverseApiFiles(apiPath, ApiType.API); + + // visit component directory if ets + if (isEts) { + const componentPath: string = path.join(sdkPath, 'ets', version, 'component'); + traverseApiFiles(componentPath, ApiType.COMPONENT); + } + + // visit the UI conversion API + const uiConversionPath: string = path.join(sdkPath, (isEts ? 'ets' : 'js'), version, 'build-tools', 'ets-loader', 'lib', 'pre_define.js'); + extractStringsFromFile(uiConversionPath); + + writeToFile(mExportNameList, path.join(outputDir, 'nameReserved.json')); + writeToFile(mPropertyList, path.join(outputDir, 'propertiesReserved.json')); + mExportNameList.length = 0; + mPropertyList.length = 0; + } + + export function extractStringsFromFile(filePath: string): void { + let collections: string[] = []; + const fileContent = fs.readFileSync(filePath, 'utf-8'); + const regex = /"([^"]*)"/g; + const matches = fileContent.match(regex); + + if (matches) { + collections = matches.map(match => match.slice(1, -1)); + } + + mPropertyList = mPropertyList.concat(collections); + mNameList = mNameList.concat(collections); + } + + /** + * parse common project or file to extract exported api list + * @return reserved api names + */ + export function parseCommonProject(projectPath): string[] { + mPropertyList.length = 0; + + if (fs.lstatSync(projectPath).isFile()) { + if (projectPath.endsWith('.ts') || projectPath.endsWith('.js')) { + parseFile(projectPath, ApiType.PROJECT); + } + } else { + traverseApiFiles(projectPath, ApiType.PROJECT); + } + + const reservedProperties: string[] = [...mPropertyList]; + mPropertyList.length = 0; + + return reservedProperties; + } + + /** + * parse api of third party libs like libs in node_modules + * @param libPath + */ + export function parseThirdPartyLibs(libPath): string[] { + mPropertyList.length = 0; + + if (fs.lstatSync(libPath).isFile()) { + if (libPath.endsWith('.ts') || libPath.endsWith('.js')) { + parseFile(libPath, ApiType.PROJECTDEPENDENCY); + } + } else { + traverseApiFiles(libPath, ApiType.PROJECTDEPENDENCY); + } + + const reservedProperties: string[] = [...mPropertyList]; + mPropertyList.length = 0; + + return reservedProperties; + } + + /** + * save api json object to file + * @private + */ + export function writeToFile(reservedProperties: string[], outputPath: string): void { + let str: string = JSON.stringify(reservedProperties, null, '\t'); + fs.writeFileSync(outputPath, str); + } +} + diff --git a/arkguard/src/common/ApiReader.ts b/arkguard/src/common/ApiReader.ts new file mode 100644 index 0000000000000000000000000000000000000000..3c8542d14f6ff46a2d50dbd7e615b112649ea01f --- /dev/null +++ b/arkguard/src/common/ApiReader.ts @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import path from 'path'; +import fs from 'fs'; +import {FileUtils} from '../utils/FileUtils'; +import {ApiExtractor} from './ApiExtractor'; +import {ListUtil} from '../utils/ListUtil'; +import type {IOptions} from '../configs/IOptions'; +import es6Info from '../configs/preset/es6_reserved_properties.json'; + +/** + * if rename property is not open, api read and extract can be skipped + * + * init plugin, read api info of openHarmony sdk and generate file of reserved name, property and string. + * @param sdkDir absolute path like D:\\HuaweiApp\\ohsdk + * @param outputDir + */ +export function initPlugin(sdkDir: string, outputDir: string): void { + // create sdk api file if not exist + const ohSdkPath: string = path.resolve(sdkDir); + if (!ohSdkPath) { + console.error('SDK path is not found.'); + } + + const apiVersions: string[] = ['']; + + apiVersions.forEach((versionString) => { + ApiExtractor.parseOhSdk(ohSdkPath, versionString, true, outputDir); + }); +} + + +export function getReservedProperties(apiSavedPath?: string): string[] { + let reservedProperties: string[] = []; + if (apiSavedPath) { + reservedProperties = readOhReservedProperties(apiSavedPath); + } + // read language reserved property + reservedProperties = [...reservedProperties, ...es6Info]; + const propertySet: Set = new Set(reservedProperties); + + return Array.from(propertySet); +} + +/** + * read reserved properties of openHarmony sdk + */ +export function readOhReservedProperties(apiSavedPath: string): string[] { + // 1. read oh sdk api reserved property and string + let reservedProperties: string[] = []; + + const sdkApiDir: string = path.resolve(__dirname, apiSavedPath); + const fileNames: string[] = fs.readdirSync(sdkApiDir); + for (const fileName of fileNames) { + const filePath: string = path.join(sdkApiDir, fileName); + if (!fs.lstatSync(filePath).isFile()) { + continue; + } + + const properties: string[] = FileUtils.readFileAsJson(filePath); + if (properties === undefined) { + console.error('read openHarmony reserved property file error.'); + continue; + } + + reservedProperties = [...reservedProperties, ...properties]; + } + return reservedProperties; +} + +/** + * need read api info or not + * @param customProfiles + */ +export function needReadApiInfo(customProfiles: IOptions): boolean { + return customProfiles.mNameObfuscation && + customProfiles.mNameObfuscation.mEnable && + customProfiles.mNameObfuscation.mRenameProperties; +} + +/** + * read project reserved properties + * @param projectPaths can be dir or file + * @param customProfiles + */ +export function readProjectProperties(projectPaths: string[], customProfiles: IOptions): void { + if (!needReadApiInfo(customProfiles)) { + return; + } + + for (const projectPath of projectPaths) { + if (!fs.existsSync(projectPath)) { + console.error(`File ${FileUtils.getFileName(projectPath)} is not found.`); + return; + } + + const projProperties: string[] = ApiExtractor.parseCommonProject(projectPath); + const sdkProperties: string[] = readThirdPartyLibProperties(projectPath); + + // read project code export names + customProfiles.mNameObfuscation.mReservedProperties = ListUtil.uniqueMergeList(projProperties, + customProfiles.mNameObfuscation.mReservedProperties); + + // read project lib export names + if (sdkProperties) { + customProfiles.mNameObfuscation.mReservedProperties = ListUtil.uniqueMergeList(sdkProperties, + customProfiles.mNameObfuscation.mReservedProperties); + } + } +} + +function readThirdPartyLibProperties(projectPath: string): string[] { + let reservedProperties: string[] = []; + + if (!fs.lstatSync(projectPath).isDirectory()) { + return undefined; + } + + // find third party lib and extract reserved names + const fileNames: string[] = fs.readdirSync(projectPath); + const hasNodeModules: boolean = fileNames.includes('node_modules'); + const hasOHModules: boolean = fileNames.includes('oh_modules'); + if (!hasNodeModules && !hasOHModules) { + return undefined; + } + if (hasNodeModules && hasOHModules) { + throw new Error(`There are both node_modules and oh_modules folders in ${projectPath}`); + } + + let filePath: string = ''; + if (hasNodeModules) { + filePath = path.join(projectPath, 'node_modules'); + } + else { + filePath = path.join(projectPath, 'oh_modules'); + } + + const properties: string[] = ApiExtractor.parseThirdPartyLibs(filePath); + reservedProperties = [...reservedProperties, ...properties]; + const propertySet: Set = new Set(reservedProperties); + + return Array.from(propertySet); +} diff --git a/arkguard/src/configs/ArkGuardOptions.ts b/arkguard/src/configs/ArkGuardOptions.ts new file mode 100644 index 0000000000000000000000000000000000000000..ced1afce585109aea81c094a0598825b46ad62d0 --- /dev/null +++ b/arkguard/src/configs/ArkGuardOptions.ts @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type {IOptions} from './IOptions'; + +export interface ArkGuardOptions { + /** + * path of open harmony sdk + */ + sdkPath?: string, + + /** + * api version of open harmony sdk + */ + apiVersion?: string, + + /** + * Protection level specified by user + */ + protectedLevel?: boolean; + + /** + * whether to turn on source map function. + */ + sourceMap?: boolean, + /** + * specify the path of name cache file, use in hot update. + */ + nameCache?: string, + + /** + * output directory for obfuscated results. + */ + outDir?: string, + + /** + * obfuscation options + */ + obfuscations?: IOptions, +} diff --git a/arkguard/src/configs/IBogusControlFlowOption.ts b/arkguard/src/configs/IBogusControlFlowOption.ts new file mode 100644 index 0000000000000000000000000000000000000000..fcc40f24a27178b8248c78e2ec2ed7a89680008b --- /dev/null +++ b/arkguard/src/configs/IBogusControlFlowOption.ts @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Generation type of the inserted block statement + */ +export enum BogusBlockType { + /** + * Use other available block and rename variables in block + */ + OTHER_BLOCK_RENAME = 1, + + /** + * Use a deformation of current block, replaces with some basic operations + */ + CURRENT_BLOCK_DEFORM = 2, +} + +export interface IBogusControlFlowOption { + /** + * Whether to enable bogus control flow obfuscation + */ + readonly mEnable: boolean; + + /** + * Probability of inserting bogus control flow into the target node + */ + readonly mThreshold: number; + + /** + * skip obfuscation in loop for performance + */ + readonly mSkipLoop?: boolean; + + /** + * Whether to use opaque predicates + */ + readonly mUseOpaquePredicate: boolean; + + /** + * Generation type of the inserted bogus block. + */ + readonly mInsertBlockType: BogusBlockType; +} diff --git a/arkguard/src/configs/IControlFlowFatteningOption.ts b/arkguard/src/configs/IControlFlowFatteningOption.ts new file mode 100644 index 0000000000000000000000000000000000000000..d4ead7bc3aef6107fb0e3a1ad0c9c92950d48b58 --- /dev/null +++ b/arkguard/src/configs/IControlFlowFatteningOption.ts @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface IControlFlowFatteningOption { + /** + * Whether to enable control flow obfuscation + */ + readonly mEnable: boolean; + + /** + * Probability of control flow obfuscation + */ + readonly mThreshold: number; + + /** + * skip obfuscation in loop for performance + */ + readonly mSkipLoop?: boolean; + + /** + * advance switch + */ + readonly mAdvance?: boolean; + + /** + * Whether to flatten if statement + */ + readonly mIfFlattening?: boolean; + + /** + * Whether to flatten switch statement + */ + readonly mSwitchFlatting?: boolean; + + /** + * Whether to convert case constants to expression + */ + readonly mCaseToExpression?: boolean; +} diff --git a/arkguard/src/configs/IDataObfuscationOption.ts b/arkguard/src/configs/IDataObfuscationOption.ts new file mode 100644 index 0000000000000000000000000000000000000000..74c1de9a699f582eca614e151cd3a3cecc9bceb9 --- /dev/null +++ b/arkguard/src/configs/IDataObfuscationOption.ts @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type {EncryptType} from '../transformers/data/StringUnit'; + +export interface IBooleanOption { + readonly mEnable: boolean; + + readonly mThreshold: number; + + /** + * skip obfuscation in loop for performance + */ + readonly mSkipLoop: boolean; +} + +export interface INumberOption { + readonly mEnable: boolean; + + readonly mThreshold: number; + + /** + * skip obfuscation in loop for performance + */ + readonly mSkipLoop: boolean; +} + +export interface IStringOption { + + readonly mEnable: boolean; + + readonly mThreshold: number; + + /** + * skip obfuscation in loop for performance + */ + readonly mSkipLoop: boolean; + + readonly mSkipProperty: boolean; + + readonly mSplitString: boolean; + + readonly mStringArray: boolean; + + readonly mStringArrayThreshold: number; + + readonly mEncryptType: EncryptType; + + readonly mStringArrayShuffle: boolean; + + readonly mStringArrayCallsTransform: boolean; + + readonly mStringArrayCallsThreshold: number; + + mReservedStrings: string[]; + + readonly mObfuscationString: string[]; +} + +export interface IDataObfuscationOption { + + readonly mEnable: boolean; + + readonly mNumberOption: INumberOption; + + readonly mStringOption: IStringOption; + + readonly mBooleanOption: IBooleanOption; +} diff --git a/arkguard/src/configs/IHideOhApiOption.ts b/arkguard/src/configs/IHideOhApiOption.ts new file mode 100644 index 0000000000000000000000000000000000000000..ef4ee5389b45971d394c1290b77d639a64c0e0fd --- /dev/null +++ b/arkguard/src/configs/IHideOhApiOption.ts @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface IHideOhApiOption { + readonly mEnable: boolean; + + /** + * openHarmony api list to be hidden, like: + * - @ohos.hilog.info + */ + readonly mProtectedApi: string[]; +} diff --git a/arkguard/src/configs/IInstructionObfuscationOption.ts b/arkguard/src/configs/IInstructionObfuscationOption.ts new file mode 100644 index 0000000000000000000000000000000000000000..e6e6fd458b9097ebe7dfbf22044377e10327b220 --- /dev/null +++ b/arkguard/src/configs/IInstructionObfuscationOption.ts @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export enum InstructionObfsMethod { + /** + * use simple deformation to instruction + */ + SIMPLE_DEFORM = 1, + + /** + * transform instruction to MBA expression + */ + MBA_EXPRESSION = 2, +} + +export interface IInstructionObfuscationOption { + readonly mEnable: boolean; + + readonly mThreshold: number; + + /** + * skip obfuscation in loop for performance + */ + readonly mSkipLoop: boolean; + + readonly mInstructionObfsMethod: InstructionObfsMethod; +} diff --git a/arkguard/src/configs/INameObfuscationOption.ts b/arkguard/src/configs/INameObfuscationOption.ts new file mode 100644 index 0000000000000000000000000000000000000000..6279264c1ed642dfd18cd269275707b199f76d10 --- /dev/null +++ b/arkguard/src/configs/INameObfuscationOption.ts @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type {NameGeneratorType} from '../generator/NameFactory'; + +export interface INameObfuscationOption { + + readonly mEnable: boolean; + + readonly mNameGeneratorType: NameGeneratorType; + + readonly mRenameProperties: boolean; + + readonly mReservedNames: string[]; + + mReservedProperties: string[]; + + readonly mDictionaryList?: string[]; +} diff --git a/arkguard/src/configs/IOptions.ts b/arkguard/src/configs/IOptions.ts new file mode 100644 index 0000000000000000000000000000000000000000..4319bd3c25c9dbdef15e8fbe4270a3a862b2c163 --- /dev/null +++ b/arkguard/src/configs/IOptions.ts @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type {IControlFlowFatteningOption} from './IControlFlowFatteningOption'; +import type {IDataObfuscationOption} from './IDataObfuscationOption'; +import type {IBogusControlFlowOption} from './IBogusControlFlowOption'; +import type {INameObfuscationOption} from './INameObfuscationOption'; +import type {IInstructionObfuscationOption} from './IInstructionObfuscationOption'; +import type {IHideOhApiOption} from './IHideOhApiOption'; + +export interface IOptions { + // Whether to generate compact code + readonly mCompact?: boolean; + + // Whether to remove comments; + readonly mRemoveComments?: boolean; + + // Whether to disable console output + readonly mDisableConsole?: boolean; + + // whether to disable hilog output + readonly mDisableHilog?: boolean; + + // Whether to do code simplification, includes variable declarations merging, expression merging... + readonly mSimplify?: boolean; + + // whether to hide openHarmony api + readonly mHideOhApi?: IHideOhApiOption; + + // Whether to do Name Obfuscation + readonly mNameObfuscation?: INameObfuscationOption; + + // Whether to insert bogus control flow. + readonly mBogusControlFlow?: IBogusControlFlowOption; + + // Whether to do control flow flattening + readonly mControlFlowFlattening?: IControlFlowFatteningOption; + + // Whether to do data obfuscation + readonly mDataObfuscation?: IDataObfuscationOption; + + // Whether to do Instruction obfuscation, includes obfuscating binary expression, logical expression, call expression. + readonly mInstructionObfuscation?: IInstructionObfuscationOption; + + mNarrowFunctionNames?: Array; + + mOutputDir?: string; + + readonly mOhSdkPath?: string; + + readonly mTopLevel?: boolean; + + readonly mEnableSourceMap?: boolean; + + readonly mEnableNameCache?: boolean; + + readonly apiSavedDir?: string; + + readonly applyReservedNamePath?: string; +} diff --git a/arkguard/src/configs/preset/ConfusionTables.ts b/arkguard/src/configs/preset/ConfusionTables.ts new file mode 100644 index 0000000000000000000000000000000000000000..55c907bfb29ae81663241b7628d06ea514be26f3 --- /dev/null +++ b/arkguard/src/configs/preset/ConfusionTables.ts @@ -0,0 +1,1992 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export let table: Object = { + '-': [ + '\u{06d4}', + '\u{2cba}', + '\u{fe58}', + '\u{02d7}', + '\u{2212}', + '\u{2796}', + '\u{2011}', + '\u{2043}', + '\u{2012}', + '\u{2013}', + '\u{2010}' + ], + '.': [ + '\u{0701}', + '\u{0660}', + '\u{2024}', + '\u{06f0}', + '\u{a60e}', + '\u{a4f8}', + '\u{0702}', + '\u{10a50}', + '\u{ff0e}', + '\u{1d16d}' + ], + '0': [ + '\u{1d476}', + '\u{0585}', + '\u{004f}', + '\u{fbaa}', + '\u{1d4aa}', + '\u{06be}', + '\u{1d70e}', + '\u{09e6}', + '\u{0d02}', + '\u{1d4de}', + '\u{fee9}', + '\u{1d630}', + '\u{06c1}', + '\u{1ee24}', + '\u{1d45c}', + '\u{0a66}', + '\u{1d7bc}', + '\u{0c02}', + '\u{10ff}', + '\u{1d490}', + '\u{1d5c8}', + '\u{0d82}', + '\u{ff4f}', + '\u{1d744}', + '\u{0d20}', + '\u{1d5fc}', + '\u{fba6}', + '\u{0c66}', + '\u{102ab}', + '\u{1d11}', + '\u{0665}', + '\u{fbab}', + '\u{1d6d0}', + '\u{1d7b8}', + '\u{118c8}', + '\u{104c2}', + '\u{1d546}', + '\u{ff10}', + '\u{1d442}', + '\u{039f}', + '\u{10292}', + '\u{1d79e}', + '\u{feec}', + '\u{1d7ce}', + '\u{1d782}', + '\u{1d6d4}', + '\u{06f5}', + '\u{fbad}', + '\u{a4f3}', + '\u{feeb}', + '\u{1ee64}', + '\u{118e0}', + '\u{10404}', + '\u{2d54}', + '\u{1d7ec}', + '\u{feea}', + '\u{3007}', + '\u{1040}', + '\u{fba7}', + '\u{1d77e}', + '\u{1d428}', + '\u{0ae6}', + '\u{118b5}', + '\u{1d698}', + '\u{104ea}', + '\u{0ed0}', + '\u{05e1}', + '\u{1d4f8}', + '\u{0647}', + '\u{0c82}', + '\u{0966}', + '\u{0d66}', + '\u{1d7e2}', + '\u{118d7}', + '\u{1d64a}', + '\u{fbac}', + '\u{1d764}', + '\u{1042c}', + '\u{1d748}', + '\u{2134}', + '\u{1d67e}', + '\u{0b66}', + '\u{041e}', + '\u{ab3d}', + '\u{1ee84}', + '\u{1d6f0}', + '\u{1fbf0}', + '\u{0ce6}', + '\u{114d0}', + '\u{1d7d8}', + '\u{06d5}', + '\u{1d70a}', + '\u{1d40e}', + '\u{0b20}', + '\u{0e50}', + '\u{1d52c}', + '\u{1d594}', + '\u{1d616}', + '\u{1d5ae}', + '\u{03c3}', + '\u{043e}', + '\u{12d0}', + '\u{1d57a}', + '\u{1d72a}', + '\u{1d0f}', + '\u{006f}', + '\u{03bf}', + '\u{2c9e}', + '\u{1d560}', + '\u{0555}', + '\u{1d5e2}', + '\u{10516}', + '\u{0be6}', + '\u{07c0}', + '\u{1d6b6}', + '\u{1d664}', + '\u{ff2f}', + '\u{1d512}', + '\u{fba8}', + '\u{fba9}', + '\u{1d7f6}', + '\u{2c9f}', + '\u{101d}' + ], + '1': [ + '\u{1d55d}', + '\u{0049}', + '\u{1d574}', + '\u{1d43c}', + '\u{0196}', + '\u{2d4f}', + '\u{1ee00}', + '\u{a4f2}', + '\u{fe8d}', + '\u{ff4c}', + '\u{1d661}', + '\u{2223}', + '\u{1d6b0}', + '\u{0406}', + '\u{2c92}', + '\u{05c0}', + '\u{1d7ed}', + '\u{1d6ea}', + '\u{ff11}', + '\u{1d610}', + '\u{05df}', + '\u{007c}', + '\u{1d5c5}', + '\u{1d695}', + '\u{ffe8}', + '\u{0661}', + '\u{1d408}', + '\u{1d540}', + '\u{05d5}', + '\u{1d7e3}', + '\u{1d678}', + '\u{16f28}', + '\u{1d5f9}', + '\u{1d4c1}', + '\u{1d7f7}', + '\u{1d724}', + '\u{1d4f5}', + '\u{217c}', + '\u{006c}', + '\u{1d7cf}', + '\u{1d5a8}', + '\u{1d425}', + '\u{04c0}', + '\u{10309}', + '\u{1d5dc}', + '\u{10320}', + '\u{1d459}', + '\u{1e8c7}', + '\u{23fd}', + '\u{0399}', + '\u{01c0}', + '\u{1d529}', + '\u{1d470}', + '\u{1d62d}', + '\u{07ca}', + '\u{ff29}', + '\u{2111}', + '\u{2160}', + '\u{fe8e}', + '\u{1ee80}', + '\u{2113}', + '\u{1028a}', + '\u{1d75e}', + '\u{2110}', + '\u{1d798}', + '\u{1fbf1}', + '\u{1d4d8}', + '\u{06f1}', + '\u{1d48d}', + '\u{1d7d9}', + '\u{1d644}', + '\u{0627}', + '\u{1d591}', + '\u{16c1}' + ], + '2': [ + '\u{a75a}', + '\u{14bf}', + '\u{03e8}', + '\u{1d7ee}', + '\u{a6ef}', + '\u{01a7}', + '\u{1d7da}', + '\u{1d7e4}', + '\u{1fbf2}', + '\u{1d7d0}', + '\u{ff12}', + '\u{a644}', + '\u{1d7f8}' + ], + '3': [ + '\u{1d7e5}', + '\u{a76a}', + '\u{1d7f9}', + '\u{021c}', + '\u{1d206}', + '\u{2ccc}', + '\u{0417}', + '\u{04e0}', + '\u{1d7ef}', + '\u{01b7}', + '\u{ff13}', + '\u{1fbf3}', + '\u{1d7db}', + '\u{1d7d1}', + '\u{16f3b}', + '\u{118ca}', + '\u{a7ab}' + ], + '4': [ + '\u{1d7dc}', + '\u{1fbf4}', + '\u{1d7d2}', + '\u{1d7f0}', + '\u{118af}', + '\u{1d7e6}', + '\u{ff14}', + '\u{13ce}', + '\u{1d7fa}' + ], + '5': [ + '\u{1d7f1}', + '\u{01bc}', + '\u{118bb}', + '\u{1fbf5}', + '\u{1d7d3}', + '\u{ff15}', + '\u{1d7fb}', + '\u{1d7e7}', + '\u{1d7dd}' + ], + '6': [ + '\u{1d7f2}', + '\u{1d7e8}', + '\u{ff16}', + '\u{1fbf6}', + '\u{1d7d4}', + '\u{118d5}', + '\u{2cd2}', + '\u{0431}', + '\u{13ee}', + '\u{1d7de}', + '\u{1d7fc}' + ], + '7': [ + '\u{1d7df}', + '\u{104d2}', + '\u{ff17}', + '\u{118c6}', + '\u{1fbf7}', + '\u{1d7f3}', + '\u{1d7e9}', + '\u{1d212}', + '\u{1d7d5}', + '\u{1d7fd}' + ], + '8': [ + '\u{1d7d6}', + '\u{1d7fe}', + '\u{0b03}', + '\u{1e8cb}', + '\u{0222}', + '\u{09ea}', + '\u{0a6a}', + '\u{1d7f4}', + '\u{0223}', + '\u{ff18}', + '\u{1031a}', + '\u{1d7e0}', + '\u{1fbf8}', + '\u{1d7ea}' + ], + '9': [ + '\u{1d7ff}', + '\u{1fbf9}', + '\u{a76e}', + '\u{118ac}', + '\u{0a67}', + '\u{1d7d7}', + '\u{118d6}', + '\u{ff19}', + '\u{1d7e1}', + '\u{1d7eb}', + '\u{09ed}', + '\u{118cc}', + '\u{0d6d}', + '\u{2cca}', + '\u{0b68}', + '\u{1d7f5}' + ], + 'A': [ + '\u{1d6e2}', + '\u{1d4d0}', + '\u{1d608}', + '\u{a4ee}', + '\u{1d71c}', + '\u{1d49c}', + '\u{1d504}', + '\u{ab7a}', + '\u{1d6a8}', + '\u{1d5d4}', + '\u{1d538}', + '\u{1d63c}', + '\u{1d56c}', + '\u{1d670}', + '\u{0391}', + '\u{1d434}', + '\u{16f40}', + '\u{0410}', + '\u{15c5}', + '\u{1d00}', + '\u{1d400}', + '\u{ff21}', + '\u{1d756}', + '\u{102a0}', + '\u{13aa}', + '\u{1d5a0}', + '\u{1d468}', + '\u{1d790}' + ], + 'B': [ + '\u{1d539}', + '\u{1d4d1}', + '\u{1d671}', + '\u{0412}', + '\u{1d5d5}', + '\u{a7b4}', + '\u{1d791}', + '\u{1d56d}', + '\u{1d757}', + '\u{10282}', + '\u{102a1}', + '\u{0432}', + '\u{1d6e3}', + '\u{0392}', + '\u{1d6a9}', + '\u{13f4}', + '\u{15f7}', + '\u{16d2}', + '\u{10301}', + '\u{1d505}', + '\u{1d469}', + '\u{1d609}', + '\u{1d71d}', + '\u{1d401}', + '\u{212c}', + '\u{1d435}', + '\u{13fc}', + '\u{1d5a1}', + '\u{1d63d}', + '\u{a4d0}', + '\u{ff22}', + '\u{0299}' + ], + 'C': [ + '\u{1d672}', + '\u{1d5a2}', + '\u{1d60a}', + '\u{1d436}', + '\u{118e9}', + '\u{10415}', + '\u{13df}', + '\u{118f2}', + '\u{212d}', + '\u{ff23}', + '\u{03f9}', + '\u{1d4d2}', + '\u{2ca4}', + '\u{1d63e}', + '\u{0421}', + '\u{1f74c}', + '\u{216d}', + '\u{1455}', + '\u{a4da}', + '\u{1d46a}', + '\u{1d49e}', + '\u{2282}', + '\u{2102}', + '\u{2e26}', + '\u{10302}', + '\u{1051c}', + '\u{1d402}', + '\u{1d56e}', + '\u{1d5d6}', + '\u{102a2}' + ], + 'D': [ + '\u{1d507}', + '\u{1d63f}', + '\u{1d49f}', + '\u{1d673}', + '\u{a4d3}', + '\u{1d60b}', + '\u{2145}', + '\u{1d46b}', + '\u{1d5d7}', + '\u{1d53b}', + '\u{ab70}', + '\u{ff24}', + '\u{1d5a3}', + '\u{1d4d3}', + '\u{1d05}', + '\u{1d56f}', + '\u{216e}', + '\u{13a0}', + '\u{15ea}', + '\u{1d437}', + '\u{15de}', + '\u{1d403}' + ], + 'E': [ + '\u{1d46c}', + '\u{1d6ac}', + '\u{1d53c}', + '\u{1d570}', + '\u{1d5d8}', + '\u{118a6}', + '\u{1d404}', + '\u{1d6e6}', + '\u{1d508}', + '\u{22ff}', + '\u{1d674}', + '\u{2130}', + '\u{13ac}', + '\u{a4f0}', + '\u{1d794}', + '\u{2d39}', + '\u{118ae}', + '\u{1d640}', + '\u{ff25}', + '\u{ab7c}', + '\u{1d4d4}', + '\u{1d438}', + '\u{1d5a4}', + '\u{0395}', + '\u{1d60c}', + '\u{1d720}', + '\u{0415}', + '\u{1d07}', + '\u{1d75a}', + '\u{10286}' + ], + 'F': [ + '\u{1d571}', + '\u{2131}', + '\u{a798}', + '\u{1d405}', + '\u{a4dd}', + '\u{118c2}', + '\u{1d5a5}', + '\u{1d60d}', + '\u{118a2}', + '\u{15b4}', + '\u{1d675}', + '\u{1d5d9}', + '\u{1d46d}', + '\u{1d641}', + '\u{10287}', + '\u{10525}', + '\u{1d509}', + '\u{ff26}', + '\u{1d213}', + '\u{1d7ca}', + '\u{1d53d}', + '\u{1d4d5}', + '\u{1d439}', + '\u{102a5}', + '\u{03dc}' + ], + 'G': [ + '\u{1d4a2}', + '\u{0262}', + '\u{13c0}', + '\u{a4d6}', + '\u{1d43a}', + '\u{1d53e}', + '\u{1d5da}', + '\u{050c}', + '\u{1d676}', + '\u{1d572}', + '\u{1d60e}', + '\u{1d4d6}', + '\u{13f3}', + '\u{1d642}', + '\u{1d5a6}', + '\u{1d46e}', + '\u{ab90}', + '\u{050d}', + '\u{1d50a}', + '\u{1d406}', + '\u{13fb}', + '\u{ff27}' + ], + 'H': [ + '\u{210d}', + '\u{2c8e}', + '\u{ab8b}', + '\u{1d46f}', + '\u{ff28}', + '\u{041d}', + '\u{1d677}', + '\u{029c}', + '\u{1d6e8}', + '\u{1d43b}', + '\u{1d4d7}', + '\u{1d5db}', + '\u{1d573}', + '\u{a4e7}', + '\u{1d722}', + '\u{1d643}', + '\u{043d}', + '\u{1d5a7}', + '\u{0397}', + '\u{1d796}', + '\u{157c}', + '\u{1d407}', + '\u{102cf}', + '\u{210b}', + '\u{210c}', + '\u{13bb}', + '\u{1d6ae}', + '\u{1d60f}', + '\u{1d75c}' + ], + 'I': [ + '\u{1d55d}', + '\u{1d574}', + '\u{0031}', + '\u{1d43c}', + '\u{0196}', + '\u{2d4f}', + '\u{1ee00}', + '\u{a4f2}', + '\u{fe8d}', + '\u{ff4c}', + '\u{1d661}', + '\u{2223}', + '\u{1d6b0}', + '\u{0406}', + '\u{2c92}', + '\u{05c0}', + '\u{1d7ed}', + '\u{1d6ea}', + '\u{ff11}', + '\u{1d610}', + '\u{05df}', + '\u{007c}', + '\u{1d5c5}', + '\u{1d695}', + '\u{ffe8}', + '\u{0661}', + '\u{1d408}', + '\u{1d540}', + '\u{05d5}', + '\u{1d7e3}', + '\u{1d678}', + '\u{16f28}', + '\u{1d5f9}', + '\u{1d4c1}', + '\u{1d7f7}', + '\u{1d724}', + '\u{1d4f5}', + '\u{217c}', + '\u{006c}', + '\u{1d7cf}', + '\u{1d5a8}', + '\u{1d425}', + '\u{04c0}', + '\u{10309}', + '\u{1d5dc}', + '\u{10320}', + '\u{1d459}', + '\u{1e8c7}', + '\u{23fd}', + '\u{0399}', + '\u{01c0}', + '\u{1d529}', + '\u{1d470}', + '\u{1d62d}', + '\u{07ca}', + '\u{ff29}', + '\u{2111}', + '\u{2160}', + '\u{fe8e}', + '\u{1ee80}', + '\u{2113}', + '\u{1028a}', + '\u{1d75e}', + '\u{2110}', + '\u{1d798}', + '\u{1fbf1}', + '\u{1d4d8}', + '\u{06f1}', + '\u{1d48d}', + '\u{1d7d9}', + '\u{1d644}', + '\u{0627}', + '\u{1d591}', + '\u{16c1}' + ], + 'J': [ + '\u{0408}', + '\u{a7b2}', + '\u{1d645}', + '\u{1d50d}', + '\u{1d5a9}', + '\u{1d575}', + '\u{1d5dd}', + '\u{ab7b}', + '\u{1d409}', + '\u{1d0a}', + '\u{148d}', + '\u{ff2a}', + '\u{1d611}', + '\u{1d43d}', + '\u{1d679}', + '\u{a4d9}', + '\u{1d4a5}', + '\u{037f}', + '\u{1d541}', + '\u{1d471}', + '\u{1d4d9}', + '\u{13ab}' + ], + 'K': [ + '\u{16d5}', + '\u{1d646}', + '\u{1d4a6}', + '\u{1d5aa}', + '\u{1d43e}', + '\u{039a}', + '\u{1d542}', + '\u{a4d7}', + '\u{1d4da}', + '\u{1d5de}', + '\u{1d612}', + '\u{1d6b1}', + '\u{10518}', + '\u{1d6eb}', + '\u{1d576}', + '\u{041a}', + '\u{1d75f}', + '\u{ff2b}', + '\u{13e6}', + '\u{1d799}', + '\u{1d50e}', + '\u{1d67a}', + '\u{1d472}', + '\u{1d40a}', + '\u{1d725}', + '\u{2c94}', + '\u{212a}' + ], + 'L': [ + '\u{2cd1}', + '\u{1d647}', + '\u{1d43f}', + '\u{1d5ab}', + '\u{1d5df}', + '\u{abae}', + '\u{1d613}', + '\u{ff2c}', + '\u{1d473}', + '\u{1d50f}', + '\u{10526}', + '\u{1d577}', + '\u{1d67b}', + '\u{10443}', + '\u{a4e1}', + '\u{16f16}', + '\u{216c}', + '\u{14aa}', + '\u{2cd0}', + '\u{118a3}', + '\u{1d543}', + '\u{029f}', + '\u{1d40b}', + '\u{118b2}', + '\u{1d4db}', + '\u{2112}', + '\u{13de}', + '\u{1d22a}', + '\u{1041b}' + ], + 'M': [ + '\u{102b0}', + '\u{1d4dc}', + '\u{216f}', + '\u{10311}', + '\u{15f0}', + '\u{1d5ac}', + '\u{16d6}', + '\u{1d614}', + '\u{039c}', + '\u{1d510}', + '\u{1d761}', + '\u{1d6b3}', + '\u{1d727}', + '\u{1d40c}', + '\u{1d474}', + '\u{1d67c}', + '\u{1d5e0}', + '\u{13b7}', + '\u{1d440}', + '\u{041c}', + '\u{2133}', + '\u{a4df}', + '\u{1d578}', + '\u{ff2d}', + '\u{1d79b}', + '\u{03fa}', + '\u{1d648}', + '\u{1d6ed}', + '\u{1d544}', + '\u{2c98}' + ], + 'N': [ + '\u{1d441}', + '\u{1d762}', + '\u{2c9a}', + '\u{1d5ad}', + '\u{1d615}', + '\u{1d40d}', + '\u{0274}', + '\u{1d6b4}', + '\u{1d579}', + '\u{1d4a9}', + '\u{1d649}', + '\u{a4e0}', + '\u{1d728}', + '\u{2115}', + '\u{10513}', + '\u{1d5e1}', + '\u{1d4dd}', + '\u{1d79c}', + '\u{1d511}', + '\u{1d6ee}', + '\u{ff2e}', + '\u{1d475}', + '\u{1d67d}', + '\u{039d}' + ], + 'O': [ + '\u{1d476}', + '\u{0585}', + '\u{fbaa}', + '\u{1d4aa}', + '\u{06be}', + '\u{1d70e}', + '\u{09e6}', + '\u{0d02}', + '\u{1d4de}', + '\u{fee9}', + '\u{1d630}', + '\u{06c1}', + '\u{1ee24}', + '\u{1d45c}', + '\u{0a66}', + '\u{1d7bc}', + '\u{0c02}', + '\u{10ff}', + '\u{1d490}', + '\u{1d5c8}', + '\u{0d82}', + '\u{ff4f}', + '\u{1d744}', + '\u{0d20}', + '\u{1d5fc}', + '\u{fba6}', + '\u{0c66}', + '\u{102ab}', + '\u{1d11}', + '\u{0665}', + '\u{fbab}', + '\u{1d6d0}', + '\u{1d7b8}', + '\u{118c8}', + '\u{0030}', + '\u{104c2}', + '\u{1d546}', + '\u{ff10}', + '\u{1d442}', + '\u{039f}', + '\u{10292}', + '\u{1d79e}', + '\u{feec}', + '\u{1d7ce}', + '\u{1d782}', + '\u{1d6d4}', + '\u{06f5}', + '\u{fbad}', + '\u{a4f3}', + '\u{feeb}', + '\u{1ee64}', + '\u{118e0}', + '\u{10404}', + '\u{2d54}', + '\u{1d7ec}', + '\u{feea}', + '\u{3007}', + '\u{1040}', + '\u{fba7}', + '\u{1d77e}', + '\u{1d428}', + '\u{0ae6}', + '\u{118b5}', + '\u{1d698}', + '\u{104ea}', + '\u{0ed0}', + '\u{05e1}', + '\u{1d4f8}', + '\u{0647}', + '\u{0c82}', + '\u{0966}', + '\u{0d66}', + '\u{1d7e2}', + '\u{118d7}', + '\u{1d64a}', + '\u{fbac}', + '\u{1d764}', + '\u{1042c}', + '\u{1d748}', + '\u{2134}', + '\u{1d67e}', + '\u{0b66}', + '\u{041e}', + '\u{ab3d}', + '\u{1ee84}', + '\u{1d6f0}', + '\u{1fbf0}', + '\u{0ce6}', + '\u{114d0}', + '\u{1d7d8}', + '\u{06d5}', + '\u{1d70a}', + '\u{1d40e}', + '\u{0b20}', + '\u{0e50}', + '\u{1d52c}', + '\u{1d594}', + '\u{1d616}', + '\u{1d5ae}', + '\u{03c3}', + '\u{043e}', + '\u{12d0}', + '\u{1d57a}', + '\u{1d72a}', + '\u{1d0f}', + '\u{006f}', + '\u{03bf}', + '\u{2c9e}', + '\u{1d560}', + '\u{0555}', + '\u{1d5e2}', + '\u{10516}', + '\u{0be6}', + '\u{07c0}', + '\u{1d6b6}', + '\u{1d664}', + '\u{ff2f}', + '\u{1d512}', + '\u{fba8}', + '\u{fba9}', + '\u{1d7f6}', + '\u{2c9f}', + '\u{101d}' + ], + 'P': [ + '\u{abb2}', + '\u{1d5e3}', + '\u{1d29}', + '\u{1d4ab}', + '\u{ff30}', + '\u{1d64b}', + '\u{1d5af}', + '\u{1d513}', + '\u{0420}', + '\u{2119}', + '\u{1d67f}', + '\u{1d4df}', + '\u{a4d1}', + '\u{1d6b8}', + '\u{03a1}', + '\u{1d57b}', + '\u{1d766}', + '\u{1d7a0}', + '\u{10295}', + '\u{1d18}', + '\u{1d443}', + '\u{146d}', + '\u{1d40f}', + '\u{2ca2}', + '\u{1d6f2}', + '\u{1d617}', + '\u{13e2}', + '\u{1d72c}', + '\u{1d477}' + ], + 'Q': [ + '\u{1d4ac}', + '\u{1d57c}', + '\u{2d55}', + '\u{1d478}', + '\u{1d444}', + '\u{1d410}', + '\u{211a}', + '\u{1d514}', + '\u{1d64c}', + '\u{ff31}', + '\u{1d618}', + '\u{1d5b0}', + '\u{1d680}', + '\u{1d5e4}', + '\u{1d4e0}' + ], + 'R': [ + '\u{1d479}', + '\u{211c}', + '\u{ab71}', + '\u{1d216}', + '\u{1d5e5}', + '\u{1587}', + '\u{0280}', + '\u{1d5b1}', + '\u{1d411}', + '\u{16b1}', + '\u{01a6}', + '\u{13a1}', + '\u{ff32}', + '\u{211b}', + '\u{aba2}', + '\u{1d64d}', + '\u{13d2}', + '\u{104b4}', + '\u{1d57d}', + '\u{211d}', + '\u{1d445}', + '\u{1d681}', + '\u{16f35}', + '\u{1d4e1}', + '\u{a4e3}', + '\u{1d619}' + ], + 'S': [ + '\u{054f}', + '\u{ff33}', + '\u{1d4e2}', + '\u{1d57e}', + '\u{1d5b2}', + '\u{10296}', + '\u{13da}', + '\u{1d47a}', + '\u{1d446}', + '\u{1d4ae}', + '\u{1d61a}', + '\u{1d64e}', + '\u{10420}', + '\u{13d5}', + '\u{1d5e6}', + '\u{a4e2}', + '\u{1d516}', + '\u{1d412}', + '\u{1d54a}', + '\u{16f3a}', + '\u{1d682}', + '\u{0405}' + ], + 'T': [ + '\u{1d6d5}', + '\u{1d683}', + '\u{1d47b}', + '\u{1d54b}', + '\u{27d9}', + '\u{2ca6}', + '\u{16f0a}', + '\u{1d1b}', + '\u{1d413}', + '\u{10297}', + '\u{ab72}', + '\u{1d4e3}', + '\u{1d7bd}', + '\u{1d61b}', + '\u{03c4}', + '\u{1d6bb}', + '\u{1d783}', + '\u{22a4}', + '\u{0422}', + '\u{0442}', + '\u{1f768}', + '\u{1d5b3}', + '\u{1d769}', + '\u{1d6f5}', + '\u{1d4af}', + '\u{1d5e7}', + '\u{1d64f}', + '\u{03a4}', + '\u{102b1}', + '\u{1d517}', + '\u{ff34}', + '\u{1d7a3}', + '\u{1d749}', + '\u{1d447}', + '\u{1d70f}', + '\u{13a2}', + '\u{a4d4}', + '\u{1d72f}', + '\u{118bc}', + '\u{10315}', + '\u{1d57f}' + ], + 'U': [ + '\u{1d448}', + '\u{1d414}', + '\u{22c3}', + '\u{222a}', + '\u{1d5b4}', + '\u{1d518}', + '\u{1d580}', + '\u{1d47c}', + '\u{1d4b0}', + '\u{1d650}', + '\u{144c}', + '\u{104ce}', + '\u{1d4e4}', + '\u{1d5e8}', + '\u{1d61c}', + '\u{1d684}', + '\u{118b8}', + '\u{16f42}', + '\u{a4f4}', + '\u{1d54c}', + '\u{1200}', + '\u{ff35}', + '\u{054d}' + ], + 'V': [ + '\u{1d415}', + '\u{1d685}', + '\u{1051d}', + '\u{2164}', + '\u{1d581}', + '\u{13d9}', + '\u{142f}', + '\u{0474}', + '\u{a6df}', + '\u{2d38}', + '\u{06f7}', + '\u{ff36}', + '\u{1d20d}', + '\u{1d54d}', + '\u{1d449}', + '\u{1d61d}', + '\u{1d4b1}', + '\u{1d47d}', + '\u{1d5b5}', + '\u{118a0}', + '\u{a4e6}', + '\u{1d519}', + '\u{0667}', + '\u{1d4e5}', + '\u{1d5e9}', + '\u{16f08}', + '\u{1d651}' + ], + 'W': [ + '\u{1d686}', + '\u{118e6}', + '\u{051c}', + '\u{1d652}', + '\u{1d47e}', + '\u{1d4b2}', + '\u{1d416}', + '\u{1d4e6}', + '\u{1d5ea}', + '\u{118ef}', + '\u{1d51a}', + '\u{13d4}', + '\u{1d5b6}', + '\u{ff37}', + '\u{1d54e}', + '\u{1d44a}', + '\u{1d582}', + '\u{13b3}', + '\u{a4ea}', + '\u{1d61e}' + ], + 'X': [ + '\u{1d5b7}', + '\u{2169}', + '\u{1d7a6}', + '\u{1d4b3}', + '\u{10322}', + '\u{2573}', + '\u{1d61f}', + '\u{03a7}', + '\u{1d6be}', + '\u{10290}', + '\u{102b4}', + '\u{1d54f}', + '\u{10317}', + '\u{a4eb}', + '\u{2cac}', + '\u{1d47f}', + '\u{0425}', + '\u{ff38}', + '\u{1d51b}', + '\u{1d76c}', + '\u{1d44b}', + '\u{118ec}', + '\u{166d}', + '\u{1d417}', + '\u{1d732}', + '\u{2d5d}', + '\u{10527}', + '\u{1d583}', + '\u{1d653}', + '\u{1d5eb}', + '\u{1d687}', + '\u{1d6f8}', + '\u{a7b3}', + '\u{1d4e7}', + '\u{16b7}' + ], + 'Y': [ + '\u{1d584}', + '\u{a4ec}', + '\u{03a5}', + '\u{1d4b4}', + '\u{1d688}', + '\u{1d480}', + '\u{102b2}', + '\u{1d620}', + '\u{1d550}', + '\u{1d76a}', + '\u{1d654}', + '\u{13bd}', + '\u{1d5ec}', + '\u{2ca8}', + '\u{1d6bc}', + '\u{13a9}', + '\u{1d7a4}', + '\u{1d730}', + '\u{1d418}', + '\u{0423}', + '\u{1d4e8}', + '\u{118a4}', + '\u{ff39}', + '\u{04ae}', + '\u{16f43}', + '\u{1d51c}', + '\u{03d2}', + '\u{1d44c}', + '\u{1d6f6}', + '\u{1d5b8}' + ], + 'Z': [ + '\u{1d44d}', + '\u{102f5}', + '\u{1d6e7}', + '\u{1d689}', + '\u{ff3a}', + '\u{2124}', + '\u{0396}', + '\u{1d655}', + '\u{1d6ad}', + '\u{1d621}', + '\u{1d721}', + '\u{1d75b}', + '\u{1d481}', + '\u{1d585}', + '\u{1d419}', + '\u{a4dc}', + '\u{1d5b9}', + '\u{1d4e9}', + '\u{13c3}', + '\u{1d795}', + '\u{1d4b5}', + '\u{1d5ed}', + '\u{118a9}', + '\u{118e5}', + '\u{2128}' + ], + 'a': [ + '\u{ff41}', + '\u{0251}', + '\u{03b1}', + '\u{1d41a}', + '\u{1d656}', + '\u{1d770}', + '\u{1d482}', + '\u{1d68a}', + '\u{237a}', + '\u{1d7aa}', + '\u{1d4b6}', + '\u{0430}', + '\u{1d51e}', + '\u{1d5ee}', + '\u{1d622}', + '\u{1d552}', + '\u{1d5ba}', + '\u{1d44e}', + '\u{1d6fc}', + '\u{1d6c2}', + '\u{1d4ea}', + '\u{1d736}', + '\u{1d586}' + ], + 'b': [ + '\u{1d483}', + '\u{1d41b}', + '\u{1d4b7}', + '\u{1d5bb}', + '\u{15af}', + '\u{1d587}', + '\u{1d623}', + '\u{13cf}', + '\u{1d4eb}', + '\u{0184}', + '\u{1d5ef}', + '\u{1d553}', + '\u{042c}', + '\u{1d51f}', + '\u{1d44f}', + '\u{ff42}', + '\u{1d68b}', + '\u{1d657}', + '\u{1472}' + ], + 'c': [ + '\u{1d520}', + '\u{1d450}', + '\u{1d5f0}', + '\u{217d}', + '\u{1d588}', + '\u{1d04}', + '\u{1043d}', + '\u{abaf}', + '\u{1d4ec}', + '\u{1d624}', + '\u{1d41c}', + '\u{1d5bc}', + '\u{1d658}', + '\u{0441}', + '\u{1d554}', + '\u{03f2}', + '\u{2ca5}', + '\u{1d68c}', + '\u{1d484}', + '\u{1d4b8}', + '\u{ff43}' + ], + 'd': [ + '\u{1d5f1}', + '\u{13e7}', + '\u{1d41d}', + '\u{1d4b9}', + '\u{2146}', + '\u{a4d2}', + '\u{0501}', + '\u{ff44}', + '\u{1d589}', + '\u{1d521}', + '\u{1d68d}', + '\u{1d659}', + '\u{1d5bd}', + '\u{146f}', + '\u{1d451}', + '\u{1d625}', + '\u{217e}', + '\u{1d555}', + '\u{1d485}', + '\u{1d4ed}' + ], + 'e': [ + '\u{212f}', + '\u{1d522}', + '\u{04bd}', + '\u{ff45}', + '\u{1d556}', + '\u{2147}', + '\u{1d65a}', + '\u{212e}', + '\u{ab32}', + '\u{1d486}', + '\u{1d5f2}', + '\u{1d452}', + '\u{1d5be}', + '\u{1d4ee}', + '\u{1d58a}', + '\u{1d626}', + '\u{1d68e}', + '\u{0435}', + '\u{1d41e}' + ], + 'f': [ + '\u{1d65b}', + '\u{1d487}', + '\u{017f}', + '\u{1d4bb}', + '\u{1d523}', + '\u{0584}', + '\u{1d7cb}', + '\u{1d5f3}', + '\u{ff46}', + '\u{1d68f}', + '\u{1d58b}', + '\u{ab35}', + '\u{1d4ef}', + '\u{1e9d}', + '\u{1d557}', + '\u{1d5bf}', + '\u{1d453}', + '\u{1d41f}', + '\u{03dd}', + '\u{1d627}', + '\u{a799}' + ], + 'g': [ + '\u{1d58c}', + '\u{1d420}', + '\u{210a}', + '\u{1d5f4}', + '\u{1d558}', + '\u{1d65c}', + '\u{0261}', + '\u{1d524}', + '\u{1d690}', + '\u{018d}', + '\u{0581}', + '\u{1d5c0}', + '\u{1d628}', + '\u{ff47}', + '\u{1d488}', + '\u{1d83}', + '\u{1d4f0}', + '\u{1d454}' + ], + 'h': [ + '\u{1d421}', + '\u{1d4bd}', + '\u{ff48}', + '\u{1d58d}', + '\u{1d65d}', + '\u{1d691}', + '\u{1d559}', + '\u{1d5c1}', + '\u{1d629}', + '\u{13c2}', + '\u{0570}', + '\u{1d5f5}', + '\u{1d4f1}', + '\u{210e}', + '\u{1d489}', + '\u{1d525}', + '\u{04bb}' + ], + 'i': [ + '\u{1d62a}', + '\u{1fbe}', + '\u{2148}', + '\u{1d778}', + '\u{1d58e}', + '\u{1d422}', + '\u{04cf}', + '\u{037a}', + '\u{ff49}', + '\u{1d5c2}', + '\u{1d73e}', + '\u{a647}', + '\u{1d5f6}', + '\u{13a5}', + '\u{1d65e}', + '\u{118c3}', + '\u{0269}', + '\u{1d4be}', + '\u{1d6a4}', + '\u{2373}', + '\u{1d526}', + '\u{1d456}', + '\u{03b9}', + '\u{1d4f2}', + '\u{1d6ca}', + '\u{1d7b2}', + '\u{1d48a}', + '\u{1d692}', + '\u{026a}', + '\u{1d704}', + '\u{02db}', + '\u{ab75}', + '\u{0456}', + '\u{2170}', + '\u{2139}', + '\u{1d55a}', + '\u{0131}' + ], + 'j': [ + '\u{1d423}', + '\u{1d5c3}', + '\u{1d693}', + '\u{2149}', + '\u{1d55b}', + '\u{03f3}', + '\u{ff4a}', + '\u{1d48b}', + '\u{1d457}', + '\u{1d4bf}', + '\u{1d65f}', + '\u{0458}', + '\u{1d527}', + '\u{1d62b}', + '\u{1d5f7}', + '\u{1d4f3}', + '\u{1d58f}' + ], + 'k': [ + '\u{ff4b}', + '\u{1d55c}', + '\u{1d458}', + '\u{1d424}', + '\u{1d660}', + '\u{1d694}', + '\u{1d590}', + '\u{1d5c4}', + '\u{1d5f8}', + '\u{1d528}', + '\u{1d62c}', + '\u{1d48c}', + '\u{1d4f4}', + '\u{1d4c0}' + ], + 'l': [ + '\u{1d55d}', + '\u{0049}', + '\u{1d574}', + '\u{0031}', + '\u{1d43c}', + '\u{0196}', + '\u{2d4f}', + '\u{1ee00}', + '\u{a4f2}', + '\u{fe8d}', + '\u{ff4c}', + '\u{1d661}', + '\u{2223}', + '\u{1d6b0}', + '\u{0406}', + '\u{2c92}', + '\u{05c0}', + '\u{1d7ed}', + '\u{1d6ea}', + '\u{ff11}', + '\u{1d610}', + '\u{05df}', + '\u{007c}', + '\u{1d5c5}', + '\u{1d695}', + '\u{ffe8}', + '\u{0661}', + '\u{1d408}', + '\u{1d540}', + '\u{05d5}', + '\u{1d7e3}', + '\u{1d678}', + '\u{16f28}', + '\u{1d5f9}', + '\u{1d4c1}', + '\u{1d7f7}', + '\u{1d724}', + '\u{1d4f5}', + '\u{217c}', + '\u{1d7cf}', + '\u{1d5a8}', + '\u{1d425}', + '\u{04c0}', + '\u{10309}', + '\u{1d5dc}', + '\u{10320}', + '\u{1d459}', + '\u{1e8c7}', + '\u{23fd}', + '\u{0399}', + '\u{01c0}', + '\u{1d529}', + '\u{1d470}', + '\u{1d62d}', + '\u{07ca}', + '\u{ff29}', + '\u{2111}', + '\u{2160}', + '\u{fe8e}', + '\u{1ee80}', + '\u{2113}', + '\u{1028a}', + '\u{1d75e}', + '\u{2110}', + '\u{1d798}', + '\u{1fbf1}', + '\u{1d4d8}', + '\u{06f1}', + '\u{1d48d}', + '\u{1d7d9}', + '\u{1d644}', + '\u{0627}', + '\u{1d591}', + '\u{16c1}' + ], + 'm': [ + '\u{ff4d}' + ], + 'n': [ + '\u{1d52b}', + '\u{1d593}', + '\u{1d5c7}', + '\u{1d45b}', + '\u{ff4e}', + '\u{1d5fb}', + '\u{0578}', + '\u{1d62f}', + '\u{1d4f7}', + '\u{1d663}', + '\u{1d48f}', + '\u{1d4c3}', + '\u{1d55f}', + '\u{1d697}', + '\u{1d427}', + '\u{057c}' + ], + 'o': [ + '\u{1d476}', + '\u{0585}', + '\u{004f}', + '\u{fbaa}', + '\u{1d4aa}', + '\u{06be}', + '\u{1d70e}', + '\u{09e6}', + '\u{0d02}', + '\u{1d4de}', + '\u{fee9}', + '\u{1d630}', + '\u{06c1}', + '\u{1ee24}', + '\u{1d45c}', + '\u{0a66}', + '\u{1d7bc}', + '\u{0c02}', + '\u{10ff}', + '\u{1d490}', + '\u{1d5c8}', + '\u{0d82}', + '\u{ff4f}', + '\u{1d744}', + '\u{0d20}', + '\u{1d5fc}', + '\u{fba6}', + '\u{0c66}', + '\u{102ab}', + '\u{1d11}', + '\u{0665}', + '\u{fbab}', + '\u{1d6d0}', + '\u{1d7b8}', + '\u{118c8}', + '\u{0030}', + '\u{104c2}', + '\u{1d546}', + '\u{ff10}', + '\u{1d442}', + '\u{039f}', + '\u{10292}', + '\u{1d79e}', + '\u{feec}', + '\u{1d7ce}', + '\u{1d782}', + '\u{1d6d4}', + '\u{06f5}', + '\u{fbad}', + '\u{a4f3}', + '\u{feeb}', + '\u{1ee64}', + '\u{118e0}', + '\u{10404}', + '\u{2d54}', + '\u{1d7ec}', + '\u{feea}', + '\u{3007}', + '\u{1040}', + '\u{fba7}', + '\u{1d77e}', + '\u{1d428}', + '\u{0ae6}', + '\u{118b5}', + '\u{1d698}', + '\u{104ea}', + '\u{0ed0}', + '\u{05e1}', + '\u{1d4f8}', + '\u{0647}', + '\u{0c82}', + '\u{0966}', + '\u{0d66}', + '\u{1d7e2}', + '\u{118d7}', + '\u{1d64a}', + '\u{fbac}', + '\u{1d764}', + '\u{1042c}', + '\u{1d748}', + '\u{2134}', + '\u{1d67e}', + '\u{0b66}', + '\u{041e}', + '\u{ab3d}', + '\u{1ee84}', + '\u{1d6f0}', + '\u{1fbf0}', + '\u{0ce6}', + '\u{114d0}', + '\u{1d7d8}', + '\u{06d5}', + '\u{1d70a}', + '\u{1d40e}', + '\u{0b20}', + '\u{0e50}', + '\u{1d52c}', + '\u{1d594}', + '\u{1d616}', + '\u{1d5ae}', + '\u{03c3}', + '\u{043e}', + '\u{12d0}', + '\u{1d57a}', + '\u{1d72a}', + '\u{1d0f}', + '\u{03bf}', + '\u{2c9e}', + '\u{1d560}', + '\u{0555}', + '\u{1d5e2}', + '\u{10516}', + '\u{0be6}', + '\u{07c0}', + '\u{1d6b6}', + '\u{1d664}', + '\u{ff2f}', + '\u{1d512}', + '\u{fba8}', + '\u{fba9}', + '\u{1d7f6}', + '\u{2c9f}', + '\u{101d}' + ], + 'p': [ + '\u{1d45d}', + '\u{1d561}', + '\u{1d78e}', + '\u{03f1}', + '\u{1d7c8}', + '\u{1d70c}', + '\u{ff50}', + '\u{2ca3}', + '\u{1d4c5}', + '\u{1d7ba}', + '\u{1d491}', + '\u{1d595}', + '\u{1d746}', + '\u{1d429}', + '\u{1d71a}', + '\u{1d665}', + '\u{1d754}', + '\u{1d780}', + '\u{1d52d}', + '\u{1d699}', + '\u{03c1}', + '\u{2374}', + '\u{1d5c9}', + '\u{1d6e0}', + '\u{1d5fd}', + '\u{0440}', + '\u{1d631}', + '\u{1d6d2}', + '\u{1d4f9}' + ], + 'q': [ + '\u{051b}', + '\u{ff51}', + '\u{1d4fa}', + '\u{1d5ca}', + '\u{1d52e}', + '\u{1d562}', + '\u{1d45e}', + '\u{1d5fe}', + '\u{1d666}', + '\u{1d596}', + '\u{1d69a}', + '\u{0563}', + '\u{1d492}', + '\u{1d632}', + '\u{1d42a}', + '\u{0566}', + '\u{1d4c6}' + ], + 'r': [ + '\u{1d597}', + '\u{1d4fb}', + '\u{2c85}', + '\u{1d5cb}', + '\u{1d45f}', + '\u{ab47}', + '\u{1d69b}', + '\u{1d42b}', + '\u{1d667}', + '\u{0433}', + '\u{1d493}', + '\u{1d4c7}', + '\u{ab48}', + '\u{1d5ff}', + '\u{ff52}', + '\u{1d52f}', + '\u{1d26}', + '\u{1d563}', + '\u{ab81}', + '\u{1d633}' + ], + 's': [ + '\u{1d69c}', + '\u{a731}', + '\u{abaa}', + '\u{1d600}', + '\u{01bd}', + '\u{0455}', + '\u{1d460}', + '\u{118c1}', + '\u{1d564}', + '\u{1d668}', + '\u{1d4fc}', + '\u{1d494}', + '\u{1d5cc}', + '\u{1d634}', + '\u{1d42c}', + '\u{10448}', + '\u{1d530}', + '\u{1d598}', + '\u{ff53}', + '\u{1d4c8}' + ], + 't': [ + '\u{1d495}', + '\u{1d5cd}', + '\u{1d599}', + '\u{1d669}', + '\u{1d531}', + '\u{1d4fd}', + '\u{1d4c9}', + '\u{1d42d}', + '\u{1d601}', + '\u{1d461}', + '\u{1d69d}', + '\u{1d565}', + '\u{ff54}', + '\u{1d635}' + ], + 'u': [ + '\u{1d462}', + '\u{104f6}', + '\u{1d5ce}', + '\u{1d6d6}', + '\u{1d1c}', + '\u{ff55}', + '\u{1d42e}', + '\u{1d59a}', + '\u{1d69e}', + '\u{1d710}', + '\u{1d602}', + '\u{1d636}', + '\u{1d496}', + '\u{1d532}', + '\u{1d66a}', + '\u{118d8}', + '\u{03c5}', + '\u{1d7be}', + '\u{1d4ca}', + '\u{1d4fe}', + '\u{1d566}', + '\u{057d}', + '\u{ab4e}', + '\u{ab52}', + '\u{a79f}', + '\u{1d784}', + '\u{028b}', + '\u{1d74a}' + ], + 'v': [ + '\u{1d66b}', + '\u{1d4ff}', + '\u{0475}', + '\u{1d7b6}', + '\u{ff56}', + '\u{1d497}', + '\u{1d533}', + '\u{1d77c}', + '\u{1d603}', + '\u{1d69f}', + '\u{1d42f}', + '\u{1d20}', + '\u{1d4cb}', + '\u{1d59b}', + '\u{05d8}', + '\u{22c1}', + '\u{1d742}', + '\u{1d6ce}', + '\u{11706}', + '\u{03bd}', + '\u{1d708}', + '\u{1d463}', + '\u{2228}', + '\u{1d637}', + '\u{1d5cf}', + '\u{aba9}', + '\u{118c0}', + '\u{2174}', + '\u{1d567}' + ], + 'w': [ + '\u{1d604}', + '\u{ff57}', + '\u{1d5d0}', + '\u{1d498}', + '\u{1d430}', + '\u{1170f}', + '\u{1d638}', + '\u{1d66c}', + '\u{1d59c}', + '\u{1d534}', + '\u{1d500}', + '\u{ab83}', + '\u{1d464}', + '\u{026f}', + '\u{1170a}', + '\u{0561}', + '\u{1d6a0}', + '\u{1d568}', + '\u{1d21}', + '\u{1d4cc}', + '\u{0461}', + '\u{1170e}', + '\u{051d}' + ], + 'x': [ + '\u{1d431}', + '\u{1d465}', + '\u{2a2f}', + '\u{1d535}', + '\u{1d5d1}', + '\u{0445}', + '\u{157d}', + '\u{1d639}', + '\u{1d4cd}', + '\u{1d499}', + '\u{2179}', + '\u{292c}', + '\u{1d605}', + '\u{00d7}', + '\u{166e}', + '\u{1d6a1}', + '\u{ff58}', + '\u{1541}', + '\u{1d569}', + '\u{292b}', + '\u{1d59d}', + '\u{1d501}', + '\u{1d66d}' + ], + 'y': [ + '\u{ab5a}', + '\u{1eff}', + '\u{0443}', + '\u{028f}', + '\u{1d606}', + '\u{213d}', + '\u{1d772}', + '\u{04af}', + '\u{10e7}', + '\u{1d56a}', + '\u{1d4ce}', + '\u{1d6c4}', + '\u{1d63a}', + '\u{ff59}', + '\u{1d66e}', + '\u{1d738}', + '\u{0263}', + '\u{1d7ac}', + '\u{1d502}', + '\u{1d466}', + '\u{1d6a2}', + '\u{03b3}', + '\u{1d536}', + '\u{1d8c}', + '\u{1d49a}', + '\u{118dc}', + '\u{1d432}', + '\u{1d59e}', + '\u{1d6fe}', + '\u{1d5d2}' + ], + 'z': [ + '\u{1d49b}', + '\u{1d433}', + '\u{1d59f}', + '\u{1d63b}', + '\u{1d56b}', + '\u{1d607}', + '\u{1d537}', + '\u{1d22}', + '\u{1d4cf}', + '\u{ab93}', + '\u{1d467}', + '\u{1d66f}', + '\u{1d6a3}', + '\u{118c4}', + '\u{1d503}', + '\u{1d5d3}', + '\u{ff5a}' + ] +}; diff --git a/arkguard/src/configs/preset/es6_reserved_properties.json b/arkguard/src/configs/preset/es6_reserved_properties.json new file mode 100644 index 0000000000000000000000000000000000000000..cf3d2dd8710b6ce79148d5b14e82fa66990dc34a --- /dev/null +++ b/arkguard/src/configs/preset/es6_reserved_properties.json @@ -0,0 +1,7884 @@ +[ + "$&", + "$'", + "$*", + "$+", + "$1", + "$2", + "$3", + "$4", + "$5", + "$6", + "$7", + "$8", + "$9", + "$_", + "$`", + "$input", + "-moz-animation", + "-moz-animation-delay", + "-moz-animation-direction", + "-moz-animation-duration", + "-moz-animation-fill-mode", + "-moz-animation-iteration-count", + "-moz-animation-name", + "-moz-animation-play-state", + "-moz-animation-timing-function", + "-moz-appearance", + "-moz-backface-visibility", + "-moz-border-end", + "-moz-border-end-color", + "-moz-border-end-style", + "-moz-border-end-width", + "-moz-border-image", + "-moz-border-start", + "-moz-border-start-color", + "-moz-border-start-style", + "-moz-border-start-width", + "-moz-box-align", + "-moz-box-direction", + "-moz-box-flex", + "-moz-box-ordinal-group", + "-moz-box-orient", + "-moz-box-pack", + "-moz-box-sizing", + "-moz-float-edge", + "-moz-font-feature-settings", + "-moz-font-language-override", + "-moz-force-broken-image-icon", + "-moz-hyphens", + "-moz-image-region", + "-moz-margin-end", + "-moz-margin-start", + "-moz-orient", + "-moz-osx-font-smoothing", + "-moz-outline-radius", + "-moz-outline-radius-bottomleft", + "-moz-outline-radius-bottomright", + "-moz-outline-radius-topleft", + "-moz-outline-radius-topright", + "-moz-padding-end", + "-moz-padding-start", + "-moz-perspective", + "-moz-perspective-origin", + "-moz-tab-size", + "-moz-text-size-adjust", + "-moz-transform", + "-moz-transform-origin", + "-moz-transform-style", + "-moz-transition", + "-moz-transition-delay", + "-moz-transition-duration", + "-moz-transition-property", + "-moz-transition-timing-function", + "-moz-user-focus", + "-moz-user-input", + "-moz-user-modify", + "-moz-user-select", + "-moz-window-dragging", + "-webkit-align-content", + "-webkit-align-items", + "-webkit-align-self", + "-webkit-animation", + "-webkit-animation-delay", + "-webkit-animation-direction", + "-webkit-animation-duration", + "-webkit-animation-fill-mode", + "-webkit-animation-iteration-count", + "-webkit-animation-name", + "-webkit-animation-play-state", + "-webkit-animation-timing-function", + "-webkit-appearance", + "-webkit-backface-visibility", + "-webkit-background-clip", + "-webkit-background-origin", + "-webkit-background-size", + "-webkit-border-bottom-left-radius", + "-webkit-border-bottom-right-radius", + "-webkit-border-image", + "-webkit-border-radius", + "-webkit-border-top-left-radius", + "-webkit-border-top-right-radius", + "-webkit-box-align", + "-webkit-box-direction", + "-webkit-box-flex", + "-webkit-box-ordinal-group", + "-webkit-box-orient", + "-webkit-box-pack", + "-webkit-box-shadow", + "-webkit-box-sizing", + "-webkit-filter", + "-webkit-flex", + "-webkit-flex-basis", + "-webkit-flex-direction", + "-webkit-flex-flow", + "-webkit-flex-grow", + "-webkit-flex-shrink", + "-webkit-flex-wrap", + "-webkit-justify-content", + "-webkit-line-clamp", + "-webkit-mask", + "-webkit-mask-clip", + "-webkit-mask-composite", + "-webkit-mask-image", + "-webkit-mask-origin", + "-webkit-mask-position", + "-webkit-mask-position-x", + "-webkit-mask-position-y", + "-webkit-mask-repeat", + "-webkit-mask-size", + "-webkit-order", + "-webkit-perspective", + "-webkit-perspective-origin", + "-webkit-text-fill-color", + "-webkit-text-size-adjust", + "-webkit-text-stroke", + "-webkit-text-stroke-color", + "-webkit-text-stroke-width", + "-webkit-transform", + "-webkit-transform-origin", + "-webkit-transform-style", + "-webkit-transition", + "-webkit-transition-delay", + "-webkit-transition-duration", + "-webkit-transition-property", + "-webkit-transition-timing-function", + "-webkit-user-select", + "0", + "1", + "10", + "11", + "12", + "13", + "14", + "15", + "16", + "17", + "18", + "19", + "2", + "20", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "@@iterator", + "ABORT_ERR", + "ACTIVE", + "ACTIVE_ATTRIBUTES", + "ACTIVE_TEXTURE", + "ACTIVE_UNIFORMS", + "ACTIVE_UNIFORM_BLOCKS", + "ADDITION", + "ALIASED_LINE_WIDTH_RANGE", + "ALIASED_POINT_SIZE_RANGE", + "ALLOW_KEYBOARD_INPUT", + "ALLPASS", + "ALPHA", + "ALPHA_BITS", + "ALREADY_SIGNALED", + "ALT_MASK", + "ALWAYS", + "ANY_SAMPLES_PASSED", + "ANY_SAMPLES_PASSED_CONSERVATIVE", + "ANY_TYPE", + "ANY_UNORDERED_NODE_TYPE", + "ARRAY_BUFFER", + "ARRAY_BUFFER_BINDING", + "ATTACHED_SHADERS", + "ATTRIBUTE_NODE", + "AT_TARGET", + "AbortController", + "AbortSignal", + "AbsoluteOrientationSensor", + "AbstractRange", + "Accelerometer", + "AddSearchProvider", + "AggregateError", + "AnalyserNode", + "Animation", + "AnimationEffect", + "AnimationEvent", + "AnimationPlaybackEvent", + "AnimationTimeline", + "AnonXMLHttpRequest", + "Any", + "ApplicationCache", + "ApplicationCacheErrorEvent", + "Array", + "ArrayBuffer", + "ArrayType", + "Atomics", + "Attr", + "Audio", + "AudioBuffer", + "AudioBufferSourceNode", + "AudioContext", + "AudioDestinationNode", + "AudioListener", + "AudioNode", + "AudioParam", + "AudioParamMap", + "AudioProcessingEvent", + "AudioScheduledSourceNode", + "AudioStreamTrack", + "AudioWorklet", + "AudioWorkletNode", + "AuthenticatorAssertionResponse", + "AuthenticatorAttestationResponse", + "AuthenticatorResponse", + "AutocompleteErrorEvent", + "BACK", + "BAD_BOUNDARYPOINTS_ERR", + "BAD_REQUEST", + "BANDPASS", + "BLEND", + "BLEND_COLOR", + "BLEND_DST_ALPHA", + "BLEND_DST_RGB", + "BLEND_EQUATION", + "BLEND_EQUATION_ALPHA", + "BLEND_EQUATION_RGB", + "BLEND_SRC_ALPHA", + "BLEND_SRC_RGB", + "BLUE_BITS", + "BLUR", + "BOOL", + "BOOLEAN_TYPE", + "BOOL_VEC2", + "BOOL_VEC3", + "BOOL_VEC4", + "BOTH", + "BROWSER_DEFAULT_WEBGL", + "BUBBLING_PHASE", + "BUFFER_SIZE", + "BUFFER_USAGE", + "BYTE", + "BYTES_PER_ELEMENT", + "BackgroundFetchManager", + "BackgroundFetchRecord", + "BackgroundFetchRegistration", + "BarProp", + "BarcodeDetector", + "BaseAudioContext", + "BaseHref", + "BatteryManager", + "BeforeInstallPromptEvent", + "BeforeLoadEvent", + "BeforeUnloadEvent", + "BigInt", + "BigInt64Array", + "BigUint64Array", + "BiquadFilterNode", + "Blob", + "BlobEvent", + "Bluetooth", + "BluetoothCharacteristicProperties", + "BluetoothDevice", + "BluetoothRemoteGATTCharacteristic", + "BluetoothRemoteGATTDescriptor", + "BluetoothRemoteGATTServer", + "BluetoothRemoteGATTService", + "BluetoothUUID", + "Boolean", + "BroadcastChannel", + "ByteLengthQueuingStrategy", + "CAPTURING_PHASE", + "CCW", + "CDATASection", + "CDATA_SECTION_NODE", + "CHANGE", + "CHARSET_RULE", + "CHECKING", + "CLAMP_TO_EDGE", + "CLICK", + "CLOSED", + "CLOSING", + "COLOR", + "COLOR_ATTACHMENT0", + "COLOR_ATTACHMENT1", + "COLOR_ATTACHMENT10", + "COLOR_ATTACHMENT11", + "COLOR_ATTACHMENT12", + "COLOR_ATTACHMENT13", + "COLOR_ATTACHMENT14", + "COLOR_ATTACHMENT15", + "COLOR_ATTACHMENT2", + "COLOR_ATTACHMENT3", + "COLOR_ATTACHMENT4", + "COLOR_ATTACHMENT5", + "COLOR_ATTACHMENT6", + "COLOR_ATTACHMENT7", + "COLOR_ATTACHMENT8", + "COLOR_ATTACHMENT9", + "COLOR_BUFFER_BIT", + "COLOR_CLEAR_VALUE", + "COLOR_WRITEMASK", + "COMMENT_NODE", + "COMPARE_REF_TO_TEXTURE", + "COMPILE_STATUS", + "COMPRESSED_RGBA_S3TC_DXT1_EXT", + "COMPRESSED_RGBA_S3TC_DXT3_EXT", + "COMPRESSED_RGBA_S3TC_DXT5_EXT", + "COMPRESSED_RGB_S3TC_DXT1_EXT", + "COMPRESSED_TEXTURE_FORMATS", + "CONDITION_SATISFIED", + "CONFIGURATION_UNSUPPORTED", + "CONNECTING", + "CONSTANT_ALPHA", + "CONSTANT_COLOR", + "CONSTRAINT_ERR", + "CONTEXT_LOST_WEBGL", + "CONTROL_MASK", + "COPY_READ_BUFFER", + "COPY_READ_BUFFER_BINDING", + "COPY_WRITE_BUFFER", + "COPY_WRITE_BUFFER_BINDING", + "COUNTER_STYLE_RULE", + "CSS", + "CSS2Properties", + "CSSAnimation", + "CSSCharsetRule", + "CSSConditionRule", + "CSSCounterStyleRule", + "CSSFontFaceRule", + "CSSFontFeatureValuesRule", + "CSSGroupingRule", + "CSSImageValue", + "CSSImportRule", + "CSSKeyframeRule", + "CSSKeyframesRule", + "CSSKeywordValue", + "CSSMathInvert", + "CSSMathMax", + "CSSMathMin", + "CSSMathNegate", + "CSSMathProduct", + "CSSMathSum", + "CSSMathValue", + "CSSMatrixComponent", + "CSSMediaRule", + "CSSMozDocumentRule", + "CSSNameSpaceRule", + "CSSNamespaceRule", + "CSSNumericArray", + "CSSNumericValue", + "CSSPageRule", + "CSSPerspective", + "CSSPositionValue", + "CSSPrimitiveValue", + "CSSRotate", + "CSSRule", + "CSSRuleList", + "CSSScale", + "CSSSkew", + "CSSSkewX", + "CSSSkewY", + "CSSStyleDeclaration", + "CSSStyleRule", + "CSSStyleSheet", + "CSSStyleValue", + "CSSSupportsRule", + "CSSTransformComponent", + "CSSTransformValue", + "CSSTransition", + "CSSTranslate", + "CSSUnitValue", + "CSSUnknownRule", + "CSSUnparsedValue", + "CSSValue", + "CSSValueList", + "CSSVariableReferenceValue", + "CSSVariablesDeclaration", + "CSSVariablesRule", + "CSSViewportRule", + "CSS_ATTR", + "CSS_CM", + "CSS_COUNTER", + "CSS_CUSTOM", + "CSS_DEG", + "CSS_DIMENSION", + "CSS_EMS", + "CSS_EXS", + "CSS_FILTER_BLUR", + "CSS_FILTER_BRIGHTNESS", + "CSS_FILTER_CONTRAST", + "CSS_FILTER_CUSTOM", + "CSS_FILTER_DROP_SHADOW", + "CSS_FILTER_GRAYSCALE", + "CSS_FILTER_HUE_ROTATE", + "CSS_FILTER_INVERT", + "CSS_FILTER_OPACITY", + "CSS_FILTER_REFERENCE", + "CSS_FILTER_SATURATE", + "CSS_FILTER_SEPIA", + "CSS_GRAD", + "CSS_HZ", + "CSS_IDENT", + "CSS_IN", + "CSS_INHERIT", + "CSS_KHZ", + "CSS_MATRIX", + "CSS_MATRIX3D", + "CSS_MM", + "CSS_MS", + "CSS_NUMBER", + "CSS_PC", + "CSS_PERCENTAGE", + "CSS_PERSPECTIVE", + "CSS_PRIMITIVE_VALUE", + "CSS_PT", + "CSS_PX", + "CSS_RAD", + "CSS_RECT", + "CSS_RGBCOLOR", + "CSS_ROTATE", + "CSS_ROTATE3D", + "CSS_ROTATEX", + "CSS_ROTATEY", + "CSS_ROTATEZ", + "CSS_S", + "CSS_SCALE", + "CSS_SCALE3D", + "CSS_SCALEX", + "CSS_SCALEY", + "CSS_SCALEZ", + "CSS_SKEW", + "CSS_SKEWX", + "CSS_SKEWY", + "CSS_STRING", + "CSS_TRANSLATE", + "CSS_TRANSLATE3D", + "CSS_TRANSLATEX", + "CSS_TRANSLATEY", + "CSS_TRANSLATEZ", + "CSS_UNKNOWN", + "CSS_URI", + "CSS_VALUE_LIST", + "CSS_VH", + "CSS_VMAX", + "CSS_VMIN", + "CSS_VW", + "CULL_FACE", + "CULL_FACE_MODE", + "CURRENT_PROGRAM", + "CURRENT_QUERY", + "CURRENT_VERTEX_ATTRIB", + "CUSTOM", + "CW", + "Cache", + "CacheStorage", + "CanvasCaptureMediaStream", + "CanvasCaptureMediaStreamTrack", + "CanvasGradient", + "CanvasPattern", + "CanvasRenderingContext2D", + "CaretPosition", + "ChannelMergerNode", + "ChannelSplitterNode", + "CharacterData", + "ClientRect", + "ClientRectList", + "Clipboard", + "ClipboardEvent", + "ClipboardItem", + "CloseEvent", + "Collator", + "CommandEvent", + "Comment", + "CompileError", + "CompositionEvent", + "CompressionStream", + "Console", + "ConstantSourceNode", + "Controllers", + "ConvolverNode", + "CountQueuingStrategy", + "Counter", + "Credential", + "CredentialsContainer", + "Crypto", + "CryptoKey", + "CustomElementRegistry", + "CustomEvent", + "DATABASE_ERR", + "DATA_CLONE_ERR", + "DATA_ERR", + "DBLCLICK", + "DECR", + "DECR_WRAP", + "DELETE_STATUS", + "DEPTH", + "DEPTH24_STENCIL8", + "DEPTH32F_STENCIL8", + "DEPTH_ATTACHMENT", + "DEPTH_BITS", + "DEPTH_BUFFER_BIT", + "DEPTH_CLEAR_VALUE", + "DEPTH_COMPONENT", + "DEPTH_COMPONENT16", + "DEPTH_COMPONENT24", + "DEPTH_COMPONENT32F", + "DEPTH_FUNC", + "DEPTH_RANGE", + "DEPTH_STENCIL", + "DEPTH_STENCIL_ATTACHMENT", + "DEPTH_TEST", + "DEPTH_WRITEMASK", + "DEVICE_INELIGIBLE", + "DIRECTION_DOWN", + "DIRECTION_LEFT", + "DIRECTION_RIGHT", + "DIRECTION_UP", + "DISABLED", + "DISPATCH_REQUEST_ERR", + "DITHER", + "DOCUMENT_FRAGMENT_NODE", + "DOCUMENT_NODE", + "DOCUMENT_POSITION_CONTAINED_BY", + "DOCUMENT_POSITION_CONTAINS", + "DOCUMENT_POSITION_DISCONNECTED", + "DOCUMENT_POSITION_FOLLOWING", + "DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC", + "DOCUMENT_POSITION_PRECEDING", + "DOCUMENT_TYPE_NODE", + "DOMCursor", + "DOMError", + "DOMException", + "DOMImplementation", + "DOMImplementationLS", + "DOMMatrix", + "DOMMatrixReadOnly", + "DOMParser", + "DOMPoint", + "DOMPointReadOnly", + "DOMQuad", + "DOMRect", + "DOMRectList", + "DOMRectReadOnly", + "DOMRequest", + "DOMSTRING_SIZE_ERR", + "DOMSettableTokenList", + "DOMStringList", + "DOMStringMap", + "DOMTokenList", + "DOMTransactionEvent", + "DOM_DELTA_LINE", + "DOM_DELTA_PAGE", + "DOM_DELTA_PIXEL", + "DOM_INPUT_METHOD_DROP", + "DOM_INPUT_METHOD_HANDWRITING", + "DOM_INPUT_METHOD_IME", + "DOM_INPUT_METHOD_KEYBOARD", + "DOM_INPUT_METHOD_MULTIMODAL", + "DOM_INPUT_METHOD_OPTION", + "DOM_INPUT_METHOD_PASTE", + "DOM_INPUT_METHOD_SCRIPT", + "DOM_INPUT_METHOD_UNKNOWN", + "DOM_INPUT_METHOD_VOICE", + "DOM_KEY_LOCATION_JOYSTICK", + "DOM_KEY_LOCATION_LEFT", + "DOM_KEY_LOCATION_MOBILE", + "DOM_KEY_LOCATION_NUMPAD", + "DOM_KEY_LOCATION_RIGHT", + "DOM_KEY_LOCATION_STANDARD", + "DOM_VK_0", + "DOM_VK_1", + "DOM_VK_2", + "DOM_VK_3", + "DOM_VK_4", + "DOM_VK_5", + "DOM_VK_6", + "DOM_VK_7", + "DOM_VK_8", + "DOM_VK_9", + "DOM_VK_A", + "DOM_VK_ACCEPT", + "DOM_VK_ADD", + "DOM_VK_ALT", + "DOM_VK_ALTGR", + "DOM_VK_AMPERSAND", + "DOM_VK_ASTERISK", + "DOM_VK_AT", + "DOM_VK_ATTN", + "DOM_VK_B", + "DOM_VK_BACKSPACE", + "DOM_VK_BACK_QUOTE", + "DOM_VK_BACK_SLASH", + "DOM_VK_BACK_SPACE", + "DOM_VK_C", + "DOM_VK_CANCEL", + "DOM_VK_CAPS_LOCK", + "DOM_VK_CIRCUMFLEX", + "DOM_VK_CLEAR", + "DOM_VK_CLOSE_BRACKET", + "DOM_VK_CLOSE_CURLY_BRACKET", + "DOM_VK_CLOSE_PAREN", + "DOM_VK_COLON", + "DOM_VK_COMMA", + "DOM_VK_CONTEXT_MENU", + "DOM_VK_CONTROL", + "DOM_VK_CONVERT", + "DOM_VK_CRSEL", + "DOM_VK_CTRL", + "DOM_VK_D", + "DOM_VK_DECIMAL", + "DOM_VK_DELETE", + "DOM_VK_DIVIDE", + "DOM_VK_DOLLAR", + "DOM_VK_DOUBLE_QUOTE", + "DOM_VK_DOWN", + "DOM_VK_E", + "DOM_VK_EISU", + "DOM_VK_END", + "DOM_VK_ENTER", + "DOM_VK_EQUALS", + "DOM_VK_EREOF", + "DOM_VK_ESCAPE", + "DOM_VK_EXCLAMATION", + "DOM_VK_EXECUTE", + "DOM_VK_EXSEL", + "DOM_VK_F", + "DOM_VK_F1", + "DOM_VK_F10", + "DOM_VK_F11", + "DOM_VK_F12", + "DOM_VK_F13", + "DOM_VK_F14", + "DOM_VK_F15", + "DOM_VK_F16", + "DOM_VK_F17", + "DOM_VK_F18", + "DOM_VK_F19", + "DOM_VK_F2", + "DOM_VK_F20", + "DOM_VK_F21", + "DOM_VK_F22", + "DOM_VK_F23", + "DOM_VK_F24", + "DOM_VK_F25", + "DOM_VK_F26", + "DOM_VK_F27", + "DOM_VK_F28", + "DOM_VK_F29", + "DOM_VK_F3", + "DOM_VK_F30", + "DOM_VK_F31", + "DOM_VK_F32", + "DOM_VK_F33", + "DOM_VK_F34", + "DOM_VK_F35", + "DOM_VK_F36", + "DOM_VK_F4", + "DOM_VK_F5", + "DOM_VK_F6", + "DOM_VK_F7", + "DOM_VK_F8", + "DOM_VK_F9", + "DOM_VK_FINAL", + "DOM_VK_FRONT", + "DOM_VK_G", + "DOM_VK_GREATER_THAN", + "DOM_VK_H", + "DOM_VK_HANGUL", + "DOM_VK_HANJA", + "DOM_VK_HASH", + "DOM_VK_HELP", + "DOM_VK_HK_TOGGLE", + "DOM_VK_HOME", + "DOM_VK_HYPHEN_MINUS", + "DOM_VK_I", + "DOM_VK_INSERT", + "DOM_VK_J", + "DOM_VK_JUNJA", + "DOM_VK_K", + "DOM_VK_KANA", + "DOM_VK_KANJI", + "DOM_VK_L", + "DOM_VK_LEFT", + "DOM_VK_LEFT_TAB", + "DOM_VK_LESS_THAN", + "DOM_VK_M", + "DOM_VK_META", + "DOM_VK_MODECHANGE", + "DOM_VK_MULTIPLY", + "DOM_VK_N", + "DOM_VK_NONCONVERT", + "DOM_VK_NUMPAD0", + "DOM_VK_NUMPAD1", + "DOM_VK_NUMPAD2", + "DOM_VK_NUMPAD3", + "DOM_VK_NUMPAD4", + "DOM_VK_NUMPAD5", + "DOM_VK_NUMPAD6", + "DOM_VK_NUMPAD7", + "DOM_VK_NUMPAD8", + "DOM_VK_NUMPAD9", + "DOM_VK_NUM_LOCK", + "DOM_VK_O", + "DOM_VK_OEM_1", + "DOM_VK_OEM_102", + "DOM_VK_OEM_2", + "DOM_VK_OEM_3", + "DOM_VK_OEM_4", + "DOM_VK_OEM_5", + "DOM_VK_OEM_6", + "DOM_VK_OEM_7", + "DOM_VK_OEM_8", + "DOM_VK_OEM_COMMA", + "DOM_VK_OEM_MINUS", + "DOM_VK_OEM_PERIOD", + "DOM_VK_OEM_PLUS", + "DOM_VK_OPEN_BRACKET", + "DOM_VK_OPEN_CURLY_BRACKET", + "DOM_VK_OPEN_PAREN", + "DOM_VK_P", + "DOM_VK_PA1", + "DOM_VK_PAGEDOWN", + "DOM_VK_PAGEUP", + "DOM_VK_PAGE_DOWN", + "DOM_VK_PAGE_UP", + "DOM_VK_PAUSE", + "DOM_VK_PERCENT", + "DOM_VK_PERIOD", + "DOM_VK_PIPE", + "DOM_VK_PLAY", + "DOM_VK_PLUS", + "DOM_VK_PRINT", + "DOM_VK_PRINTSCREEN", + "DOM_VK_PROCESSKEY", + "DOM_VK_PROPERITES", + "DOM_VK_Q", + "DOM_VK_QUESTION_MARK", + "DOM_VK_QUOTE", + "DOM_VK_R", + "DOM_VK_REDO", + "DOM_VK_RETURN", + "DOM_VK_RIGHT", + "DOM_VK_S", + "DOM_VK_SCROLL_LOCK", + "DOM_VK_SELECT", + "DOM_VK_SEMICOLON", + "DOM_VK_SEPARATOR", + "DOM_VK_SHIFT", + "DOM_VK_SLASH", + "DOM_VK_SLEEP", + "DOM_VK_SPACE", + "DOM_VK_SUBTRACT", + "DOM_VK_T", + "DOM_VK_TAB", + "DOM_VK_TILDE", + "DOM_VK_U", + "DOM_VK_UNDERSCORE", + "DOM_VK_UNDO", + "DOM_VK_UNICODE", + "DOM_VK_UP", + "DOM_VK_V", + "DOM_VK_VOLUME_DOWN", + "DOM_VK_VOLUME_MUTE", + "DOM_VK_VOLUME_UP", + "DOM_VK_W", + "DOM_VK_WIN", + "DOM_VK_WINDOW", + "DOM_VK_WIN_ICO_00", + "DOM_VK_WIN_ICO_CLEAR", + "DOM_VK_WIN_ICO_HELP", + "DOM_VK_WIN_OEM_ATTN", + "DOM_VK_WIN_OEM_AUTO", + "DOM_VK_WIN_OEM_BACKTAB", + "DOM_VK_WIN_OEM_CLEAR", + "DOM_VK_WIN_OEM_COPY", + "DOM_VK_WIN_OEM_CUSEL", + "DOM_VK_WIN_OEM_ENLW", + "DOM_VK_WIN_OEM_FINISH", + "DOM_VK_WIN_OEM_FJ_JISHO", + "DOM_VK_WIN_OEM_FJ_LOYA", + "DOM_VK_WIN_OEM_FJ_MASSHOU", + "DOM_VK_WIN_OEM_FJ_ROYA", + "DOM_VK_WIN_OEM_FJ_TOUROKU", + "DOM_VK_WIN_OEM_JUMP", + "DOM_VK_WIN_OEM_PA1", + "DOM_VK_WIN_OEM_PA2", + "DOM_VK_WIN_OEM_PA3", + "DOM_VK_WIN_OEM_RESET", + "DOM_VK_WIN_OEM_WSCTRL", + "DOM_VK_X", + "DOM_VK_XF86XK_ADD_FAVORITE", + "DOM_VK_XF86XK_APPLICATION_LEFT", + "DOM_VK_XF86XK_APPLICATION_RIGHT", + "DOM_VK_XF86XK_AUDIO_CYCLE_TRACK", + "DOM_VK_XF86XK_AUDIO_FORWARD", + "DOM_VK_XF86XK_AUDIO_LOWER_VOLUME", + "DOM_VK_XF86XK_AUDIO_MEDIA", + "DOM_VK_XF86XK_AUDIO_MUTE", + "DOM_VK_XF86XK_AUDIO_NEXT", + "DOM_VK_XF86XK_AUDIO_PAUSE", + "DOM_VK_XF86XK_AUDIO_PLAY", + "DOM_VK_XF86XK_AUDIO_PREV", + "DOM_VK_XF86XK_AUDIO_RAISE_VOLUME", + "DOM_VK_XF86XK_AUDIO_RANDOM_PLAY", + "DOM_VK_XF86XK_AUDIO_RECORD", + "DOM_VK_XF86XK_AUDIO_REPEAT", + "DOM_VK_XF86XK_AUDIO_REWIND", + "DOM_VK_XF86XK_AUDIO_STOP", + "DOM_VK_XF86XK_AWAY", + "DOM_VK_XF86XK_BACK", + "DOM_VK_XF86XK_BACK_FORWARD", + "DOM_VK_XF86XK_BATTERY", + "DOM_VK_XF86XK_BLUE", + "DOM_VK_XF86XK_BLUETOOTH", + "DOM_VK_XF86XK_BOOK", + "DOM_VK_XF86XK_BRIGHTNESS_ADJUST", + "DOM_VK_XF86XK_CALCULATOR", + "DOM_VK_XF86XK_CALENDAR", + "DOM_VK_XF86XK_CD", + "DOM_VK_XF86XK_CLOSE", + "DOM_VK_XF86XK_COMMUNITY", + "DOM_VK_XF86XK_CONTRAST_ADJUST", + "DOM_VK_XF86XK_COPY", + "DOM_VK_XF86XK_CUT", + "DOM_VK_XF86XK_CYCLE_ANGLE", + "DOM_VK_XF86XK_DISPLAY", + "DOM_VK_XF86XK_DOCUMENTS", + "DOM_VK_XF86XK_DOS", + "DOM_VK_XF86XK_EJECT", + "DOM_VK_XF86XK_EXCEL", + "DOM_VK_XF86XK_EXPLORER", + "DOM_VK_XF86XK_FAVORITES", + "DOM_VK_XF86XK_FINANCE", + "DOM_VK_XF86XK_FORWARD", + "DOM_VK_XF86XK_FRAME_BACK", + "DOM_VK_XF86XK_FRAME_FORWARD", + "DOM_VK_XF86XK_GAME", + "DOM_VK_XF86XK_GO", + "DOM_VK_XF86XK_GREEN", + "DOM_VK_XF86XK_HIBERNATE", + "DOM_VK_XF86XK_HISTORY", + "DOM_VK_XF86XK_HOME_PAGE", + "DOM_VK_XF86XK_HOT_LINKS", + "DOM_VK_XF86XK_I_TOUCH", + "DOM_VK_XF86XK_KBD_BRIGHTNESS_DOWN", + "DOM_VK_XF86XK_KBD_BRIGHTNESS_UP", + "DOM_VK_XF86XK_KBD_LIGHT_ON_OFF", + "DOM_VK_XF86XK_LAUNCH0", + "DOM_VK_XF86XK_LAUNCH1", + "DOM_VK_XF86XK_LAUNCH2", + "DOM_VK_XF86XK_LAUNCH3", + "DOM_VK_XF86XK_LAUNCH4", + "DOM_VK_XF86XK_LAUNCH5", + "DOM_VK_XF86XK_LAUNCH6", + "DOM_VK_XF86XK_LAUNCH7", + "DOM_VK_XF86XK_LAUNCH8", + "DOM_VK_XF86XK_LAUNCH9", + "DOM_VK_XF86XK_LAUNCH_A", + "DOM_VK_XF86XK_LAUNCH_B", + "DOM_VK_XF86XK_LAUNCH_C", + "DOM_VK_XF86XK_LAUNCH_D", + "DOM_VK_XF86XK_LAUNCH_E", + "DOM_VK_XF86XK_LAUNCH_F", + "DOM_VK_XF86XK_LIGHT_BULB", + "DOM_VK_XF86XK_LOG_OFF", + "DOM_VK_XF86XK_MAIL", + "DOM_VK_XF86XK_MAIL_FORWARD", + "DOM_VK_XF86XK_MARKET", + "DOM_VK_XF86XK_MEETING", + "DOM_VK_XF86XK_MEMO", + "DOM_VK_XF86XK_MENU_KB", + "DOM_VK_XF86XK_MENU_PB", + "DOM_VK_XF86XK_MESSENGER", + "DOM_VK_XF86XK_MON_BRIGHTNESS_DOWN", + "DOM_VK_XF86XK_MON_BRIGHTNESS_UP", + "DOM_VK_XF86XK_MUSIC", + "DOM_VK_XF86XK_MY_COMPUTER", + "DOM_VK_XF86XK_MY_SITES", + "DOM_VK_XF86XK_NEW", + "DOM_VK_XF86XK_NEWS", + "DOM_VK_XF86XK_OFFICE_HOME", + "DOM_VK_XF86XK_OPEN", + "DOM_VK_XF86XK_OPEN_URL", + "DOM_VK_XF86XK_OPTION", + "DOM_VK_XF86XK_PASTE", + "DOM_VK_XF86XK_PHONE", + "DOM_VK_XF86XK_PICTURES", + "DOM_VK_XF86XK_POWER_DOWN", + "DOM_VK_XF86XK_POWER_OFF", + "DOM_VK_XF86XK_RED", + "DOM_VK_XF86XK_REFRESH", + "DOM_VK_XF86XK_RELOAD", + "DOM_VK_XF86XK_REPLY", + "DOM_VK_XF86XK_ROCKER_DOWN", + "DOM_VK_XF86XK_ROCKER_ENTER", + "DOM_VK_XF86XK_ROCKER_UP", + "DOM_VK_XF86XK_ROTATE_WINDOWS", + "DOM_VK_XF86XK_ROTATION_KB", + "DOM_VK_XF86XK_ROTATION_PB", + "DOM_VK_XF86XK_SAVE", + "DOM_VK_XF86XK_SCREEN_SAVER", + "DOM_VK_XF86XK_SCROLL_CLICK", + "DOM_VK_XF86XK_SCROLL_DOWN", + "DOM_VK_XF86XK_SCROLL_UP", + "DOM_VK_XF86XK_SEARCH", + "DOM_VK_XF86XK_SEND", + "DOM_VK_XF86XK_SHOP", + "DOM_VK_XF86XK_SPELL", + "DOM_VK_XF86XK_SPLIT_SCREEN", + "DOM_VK_XF86XK_STANDBY", + "DOM_VK_XF86XK_START", + "DOM_VK_XF86XK_STOP", + "DOM_VK_XF86XK_SUBTITLE", + "DOM_VK_XF86XK_SUPPORT", + "DOM_VK_XF86XK_SUSPEND", + "DOM_VK_XF86XK_TASK_PANE", + "DOM_VK_XF86XK_TERMINAL", + "DOM_VK_XF86XK_TIME", + "DOM_VK_XF86XK_TOOLS", + "DOM_VK_XF86XK_TOP_MENU", + "DOM_VK_XF86XK_TO_DO_LIST", + "DOM_VK_XF86XK_TRAVEL", + "DOM_VK_XF86XK_USER1KB", + "DOM_VK_XF86XK_USER2KB", + "DOM_VK_XF86XK_USER_PB", + "DOM_VK_XF86XK_UWB", + "DOM_VK_XF86XK_VENDOR_HOME", + "DOM_VK_XF86XK_VIDEO", + "DOM_VK_XF86XK_VIEW", + "DOM_VK_XF86XK_WAKE_UP", + "DOM_VK_XF86XK_WEB_CAM", + "DOM_VK_XF86XK_WHEEL_BUTTON", + "DOM_VK_XF86XK_WLAN", + "DOM_VK_XF86XK_WORD", + "DOM_VK_XF86XK_WWW", + "DOM_VK_XF86XK_XFER", + "DOM_VK_XF86XK_YELLOW", + "DOM_VK_XF86XK_ZOOM_IN", + "DOM_VK_XF86XK_ZOOM_OUT", + "DOM_VK_Y", + "DOM_VK_Z", + "DOM_VK_ZOOM", + "DONE", + "DONT_CARE", + "DOWNLOADING", + "DRAGDROP", + "DRAW_BUFFER0", + "DRAW_BUFFER1", + "DRAW_BUFFER10", + "DRAW_BUFFER11", + "DRAW_BUFFER12", + "DRAW_BUFFER13", + "DRAW_BUFFER14", + "DRAW_BUFFER15", + "DRAW_BUFFER2", + "DRAW_BUFFER3", + "DRAW_BUFFER4", + "DRAW_BUFFER5", + "DRAW_BUFFER6", + "DRAW_BUFFER7", + "DRAW_BUFFER8", + "DRAW_BUFFER9", + "DRAW_FRAMEBUFFER", + "DRAW_FRAMEBUFFER_BINDING", + "DST_ALPHA", + "DST_COLOR", + "DYNAMIC_COPY", + "DYNAMIC_DRAW", + "DYNAMIC_READ", + "DataChannel", + "DataTransfer", + "DataTransferItem", + "DataTransferItemList", + "DataView", + "Date", + "DateTimeFormat", + "DecompressionStream", + "DelayNode", + "DeprecationReportBody", + "DesktopNotification", + "DesktopNotificationCenter", + "DeviceLightEvent", + "DeviceMotionEvent", + "DeviceMotionEventAcceleration", + "DeviceMotionEventRotationRate", + "DeviceOrientationEvent", + "DeviceProximityEvent", + "DeviceStorage", + "DeviceStorageChangeEvent", + "Directory", + "DisplayNames", + "Document", + "DocumentFragment", + "DocumentTimeline", + "DocumentType", + "DragEvent", + "DynamicsCompressorNode", + "E", + "ELEMENT_ARRAY_BUFFER", + "ELEMENT_ARRAY_BUFFER_BINDING", + "ELEMENT_NODE", + "EMPTY", + "ENCODING_ERR", + "ENDED", + "END_TO_END", + "END_TO_START", + "ENTITY_NODE", + "ENTITY_REFERENCE_NODE", + "EPSILON", + "EQUAL", + "EQUALPOWER", + "ERROR", + "EXPONENTIAL_DISTANCE", + "exports", + "Element", + "ElementInternals", + "ElementQuery", + "EnterPictureInPictureEvent", + "Entity", + "EntityReference", + "Error", + "ErrorEvent", + "EvalError", + "Event", + "EventException", + "EventSource", + "EventTarget", + "External", + "FASTEST", + "FIDOSDK", + "FILTER_ACCEPT", + "FILTER_INTERRUPT", + "FILTER_REJECT", + "FILTER_SKIP", + "FINISHED_STATE", + "FIRST_ORDERED_NODE_TYPE", + "FLOAT", + "FLOAT_32_UNSIGNED_INT_24_8_REV", + "FLOAT_MAT2", + "FLOAT_MAT2x3", + "FLOAT_MAT2x4", + "FLOAT_MAT3", + "FLOAT_MAT3x2", + "FLOAT_MAT3x4", + "FLOAT_MAT4", + "FLOAT_MAT4x2", + "FLOAT_MAT4x3", + "FLOAT_VEC2", + "FLOAT_VEC3", + "FLOAT_VEC4", + "FOCUS", + "FONT_FACE_RULE", + "FONT_FEATURE_VALUES_RULE", + "FRAGMENT_SHADER", + "FRAGMENT_SHADER_DERIVATIVE_HINT", + "FRAGMENT_SHADER_DERIVATIVE_HINT_OES", + "FRAMEBUFFER", + "FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE", + "FRAMEBUFFER_ATTACHMENT_BLUE_SIZE", + "FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING", + "FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE", + "FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE", + "FRAMEBUFFER_ATTACHMENT_GREEN_SIZE", + "FRAMEBUFFER_ATTACHMENT_OBJECT_NAME", + "FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE", + "FRAMEBUFFER_ATTACHMENT_RED_SIZE", + "FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE", + "FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE", + "FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER", + "FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL", + "FRAMEBUFFER_BINDING", + "FRAMEBUFFER_COMPLETE", + "FRAMEBUFFER_DEFAULT", + "FRAMEBUFFER_INCOMPLETE_ATTACHMENT", + "FRAMEBUFFER_INCOMPLETE_DIMENSIONS", + "FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT", + "FRAMEBUFFER_INCOMPLETE_MULTISAMPLE", + "FRAMEBUFFER_UNSUPPORTED", + "FRONT", + "FRONT_AND_BACK", + "FRONT_FACE", + "FUNC_ADD", + "FUNC_REVERSE_SUBTRACT", + "FUNC_SUBTRACT", + "FeaturePolicy", + "FeaturePolicyViolationReportBody", + "FederatedCredential", + "Feed", + "FeedEntry", + "File", + "FileError", + "FileList", + "FileReader", + "FileSystem", + "FileSystemDirectoryEntry", + "FileSystemDirectoryReader", + "FileSystemEntry", + "FileSystemFileEntry", + "FinalizationRegistry", + "FindInPage", + "Float32Array", + "Float64Array", + "FocusEvent", + "FontFace", + "FontFaceSet", + "FontFaceSetLoadEvent", + "FormData", + "FormDataEvent", + "FragmentDirective", + "Function", + "GENERATE_MIPMAP_HINT", + "GEQUAL", + "GREATER", + "GREEN_BITS", + "GainNode", + "Gamepad", + "GamepadAxisMoveEvent", + "GamepadButton", + "GamepadButtonEvent", + "GamepadEvent", + "GamepadHapticActuator", + "GamepadPose", + "Geolocation", + "GeolocationCoordinates", + "GeolocationPosition", + "GeolocationPositionError", + "GestureEvent", + "Global", + "Gyroscope", + "HALF_FLOAT", + "HAVE_CURRENT_DATA", + "HAVE_ENOUGH_DATA", + "HAVE_FUTURE_DATA", + "HAVE_METADATA", + "HAVE_NOTHING", + "HEADERS_RECEIVED", + "HIDDEN", + "HIERARCHY_REQUEST_ERR", + "HIGHPASS", + "HIGHSHELF", + "HIGH_FLOAT", + "HIGH_INT", + "HORIZONTAL", + "HORIZONTAL_AXIS", + "HRTF", + "HTMLAllCollection", + "HTMLAnchorElement", + "HTMLAppletElement", + "HTMLAreaElement", + "HTMLAudioElement", + "HTMLBRElement", + "HTMLBaseElement", + "HTMLBaseFontElement", + "HTMLBlockquoteElement", + "HTMLBodyElement", + "HTMLButtonElement", + "HTMLCanvasElement", + "HTMLCollection", + "HTMLCommandElement", + "HTMLContentElement", + "HTMLDListElement", + "HTMLDataElement", + "HTMLDataListElement", + "HTMLDetailsElement", + "HTMLDialogElement", + "HTMLDirectoryElement", + "HTMLDivElement", + "HTMLDocument", + "HTMLElement", + "HTMLEmbedElement", + "HTMLFieldSetElement", + "HTMLFontElement", + "HTMLFormControlsCollection", + "HTMLFormElement", + "HTMLFrameElement", + "HTMLFrameSetElement", + "HTMLHRElement", + "HTMLHeadElement", + "HTMLHeadingElement", + "HTMLHtmlElement", + "HTMLIFrameElement", + "HTMLImageElement", + "HTMLInputElement", + "HTMLIsIndexElement", + "HTMLKeygenElement", + "HTMLLIElement", + "HTMLLabelElement", + "HTMLLegendElement", + "HTMLLinkElement", + "HTMLMapElement", + "HTMLMarqueeElement", + "HTMLMediaElement", + "HTMLMenuElement", + "HTMLMenuItemElement", + "HTMLMetaElement", + "HTMLMeterElement", + "HTMLModElement", + "HTMLOListElement", + "HTMLObjectElement", + "HTMLOptGroupElement", + "HTMLOptionElement", + "HTMLOptionsCollection", + "HTMLOutputElement", + "HTMLParagraphElement", + "HTMLParamElement", + "HTMLPictureElement", + "HTMLPreElement", + "HTMLProgressElement", + "HTMLPropertiesCollection", + "HTMLQuoteElement", + "HTMLScriptElement", + "HTMLSelectElement", + "HTMLShadowElement", + "HTMLSlotElement", + "HTMLSourceElement", + "HTMLSpanElement", + "HTMLStyleElement", + "HTMLTableCaptionElement", + "HTMLTableCellElement", + "HTMLTableColElement", + "HTMLTableElement", + "HTMLTableRowElement", + "HTMLTableSectionElement", + "HTMLTemplateElement", + "HTMLTextAreaElement", + "HTMLTimeElement", + "HTMLTitleElement", + "HTMLTrackElement", + "HTMLUListElement", + "HTMLUnknownElement", + "HTMLVideoElement", + "HashChangeEvent", + "Headers", + "History", + "Hz", + "ICE_CHECKING", + "ICE_CLOSED", + "ICE_COMPLETED", + "ICE_CONNECTED", + "ICE_FAILED", + "ICE_GATHERING", + "ICE_WAITING", + "IDBCursor", + "IDBCursorWithValue", + "IDBDatabase", + "IDBDatabaseException", + "IDBFactory", + "IDBFileHandle", + "IDBFileRequest", + "IDBIndex", + "IDBKeyRange", + "IDBMutableFile", + "IDBObjectStore", + "IDBOpenDBRequest", + "IDBRequest", + "IDBTransaction", + "IDBVersionChangeEvent", + "IDLE", + "IIRFilterNode", + "IMPLEMENTATION_COLOR_READ_FORMAT", + "IMPLEMENTATION_COLOR_READ_TYPE", + "IMPORT_RULE", + "INCR", + "INCR_WRAP", + "INDEX_SIZE_ERR", + "INT", + "INTERLEAVED_ATTRIBS", + "INT_2_10_10_10_REV", + "INT_SAMPLER_2D", + "INT_SAMPLER_2D_ARRAY", + "INT_SAMPLER_3D", + "INT_SAMPLER_CUBE", + "INT_VEC2", + "INT_VEC3", + "INT_VEC4", + "INUSE_ATTRIBUTE_ERR", + "INVALID_ACCESS_ERR", + "INVALID_CHARACTER_ERR", + "INVALID_ENUM", + "INVALID_EXPRESSION_ERR", + "INVALID_FRAMEBUFFER_OPERATION", + "INVALID_INDEX", + "INVALID_MODIFICATION_ERR", + "INVALID_NODE_TYPE_ERR", + "INVALID_OPERATION", + "INVALID_STATE_ERR", + "INVALID_VALUE", + "INVERSE_DISTANCE", + "INVERT", + "IceCandidate", + "IdleDeadline", + "Image", + "ImageBitmap", + "ImageBitmapRenderingContext", + "ImageCapture", + "ImageData", + "Infinity", + "InputDeviceCapabilities", + "InputDeviceInfo", + "InputEvent", + "InputMethodContext", + "InstallTrigger", + "InstallTriggerImpl", + "Instance", + "Int16Array", + "Int32Array", + "Int8Array", + "Intent", + "InternalError", + "IntersectionObserver", + "IntersectionObserverEntry", + "Intl", + "IsSearchProviderInstalled", + "Iterator", + "JSON", + "KEEP", + "KEYDOWN", + "KEYFRAMES_RULE", + "KEYFRAME_RULE", + "KEYPRESS", + "KEYUP", + "KeyEvent", + "Keyboard", + "KeyboardEvent", + "KeyboardLayoutMap", + "KeyframeEffect", + "LENGTHADJUST_SPACING", + "LENGTHADJUST_SPACINGANDGLYPHS", + "LENGTHADJUST_UNKNOWN", + "LEQUAL", + "LESS", + "LINEAR", + "LINEAR_DISTANCE", + "LINEAR_MIPMAP_LINEAR", + "LINEAR_MIPMAP_NEAREST", + "LINES", + "LINE_LOOP", + "LINE_STRIP", + "LINE_WIDTH", + "LINK_STATUS", + "LIVE", + "LN10", + "LN2", + "LOADED", + "LOADING", + "LOG10E", + "LOG2E", + "LOWPASS", + "LOWSHELF", + "LOW_FLOAT", + "LOW_INT", + "LSException", + "LSParserFilter", + "LUMINANCE", + "LUMINANCE_ALPHA", + "LargestContentfulPaint", + "LayoutShift", + "LayoutShiftAttribution", + "LinearAccelerationSensor", + "LinkError", + "ListFormat", + "LocalMediaStream", + "Locale", + "Location", + "Lock", + "LockManager", + "MAX", + "MAX_3D_TEXTURE_SIZE", + "MAX_ARRAY_TEXTURE_LAYERS", + "MAX_CLIENT_WAIT_TIMEOUT_WEBGL", + "MAX_COLOR_ATTACHMENTS", + "MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS", + "MAX_COMBINED_TEXTURE_IMAGE_UNITS", + "MAX_COMBINED_UNIFORM_BLOCKS", + "MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS", + "MAX_CUBE_MAP_TEXTURE_SIZE", + "MAX_DRAW_BUFFERS", + "MAX_ELEMENTS_INDICES", + "MAX_ELEMENTS_VERTICES", + "MAX_ELEMENT_INDEX", + "MAX_FRAGMENT_INPUT_COMPONENTS", + "MAX_FRAGMENT_UNIFORM_BLOCKS", + "MAX_FRAGMENT_UNIFORM_COMPONENTS", + "MAX_FRAGMENT_UNIFORM_VECTORS", + "MAX_PROGRAM_TEXEL_OFFSET", + "MAX_RENDERBUFFER_SIZE", + "MAX_SAFE_INTEGER", + "MAX_SAMPLES", + "MAX_SERVER_WAIT_TIMEOUT", + "MAX_TEXTURE_IMAGE_UNITS", + "MAX_TEXTURE_LOD_BIAS", + "MAX_TEXTURE_MAX_ANISOTROPY_EXT", + "MAX_TEXTURE_SIZE", + "MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS", + "MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS", + "MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS", + "MAX_UNIFORM_BLOCK_SIZE", + "MAX_UNIFORM_BUFFER_BINDINGS", + "MAX_VALUE", + "MAX_VARYING_COMPONENTS", + "MAX_VARYING_VECTORS", + "MAX_VERTEX_ATTRIBS", + "MAX_VERTEX_OUTPUT_COMPONENTS", + "MAX_VERTEX_TEXTURE_IMAGE_UNITS", + "MAX_VERTEX_UNIFORM_BLOCKS", + "MAX_VERTEX_UNIFORM_COMPONENTS", + "MAX_VERTEX_UNIFORM_VECTORS", + "MAX_VIEWPORT_DIMS", + "MEDIA_ERR_ABORTED", + "MEDIA_ERR_DECODE", + "MEDIA_ERR_ENCRYPTED", + "MEDIA_ERR_NETWORK", + "MEDIA_ERR_SRC_NOT_SUPPORTED", + "MEDIA_KEYERR_CLIENT", + "MEDIA_KEYERR_DOMAIN", + "MEDIA_KEYERR_HARDWARECHANGE", + "MEDIA_KEYERR_OUTPUT", + "MEDIA_KEYERR_SERVICE", + "MEDIA_KEYERR_UNKNOWN", + "MEDIA_RULE", + "MEDIUM_FLOAT", + "MEDIUM_INT", + "META_MASK", + "MIDIAccess", + "MIDIConnectionEvent", + "MIDIInput", + "MIDIInputMap", + "MIDIMessageEvent", + "MIDIOutput", + "MIDIOutputMap", + "MIDIPort", + "MIN", + "MIN_PROGRAM_TEXEL_OFFSET", + "MIN_SAFE_INTEGER", + "MIN_VALUE", + "MIRRORED_REPEAT", + "MODE_ASYNCHRONOUS", + "MODE_SYNCHRONOUS", + "MODIFICATION", + "MOUSEDOWN", + "MOUSEDRAG", + "MOUSEMOVE", + "MOUSEOUT", + "MOUSEOVER", + "MOUSEUP", + "MOZ_KEYFRAMES_RULE", + "MOZ_KEYFRAME_RULE", + "MOZ_SOURCE_CURSOR", + "MOZ_SOURCE_ERASER", + "MOZ_SOURCE_KEYBOARD", + "MOZ_SOURCE_MOUSE", + "MOZ_SOURCE_PEN", + "MOZ_SOURCE_TOUCH", + "MOZ_SOURCE_UNKNOWN", + "MSGESTURE_FLAG_BEGIN", + "MSGESTURE_FLAG_CANCEL", + "MSGESTURE_FLAG_END", + "MSGESTURE_FLAG_INERTIA", + "MSGESTURE_FLAG_NONE", + "MSPOINTER_TYPE_MOUSE", + "MSPOINTER_TYPE_PEN", + "MSPOINTER_TYPE_TOUCH", + "MS_ASYNC_CALLBACK_STATUS_ASSIGN_DELEGATE", + "MS_ASYNC_CALLBACK_STATUS_CANCEL", + "MS_ASYNC_CALLBACK_STATUS_CHOOSEANY", + "MS_ASYNC_CALLBACK_STATUS_ERROR", + "MS_ASYNC_CALLBACK_STATUS_JOIN", + "MS_ASYNC_OP_STATUS_CANCELED", + "MS_ASYNC_OP_STATUS_ERROR", + "MS_ASYNC_OP_STATUS_SUCCESS", + "MS_MANIPULATION_STATE_ACTIVE", + "MS_MANIPULATION_STATE_CANCELLED", + "MS_MANIPULATION_STATE_COMMITTED", + "MS_MANIPULATION_STATE_DRAGGING", + "MS_MANIPULATION_STATE_INERTIA", + "MS_MANIPULATION_STATE_PRESELECT", + "MS_MANIPULATION_STATE_SELECTING", + "MS_MANIPULATION_STATE_STOPPED", + "MS_MEDIA_ERR_ENCRYPTED", + "MS_MEDIA_KEYERR_CLIENT", + "MS_MEDIA_KEYERR_DOMAIN", + "MS_MEDIA_KEYERR_HARDWARECHANGE", + "MS_MEDIA_KEYERR_OUTPUT", + "MS_MEDIA_KEYERR_SERVICE", + "MS_MEDIA_KEYERR_UNKNOWN", + "Map", + "Math", + "MathMLElement", + "MediaCapabilities", + "MediaCapabilitiesInfo", + "MediaController", + "MediaDeviceInfo", + "MediaDevices", + "MediaElementAudioSourceNode", + "MediaEncryptedEvent", + "MediaError", + "MediaKeyError", + "MediaKeyEvent", + "MediaKeyMessageEvent", + "MediaKeyNeededEvent", + "MediaKeySession", + "MediaKeyStatusMap", + "MediaKeySystemAccess", + "MediaKeys", + "MediaList", + "MediaMetadata", + "MediaQueryList", + "MediaQueryListEvent", + "MediaRecorder", + "MediaRecorderErrorEvent", + "MediaSession", + "MediaSettingsRange", + "MediaSource", + "MediaStream", + "MediaStreamAudioDestinationNode", + "MediaStreamAudioSourceNode", + "MediaStreamEvent", + "MediaStreamTrack", + "MediaStreamTrackAudioSourceNode", + "MediaStreamTrackEvent", + "Memory", + "MessageChannel", + "MessageEvent", + "MessagePort", + "Methods", + "MimeType", + "MimeTypeArray", + "Module", + "MouseEvent", + "MouseScrollEvent", + "MozAnimation", + "MozAnimationDelay", + "MozAnimationDirection", + "MozAnimationDuration", + "MozAnimationFillMode", + "MozAnimationIterationCount", + "MozAnimationName", + "MozAnimationPlayState", + "MozAnimationTimingFunction", + "MozAppearance", + "MozBackfaceVisibility", + "MozBinding", + "MozBorderBottomColors", + "MozBorderEnd", + "MozBorderEndColor", + "MozBorderEndStyle", + "MozBorderEndWidth", + "MozBorderImage", + "MozBorderLeftColors", + "MozBorderRightColors", + "MozBorderStart", + "MozBorderStartColor", + "MozBorderStartStyle", + "MozBorderStartWidth", + "MozBorderTopColors", + "MozBoxAlign", + "MozBoxDirection", + "MozBoxFlex", + "MozBoxOrdinalGroup", + "MozBoxOrient", + "MozBoxPack", + "MozBoxSizing", + "MozCSSKeyframeRule", + "MozCSSKeyframesRule", + "MozColumnCount", + "MozColumnFill", + "MozColumnGap", + "MozColumnRule", + "MozColumnRuleColor", + "MozColumnRuleStyle", + "MozColumnRuleWidth", + "MozColumnWidth", + "MozColumns", + "MozContactChangeEvent", + "MozFloatEdge", + "MozFontFeatureSettings", + "MozFontLanguageOverride", + "MozForceBrokenImageIcon", + "MozHyphens", + "MozImageRegion", + "MozMarginEnd", + "MozMarginStart", + "MozMmsEvent", + "MozMmsMessage", + "MozMobileMessageThread", + "MozOSXFontSmoothing", + "MozOrient", + "MozOsxFontSmoothing", + "MozOutlineRadius", + "MozOutlineRadiusBottomleft", + "MozOutlineRadiusBottomright", + "MozOutlineRadiusTopleft", + "MozOutlineRadiusTopright", + "MozPaddingEnd", + "MozPaddingStart", + "MozPerspective", + "MozPerspectiveOrigin", + "MozPowerManager", + "MozSettingsEvent", + "MozSmsEvent", + "MozSmsMessage", + "MozStackSizing", + "MozTabSize", + "MozTextAlignLast", + "MozTextDecorationColor", + "MozTextDecorationLine", + "MozTextDecorationStyle", + "MozTextSizeAdjust", + "MozTransform", + "MozTransformOrigin", + "MozTransformStyle", + "MozTransition", + "MozTransitionDelay", + "MozTransitionDuration", + "MozTransitionProperty", + "MozTransitionTimingFunction", + "MozUserFocus", + "MozUserInput", + "MozUserModify", + "MozUserSelect", + "MozWindowDragging", + "MozWindowShadow", + "MutationEvent", + "MutationObserver", + "MutationRecord", + "NAMESPACE_ERR", + "NAMESPACE_RULE", + "NEAREST", + "NEAREST_MIPMAP_LINEAR", + "NEAREST_MIPMAP_NEAREST", + "NEGATIVE_INFINITY", + "NETWORK_EMPTY", + "NETWORK_ERR", + "NETWORK_IDLE", + "NETWORK_LOADED", + "NETWORK_LOADING", + "NETWORK_NO_SOURCE", + "NEVER", + "NEW", + "NEXT", + "NEXT_NO_DUPLICATE", + "NICEST", + "NODE_AFTER", + "NODE_BEFORE", + "NODE_BEFORE_AND_AFTER", + "NODE_INSIDE", + "NONE", + "NON_TRANSIENT_ERR", + "NOTATION_NODE", + "NOTCH", + "NOTEQUAL", + "NOT_ALLOWED_ERR", + "NOT_FOUND_ERR", + "NOT_READABLE_ERR", + "NOT_SUPPORTED_ERR", + "NO_DATA_ALLOWED_ERR", + "NO_ERR", + "NO_ERROR", + "NO_MODIFICATION_ALLOWED_ERR", + "NUMBER_TYPE", + "NUM_COMPRESSED_TEXTURE_FORMATS", + "NaN", + "NamedNodeMap", + "NavigationPreloadManager", + "Navigator", + "NearbyLinks", + "NetworkInformation", + "Node", + "NodeFilter", + "NodeIterator", + "NodeList", + "Notation", + "Notification", + "NotifyPaintEvent", + "Number", + "NumberFormat", + "OBJECT_TYPE", + "OBSOLETE", + "OK", + "ONE", + "ONE_MINUS_CONSTANT_ALPHA", + "ONE_MINUS_CONSTANT_COLOR", + "ONE_MINUS_DST_ALPHA", + "ONE_MINUS_DST_COLOR", + "ONE_MINUS_SRC_ALPHA", + "ONE_MINUS_SRC_COLOR", + "OPEN", + "OPENED", + "OPENING", + "ORDERED_NODE_ITERATOR_TYPE", + "ORDERED_NODE_SNAPSHOT_TYPE", + "OTHER_ERROR", + "OUT_OF_MEMORY", + "Object", + "OfflineAudioCompletionEvent", + "OfflineAudioContext", + "OfflineResourceList", + "OffscreenCanvas", + "OffscreenCanvasRenderingContext2D", + "Option", + "OrientationSensor", + "OscillatorNode", + "OverconstrainedError", + "OverflowEvent", + "PACK_ALIGNMENT", + "PACK_ROW_LENGTH", + "PACK_SKIP_PIXELS", + "PACK_SKIP_ROWS", + "PAGE_RULE", + "PARSE_ERR", + "PATHSEG_ARC_ABS", + "PATHSEG_ARC_REL", + "PATHSEG_CLOSEPATH", + "PATHSEG_CURVETO_CUBIC_ABS", + "PATHSEG_CURVETO_CUBIC_REL", + "PATHSEG_CURVETO_CUBIC_SMOOTH_ABS", + "PATHSEG_CURVETO_CUBIC_SMOOTH_REL", + "PATHSEG_CURVETO_QUADRATIC_ABS", + "PATHSEG_CURVETO_QUADRATIC_REL", + "PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS", + "PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL", + "PATHSEG_LINETO_ABS", + "PATHSEG_LINETO_HORIZONTAL_ABS", + "PATHSEG_LINETO_HORIZONTAL_REL", + "PATHSEG_LINETO_REL", + "PATHSEG_LINETO_VERTICAL_ABS", + "PATHSEG_LINETO_VERTICAL_REL", + "PATHSEG_MOVETO_ABS", + "PATHSEG_MOVETO_REL", + "PATHSEG_UNKNOWN", + "PATH_EXISTS_ERR", + "PEAKING", + "PERMISSION_DENIED", + "PERSISTENT", + "PI", + "PIXEL_PACK_BUFFER", + "PIXEL_PACK_BUFFER_BINDING", + "PIXEL_UNPACK_BUFFER", + "PIXEL_UNPACK_BUFFER_BINDING", + "PLAYING_STATE", + "POINTS", + "POLYGON_OFFSET_FACTOR", + "POLYGON_OFFSET_FILL", + "POLYGON_OFFSET_UNITS", + "POSITION_UNAVAILABLE", + "POSITIVE_INFINITY", + "PREV", + "PREV_NO_DUPLICATE", + "PROCESSING_INSTRUCTION_NODE", + "PageChangeEvent", + "PageTransitionEvent", + "PaintRequest", + "PaintRequestList", + "PannerNode", + "PasswordCredential", + "Path2D", + "PaymentAddress", + "PaymentInstruments", + "PaymentManager", + "PaymentMethodChangeEvent", + "PaymentRequest", + "PaymentRequestUpdateEvent", + "PaymentResponse", + "Performance", + "PerformanceElementTiming", + "PerformanceEntry", + "PerformanceEventTiming", + "PerformanceLongTaskTiming", + "PerformanceMark", + "PerformanceMeasure", + "PerformanceNavigation", + "PerformanceNavigationTiming", + "PerformanceObserver", + "PerformanceObserverEntryList", + "PerformancePaintTiming", + "PerformanceResourceTiming", + "PerformanceServerTiming", + "PerformanceTiming", + "PeriodicSyncManager", + "PeriodicWave", + "PermissionStatus", + "Permissions", + "PhotoCapabilities", + "PictureInPictureWindow", + "Plugin", + "PluginArray", + "PluralRules", + "PointerEvent", + "PopStateEvent", + "PopupBlockedEvent", + "Presentation", + "PresentationAvailability", + "PresentationConnection", + "PresentationConnectionAvailableEvent", + "PresentationConnectionCloseEvent", + "PresentationConnectionList", + "PresentationReceiver", + "PresentationRequest", + "ProcessingInstruction", + "ProgressEvent", + "Promise", + "PromiseRejectionEvent", + "PropertyNodeList", + "Proxy", + "PublicKeyCredential", + "PushManager", + "PushSubscription", + "PushSubscriptionOptions", + "Q", + "QUERY_RESULT", + "QUERY_RESULT_AVAILABLE", + "QUOTA_ERR", + "QUOTA_EXCEEDED_ERR", + "QueryInterface", + "R11F_G11F_B10F", + "R16F", + "R16I", + "R16UI", + "R32F", + "R32I", + "R32UI", + "R8", + "R8I", + "R8UI", + "R8_SNORM", + "RASTERIZER_DISCARD", + "READ_BUFFER", + "READ_FRAMEBUFFER", + "READ_FRAMEBUFFER_BINDING", + "READ_ONLY", + "READ_ONLY_ERR", + "READ_WRITE", + "RED", + "RED_BITS", + "RED_INTEGER", + "REMOVAL", + "RENDERBUFFER", + "RENDERBUFFER_ALPHA_SIZE", + "RENDERBUFFER_BINDING", + "RENDERBUFFER_BLUE_SIZE", + "RENDERBUFFER_DEPTH_SIZE", + "RENDERBUFFER_GREEN_SIZE", + "RENDERBUFFER_HEIGHT", + "RENDERBUFFER_INTERNAL_FORMAT", + "RENDERBUFFER_RED_SIZE", + "RENDERBUFFER_SAMPLES", + "RENDERBUFFER_STENCIL_SIZE", + "RENDERBUFFER_WIDTH", + "RENDERER", + "RENDERING_INTENT_ABSOLUTE_COLORIMETRIC", + "RENDERING_INTENT_AUTO", + "RENDERING_INTENT_PERCEPTUAL", + "RENDERING_INTENT_RELATIVE_COLORIMETRIC", + "RENDERING_INTENT_SATURATION", + "RENDERING_INTENT_UNKNOWN", + "REPEAT", + "REPLACE", + "RG", + "RG16F", + "RG16I", + "RG16UI", + "RG32F", + "RG32I", + "RG32UI", + "RG8", + "RG8I", + "RG8UI", + "RG8_SNORM", + "RGB", + "RGB10_A2", + "RGB10_A2UI", + "RGB16F", + "RGB16I", + "RGB16UI", + "RGB32F", + "RGB32I", + "RGB32UI", + "RGB565", + "RGB5_A1", + "RGB8", + "RGB8I", + "RGB8UI", + "RGB8_SNORM", + "RGB9_E5", + "RGBA", + "RGBA16F", + "RGBA16I", + "RGBA16UI", + "RGBA32F", + "RGBA32I", + "RGBA32UI", + "RGBA4", + "RGBA8", + "RGBA8I", + "RGBA8UI", + "RGBA8_SNORM", + "RGBA_INTEGER", + "RGBColor", + "RGB_INTEGER", + "RG_INTEGER", + "ROTATION_CLOCKWISE", + "ROTATION_COUNTERCLOCKWISE", + "RTCCertificate", + "RTCDTMFSender", + "RTCDTMFToneChangeEvent", + "RTCDataChannel", + "RTCDataChannelEvent", + "RTCDtlsTransport", + "RTCError", + "RTCErrorEvent", + "RTCIceCandidate", + "RTCIceTransport", + "RTCPeerConnection", + "RTCPeerConnectionIceErrorEvent", + "RTCPeerConnectionIceEvent", + "RTCRtpReceiver", + "RTCRtpSender", + "RTCRtpTransceiver", + "RTCSctpTransport", + "RTCSessionDescription", + "RTCStatsReport", + "RTCTrackEvent", + "RadioNodeList", + "Range", + "RangeError", + "RangeException", + "ReadableStream", + "ReadableStreamDefaultReader", + "RecordErrorEvent", + "Rect", + "ReferenceError", + "Reflect", + "RegExp", + "RelativeOrientationSensor", + "RelativeTimeFormat", + "RemotePlayback", + "Report", + "ReportBody", + "ReportingObserver", + "Request", + "ResizeObserver", + "ResizeObserverEntry", + "ResizeObserverSize", + "Response", + "RuntimeError", + "SAMPLER_2D", + "SAMPLER_2D_ARRAY", + "SAMPLER_2D_ARRAY_SHADOW", + "SAMPLER_2D_SHADOW", + "SAMPLER_3D", + "SAMPLER_BINDING", + "SAMPLER_CUBE", + "SAMPLER_CUBE_SHADOW", + "SAMPLES", + "SAMPLE_ALPHA_TO_COVERAGE", + "SAMPLE_BUFFERS", + "SAMPLE_COVERAGE", + "SAMPLE_COVERAGE_INVERT", + "SAMPLE_COVERAGE_VALUE", + "SAWTOOTH", + "SCHEDULED_STATE", + "SCISSOR_BOX", + "SCISSOR_TEST", + "SCROLL_PAGE_DOWN", + "SCROLL_PAGE_UP", + "SDP_ANSWER", + "SDP_OFFER", + "SDP_PRANSWER", + "SECURITY_ERR", + "SELECT", + "SEPARATE_ATTRIBS", + "SERIALIZE_ERR", + "SEVERITY_ERROR", + "SEVERITY_FATAL_ERROR", + "SEVERITY_WARNING", + "SHADER_COMPILER", + "SHADER_TYPE", + "SHADING_LANGUAGE_VERSION", + "SHIFT_MASK", + "SHORT", + "SHOWING", + "SHOW_ALL", + "SHOW_ATTRIBUTE", + "SHOW_CDATA_SECTION", + "SHOW_COMMENT", + "SHOW_DOCUMENT", + "SHOW_DOCUMENT_FRAGMENT", + "SHOW_DOCUMENT_TYPE", + "SHOW_ELEMENT", + "SHOW_ENTITY", + "SHOW_ENTITY_REFERENCE", + "SHOW_NOTATION", + "SHOW_PROCESSING_INSTRUCTION", + "SHOW_TEXT", + "SIGNALED", + "SIGNED_NORMALIZED", + "SINE", + "SOUNDFIELD", + "SQLException", + "SQRT1_2", + "SQRT2", + "SQUARE", + "SRC_ALPHA", + "SRC_ALPHA_SATURATE", + "SRC_COLOR", + "SRGB", + "SRGB8", + "SRGB8_ALPHA8", + "START_TO_END", + "START_TO_START", + "STATIC_COPY", + "STATIC_DRAW", + "STATIC_READ", + "STENCIL", + "STENCIL_ATTACHMENT", + "STENCIL_BACK_FAIL", + "STENCIL_BACK_FUNC", + "STENCIL_BACK_PASS_DEPTH_FAIL", + "STENCIL_BACK_PASS_DEPTH_PASS", + "STENCIL_BACK_REF", + "STENCIL_BACK_VALUE_MASK", + "STENCIL_BACK_WRITEMASK", + "STENCIL_BITS", + "STENCIL_BUFFER_BIT", + "STENCIL_CLEAR_VALUE", + "STENCIL_FAIL", + "STENCIL_FUNC", + "STENCIL_INDEX", + "STENCIL_INDEX8", + "STENCIL_PASS_DEPTH_FAIL", + "STENCIL_PASS_DEPTH_PASS", + "STENCIL_REF", + "STENCIL_TEST", + "STENCIL_VALUE_MASK", + "STENCIL_WRITEMASK", + "STREAM_COPY", + "STREAM_DRAW", + "STREAM_READ", + "STRING_TYPE", + "STYLE_RULE", + "SUBPIXEL_BITS", + "SUPPORTS_RULE", + "SVGAElement", + "SVGAltGlyphDefElement", + "SVGAltGlyphElement", + "SVGAltGlyphItemElement", + "SVGAngle", + "SVGAnimateColorElement", + "SVGAnimateElement", + "SVGAnimateMotionElement", + "SVGAnimateTransformElement", + "SVGAnimatedAngle", + "SVGAnimatedBoolean", + "SVGAnimatedEnumeration", + "SVGAnimatedInteger", + "SVGAnimatedLength", + "SVGAnimatedLengthList", + "SVGAnimatedNumber", + "SVGAnimatedNumberList", + "SVGAnimatedPreserveAspectRatio", + "SVGAnimatedRect", + "SVGAnimatedString", + "SVGAnimatedTransformList", + "SVGAnimationElement", + "SVGCircleElement", + "SVGClipPathElement", + "SVGColor", + "SVGComponentTransferFunctionElement", + "SVGCursorElement", + "SVGDefsElement", + "SVGDescElement", + "SVGDiscardElement", + "SVGDocument", + "SVGElement", + "SVGElementInstance", + "SVGElementInstanceList", + "SVGEllipseElement", + "SVGException", + "SVGFEBlendElement", + "SVGFEColorMatrixElement", + "SVGFEComponentTransferElement", + "SVGFECompositeElement", + "SVGFEConvolveMatrixElement", + "SVGFEDiffuseLightingElement", + "SVGFEDisplacementMapElement", + "SVGFEDistantLightElement", + "SVGFEDropShadowElement", + "SVGFEFloodElement", + "SVGFEFuncAElement", + "SVGFEFuncBElement", + "SVGFEFuncGElement", + "SVGFEFuncRElement", + "SVGFEGaussianBlurElement", + "SVGFEImageElement", + "SVGFEMergeElement", + "SVGFEMergeNodeElement", + "SVGFEMorphologyElement", + "SVGFEOffsetElement", + "SVGFEPointLightElement", + "SVGFESpecularLightingElement", + "SVGFESpotLightElement", + "SVGFETileElement", + "SVGFETurbulenceElement", + "SVGFilterElement", + "SVGFontElement", + "SVGFontFaceElement", + "SVGFontFaceFormatElement", + "SVGFontFaceNameElement", + "SVGFontFaceSrcElement", + "SVGFontFaceUriElement", + "SVGForeignObjectElement", + "SVGGElement", + "SVGGeometryElement", + "SVGGlyphElement", + "SVGGlyphRefElement", + "SVGGradientElement", + "SVGGraphicsElement", + "SVGHKernElement", + "SVGImageElement", + "SVGLength", + "SVGLengthList", + "SVGLineElement", + "SVGLinearGradientElement", + "SVGMPathElement", + "SVGMarkerElement", + "SVGMaskElement", + "SVGMatrix", + "SVGMetadataElement", + "SVGMissingGlyphElement", + "SVGNumber", + "SVGNumberList", + "SVGPaint", + "SVGPathElement", + "SVGPathSeg", + "SVGPathSegArcAbs", + "SVGPathSegArcRel", + "SVGPathSegClosePath", + "SVGPathSegCurvetoCubicAbs", + "SVGPathSegCurvetoCubicRel", + "SVGPathSegCurvetoCubicSmoothAbs", + "SVGPathSegCurvetoCubicSmoothRel", + "SVGPathSegCurvetoQuadraticAbs", + "SVGPathSegCurvetoQuadraticRel", + "SVGPathSegCurvetoQuadraticSmoothAbs", + "SVGPathSegCurvetoQuadraticSmoothRel", + "SVGPathSegLinetoAbs", + "SVGPathSegLinetoHorizontalAbs", + "SVGPathSegLinetoHorizontalRel", + "SVGPathSegLinetoRel", + "SVGPathSegLinetoVerticalAbs", + "SVGPathSegLinetoVerticalRel", + "SVGPathSegList", + "SVGPathSegMovetoAbs", + "SVGPathSegMovetoRel", + "SVGPatternElement", + "SVGPoint", + "SVGPointList", + "SVGPolygonElement", + "SVGPolylineElement", + "SVGPreserveAspectRatio", + "SVGRadialGradientElement", + "SVGRect", + "SVGRectElement", + "SVGRenderingIntent", + "SVGSVGElement", + "SVGScriptElement", + "SVGSetElement", + "SVGStopElement", + "SVGStringList", + "SVGStyleElement", + "SVGSwitchElement", + "SVGSymbolElement", + "SVGTRefElement", + "SVGTSpanElement", + "SVGTextContentElement", + "SVGTextElement", + "SVGTextPathElement", + "SVGTextPositioningElement", + "SVGTitleElement", + "SVGTransform", + "SVGTransformList", + "SVGUnitTypes", + "SVGUseElement", + "SVGVKernElement", + "SVGViewElement", + "SVGViewSpec", + "SVGZoomAndPan", + "SVGZoomEvent", + "SVG_ANGLETYPE_DEG", + "SVG_ANGLETYPE_GRAD", + "SVG_ANGLETYPE_RAD", + "SVG_ANGLETYPE_UNKNOWN", + "SVG_ANGLETYPE_UNSPECIFIED", + "SVG_CHANNEL_A", + "SVG_CHANNEL_B", + "SVG_CHANNEL_G", + "SVG_CHANNEL_R", + "SVG_CHANNEL_UNKNOWN", + "SVG_COLORTYPE_CURRENTCOLOR", + "SVG_COLORTYPE_RGBCOLOR", + "SVG_COLORTYPE_RGBCOLOR_ICCCOLOR", + "SVG_COLORTYPE_UNKNOWN", + "SVG_EDGEMODE_DUPLICATE", + "SVG_EDGEMODE_NONE", + "SVG_EDGEMODE_UNKNOWN", + "SVG_EDGEMODE_WRAP", + "SVG_FEBLEND_MODE_COLOR", + "SVG_FEBLEND_MODE_COLOR_BURN", + "SVG_FEBLEND_MODE_COLOR_DODGE", + "SVG_FEBLEND_MODE_DARKEN", + "SVG_FEBLEND_MODE_DIFFERENCE", + "SVG_FEBLEND_MODE_EXCLUSION", + "SVG_FEBLEND_MODE_HARD_LIGHT", + "SVG_FEBLEND_MODE_HUE", + "SVG_FEBLEND_MODE_LIGHTEN", + "SVG_FEBLEND_MODE_LUMINOSITY", + "SVG_FEBLEND_MODE_MULTIPLY", + "SVG_FEBLEND_MODE_NORMAL", + "SVG_FEBLEND_MODE_OVERLAY", + "SVG_FEBLEND_MODE_SATURATION", + "SVG_FEBLEND_MODE_SCREEN", + "SVG_FEBLEND_MODE_SOFT_LIGHT", + "SVG_FEBLEND_MODE_UNKNOWN", + "SVG_FECOLORMATRIX_TYPE_HUEROTATE", + "SVG_FECOLORMATRIX_TYPE_LUMINANCETOALPHA", + "SVG_FECOLORMATRIX_TYPE_MATRIX", + "SVG_FECOLORMATRIX_TYPE_SATURATE", + "SVG_FECOLORMATRIX_TYPE_UNKNOWN", + "SVG_FECOMPONENTTRANSFER_TYPE_DISCRETE", + "SVG_FECOMPONENTTRANSFER_TYPE_GAMMA", + "SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY", + "SVG_FECOMPONENTTRANSFER_TYPE_LINEAR", + "SVG_FECOMPONENTTRANSFER_TYPE_TABLE", + "SVG_FECOMPONENTTRANSFER_TYPE_UNKNOWN", + "SVG_FECOMPOSITE_OPERATOR_ARITHMETIC", + "SVG_FECOMPOSITE_OPERATOR_ATOP", + "SVG_FECOMPOSITE_OPERATOR_IN", + "SVG_FECOMPOSITE_OPERATOR_OUT", + "SVG_FECOMPOSITE_OPERATOR_OVER", + "SVG_FECOMPOSITE_OPERATOR_UNKNOWN", + "SVG_FECOMPOSITE_OPERATOR_XOR", + "SVG_INVALID_VALUE_ERR", + "SVG_LENGTHTYPE_CM", + "SVG_LENGTHTYPE_EMS", + "SVG_LENGTHTYPE_EXS", + "SVG_LENGTHTYPE_IN", + "SVG_LENGTHTYPE_MM", + "SVG_LENGTHTYPE_NUMBER", + "SVG_LENGTHTYPE_PC", + "SVG_LENGTHTYPE_PERCENTAGE", + "SVG_LENGTHTYPE_PT", + "SVG_LENGTHTYPE_PX", + "SVG_LENGTHTYPE_UNKNOWN", + "SVG_MARKERUNITS_STROKEWIDTH", + "SVG_MARKERUNITS_UNKNOWN", + "SVG_MARKERUNITS_USERSPACEONUSE", + "SVG_MARKER_ORIENT_ANGLE", + "SVG_MARKER_ORIENT_AUTO", + "SVG_MARKER_ORIENT_UNKNOWN", + "SVG_MASKTYPE_ALPHA", + "SVG_MASKTYPE_LUMINANCE", + "SVG_MATRIX_NOT_INVERTABLE", + "SVG_MEETORSLICE_MEET", + "SVG_MEETORSLICE_SLICE", + "SVG_MEETORSLICE_UNKNOWN", + "SVG_MORPHOLOGY_OPERATOR_DILATE", + "SVG_MORPHOLOGY_OPERATOR_ERODE", + "SVG_MORPHOLOGY_OPERATOR_UNKNOWN", + "SVG_PAINTTYPE_CURRENTCOLOR", + "SVG_PAINTTYPE_NONE", + "SVG_PAINTTYPE_RGBCOLOR", + "SVG_PAINTTYPE_RGBCOLOR_ICCCOLOR", + "SVG_PAINTTYPE_UNKNOWN", + "SVG_PAINTTYPE_URI", + "SVG_PAINTTYPE_URI_CURRENTCOLOR", + "SVG_PAINTTYPE_URI_NONE", + "SVG_PAINTTYPE_URI_RGBCOLOR", + "SVG_PAINTTYPE_URI_RGBCOLOR_ICCCOLOR", + "SVG_PRESERVEASPECTRATIO_NONE", + "SVG_PRESERVEASPECTRATIO_UNKNOWN", + "SVG_PRESERVEASPECTRATIO_XMAXYMAX", + "SVG_PRESERVEASPECTRATIO_XMAXYMID", + "SVG_PRESERVEASPECTRATIO_XMAXYMIN", + "SVG_PRESERVEASPECTRATIO_XMIDYMAX", + "SVG_PRESERVEASPECTRATIO_XMIDYMID", + "SVG_PRESERVEASPECTRATIO_XMIDYMIN", + "SVG_PRESERVEASPECTRATIO_XMINYMAX", + "SVG_PRESERVEASPECTRATIO_XMINYMID", + "SVG_PRESERVEASPECTRATIO_XMINYMIN", + "SVG_SPREADMETHOD_PAD", + "SVG_SPREADMETHOD_REFLECT", + "SVG_SPREADMETHOD_REPEAT", + "SVG_SPREADMETHOD_UNKNOWN", + "SVG_STITCHTYPE_NOSTITCH", + "SVG_STITCHTYPE_STITCH", + "SVG_STITCHTYPE_UNKNOWN", + "SVG_TRANSFORM_MATRIX", + "SVG_TRANSFORM_ROTATE", + "SVG_TRANSFORM_SCALE", + "SVG_TRANSFORM_SKEWX", + "SVG_TRANSFORM_SKEWY", + "SVG_TRANSFORM_TRANSLATE", + "SVG_TRANSFORM_UNKNOWN", + "SVG_TURBULENCE_TYPE_FRACTALNOISE", + "SVG_TURBULENCE_TYPE_TURBULENCE", + "SVG_TURBULENCE_TYPE_UNKNOWN", + "SVG_UNIT_TYPE_OBJECTBOUNDINGBOX", + "SVG_UNIT_TYPE_UNKNOWN", + "SVG_UNIT_TYPE_USERSPACEONUSE", + "SVG_WRONG_TYPE_ERR", + "SVG_ZOOMANDPAN_DISABLE", + "SVG_ZOOMANDPAN_MAGNIFY", + "SVG_ZOOMANDPAN_UNKNOWN", + "SYNC_CONDITION", + "SYNC_FENCE", + "SYNC_FLAGS", + "SYNC_FLUSH_COMMANDS_BIT", + "SYNC_GPU_COMMANDS_COMPLETE", + "SYNC_STATUS", + "SYNTAX_ERR", + "SavedPages", + "Screen", + "ScreenOrientation", + "Script", + "ScriptProcessorNode", + "ScrollAreaEvent", + "SecurityPolicyViolationEvent", + "Selection", + "Sensor", + "SensorErrorEvent", + "ServiceWorker", + "ServiceWorkerContainer", + "ServiceWorkerRegistration", + "SessionDescription", + "Set", + "ShadowRoot", + "SharedArrayBuffer", + "SharedWorker", + "SimpleGestureEvent", + "SourceBuffer", + "SourceBufferList", + "SpeechSynthesis", + "SpeechSynthesisErrorEvent", + "SpeechSynthesisEvent", + "SpeechSynthesisUtterance", + "SpeechSynthesisVoice", + "StaticRange", + "StereoPannerNode", + "StopIteration", + "Storage", + "StorageEvent", + "StorageManager", + "String", + "StructType", + "StylePropertyMap", + "StylePropertyMapReadOnly", + "StyleSheet", + "StyleSheetList", + "SubmitEvent", + "SubtleCrypto", + "Symbol", + "SyncManager", + "SyntaxError", + "TEMPORARY", + "TEXTPATH_METHODTYPE_ALIGN", + "TEXTPATH_METHODTYPE_STRETCH", + "TEXTPATH_METHODTYPE_UNKNOWN", + "TEXTPATH_SPACINGTYPE_AUTO", + "TEXTPATH_SPACINGTYPE_EXACT", + "TEXTPATH_SPACINGTYPE_UNKNOWN", + "TEXTURE", + "TEXTURE0", + "TEXTURE1", + "TEXTURE10", + "TEXTURE11", + "TEXTURE12", + "TEXTURE13", + "TEXTURE14", + "TEXTURE15", + "TEXTURE16", + "TEXTURE17", + "TEXTURE18", + "TEXTURE19", + "TEXTURE2", + "TEXTURE20", + "TEXTURE21", + "TEXTURE22", + "TEXTURE23", + "TEXTURE24", + "TEXTURE25", + "TEXTURE26", + "TEXTURE27", + "TEXTURE28", + "TEXTURE29", + "TEXTURE3", + "TEXTURE30", + "TEXTURE31", + "TEXTURE4", + "TEXTURE5", + "TEXTURE6", + "TEXTURE7", + "TEXTURE8", + "TEXTURE9", + "TEXTURE_2D", + "TEXTURE_2D_ARRAY", + "TEXTURE_3D", + "TEXTURE_BASE_LEVEL", + "TEXTURE_BINDING_2D", + "TEXTURE_BINDING_2D_ARRAY", + "TEXTURE_BINDING_3D", + "TEXTURE_BINDING_CUBE_MAP", + "TEXTURE_COMPARE_FUNC", + "TEXTURE_COMPARE_MODE", + "TEXTURE_CUBE_MAP", + "TEXTURE_CUBE_MAP_NEGATIVE_X", + "TEXTURE_CUBE_MAP_NEGATIVE_Y", + "TEXTURE_CUBE_MAP_NEGATIVE_Z", + "TEXTURE_CUBE_MAP_POSITIVE_X", + "TEXTURE_CUBE_MAP_POSITIVE_Y", + "TEXTURE_CUBE_MAP_POSITIVE_Z", + "TEXTURE_IMMUTABLE_FORMAT", + "TEXTURE_IMMUTABLE_LEVELS", + "TEXTURE_MAG_FILTER", + "TEXTURE_MAX_ANISOTROPY_EXT", + "TEXTURE_MAX_LEVEL", + "TEXTURE_MAX_LOD", + "TEXTURE_MIN_FILTER", + "TEXTURE_MIN_LOD", + "TEXTURE_WRAP_R", + "TEXTURE_WRAP_S", + "TEXTURE_WRAP_T", + "TEXT_NODE", + "TIMEOUT", + "TIMEOUT_ERR", + "TIMEOUT_EXPIRED", + "TIMEOUT_IGNORED", + "TOO_LARGE_ERR", + "TRANSACTION_INACTIVE_ERR", + "TRANSFORM_FEEDBACK", + "TRANSFORM_FEEDBACK_ACTIVE", + "TRANSFORM_FEEDBACK_BINDING", + "TRANSFORM_FEEDBACK_BUFFER", + "TRANSFORM_FEEDBACK_BUFFER_BINDING", + "TRANSFORM_FEEDBACK_BUFFER_MODE", + "TRANSFORM_FEEDBACK_BUFFER_SIZE", + "TRANSFORM_FEEDBACK_BUFFER_START", + "TRANSFORM_FEEDBACK_PAUSED", + "TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN", + "TRANSFORM_FEEDBACK_VARYINGS", + "TRIANGLE", + "TRIANGLES", + "TRIANGLE_FAN", + "TRIANGLE_STRIP", + "TYPE_BACK_FORWARD", + "TYPE_ERR", + "TYPE_MISMATCH_ERR", + "TYPE_NAVIGATE", + "TYPE_RELOAD", + "TYPE_RESERVED", + "Table", + "TaskAttributionTiming", + "Text", + "TextDecoder", + "TextDecoderStream", + "TextEncoder", + "TextEncoderStream", + "TextEvent", + "TextMetrics", + "TextTrack", + "TextTrackCue", + "TextTrackCueList", + "TextTrackList", + "TimeEvent", + "TimeRanges", + "Touch", + "TouchEvent", + "TouchList", + "TrackEvent", + "TransformStream", + "TransitionEvent", + "TreeWalker", + "TrustedHTML", + "TrustedScript", + "TrustedScriptURL", + "TrustedTypePolicy", + "TrustedTypePolicyFactory", + "TypeError", + "TypedObject", + "U2F", + "UIEvent", + "UNCACHED", + "UNIFORM_ARRAY_STRIDE", + "UNIFORM_BLOCK_ACTIVE_UNIFORMS", + "UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES", + "UNIFORM_BLOCK_BINDING", + "UNIFORM_BLOCK_DATA_SIZE", + "UNIFORM_BLOCK_INDEX", + "UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER", + "UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER", + "UNIFORM_BUFFER", + "UNIFORM_BUFFER_BINDING", + "UNIFORM_BUFFER_OFFSET_ALIGNMENT", + "UNIFORM_BUFFER_SIZE", + "UNIFORM_BUFFER_START", + "UNIFORM_IS_ROW_MAJOR", + "UNIFORM_MATRIX_STRIDE", + "UNIFORM_OFFSET", + "UNIFORM_SIZE", + "UNIFORM_TYPE", + "UNKNOWN_ERR", + "UNKNOWN_RULE", + "UNMASKED_RENDERER_WEBGL", + "UNMASKED_VENDOR_WEBGL", + "UNORDERED_NODE_ITERATOR_TYPE", + "UNORDERED_NODE_SNAPSHOT_TYPE", + "UNPACK_ALIGNMENT", + "UNPACK_COLORSPACE_CONVERSION_WEBGL", + "UNPACK_FLIP_Y_WEBGL", + "UNPACK_IMAGE_HEIGHT", + "UNPACK_PREMULTIPLY_ALPHA_WEBGL", + "UNPACK_ROW_LENGTH", + "UNPACK_SKIP_IMAGES", + "UNPACK_SKIP_PIXELS", + "UNPACK_SKIP_ROWS", + "UNSCHEDULED_STATE", + "UNSENT", + "UNSIGNALED", + "UNSIGNED_BYTE", + "UNSIGNED_INT", + "UNSIGNED_INT_10F_11F_11F_REV", + "UNSIGNED_INT_24_8", + "UNSIGNED_INT_2_10_10_10_REV", + "UNSIGNED_INT_5_9_9_9_REV", + "UNSIGNED_INT_SAMPLER_2D", + "UNSIGNED_INT_SAMPLER_2D_ARRAY", + "UNSIGNED_INT_SAMPLER_3D", + "UNSIGNED_INT_SAMPLER_CUBE", + "UNSIGNED_INT_VEC2", + "UNSIGNED_INT_VEC3", + "UNSIGNED_INT_VEC4", + "UNSIGNED_NORMALIZED", + "UNSIGNED_SHORT", + "UNSIGNED_SHORT_4_4_4_4", + "UNSIGNED_SHORT_5_5_5_1", + "UNSIGNED_SHORT_5_6_5", + "UNSPECIFIED_EVENT_TYPE_ERR", + "UPDATEREADY", + "URIError", + "URL", + "URLSearchParams", + "URLUnencoded", + "URL_MISMATCH_ERR", + "USB", + "USBAlternateInterface", + "USBConfiguration", + "USBConnectionEvent", + "USBDevice", + "USBEndpoint", + "USBInTransferResult", + "USBInterface", + "USBIsochronousInTransferPacket", + "USBIsochronousInTransferResult", + "USBIsochronousOutTransferPacket", + "USBIsochronousOutTransferResult", + "USBOutTransferResult", + "UTC", + "Uint16Array", + "Uint32Array", + "Uint8Array", + "Uint8ClampedArray", + "UserActivation", + "UserMessageHandler", + "UserMessageHandlersNamespace", + "UserProximityEvent", + "VALIDATE_STATUS", + "VALIDATION_ERR", + "VARIABLES_RULE", + "VENDOR", + "VERSION", + "VERSION_CHANGE", + "VERSION_ERR", + "VERTEX_ARRAY_BINDING", + "VERTEX_ATTRIB_ARRAY_BUFFER_BINDING", + "VERTEX_ATTRIB_ARRAY_DIVISOR", + "VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE", + "VERTEX_ATTRIB_ARRAY_ENABLED", + "VERTEX_ATTRIB_ARRAY_INTEGER", + "VERTEX_ATTRIB_ARRAY_NORMALIZED", + "VERTEX_ATTRIB_ARRAY_POINTER", + "VERTEX_ATTRIB_ARRAY_SIZE", + "VERTEX_ATTRIB_ARRAY_STRIDE", + "VERTEX_ATTRIB_ARRAY_TYPE", + "VERTEX_SHADER", + "VERTICAL", + "VERTICAL_AXIS", + "VER_ERR", + "VIEWPORT", + "VIEWPORT_RULE", + "VRDisplay", + "VRDisplayCapabilities", + "VRDisplayEvent", + "VREyeParameters", + "VRFieldOfView", + "VRFrameData", + "VRPose", + "VRStageParameters", + "VTTCue", + "VTTRegion", + "ValidityState", + "VideoPlaybackQuality", + "VideoStreamTrack", + "VisualViewport", + "WAIT_FAILED", + "WEBKIT_FILTER_RULE", + "WEBKIT_KEYFRAMES_RULE", + "WEBKIT_KEYFRAME_RULE", + "WEBKIT_REGION_RULE", + "WRONG_DOCUMENT_ERR", + "WakeLock", + "WakeLockSentinel", + "WasmAnyRef", + "WaveShaperNode", + "WeakMap", + "WeakRef", + "WeakSet", + "WebAssembly", + "WebGL2RenderingContext", + "WebGLActiveInfo", + "WebGLBuffer", + "WebGLContextEvent", + "WebGLFramebuffer", + "WebGLProgram", + "WebGLQuery", + "WebGLRenderbuffer", + "WebGLRenderingContext", + "WebGLSampler", + "WebGLShader", + "WebGLShaderPrecisionFormat", + "WebGLSync", + "WebGLTexture", + "WebGLTransformFeedback", + "WebGLUniformLocation", + "WebGLVertexArray", + "WebGLVertexArrayObject", + "WebKitAnimationEvent", + "WebKitBlobBuilder", + "WebKitCSSFilterRule", + "WebKitCSSFilterValue", + "WebKitCSSKeyframeRule", + "WebKitCSSKeyframesRule", + "WebKitCSSMatrix", + "WebKitCSSRegionRule", + "WebKitCSSTransformValue", + "WebKitDataCue", + "WebKitGamepad", + "WebKitMediaKeyError", + "WebKitMediaKeyMessageEvent", + "WebKitMediaKeySession", + "WebKitMediaKeys", + "WebKitMediaSource", + "WebKitMutationObserver", + "WebKitNamespace", + "WebKitPlaybackTargetAvailabilityEvent", + "WebKitPoint", + "WebKitShadowRoot", + "WebKitSourceBuffer", + "WebKitSourceBufferList", + "WebKitTransitionEvent", + "WebSocket", + "WebkitAlignContent", + "WebkitAlignItems", + "WebkitAlignSelf", + "WebkitAnimation", + "WebkitAnimationDelay", + "WebkitAnimationDirection", + "WebkitAnimationDuration", + "WebkitAnimationFillMode", + "WebkitAnimationIterationCount", + "WebkitAnimationName", + "WebkitAnimationPlayState", + "WebkitAnimationTimingFunction", + "WebkitAppearance", + "WebkitBackfaceVisibility", + "WebkitBackgroundClip", + "WebkitBackgroundOrigin", + "WebkitBackgroundSize", + "WebkitBorderBottomLeftRadius", + "WebkitBorderBottomRightRadius", + "WebkitBorderImage", + "WebkitBorderRadius", + "WebkitBorderTopLeftRadius", + "WebkitBorderTopRightRadius", + "WebkitBoxAlign", + "WebkitBoxDirection", + "WebkitBoxFlex", + "WebkitBoxOrdinalGroup", + "WebkitBoxOrient", + "WebkitBoxPack", + "WebkitBoxShadow", + "WebkitBoxSizing", + "WebkitFilter", + "WebkitFlex", + "WebkitFlexBasis", + "WebkitFlexDirection", + "WebkitFlexFlow", + "WebkitFlexGrow", + "WebkitFlexShrink", + "WebkitFlexWrap", + "WebkitJustifyContent", + "WebkitLineClamp", + "WebkitMask", + "WebkitMaskClip", + "WebkitMaskComposite", + "WebkitMaskImage", + "WebkitMaskOrigin", + "WebkitMaskPosition", + "WebkitMaskPositionX", + "WebkitMaskPositionY", + "WebkitMaskRepeat", + "WebkitMaskSize", + "WebkitOrder", + "WebkitPerspective", + "WebkitPerspectiveOrigin", + "WebkitTextFillColor", + "WebkitTextSizeAdjust", + "WebkitTextStroke", + "WebkitTextStrokeColor", + "WebkitTextStrokeWidth", + "WebkitTransform", + "WebkitTransformOrigin", + "WebkitTransformStyle", + "WebkitTransition", + "WebkitTransitionDelay", + "WebkitTransitionDuration", + "WebkitTransitionProperty", + "WebkitTransitionTimingFunction", + "WebkitUserSelect", + "WheelEvent", + "Window", + "Worker", + "Worklet", + "WritableStream", + "WritableStreamDefaultWriter", + "XMLDocument", + "XMLHttpRequest", + "XMLHttpRequestEventTarget", + "XMLHttpRequestException", + "XMLHttpRequestProgressEvent", + "XMLHttpRequestUpload", + "XMLSerializer", + "XMLStylesheetProcessingInstruction", + "XPathEvaluator", + "XPathException", + "XPathExpression", + "XPathNSResolver", + "XPathResult", + "XRBoundedReferenceSpace", + "XRDOMOverlayState", + "XRFrame", + "XRHitTestResult", + "XRHitTestSource", + "XRInputSource", + "XRInputSourceArray", + "XRInputSourceEvent", + "XRInputSourcesChangeEvent", + "XRLayer", + "XRPose", + "XRRay", + "XRReferenceSpace", + "XRReferenceSpaceEvent", + "XRRenderState", + "XRRigidTransform", + "XRSession", + "XRSessionEvent", + "XRSpace", + "XRSystem", + "XRTransientInputHitTestResult", + "XRTransientInputHitTestSource", + "XRView", + "XRViewerPose", + "XRViewport", + "XRWebGLLayer", + "XSLTProcessor", + "ZERO", + "_XD0M_", + "_YD0M_", + "__defineGetter__", + "__defineSetter__", + "__lookupGetter__", + "__lookupSetter__", + "__opera", + "__proto__", + "_browserjsran", + "a", + "aLink", + "abbr", + "abort", + "aborted", + "abs", + "absolute", + "acceleration", + "accelerationIncludingGravity", + "accelerator", + "accept", + "acceptCharset", + "acceptNode", + "accessKey", + "accessKeyLabel", + "accuracy", + "acos", + "acosh", + "action", + "actionURL", + "actions", + "activated", + "active", + "activeCues", + "activeElement", + "activeSourceBuffers", + "activeSourceCount", + "activeTexture", + "activeVRDisplays", + "actualBoundingBoxAscent", + "actualBoundingBoxDescent", + "actualBoundingBoxLeft", + "actualBoundingBoxRight", + "add", + "addAll", + "addBehavior", + "addCandidate", + "addColorStop", + "addCue", + "addElement", + "addEventListener", + "addFilter", + "addFromString", + "addFromUri", + "addIceCandidate", + "addImport", + "addListener", + "addModule", + "addNamed", + "addPageRule", + "addPath", + "addPointer", + "addRange", + "addRegion", + "addRule", + "addSearchEngine", + "addSourceBuffer", + "addStream", + "addTextTrack", + "addTrack", + "addTransceiver", + "addWakeLockListener", + "added", + "addedNodes", + "additionalName", + "additiveSymbols", + "addons", + "address", + "addressLine", + "adoptNode", + "adoptedStyleSheets", + "adr", + "advance", + "after", + "album", + "alert", + "algorithm", + "align", + "align-content", + "align-items", + "align-self", + "alignContent", + "alignItems", + "alignSelf", + "alignmentBaseline", + "alinkColor", + "all", + "allSettled", + "allow", + "allowFullscreen", + "allowPaymentRequest", + "allowedDirections", + "allowedFeatures", + "allowedToPlay", + "allowsFeature", + "alpha", + "alt", + "altGraphKey", + "altHtml", + "altKey", + "altLeft", + "alternate", + "alternateSetting", + "alternates", + "altitude", + "altitudeAccuracy", + "amplitude", + "ancestorOrigins", + "anchor", + "anchorNode", + "anchorOffset", + "anchors", + "and", + "angle", + "angularAcceleration", + "angularVelocity", + "animVal", + "animate", + "animatedInstanceRoot", + "animatedNormalizedPathSegList", + "animatedPathSegList", + "animatedPoints", + "animation", + "animation-delay", + "animation-direction", + "animation-duration", + "animation-fill-mode", + "animation-iteration-count", + "animation-name", + "animation-play-state", + "animation-timing-function", + "animationDelay", + "animationDirection", + "animationDuration", + "animationFillMode", + "animationIterationCount", + "animationName", + "animationPlayState", + "animationStartTime", + "animationTimingFunction", + "animationsPaused", + "anniversary", + "antialias", + "anticipatedRemoval", + "any", + "app", + "appCodeName", + "appMinorVersion", + "appName", + "appNotifications", + "appVersion", + "appearance", + "append", + "appendBuffer", + "appendChild", + "appendData", + "appendItem", + "appendMedium", + "appendNamed", + "appendRule", + "appendStream", + "appendWindowEnd", + "appendWindowStart", + "applets", + "applicationCache", + "applicationServerKey", + "apply", + "applyConstraints", + "applyElement", + "arc", + "arcTo", + "archive", + "areas", + "arguments", + "ariaAtomic", + "ariaAutoComplete", + "ariaBusy", + "ariaChecked", + "ariaColCount", + "ariaColIndex", + "ariaColSpan", + "ariaCurrent", + "ariaDescription", + "ariaDisabled", + "ariaExpanded", + "ariaHasPopup", + "ariaHidden", + "ariaKeyShortcuts", + "ariaLabel", + "ariaLevel", + "ariaLive", + "ariaModal", + "ariaMultiLine", + "ariaMultiSelectable", + "ariaOrientation", + "ariaPlaceholder", + "ariaPosInSet", + "ariaPressed", + "ariaReadOnly", + "ariaRelevant", + "ariaRequired", + "ariaRoleDescription", + "ariaRowCount", + "ariaRowIndex", + "ariaRowSpan", + "ariaSelected", + "ariaSetSize", + "ariaSort", + "ariaValueMax", + "ariaValueMin", + "ariaValueNow", + "ariaValueText", + "arrayBuffer", + "artist", + "artwork", + "as", + "asIntN", + "asUintN", + "asin", + "asinh", + "assert", + "assign", + "assignedElements", + "assignedNodes", + "assignedSlot", + "async", + "asyncIterator", + "atEnd", + "atan", + "atan2", + "atanh", + "atob", + "attachEvent", + "attachInternals", + "attachShader", + "attachShadow", + "attachments", + "attack", + "attestationObject", + "attrChange", + "attrName", + "attributeFilter", + "attributeName", + "attributeNamespace", + "attributeOldValue", + "attributeStyleMap", + "attributes", + "attribution", + "audioBitsPerSecond", + "audioTracks", + "audioWorklet", + "authenticatedSignedWrites", + "authenticatorData", + "autoIncrement", + "autobuffer", + "autocapitalize", + "autocomplete", + "autocorrect", + "autofocus", + "automationRate", + "autoplay", + "availHeight", + "availLeft", + "availTop", + "availWidth", + "availability", + "available", + "aversion", + "ax", + "axes", + "axis", + "ay", + "azimuth", + "b", + "back", + "backface-visibility", + "backfaceVisibility", + "background", + "background-attachment", + "background-blend-mode", + "background-clip", + "background-color", + "background-image", + "background-origin", + "background-position", + "background-position-x", + "background-position-y", + "background-repeat", + "background-size", + "backgroundAttachment", + "backgroundBlendMode", + "backgroundClip", + "backgroundColor", + "backgroundFetch", + "backgroundImage", + "backgroundOrigin", + "backgroundPosition", + "backgroundPositionX", + "backgroundPositionY", + "backgroundRepeat", + "backgroundSize", + "badInput", + "badge", + "balance", + "baseFrequencyX", + "baseFrequencyY", + "baseLatency", + "baseLayer", + "baseNode", + "baseOffset", + "baseURI", + "baseVal", + "baselineShift", + "battery", + "bday", + "before", + "beginElement", + "beginElementAt", + "beginPath", + "beginQuery", + "beginTransformFeedback", + "behavior", + "behaviorCookie", + "behaviorPart", + "behaviorUrns", + "beta", + "bezierCurveTo", + "bgColor", + "bgProperties", + "bias", + "big", + "bigint64", + "biguint64", + "binaryType", + "bind", + "bindAttribLocation", + "bindBuffer", + "bindBufferBase", + "bindBufferRange", + "bindFramebuffer", + "bindRenderbuffer", + "bindSampler", + "bindTexture", + "bindTransformFeedback", + "bindVertexArray", + "blendColor", + "blendEquation", + "blendEquationSeparate", + "blendFunc", + "blendFuncSeparate", + "blink", + "blitFramebuffer", + "blob", + "block-size", + "blockDirection", + "blockSize", + "blockedURI", + "blue", + "bluetooth", + "blur", + "body", + "bodyUsed", + "bold", + "bookmarks", + "booleanValue", + "border", + "border-block", + "border-block-color", + "border-block-end", + "border-block-end-color", + "border-block-end-style", + "border-block-end-width", + "border-block-start", + "border-block-start-color", + "border-block-start-style", + "border-block-start-width", + "border-block-style", + "border-block-width", + "border-bottom", + "border-bottom-color", + "border-bottom-left-radius", + "border-bottom-right-radius", + "border-bottom-style", + "border-bottom-width", + "border-collapse", + "border-color", + "border-end-end-radius", + "border-end-start-radius", + "border-image", + "border-image-outset", + "border-image-repeat", + "border-image-slice", + "border-image-source", + "border-image-width", + "border-inline", + "border-inline-color", + "border-inline-end", + "border-inline-end-color", + "border-inline-end-style", + "border-inline-end-width", + "border-inline-start", + "border-inline-start-color", + "border-inline-start-style", + "border-inline-start-width", + "border-inline-style", + "border-inline-width", + "border-left", + "border-left-color", + "border-left-style", + "border-left-width", + "border-radius", + "border-right", + "border-right-color", + "border-right-style", + "border-right-width", + "border-spacing", + "border-start-end-radius", + "border-start-start-radius", + "border-style", + "border-top", + "border-top-color", + "border-top-left-radius", + "border-top-right-radius", + "border-top-style", + "border-top-width", + "border-width", + "borderBlock", + "borderBlockColor", + "borderBlockEnd", + "borderBlockEndColor", + "borderBlockEndStyle", + "borderBlockEndWidth", + "borderBlockStart", + "borderBlockStartColor", + "borderBlockStartStyle", + "borderBlockStartWidth", + "borderBlockStyle", + "borderBlockWidth", + "borderBottom", + "borderBottomColor", + "borderBottomLeftRadius", + "borderBottomRightRadius", + "borderBottomStyle", + "borderBottomWidth", + "borderBoxSize", + "borderCollapse", + "borderColor", + "borderColorDark", + "borderColorLight", + "borderEndEndRadius", + "borderEndStartRadius", + "borderImage", + "borderImageOutset", + "borderImageRepeat", + "borderImageSlice", + "borderImageSource", + "borderImageWidth", + "borderInline", + "borderInlineColor", + "borderInlineEnd", + "borderInlineEndColor", + "borderInlineEndStyle", + "borderInlineEndWidth", + "borderInlineStart", + "borderInlineStartColor", + "borderInlineStartStyle", + "borderInlineStartWidth", + "borderInlineStyle", + "borderInlineWidth", + "borderLeft", + "borderLeftColor", + "borderLeftStyle", + "borderLeftWidth", + "borderRadius", + "borderRight", + "borderRightColor", + "borderRightStyle", + "borderRightWidth", + "borderSpacing", + "borderStartEndRadius", + "borderStartStartRadius", + "borderStyle", + "borderTop", + "borderTopColor", + "borderTopLeftRadius", + "borderTopRightRadius", + "borderTopStyle", + "borderTopWidth", + "borderWidth", + "bottom", + "bottomMargin", + "bound", + "boundElements", + "boundingClientRect", + "boundingHeight", + "boundingLeft", + "boundingTop", + "boundingWidth", + "bounds", + "boundsGeometry", + "box-decoration-break", + "box-shadow", + "box-sizing", + "boxDecorationBreak", + "boxShadow", + "boxSizing", + "break-after", + "break-before", + "break-inside", + "breakAfter", + "breakBefore", + "breakInside", + "broadcast", + "browserLanguage", + "btoa", + "bubbles", + "buffer", + "bufferData", + "bufferDepth", + "bufferSize", + "bufferSubData", + "buffered", + "bufferedAmount", + "bufferedAmountLowThreshold", + "buildID", + "buildNumber", + "button", + "buttonID", + "buttons", + "byteLength", + "byteOffset", + "bytesWritten", + "c", + "cache", + "caches", + "call", + "caller", + "canBeFormatted", + "canBeMounted", + "canBeShared", + "canHaveChildren", + "canHaveHTML", + "canInsertDTMF", + "canMakePayment", + "canPlayType", + "canPresent", + "canTrickleIceCandidates", + "cancel", + "cancelAndHoldAtTime", + "cancelAnimationFrame", + "cancelBubble", + "cancelIdleCallback", + "cancelScheduledValues", + "cancelVideoFrameCallback", + "cancelWatchAvailability", + "cancelable", + "candidate", + "canonicalUUID", + "canvas", + "capabilities", + "caption", + "caption-side", + "captionSide", + "capture", + "captureEvents", + "captureStackTrace", + "captureStream", + "caret-color", + "caretBidiLevel", + "caretColor", + "caretPositionFromPoint", + "caretRangeFromPoint", + "cast", + "catch", + "category", + "cbrt", + "cd", + "ceil", + "cellIndex", + "cellPadding", + "cellSpacing", + "cells", + "ch", + "chOff", + "chain", + "challenge", + "changeType", + "changedTouches", + "channel", + "channelCount", + "channelCountMode", + "channelInterpretation", + "char", + "charAt", + "charCode", + "charCodeAt", + "charIndex", + "charLength", + "characterData", + "characterDataOldValue", + "characterSet", + "characteristic", + "charging", + "chargingTime", + "charset", + "check", + "checkEnclosure", + "checkFramebufferStatus", + "checkIntersection", + "checkValidity", + "checked", + "childElementCount", + "childList", + "childNodes", + "children", + "chrome", + "ciphertext", + "cite", + "city", + "claimInterface", + "claimed", + "classList", + "className", + "classid", + "clear", + "clearAppBadge", + "clearAttributes", + "clearBufferfi", + "clearBufferfv", + "clearBufferiv", + "clearBufferuiv", + "clearColor", + "clearData", + "clearDepth", + "clearHalt", + "clearImmediate", + "clearInterval", + "clearLiveSeekableRange", + "clearMarks", + "clearMaxGCPauseAccumulator", + "clearMeasures", + "clearParameters", + "clearRect", + "clearResourceTimings", + "clearShadow", + "clearStencil", + "clearTimeout", + "clearWatch", + "click", + "clickCount", + "clientDataJSON", + "clientHeight", + "clientInformation", + "clientLeft", + "clientRect", + "clientRects", + "clientTop", + "clientWaitSync", + "clientWidth", + "clientX", + "clientY", + "clip", + "clip-path", + "clip-rule", + "clipBottom", + "clipLeft", + "clipPath", + "clipPathUnits", + "clipRight", + "clipRule", + "clipTop", + "clipboard", + "clipboardData", + "clone", + "cloneContents", + "cloneNode", + "cloneRange", + "close", + "closePath", + "closed", + "closest", + "clz", + "clz32", + "cm", + "cmp", + "code", + "codeBase", + "codePointAt", + "codeType", + "colSpan", + "collapse", + "collapseToEnd", + "collapseToStart", + "collapsed", + "collect", + "colno", + "color", + "color-adjust", + "color-interpolation", + "color-interpolation-filters", + "colorAdjust", + "colorDepth", + "colorInterpolation", + "colorInterpolationFilters", + "colorMask", + "colorType", + "cols", + "column-count", + "column-fill", + "column-gap", + "column-rule", + "column-rule-color", + "column-rule-style", + "column-rule-width", + "column-span", + "column-width", + "columnCount", + "columnFill", + "columnGap", + "columnNumber", + "columnRule", + "columnRuleColor", + "columnRuleStyle", + "columnRuleWidth", + "columnSpan", + "columnWidth", + "columns", + "command", + "commit", + "commitPreferences", + "commitStyles", + "commonAncestorContainer", + "compact", + "compareBoundaryPoints", + "compareDocumentPosition", + "compareEndPoints", + "compareExchange", + "compareNode", + "comparePoint", + "compatMode", + "compatible", + "compile", + "compileShader", + "compileStreaming", + "complete", + "component", + "componentFromPoint", + "composed", + "composedPath", + "composite", + "compositionEndOffset", + "compositionStartOffset", + "compressedTexImage2D", + "compressedTexImage3D", + "compressedTexSubImage2D", + "compressedTexSubImage3D", + "computedStyleMap", + "concat", + "conditionText", + "coneInnerAngle", + "coneOuterAngle", + "coneOuterGain", + "configuration", + "configurationName", + "configurationValue", + "configurations", + "confirm", + "confirmComposition", + "confirmSiteSpecificTrackingException", + "confirmWebWideTrackingException", + "connect", + "connectEnd", + "connectShark", + "connectStart", + "connected", + "connection", + "connectionList", + "connectionSpeed", + "connectionState", + "connections", + "console", + "consolidate", + "constraint", + "constrictionActive", + "construct", + "constructor", + "contactID", + "contain", + "containerId", + "containerName", + "containerSrc", + "containerType", + "contains", + "containsNode", + "content", + "contentBoxSize", + "contentDocument", + "contentEditable", + "contentHint", + "contentOverflow", + "contentRect", + "contentScriptType", + "contentStyleType", + "contentType", + "contentWindow", + "context", + "contextMenu", + "contextmenu", + "continue", + "continuePrimaryKey", + "continuous", + "control", + "controlTransferIn", + "controlTransferOut", + "controller", + "controls", + "controlsList", + "convertPointFromNode", + "convertQuadFromNode", + "convertRectFromNode", + "convertToBlob", + "convertToSpecifiedUnits", + "cookie", + "cookieEnabled", + "coords", + "copyBufferSubData", + "copyFromChannel", + "copyTexImage2D", + "copyTexSubImage2D", + "copyTexSubImage3D", + "copyToChannel", + "copyWithin", + "correspondingElement", + "correspondingUseElement", + "corruptedVideoFrames", + "cos", + "cosh", + "count", + "countReset", + "counter-increment", + "counter-reset", + "counter-set", + "counterIncrement", + "counterReset", + "counterSet", + "country", + "cpuClass", + "cpuSleepAllowed", + "create", + "createAnalyser", + "createAnswer", + "createAttribute", + "createAttributeNS", + "createBiquadFilter", + "createBuffer", + "createBufferSource", + "createCDATASection", + "createCSSStyleSheet", + "createCaption", + "createChannelMerger", + "createChannelSplitter", + "createComment", + "createConstantSource", + "createContextualFragment", + "createControlRange", + "createConvolver", + "createDTMFSender", + "createDataChannel", + "createDelay", + "createDelayNode", + "createDocument", + "createDocumentFragment", + "createDocumentType", + "createDynamicsCompressor", + "createElement", + "createElementNS", + "createEntityReference", + "createEvent", + "createEventObject", + "createExpression", + "createFramebuffer", + "createFunction", + "createGain", + "createGainNode", + "createHTML", + "createHTMLDocument", + "createIIRFilter", + "createImageBitmap", + "createImageData", + "createIndex", + "createJavaScriptNode", + "createLinearGradient", + "createMediaElementSource", + "createMediaKeys", + "createMediaStreamDestination", + "createMediaStreamSource", + "createMediaStreamTrackSource", + "createMutableFile", + "createNSResolver", + "createNodeIterator", + "createNotification", + "createObjectStore", + "createObjectURL", + "createOffer", + "createOscillator", + "createPanner", + "createPattern", + "createPeriodicWave", + "createPolicy", + "createPopup", + "createProcessingInstruction", + "createProgram", + "createQuery", + "createRadialGradient", + "createRange", + "createRangeCollection", + "createReader", + "createRenderbuffer", + "createSVGAngle", + "createSVGLength", + "createSVGMatrix", + "createSVGNumber", + "createSVGPathSegArcAbs", + "createSVGPathSegArcRel", + "createSVGPathSegClosePath", + "createSVGPathSegCurvetoCubicAbs", + "createSVGPathSegCurvetoCubicRel", + "createSVGPathSegCurvetoCubicSmoothAbs", + "createSVGPathSegCurvetoCubicSmoothRel", + "createSVGPathSegCurvetoQuadraticAbs", + "createSVGPathSegCurvetoQuadraticRel", + "createSVGPathSegCurvetoQuadraticSmoothAbs", + "createSVGPathSegCurvetoQuadraticSmoothRel", + "createSVGPathSegLinetoAbs", + "createSVGPathSegLinetoHorizontalAbs", + "createSVGPathSegLinetoHorizontalRel", + "createSVGPathSegLinetoRel", + "createSVGPathSegLinetoVerticalAbs", + "createSVGPathSegLinetoVerticalRel", + "createSVGPathSegMovetoAbs", + "createSVGPathSegMovetoRel", + "createSVGPoint", + "createSVGRect", + "createSVGTransform", + "createSVGTransformFromMatrix", + "createSampler", + "createScript", + "createScriptProcessor", + "createScriptURL", + "createSession", + "createShader", + "createShadowRoot", + "createStereoPanner", + "createStyleSheet", + "createTBody", + "createTFoot", + "createTHead", + "createTextNode", + "createTextRange", + "createTexture", + "createTouch", + "createTouchList", + "createTransformFeedback", + "createTreeWalker", + "createVertexArray", + "createWaveShaper", + "creationTime", + "credentials", + "crossOrigin", + "crossOriginIsolated", + "crypto", + "csi", + "csp", + "cssFloat", + "cssRules", + "cssText", + "cssValueType", + "ctrlKey", + "ctrlLeft", + "cues", + "cullFace", + "currentDirection", + "currentLocalDescription", + "currentNode", + "currentPage", + "currentRect", + "currentRemoteDescription", + "currentScale", + "currentScript", + "currentSrc", + "currentState", + "currentStyle", + "currentTarget", + "currentTime", + "currentTranslate", + "currentView", + "cursor", + "curve", + "customElements", + "customError", + "cx", + "cy", + "d", + "data", + "dataFld", + "dataFormatAs", + "dataLoss", + "dataLossMessage", + "dataPageSize", + "dataSrc", + "dataTransfer", + "database", + "databases", + "dataset", + "dateTime", + "db", + "debug", + "debuggerEnabled", + "declare", + "decode", + "decodeAudioData", + "decodeURI", + "decodeURIComponent", + "decodedBodySize", + "decoding", + "decodingInfo", + "decrypt", + "default", + "defaultCharset", + "defaultChecked", + "defaultMuted", + "defaultPlaybackRate", + "defaultPolicy", + "defaultPrevented", + "defaultRequest", + "defaultSelected", + "defaultStatus", + "defaultURL", + "defaultValue", + "defaultView", + "defaultstatus", + "defer", + "define", + "defineMagicFunction", + "defineMagicVariable", + "defineProperties", + "defineProperty", + "deg", + "delay", + "delayTime", + "delegatesFocus", + "delete", + "deleteBuffer", + "deleteCaption", + "deleteCell", + "deleteContents", + "deleteData", + "deleteDatabase", + "deleteFramebuffer", + "deleteFromDocument", + "deleteIndex", + "deleteMedium", + "deleteObjectStore", + "deleteProgram", + "deleteProperty", + "deleteQuery", + "deleteRenderbuffer", + "deleteRow", + "deleteRule", + "deleteSampler", + "deleteShader", + "deleteSync", + "deleteTFoot", + "deleteTHead", + "deleteTexture", + "deleteTransformFeedback", + "deleteVertexArray", + "deliverChangeRecords", + "delivery", + "deliveryInfo", + "deliveryStatus", + "deliveryTimestamp", + "delta", + "deltaMode", + "deltaX", + "deltaY", + "deltaZ", + "dependentLocality", + "depthFar", + "depthFunc", + "depthMask", + "depthNear", + "depthRange", + "deref", + "deriveBits", + "deriveKey", + "description", + "deselectAll", + "designMode", + "desiredSize", + "destination", + "destinationURL", + "detach", + "detachEvent", + "detachShader", + "detail", + "details", + "detect", + "detune", + "device", + "deviceClass", + "deviceId", + "deviceMemory", + "devicePixelContentBoxSize", + "devicePixelRatio", + "deviceProtocol", + "deviceSubclass", + "deviceVersionMajor", + "deviceVersionMinor", + "deviceVersionSubminor", + "deviceXDPI", + "deviceYDPI", + "didTimeout", + "diffuseConstant", + "digest", + "dimensions", + "dir", + "dirName", + "direction", + "dirxml", + "disable", + "disablePictureInPicture", + "disableRemotePlayback", + "disableVertexAttribArray", + "disabled", + "dischargingTime", + "disconnect", + "disconnectShark", + "dispatchEvent", + "display", + "displayId", + "displayName", + "disposition", + "distanceModel", + "div", + "divisor", + "djsapi", + "djsproxy", + "doImport", + "doNotTrack", + "doScroll", + "doctype", + "document", + "documentElement", + "documentMode", + "documentURI", + "dolphin", + "dolphinGameCenter", + "dolphininfo", + "dolphinmeta", + "domComplete", + "domContentLoadedEventEnd", + "domContentLoadedEventStart", + "domInteractive", + "domLoading", + "domOverlayState", + "domain", + "domainLookupEnd", + "domainLookupStart", + "dominant-baseline", + "dominantBaseline", + "done", + "dopplerFactor", + "dotAll", + "downDegrees", + "downlink", + "download", + "downloadTotal", + "downloaded", + "dpcm", + "dpi", + "dppx", + "dragDrop", + "draggable", + "drawArrays", + "drawArraysInstanced", + "drawArraysInstancedANGLE", + "drawBuffers", + "drawCustomFocusRing", + "drawElements", + "drawElementsInstanced", + "drawElementsInstancedANGLE", + "drawFocusIfNeeded", + "drawImage", + "drawImageFromRect", + "drawRangeElements", + "drawSystemFocusRing", + "drawingBufferHeight", + "drawingBufferWidth", + "dropEffect", + "droppedVideoFrames", + "dropzone", + "dtmf", + "dump", + "dumpProfile", + "duplicate", + "durability", + "duration", + "dvname", + "dvnum", + "dx", + "dy", + "dynsrc", + "e", + "edgeMode", + "effect", + "effectAllowed", + "effectiveDirective", + "effectiveType", + "elapsedTime", + "element", + "elementFromPoint", + "elementTiming", + "elements", + "elementsFromPoint", + "elevation", + "ellipse", + "em", + "email", + "embeds", + "emma", + "empty", + "empty-cells", + "emptyCells", + "emptyHTML", + "emptyScript", + "emulatedPosition", + "enable", + "enableBackground", + "enableDelegations", + "enableStyleSheetsForSet", + "enableVertexAttribArray", + "enabled", + "enabledPlugin", + "encode", + "encodeInto", + "encodeURI", + "encodeURIComponent", + "encodedBodySize", + "encoding", + "encodingInfo", + "encrypt", + "enctype", + "end", + "endContainer", + "endElement", + "endElementAt", + "endOfStream", + "endOffset", + "endQuery", + "endTime", + "endTransformFeedback", + "ended", + "endpoint", + "endpointNumber", + "endpoints", + "endsWith", + "enterKeyHint", + "entities", + "entries", + "entryType", + "enumerate", + "enumerateDevices", + "enumerateEditable", + "environmentBlendMode", + "equals", + "error", + "errorCode", + "errorDetail", + "errorText", + "escape", + "estimate", + "eval", + "evaluate", + "event", + "eventPhase", + "every", + "ex", + "exception", + "exchange", + "exec", + "execCommand", + "execCommandShowHelp", + "execScript", + "exitFullscreen", + "exitPictureInPicture", + "exitPointerLock", + "exitPresent", + "exp", + "expand", + "expandEntityReferences", + "expando", + "expansion", + "expiration", + "expirationTime", + "expires", + "expiryDate", + "explicitOriginalTarget", + "expm1", + "exponent", + "exponentialRampToValueAtTime", + "exportKey", + "extend", + "extensions", + "extentNode", + "extentOffset", + "external", + "externalResourcesRequired", + "extractContents", + "extractable", + "eye", + "f", + "face", + "factoryReset", + "failureReason", + "fallback", + "family", + "familyName", + "farthestViewportElement", + "fastSeek", + "fatal", + "featureId", + "featurePolicy", + "featureSettings", + "features", + "fenceSync", + "fetch", + "fetchStart", + "fftSize", + "fgColor", + "fieldOfView", + "file", + "fileCreatedDate", + "fileHandle", + "fileModifiedDate", + "fileName", + "fileSize", + "fileUpdatedDate", + "filename", + "files", + "filesystem", + "fill", + "fill-opacity", + "fill-rule", + "fillLightMode", + "fillOpacity", + "fillRect", + "fillRule", + "fillStyle", + "fillText", + "filter", + "filterResX", + "filterResY", + "filterUnits", + "filters", + "finally", + "find", + "findIndex", + "findRule", + "findText", + "finish", + "finished", + "fireEvent", + "firesTouchEvents", + "firstChild", + "firstElementChild", + "firstPage", + "fixed", + "flags", + "flat", + "flatMap", + "flex", + "flex-basis", + "flex-direction", + "flex-flow", + "flex-grow", + "flex-shrink", + "flex-wrap", + "flexBasis", + "flexDirection", + "flexFlow", + "flexGrow", + "flexShrink", + "flexWrap", + "flipX", + "flipY", + "float", + "float32", + "float64", + "flood-color", + "flood-opacity", + "floodColor", + "floodOpacity", + "floor", + "flush", + "focus", + "focusNode", + "focusOffset", + "font", + "font-family", + "font-feature-settings", + "font-kerning", + "font-language-override", + "font-optical-sizing", + "font-size", + "font-size-adjust", + "font-stretch", + "font-style", + "font-synthesis", + "font-variant", + "font-variant-alternates", + "font-variant-caps", + "font-variant-east-asian", + "font-variant-ligatures", + "font-variant-numeric", + "font-variant-position", + "font-variation-settings", + "font-weight", + "fontFamily", + "fontFeatureSettings", + "fontKerning", + "fontLanguageOverride", + "fontOpticalSizing", + "fontSize", + "fontSizeAdjust", + "fontSmoothingEnabled", + "fontStretch", + "fontStyle", + "fontSynthesis", + "fontVariant", + "fontVariantAlternates", + "fontVariantCaps", + "fontVariantEastAsian", + "fontVariantLigatures", + "fontVariantNumeric", + "fontVariantPosition", + "fontVariationSettings", + "fontWeight", + "fontcolor", + "fontfaces", + "fonts", + "fontsize", + "for", + "forEach", + "force", + "forceRedraw", + "form", + "formAction", + "formData", + "formEnctype", + "formMethod", + "formNoValidate", + "formTarget", + "format", + "formatToParts", + "forms", + "forward", + "forwardX", + "forwardY", + "forwardZ", + "foundation", + "fr", + "fragmentDirective", + "frame", + "frameBorder", + "frameElement", + "frameSpacing", + "framebuffer", + "framebufferHeight", + "framebufferRenderbuffer", + "framebufferTexture2D", + "framebufferTextureLayer", + "framebufferWidth", + "frames", + "freeSpace", + "freeze", + "frequency", + "frequencyBinCount", + "from", + "fromCharCode", + "fromCodePoint", + "fromElement", + "fromEntries", + "fromFloat32Array", + "fromFloat64Array", + "fromMatrix", + "fromPoint", + "fromQuad", + "fromRect", + "frontFace", + "fround", + "fullPath", + "fullScreen", + "fullscreen", + "fullscreenElement", + "fullscreenEnabled", + "fx", + "fy", + "gain", + "gamepad", + "gamma", + "gap", + "gatheringState", + "gatt", + "genderIdentity", + "generateCertificate", + "generateKey", + "generateMipmap", + "generateRequest", + "geolocation", + "gestureObject", + "get", + "getActiveAttrib", + "getActiveUniform", + "getActiveUniformBlockName", + "getActiveUniformBlockParameter", + "getActiveUniforms", + "getAdjacentText", + "getAll", + "getAllKeys", + "getAllResponseHeaders", + "getAllowlistForFeature", + "getAnimations", + "getAsFile", + "getAsString", + "getAttachedShaders", + "getAttribLocation", + "getAttribute", + "getAttributeNS", + "getAttributeNames", + "getAttributeNode", + "getAttributeNodeNS", + "getAttributeType", + "getAudioTracks", + "getAvailability", + "getBBox", + "getBattery", + "getBigInt64", + "getBigUint64", + "getBlob", + "getBookmark", + "getBoundingClientRect", + "getBounds", + "getBoxQuads", + "getBufferParameter", + "getBufferSubData", + "getByteFrequencyData", + "getByteTimeDomainData", + "getCSSCanvasContext", + "getCTM", + "getCandidateWindowClientRect", + "getCanonicalLocales", + "getCapabilities", + "getChannelData", + "getCharNumAtPosition", + "getCharacteristic", + "getCharacteristics", + "getClientExtensionResults", + "getClientRect", + "getClientRects", + "getCoalescedEvents", + "getCompositionAlternatives", + "getComputedStyle", + "getComputedTextLength", + "getComputedTiming", + "getConfiguration", + "getConstraints", + "getContext", + "getContextAttributes", + "getContributingSources", + "getCounterValue", + "getCueAsHTML", + "getCueById", + "getCurrentPosition", + "getCurrentTime", + "getData", + "getDatabaseNames", + "getDate", + "getDay", + "getDefaultComputedStyle", + "getDescriptor", + "getDescriptors", + "getDestinationInsertionPoints", + "getDevices", + "getDirectory", + "getDisplayMedia", + "getDistributedNodes", + "getEditable", + "getElementById", + "getElementsByClassName", + "getElementsByName", + "getElementsByTagName", + "getElementsByTagNameNS", + "getEnclosureList", + "getEndPositionOfChar", + "getEntries", + "getEntriesByName", + "getEntriesByType", + "getError", + "getExtension", + "getExtentOfChar", + "getEyeParameters", + "getFeature", + "getFile", + "getFiles", + "getFilesAndDirectories", + "getFingerprints", + "getFloat32", + "getFloat64", + "getFloatFrequencyData", + "getFloatTimeDomainData", + "getFloatValue", + "getFragDataLocation", + "getFrameData", + "getFramebufferAttachmentParameter", + "getFrequencyResponse", + "getFullYear", + "getGamepads", + "getHitTestResults", + "getHitTestResultsForTransientInput", + "getHours", + "getIdentityAssertion", + "getIds", + "getImageData", + "getIndexedParameter", + "getInstalledRelatedApps", + "getInt16", + "getInt32", + "getInt8", + "getInternalformatParameter", + "getIntersectionList", + "getItem", + "getItems", + "getKey", + "getKeyframes", + "getLayers", + "getLayoutMap", + "getLineDash", + "getLocalCandidates", + "getLocalParameters", + "getLocalStreams", + "getMarks", + "getMatchedCSSRules", + "getMaxGCPauseSinceClear", + "getMeasures", + "getMetadata", + "getMilliseconds", + "getMinutes", + "getModifierState", + "getMonth", + "getNamedItem", + "getNamedItemNS", + "getNativeFramebufferScaleFactor", + "getNotifications", + "getNotifier", + "getNumberOfChars", + "getOffsetReferenceSpace", + "getOutputTimestamp", + "getOverrideHistoryNavigationMode", + "getOverrideStyle", + "getOwnPropertyDescriptor", + "getOwnPropertyDescriptors", + "getOwnPropertyNames", + "getOwnPropertySymbols", + "getParameter", + "getParameters", + "getParent", + "getPathSegAtLength", + "getPhotoCapabilities", + "getPhotoSettings", + "getPointAtLength", + "getPose", + "getPredictedEvents", + "getPreference", + "getPreferenceDefault", + "getPresentationAttribute", + "getPreventDefault", + "getPrimaryService", + "getPrimaryServices", + "getProgramInfoLog", + "getProgramParameter", + "getPropertyCSSValue", + "getPropertyPriority", + "getPropertyShorthand", + "getPropertyType", + "getPropertyValue", + "getPrototypeOf", + "getQuery", + "getQueryParameter", + "getRGBColorValue", + "getRandomValues", + "getRangeAt", + "getReader", + "getReceivers", + "getRectValue", + "getRegistration", + "getRegistrations", + "getRemoteCandidates", + "getRemoteCertificates", + "getRemoteParameters", + "getRemoteStreams", + "getRenderbufferParameter", + "getResponseHeader", + "getRoot", + "getRootNode", + "getRotationOfChar", + "getSVGDocument", + "getSamplerParameter", + "getScreenCTM", + "getSeconds", + "getSelectedCandidatePair", + "getSelection", + "getSenders", + "getService", + "getSettings", + "getShaderInfoLog", + "getShaderParameter", + "getShaderPrecisionFormat", + "getShaderSource", + "getSimpleDuration", + "getSiteIcons", + "getSources", + "getSpeculativeParserUrls", + "getStartPositionOfChar", + "getStartTime", + "getState", + "getStats", + "getStatusForPolicy", + "getStorageUpdates", + "getStreamById", + "getStringValue", + "getSubStringLength", + "getSubscription", + "getSupportedConstraints", + "getSupportedExtensions", + "getSupportedFormats", + "getSyncParameter", + "getSynchronizationSources", + "getTags", + "getTargetRanges", + "getTexParameter", + "getTime", + "getTimezoneOffset", + "getTiming", + "getTotalLength", + "getTrackById", + "getTracks", + "getTransceivers", + "getTransform", + "getTransformFeedbackVarying", + "getTransformToElement", + "getTransports", + "getType", + "getTypeMapping", + "getUTCDate", + "getUTCDay", + "getUTCFullYear", + "getUTCHours", + "getUTCMilliseconds", + "getUTCMinutes", + "getUTCMonth", + "getUTCSeconds", + "getUint16", + "getUint32", + "getUint8", + "getUniform", + "getUniformBlockIndex", + "getUniformIndices", + "getUniformLocation", + "getUserMedia", + "getVRDisplays", + "getValues", + "getVarDate", + "getVariableValue", + "getVertexAttrib", + "getVertexAttribOffset", + "getVideoPlaybackQuality", + "getVideoTracks", + "getViewerPose", + "getViewport", + "getVoices", + "getWakeLockState", + "getWriter", + "getYear", + "givenName", + "global", + "globalAlpha", + "globalCompositeOperation", + "globalThis", + "glyphOrientationHorizontal", + "glyphOrientationVertical", + "glyphRef", + "go", + "grabFrame", + "grad", + "gradientTransform", + "gradientUnits", + "grammars", + "green", + "grid", + "grid-area", + "grid-auto-columns", + "grid-auto-flow", + "grid-auto-rows", + "grid-column", + "grid-column-end", + "grid-column-gap", + "grid-column-start", + "grid-gap", + "grid-row", + "grid-row-end", + "grid-row-gap", + "grid-row-start", + "grid-template", + "grid-template-areas", + "grid-template-columns", + "grid-template-rows", + "gridArea", + "gridAutoColumns", + "gridAutoFlow", + "gridAutoRows", + "gridColumn", + "gridColumnEnd", + "gridColumnGap", + "gridColumnStart", + "gridGap", + "gridRow", + "gridRowEnd", + "gridRowGap", + "gridRowStart", + "gridTemplate", + "gridTemplateAreas", + "gridTemplateColumns", + "gridTemplateRows", + "gripSpace", + "group", + "groupCollapsed", + "groupEnd", + "groupId", + "hadRecentInput", + "hand", + "handedness", + "hapticActuators", + "hardwareConcurrency", + "has", + "hasAttribute", + "hasAttributeNS", + "hasAttributes", + "hasBeenActive", + "hasChildNodes", + "hasComposition", + "hasEnrolledInstrument", + "hasExtension", + "hasExternalDisplay", + "hasFeature", + "hasFocus", + "hasInstance", + "hasLayout", + "hasOrientation", + "hasOwnProperty", + "hasPointerCapture", + "hasPosition", + "hasReading", + "hasStorageAccess", + "hash", + "head", + "headers", + "heading", + "height", + "hidden", + "hide", + "hideFocus", + "high", + "highWaterMark", + "hint", + "history", + "honorificPrefix", + "honorificSuffix", + "horizontalOverflow", + "host", + "hostCandidate", + "hostname", + "href", + "hrefTranslate", + "hreflang", + "hspace", + "html5TagCheckInerface", + "htmlFor", + "htmlText", + "httpEquiv", + "httpRequestStatusCode", + "hwTimestamp", + "hyphens", + "hypot", + "iccId", + "iceConnectionState", + "iceGatheringState", + "iceTransport", + "icon", + "iconURL", + "id", + "identifier", + "identity", + "idpLoginUrl", + "ignoreBOM", + "ignoreCase", + "ignoreDepthValues", + "image-orientation", + "image-rendering", + "imageHeight", + "imageOrientation", + "imageRendering", + "imageSizes", + "imageSmoothingEnabled", + "imageSmoothingQuality", + "imageSrcset", + "imageWidth", + "images", + "ime-mode", + "imeMode", + "implementation", + "importKey", + "importNode", + "importStylesheet", + "imports", + "impp", + "imul", + "in", + "in1", + "in2", + "inBandMetadataTrackDispatchType", + "inRange", + "includes", + "incremental", + "indeterminate", + "index", + "indexNames", + "indexOf", + "indexedDB", + "indicate", + "inertiaDestinationX", + "inertiaDestinationY", + "info", + "init", + "initAnimationEvent", + "initBeforeLoadEvent", + "initClipboardEvent", + "initCloseEvent", + "initCommandEvent", + "initCompositionEvent", + "initCustomEvent", + "initData", + "initDataType", + "initDeviceMotionEvent", + "initDeviceOrientationEvent", + "initDragEvent", + "initErrorEvent", + "initEvent", + "initFocusEvent", + "initGestureEvent", + "initHashChangeEvent", + "initKeyEvent", + "initKeyboardEvent", + "initMSManipulationEvent", + "initMessageEvent", + "initMouseEvent", + "initMouseScrollEvent", + "initMouseWheelEvent", + "initMutationEvent", + "initNSMouseEvent", + "initOverflowEvent", + "initPageEvent", + "initPageTransitionEvent", + "initPointerEvent", + "initPopStateEvent", + "initProgressEvent", + "initScrollAreaEvent", + "initSimpleGestureEvent", + "initStorageEvent", + "initTextEvent", + "initTimeEvent", + "initTouchEvent", + "initTransitionEvent", + "initUIEvent", + "initWebKitAnimationEvent", + "initWebKitTransitionEvent", + "initWebKitWheelEvent", + "initWheelEvent", + "initialTime", + "initialize", + "initiatorType", + "inline-size", + "inlineSize", + "inlineVerticalFieldOfView", + "inner", + "innerHTML", + "innerHeight", + "innerText", + "innerWidth", + "input", + "inputBuffer", + "inputEncoding", + "inputMethod", + "inputMode", + "inputSource", + "inputSources", + "inputType", + "inputs", + "insertAdjacentElement", + "insertAdjacentHTML", + "insertAdjacentText", + "insertBefore", + "insertCell", + "insertDTMF", + "insertData", + "insertItemBefore", + "insertNode", + "insertRow", + "insertRule", + "inset", + "inset-block", + "inset-block-end", + "inset-block-start", + "inset-inline", + "inset-inline-end", + "inset-inline-start", + "insetBlock", + "insetBlockEnd", + "insetBlockStart", + "insetInline", + "insetInlineEnd", + "insetInlineStart", + "installing", + "instanceRoot", + "instantiate", + "instantiateStreaming", + "instruments", + "int16", + "int32", + "int8", + "integrity", + "interactionMode", + "intercept", + "interfaceClass", + "interfaceName", + "interfaceNumber", + "interfaceProtocol", + "interfaceSubclass", + "interfaces", + "interimResults", + "internalSubset", + "interpretation", + "intersectionRatio", + "intersectionRect", + "intersectsNode", + "interval", + "invalidIteratorState", + "invalidateFramebuffer", + "invalidateSubFramebuffer", + "inverse", + "invertSelf", + "is", + "is2D", + "isActive", + "isAlternate", + "isArray", + "isBingCurrentSearchDefault", + "isBuffer", + "isCandidateWindowVisible", + "isChar", + "isCollapsed", + "isComposing", + "isConcatSpreadable", + "isConnected", + "isContentEditable", + "isContentHandlerRegistered", + "isContextLost", + "isDefaultNamespace", + "isDirectory", + "isDisabled", + "isEnabled", + "isEqual", + "isEqualNode", + "isExtensible", + "isExternalCTAP2SecurityKeySupported", + "isFile", + "isFinite", + "isFramebuffer", + "isFrozen", + "isGenerator", + "isHTML", + "isHistoryNavigation", + "isId", + "isIdentity", + "isInjected", + "isInteger", + "isIntersecting", + "isLockFree", + "isMap", + "isMultiLine", + "isNaN", + "isOpen", + "isPointInFill", + "isPointInPath", + "isPointInRange", + "isPointInStroke", + "isPrefAlternate", + "isPresenting", + "isPrimary", + "isProgram", + "isPropertyImplicit", + "isProtocolHandlerRegistered", + "isPrototypeOf", + "isQuery", + "isRenderbuffer", + "isSafeInteger", + "isSameNode", + "isSampler", + "isScript", + "isScriptURL", + "isSealed", + "isSecureContext", + "isSessionSupported", + "isShader", + "isSupported", + "isSync", + "isTextEdit", + "isTexture", + "isTransformFeedback", + "isTrusted", + "isTypeSupported", + "isUserVerifyingPlatformAuthenticatorAvailable", + "isVertexArray", + "isView", + "isVisible", + "isochronousTransferIn", + "isochronousTransferOut", + "isolation", + "italics", + "item", + "itemId", + "itemProp", + "itemRef", + "itemScope", + "itemType", + "itemValue", + "items", + "iterateNext", + "iterationComposite", + "iterator", + "javaEnabled", + "jobTitle", + "join", + "json", + "justify-content", + "justify-items", + "justify-self", + "justifyContent", + "justifyItems", + "justifySelf", + "k1", + "k2", + "k3", + "k4", + "kHz", + "keepalive", + "kernelMatrix", + "kernelUnitLengthX", + "kernelUnitLengthY", + "kerning", + "key", + "keyCode", + "keyFor", + "keyIdentifier", + "keyLightEnabled", + "keyLocation", + "keyPath", + "keyStatuses", + "keySystem", + "keyText", + "keyUsage", + "keyboard", + "keys", + "keytype", + "kind", + "knee", + "label", + "labels", + "lang", + "language", + "languages", + "largeArcFlag", + "lastChild", + "lastElementChild", + "lastEventId", + "lastIndex", + "lastIndexOf", + "lastInputTime", + "lastMatch", + "lastMessageSubject", + "lastMessageType", + "lastModified", + "lastModifiedDate", + "lastPage", + "lastParen", + "lastState", + "lastStyleSheetSet", + "latitude", + "layerX", + "layerY", + "layoutFlow", + "layoutGrid", + "layoutGridChar", + "layoutGridLine", + "layoutGridMode", + "layoutGridType", + "lbound", + "left", + "leftContext", + "leftDegrees", + "leftMargin", + "leftProjectionMatrix", + "leftViewMatrix", + "length", + "lengthAdjust", + "lengthComputable", + "letter-spacing", + "letterSpacing", + "level", + "lighting-color", + "lightingColor", + "limitingConeAngle", + "line", + "line-break", + "line-height", + "lineAlign", + "lineBreak", + "lineCap", + "lineDashOffset", + "lineHeight", + "lineJoin", + "lineNumber", + "lineTo", + "lineWidth", + "linearAcceleration", + "linearRampToValueAtTime", + "linearVelocity", + "lineno", + "lines", + "link", + "linkColor", + "linkProgram", + "links", + "list", + "list-style", + "list-style-image", + "list-style-position", + "list-style-type", + "listStyle", + "listStyleImage", + "listStylePosition", + "listStyleType", + "listener", + "load", + "loadEventEnd", + "loadEventStart", + "loadTime", + "loadTimes", + "loaded", + "loading", + "localDescription", + "localName", + "localService", + "localStorage", + "locale", + "localeCompare", + "location", + "locationbar", + "lock", + "locked", + "lockedFile", + "locks", + "log", + "log10", + "log1p", + "log2", + "logicalXDPI", + "logicalYDPI", + "longDesc", + "longitude", + "lookupNamespaceURI", + "lookupPrefix", + "loop", + "loopEnd", + "loopStart", + "looping", + "low", + "lower", + "lowerBound", + "lowerOpen", + "lowsrc", + "m11", + "m12", + "m13", + "m14", + "m21", + "m22", + "m23", + "m24", + "m31", + "m32", + "m33", + "m34", + "m41", + "m42", + "m43", + "m44", + "makeXRCompatible", + "manifest", + "manufacturer", + "manufacturerName", + "map", + "mapping", + "margin", + "margin-block", + "margin-block-end", + "margin-block-start", + "margin-bottom", + "margin-inline", + "margin-inline-end", + "margin-inline-start", + "margin-left", + "margin-right", + "margin-top", + "marginBlock", + "marginBlockEnd", + "marginBlockStart", + "marginBottom", + "marginHeight", + "marginInline", + "marginInlineEnd", + "marginInlineStart", + "marginLeft", + "marginRight", + "marginTop", + "marginWidth", + "mark", + "marker", + "marker-end", + "marker-mid", + "marker-offset", + "marker-start", + "markerEnd", + "markerHeight", + "markerMid", + "markerOffset", + "markerStart", + "markerUnits", + "markerWidth", + "marks", + "mask", + "mask-clip", + "mask-composite", + "mask-image", + "mask-mode", + "mask-origin", + "mask-position", + "mask-position-x", + "mask-position-y", + "mask-repeat", + "mask-size", + "mask-type", + "maskClip", + "maskComposite", + "maskContentUnits", + "maskImage", + "maskMode", + "maskOrigin", + "maskPosition", + "maskPositionX", + "maskPositionY", + "maskRepeat", + "maskSize", + "maskType", + "maskUnits", + "match", + "matchAll", + "matchMedia", + "matchMedium", + "matches", + "matrix", + "matrixTransform", + "max", + "max-block-size", + "max-height", + "max-inline-size", + "max-width", + "maxActions", + "maxAlternatives", + "maxBlockSize", + "maxChannelCount", + "maxChannels", + "maxConnectionsPerServer", + "maxDecibels", + "maxDistance", + "maxHeight", + "maxInlineSize", + "maxLayers", + "maxLength", + "maxMessageSize", + "maxPacketLifeTime", + "maxRetransmits", + "maxTouchPoints", + "maxValue", + "maxWidth", + "measure", + "measureText", + "media", + "mediaCapabilities", + "mediaDevices", + "mediaElement", + "mediaGroup", + "mediaKeys", + "mediaSession", + "mediaStream", + "mediaText", + "meetOrSlice", + "memory", + "menubar", + "mergeAttributes", + "message", + "messageClass", + "messageHandlers", + "messageType", + "metaKey", + "metadata", + "method", + "methodDetails", + "methodName", + "mid", + "mimeType", + "mimeTypes", + "min", + "min-block-size", + "min-height", + "min-inline-size", + "min-width", + "minBlockSize", + "minDecibels", + "minHeight", + "minInlineSize", + "minLength", + "minValue", + "minWidth", + "miterLimit", + "mix-blend-mode", + "mixBlendMode", + "mm", + "mode", + "modify", + "mount", + "move", + "moveBy", + "moveEnd", + "moveFirst", + "moveFocusDown", + "moveFocusLeft", + "moveFocusRight", + "moveFocusUp", + "moveNext", + "moveRow", + "moveStart", + "moveTo", + "moveToBookmark", + "moveToElementText", + "moveToPoint", + "movementX", + "movementY", + "mozAdd", + "mozAnimationStartTime", + "mozAnon", + "mozApps", + "mozAudioCaptured", + "mozAudioChannelType", + "mozAutoplayEnabled", + "mozCancelAnimationFrame", + "mozCancelFullScreen", + "mozCancelRequestAnimationFrame", + "mozCaptureStream", + "mozCaptureStreamUntilEnded", + "mozClearDataAt", + "mozContact", + "mozContacts", + "mozCreateFileHandle", + "mozCurrentTransform", + "mozCurrentTransformInverse", + "mozCursor", + "mozDash", + "mozDashOffset", + "mozDecodedFrames", + "mozExitPointerLock", + "mozFillRule", + "mozFragmentEnd", + "mozFrameDelay", + "mozFullScreen", + "mozFullScreenElement", + "mozFullScreenEnabled", + "mozGetAll", + "mozGetAllKeys", + "mozGetAsFile", + "mozGetDataAt", + "mozGetMetadata", + "mozGetUserMedia", + "mozHasAudio", + "mozHasItem", + "mozHidden", + "mozImageSmoothingEnabled", + "mozIndexedDB", + "mozInnerScreenX", + "mozInnerScreenY", + "mozInputSource", + "mozIsTextField", + "mozItem", + "mozItemCount", + "mozItems", + "mozLength", + "mozLockOrientation", + "mozMatchesSelector", + "mozMovementX", + "mozMovementY", + "mozOpaque", + "mozOrientation", + "mozPaintCount", + "mozPaintedFrames", + "mozParsedFrames", + "mozPay", + "mozPointerLockElement", + "mozPresentedFrames", + "mozPreservesPitch", + "mozPressure", + "mozPrintCallback", + "mozRTCIceCandidate", + "mozRTCPeerConnection", + "mozRTCSessionDescription", + "mozRemove", + "mozRequestAnimationFrame", + "mozRequestFullScreen", + "mozRequestPointerLock", + "mozSetDataAt", + "mozSetImageElement", + "mozSourceNode", + "mozSrcObject", + "mozSystem", + "mozTCPSocket", + "mozTextStyle", + "mozTypesAt", + "mozUnlockOrientation", + "mozUserCancelled", + "mozVisibilityState", + "ms", + "msAnimation", + "msAnimationDelay", + "msAnimationDirection", + "msAnimationDuration", + "msAnimationFillMode", + "msAnimationIterationCount", + "msAnimationName", + "msAnimationPlayState", + "msAnimationStartTime", + "msAnimationTimingFunction", + "msBackfaceVisibility", + "msBlockProgression", + "msCSSOMElementFloatMetrics", + "msCaching", + "msCachingEnabled", + "msCancelRequestAnimationFrame", + "msCapsLockWarningOff", + "msClearImmediate", + "msClose", + "msContentZoomChaining", + "msContentZoomFactor", + "msContentZoomLimit", + "msContentZoomLimitMax", + "msContentZoomLimitMin", + "msContentZoomSnap", + "msContentZoomSnapPoints", + "msContentZoomSnapType", + "msContentZooming", + "msConvertURL", + "msCrypto", + "msDoNotTrack", + "msElementsFromPoint", + "msElementsFromRect", + "msExitFullscreen", + "msExtendedCode", + "msFillRule", + "msFirstPaint", + "msFlex", + "msFlexAlign", + "msFlexDirection", + "msFlexFlow", + "msFlexItemAlign", + "msFlexLinePack", + "msFlexNegative", + "msFlexOrder", + "msFlexPack", + "msFlexPositive", + "msFlexPreferredSize", + "msFlexWrap", + "msFlowFrom", + "msFlowInto", + "msFontFeatureSettings", + "msFullscreenElement", + "msFullscreenEnabled", + "msGetInputContext", + "msGetRegionContent", + "msGetUntransformedBounds", + "msGraphicsTrustStatus", + "msGridColumn", + "msGridColumnAlign", + "msGridColumnSpan", + "msGridColumns", + "msGridRow", + "msGridRowAlign", + "msGridRowSpan", + "msGridRows", + "msHidden", + "msHighContrastAdjust", + "msHyphenateLimitChars", + "msHyphenateLimitLines", + "msHyphenateLimitZone", + "msHyphens", + "msImageSmoothingEnabled", + "msImeAlign", + "msIndexedDB", + "msInterpolationMode", + "msIsStaticHTML", + "msKeySystem", + "msKeys", + "msLaunchUri", + "msLockOrientation", + "msManipulationViewsEnabled", + "msMatchMedia", + "msMatchesSelector", + "msMaxTouchPoints", + "msOrientation", + "msOverflowStyle", + "msPerspective", + "msPerspectiveOrigin", + "msPlayToDisabled", + "msPlayToPreferredSourceUri", + "msPlayToPrimary", + "msPointerEnabled", + "msRegionOverflow", + "msReleasePointerCapture", + "msRequestAnimationFrame", + "msRequestFullscreen", + "msSaveBlob", + "msSaveOrOpenBlob", + "msScrollChaining", + "msScrollLimit", + "msScrollLimitXMax", + "msScrollLimitXMin", + "msScrollLimitYMax", + "msScrollLimitYMin", + "msScrollRails", + "msScrollSnapPointsX", + "msScrollSnapPointsY", + "msScrollSnapType", + "msScrollSnapX", + "msScrollSnapY", + "msScrollTranslation", + "msSetImmediate", + "msSetMediaKeys", + "msSetPointerCapture", + "msTextCombineHorizontal", + "msTextSizeAdjust", + "msToBlob", + "msTouchAction", + "msTouchSelect", + "msTraceAsyncCallbackCompleted", + "msTraceAsyncCallbackStarting", + "msTraceAsyncOperationCompleted", + "msTraceAsyncOperationStarting", + "msTransform", + "msTransformOrigin", + "msTransformStyle", + "msTransition", + "msTransitionDelay", + "msTransitionDuration", + "msTransitionProperty", + "msTransitionTimingFunction", + "msUnlockOrientation", + "msUpdateAsyncCallbackRelation", + "msUserSelect", + "msVisibilityState", + "msWrapFlow", + "msWrapMargin", + "msWrapThrough", + "msWriteProfilerMark", + "msZoom", + "msZoomTo", + "mt", + "mul", + "multiEntry", + "multiSelectionObj", + "multiline", + "multiple", + "multiply", + "multiplySelf", + "mutableFile", + "muted", + "n", + "name", + "nameProp", + "namedItem", + "namedRecordset", + "names", + "namespaceURI", + "namespaces", + "naturalHeight", + "naturalWidth", + "navigate", + "navigation", + "navigationMode", + "navigationPreload", + "navigationStart", + "navigator", + "near", + "nearestViewportElement", + "negative", + "negotiated", + "netscape", + "networkState", + "newScale", + "newTranslate", + "newURL", + "newValue", + "newValueSpecifiedUnits", + "newVersion", + "newhome", + "next", + "nextElementSibling", + "nextHopProtocol", + "nextNode", + "nextPage", + "nextSibling", + "nickname", + "noHref", + "noModule", + "noResize", + "noShade", + "noValidate", + "noWrap", + "node", + "nodeName", + "nodeType", + "nodeValue", + "nonce", + "normalize", + "normalizedPathSegList", + "notationName", + "notations", + "note", + "noteGrainOn", + "noteOff", + "noteOn", + "notify", + "now", + "numOctaves", + "number", + "numberOfChannels", + "numberOfInputs", + "numberOfItems", + "numberOfOutputs", + "numberValue", + "oMatchesSelector", + "object", + "object-fit", + "object-position", + "objectFit", + "objectPosition", + "objectStore", + "objectStoreNames", + "objectType", + "observe", + "of", + "offscreenBuffering", + "offset", + "offset-anchor", + "offset-distance", + "offset-path", + "offset-rotate", + "offsetAnchor", + "offsetDistance", + "offsetHeight", + "offsetLeft", + "offsetNode", + "offsetParent", + "offsetPath", + "offsetRotate", + "offsetTop", + "offsetWidth", + "offsetX", + "offsetY", + "ok", + "oldURL", + "oldValue", + "oldVersion", + "olderShadowRoot", + "onLine", + "onabort", + "onabsolutedeviceorientation", + "onactivate", + "onactive", + "onaddsourcebuffer", + "onaddstream", + "onaddtrack", + "onafterprint", + "onafterscriptexecute", + "onafterupdate", + "onanimationcancel", + "onanimationend", + "onanimationiteration", + "onanimationstart", + "onappinstalled", + "onaudioend", + "onaudioprocess", + "onaudiostart", + "onautocomplete", + "onautocompleteerror", + "onauxclick", + "onbeforeactivate", + "onbeforecopy", + "onbeforecut", + "onbeforedeactivate", + "onbeforeeditfocus", + "onbeforeinstallprompt", + "onbeforepaste", + "onbeforeprint", + "onbeforescriptexecute", + "onbeforeunload", + "onbeforeupdate", + "onbeforexrselect", + "onbegin", + "onblocked", + "onblur", + "onbounce", + "onboundary", + "onbufferedamountlow", + "oncached", + "oncancel", + "oncandidatewindowhide", + "oncandidatewindowshow", + "oncandidatewindowupdate", + "oncanplay", + "oncanplaythrough", + "once", + "oncellchange", + "onchange", + "oncharacteristicvaluechanged", + "onchargingchange", + "onchargingtimechange", + "onchecking", + "onclick", + "onclose", + "onclosing", + "oncompassneedscalibration", + "oncomplete", + "onconnect", + "onconnecting", + "onconnectionavailable", + "onconnectionstatechange", + "oncontextmenu", + "oncontrollerchange", + "oncontrolselect", + "oncopy", + "oncuechange", + "oncut", + "ondataavailable", + "ondatachannel", + "ondatasetchanged", + "ondatasetcomplete", + "ondblclick", + "ondeactivate", + "ondevicechange", + "ondevicelight", + "ondevicemotion", + "ondeviceorientation", + "ondeviceorientationabsolute", + "ondeviceproximity", + "ondischargingtimechange", + "ondisconnect", + "ondisplay", + "ondownloading", + "ondrag", + "ondragend", + "ondragenter", + "ondragexit", + "ondragleave", + "ondragover", + "ondragstart", + "ondrop", + "ondurationchange", + "onemptied", + "onencrypted", + "onend", + "onended", + "onenter", + "onenterpictureinpicture", + "onerror", + "onerrorupdate", + "onexit", + "onfilterchange", + "onfinish", + "onfocus", + "onfocusin", + "onfocusout", + "onformdata", + "onfreeze", + "onfullscreenchange", + "onfullscreenerror", + "ongatheringstatechange", + "ongattserverdisconnected", + "ongesturechange", + "ongestureend", + "ongesturestart", + "ongotpointercapture", + "onhashchange", + "onhelp", + "onicecandidate", + "onicecandidateerror", + "oniceconnectionstatechange", + "onicegatheringstatechange", + "oninactive", + "oninput", + "oninputsourceschange", + "oninvalid", + "onkeydown", + "onkeypress", + "onkeystatuseschange", + "onkeyup", + "onlanguagechange", + "onlayoutcomplete", + "onleavepictureinpicture", + "onlevelchange", + "onload", + "onloadeddata", + "onloadedmetadata", + "onloadend", + "onloading", + "onloadingdone", + "onloadingerror", + "onloadstart", + "onlosecapture", + "onlostpointercapture", + "only", + "onmark", + "onmessage", + "onmessageerror", + "onmidimessage", + "onmousedown", + "onmouseenter", + "onmouseleave", + "onmousemove", + "onmouseout", + "onmouseover", + "onmouseup", + "onmousewheel", + "onmove", + "onmoveend", + "onmovestart", + "onmozfullscreenchange", + "onmozfullscreenerror", + "onmozorientationchange", + "onmozpointerlockchange", + "onmozpointerlockerror", + "onmscontentzoom", + "onmsfullscreenchange", + "onmsfullscreenerror", + "onmsgesturechange", + "onmsgesturedoubletap", + "onmsgestureend", + "onmsgesturehold", + "onmsgesturestart", + "onmsgesturetap", + "onmsgotpointercapture", + "onmsinertiastart", + "onmslostpointercapture", + "onmsmanipulationstatechanged", + "onmsneedkey", + "onmsorientationchange", + "onmspointercancel", + "onmspointerdown", + "onmspointerenter", + "onmspointerhover", + "onmspointerleave", + "onmspointermove", + "onmspointerout", + "onmspointerover", + "onmspointerup", + "onmssitemodejumplistitemremoved", + "onmsthumbnailclick", + "onmute", + "onnegotiationneeded", + "onnomatch", + "onnoupdate", + "onobsolete", + "onoffline", + "ononline", + "onopen", + "onorientationchange", + "onpagechange", + "onpagehide", + "onpageshow", + "onpaste", + "onpause", + "onpayerdetailchange", + "onpaymentmethodchange", + "onplay", + "onplaying", + "onpluginstreamstart", + "onpointercancel", + "onpointerdown", + "onpointerenter", + "onpointerleave", + "onpointerlockchange", + "onpointerlockerror", + "onpointermove", + "onpointerout", + "onpointerover", + "onpointerrawupdate", + "onpointerup", + "onpopstate", + "onprocessorerror", + "onprogress", + "onpropertychange", + "onratechange", + "onreading", + "onreadystatechange", + "onrejectionhandled", + "onrelease", + "onremove", + "onremovesourcebuffer", + "onremovestream", + "onremovetrack", + "onrepeat", + "onreset", + "onresize", + "onresizeend", + "onresizestart", + "onresourcetimingbufferfull", + "onresult", + "onresume", + "onrowenter", + "onrowexit", + "onrowsdelete", + "onrowsinserted", + "onscroll", + "onsearch", + "onsecuritypolicyviolation", + "onseeked", + "onseeking", + "onselect", + "onselectedcandidatepairchange", + "onselectend", + "onselectionchange", + "onselectstart", + "onshippingaddresschange", + "onshippingoptionchange", + "onshow", + "onsignalingstatechange", + "onsoundend", + "onsoundstart", + "onsourceclose", + "onsourceclosed", + "onsourceended", + "onsourceopen", + "onspeechend", + "onspeechstart", + "onsqueeze", + "onsqueezeend", + "onsqueezestart", + "onstalled", + "onstart", + "onstatechange", + "onstop", + "onstorage", + "onstoragecommit", + "onsubmit", + "onsuccess", + "onsuspend", + "onterminate", + "ontextinput", + "ontimeout", + "ontimeupdate", + "ontoggle", + "ontonechange", + "ontouchcancel", + "ontouchend", + "ontouchmove", + "ontouchstart", + "ontrack", + "ontransitioncancel", + "ontransitionend", + "ontransitionrun", + "ontransitionstart", + "onunhandledrejection", + "onunload", + "onunmute", + "onupdate", + "onupdateend", + "onupdatefound", + "onupdateready", + "onupdatestart", + "onupgradeneeded", + "onuserproximity", + "onversionchange", + "onvisibilitychange", + "onvoiceschanged", + "onvolumechange", + "onvrdisplayactivate", + "onvrdisplayconnect", + "onvrdisplaydeactivate", + "onvrdisplaydisconnect", + "onvrdisplaypresentchange", + "onwaiting", + "onwaitingforkey", + "onwarning", + "onwebkitanimationend", + "onwebkitanimationiteration", + "onwebkitanimationstart", + "onwebkitcurrentplaybacktargetiswirelesschanged", + "onwebkitfullscreenchange", + "onwebkitfullscreenerror", + "onwebkitkeyadded", + "onwebkitkeyerror", + "onwebkitkeymessage", + "onwebkitneedkey", + "onwebkitorientationchange", + "onwebkitplaybacktargetavailabilitychanged", + "onwebkitpointerlockchange", + "onwebkitpointerlockerror", + "onwebkitresourcetimingbufferfull", + "onwebkittransitionend", + "onwheel", + "onzoom", + "opacity", + "open", + "openCursor", + "openDatabase", + "openKeyCursor", + "opened", + "opener", + "opera", + "operationType", + "operator", + "opr", + "optimum", + "options", + "or", + "order", + "orderX", + "orderY", + "ordered", + "org", + "organization", + "orient", + "orientAngle", + "orientType", + "orientation", + "orientationX", + "orientationY", + "orientationZ", + "origin", + "originalPolicy", + "originalTarget", + "orphans", + "oscpu", + "outerHTML", + "outerHeight", + "outerText", + "outerWidth", + "outline", + "outline-color", + "outline-offset", + "outline-style", + "outline-width", + "outlineColor", + "outlineOffset", + "outlineStyle", + "outlineWidth", + "outputBuffer", + "outputLatency", + "outputs", + "overflow", + "overflow-anchor", + "overflow-block", + "overflow-inline", + "overflow-wrap", + "overflow-x", + "overflow-y", + "overflowAnchor", + "overflowBlock", + "overflowInline", + "overflowWrap", + "overflowX", + "overflowY", + "overrideMimeType", + "oversample", + "overscroll-behavior", + "overscroll-behavior-block", + "overscroll-behavior-inline", + "overscroll-behavior-x", + "overscroll-behavior-y", + "overscrollBehavior", + "overscrollBehaviorBlock", + "overscrollBehaviorInline", + "overscrollBehaviorX", + "overscrollBehaviorY", + "ownKeys", + "ownerDocument", + "ownerElement", + "ownerNode", + "ownerRule", + "ownerSVGElement", + "owningElement", + "p1", + "p2", + "p3", + "p4", + "packetSize", + "packets", + "pad", + "padEnd", + "padStart", + "padding", + "padding-block", + "padding-block-end", + "padding-block-start", + "padding-bottom", + "padding-inline", + "padding-inline-end", + "padding-inline-start", + "padding-left", + "padding-right", + "padding-top", + "paddingBlock", + "paddingBlockEnd", + "paddingBlockStart", + "paddingBottom", + "paddingInline", + "paddingInlineEnd", + "paddingInlineStart", + "paddingLeft", + "paddingRight", + "paddingTop", + "page", + "page-break-after", + "page-break-before", + "page-break-inside", + "pageBreakAfter", + "pageBreakBefore", + "pageBreakInside", + "pageCount", + "pageLeft", + "pageTop", + "pageX", + "pageXOffset", + "pageY", + "pageYOffset", + "pages", + "paint-order", + "paintOrder", + "paintRequests", + "paintType", + "paintWorklet", + "palette", + "pan", + "panningModel", + "parameters", + "parent", + "parentElement", + "parentNode", + "parentRule", + "parentStyleSheet", + "parentTextEdit", + "parentWindow", + "parse", + "parseAll", + "parseFloat", + "parseFromString", + "parseInt", + "part", + "participants", + "passive", + "password", + "pasteHTML", + "path", + "pathLength", + "pathSegList", + "pathSegType", + "pathSegTypeAsLetter", + "pathname", + "pattern", + "patternContentUnits", + "patternMismatch", + "patternTransform", + "patternUnits", + "pause", + "pauseAnimations", + "pauseOnExit", + "pauseProfilers", + "pauseTransformFeedback", + "paused", + "payerEmail", + "payerName", + "payerPhone", + "paymentManager", + "pc", + "peerIdentity", + "pending", + "pendingLocalDescription", + "pendingRemoteDescription", + "percent", + "performance", + "periodicSync", + "permission", + "permissionState", + "permissions", + "persist", + "persisted", + "personalbar", + "perspective", + "perspective-origin", + "perspectiveOrigin", + "phone", + "phoneticFamilyName", + "phoneticGivenName", + "photo", + "pictureInPictureElement", + "pictureInPictureEnabled", + "pictureInPictureWindow", + "ping", + "pipeThrough", + "pipeTo", + "pitch", + "pixelBottom", + "pixelDepth", + "pixelHeight", + "pixelLeft", + "pixelRight", + "pixelStorei", + "pixelTop", + "pixelUnitToMillimeterX", + "pixelUnitToMillimeterY", + "pixelWidth", + "place-content", + "place-items", + "place-self", + "placeContent", + "placeItems", + "placeSelf", + "placeholder", + "platform", + "platforms", + "play", + "playEffect", + "playState", + "playbackRate", + "playbackState", + "playbackTime", + "played", + "playoutDelayHint", + "playsInline", + "plugins", + "pluginspage", + "pname", + "pointer-events", + "pointerBeforeReferenceNode", + "pointerEnabled", + "pointerEvents", + "pointerId", + "pointerLockElement", + "pointerType", + "points", + "pointsAtX", + "pointsAtY", + "pointsAtZ", + "polygonOffset", + "pop", + "populateMatrix", + "popupWindowFeatures", + "popupWindowName", + "popupWindowURI", + "port", + "port1", + "port2", + "ports", + "posBottom", + "posHeight", + "posLeft", + "posRight", + "posTop", + "posWidth", + "pose", + "position", + "positionAlign", + "positionX", + "positionY", + "positionZ", + "postError", + "postMessage", + "postalCode", + "poster", + "pow", + "powerEfficient", + "powerOff", + "preMultiplySelf", + "precision", + "preferredStyleSheetSet", + "preferredStylesheetSet", + "prefix", + "preload", + "prepend", + "presentation", + "preserveAlpha", + "preserveAspectRatio", + "preserveAspectRatioString", + "pressed", + "pressure", + "prevValue", + "preventDefault", + "preventExtensions", + "preventSilentAccess", + "previousElementSibling", + "previousNode", + "previousPage", + "previousRect", + "previousScale", + "previousSibling", + "previousTranslate", + "primaryKey", + "primitiveType", + "primitiveUnits", + "principals", + "print", + "priority", + "privateKey", + "probablySupportsContext", + "process", + "processIceMessage", + "processingEnd", + "processingStart", + "product", + "productId", + "productName", + "productSub", + "profile", + "profileEnd", + "profiles", + "projectionMatrix", + "promise", + "prompt", + "properties", + "propertyIsEnumerable", + "propertyName", + "protocol", + "protocolLong", + "prototype", + "provider", + "pseudoClass", + "pseudoElement", + "pt", + "publicId", + "publicKey", + "published", + "pulse", + "push", + "pushManager", + "pushNotification", + "pushState", + "put", + "putImageData", + "px", + "quadraticCurveTo", + "qualifier", + "quaternion", + "query", + "queryCommandEnabled", + "queryCommandIndeterm", + "queryCommandState", + "queryCommandSupported", + "queryCommandText", + "queryCommandValue", + "querySelector", + "querySelectorAll", + "queueMicrotask", + "quote", + "quotes", + "r", + "r1", + "r2", + "race", + "rad", + "radiogroup", + "radiusX", + "radiusY", + "random", + "range", + "rangeCount", + "rangeMax", + "rangeMin", + "rangeOffset", + "rangeOverflow", + "rangeParent", + "rangeUnderflow", + "rate", + "ratio", + "raw", + "rawId", + "read", + "readAsArrayBuffer", + "readAsBinaryString", + "readAsBlob", + "readAsDataURL", + "readAsText", + "readBuffer", + "readEntries", + "readOnly", + "readPixels", + "readReportRequested", + "readText", + "readValue", + "readable", + "ready", + "readyState", + "reason", + "reboot", + "receivedAlert", + "receiver", + "receivers", + "recipient", + "reconnect", + "recordNumber", + "recordsAvailable", + "recordset", + "rect", + "red", + "redEyeReduction", + "redirect", + "redirectCount", + "redirectEnd", + "redirectStart", + "redirected", + "reduce", + "reduceRight", + "reduction", + "refDistance", + "refX", + "refY", + "referenceNode", + "referenceSpace", + "referrer", + "referrerPolicy", + "refresh", + "region", + "regionAnchorX", + "regionAnchorY", + "regionId", + "regions", + "register", + "registerContentHandler", + "registerElement", + "registerProperty", + "registerProtocolHandler", + "reject", + "rel", + "relList", + "relatedAddress", + "relatedNode", + "relatedPort", + "relatedTarget", + "release", + "releaseCapture", + "releaseEvents", + "releaseInterface", + "releaseLock", + "releasePointerCapture", + "releaseShaderCompiler", + "reliable", + "reliableWrite", + "reload", + "rem", + "remainingSpace", + "remote", + "remoteDescription", + "remove", + "removeAllRanges", + "removeAttribute", + "removeAttributeNS", + "removeAttributeNode", + "removeBehavior", + "removeChild", + "removeCue", + "removeEventListener", + "removeFilter", + "removeImport", + "removeItem", + "removeListener", + "removeNamedItem", + "removeNamedItemNS", + "removeNode", + "removeParameter", + "removeProperty", + "removeRange", + "removeRegion", + "removeRule", + "removeSiteSpecificTrackingException", + "removeSourceBuffer", + "removeStream", + "removeTrack", + "removeVariable", + "removeWakeLockListener", + "removeWebWideTrackingException", + "removed", + "removedNodes", + "renderHeight", + "renderState", + "renderTime", + "renderWidth", + "renderbufferStorage", + "renderbufferStorageMultisample", + "renderedBuffer", + "renderingMode", + "renotify", + "repeat", + "replace", + "replaceAdjacentText", + "replaceAll", + "replaceChild", + "replaceChildren", + "replaceData", + "replaceId", + "replaceItem", + "replaceNode", + "replaceState", + "replaceSync", + "replaceTrack", + "replaceWholeText", + "replaceWith", + "reportValidity", + "request", + "requestAnimationFrame", + "requestAutocomplete", + "requestData", + "requestDevice", + "requestFrame", + "requestFullscreen", + "requestHitTestSource", + "requestHitTestSourceForTransientInput", + "requestId", + "requestIdleCallback", + "requestMIDIAccess", + "requestMediaKeySystemAccess", + "requestPermission", + "requestPictureInPicture", + "requestPointerLock", + "requestPresent", + "requestReferenceSpace", + "requestSession", + "requestStart", + "requestStorageAccess", + "requestSubmit", + "requestVideoFrameCallback", + "requestingWindow", + "requireInteraction", + "required", + "requiredExtensions", + "requiredFeatures", + "reset", + "resetPose", + "resetTransform", + "resize", + "resizeBy", + "resizeTo", + "resolve", + "response", + "responseBody", + "responseEnd", + "responseReady", + "responseStart", + "responseText", + "responseType", + "responseURL", + "responseXML", + "restartIce", + "restore", + "result", + "resultIndex", + "resultType", + "results", + "resume", + "resumeProfilers", + "resumeTransformFeedback", + "retry", + "return", + "returnValue", + "rev", + "reverse", + "reversed", + "revocable", + "revokeObjectURL", + "rgbColor", + "right", + "rightContext", + "rightDegrees", + "rightMargin", + "rightProjectionMatrix", + "rightViewMatrix", + "role", + "rolloffFactor", + "root", + "rootBounds", + "rootElement", + "rootMargin", + "rotate", + "rotateAxisAngle", + "rotateAxisAngleSelf", + "rotateFromVector", + "rotateFromVectorSelf", + "rotateSelf", + "rotation", + "rotationAngle", + "rotationRate", + "round", + "row-gap", + "rowGap", + "rowIndex", + "rowSpan", + "rows", + "rtcpTransport", + "rtt", + "ruby-align", + "ruby-position", + "rubyAlign", + "rubyOverhang", + "rubyPosition", + "rules", + "runtime", + "runtimeStyle", + "rx", + "ry", + "s", + "safari", + "sample", + "sampleCoverage", + "sampleRate", + "samplerParameterf", + "samplerParameteri", + "sandbox", + "save", + "saveData", + "scale", + "scale3d", + "scale3dSelf", + "scaleNonUniform", + "scaleNonUniformSelf", + "scaleSelf", + "scheme", + "scissor", + "scope", + "scopeName", + "scoped", + "screen", + "screenBrightness", + "screenEnabled", + "screenLeft", + "screenPixelToMillimeterX", + "screenPixelToMillimeterY", + "screenTop", + "screenX", + "screenY", + "scriptURL", + "scripts", + "scroll", + "scroll-behavior", + "scroll-margin", + "scroll-margin-block", + "scroll-margin-block-end", + "scroll-margin-block-start", + "scroll-margin-bottom", + "scroll-margin-inline", + "scroll-margin-inline-end", + "scroll-margin-inline-start", + "scroll-margin-left", + "scroll-margin-right", + "scroll-margin-top", + "scroll-padding", + "scroll-padding-block", + "scroll-padding-block-end", + "scroll-padding-block-start", + "scroll-padding-bottom", + "scroll-padding-inline", + "scroll-padding-inline-end", + "scroll-padding-inline-start", + "scroll-padding-left", + "scroll-padding-right", + "scroll-padding-top", + "scroll-snap-align", + "scroll-snap-type", + "scrollAmount", + "scrollBehavior", + "scrollBy", + "scrollByLines", + "scrollByPages", + "scrollDelay", + "scrollHeight", + "scrollIntoView", + "scrollIntoViewIfNeeded", + "scrollLeft", + "scrollLeftMax", + "scrollMargin", + "scrollMarginBlock", + "scrollMarginBlockEnd", + "scrollMarginBlockStart", + "scrollMarginBottom", + "scrollMarginInline", + "scrollMarginInlineEnd", + "scrollMarginInlineStart", + "scrollMarginLeft", + "scrollMarginRight", + "scrollMarginTop", + "scrollMaxX", + "scrollMaxY", + "scrollPadding", + "scrollPaddingBlock", + "scrollPaddingBlockEnd", + "scrollPaddingBlockStart", + "scrollPaddingBottom", + "scrollPaddingInline", + "scrollPaddingInlineEnd", + "scrollPaddingInlineStart", + "scrollPaddingLeft", + "scrollPaddingRight", + "scrollPaddingTop", + "scrollRestoration", + "scrollSnapAlign", + "scrollSnapType", + "scrollTo", + "scrollTop", + "scrollTopMax", + "scrollWidth", + "scrollX", + "scrollY", + "scrollbar-color", + "scrollbar-width", + "scrollbar3dLightColor", + "scrollbarArrowColor", + "scrollbarBaseColor", + "scrollbarColor", + "scrollbarDarkShadowColor", + "scrollbarFaceColor", + "scrollbarHighlightColor", + "scrollbarShadowColor", + "scrollbarTrackColor", + "scrollbarWidth", + "scrollbars", + "scrolling", + "scrollingElement", + "sctp", + "sctpCauseCode", + "sdp", + "sdpLineNumber", + "sdpMLineIndex", + "sdpMid", + "seal", + "search", + "searchBox", + "searchBoxJavaBridge_", + "searchParams", + "sectionRowIndex", + "secureConnectionStart", + "security", + "seed", + "seekToNextFrame", + "seekable", + "seeking", + "select", + "selectAllChildren", + "selectAlternateInterface", + "selectConfiguration", + "selectNode", + "selectNodeContents", + "selectNodes", + "selectSingleNode", + "selectSubString", + "selected", + "selectedIndex", + "selectedOptions", + "selectedStyleSheetSet", + "selectedStylesheetSet", + "selection", + "selectionDirection", + "selectionEnd", + "selectionStart", + "selector", + "selectorText", + "self", + "send", + "sendAsBinary", + "sendBeacon", + "sender", + "sentAlert", + "sentTimestamp", + "separator", + "serialNumber", + "serializeToString", + "serverTiming", + "service", + "serviceWorker", + "session", + "sessionId", + "sessionStorage", + "set", + "setActionHandler", + "setActive", + "setAlpha", + "setAppBadge", + "setAttribute", + "setAttributeNS", + "setAttributeNode", + "setAttributeNodeNS", + "setBaseAndExtent", + "setBigInt64", + "setBigUint64", + "setBingCurrentSearchDefault", + "setCapture", + "setCodecPreferences", + "setColor", + "setCompositeOperation", + "setConfiguration", + "setCurrentTime", + "setCustomValidity", + "setData", + "setDate", + "setDragImage", + "setEnd", + "setEndAfter", + "setEndBefore", + "setEndPoint", + "setFillColor", + "setFilterRes", + "setFloat32", + "setFloat64", + "setFloatValue", + "setFormValue", + "setFullYear", + "setHeaderValue", + "setHours", + "setIdentityProvider", + "setImmediate", + "setInt16", + "setInt32", + "setInt8", + "setInterval", + "setItem", + "setKeyframes", + "setLineCap", + "setLineDash", + "setLineJoin", + "setLineWidth", + "setLiveSeekableRange", + "setLocalDescription", + "setMatrix", + "setMatrixValue", + "setMediaKeys", + "setMilliseconds", + "setMinutes", + "setMiterLimit", + "setMonth", + "setNamedItem", + "setNamedItemNS", + "setNonUserCodeExceptions", + "setOrientToAngle", + "setOrientToAuto", + "setOrientation", + "setOverrideHistoryNavigationMode", + "setPaint", + "setParameter", + "setParameters", + "setPeriodicWave", + "setPointerCapture", + "setPosition", + "setPositionState", + "setPreference", + "setProperty", + "setPrototypeOf", + "setRGBColor", + "setRGBColorICCColor", + "setRadius", + "setRangeText", + "setRemoteDescription", + "setRequestHeader", + "setResizable", + "setResourceTimingBufferSize", + "setRotate", + "setScale", + "setSeconds", + "setSelectionRange", + "setServerCertificate", + "setShadow", + "setSinkId", + "setSkewX", + "setSkewY", + "setStart", + "setStartAfter", + "setStartBefore", + "setStdDeviation", + "setStreams", + "setStringValue", + "setStrokeColor", + "setSuggestResult", + "setTargetAtTime", + "setTargetValueAtTime", + "setTime", + "setTimeout", + "setTransform", + "setTranslate", + "setUTCDate", + "setUTCFullYear", + "setUTCHours", + "setUTCMilliseconds", + "setUTCMinutes", + "setUTCMonth", + "setUTCSeconds", + "setUint16", + "setUint32", + "setUint8", + "setUri", + "setValidity", + "setValueAtTime", + "setValueCurveAtTime", + "setVariable", + "setVelocity", + "setVersion", + "setYear", + "settingName", + "settingValue", + "sex", + "shaderSource", + "shadowBlur", + "shadowColor", + "shadowOffsetX", + "shadowOffsetY", + "shadowRoot", + "shape", + "shape-image-threshold", + "shape-margin", + "shape-outside", + "shape-rendering", + "shapeImageThreshold", + "shapeMargin", + "shapeOutside", + "shapeRendering", + "sheet", + "shift", + "shiftKey", + "shiftLeft", + "shippingAddress", + "shippingOption", + "shippingType", + "show", + "showHelp", + "showModal", + "showModalDialog", + "showModelessDialog", + "showNotification", + "sidebar", + "sign", + "signal", + "signalingState", + "signature", + "silent", + "sin", + "singleNodeValue", + "sinh", + "sinkId", + "sittingToStandingTransform", + "size", + "sizeToContent", + "sizeX", + "sizeZ", + "sizes", + "skewX", + "skewXSelf", + "skewY", + "skewYSelf", + "slice", + "slope", + "slot", + "small", + "smil", + "smooth", + "smoothingTimeConstant", + "snapToLines", + "snapshotItem", + "snapshotLength", + "some", + "sort", + "sortingCode", + "source", + "sourceBuffer", + "sourceBuffers", + "sourceCapabilities", + "sourceFile", + "sourceIndex", + "sources", + "spacing", + "span", + "speak", + "speakAs", + "speaking", + "species", + "specified", + "specularConstant", + "specularExponent", + "speechSynthesis", + "speed", + "speedOfSound", + "spellcheck", + "splice", + "split", + "splitText", + "spreadMethod", + "sqrt", + "src", + "srcElement", + "srcFilter", + "srcObject", + "srcUrn", + "srcdoc", + "srclang", + "srcset", + "stack", + "stackTraceLimit", + "stacktrace", + "stageParameters", + "standalone", + "standby", + "start", + "startContainer", + "startIce", + "startMessages", + "startNotifications", + "startOffset", + "startProfiling", + "startRendering", + "startShark", + "startTime", + "startsWith", + "state", + "status", + "statusCode", + "statusMessage", + "statusText", + "statusbar", + "stdDeviationX", + "stdDeviationY", + "stencilFunc", + "stencilFuncSeparate", + "stencilMask", + "stencilMaskSeparate", + "stencilOp", + "stencilOpSeparate", + "step", + "stepDown", + "stepMismatch", + "stepUp", + "sticky", + "stitchTiles", + "stop", + "stop-color", + "stop-opacity", + "stopColor", + "stopImmediatePropagation", + "stopNotifications", + "stopOpacity", + "stopProfiling", + "stopPropagation", + "stopShark", + "stopped", + "storage", + "storageArea", + "storageName", + "storageStatus", + "store", + "storeSiteSpecificTrackingException", + "storeWebWideTrackingException", + "stpVersion", + "stream", + "streams", + "stretch", + "strike", + "string", + "stringValue", + "stringify", + "stroke", + "stroke-dasharray", + "stroke-dashoffset", + "stroke-linecap", + "stroke-linejoin", + "stroke-miterlimit", + "stroke-opacity", + "stroke-width", + "strokeDasharray", + "strokeDashoffset", + "strokeLinecap", + "strokeLinejoin", + "strokeMiterlimit", + "strokeOpacity", + "strokeRect", + "strokeStyle", + "strokeText", + "strokeWidth", + "style", + "styleFloat", + "styleMap", + "styleMedia", + "styleSheet", + "styleSheetSets", + "styleSheets", + "sub", + "subarray", + "subject", + "submit", + "submitFrame", + "submitter", + "subscribe", + "substr", + "substring", + "substringData", + "subtle", + "subtree", + "suffix", + "suffixes", + "summary", + "sup", + "supported", + "supportedContentEncodings", + "supportedEntryTypes", + "supports", + "supportsSession", + "surfaceScale", + "surroundContents", + "suspend", + "suspendRedraw", + "swapCache", + "swapNode", + "sweepFlag", + "symbols", + "sync", + "sysexEnabled", + "system", + "systemCode", + "systemId", + "systemLanguage", + "systemXDPI", + "systemYDPI", + "tBodies", + "tFoot", + "tHead", + "tabIndex", + "table", + "table-layout", + "tableLayout", + "tableValues", + "tag", + "tagName", + "tagUrn", + "tags", + "taintEnabled", + "takePhoto", + "takeRecords", + "tan", + "tangentialPressure", + "tanh", + "target", + "targetElement", + "targetRayMode", + "targetRaySpace", + "targetTouches", + "targetX", + "targetY", + "tcpType", + "tee", + "tel", + "terminate", + "test", + "texImage2D", + "texImage3D", + "texParameterf", + "texParameteri", + "texStorage2D", + "texStorage3D", + "texSubImage2D", + "texSubImage3D", + "text", + "text-align", + "text-align-last", + "text-anchor", + "text-combine-upright", + "text-decoration", + "text-decoration-color", + "text-decoration-line", + "text-decoration-skip-ink", + "text-decoration-style", + "text-decoration-thickness", + "text-emphasis", + "text-emphasis-color", + "text-emphasis-position", + "text-emphasis-style", + "text-indent", + "text-justify", + "text-orientation", + "text-overflow", + "text-rendering", + "text-shadow", + "text-transform", + "text-underline-offset", + "text-underline-position", + "textAlign", + "textAlignLast", + "textAnchor", + "textAutospace", + "textBaseline", + "textCombineUpright", + "textContent", + "textDecoration", + "textDecorationBlink", + "textDecorationColor", + "textDecorationLine", + "textDecorationLineThrough", + "textDecorationNone", + "textDecorationOverline", + "textDecorationSkipInk", + "textDecorationStyle", + "textDecorationThickness", + "textDecorationUnderline", + "textEmphasis", + "textEmphasisColor", + "textEmphasisPosition", + "textEmphasisStyle", + "textIndent", + "textJustify", + "textJustifyTrim", + "textKashida", + "textKashidaSpace", + "textLength", + "textOrientation", + "textOverflow", + "textRendering", + "textShadow", + "textTracks", + "textTransform", + "textUnderlineOffset", + "textUnderlinePosition", + "then", + "threadId", + "threshold", + "thresholds", + "throw", + "tiltX", + "tiltY", + "time", + "timeEnd", + "timeLog", + "timeOrigin", + "timeRemaining", + "timeStamp", + "timecode", + "timeline", + "timelineTime", + "timeout", + "timestamp", + "timestampOffset", + "timing", + "title", + "to", + "toArray", + "toBlob", + "toDataURL", + "toDateString", + "toElement", + "toExponential", + "toFixed", + "toFloat32Array", + "toFloat64Array", + "toGMTString", + "toISOString", + "toJSON", + "toLocaleDateString", + "toLocaleFormat", + "toLocaleLowerCase", + "toLocaleString", + "toLocaleTimeString", + "toLocaleUpperCase", + "toLowerCase", + "toMatrix", + "toMethod", + "toPrecision", + "toPrimitive", + "toSdp", + "toSource", + "toStaticHTML", + "toString", + "toStringTag", + "toSum", + "toTimeString", + "toUTCString", + "toUpperCase", + "toggle", + "toggleAttribute", + "toggleLongPressEnabled", + "tone", + "toneBuffer", + "tooLong", + "tooShort", + "toolbar", + "top", + "topMargin", + "total", + "totalFrameDelay", + "totalVideoFrames", + "touch-action", + "touchAction", + "touched", + "touches", + "trace", + "track", + "trackVisibility", + "transaction", + "transactions", + "transceiver", + "transferControlToOffscreen", + "transferFromImageBitmap", + "transferImageBitmap", + "transferIn", + "transferOut", + "transferSize", + "transferToImageBitmap", + "transform", + "transform-box", + "transform-origin", + "transform-style", + "transformBox", + "transformFeedbackVaryings", + "transformOrigin", + "transformPoint", + "transformString", + "transformStyle", + "transformToDocument", + "transformToFragment", + "transition", + "transition-delay", + "transition-duration", + "transition-property", + "transition-timing-function", + "transitionDelay", + "transitionDuration", + "transitionProperty", + "transitionTimingFunction", + "translate", + "translateSelf", + "translationX", + "translationY", + "transport", + "trim", + "trimEnd", + "trimLeft", + "trimRight", + "trimStart", + "trueSpeed", + "trunc", + "truncate", + "trustedTypes", + "turn", + "twist", + "type", + "typeDetail", + "typeMismatch", + "typeMustMatch", + "types", + "u2f", + "ubound", + "uint16", + "uint32", + "uint8", + "uint8Clamped", + "undefined", + "unescape", + "uneval", + "unicode", + "unicode-bidi", + "unicodeBidi", + "unicodeRange", + "uniform1f", + "uniform1fv", + "uniform1i", + "uniform1iv", + "uniform1ui", + "uniform1uiv", + "uniform2f", + "uniform2fv", + "uniform2i", + "uniform2iv", + "uniform2ui", + "uniform2uiv", + "uniform3f", + "uniform3fv", + "uniform3i", + "uniform3iv", + "uniform3ui", + "uniform3uiv", + "uniform4f", + "uniform4fv", + "uniform4i", + "uniform4iv", + "uniform4ui", + "uniform4uiv", + "uniformBlockBinding", + "uniformMatrix2fv", + "uniformMatrix2x3fv", + "uniformMatrix2x4fv", + "uniformMatrix3fv", + "uniformMatrix3x2fv", + "uniformMatrix3x4fv", + "uniformMatrix4fv", + "uniformMatrix4x2fv", + "uniformMatrix4x3fv", + "unique", + "uniqueID", + "uniqueNumber", + "unit", + "unitType", + "units", + "unloadEventEnd", + "unloadEventStart", + "unlock", + "unmount", + "unobserve", + "unpause", + "unpauseAnimations", + "unreadCount", + "unregister", + "unregisterContentHandler", + "unregisterProtocolHandler", + "unscopables", + "unselectable", + "unshift", + "unsubscribe", + "unsuspendRedraw", + "unsuspendRedrawAll", + "unwatch", + "unwrapKey", + "upDegrees", + "upX", + "upY", + "upZ", + "update", + "updateCommands", + "updateIce", + "updateInterval", + "updatePlaybackRate", + "updateRenderState", + "updateSettings", + "updateTiming", + "updateViaCache", + "updateWith", + "updated", + "updating", + "upgrade", + "upload", + "uploadTotal", + "uploaded", + "upper", + "upperBound", + "upperOpen", + "uri", + "url", + "urn", + "urns", + "usages", + "usb", + "usbVersionMajor", + "usbVersionMinor", + "usbVersionSubminor", + "useCurrentView", + "useMap", + "useProgram", + "usedSpace", + "user-select", + "userActivation", + "userAgent", + "userChoice", + "userHandle", + "userHint", + "userLanguage", + "userSelect", + "userVisibleOnly", + "username", + "usernameFragment", + "utterance", + "uuid", + "v8BreakIterator", + "vAlign", + "vLink", + "valid", + "validate", + "validateProgram", + "validationMessage", + "validity", + "value", + "valueAsDate", + "valueAsNumber", + "valueAsString", + "valueInSpecifiedUnits", + "valueMissing", + "valueOf", + "valueText", + "valueType", + "values", + "variable", + "variant", + "variationSettings", + "vector-effect", + "vectorEffect", + "velocityAngular", + "velocityExpansion", + "velocityX", + "velocityY", + "vendor", + "vendorId", + "vendorSub", + "verify", + "version", + "vertexAttrib1f", + "vertexAttrib1fv", + "vertexAttrib2f", + "vertexAttrib2fv", + "vertexAttrib3f", + "vertexAttrib3fv", + "vertexAttrib4f", + "vertexAttrib4fv", + "vertexAttribDivisor", + "vertexAttribDivisorANGLE", + "vertexAttribI4i", + "vertexAttribI4iv", + "vertexAttribI4ui", + "vertexAttribI4uiv", + "vertexAttribIPointer", + "vertexAttribPointer", + "vertical", + "vertical-align", + "verticalAlign", + "verticalOverflow", + "vh", + "vibrate", + "vibrationActuator", + "videoBitsPerSecond", + "videoHeight", + "videoTracks", + "videoWidth", + "view", + "viewBox", + "viewBoxString", + "viewTarget", + "viewTargetString", + "viewport", + "viewportAnchorX", + "viewportAnchorY", + "viewportElement", + "views", + "violatedDirective", + "visibility", + "visibilityState", + "visible", + "visualViewport", + "vlinkColor", + "vmax", + "vmin", + "voice", + "voiceURI", + "volume", + "vrml", + "vspace", + "vw", + "w", + "wait", + "waitSync", + "waiting", + "wake", + "wakeLock", + "wand", + "warn", + "wasClean", + "wasDiscarded", + "watch", + "watchAvailability", + "watchPosition", + "webdriver", + "webkitAddKey", + "webkitAlignContent", + "webkitAlignItems", + "webkitAlignSelf", + "webkitAnimation", + "webkitAnimationDelay", + "webkitAnimationDirection", + "webkitAnimationDuration", + "webkitAnimationFillMode", + "webkitAnimationIterationCount", + "webkitAnimationName", + "webkitAnimationPlayState", + "webkitAnimationTimingFunction", + "webkitAppearance", + "webkitAudioContext", + "webkitAudioDecodedByteCount", + "webkitAudioPannerNode", + "webkitBackfaceVisibility", + "webkitBackground", + "webkitBackgroundAttachment", + "webkitBackgroundClip", + "webkitBackgroundColor", + "webkitBackgroundImage", + "webkitBackgroundOrigin", + "webkitBackgroundPosition", + "webkitBackgroundPositionX", + "webkitBackgroundPositionY", + "webkitBackgroundRepeat", + "webkitBackgroundSize", + "webkitBackingStorePixelRatio", + "webkitBorderBottomLeftRadius", + "webkitBorderBottomRightRadius", + "webkitBorderImage", + "webkitBorderImageOutset", + "webkitBorderImageRepeat", + "webkitBorderImageSlice", + "webkitBorderImageSource", + "webkitBorderImageWidth", + "webkitBorderRadius", + "webkitBorderTopLeftRadius", + "webkitBorderTopRightRadius", + "webkitBoxAlign", + "webkitBoxDirection", + "webkitBoxFlex", + "webkitBoxOrdinalGroup", + "webkitBoxOrient", + "webkitBoxPack", + "webkitBoxShadow", + "webkitBoxSizing", + "webkitCancelAnimationFrame", + "webkitCancelFullScreen", + "webkitCancelKeyRequest", + "webkitCancelRequestAnimationFrame", + "webkitClearResourceTimings", + "webkitClosedCaptionsVisible", + "webkitConvertPointFromNodeToPage", + "webkitConvertPointFromPageToNode", + "webkitCreateShadowRoot", + "webkitCurrentFullScreenElement", + "webkitCurrentPlaybackTargetIsWireless", + "webkitDecodedFrameCount", + "webkitDirectionInvertedFromDevice", + "webkitDisplayingFullscreen", + "webkitDroppedFrameCount", + "webkitEnterFullScreen", + "webkitEnterFullscreen", + "webkitEntries", + "webkitExitFullScreen", + "webkitExitFullscreen", + "webkitExitPointerLock", + "webkitFilter", + "webkitFlex", + "webkitFlexBasis", + "webkitFlexDirection", + "webkitFlexFlow", + "webkitFlexGrow", + "webkitFlexShrink", + "webkitFlexWrap", + "webkitFullScreenKeyboardInputAllowed", + "webkitFullscreenElement", + "webkitFullscreenEnabled", + "webkitGenerateKeyRequest", + "webkitGetAsEntry", + "webkitGetDatabaseNames", + "webkitGetEntries", + "webkitGetEntriesByName", + "webkitGetEntriesByType", + "webkitGetFlowByName", + "webkitGetGamepads", + "webkitGetImageDataHD", + "webkitGetNamedFlows", + "webkitGetRegionFlowRanges", + "webkitGetUserMedia", + "webkitHasClosedCaptions", + "webkitHidden", + "webkitIDBCursor", + "webkitIDBDatabase", + "webkitIDBDatabaseError", + "webkitIDBDatabaseException", + "webkitIDBFactory", + "webkitIDBIndex", + "webkitIDBKeyRange", + "webkitIDBObjectStore", + "webkitIDBRequest", + "webkitIDBTransaction", + "webkitImageSmoothingEnabled", + "webkitIndexedDB", + "webkitInitMessageEvent", + "webkitIsFullScreen", + "webkitJustifyContent", + "webkitKeys", + "webkitLineClamp", + "webkitLineDashOffset", + "webkitLockOrientation", + "webkitMask", + "webkitMaskClip", + "webkitMaskComposite", + "webkitMaskImage", + "webkitMaskOrigin", + "webkitMaskPosition", + "webkitMaskPositionX", + "webkitMaskPositionY", + "webkitMaskRepeat", + "webkitMaskSize", + "webkitMatchesSelector", + "webkitMediaStream", + "webkitNotifications", + "webkitOfflineAudioContext", + "webkitOrder", + "webkitOrientation", + "webkitPeerConnection00", + "webkitPersistentStorage", + "webkitPerspective", + "webkitPerspectiveOrigin", + "webkitPointerLockElement", + "webkitPostMessage", + "webkitPreservesPitch", + "webkitPutImageDataHD", + "webkitRTCPeerConnection", + "webkitRegionOverset", + "webkitRelativePath", + "webkitRequestAnimationFrame", + "webkitRequestFileSystem", + "webkitRequestFullScreen", + "webkitRequestFullscreen", + "webkitRequestPointerLock", + "webkitResolveLocalFileSystemURL", + "webkitSetMediaKeys", + "webkitSetResourceTimingBufferSize", + "webkitShadowRoot", + "webkitShowPlaybackTargetPicker", + "webkitSlice", + "webkitSpeechGrammar", + "webkitSpeechGrammarList", + "webkitSpeechRecognition", + "webkitSpeechRecognitionError", + "webkitSpeechRecognitionEvent", + "webkitStorageInfo", + "webkitSupportsFullscreen", + "webkitTemporaryStorage", + "webkitTextFillColor", + "webkitTextSizeAdjust", + "webkitTextStroke", + "webkitTextStrokeColor", + "webkitTextStrokeWidth", + "webkitTransform", + "webkitTransformOrigin", + "webkitTransformStyle", + "webkitTransition", + "webkitTransitionDelay", + "webkitTransitionDuration", + "webkitTransitionProperty", + "webkitTransitionTimingFunction", + "webkitURL", + "webkitUnlockOrientation", + "webkitUserSelect", + "webkitVideoDecodedByteCount", + "webkitVisibilityState", + "webkitWirelessVideoPlaybackDisabled", + "webkitdirectory", + "webkitdropzone", + "webstore", + "weight", + "whatToShow", + "wheelDelta", + "wheelDeltaX", + "wheelDeltaY", + "whenDefined", + "which", + "white-space", + "whiteSpace", + "wholeText", + "widows", + "width", + "will-change", + "willChange", + "willValidate", + "window", + "withCredentials", + "word-break", + "word-spacing", + "word-wrap", + "wordBreak", + "wordSpacing", + "wordWrap", + "workerStart", + "wrap", + "wrapKey", + "writable", + "writableAuxiliaries", + "write", + "writeText", + "writeValue", + "writeWithoutResponse", + "writeln", + "writing-mode", + "writingMode", + "x", + "x1", + "x2", + "xChannelSelector", + "xmlEncoding", + "xmlStandalone", + "xmlVersion", + "xmlbase", + "xmllang", + "xmlspace", + "xor", + "xr", + "y", + "y1", + "y2", + "yChannelSelector", + "yandex", + "z", + "z-index", + "zIndex", + "zoom", + "zoomAndPan", + "zoomRectScreen", + "PropertyKey", + "PropertyDescriptor", + "configurable", + "enumerable", + "PropertyDescriptorMap", + "ObjectConstructor", + "FunctionConstructor", + "ThisParameterType", + "OmitThisParameter", + "CallableFunction", + "NewableFunction", + "IArguments", + "callee", + "StringConstructor", + "BooleanConstructor", + "NumberConstructor", + "TemplateStringsArray", + "ImportMeta", + "DateConstructor", + "RegExpMatchArray", + "RegExpExecArray", + "RegExpConstructor", + "ErrorConstructor", + "EvalErrorConstructor", + "RangeErrorConstructor", + "ReferenceErrorConstructor", + "SyntaxErrorConstructor", + "TypeErrorConstructor", + "URIErrorConstructor", + "ReadonlyArray", + "ConcatArray", + "ArrayConstructor", + "TypedPropertyDescriptor", + "ClassDecorator", + "PropertyDecorator", + "MethodDecorator", + "ParameterDecorator", + "PromiseConstructorLike", + "PromiseLike", + "ArrayLike", + "Partial", + "Required", + "Readonly", + "Pick", + "Record", + "Exclude", + "Extract", + "Omit", + "NonNullable", + "Parameters", + "ConstructorParameters", + "ReturnType", + "InstanceType", + "Uppercase", + "Lowercase", + "Capitalize", + "Uncapitalize", + "ThisType", + "ArrayBufferTypes", + "ArrayBufferLike", + "ArrayBufferConstructor", + "ArrayBufferView", + "DataViewConstructor", + "Int8ArrayConstructor", + "Uint8ArrayConstructor", + "Uint8ClampedArrayConstructor", + "Int16ArrayConstructor", + "Uint16ArrayConstructor", + "Int32ArrayConstructor", + "Uint32ArrayConstructor", + "Float32ArrayConstructor", + "Float64ArrayConstructor", + "CollatorOptions", + "usage", + "localeMatcher", + "numeric", + "caseFirst", + "sensitivity", + "ignorePunctuation", + "ResolvedCollatorOptions", + "collation", + "compare", + "resolvedOptions", + "supportedLocalesOf", + "NumberFormatOptions", + "currency", + "currencyDisplay", + "currencySign", + "useGrouping", + "minimumIntegerDigits", + "minimumFractionDigits", + "maximumFractionDigits", + "minimumSignificantDigits", + "maximumSignificantDigits", + "ResolvedNumberFormatOptions", + "numberingSystem", + "DateTimeFormatOptions", + "weekday", + "era", + "year", + "month", + "day", + "hour", + "minute", + "second", + "timeZoneName", + "formatMatcher", + "hour12", + "timeZone", + "ResolvedDateTimeFormatOptions", + "calendar" +] \ No newline at end of file diff --git a/arkguard/src/generator/DictionaryNameGenerator.ts b/arkguard/src/generator/DictionaryNameGenerator.ts new file mode 100644 index 0000000000000000000000000000000000000000..70eb3d9a5cbdb607e22cf606c799916c4e416151 --- /dev/null +++ b/arkguard/src/generator/DictionaryNameGenerator.ts @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type {INameGenerator, NameGeneratorOptions} from './INameGenerator'; + +/** + * @Desc: a name generator which use given identifiers to get incremental obfuscated name + */ +export class DictionaryNameGenerator implements INameGenerator { + private readonly mDictionaryList: string[]; + private readonly mReservedNames: Set; + + private mDictIndex: number; + private mTransformNumber: number; + + /** + * + * @param options: {dictionaryList: list} + */ + constructor(options?: NameGeneratorOptions) { + this.mDictionaryList = (options && options.dictionaryList) ? options.dictionaryList : ['hello', 'world', 'dictionary', 'light', 'thunder', 'storm']; + this.mReservedNames = options?.reservedNames; + + this.mDictIndex = 0; + this.mTransformNumber = 0; + } + + /** + * @return: null for end + */ + public getName(): string { + if (this.mDictIndex >= this.mDictionaryList.length) { + return null; + } + + let originIdentifier: string[] = Array.from(this.mDictionaryList[this.mDictIndex].toLowerCase()); + const BINARY_RADIX: number = 2; + let binary: string = this.mTransformNumber.toString(BINARY_RADIX).split('').reverse().join(''); + let countTrue: number = 0; + for (let i = 0; i < binary.length; i++) { + if (binary[i] === '1') { + originIdentifier[i] = originIdentifier[i].toUpperCase(); + countTrue += 1; + } + } + + this.mTransformNumber += 1; + if (countTrue >= originIdentifier.length) { + this.mDictIndex += 1; + this.mTransformNumber = 0; + } + + if (this.mReservedNames?.has(originIdentifier.join(''))) { + return this.getName(); + } + + return originIdentifier.join(''); + } + + public reset(): void { + this.mDictIndex = 0; + this.mTransformNumber = 0; + } +} diff --git a/arkguard/src/generator/DisorderNameGenerator.ts b/arkguard/src/generator/DisorderNameGenerator.ts new file mode 100644 index 0000000000000000000000000000000000000000..30ed891021b54c75fb0491cd3fa198c7b23fa908 --- /dev/null +++ b/arkguard/src/generator/DisorderNameGenerator.ts @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type {INameGenerator, NameGeneratorOptions} from './INameGenerator'; +import {ListUtil} from '../utils/ListUtil'; + +/** + * @Desc: simple disordered name generator + * e.g.: c, b, z, a, ..., d1, a1, z1, ... + */ +export class DisorderNameGenerator implements INameGenerator { + private mCharIndex: number; + private mLoopNumber: number; + private mReservedNames: Set; + + private readonly CHAR_COUNT: number = 26; + private readonly CHAR_CODE_A: number = 97; + + private readonly mCharIndexList: number[]; + + constructor(options?: NameGeneratorOptions) { + this.mCharIndex = 0; + this.mLoopNumber = 0; + this.mReservedNames = options?.reservedNames; + + this.mCharIndexList = ListUtil.getInitList(this.CHAR_COUNT); + ListUtil.shuffle(this.mCharIndexList); + } + + private updateElements(): void { + this.mCharIndex = (this.mCharIndex + 1) % this.CHAR_COUNT; + + if (this.mCharIndex === 0) { + this.mLoopNumber += 1; + ListUtil.shuffle(this.mCharIndexList); + } + } + + public getName(): string { + let generatedName: string = String.fromCharCode(this.CHAR_CODE_A + this.mCharIndexList[this.mCharIndex]); + if (this.mLoopNumber > 0) { + generatedName += this.mLoopNumber; + } + + // update elements after generate name + this.updateElements(); + if (this.mReservedNames?.has(generatedName)) { + return this.getName(); + } + + return generatedName; + } + + public reset(): void { + this.mCharIndex = 0; + this.mLoopNumber = 0; + ListUtil.shuffle(this.mCharIndexList); + } +} diff --git a/arkguard/src/generator/HexNameGenerator.ts b/arkguard/src/generator/HexNameGenerator.ts new file mode 100644 index 0000000000000000000000000000000000000000..3c808e0d6b8e90883ad874f62cd5597ad395b8d4 --- /dev/null +++ b/arkguard/src/generator/HexNameGenerator.ts @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {randomBytes} from 'crypto'; + +import type {INameGenerator, NameGeneratorOptions} from './INameGenerator'; + +/** + * @Desc: a name generator which used given length to generate random length-limiting name + */ +export class HexNameGenerator implements INameGenerator { + private readonly mHexLength: number; + private readonly mReservedNames: Set; + private readonly mWithPrefixSuffix: boolean; + + private readonly mHexPrefix: string; + private readonly mHexSuffix: string; + + private mHistoryNameList: string[]; + + /** + * constructor for hex name generator + * @param options: {hexLength: number} + */ + constructor(options?: NameGeneratorOptions) { + this.mHexLength = 4; + if (options && options.hexLength) { + this.mHexLength = options.hexLength; + } + + this.mWithPrefixSuffix = options && options.hexWithPrefixSuffix; + this.mReservedNames = options?.reservedNames; + + this.mHexPrefix = '_0x'; + this.mHexSuffix = '_'; + + this.mHistoryNameList = []; + } + + private generateName(): string { + let buffer: Buffer = randomBytes(this.mHexLength); + let generatedName: string = buffer.toString('hex'); + if (this.mWithPrefixSuffix) { + return this.mHexPrefix + generatedName + this.mHexSuffix; + } + + return generatedName; + } + + /** + * @return: null for end + */ + public getName(): string { + while (true) { + let generatedName: string = this.generateName(); + if (!this.mHistoryNameList.includes(generatedName) && !this.mReservedNames?.has(generatedName)) { + this.mHistoryNameList.push(generatedName); + return generatedName; + } + const baseHex: number = 16; + if (this.mHistoryNameList.length >= Math.pow(baseHex, this.mHexLength)) { + return null; + } + } + } + + public reset(): void { + this.mHistoryNameList.length = 0; + } +} diff --git a/arkguard/src/generator/INameGenerator.ts b/arkguard/src/generator/INameGenerator.ts new file mode 100644 index 0000000000000000000000000000000000000000..ec15117d51ed7c66ab86ff0324e50b32aa05dd39 --- /dev/null +++ b/arkguard/src/generator/INameGenerator.ts @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface NameGeneratorOptions { + // common + reservedNames?: Set; + + // hex name generator + hexLength?: number; + hexWithPrefixSuffix?: boolean; + + // dictionary name generator + dictionaryList?: string[]; + + // underline name generator + underlineMaxLength?: number; +} + +/** + * @desc interface for name generator, use factory model + */ +export interface INameGenerator { + /** + * @desc get name from generator. + * @return unique name generated + */ + getName(): string; + + /** + * @desc reset name generator + */ + reset(): void; +} diff --git a/arkguard/src/generator/NameFactory.ts b/arkguard/src/generator/NameFactory.ts new file mode 100644 index 0000000000000000000000000000000000000000..ee5354a7a116ab17c71f41afe07ac940478183fc --- /dev/null +++ b/arkguard/src/generator/NameFactory.ts @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type {INameGenerator, NameGeneratorOptions} from './INameGenerator'; +import {OrderedNameGenerator} from './OrderedNameGenerator'; +import {DisorderNameGenerator} from './DisorderNameGenerator'; +import {HexNameGenerator} from './HexNameGenerator'; +import {DictionaryNameGenerator} from './DictionaryNameGenerator'; +import {ReservedNameGenerator} from './ReservedNameGenerator'; +import {UnderlineNameGenerator} from './UnderlineNameGenerator'; + +export enum NameGeneratorType { + ORDERED = 1, + DISORDERED = 2, + HEX = 3, + DICTIONARY = 4, + RESERVED_NAME = 5, + UNDERLINE = 6, +} + +export function getNameGenerator(generatorType: NameGeneratorType, options?: NameGeneratorOptions): INameGenerator { + // 10 branch is max in switch + switch (generatorType) { + case NameGeneratorType.ORDERED: + return new OrderedNameGenerator(options); + case NameGeneratorType.DISORDERED: + return new DisorderNameGenerator(options); + case NameGeneratorType.HEX: + return new HexNameGenerator(options); + case NameGeneratorType.DICTIONARY: + return new DictionaryNameGenerator(options); + case NameGeneratorType.RESERVED_NAME: + return new ReservedNameGenerator(options); + case NameGeneratorType.UNDERLINE: + return new UnderlineNameGenerator(options); + default: + console.error('name generator type in getGenerator() is not support'); + return new OrderedNameGenerator(options); + } +} diff --git a/arkguard/src/generator/OrderedNameGenerator.ts b/arkguard/src/generator/OrderedNameGenerator.ts new file mode 100644 index 0000000000000000000000000000000000000000..699db8c1946ec21f6871f5176fe29f89e0755a0b --- /dev/null +++ b/arkguard/src/generator/OrderedNameGenerator.ts @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type {INameGenerator, NameGeneratorOptions} from './INameGenerator'; + +/** + * @desc simple ordered name generator, e.g.: a, b, c, d, ..., a1, b1, c1, ... + */ +export class OrderedNameGenerator implements INameGenerator { + private mCharIndex: number; + private mLoopNumber: number; + private mReservedNames: Set; + + private readonly CHAR_COUNT: number = 26; + private readonly CHAR_CODE_A: number = 97; + + constructor(options?: NameGeneratorOptions) { + this.mCharIndex = 0; + this.mLoopNumber = 0; + this.mReservedNames = options?.reservedNames; + } + + private updateElements(): void { + this.mCharIndex = (this.mCharIndex + 1) % this.CHAR_COUNT; + if (this.mCharIndex === 0) { + this.mLoopNumber += 1; + } + } + + public getName(): string { + let generatedName: string = String.fromCharCode(this.CHAR_CODE_A + this.mCharIndex); + if (this.mLoopNumber > 0) { + generatedName += this.mLoopNumber; + } + + this.updateElements(); + if (this.mReservedNames?.has(generatedName)) { + return this.getName(); + } + + return generatedName; + } + + public reset(): void { + this.mCharIndex = 0; + this.mLoopNumber = 0; + } +} diff --git a/arkguard/src/generator/ReservedNameGenerator.ts b/arkguard/src/generator/ReservedNameGenerator.ts new file mode 100644 index 0000000000000000000000000000000000000000..99df5970e2cfb7d91c60c76c38c64d1d8fd80b3b --- /dev/null +++ b/arkguard/src/generator/ReservedNameGenerator.ts @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type {INameGenerator, NameGeneratorOptions} from './INameGenerator'; + +/** + * need reserved keyword which contain transformDict character + */ +const gReservedIdentifier = [ + 'let', 'return', 'break', 'continue', 'const', 'var', 'console', 'enum', + 'boolean', 'number', 'string', 'any', 'void', 'undefined', 'null', + 'never', 'function', 'declare', 'as', 'while', 'for', 'if', 'else', + 'true', 'false', 'try', 'catch', 'throw', 'type', 'class', 'new', + 'interface', 'export', 'readonly', 'private', 'public', 'extends', + 'implements', 'constructor', 'this', 'static', 'protected', 'switch', + 'case', 'default', 'typeof', 'instanceof', 'in', 'of', 'import', 'require', + 'module', 'from', 'abstract', 'async', 'namespace', 'arguments' +]; + +const gTransformDict = { + 'a': 'α', + 'b': 'þ', + 'c': 'ç', + 'e': 'è', + 'i': 'ì', + 'k': 'κ', + 'l': 'ι', + 'n': 'η', + 'o': 'ο', + 'p': 'ρ', + 'u': 'υ', + 'v': 'ν', + 'w': 'ω', + 'x': 'χ', + 'y': 'γ', + 'z': 'ζ' +}; + +/** + * @Desc: a name generator which use reserved keywords similar words to get obfuscated name + */ +export class ReservedNameGenerator implements INameGenerator { + private readonly mReservedNames: Set; + private readonly mTransformSet: Set; + + private mIdIndex: number; + private readonly mWordInfo: number[]; + private mWordIndex: number; + + constructor(options?: NameGeneratorOptions) { + this.mTransformSet = new Set(); + + this.mReservedNames = options?.reservedNames; + + const dictKeys: string[] = Object.keys(gTransformDict); + for (const key of dictKeys) { + this.mTransformSet.add(key); + } + + this.mIdIndex = 0; + this.mWordIndex = 1; + this.mWordInfo = []; + + this.getWordInfo(gReservedIdentifier[this.mIdIndex]); + } + + private getWordInfo(originName: string): void { + for (let i = 0; i < originName.length; i++) { + if (this.mTransformSet.has(originName[i])) { + this.mWordInfo.push(i); + } + } + } + + private transformName(originName: string): string { + let charArr: string[] = originName.split(''); + const BINARY_RADIX: number = 2; + let binaryArr: string = this.mWordIndex.toString(BINARY_RADIX).split('').reverse().join(''); + for (let i = 0; i < binaryArr.length; i++) { + if (binaryArr[i] === '1') { + charArr[this.mWordInfo[i]] = gTransformDict[charArr[this.mWordInfo[i]]]; + } + } + + this.mWordIndex += 1; + if (this.mWordIndex === Math.pow(BINARY_RADIX, this.mWordInfo.length)) { + this.mIdIndex += 1; + this.mWordInfo.length = 0; + this.mWordIndex = 1; + + if (this.mIdIndex < gReservedIdentifier.length) { + this.getWordInfo(gReservedIdentifier[this.mIdIndex]); + } + } + + return charArr.join(''); + } + + /** + * @return: null for end + */ + public getName(): string { + let originName: string = gReservedIdentifier[this.mIdIndex]; + + let transformedName: string = this.transformName(originName); + if (this.mIdIndex >= gReservedIdentifier.length) { + return null; + } + + if (this.mReservedNames?.has(transformedName)) { + return this.getName(); + } + + return transformedName; + } + + public reset(): void { + this.mIdIndex = 0; + this.mWordIndex = 1; + this.mWordInfo.length = 0; + this.getWordInfo(gReservedIdentifier[this.mIdIndex]); + } +} diff --git a/arkguard/src/generator/UnderlineNameGenerator.ts b/arkguard/src/generator/UnderlineNameGenerator.ts new file mode 100644 index 0000000000000000000000000000000000000000..f10d67d49333da0990840e8e882558184a4e854a --- /dev/null +++ b/arkguard/src/generator/UnderlineNameGenerator.ts @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type {INameGenerator, NameGeneratorOptions} from './INameGenerator'; + +/** + * @Desc: a name generator which use underline to get obfuscated name + */ +export class UnderlineNameGenerator implements INameGenerator { + private readonly mMaxLength: number; + private readonly mReservedNames: Set; + + private mCurrentLength: number; + + constructor(options: NameGeneratorOptions) { + const maxValue: number = 128; + this.mMaxLength = (options && options.underlineMaxLength) ? options.underlineMaxLength : maxValue; + this.mReservedNames = options?.reservedNames; + this.mCurrentLength = 1; + } + + /** + * @return: null for end + */ + public getName(): string { + if (this.mCurrentLength > this.mMaxLength) { + return null; + } + + let targetStr: string = '_'.repeat(this.mCurrentLength); + this.mCurrentLength += 1; + + if (this.mReservedNames?.has(targetStr)) { + return this.getName(); + } + + return targetStr; + } + + public reset(): void { + this.mCurrentLength = 1; + } +} diff --git a/arkguard/src/transformers/TransformPlugin.ts b/arkguard/src/transformers/TransformPlugin.ts new file mode 100644 index 0000000000000000000000000000000000000000..f4d43dc606847051d56401be24b55185948aafc9 --- /dev/null +++ b/arkguard/src/transformers/TransformPlugin.ts @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type {IOptions} from '../configs/IOptions'; +import type {Node, TransformerFactory} from 'typescript'; + +export interface TransformPlugin { + name: string; + order: number + createTransformerFactory: (option: IOptions) => TransformerFactory; +} diff --git a/arkguard/src/transformers/TransformerManager.ts b/arkguard/src/transformers/TransformerManager.ts new file mode 100644 index 0000000000000000000000000000000000000000..dee28a04e99eb8c1b31fbe16eba06a99ac023e84 --- /dev/null +++ b/arkguard/src/transformers/TransformerManager.ts @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type {Node, TransformerFactory} from 'typescript'; +import {lstatSync, readdirSync} from 'fs'; +import {join, resolve} from 'path'; + +import type {IOptions} from '../configs/IOptions'; +import type {TransformPlugin} from './TransformPlugin'; + +export class TransformerManager { + private static sInstance: TransformerManager | null = null; + + private static readonly sLoadPath: string = join(__dirname, '../', 'transformers'); + + private readonly mTransformers: TransformerFactory[]; + + public static getInstance(): TransformerManager { + if (!this.sInstance) { + this.sInstance = new TransformerManager(); + } + + return this.sInstance as TransformerManager; + } + + private constructor() { + this.mTransformers = []; + } + + public loadTransformers(options: IOptions): TransformerFactory[] { + let subFiles: string[] = readdirSync(TransformerManager.sLoadPath); + let plugins: TransformPlugin[] = []; + for (const subFile of subFiles) { + let subPath: string = resolve(TransformerManager.sLoadPath + '/' + subFile); + let isDir: boolean = lstatSync(subPath)?.isDirectory(); + if (!isDir) { + continue; + } + + let subDir: string[] = readdirSync(subPath); + for (const file of subDir) { + if (!file.endsWith('.ts')) { + continue; + } + const fileNameNoSuffix = file.lastIndexOf('.d.ts') > -1 ? file.slice(0, file.lastIndexOf('.d.ts')) : file.slice(0, file.lastIndexOf('.ts')); + let path: string = join(subPath, fileNameNoSuffix); + let module = require(path); + let plugin: TransformPlugin = module?.transformerPlugin; + if (plugin) { + plugins.push(plugin as TransformPlugin); + } + } + } + + plugins.sort((plugin1: TransformPlugin, plugin2: TransformPlugin) => { + return plugin1.order - plugin2.order; + }); + + plugins.forEach((plugin: TransformPlugin) => { + let transformerFactory: TransformerFactory = plugin?.createTransformerFactory(options); + let name: string = plugin?.name; + if (transformerFactory && name) { + this.mTransformers.push(transformerFactory); + } + }); + + return this.mTransformers; + } +} diff --git a/arkguard/src/transformers/bogus/AbstractBogusControlHelper.ts b/arkguard/src/transformers/bogus/AbstractBogusControlHelper.ts new file mode 100644 index 0000000000000000000000000000000000000000..768a6bea748ac05e0eb8c24a92f2ffbd87178cbb --- /dev/null +++ b/arkguard/src/transformers/bogus/AbstractBogusControlHelper.ts @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type {Block, Statement} from 'typescript'; + +export abstract class AbstractBogusControlHelper { + protected mOriginalUnits: Statement[]; + protected mUseOpaquePredicate: boolean; + + protected constructor(units: Statement[], useOpaquePredicate: boolean) { + this.mOriginalUnits = units; + this.mUseOpaquePredicate = useOpaquePredicate; + } + + public abstract getNewBlock(bogusBlock: Block): Block; + + public getBogusStruct(bogusBlock: Block): Block { + return this.getNewBlock(bogusBlock); + } +} diff --git a/arkguard/src/transformers/bogus/BogusControlTransformer.ts b/arkguard/src/transformers/bogus/BogusControlTransformer.ts new file mode 100644 index 0000000000000000000000000000000000000000..c924ecf591bc4b5af0e60fd687f1ddf4c6f2c494 --- /dev/null +++ b/arkguard/src/transformers/bogus/BogusControlTransformer.ts @@ -0,0 +1,484 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as crypto from 'crypto'; +import { + factory, + forEachChild, + isBinaryExpression, + isBlock, + isBreakOrContinueStatement, + isClassDeclaration, + isFunctionDeclaration, + isFunctionLike, + isIdentifier, + isLabeledStatement, + isPropertyAccessExpression, + isSourceFile, + isVariableDeclaration, + setParentRecursive, + SyntaxKind, + visitEachChild +} from 'typescript'; + +import type { + BinaryExpression, + BinaryOperator, + Block, + Node, + PropertyAccessExpression, + SourceFile, + Statement, + TransformationContext, + Transformer, + TransformerFactory +} from 'typescript'; + +import type {TransformPlugin} from '../TransformPlugin'; +import type {IOptions} from '../../configs/IOptions'; +import {BogusBlockType} from '../../configs/IBogusControlFlowOption'; +import type {IBogusControlFlowOption} from '../../configs/IBogusControlFlowOption'; +import {NodeUtils} from '../../utils/NodeUtils'; +import {collectExistNames, isObfsIgnoreNode} from '../../utils/TransformUtil'; +import type {AbstractBogusControlHelper} from './AbstractBogusControlHelper'; +import {SimpleBogusControlHelper} from './SimpleBogusControlHelper'; +import type {INameGenerator, NameGeneratorOptions} from '../../generator/INameGenerator'; +import {getNameGenerator, NameGeneratorType} from '../../generator/NameFactory'; +import type {Hash} from 'crypto'; + +namespace secharmony { + const createBogusControlFactory = function (option: IOptions): TransformerFactory { + let profile: IBogusControlFlowOption | undefined = option?.mBogusControlFlow; + if (!profile || !profile.mEnable || profile.mThreshold <= 0) { + return null; + } + + return bogusControlFactory; + + function bogusControlFactory(context: TransformationContext): Transformer { + let blockMap: Map = new Map(); + let blockMapKeys: string[] = []; + let bogusType: BogusBlockType = BogusBlockType.CURRENT_BLOCK_DEFORM; + let sourceFile: SourceFile; + let reservedNames: Set; + let nameGenerator: INameGenerator; + + return transformer; + + function transformer(node: Node): Node { + if (!isSourceFile(node) || node.fileName.endsWith('.d.ts')) { + return node; + } + + sourceFile = node; + + // we only do bogus control flow with block + if (!hasBlock(node)) { + return node; + } + + reservedNames = collectExistNames(sourceFile); + const options: NameGeneratorOptions = { + reservedNames: reservedNames + }; + nameGenerator = getNameGenerator(NameGeneratorType.ORDERED, options); + + // if bogus block get from other block rename, extract all available blocks + // javascript support current block deform and other block deform, typescript only + // support current block deform. + if (profile.mInsertBlockType === BogusBlockType.OTHER_BLOCK_RENAME && node.fileName.endsWith('.js')) { + bogusType = BogusBlockType.OTHER_BLOCK_RENAME; + getAvailableBlocks(node); + for (const key of blockMap.keys()) { + blockMapKeys.push(key); + } + } + + return setParentRecursive(bogusAst(node), true); + } + + /** + * Block is minimum process unit for us in bogus control flow, + * we only inject code in the most inner Block + * @param node + */ + function bogusAst(node: Node): Node { + if (profile.mSkipLoop && NodeUtils.isLoopStatement(node)) { + return node; + } + + if (!isSourceFile(node) && isObfsIgnoreNode(node, sourceFile)) { + return node; + } + + if (!isBlock(node)) { + return visitEachChild(node, bogusAst, context); + } + + const bogusNode: Block = visitEachChild(node, bogusAst, context); + return bogusControlFlow(bogusNode); + } + + function bogusControlFlow(node: Block): Block { + if (NodeUtils.isContainForbidStringStatement(node) || node.statements.length <= 1) { + return node; + } + + // judge threshold + const randomMaxValue: number = 100; + const temp: number = crypto.randomInt(randomMaxValue); + if (temp > randomMaxValue * profile.mThreshold) { + return node; + } + + let helper: AbstractBogusControlHelper = new SimpleBogusControlHelper( + [...node.statements], + profile.mUseOpaquePredicate, + nameGenerator + ); + + const bogusBlock: Block = getBogusBlock(node, context); + return helper.getBogusStruct(bogusBlock); + } + + /** + * random select other block or deform current block as bogus block + */ + function getBogusBlock(node: Block, context: TransformationContext): Block { + if (bogusType === BogusBlockType.CURRENT_BLOCK_DEFORM || blockMapKeys.length <= 1) { + return deformBlock(node, context); + } + + const randomMaxValue: number = 100; + let index: number = crypto.randomInt(randomMaxValue) % blockMapKeys.length; + if (getHash(NodeUtils.printNode(node, sourceFile)) === blockMapKeys[index]) { + index = (index + 1) % blockMapKeys.length; + } + + let bogusBlock: Block = blockMap.get(blockMapKeys[index]); + // for randomness + const deformedBlock: Block = deformBlock(bogusBlock, context); + // rename identifier + return renameIdentifier(deformedBlock, context, nameGenerator); + } + + /** + * get all blocks of current source file + * @private + */ + function getAvailableBlocks(node: Node): void { + if (!isBlock(node)) { + node.forEachChild((child) => { + getAvailableBlocks(child); + }); + + return; + } + + // remove special statement + let deformedBlock: Block = removeSpecial(node); + if (deformedBlock === null) { + return; + } + + // use printer to print block + blockMap.set(getHash(NodeUtils.printNode(node, sourceFile)), deformedBlock); + node.forEachChild((child) => { + getAvailableBlocks(child); + }); + } + } + }; + + const TRANSFORMER_ORDER: number = 4; + export let transformerPlugin: TransformPlugin = { + 'name': 'BogusControlTransformer', + 'createTransformerFactory': createBogusControlFactory, + 'order': (1 << TRANSFORMER_ORDER) + }; + + const hasBlock = function (node: Node): boolean { + let flag: boolean = false; + let visit = (inputNode): void => { + if (flag) { + return; + } + + if (isBlock(inputNode)) { + flag = true; + return; + } + + forEachChild(inputNode, visit); + }; + + visit(node); + return flag; + }; + + /** + * deform binary expression, example: + * a+b; -> a-b; + * a += b; -> a -= b; + * @param expression + * @private + */ + const deformBinary = function (expression: BinaryExpression): BinaryExpression { + const binaryOperators: SyntaxKind[] = [ + SyntaxKind.PlusToken, SyntaxKind.MinusToken, SyntaxKind.AsteriskToken, + SyntaxKind.SlashToken, SyntaxKind.BarToken, SyntaxKind.CaretToken, + SyntaxKind.AmpersandToken + ]; + + const kind: SyntaxKind = expression.operatorToken.kind; + // plus need consider string value + if (kind === SyntaxKind.PlusToken) { + if (isBinaryExpression(expression.left) || isBinaryExpression(expression.right)) { + return expression; + } + + return factory.createBinaryExpression( + factory.createBinaryExpression( + {...expression.left}, + SyntaxKind.PlusToken, + {...expression.right} + ), + SyntaxKind.PlusToken, + {...expression.left} + ); + } + + if (kind === SyntaxKind.PlusEqualsToken) { + return factory.createBinaryExpression( + {...expression.left}, + SyntaxKind.PlusEqualsToken, + factory.createBinaryExpression( + {...expression.left}, + SyntaxKind.PlusToken, + {...expression.right} + ) + ); + } + + let replaceKind: SyntaxKind = undefined; + if (kind === SyntaxKind.MinusToken || kind === SyntaxKind.AsteriskToken || + kind === SyntaxKind.SlashToken || kind === SyntaxKind.BarToken || + kind === SyntaxKind.CaretToken || kind === SyntaxKind.AmpersandToken || + kind === SyntaxKind.PercentToken) { + const randomMaxValue: number = 100; + let index: number = crypto.randomInt(randomMaxValue) % binaryOperators.length; + if (binaryOperators[index] === expression.operatorToken.kind) { + index = (index + 1) % binaryOperators.length; + } + + replaceKind = binaryOperators[index]; + } + + const binaryEqualOperators: SyntaxKind[] = [SyntaxKind.PlusEqualsToken, SyntaxKind.MinusEqualsToken, + SyntaxKind.AsteriskEqualsToken, SyntaxKind.SlashEqualsToken, SyntaxKind.BarEqualsToken, + SyntaxKind.CaretEqualsToken, SyntaxKind.AmpersandEqualsToken]; + if (kind === SyntaxKind.MinusEqualsToken || kind === SyntaxKind.AsteriskEqualsToken || + kind === SyntaxKind.SlashEqualsToken || kind === SyntaxKind.BarEqualsToken || + kind === SyntaxKind.CaretEqualsToken || kind === SyntaxKind.AmpersandEqualsToken) { + const randomMaxValue: number = 100; + let index: number = crypto.randomInt(randomMaxValue) % binaryEqualOperators.length; + if (binaryEqualOperators[index] === expression.operatorToken.kind) { + index = (index + 1) % binaryEqualOperators.length; + } + + replaceKind = binaryEqualOperators[index]; + } + + const shiftOperators: SyntaxKind[] = [ + SyntaxKind.LessThanLessThanToken, SyntaxKind.GreaterThanGreaterThanToken, + SyntaxKind.GreaterThanGreaterThanGreaterThanToken + ]; + if (shiftOperators.includes(kind)) { + const index: number = (shiftOperators.indexOf(kind) + 1) % shiftOperators.length; + replaceKind = shiftOperators[index]; + } + + const equalOperators: SyntaxKind[] = [ + SyntaxKind.EqualsEqualsToken, SyntaxKind.ExclamationEqualsToken, + SyntaxKind.EqualsEqualsEqualsToken, SyntaxKind.ExclamationEqualsEqualsToken, + SyntaxKind.LessThanToken, SyntaxKind.LessThanEqualsToken, + SyntaxKind.GreaterThanToken, SyntaxKind.GreaterThanEqualsToken, + ]; + if (equalOperators.includes(kind)) { + const index: number = (equalOperators.indexOf(kind) + 1) % equalOperators.length; + replaceKind = equalOperators[index]; + } + + if (replaceKind === undefined) { + return expression; + } + + return factory.createBinaryExpression( + {...expression.left}, + replaceKind as BinaryOperator, + {...expression.right} + ); + }; + + /** + * find special statement: + * return, break, continue, yield, await, super, this + * @param statement + * @private + */ + const findSpecial = function (statement: Statement): boolean { + let result: boolean = false; + let visit = (node: Node): void => { + if (result) { + return; + } + + if (isFunctionLike(node) || + NodeUtils.isLoopStatement(node)) { + return; + } + + if (isBreakOrContinueStatement(node)) { + result = true; + return; + } + + if (node.kind === SyntaxKind.YieldKeyword || + node.kind === SyntaxKind.AwaitKeyword || + node.kind === SyntaxKind.SuperKeyword || + node.kind === SyntaxKind.ThisKeyword) { + result = true; + return; + } + + forEachChild(node, visit); + }; + + visit(statement); + return result; + }; + + /** + * remove special statement of javascript + * @param block + * @private + */ + const removeSpecial = function (block: Block): Block { + const statements: Statement[] = []; + for (const statement of block.statements) { + if (findSpecial(statement)) { + continue; + } + + statements.push(statement); + } + + if (statements.length === 0) { + return null; + } + + return factory.createBlock(statements, true); + }; + + /** + * deform block + * method: + * change binary expression; + * change true and false + * @private + */ + const deformBlock = function (originBlock: Block, context: TransformationContext): Block { + // deform statement + function visit(node: Node): Node { + switch (node.kind) { + case SyntaxKind.PropertyAccessExpression: + return NodeUtils.changePropertyAccessToElementAccess(node as PropertyAccessExpression); + case SyntaxKind.BinaryExpression: + if (NodeUtils.isMostInnerBinary(node)) { + return deformBinary(node as BinaryExpression); + } + break; + case SyntaxKind.TrueKeyword: + return factory.createFalse(); + case SyntaxKind.FalseKeyword: + return factory.createTrue(); + case SyntaxKind.ContinueStatement: + return factory.createBreakStatement(); + default: + break; + } + + return visitEachChild(node, visit, context); + } + + return visit(originBlock) as Block; + }; + + const renameIdentifier = function (originBlock: Block, context: TransformationContext, nameGenerator: INameGenerator): Block { + const nameCache: Map = new Map(); + const labelNameCache: Map = new Map(); + + function visit(node: Node): Node { + if (!isIdentifier(node) || !node.parent) { + return visitEachChild(node, visit, context); + } + + if (isLabeledStatement(node.parent)) { + const deformedName: string = nameGenerator.getName(); + labelNameCache.set(node.text, deformedName); + return factory.createIdentifier(deformedName); + } + + if (isBreakOrContinueStatement(node.parent)) { + const foundLabelName: string = labelNameCache.get(node.text); + if (foundLabelName) { + return factory.createIdentifier(foundLabelName); + } + + return node; + } + + if (isVariableDeclaration(node.parent) || isFunctionDeclaration(node.parent) || isClassDeclaration(node.parent)) { + const deformedName: string = nameGenerator.getName(); + nameCache.set(node.text, deformedName); + return factory.createIdentifier(deformedName); + } + + if (isPropertyAccessExpression(node.parent)) { + return node; + } + + const foundName: string = nameCache.get(node.text); + if (foundName) { + return factory.createIdentifier(foundName); + } + + return node; + } + + return visit(originBlock) as Block; + }; + + /** + * get hash value of string + * @private + */ + const getHash = function (str: string): string { + const hash: Hash = crypto.createHash('sha256'); + return hash.update(str).digest('hex').toLowerCase(); + }; +} + +export = secharmony; diff --git a/arkguard/src/transformers/bogus/SimpleBogusControlHelper.ts b/arkguard/src/transformers/bogus/SimpleBogusControlHelper.ts new file mode 100644 index 0000000000000000000000000000000000000000..53f3bdae6c255bd0d4b7359c4d1a20de36f42192 --- /dev/null +++ b/arkguard/src/transformers/bogus/SimpleBogusControlHelper.ts @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {factory, SyntaxKind} from 'typescript'; +import type {BinaryExpression, Block, Expression, IfStatement, Statement} from 'typescript'; +import crypto from 'crypto'; + +import {AbstractBogusControlHelper} from './AbstractBogusControlHelper'; +import {NodeUtils} from '../../utils/NodeUtils'; +import type {INameGenerator} from '../../generator/INameGenerator'; + +export class SimpleBogusControlHelper extends AbstractBogusControlHelper { + protected mNameGenerator: INameGenerator; + + public constructor(units: Statement[], useOpaquePredicate: boolean, nameGenerator: INameGenerator) { + super(units, useOpaquePredicate); + this.mNameGenerator = nameGenerator; + } + + public getNewBlock(bogusBlock: Block): Block { + const preStatements: Statement[] = []; + const randomMaxValue: number = 100; + const useTrue: boolean = (crypto.randomInt(randomMaxValue) & 1) === 0; + + let predicate: Expression; + if (this.mUseOpaquePredicate) { + predicate = this.createOpaquePredicate(preStatements, useTrue); + } else { + predicate = this.createSimplePredicate(preStatements, useTrue); + } + + const originalBlock: Block = factory.createBlock([...this.mOriginalUnits], true); + + let ifStatement: IfStatement; + if (useTrue) { + ifStatement = factory.createIfStatement(predicate, originalBlock, bogusBlock); + } else { + ifStatement = factory.createIfStatement(predicate, bogusBlock, originalBlock); + } + + return factory.createBlock( + [ + ...preStatements, + ifStatement + ], + true + ); + } + + public createSimplePredicate(preStatements: Statement[], useTrue: boolean): Expression { + const arrayName: string = this.mNameGenerator.getName(); + const stringArray: string[] = []; + const traversalRange: number = 10; + for (let i = 0; i < traversalRange; i++) { + stringArray.push(this.mNameGenerator.getName()); + } + + const arrayInitStatement: Statement = NodeUtils.createArrayInit(true, arrayName, + SyntaxKind.StringLiteral, stringArray); + preStatements.push(arrayInitStatement); + + const syntaxSymbol: SyntaxKind = useTrue ? SyntaxKind.ExclamationEqualsEqualsToken : + SyntaxKind.EqualsEqualsEqualsToken; + + return factory.createBinaryExpression( + factory.createElementAccessExpression( + factory.createIdentifier(arrayName), + factory.createNumericLiteral('1') + ), + syntaxSymbol, + factory.createElementAccessExpression( + factory.createIdentifier(arrayName), + factory.createNumericLiteral('6') + ) + ); + } + + /** + * create condition judgement use opaque predicate + */ + public createOpaquePredicate(preStatements, useTrue: boolean): Expression { + const nameGenerator: INameGenerator = this.mNameGenerator; + + const xName: string = nameGenerator.getName(); + const randomMaxValue: number = 125; + preStatements.push(NodeUtils.createNumericWithRandom(xName, 1, randomMaxValue)); + + /** + * y < 10 || x * (x + 1) % 2 == 0, always true + * x is integer + */ + function method1(): BinaryExpression { + const yName: string = nameGenerator.getName(); + preStatements.push(NodeUtils.createNumericWithRandom(yName, 1, randomMaxValue)); + + const left: BinaryExpression = factory.createBinaryExpression( + factory.createIdentifier(yName), + SyntaxKind.LessThanToken, + factory.createNumericLiteral('10') + ); + + const rightLeft: BinaryExpression = factory.createBinaryExpression( + factory.createBinaryExpression( + factory.createIdentifier(xName), + SyntaxKind.AsteriskToken, + factory.createParenthesizedExpression( + factory.createBinaryExpression( + factory.createIdentifier(xName), + SyntaxKind.PlusToken, + factory.createNumericLiteral('1') + ) + ) + ), + SyntaxKind.PercentToken, + factory.createNumericLiteral('2') + ); + + const right: BinaryExpression = factory.createBinaryExpression( + rightLeft, + SyntaxKind.EqualsEqualsEqualsToken, + factory.createNumericLiteral('0') + ); + + return factory.createBinaryExpression( + left, + SyntaxKind.BarBarToken, + right + ); + } + + /** + * 7* x* x − y* y != 1 || y < n, always true + * x, y in [0, 125); + * n in [0, 125]; + */ + function method2(): BinaryExpression { + const yName: string = nameGenerator.getName(); + const randomMaxValue: number = 125; + preStatements.push(NodeUtils.createNumericWithRandom(yName, 1, randomMaxValue)); + + const nName: string = nameGenerator.getName(); + preStatements.push(NodeUtils.createNumericWithRandom(nName, 0, randomMaxValue)); + + const left: BinaryExpression = factory.createBinaryExpression( + factory.createBinaryExpression( + factory.createBinaryExpression( + factory.createBinaryExpression( + factory.createNumericLiteral('7'), + SyntaxKind.AsteriskToken, + factory.createIdentifier(xName) + ), + SyntaxKind.AsteriskToken, + factory.createIdentifier(xName) + ), + SyntaxKind.MinusToken, + factory.createBinaryExpression( + factory.createIdentifier(yName), + SyntaxKind.AsteriskToken, + factory.createIdentifier(yName) + ) + ), + SyntaxKind.ExclamationEqualsEqualsToken, + factory.createNumericLiteral('1') + ); + + const right: BinaryExpression = factory.createBinaryExpression( + factory.createIdentifier(yName), + SyntaxKind.LessThanToken, + factory.createIdentifier(nName) + ); + + return factory.createBinaryExpression( + left, + SyntaxKind.BarBarToken, + right + ); + } + + /** + * (4*x*x + 1) % 19 != 0, always true + */ + function method3(): BinaryExpression { + const leftInner: BinaryExpression = factory.createBinaryExpression( + factory.createBinaryExpression( + factory.createBinaryExpression( + factory.createNumericLiteral('4'), + SyntaxKind.AsteriskToken, + factory.createIdentifier(xName) + ), + SyntaxKind.AsteriskToken, + factory.createIdentifier(xName) + ), + SyntaxKind.PlusToken, + factory.createNumericLiteral('4') + ); + + const left: BinaryExpression = factory.createBinaryExpression( + factory.createParenthesizedExpression( + leftInner + ), + SyntaxKind.PercentToken, + factory.createNumericLiteral('19') + ); + + return factory.createBinaryExpression( + left, + SyntaxKind.ExclamationEqualsEqualsToken, + factory.createNumericLiteral('0') + ); + } + + /** + * (x*x + x +7) % 81 != 0, always true + */ + function method4(): BinaryExpression { + const leftInner: BinaryExpression = factory.createBinaryExpression( + factory.createBinaryExpression( + factory.createBinaryExpression( + factory.createIdentifier(xName), + SyntaxKind.AsteriskToken, + factory.createIdentifier(xName) + ), + SyntaxKind.PlusToken, + factory.createIdentifier(xName) + ), + SyntaxKind.PlusToken, + factory.createNumericLiteral('7') + ); + + const left: BinaryExpression = factory.createBinaryExpression( + factory.createParenthesizedExpression( + leftInner + ), + SyntaxKind.PercentToken, + factory.createNumericLiteral('81') + ); + + return factory.createBinaryExpression( + left, + SyntaxKind.ExclamationEqualsEqualsToken, + factory.createNumericLiteral('0') + ); + } + + /** + * (x*x*x -x) % 3 == 0, always true + */ + function method5(): BinaryExpression { + const leftInner: BinaryExpression = factory.createBinaryExpression( + factory.createBinaryExpression( + factory.createBinaryExpression( + factory.createIdentifier(xName), + SyntaxKind.AsteriskToken, + factory.createIdentifier(xName) + ), + SyntaxKind.AsteriskToken, + factory.createIdentifier(xName) + ), + SyntaxKind.MinusToken, + factory.createIdentifier(xName) + ); + + const left: BinaryExpression = factory.createBinaryExpression( + factory.createParenthesizedExpression( + leftInner + ), + SyntaxKind.PercentToken, + factory.createNumericLiteral('3') + ); + + return factory.createBinaryExpression( + left, + SyntaxKind.EqualsEqualsEqualsToken, + factory.createNumericLiteral('0') + ); + } + + const methodList: (() => BinaryExpression)[] = [method1, method2, method3, method4, method5]; + const opaqueMethod: () => BinaryExpression = methodList[crypto.randomInt(methodList.length)]; + + if (useTrue) { + return opaqueMethod(); + } + + return factory.createPrefixUnaryExpression( + SyntaxKind.ExclamationToken, + factory.createParenthesizedExpression( + opaqueMethod() + ) + ); + } +} diff --git a/arkguard/src/transformers/control/AbstractControlFlowFlattenHelper.ts b/arkguard/src/transformers/control/AbstractControlFlowFlattenHelper.ts new file mode 100644 index 0000000000000000000000000000000000000000..c8533b76c0c25fcfe1bd39c78205a8e874d99d10 --- /dev/null +++ b/arkguard/src/transformers/control/AbstractControlFlowFlattenHelper.ts @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type {Expression, ForStatement, Statement, SwitchStatement, WhileStatement} from 'typescript'; + +import type {INameGenerator, NameGeneratorOptions} from '../../generator/INameGenerator'; +import {getNameGenerator, NameGeneratorType} from '../../generator/NameFactory'; + +export abstract class AbstractControlFlowFlattenHelper { + protected mOrderObjName: string; + + protected mIndexName: string; + + protected mOriginalUnits: Statement[]; + + protected mStatementUnits: Map; + + protected mNameGenerator: INameGenerator; + + protected constructor(units: Statement[], reservedNames: Set) { + this.mOriginalUnits = units; + const options: NameGeneratorOptions = { + reservedNames: reservedNames + }; + this.mNameGenerator = getNameGenerator(NameGeneratorType.ORDERED, options); + this.mOrderObjName = this.mNameGenerator.getName(); + reservedNames.add(this.mOrderObjName); + this.mIndexName = this.mNameGenerator.getName(); + reservedNames.add(this.mIndexName); + } + + public abstract getLoopCondition(): Expression; + + public abstract getLoopStruct(): WhileStatement | ForStatement; + + public abstract getSwitchStruct(): SwitchStatement; + + public abstract getVariableRelatedStatements(): Statement[]; + + public getFlattenStruct(): Statement[] { + return [...this.getVariableRelatedStatements(), this.getLoopStruct()]; + } +} diff --git a/arkguard/src/transformers/control/ConfusedCharsFlattenHelper.ts b/arkguard/src/transformers/control/ConfusedCharsFlattenHelper.ts new file mode 100644 index 0000000000000000000000000000000000000000..c608513768ea4053badf8465332654c506c3f2da --- /dev/null +++ b/arkguard/src/transformers/control/ConfusedCharsFlattenHelper.ts @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + factory, + isIdentifierStart, + isReturnStatement, + ScriptTarget, + SyntaxKind, + NodeFlags +} from 'typescript'; + +import type { + CaseClause, + ObjectLiteralExpression, + PropertyAssignment, + Statement, + SwitchStatement, + CallExpression, + VariableStatement, + ElementAccessExpression +} from 'typescript'; + +import {randomInt} from 'crypto'; + +import {table as confusionTable} from '../../configs/preset/ConfusionTables'; +import {SimpleControlFlowFlattenHelper} from './SimpleControlFlowFlattenHelper'; + +export class ConfusedCharsFlattenHelper extends SimpleControlFlowFlattenHelper { + private readonly mChoiceName: string; + + private mMangledTable: Map; + + private mChooseMaps: Map; + + public constructor(units: Statement[], reservedNames: Set) { + super(units, reservedNames); + + this.mChoiceName = this.mNameGenerator.getName(); + reservedNames.add(this.mChoiceName); + + this.mMangledTable = new Map(); + this.mChooseMaps = new Map(); + + let index: number = 0; + const confusionTableKeys: string[] = Object.keys(confusionTable); + for (const key of confusionTableKeys) { + this.mMangledTable.set(index++, confusionTable[key]); + } + + index = 0; + let chooseList: string[] = this.chooseMangledChars(); + for (const [key, _] of this.mStatementUnits) { + this.mChooseMaps.set(key, chooseList[index++]); + } + } + + private chooseMangledChars(): string[] { + let chooseList: Set = new Set(); + let remainLen: number = this.mOriginalUnits.length; + let historyIndex: Set = new Set(); + + while (remainLen > 0) { + if (historyIndex.size === this.mMangledTable.size) { + const MIN_UNICODE = 0x100; + const MAX_UNICODE = 0x7fff; + let unicode: number = randomInt(MIN_UNICODE, MAX_UNICODE); + if (isIdentifierStart(unicode, ScriptTarget.ES2015)) { + chooseList.add(String.fromCharCode(unicode)); + remainLen = this.mOriginalUnits.length - chooseList.size; + } + + continue; + } + + let choice: number = randomInt(0, this.mMangledTable.size); + if (historyIndex.has(choice)) { + continue; + } + + historyIndex.add(choice); + let chars: string[] = this.mMangledTable.get(choice).filter((ch) => { + return isIdentifierStart(ch.codePointAt(0), ScriptTarget.ES2015); + }); + + let len: number = chars.length > remainLen ? remainLen : chars.length; + chars.slice(0, len).forEach((ch) => { + chooseList.add(ch); + }); + + remainLen = this.mOriginalUnits.length - chooseList.size; + } + + return Array.from(chooseList); + } + + public getVariableRelatedStatements(): Statement[] { + let properties: PropertyAssignment[] = []; + this.mChooseMaps.forEach((val, _) => { + const RANDOM_MIN = 0; + const RANDOM_MAX = 36; + const propValue = randomInt(RANDOM_MIN, RANDOM_MAX); + let prop: PropertyAssignment = factory.createPropertyAssignment(val, factory.createNumericLiteral(propValue)); + properties.push(prop); + }); + + let literal: ObjectLiteralExpression = factory.createObjectLiteralExpression(properties); + + const choiceExpression: CallExpression = factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier('Object'), + factory.createIdentifier('keys') + ), + undefined, + [factory.createIdentifier(this.mOrderObjName)] + ); + + const variableStatement: VariableStatement = factory.createVariableStatement( + undefined, + factory.createVariableDeclarationList( + [ + factory.createVariableDeclaration(this.mOrderObjName, undefined, undefined, literal), + factory.createVariableDeclaration(this.mIndexName, undefined, undefined, factory.createNumericLiteral(0)), + factory.createVariableDeclaration(this.mChoiceName, undefined, undefined, choiceExpression) + ], + NodeFlags.Let + ) + ); + + return [variableStatement]; + } + + public getSwitchStruct(): SwitchStatement { + let condition: ElementAccessExpression = factory.createElementAccessExpression( + factory.createIdentifier(this.mChoiceName), + factory.createPostfixUnaryExpression(factory.createIdentifier(this.mIndexName), SyntaxKind.PlusPlusToken) + ); + + let caseList: CaseClause[] = []; + for (let index = 0; index < this.mOriginalUnits.length; index++) { + let st: Statement = this.mStatementUnits.get(index); + let statements: Statement[] = isReturnStatement(st) ? [st] : [st, factory.createContinueStatement()]; + let caseSt: CaseClause = factory.createCaseClause( + factory.createStringLiteral(this.mChooseMaps.get(index)), statements); + caseList.push(caseSt); + } + + return factory.createSwitchStatement(condition, factory.createCaseBlock(caseList)); + } +} diff --git a/arkguard/src/transformers/control/ControlFlowFlattenTransformer.ts b/arkguard/src/transformers/control/ControlFlowFlattenTransformer.ts new file mode 100644 index 0000000000000000000000000000000000000000..97728f22adb4b33211d25094294f378c63ba69fa --- /dev/null +++ b/arkguard/src/transformers/control/ControlFlowFlattenTransformer.ts @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + factory, + forEachChild, + isBlock, + isBreakOrContinueStatement, isCallExpression, + isClassDeclaration, isExpressionStatement, + isFunctionDeclaration, + isFunctionLike, isSourceFile, isStringLiteral, + isSwitchStatement, + isVariableStatement, + NodeFlags, + setParentRecursive, + SyntaxKind, + visitEachChild +} from 'typescript'; + +import type { + Block, + Node, + SourceFile, + Statement, + TransformationContext, + Transformer, + TransformerFactory +} from 'typescript'; + +import crypto from 'crypto'; + +import type {TransformPlugin} from '../TransformPlugin'; +import type {IOptions} from '../../configs/IOptions'; +import type {IControlFlowFatteningOption} from '../../configs/IControlFlowFatteningOption'; +import {SimpleControlFlowFlattenHelper} from './SimpleControlFlowFlattenHelper'; +import {ConfusedCharsFlattenHelper} from './ConfusedCharsFlattenHelper'; +import {NodeUtils} from '../../utils/NodeUtils'; +import {collectExistNames, isObfsIgnoreNode} from '../../utils/TransformUtil'; + +namespace secharmony { + + const MIN_TARGET_BLOCK_LENGTH: number = 4; + const MAX_TARGET_BLOCK_LENGTH: number = 1000; + + const createCfgFlattenFactory = function (option: IOptions): TransformerFactory { + let profile: IControlFlowFatteningOption | undefined = option?.mControlFlowFlattening; + if (!profile || !profile.mEnable) { + return null; + } + + return cfgFlattenFactory; + + function cfgFlattenFactory(context: TransformationContext): Transformer { + let narrowNames: string[] = option?.mNarrowFunctionNames ?? []; + let threshold: number = profile?.mThreshold; + let skipLoop: boolean = profile.mSkipLoop; + let reservedNames: Set; + let sourceFile: SourceFile; + + return controlFlowFlattenTransformer; + + function controlFlowFlattenTransformer(node: Node): Node { + if (!isSourceFile(node) || node.fileName.endsWith('.d.ts')) { + return node; + } + + sourceFile = node; + reservedNames = collectExistNames(node); + + return setParentRecursive(controlFlowFlatten(node), true); + } + + function controlFlowFlatten(node: Node): Node { + if (skipLoop && NodeUtils.isLoopStatement(node)) { + return node; + } + + if (!isSourceFile(node) && isObfsIgnoreNode(node, sourceFile)) { + return node; + } + + if (!isBlock(node)) { + return visitEachChild(node, controlFlowFlatten, context); + } + + let newNode: Block = visitEachChild(node, controlFlowFlatten, context); + if (ignoreFlatten(newNode.statements.length) || + NodeUtils.isContainNarrowNames(node, narrowNames)) { + return newNode; + } + + return factory.createBlock(obfuscateCfg(newNode), true); + } + + function obfuscateCfg(node: Block): Statement[] { + let finalStatements: Statement[] = []; + const continuousStatement: Statement[] = []; + + // 1. filter continuous statements that can be flattened + node.statements.forEach((child) => { + if (!isForbiddenStatement(child)) { + continuousStatement.push(child); + return; + } + + if (ignoreFlatten(continuousStatement.length)) { + finalStatements = [...finalStatements, ...continuousStatement]; + finalStatements.push(child); + continuousStatement.length = 0; + return; + } + + // 2. flatten continuous statements + let helper: SimpleControlFlowFlattenHelper = profile?.mAdvance ? + new ConfusedCharsFlattenHelper(continuousStatement, reservedNames) : + new SimpleControlFlowFlattenHelper(continuousStatement, reservedNames); + + const flattenStatements: Statement[] = helper.getFlattenStruct(); + finalStatements = [...finalStatements, ...flattenStatements]; + finalStatements.push(child); + continuousStatement.length = 0; + }); + + if (ignoreFlatten(continuousStatement.length)) { + finalStatements = [...finalStatements, ...continuousStatement]; + continuousStatement.length = 0; + return finalStatements; + } + + // 2. flatten continuous statements + let finalHelper: SimpleControlFlowFlattenHelper = profile?.mAdvance ? + new ConfusedCharsFlattenHelper(continuousStatement, reservedNames) : + new SimpleControlFlowFlattenHelper(continuousStatement, reservedNames); + + const flatten: Statement[] = finalHelper.getFlattenStruct(); + finalStatements = [...finalStatements, ...flatten]; + return finalStatements; + } + + function ignoreFlatten(statementsLen: number): boolean { + if (statementsLen < MIN_TARGET_BLOCK_LENGTH || statementsLen > MAX_TARGET_BLOCK_LENGTH) { + return true; + } + + // judge threshold + const randomMaxValue: number = 100; + const temp: number = crypto.randomInt(randomMaxValue); + return temp > randomMaxValue * threshold; + } + + /** + * is break or continue statement contained + * @param statement + */ + function isContainForbidBreakOrContinue(statement: Statement): boolean { + let result: boolean = false; + let visit = (n: Node): void => { + if (isFunctionLike(n) || + isSwitchStatement(n) || + NodeUtils.isLoopStatement(n)) { + return; + } + + if (isBreakOrContinueStatement(n)) { + result = true; + return; + } + + forEachChild(n, visit); + }; + + forEachChild(statement, visit); + return result; + } + + /** + * is statement forbidden in control flow flatten, list of forbidden: + * - let/const declaration; + * - function declaration; + * - class declaration; + * - 'use strict' like statement; + * - break/continue; + * @param statement + */ + function isForbiddenStatement(statement: Statement): boolean { + if (isVariableStatement(statement)) { + return !!(statement.declarationList.flags & NodeFlags.Const || + statement.declarationList.flags & NodeFlags.Let); + } + + if (isExpressionStatement(statement)) { + if (isStringLiteral(statement.expression)) { + return true; + } + + return isCallExpression(statement.expression) && + statement.expression.expression.kind === SyntaxKind.SuperKeyword; + } + + return isFunctionDeclaration(statement) || + isClassDeclaration(statement) || + isContainForbidBreakOrContinue(statement); + } + } + }; + + const TRANSFORMER_ORDER: number = 7; + export let transformerPlugin: TransformPlugin = { + 'name': 'ControlFlowFlattenTransformer', + 'createTransformerFactory': createCfgFlattenFactory, + 'order': (1 << TRANSFORMER_ORDER) + }; +} + +export = secharmony; diff --git a/arkguard/src/transformers/control/SimpleControlFlowFlattenHelper.ts b/arkguard/src/transformers/control/SimpleControlFlowFlattenHelper.ts new file mode 100644 index 0000000000000000000000000000000000000000..0a8eab91e77907cf5df95397e29c5cc5bac1ea09 --- /dev/null +++ b/arkguard/src/transformers/control/SimpleControlFlowFlattenHelper.ts @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + factory, + isReturnStatement, + Map, + NodeFlags, + SyntaxKind, +} from 'typescript'; + +import type { + Block, + CaseClause, + ElementAccessExpression, + Expression, + ForStatement, + NumericLiteral, + Statement, + SwitchStatement, + WhileStatement +} from 'typescript'; + +import crypto from 'crypto'; + +import {AbstractControlFlowFlattenHelper} from './AbstractControlFlowFlattenHelper'; +import {ListUtil} from '../../utils/ListUtil'; + +export class SimpleControlFlowFlattenHelper extends AbstractControlFlowFlattenHelper { + protected mIndexArrayName: string; + protected mStringArray: number[]; + protected mIndexArray: number[]; + + public constructor(units: Statement[], reservedNames: Set) { + super(units, reservedNames); + + this.mIndexArrayName = this.mNameGenerator.getName(); + reservedNames.add(this.mIndexArrayName); + + let shuffledArr: number[] = ListUtil.getInitList(units.length); + ListUtil.shuffle(shuffledArr); + + this.mStringArray = [...shuffledArr]; + ListUtil.shuffle(this.mStringArray); + + this.mIndexArray = []; + shuffledArr.forEach((value) => { + this.mIndexArray.push(this.mStringArray.indexOf(value)); + }); + + this.mStatementUnits = new Map(); + let index: number = 0; + shuffledArr.forEach((val) => { + this.mStatementUnits.set(val, this.mOriginalUnits[index++]); + }); + } + + public getSwitchStruct(): SwitchStatement { + let condition: ElementAccessExpression = factory.createElementAccessExpression( + factory.createIdentifier(this.mOrderObjName), + factory.createElementAccessExpression( + factory.createIdentifier(this.mIndexArrayName), + factory.createPostfixUnaryExpression( + factory.createIdentifier(this.mIndexName), + SyntaxKind.PlusPlusToken + ) + )); + + let caseList: CaseClause[] = []; + for (let index = 0; index < this.mOriginalUnits.length; index++) { + let st: Statement = this.mStatementUnits.get(index); + let statements: Statement[] = isReturnStatement(st) ? [st] : [st, factory.createContinueStatement()]; + let caseSt: CaseClause = factory.createCaseClause( + factory.createStringLiteral(index.toString()), statements); + caseList.push(caseSt); + } + + return factory.createSwitchStatement(condition, factory.createCaseBlock(caseList)); + } + + public getLoopStruct(): WhileStatement | ForStatement { + let loopBody: Block = factory.createBlock([ + this.getSwitchStruct(), + factory.createBreakStatement(), + ]); + + const MAX_RANDOM = 100; + const HALF_RANDOM = 100; + const temp: number = crypto.randomInt(MAX_RANDOM); + let choice: boolean = temp > HALF_RANDOM; + if (choice) { + return factory.createForStatement(undefined, undefined, undefined, loopBody); + } + + let condition: Expression = this.getLoopCondition(); + return factory.createWhileStatement(condition, loopBody); + } + + public getLoopCondition(): Expression { + return factory.createPrefixUnaryExpression( + SyntaxKind.ExclamationToken, + factory.createPrefixUnaryExpression( + SyntaxKind.ExclamationToken, + factory.createArrayLiteralExpression([]) + ) + ); + } + + public getVariableRelatedStatements(): Statement[] { + let indexStr: string = this.mStringArray.join('|'); + + let arrayList: NumericLiteral[] = []; + this.mIndexArray.forEach((value) => { + arrayList.push(factory.createNumericLiteral(value.toString())); + }); + + return [ + factory.createVariableStatement( + undefined, + factory.createVariableDeclarationList( + [ + factory.createVariableDeclaration( + factory.createIdentifier(this.mOrderObjName), + undefined, + undefined, + factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createStringLiteral(indexStr), + factory.createIdentifier('split') + ), + undefined, + [factory.createStringLiteral('|')] + ) + ), + factory.createVariableDeclaration( + factory.createIdentifier(this.mIndexArrayName), + undefined, + undefined, + factory.createArrayLiteralExpression(arrayList) + ), + factory.createVariableDeclaration( + factory.createIdentifier(this.mIndexName), + undefined, + undefined, + factory.createNumericLiteral(0) + ) + ], + NodeFlags.Let + ) + ) + ]; + } +} diff --git a/arkguard/src/transformers/data/BoolObfuscationHelper.ts b/arkguard/src/transformers/data/BoolObfuscationHelper.ts new file mode 100644 index 0000000000000000000000000000000000000000..06fc296eb9babda275666f3b9b52d1da97cd8a3a --- /dev/null +++ b/arkguard/src/transformers/data/BoolObfuscationHelper.ts @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {factory, SyntaxKind} from 'typescript'; +import type {Expression, Node} from 'typescript'; + +export class BoolObfuscationHelper { + public static isBooleanLiteral(node: Node): boolean { + return node.kind === SyntaxKind.TrueKeyword || node.kind === SyntaxKind.FalseKeyword; + } + + public static isTrueKeyword(node: Node): boolean { + return node.kind === SyntaxKind.TrueKeyword; + } + + public static createTrueObfuscation(): Expression { + return factory.createPrefixUnaryExpression( + SyntaxKind.ExclamationToken, + factory.createPrefixUnaryExpression( + SyntaxKind.ExclamationToken, + factory.createArrayLiteralExpression() + ) + ); + } + + public static createFalseObfuscation(): Expression { + return factory.createPrefixUnaryExpression( + SyntaxKind.ExclamationToken, + factory.createArrayLiteralExpression() + ); + } +} diff --git a/arkguard/src/transformers/data/DataObfuscationTransformer.ts b/arkguard/src/transformers/data/DataObfuscationTransformer.ts new file mode 100644 index 0000000000000000000000000000000000000000..9393ab6ba36551e49c97dc8e92a8ef07b9a7462d --- /dev/null +++ b/arkguard/src/transformers/data/DataObfuscationTransformer.ts @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + factory, isElementAccessExpression, + isEnumDeclaration, isExportDeclaration, + isExpressionStatement, isImportDeclaration, + isImportEqualsDeclaration, + isSourceFile, + isStringLiteralLike, isTypeAliasDeclaration, + setParentRecursive, + visitEachChild, +} from 'typescript'; + +import type { + Node, + SourceFile, + Statement, + TransformationContext, + Transformer, + TransformerFactory +} from 'typescript'; + +import crypto from 'crypto'; + +import type { + IBooleanOption, + IDataObfuscationOption, + INumberOption, + IStringOption +} from '../../configs/IDataObfuscationOption'; + +import type {TransformPlugin} from '../TransformPlugin'; +import type {IOptions} from '../../configs/IOptions'; +import {SimpleStringObfuscateHelper} from './SimpleStringObfuscateHelper'; +import {NodeUtils} from '../../utils/NodeUtils'; +import type {INameGenerator, NameGeneratorOptions} from '../../generator/INameGenerator'; +import {collectExistNames, isObfsIgnoreNode} from '../../utils/TransformUtil'; +import {getNameGenerator, NameGeneratorType} from '../../generator/NameFactory'; +import {BoolObfuscationHelper} from './BoolObfuscationHelper'; +import {NumberObfuscationHelper} from './NumberObfuscationHelper'; + +/** + * Data obfuscation must follow attribute name obfuscation. Because if data is obfuscated and strings are + * extracted onto arrays, attribute name obfuscation may result in some strings not being obfuscated. + */ +namespace secharmony { + const RANDOM_MAX: number = 100; + + const createDataObfuscationFactory = function (options: IOptions): TransformerFactory { + let profile: IDataObfuscationOption | undefined = options?.mDataObfuscation; + if (!profile || !profile.mEnable) { + return null; + } + + return dataObfuscationFactory; + + function dataObfuscationFactory(context: TransformationContext): Transformer { + let boolOption: IBooleanOption = profile.mBooleanOption; + let stringOption: IStringOption = profile.mStringOption; + let numberOption: INumberOption = profile.mNumberOption; + let nameGenerator: INameGenerator; + let sourceFile: SourceFile; + + return transformer; + + function transformer(node: Node): Node { + if (!isSourceFile(node) || node.fileName.endsWith('.d.ts')) { + return node; + } + + sourceFile = node; + let newNode: SourceFile = node; + + if (boolOption && boolOption.mEnable) { + newNode = doBoolTransform(newNode) as SourceFile; + } + + if (numberOption && numberOption.mEnable) { + newNode = doNumberTransform(newNode) as SourceFile; + } + + if (stringOption && stringOption.mEnable) { + const reservedNames: Set = collectExistNames(node); + const generatorOptions: NameGeneratorOptions = { + reservedNames: reservedNames + }; + + nameGenerator = getNameGenerator(NameGeneratorType.ORDERED, generatorOptions); + newNode = doStringTransform(newNode, nameGenerator); + } + + return newNode; + } + + function doBoolTransform(node: Node): Node { + if (boolOption.mSkipLoop && NodeUtils.isLoopStatement(node)) { + return node; + } + + if (!BoolObfuscationHelper.isBooleanLiteral(node)) { + return visitEachChild(node, doBoolTransform, context); + } + + // threshold check + const temp: number = crypto.randomInt(RANDOM_MAX); + if (temp > RANDOM_MAX * boolOption.mThreshold) { + return node; + } + + if (BoolObfuscationHelper.isTrueKeyword(node)) { + return BoolObfuscationHelper.createTrueObfuscation(); + } + + return BoolObfuscationHelper.createFalseObfuscation(); + } + + function doNumberTransform(node: Node): Node { + if (numberOption.mSkipLoop && NodeUtils.isLoopStatement(node)) { + return node; + } + + if (!NumberObfuscationHelper.isTargetNumberNode(node)) { + return visitEachChild(node, doNumberTransform, context); + } + + // threshold check + const temp: number = crypto.randomInt(RANDOM_MAX); + if (temp > RANDOM_MAX * numberOption.mThreshold) { + return node; + } + + return NumberObfuscationHelper.convertNumberToExpression(node); + } + + function doStringTransform(node: SourceFile, generator: INameGenerator): SourceFile { + let helper: SimpleStringObfuscateHelper = new SimpleStringObfuscateHelper(stringOption, generator); + helper.collectLiterals(node); + + sourceFile = node as SourceFile; + let source: Node = stringVisitor(node); + let newStatements: Statement[] = NodeUtils.randomInsertStatements( + NodeUtils.randomInsertStatements([...(source as SourceFile).statements], + helper.prepareIndexFunctionStruct()), + helper.prepareArrayFunctionStruct()); + + return setParentRecursive(factory.updateSourceFile(source as SourceFile, newStatements), true); + + function stringVisitor(node: Node): Node { + if (stringOption.mSkipLoop && NodeUtils.isLoopStatement(node)) { + return node; + } + + if (!isSourceFile(node) && isObfsIgnoreNode(node, sourceFile)) { + return node; + } + + // module name in import / export like statement + if ((isImportDeclaration(node) || isExportDeclaration(node)) && node.moduleSpecifier) { + return node; + } + + if (isImportEqualsDeclaration(node)) { + return node; + } + + if (isTypeAliasDeclaration(node)) { + return node; + } + + // TS18033: Only numeric enums can have computed members, but this expression has type 'string'. If + // you do not need exhaustiveness checks, consider using an object literal instead. + if (isEnumDeclaration(node)) { + return node; + } + + if (!isStringLiteralLike(node)) { + return visitEachChild(node, stringVisitor, context); + } + + if (isExpressionStatement(node.parent)) { + return node; + } + + if (stringOption.mSkipProperty && isElementAccessExpression(node.parent)) { + return node; + } + + if (stringOption.mReservedStrings && stringOption.mReservedStrings.includes(node.text)) { + return node; + } + + if (!helper.isTargetStr(node.text)) { + return node; + } + + if (!NodeUtils.isExtractableString(node)) { + return visitEachChild(node, stringVisitor, context); + } + + let prob: number = Math.random(); + if (prob > stringOption.mThreshold) { + return node; + } + + return helper.prepareReplaceStruct(node); + } + } + } + }; + + const TRANSFORMER_ORDER: number = 8; + export let transformerPlugin: TransformPlugin = { + 'name': 'Data Obfuscation', + 'order': (1 << TRANSFORMER_ORDER), + 'createTransformerFactory': createDataObfuscationFactory + }; +} + +export = secharmony; diff --git a/arkguard/src/transformers/data/NumberObfuscationHelper.ts b/arkguard/src/transformers/data/NumberObfuscationHelper.ts new file mode 100644 index 0000000000000000000000000000000000000000..33063625ce74858cf236ba9984d83f9ad92edfe3 --- /dev/null +++ b/arkguard/src/transformers/data/NumberObfuscationHelper.ts @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {factory, isNumericLiteral, isPropertyAssignment, SyntaxKind} from 'typescript'; +import type {BinaryExpression, Node} from 'typescript'; +import {randomInt} from 'crypto'; + +export class NumberObfuscationHelper { + /** + * ignore number like property in object + * let xxx = { + * 0: 13-1, + * 1: 1212, + * } + * + * @param node + */ + public static isTargetNumberNode(node: Node): boolean { + if (!isNumericLiteral(node)) { + return false; + } + + if (node.parent && isPropertyAssignment(node.parent)) { + return node.parent.name !== node; + } + + return true; + } + + public static convertNumberToExpression(node: Node): Node { + if (!isNumericLiteral(node)) { + return node; + } + + const originNumber: number = Number(node.text); + if (this.isUnsafeNumber(originNumber)) { + return node; + } + + const [intPart, decimalPart] = this.extractIntegerAndDecimalParts(originNumber); + + // split intPart + const MIN_RANDOM = 0xff; + const MAX_RIGHT_RANDOM = 0x1fff; + const randomLeft: number = randomInt(MIN_RANDOM, MAX_RIGHT_RANDOM); + const randomRight: number = intPart - randomLeft; + + const MAX_LEFT_LEFT_RANDOM = 0xfff; + const randomLeftLeft: number = randomInt(MIN_RANDOM, MAX_LEFT_LEFT_RANDOM); + const randomLeftRight: number = randomLeft - randomLeftLeft; + + const leftPartExpression: BinaryExpression = factory.createBinaryExpression( + factory.createBinaryExpression( + factory.createNumericLiteral(this.toHexString(randomLeftLeft)), + SyntaxKind.BarToken, + factory.createNumericLiteral(this.toHexString(randomLeftRight)) + ), + SyntaxKind.PlusToken, + factory.createBinaryExpression( + factory.createNumericLiteral(this.toHexString(randomLeftLeft)), + SyntaxKind.AmpersandToken, + factory.createNumericLiteral(this.toHexString(randomLeftRight)) + ) + ); + + const intPartExpression: BinaryExpression = factory.createBinaryExpression( + leftPartExpression, + SyntaxKind.PlusToken, + factory.createNumericLiteral(this.toHexString(randomRight)) + ); + + if (decimalPart) { + return factory.createParenthesizedExpression( + factory.createBinaryExpression( + intPartExpression, + SyntaxKind.PlusToken, + factory.createNumericLiteral(decimalPart) + )); + } + + return factory.createParenthesizedExpression(intPartExpression); + } + + public static extractIntegerAndDecimalParts(number: number): [number, number | null] { + const integerPart: number = Math.trunc(number); + const decimalPart: number | null = number !== integerPart ? number % 1 : null; + + return [integerPart, decimalPart]; + } + + public static isUnsafeNumber(number: number): boolean { + if (isNaN(number)) { + return true; + } + + return number < Number.MIN_SAFE_INTEGER || number > Number.MAX_SAFE_INTEGER; + } + + public static toHexString(value: number): string { + const HEX_RADIX = 16; + if (value > 0) { + return '0x' + value.toString(HEX_RADIX); + } + + const absValue: number = Math.abs(value); + return '-0x' + absValue.toString(HEX_RADIX); + } +} diff --git a/arkguard/src/transformers/data/SimpleStringObfuscateHelper.ts b/arkguard/src/transformers/data/SimpleStringObfuscateHelper.ts new file mode 100644 index 0000000000000000000000000000000000000000..e4eda5c80216206b4b474319540cd88858109159 --- /dev/null +++ b/arkguard/src/transformers/data/SimpleStringObfuscateHelper.ts @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + factory, + forEachChild, + isStringLiteralLike, + NodeFlags, +} from 'typescript'; + +import type { + CallExpression, + Expression, + FunctionDeclaration, + Node, + ParameterDeclaration, + ReturnStatement, + SourceFile, Statement, + StringLiteralLike, + VariableDeclaration, + VariableStatement +} from 'typescript'; + +import {createStringUnit, EncryptType} from './StringUnit'; +import type {StringUnit} from './StringUnit'; +import type {IStringOption} from '../../configs/IDataObfuscationOption'; +import {Base64Helper} from '../../utils/EncryptedUtils'; +import {NodeUtils} from '../../utils/NodeUtils'; +import type {INameGenerator} from '../../generator/INameGenerator'; + +export class SimpleStringObfuscateHelper { + private stringUnits: Map; + + private stringArray: string[]; + + private profile: IStringOption; + + private readonly arrayFuncName: string; + + private readonly indexFuncName: string; + + private readonly mNameGenerator: INameGenerator; + + public constructor(option: IStringOption, generator: INameGenerator) { + this.profile = option; + this.stringUnits = new Map(); + this.stringArray = []; + this.mNameGenerator = generator; + this.arrayFuncName = this.mNameGenerator.getName(); + this.indexFuncName = this.mNameGenerator.getName(); + } + + public collectLiterals(sourceFile: SourceFile): void { + let visit = (node: Node): void => { + if (!isStringLiteralLike(node)) { + forEachChild(node, visit); + return; + } + + // filter octal encode string + let code: string = NodeUtils.printNode(node, sourceFile); + const MIN_OCTAL_LEN: number = 3; + const ZERO_INDEX = 2; + if (code.length >= MIN_OCTAL_LEN && code[1].startsWith('\\') && code[ZERO_INDEX].startsWith('0')) { + return; + } + + // extract all + let content: string = node.text; + if (!content) { + return; + } + + if (this.stringUnits.has(content)) { + let unit: StringUnit = this.stringUnits.get(content); + unit.nodeList.push(node); + } else { + let unit: StringUnit = createStringUnit(node); + if (this.profile.mEncryptType === EncryptType.BASE64) { + let encrypted: string = new Base64Helper().encode(content); + if (encrypted) { + unit.encryptContent = encrypted; + } else { + return; + } + } + + this.stringArray.push(unit.encryptContent); + this.stringUnits.set(content, unit); + } + + forEachChild(node, visit); + }; + + visit(sourceFile); + } + + public prepareReplaceStruct(literal: StringLiteralLike): Node { + let stringUnit: StringUnit = this.stringUnits.get(literal.text); + if (!stringUnit) { + return literal; + } + + let index: number = this.stringArray.indexOf(stringUnit.encryptContent); + if (index < 0) { + return literal; + } + + return factory.createCallExpression( + factory.createIdentifier(this.indexFuncName), + undefined, + [factory.createNumericLiteral(index)] + ); + } + + public prepareArrayFunctionStruct(): FunctionDeclaration { + let statements: Statement[] = []; + + // string nodes in array + let arrNodes: Expression[] = []; + this.stringArray.forEach((element) => { + arrNodes.push(factory.createStringLiteral(element)); + }); + + let arrName: string = this.mNameGenerator.getName(); + let arrStruct: VariableDeclaration = factory.createVariableDeclaration( + factory.createIdentifier(arrName), + undefined, + undefined, + factory.createArrayLiteralExpression( + arrNodes, + true + ) + ); + + let arrFuncStruct: VariableDeclaration = factory.createVariableDeclaration( + factory.createIdentifier(this.arrayFuncName), + undefined, + undefined, + factory.createFunctionExpression( + undefined, + undefined, + undefined, + undefined, + [], + undefined, + factory.createBlock( + [factory.createReturnStatement(factory.createIdentifier(arrName))], + true + ) + ) + ); + + let declarationStatement: VariableStatement = factory.createVariableStatement(undefined, + factory.createVariableDeclarationList([arrStruct, arrFuncStruct], NodeFlags.Const)); + statements.push(declarationStatement); + + let callExpr: CallExpression = factory.createCallExpression( + factory.createIdentifier(this.arrayFuncName), + undefined, + [] + ); + + let returnStatement: ReturnStatement = factory.createReturnStatement(callExpr); + statements.push(returnStatement); + + return factory.createFunctionDeclaration( + undefined, + undefined, + undefined, + factory.createIdentifier(this.arrayFuncName), + undefined, + [], + undefined, + factory.createBlock(statements, true) + ); + } + + public prepareIndexFunctionStruct(): FunctionDeclaration { + let statements: Statement[] = []; + let indexName: string = this.mNameGenerator.getName(); + let arrName: string = this.mNameGenerator.getName(); + + let arrStruct: VariableDeclaration = factory.createVariableDeclaration( + factory.createIdentifier(arrName), + undefined, + undefined, + factory.createCallExpression( + factory.createIdentifier(this.arrayFuncName), + undefined, + [] + )); + + let indexFuncStruct: VariableDeclaration = factory.createVariableDeclaration( + factory.createIdentifier(this.indexFuncName), + undefined, + undefined, + factory.createFunctionExpression( + undefined, + undefined, + undefined, + undefined, + [factory.createParameterDeclaration( + undefined, + undefined, + undefined, + factory.createIdentifier(indexName), + undefined, + undefined, + undefined, + )], + undefined, + factory.createBlock( + [ + factory.createReturnStatement(factory.createElementAccessExpression( + factory.createIdentifier(arrName), + factory.createIdentifier(indexName), + )) + ] + ) + ) + ); + + let declaration: VariableStatement = factory.createVariableStatement( + undefined, + factory.createVariableDeclarationList( + [ + arrStruct, + indexFuncStruct, + ], + NodeFlags.Const + )); + statements.push(declaration); + + let callExpr: CallExpression = factory.createCallExpression( + factory.createIdentifier(this.indexFuncName), + undefined, + [factory.createIdentifier(indexName)]); + + if (this.profile.mEncryptType === EncryptType.BASE64) { + let decryptName: string = this.mNameGenerator.getName(); + let decryptStruct: Statement = this.prepareDecryptFuncStruct(decryptName); + statements.push(decryptStruct); + callExpr = factory.createCallExpression(factory.createIdentifier(decryptName), undefined, [callExpr]); + } + + let returnStatement: ReturnStatement = factory.createReturnStatement(callExpr); + statements.push(returnStatement); + + let paramStruct: ParameterDeclaration = factory.createParameterDeclaration( + undefined, + undefined, + undefined, + factory.createIdentifier(indexName), + undefined, + undefined, + undefined + ); + + return factory.createFunctionDeclaration( + undefined, + undefined, + undefined, + factory.createIdentifier(this.indexFuncName), + undefined, + [paramStruct], + undefined, + factory.createBlock(statements, true)); + } + + public isTargetStr(str: string): boolean { + return this.stringUnits.has(str); + } + + public prepareDecryptFuncStruct(name: string): Statement { + let names: string[] = []; + + names.push(name); + names.push(this.mNameGenerator.getName()); + names.push(this.mNameGenerator.getName()); + names.push(this.mNameGenerator.getName()); + names.push(this.mNameGenerator.getName()); + names.push(this.mNameGenerator.getName()); + names.push(this.mNameGenerator.getName()); + names.push(this.mNameGenerator.getName()); + names.push(this.mNameGenerator.getName()); + + return new Base64Helper().decodeStruct(names); + } +} diff --git a/arkguard/src/transformers/data/StringUnit.ts b/arkguard/src/transformers/data/StringUnit.ts new file mode 100644 index 0000000000000000000000000000000000000000..45999ae1cdfd7d5d1ee7a2552774797ce99dbd6f --- /dev/null +++ b/arkguard/src/transformers/data/StringUnit.ts @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import type {Node, StringLiteralLike} from 'typescript'; + +export enum EncryptType { + NONE = 0, + BASE64 = 1, + RC4 = 2, + AES256 = 3, +} + +export interface StringUnit { + // content of a string unit + 'content': string, + // order of string in array + 'order': number; + // related node list of current string unit + 'nodeList': Node[]; + // encrypt algorithm for string + 'encryptAlgo': EncryptType; + // content after encryption. + 'encryptContent': string; +} + +export function createStringUnit(node: StringLiteralLike, index: number = -1): StringUnit { + return { + content: node.text, + order: index, + nodeList: [node], + encryptAlgo: EncryptType.NONE, + encryptContent: node.text, + }; +} diff --git a/arkguard/src/transformers/instruction/InstructionObfsHelper.ts b/arkguard/src/transformers/instruction/InstructionObfsHelper.ts new file mode 100644 index 0000000000000000000000000000000000000000..8a01e81b002e1014b67e87e71d21bf369f022c58 --- /dev/null +++ b/arkguard/src/transformers/instruction/InstructionObfsHelper.ts @@ -0,0 +1,678 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + factory, + NodeFlags, + SyntaxKind, +} from 'typescript'; + +import type { + BinaryExpression, + Block, + CallExpression, + Expression, + FunctionExpression, + Identifier, + ObjectLiteralExpression, + ParameterDeclaration, + ParenthesizedExpression, + PropertyAssignment, + VariableStatement +} from 'typescript'; + +import * as crypto from 'crypto'; +import type {INameGenerator} from '../../generator/INameGenerator'; +import {NodeUtils} from '../../utils/NodeUtils'; + +export class InstructionHelper { + private readonly mArgcFuncMap: Map; + private readonly mReservedIdentifiers: Set; + private readonly mNameGenerator: INameGenerator; + + constructor(nameGenerator: INameGenerator) { + this.mArgcFuncMap = new Map(); + this.mReservedIdentifiers = new Set(); + this.mNameGenerator = nameGenerator; + } + + /** + * ignore deform for special function call + * @param callExpression + * @private + */ + private isSpecialFunctionCall(callExpression: CallExpression): boolean { + return callExpression.expression.kind === SyntaxKind.SuperKeyword; + } + + /** + * deform call expression, only support function of identifier expression + * @param callExpression + * @param varName + * @param pairArray + */ + public deformCallExpression(callExpression: CallExpression, varName: string, pairArray: PropertyAssignment[]): CallExpression { + if (this.isSpecialFunctionCall(callExpression)) { + return callExpression; + } + + // parse the information in the original instruction: function name, parameter list, and number of parameters + const argsCount: number = callExpression.arguments.length; + + for (const arg of callExpression.arguments) { + if (arg.kind === SyntaxKind.Identifier) { + this.mReservedIdentifiers.add((arg as Identifier).text); + } + } + + const funcName: Expression = {...callExpression.expression}; + + // if there is no deformation function corresponding to the number of parameters, + // generate a new pair, add it to the pairArray, and update the argcMap + if (this.mArgcFuncMap.get(argsCount) === undefined) { + const newPair: PropertyAssignment = this.createPair(argsCount); + pairArray.push(newPair); + } + + // query the corresponding deformation function name in argcMap and deform callExpression + return factory.createCallExpression( + factory.createElementAccessExpression( + factory.createIdentifier(varName), + factory.createStringLiteral(this.mArgcFuncMap.get(argsCount)) + ), + undefined, + [ + funcName, + ...callExpression.arguments + ] + ); + } + + public getReservedIdentifiers(): Set { + return this.mReservedIdentifiers; + } + + public createPair(argsCount: number): PropertyAssignment { + const key: string = this.mNameGenerator.getName(); + this.mArgcFuncMap.set(argsCount, key); + + return factory.createPropertyAssignment( + factory.createStringLiteral(key), + this.createFunc(argsCount) + ); + } + + private createFunc(argsCount: number): FunctionExpression { + let parametersList: ParameterDeclaration[] = []; + let parameterNameList: string[] = []; + + // 1. create function parameter + for (let i = 0; i < argsCount + 1; i++) { + const parameterName: string = this.mNameGenerator.getName(); + parameterNameList.push(parameterName); + + const funcParameter: ParameterDeclaration = factory.createParameterDeclaration( + undefined, + undefined, + undefined, + factory.createIdentifier(parameterName) + ); + parametersList.push(funcParameter); + } + + // 2. create call expression parameter + const callParametersList: Identifier[] = []; + for (let i = 1; i < argsCount + 1; i++) { + callParametersList.push(factory.createIdentifier(parameterNameList[i])); + } + + // 3. create function body + const funcBlock: Block = factory.createBlock( + [ + factory.createReturnStatement( + factory.createCallExpression( + factory.createIdentifier(parameterNameList[0]), + undefined, + callParametersList + ) + ) + ], + true + ); + + return factory.createFunctionExpression( + undefined, + undefined, + undefined, + undefined, + parametersList, + undefined, + funcBlock + ); + } + + public createCallMapStatement(varName: string, pairArray: PropertyAssignment[]): VariableStatement { + const value: ObjectLiteralExpression = this.createCallMapValue(pairArray); + + return factory.createVariableStatement( + undefined, + factory.createVariableDeclarationList( + [ + factory.createVariableDeclaration( + factory.createIdentifier(varName), + undefined, + undefined, + value + ) + ], + NodeFlags.Const + ) + ); + } + + private createCallMapValue(pairArray: PropertyAssignment[]): ObjectLiteralExpression { + return factory.createObjectLiteralExpression( + pairArray, + true + ); + } + + public obfuscateBinaryExpression(binaryExpression: BinaryExpression): Expression { + switch (binaryExpression.operatorToken.kind) { + case SyntaxKind.MinusToken: + return this.createMinusMBA(binaryExpression); + case SyntaxKind.CaretToken: + // a^b + return this.createCaretMBA(binaryExpression); + case SyntaxKind.BarToken: + // a|b + return this.createBarMBA(binaryExpression); + case SyntaxKind.AmpersandToken: + // a&b + return this.createAmpersandMBA(binaryExpression); + default: + return binaryExpression; + } + } + + private createMinusMBA(minusExpression: BinaryExpression): BinaryExpression { + /** + * decimal part: x - y + Math.truc(y) - Math.trunc(x) + */ + function getDecimalMinus(): BinaryExpression { + return factory.createBinaryExpression( + factory.createBinaryExpression( + factory.createBinaryExpression( + {...minusExpression.left}, + SyntaxKind.MinusToken, + {...minusExpression.right} + ), + SyntaxKind.PlusToken, + NodeUtils.createTruncExpression(minusExpression.right) + ), + SyntaxKind.MinusToken, + NodeUtils.createTruncExpression(minusExpression.left) + ); + } + + /** + * get minus expression of higher 32 bit + * trunc(x) - (x|0) - trunc(y) + (y|0) + */ + function getHigh32Minus(): BinaryExpression { + return factory.createBinaryExpression( + factory.createBinaryExpression( + factory.createBinaryExpression( + NodeUtils.createTruncExpression(minusExpression.left), + SyntaxKind.MinusToken, + NodeUtils.createLowerExpression(minusExpression.left) + ), + SyntaxKind.MinusToken, + NodeUtils.createTruncExpression(minusExpression.right) + ), + SyntaxKind.PlusToken, + NodeUtils.createLowerExpression(minusExpression.right) + ); + } + + /** + * x - y = (x|0) + ((y^-1) + 1), for lower 32 bit + */ + function method1(): BinaryExpression { + const right: ParenthesizedExpression = factory.createParenthesizedExpression( + factory.createBinaryExpression( + factory.createParenthesizedExpression( + factory.createBinaryExpression( + {...minusExpression.right}, + SyntaxKind.CaretToken, + factory.createPrefixUnaryExpression( + SyntaxKind.MinusToken, + factory.createNumericLiteral('1') + ) + ) + ), + SyntaxKind.PlusToken, + factory.createNumericLiteral('1') + ) + ); + + return factory.createBinaryExpression( + NodeUtils.createLowerExpression(minusExpression.left), + SyntaxKind.PlusToken, + right + ); + } + + /** + * x - y = (x ^ (~y+1)) - ((-2*x - 1) | (2*y - 1)) - 1 + */ + function method2(): BinaryExpression { + const first: ParenthesizedExpression = factory.createParenthesizedExpression( + factory.createBinaryExpression( + {...minusExpression.left}, + SyntaxKind.CaretToken, + factory.createParenthesizedExpression( + factory.createBinaryExpression( + factory.createPrefixUnaryExpression( + SyntaxKind.TildeToken, + {...minusExpression.right} + ), + SyntaxKind.PlusToken, + factory.createNumericLiteral('1') + ) + ) + ) + ); + + const secondLeft: BinaryExpression = factory.createBinaryExpression( + factory.createBinaryExpression( + factory.createPrefixUnaryExpression( + SyntaxKind.MinusToken, + factory.createNumericLiteral('2') + ), + SyntaxKind.AsteriskToken, + NodeUtils.createLowerExpression(minusExpression.left) + ), + SyntaxKind.MinusToken, + factory.createNumericLiteral('1') + ); + + const secondRight: BinaryExpression = factory.createBinaryExpression( + factory.createBinaryExpression( + factory.createNumericLiteral('2'), + SyntaxKind.AsteriskToken, + NodeUtils.createLowerExpression(minusExpression.right) + ), + SyntaxKind.MinusToken, + factory.createNumericLiteral('1') + ); + + const second: ParenthesizedExpression = factory.createParenthesizedExpression( + factory.createBinaryExpression( + factory.createParenthesizedExpression(secondLeft), + SyntaxKind.BarToken, + factory.createParenthesizedExpression(secondRight) + ) + ); + + return factory.createBinaryExpression( + factory.createBinaryExpression( + first, + SyntaxKind.MinusToken, + second + ), + SyntaxKind.MinusToken, + factory.createNumericLiteral('1') + ); + } + + /** + * x - y = (x & ~y) - (~x & y) + */ + function method3(): BinaryExpression { + const left: ParenthesizedExpression = factory.createParenthesizedExpression( + factory.createBinaryExpression( + {...minusExpression.left}, + SyntaxKind.AmpersandToken, + factory.createPrefixUnaryExpression( + SyntaxKind.TildeToken, + {...minusExpression.right} + ) + ) + ); + + const right: ParenthesizedExpression = factory.createParenthesizedExpression( + factory.createBinaryExpression( + factory.createPrefixUnaryExpression( + SyntaxKind.TildeToken, + {...minusExpression.left} + ), + SyntaxKind.AmpersandToken, + {...minusExpression.right} + ) + ); + + return factory.createBinaryExpression( + left, + SyntaxKind.MinusToken, + right + ); + } + + /** + * x - y = ~(~x + y) + */ + function method4(): Expression { + const inner: BinaryExpression = factory.createBinaryExpression( + factory.createPrefixUnaryExpression( + SyntaxKind.TildeToken, + {...minusExpression.left} + ), + SyntaxKind.PlusToken, + NodeUtils.createLowerExpression(minusExpression.right) + ); + + return factory.createPrefixUnaryExpression( + SyntaxKind.TildeToken, + factory.createParenthesizedExpression(inner) + ); + } + + const methodList: (() => Expression)[] = [method1, method2, method3, method4]; + const mbaMethod: () => Expression = methodList[crypto.randomInt(methodList.length)]; + + const decimalPart: BinaryExpression = getDecimalMinus(); + const highPart: BinaryExpression = getHigh32Minus(); + + return factory.createBinaryExpression( + factory.createBinaryExpression( + mbaMethod(), + SyntaxKind.PlusToken, + highPart + ), + SyntaxKind.PlusToken, + decimalPart + ); + } + + private createCaretMBA(xorExpression: BinaryExpression): BinaryExpression { + /** + * x ^ y = (x | y) - (x & y) + */ + function method1(): BinaryExpression { + const left: ParenthesizedExpression = factory.createParenthesizedExpression( + factory.createBinaryExpression( + {...xorExpression.left}, + SyntaxKind.BarToken, + {...xorExpression.right} + ) + ); + + const right: ParenthesizedExpression = factory.createParenthesizedExpression( + factory.createBinaryExpression( + {...xorExpression.left}, + SyntaxKind.AmpersandToken, + {...xorExpression.right} + ) + ); + + return factory.createBinaryExpression( + left, + SyntaxKind.MinusToken, + right + ); + } + + /** + * x ^ y = x + y - 2*(x & y) + */ + function method2(): BinaryExpression { + const left: BinaryExpression = factory.createBinaryExpression( + NodeUtils.createLowerExpression(xorExpression.left), + SyntaxKind.PlusToken, + NodeUtils.createLowerExpression(xorExpression.right) + ); + + const right: BinaryExpression = factory.createBinaryExpression( + factory.createNumericLiteral('2'), + SyntaxKind.AsteriskToken, + factory.createParenthesizedExpression( + factory.createBinaryExpression( + {...xorExpression.left}, + SyntaxKind.AmpersandToken, + {...xorExpression.right} + ) + ) + ); + + return factory.createBinaryExpression( + left, + SyntaxKind.MinusToken, + right + ); + } + + const methodList: (() => BinaryExpression)[] = [method1, method2]; + const mbaMethod: () => BinaryExpression = methodList[crypto.randomInt(methodList.length)]; + return mbaMethod(); + } + + private createBarMBA(orExpression: BinaryExpression): BinaryExpression { + /** + * x | y = (x ^ y) ^ (x & y) + */ + function method1(): BinaryExpression { + const left: ParenthesizedExpression = factory.createParenthesizedExpression( + factory.createBinaryExpression( + {...orExpression.left}, + SyntaxKind.CaretToken, + {...orExpression.right} + ) + ); + + const right: ParenthesizedExpression = factory.createParenthesizedExpression( + factory.createBinaryExpression( + {...orExpression.left}, + SyntaxKind.AmpersandToken, + {...orExpression.right} + ) + ); + + return factory.createBinaryExpression( + left, + SyntaxKind.CaretToken, + right + ); + } + + /** + * x | y = x + y - (x & y) + */ + function method2(): BinaryExpression { + const left: BinaryExpression = factory.createBinaryExpression( + NodeUtils.createLowerExpression(orExpression.left), + SyntaxKind.PlusToken, + NodeUtils.createLowerExpression(orExpression.right) + ); + + const right: ParenthesizedExpression = factory.createParenthesizedExpression( + factory.createBinaryExpression( + {...orExpression.left}, + SyntaxKind.AmpersandToken, + {...orExpression.right} + ) + ); + + return factory.createBinaryExpression( + left, + SyntaxKind.MinusToken, + right + ); + } + + /** + * x | y = (x & y) | (x ^ y) + */ + function method3(): BinaryExpression { + const left: ParenthesizedExpression = factory.createParenthesizedExpression( + factory.createBinaryExpression( + {...orExpression.left}, + SyntaxKind.AmpersandToken, + {...orExpression.right} + ) + ); + + const right: ParenthesizedExpression = factory.createParenthesizedExpression( + factory.createBinaryExpression( + {...orExpression.left}, + SyntaxKind.CaretToken, + {...orExpression.right} + ) + ); + + return factory.createBinaryExpression( + left, + SyntaxKind.BarToken, + right + ); + } + + const methodList: (() => BinaryExpression)[] = [method1, method2, method3]; + const mbaMethod: () => BinaryExpression = methodList[crypto.randomInt(methodList.length)]; + return mbaMethod(); + } + + private createAmpersandMBA(andExpression: BinaryExpression): Expression { + /** + * x & y = ~(~x | ~y) + */ + function method1(): Expression { + const inner: BinaryExpression = factory.createBinaryExpression( + factory.createPrefixUnaryExpression( + SyntaxKind.TildeToken, + {...andExpression.left} + ), + SyntaxKind.BarToken, + factory.createPrefixUnaryExpression( + SyntaxKind.TildeToken, + {...andExpression.right} + ) + ); + + return factory.createPrefixUnaryExpression( + SyntaxKind.TildeToken, + factory.createParenthesizedExpression( + inner + ) + ); + } + + /** + * x & y = x + y - (x | y) + */ + function method2(): BinaryExpression { + const left: BinaryExpression = factory.createBinaryExpression( + NodeUtils.createLowerExpression(andExpression.left), + SyntaxKind.PlusToken, + NodeUtils.createLowerExpression(andExpression.right) + ); + + const right: ParenthesizedExpression = factory.createParenthesizedExpression( + factory.createBinaryExpression( + {...andExpression.left}, + SyntaxKind.BarToken, + {...andExpression.right} + ) + ); + + return factory.createBinaryExpression( + left, + SyntaxKind.MinusToken, + right + ); + } + + /** + * x & y = (x | y) - (~x & y) - (x & ~y) + */ + function method3(): BinaryExpression { + const first: ParenthesizedExpression = factory.createParenthesizedExpression( + factory.createBinaryExpression( + {...andExpression.left}, + SyntaxKind.BarToken, + {...andExpression.right} + ) + ); + + const second: ParenthesizedExpression = factory.createParenthesizedExpression( + factory.createBinaryExpression( + factory.createPrefixUnaryExpression( + SyntaxKind.TildeToken, + {...andExpression.left} + ), + SyntaxKind.AmpersandToken, + {...andExpression.right} + ) + ); + + const third: ParenthesizedExpression = factory.createParenthesizedExpression( + factory.createBinaryExpression( + {...andExpression.left}, + SyntaxKind.AmpersandToken, + factory.createPrefixUnaryExpression( + SyntaxKind.TildeToken, + {...andExpression.right} + ) + ) + ); + + return factory.createBinaryExpression( + factory.createBinaryExpression( + first, + SyntaxKind.MinusToken, + second + ), + SyntaxKind.MinusToken, + third + ); + } + + /** + * x & y = (x ^ ~y) & x + */ + function method4(): BinaryExpression { + const left: ParenthesizedExpression = factory.createParenthesizedExpression( + factory.createBinaryExpression( + {...andExpression.left}, + SyntaxKind.CaretToken, + factory.createPrefixUnaryExpression( + SyntaxKind.TildeToken, + {...andExpression.right} + ) + ) + ); + + return factory.createBinaryExpression( + left, + SyntaxKind.AmpersandToken, + {...andExpression.left} + ); + } + + const methodList: (() => Expression)[] = [method1, method2, method3, method4]; + const mbaMethod: () => Expression = methodList[crypto.randomInt(methodList.length)]; + return mbaMethod(); + } +} diff --git a/arkguard/src/transformers/instruction/InstructionObfuscationTransformer.ts b/arkguard/src/transformers/instruction/InstructionObfuscationTransformer.ts new file mode 100644 index 0000000000000000000000000000000000000000..e2ed2843e28235324b84bbd6ae7b635ff06d82a3 --- /dev/null +++ b/arkguard/src/transformers/instruction/InstructionObfuscationTransformer.ts @@ -0,0 +1,398 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as crypto from 'crypto'; + +import { + factory, + isBinaryExpression, + isCallExpression, + isDecorator, + isElementAccessExpression, + isIdentifier, + isPropertyAccessExpression, + isSourceFile, + NodeFlags, + setParentRecursive, + SyntaxKind, + visitEachChild +} from 'typescript'; + +import type { + BinaryExpression, + BinaryOperator, + Block, + CallExpression, + CaseOrDefaultClause, + Expression, + FunctionDeclaration, + Identifier, + Node, + ParameterDeclaration, + PropertyAccessExpression, + PropertyAssignment, SourceFile, + Statement, SwitchStatement, + TransformationContext, + Transformer, + TransformerFactory, + VariableStatement +} from 'typescript'; + +import type {TransformPlugin} from '../TransformPlugin'; +import type {IOptions} from '../../configs/IOptions'; +import {InstructionObfsMethod} from '../../configs/IInstructionObfuscationOption'; +import type {IInstructionObfuscationOption} from '../../configs/IInstructionObfuscationOption'; +import {InstructionHelper} from './InstructionObfsHelper'; +import {NodeUtils} from '../../utils/NodeUtils'; +import {getNameGenerator, NameGeneratorType} from '../../generator/NameFactory'; +import type {INameGenerator, NameGeneratorOptions} from '../../generator/INameGenerator'; +import {collectExistNames, isObfsIgnoreNode} from '../../utils/TransformUtil'; + +namespace secharmony { + const createInstructionObfuscationFactory = function (option: IOptions): TransformerFactory { + let profile: IInstructionObfuscationOption | undefined = option?.mInstructionObfuscation; + if (!profile || !profile.mEnable || profile.mThreshold <= 0) { + return null; + } + + return instructionObfuscationFactory; + + function instructionObfuscationFactory(context: TransformationContext): Transformer { + const skipLoop: boolean = profile.mSkipLoop; + let instructionHelper: InstructionHelper; + let narrowNames: string[] = option?.mNarrowFunctionNames ?? []; + // for call expression + let varName: string; + let pairArray: PropertyAssignment[] = []; + let reservedNames: Set; + let reservedIdentifiers: Set; + let sourceFile: SourceFile; + + // for binary expression + let replaceMethod: InstructionObfsMethod = profile.mInstructionObfsMethod; + const methodTypeMap: Map = new Map(); + let deformFuncName: string; + const seed: string = '0x' + crypto.randomBytes(1).toString('hex'); + let simpleDeformed: boolean = false; + + return transformer; + + function transformer(node: Node): Node { + if (!isSourceFile(node) || node.fileName.endsWith('.d.ts')) { + return node; + } + + sourceFile = node; + reservedIdentifiers = collectExistNames(node); + + const options: NameGeneratorOptions = { + reservedNames: reservedIdentifiers + }; + const nameGenerator: INameGenerator = getNameGenerator(NameGeneratorType.ORDERED, options); + instructionHelper = new InstructionHelper(nameGenerator); + varName = nameGenerator.getName(); + deformFuncName = nameGenerator.getName(); + const functionDeclare: FunctionDeclaration = createSimpleDeformFunction(deformFuncName, seed); + + let obfuscatedAst: Node = visitAst(node); + + reservedNames = instructionHelper.getReservedIdentifiers(); + if (reservedNames.size > 0) { + obfuscatedAst = changeReservedNamesAccess(obfuscatedAst); + } + + if (!isSourceFile(obfuscatedAst)) { + return node; + } + + let newStatements: Statement[] = [...obfuscatedAst.statements]; + if (simpleDeformed) { + newStatements = NodeUtils.randomInsertStatements(newStatements, functionDeclare); + } + + if (pairArray.length > 0) { + const initStatement: VariableStatement = instructionHelper.createCallMapStatement(varName, pairArray); + newStatements = [initStatement, ...newStatements]; + } + + // must use update, don't create here, otherwise will encounter an issue for printer. + const newAst: SourceFile = factory.updateSourceFile(node, newStatements); + return setParentRecursive(newAst, true); + } + + function visitAst(node: Node): Node { + if (isDecorator(node)) { + return node; + } + + if (skipLoop && NodeUtils.isLoopStatement(node)) { + return node; + } + + if (!isSourceFile(node) && isObfsIgnoreNode(node, sourceFile)) { + return node; + } + + // only replace most inner instruction + if ((!isCallExpression(node) || !NodeUtils.isMostInnerCallExpression(node)) && + (!isBinaryExpression(node) || !NodeUtils.isMostInnerBinary(node))) { + return visitEachChild(node, visitAst, context); + } + + const newNode: BinaryExpression | CallExpression = visitEachChild(node, visitAst, context); + return replaceInstruction(newNode); + } + + /** + * change property access to element access of reserved names + * @param node + */ + function changeReservedNamesAccess(node: Node): Node { + if (!isPropertyAccessExpression(node)) { + return visitEachChild(node, changeReservedNamesAccess, context); + } + + if (!isIdentifier(node.expression)) { + return visitEachChild(node, changeReservedNamesAccess, context); + } + + if (!reservedNames.has(node.expression.escapedText.toString())) { + return node; + } + + const newNode: PropertyAccessExpression = visitEachChild(node, changeReservedNamesAccess, context); + return NodeUtils.changePropertyAccessToElementAccess(newNode); + } + + function simpleDeformBinary(binaryExpression: BinaryExpression): Expression { + if (methodTypeMap.get(binaryExpression.operatorToken.kind) === undefined) { + return binaryExpression; + } + + if (binaryExpression.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken || + binaryExpression.operatorToken.kind === SyntaxKind.BarBarToken) { + return binaryExpression; + } + + const type: string = methodTypeMap.get(binaryExpression.operatorToken.kind); + const HEX_RADIX: number = 16; + const fakeValue: number = parseInt(type, HEX_RADIX) - parseInt(seed, HEX_RADIX); + let fakeValueHexStr: string = '0x' + (Math.abs(fakeValue)).toString(HEX_RADIX); + if (fakeValue < 0) { + fakeValueHexStr = '-' + fakeValueHexStr; + } + + simpleDeformed = true; + return factory.createCallExpression( + factory.createIdentifier(deformFuncName), + undefined, + [ + {...binaryExpression.left}, + {...binaryExpression.right}, + factory.createNumericLiteral(fakeValueHexStr) + ] + ); + } + + function replaceInstruction(node: Node): Node { + // judge threshold + const RANDOM_MAX: number = 100; + const temp: number = crypto.randomInt(RANDOM_MAX); + if (temp > RANDOM_MAX * profile.mThreshold) { + return node; + } + + if (isCallExpression(node)) { + if (isPropertyAccessExpression(node.expression) || + isElementAccessExpression(node.expression) || + !isIdentifier(node.expression)) { + return node; + } + + if (narrowNames.includes((node.expression as Identifier).text)) { + return node; + } + + return instructionHelper.deformCallExpression(node, varName, pairArray); + } + + if (isBinaryExpression(node)) { + if (replaceMethod !== InstructionObfsMethod.MBA_EXPRESSION) { + return simpleDeformBinary(node); + } + + const replacedBinary: Expression = instructionHelper.obfuscateBinaryExpression(node); + if (replacedBinary !== node) { + return replacedBinary; + } + + return simpleDeformBinary(node); + } + + return node; + } + + function generateMethodTypeMap(): void { + const methodList: SyntaxKind[] = [ + SyntaxKind.PlusToken, SyntaxKind.MinusToken, SyntaxKind.AsteriskToken, + SyntaxKind.SlashToken, SyntaxKind.AmpersandToken, SyntaxKind.BarToken, + SyntaxKind.CaretToken, SyntaxKind.BarBarToken, SyntaxKind.AmpersandAmpersandToken, + SyntaxKind.EqualsEqualsToken, SyntaxKind.ExclamationEqualsToken, + SyntaxKind.EqualsEqualsEqualsToken, SyntaxKind.ExclamationEqualsEqualsToken, + SyntaxKind.LessThanToken, SyntaxKind.LessThanEqualsToken, + SyntaxKind.GreaterThanToken, SyntaxKind.GreaterThanEqualsToken, + SyntaxKind.LessThanLessThanToken, SyntaxKind.GreaterThanGreaterThanToken, + SyntaxKind.GreaterThanGreaterThanGreaterThanToken, + SyntaxKind.PercentToken, SyntaxKind.InstanceOfKeyword, + SyntaxKind.InKeyword + ]; + + const options: NameGeneratorOptions = { + hexLength: 2, + hexWithPrefixSuffix: false + }; + + const typeGenerator: INameGenerator = getNameGenerator(NameGeneratorType.HEX, options); + methodList.forEach((method) => { + methodTypeMap.set(method, '0x' + typeGenerator.getName()); + }); + } + + /** + * create simple deform function of calculate binary expression + * function parameter use common name because name obfuscate will be done after this transformer + * index transform prototype: x+y = (x|y) + (x&y) + * @param functionName + * @param seed + * @private + */ + function createSimpleDeformFunction(functionName: string, seed: string): FunctionDeclaration { + const parameters: ParameterDeclaration[] = [ + factory.createParameterDeclaration( + undefined, + undefined, + undefined, + factory.createIdentifier('left') + ), + factory.createParameterDeclaration( + undefined, + undefined, + undefined, + factory.createIdentifier('right') + ), + factory.createParameterDeclaration( + undefined, + undefined, + undefined, + factory.createIdentifier('type') + ) + ]; + + const valueDeclare: VariableStatement = factory.createVariableStatement( + undefined, + factory.createVariableDeclarationList( + [ + factory.createVariableDeclaration( + factory.createIdentifier('value'), + undefined, + undefined, + factory.createBinaryExpression( + factory.createParenthesizedExpression( + factory.createBinaryExpression( + factory.createNumericLiteral(seed), + SyntaxKind.BarToken, + factory.createIdentifier('type') + ) + ), + SyntaxKind.PlusToken, + factory.createParenthesizedExpression( + factory.createBinaryExpression( + factory.createNumericLiteral(seed), + SyntaxKind.AmpersandToken, + factory.createIdentifier('type') + ) + ) + ) + ) + ], + NodeFlags.Const + ) + ); + + const caseClauses: CaseOrDefaultClause[] = []; + generateMethodTypeMap(); + for (const method of methodTypeMap.keys()) { + caseClauses.push( + factory.createCaseClause( + factory.createNumericLiteral(methodTypeMap.get(method)), + [ + factory.createReturnStatement( + factory.createBinaryExpression( + factory.createIdentifier('left'), + method as BinaryOperator, + factory.createIdentifier('right') + ) + ) + ] + ) + ); + } + + caseClauses.push( + factory.createDefaultClause( + [ + factory.createReturnStatement( + factory.createNumericLiteral(seed) + ) + ] + ) + ); + + const switchStatement: SwitchStatement = factory.createSwitchStatement( + factory.createIdentifier('value'), + factory.createCaseBlock(caseClauses) + ); + + const body: Block = factory.createBlock( + [ + valueDeclare, + switchStatement + ], + true + ); + + return factory.createFunctionDeclaration( + undefined, + undefined, + undefined, + factory.createIdentifier(functionName), + undefined, + parameters, + undefined, + body + ); + } + } + }; + + const TRANSFORMER_ORDER: number = 5; + export let transformerPlugin: TransformPlugin = { + 'name': 'InstructionObfuscationTransformer', + 'createTransformerFactory': createInstructionObfuscationFactory, + 'order': (1 << TRANSFORMER_ORDER) + }; +} + +export = secharmony; diff --git a/arkguard/src/transformers/layout/DisableConsoleTransformer.ts b/arkguard/src/transformers/layout/DisableConsoleTransformer.ts new file mode 100644 index 0000000000000000000000000000000000000000..ee1b5fe02daf0a439f0a6c72611f5caf47fc5da3 --- /dev/null +++ b/arkguard/src/transformers/layout/DisableConsoleTransformer.ts @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + factory, + isBlock, + isCallExpression, + isElementAccessExpression, + isExpressionStatement, + isIdentifier, + isPropertyAccessExpression, + isSourceFile, + setParentRecursive, + visitEachChild +} from 'typescript'; + +import type { + Block, + LeftHandSideExpression, + Node, + NodeArray, + SourceFile, + Statement, + TransformationContext, + Transformer, + TransformerFactory +} from 'typescript'; + +import type {IOptions} from '../../configs/IOptions'; +import type {TransformPlugin} from '../TransformPlugin'; + +namespace secharmony { + const TRANSFORMER_ORDER: number = 1; + export let transformerPlugin: TransformPlugin = { + 'name': 'disableConsolePlugin', + 'order': (1 << TRANSFORMER_ORDER), + 'createTransformerFactory': createDisableConsoleFactory + }; + + export function createDisableConsoleFactory(option: IOptions): TransformerFactory { + if (!option.mDisableConsole) { + return null; + } + + return disableConsoleFactory; + + function disableConsoleFactory(context: TransformationContext): Transformer { + return transformer; + + function transformer(node: Node): Node { + if (!isSourceFile(node) || node.fileName.endsWith('.d.ts')) { + return node; + } + + let resultAst: Node = visitAst(node); + return setParentRecursive(resultAst, true); + } + + /** + * delete console log print expression, only support simple format like: + * - console.xxx(); + * - console['xxx'](); + * @param node + */ + function visitAst(node: Node): Node { + if (isSourceFile(node)) { + const visitedAst: SourceFile = visitEachChild(node, visitAst, context); + const deletedStatements: Statement[] = deleteConsoleStatement(visitedAst.statements); + + return factory.updateSourceFile(node, deletedStatements); + } + + if (!isBlock(node)) { + return visitEachChild(node, visitAst, context); + } + + const visitedBlock: Block = visitEachChild(node, visitAst, context); + const newStatements: Statement[] = deleteConsoleStatement(visitedBlock.statements); + + return factory.createBlock(newStatements, true); + } + + function deleteConsoleStatement(statements: NodeArray): Statement[] { + const reservedStatements: Statement[] = []; + statements.forEach((child) => { + if (!isSimpleConsoleStatement(child)) { + reservedStatements.push(child); + } + }); + + return reservedStatements; + } + + function isSimpleConsoleStatement(node: Statement): boolean { + if (!isExpressionStatement(node)) { + return false; + } + + if (!node.expression || !isCallExpression(node.expression)) { + return false; + } + + const expressionCalled: LeftHandSideExpression = node.expression.expression; + if (!expressionCalled) { + return false; + } + + if (isPropertyAccessExpression(expressionCalled) && expressionCalled.expression) { + if (isIdentifier(expressionCalled.expression) && expressionCalled.expression.text === 'console') { + return true; + } + } + + if (isElementAccessExpression(expressionCalled) && expressionCalled.expression) { + if (isIdentifier(expressionCalled.expression) && expressionCalled.expression.text === 'console') { + return true; + } + } + + return false; + } + } + } +} + +export = secharmony; diff --git a/arkguard/src/transformers/layout/DisableHilogTransformer.ts b/arkguard/src/transformers/layout/DisableHilogTransformer.ts new file mode 100644 index 0000000000000000000000000000000000000000..7b9193acfdbfb4ce2786cdbbca5da0d64d92d9a5 --- /dev/null +++ b/arkguard/src/transformers/layout/DisableHilogTransformer.ts @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + factory, + isBlock, + isCallExpression, + isElementAccessExpression, + isExpressionStatement, + isIdentifier, + isPropertyAccessExpression, + isSourceFile, + setParentRecursive, + visitEachChild +} from 'typescript'; + +import type { + Block, + LeftHandSideExpression, + Node, + NodeArray, + SourceFile, + Statement, + TransformationContext, + Transformer, + TransformerFactory +} from 'typescript'; + +import type {IOptions} from '../../configs/IOptions'; +import type {TransformPlugin} from '../TransformPlugin'; +import {OhPackType, isCommentedNode} from '../../utils/TransformUtil'; +import {findOhImportStatement} from '../../utils/OhsUtil'; + +namespace secharmony { + const TRANSFORMER_ORDER: number = 2; + export let transformerPlugin: TransformPlugin = { + 'name': 'disableHilogPlugin', + 'order': (1 << TRANSFORMER_ORDER), + 'createTransformerFactory': createDisableHilogFactory + }; + + export function createDisableHilogFactory(option: IOptions): TransformerFactory { + if (!option.mDisableHilog) { + return null; + } + + return disableHilogFactory; + + function disableHilogFactory(context: TransformationContext): Transformer { + let sourceFile: SourceFile; + return transformer; + + function transformer(node: Node): Node { + if (!isSourceFile(node) || node.fileName.endsWith('.d.ts')) { + return node; + } + + sourceFile = node; + let resultAst: Node = visitAst(node); + return setParentRecursive(resultAst, true); + } + + function visitAst(node: Node): Node { + if (isSourceFile(node)) { + const visitedAst: SourceFile = visitEachChild(node, visitAst, context); + const deletedStatements: Statement[] = deleteHilogStatement(visitedAst.statements); + + return factory.updateSourceFile(node, deletedStatements); + } + + if (!isBlock(node)) { + return visitEachChild(node, visitAst, context); + } + + const visitedBlock: Block = visitEachChild(node, visitAst, context); + const newStatements: Statement[] = deleteHilogStatement(visitedBlock.statements); + + return factory.createBlock(newStatements, true); + } + + function deleteHilogStatement(statements: NodeArray): Statement[] { + const reservedStatements: Statement[] = []; + statements.forEach((child) => { + if (isSimpleHilogStatement(child)) { + return; + } + + if (isHilogImportStatement(child)) { + if (isCommentedNode(child, sourceFile)) { + reservedStatements.push(child); + } + + return; + } + + reservedStatements.push(child); + }); + + return reservedStatements; + } + + function isHilogImportStatement(node: Statement): boolean { + const ohPackType: OhPackType = findOhImportStatement(node, '@ohos.hilog'); + return ohPackType !== OhPackType.NONE; + } + + function isSimpleHilogStatement(node: Statement): boolean { + if (!isExpressionStatement(node)) { + return false; + } + + if (!node.expression || !isCallExpression(node.expression)) { + return false; + } + + const expressionCalled: LeftHandSideExpression = node.expression.expression; + if (!expressionCalled) { + return false; + } + + if (isPropertyAccessExpression(expressionCalled) && expressionCalled.expression) { + if (isIdentifier(expressionCalled.expression) && expressionCalled.expression.text === 'hilog') { + return true; + } + } + + if (isElementAccessExpression(expressionCalled) && expressionCalled.expression) { + if (isIdentifier(expressionCalled.expression) && expressionCalled.expression.text === 'hilog') { + return true; + } + } + + return false; + } + } + } +} + +export = secharmony; diff --git a/arkguard/src/transformers/layout/SimplifyTransformer.ts b/arkguard/src/transformers/layout/SimplifyTransformer.ts new file mode 100644 index 0000000000000000000000000000000000000000..fbea88e0968784abf0da44165c9b0967e93dc173 --- /dev/null +++ b/arkguard/src/transformers/layout/SimplifyTransformer.ts @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + factory, + isBlock, + isExpressionStatement, + isReturnStatement, + isSourceFile, + isVariableStatement, + setParentRecursive, + SyntaxKind, + visitEachChild, + isStringLiteral, +} from 'typescript'; + +import type { + ExpressionStatement, + Node, + NodeFlags, + Statement, + TransformationContext, + Transformer, + TransformerFactory, + VariableDeclaration, + VariableStatement, + ModifiersArray, + SourceFile, + Block, + Expression +} from 'typescript'; + +import type {IOptions} from '../../configs/IOptions'; +import type {TransformPlugin} from '../TransformPlugin'; +import {isCommentedNode, isSuperCallStatement} from '../../utils/TransformUtil'; + +namespace secharmony { + const TRANSFORMER_ORDER: number = 10; + export let transformerPlugin: TransformPlugin = { + 'name': 'simplifyPlugin', + 'order': (1 << TRANSFORMER_ORDER), + 'createTransformerFactory': createSimplifyFactory + }; + + export function createSimplifyFactory(option: IOptions): TransformerFactory { + if (!option.mSimplify) { + return null; + } + + return simplifyFactory; + + function simplifyFactory(context: TransformationContext): Transformer { + const MIN_STATEMENTS_LEN = 2; + let sourceFile: SourceFile; + return transformer; + + function transformer(node: Node): Node { + if (!isSourceFile(node) || node.fileName.endsWith('.d.ts')) { + return node; + } + + sourceFile = node; + return setParentRecursive(visitStatements(node), true); + } + + function visitStatements(node: Node): Node { + if (!isSourceFile(node) && !isBlock(node)) { + return visitEachChild(node, visitStatements, context); + } + + const simplified: SourceFile | Block = visitEachChild(node, visitStatements, context); + if (node.statements.length < MIN_STATEMENTS_LEN) { + return node; + } + + return simplifyStatements(simplified); + } + + /** + * use variable statement merge and expression merge to simplify code + * @param node + */ + function simplifyStatements(node: Node): Node { + if (!isSourceFile(node) && !isBlock(node)) { + return node; + } + + let simplifiedStatements: Statement[] = []; + const continuousStatements: Statement[] = []; + let nodeFlag: NodeFlags = undefined; + let modifiers: ModifiersArray = undefined; + let preType: SyntaxKind | undefined = undefined; + + function mergeArray(): void { + if (continuousStatements.length < MIN_STATEMENTS_LEN) { + simplifiedStatements = [...simplifiedStatements, ...continuousStatements]; + return; + } + + if (preType === SyntaxKind.VariableStatement) { + simplifiedStatements.push(mergeVariableStatements(continuousStatements as VariableStatement[])); + return; + } + + if (preType === SyntaxKind.ExpressionStatement) { + simplifiedStatements.push(mergeExpression(continuousStatements as ExpressionStatement[])); + } + } + + function doMerge(currentType: SyntaxKind | undefined, child: Statement | undefined): void { + if (preType === currentType) { + if (preType !== SyntaxKind.VariableStatement) { + return; + } + + if (nodeFlag === (child as VariableStatement).declarationList.flags) { + if (!modifiers && !child.modifiers) { + return; + } + + let isSame: boolean = true; + if (modifiers && child.modifiers && modifiers.length === child.modifiers.length) { + modifiers.forEach((modifier, index) => { + if (modifier.kind !== child.modifiers[index].kind) { + isSame = false; + } + }); + } else { + isSame = false; + } + + if (isSame) { + return; + } + } + + mergeArray(); + nodeFlag = (child as VariableStatement).declarationList.flags; + modifiers = child.modifiers; + continuousStatements.length = 0; + return; + } + + if (preType === SyntaxKind.VariableStatement) { + nodeFlag = undefined; + modifiers = undefined; + mergeArray(); + } else if (preType === SyntaxKind.ExpressionStatement) { + mergeArray(); + } + + continuousStatements.length = 0; + preType = currentType; + } + + node.statements.forEach((child) => { + if (isCommentedNode(child, sourceFile) || + (isExpressionStatement(child) && isStringLiteral(child.expression)) || + isSuperCallStatement(child) + ) { + doMerge(undefined, undefined); + simplifiedStatements.push(child); + return; + } + + if (isVariableStatement(child)) { + doMerge(SyntaxKind.VariableStatement, child); + continuousStatements.push(child); + nodeFlag = child.declarationList.flags; + modifiers = child.modifiers; + return; + } + + if (isExpressionStatement(child)) { + doMerge(SyntaxKind.ExpressionStatement, child); + continuousStatements.push(child); + return; + } + + if (isReturnStatement(child) && child.expression !== undefined) { + doMerge(SyntaxKind.ExpressionStatement, child); + continuousStatements.push(child); + doMerge(undefined, undefined); + return; + } + + // do merge on continuous stopped + doMerge(undefined, child); + simplifiedStatements.push(child); + }); + + doMerge(undefined, undefined); + + if (isSourceFile(node)) { + return factory.updateSourceFile(node, simplifiedStatements); + } + + return factory.createBlock(simplifiedStatements, true); + } + + /** + * merge variable statement, need same type and same modifier variable and continuous + * @param variableStatements + */ + function mergeVariableStatements(variableStatements: VariableStatement[]): VariableStatement { + let variableDeclarations: VariableDeclaration[] = []; + variableStatements.forEach((statement) => { + variableDeclarations = [...variableDeclarations, ...statement.declarationList.declarations]; + }); + + return factory.createVariableStatement( + variableStatements[0].modifiers, + factory.createVariableDeclarationList( + variableDeclarations, + variableStatements[0].declarationList.flags + ) + ); + } + + /** + * merge expression, include: + * - continuous expression like a=a+1; b=b+1; + */ + function mergeExpression(expressionStatements: ExpressionStatement[]): Statement { + let pos: number = 1; + let expression: Expression = expressionStatements[0].expression; + const statementsLength: number = expressionStatements.length; + while (pos < statementsLength) { + expression = factory.createBinaryExpression( + expression, + SyntaxKind.CommaToken, + expressionStatements[pos].expression + ); + pos += 1; + } + + if (isReturnStatement(expressionStatements[statementsLength - 1])) { + return factory.createReturnStatement(expression); + } + + return factory.createExpressionStatement(expression); + } + } + } +} + +export = secharmony; diff --git a/arkguard/src/transformers/oh/HideOhApiTransformer.ts b/arkguard/src/transformers/oh/HideOhApiTransformer.ts new file mode 100644 index 0000000000000000000000000000000000000000..50ae52abd866b51987f34d159a49d680ca38c3c1 --- /dev/null +++ b/arkguard/src/transformers/oh/HideOhApiTransformer.ts @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + factory, + isBlock, + isElementAccessExpression, + isPropertyAccessExpression, + isSourceFile, + isStringLiteral, + setParentRecursive, + visitEachChild +} from 'typescript'; + +import type { + Block, + CallExpression, + Node, + NodeArray, + SourceFile, + Statement, + TransformationContext, + Transformer, + TransformerFactory +} from 'typescript'; + +import type {IOptions} from '../../configs/IOptions'; +import type {TransformPlugin} from '../TransformPlugin'; +import {collectExistNames, OhPackType} from '../../utils/TransformUtil'; +import {findOhImportStatement} from '../../utils/OhsUtil'; +import type {INameGenerator, NameGeneratorOptions} from '../../generator/INameGenerator'; +import {getNameGenerator, NameGeneratorType} from '../../generator/NameFactory'; + +namespace secharmony { + const TRANSFORMER_ORDER: number = 3; + export let transformerPlugin: TransformPlugin = { + 'name': 'hideOhApiPlugin', + 'order': (1 << TRANSFORMER_ORDER), + 'createTransformerFactory': createHideOhApiFactory + }; + + interface OhHiddenApiInfo { + moduleNames: Set, + apis: Set + } + + export function createHideOhApiFactory(option: IOptions): TransformerFactory { + if (!option.mHideOhApi || !option.mHideOhApi.mEnable) { + return null; + } + + if (!option.mHideOhApi.mProtectedApi || option.mHideOhApi.mProtectedApi.length < 1) { + return null; + } + + return hideOhApiFactory; + + function hideOhApiFactory(context: TransformationContext): Transformer { + let nameGenerator: INameGenerator; + let ohHiddenApiInfo: OhHiddenApiInfo; + + return transformer; + + function transformer(node: Node): Node { + if (!isSourceFile(node) || node.fileName.endsWith('.d.ts')) { + return node; + } + + const reservedIdentifiers: Set = collectExistNames(node); + const options: NameGeneratorOptions = { + reservedNames: reservedIdentifiers + }; + nameGenerator = getNameGenerator(NameGeneratorType.ORDERED, options); + + ohHiddenApiInfo = processOhApi(option.mHideOhApi.mProtectedApi); + + let resultAst: Node = visitAst(node); + return setParentRecursive(resultAst, true); + } + + function visitAst(node: Node): Node { + if (isSourceFile(node)) { + const hiddenNode: SourceFile = visitEachChild(node, visitAst, context); + const newStatements: Statement[] = hideStatements(hiddenNode.statements, nameGenerator, ohHiddenApiInfo, context); + return factory.updateSourceFile(hiddenNode, newStatements); + } + + if (isBlock(node)) { + const hiddenNode: Block = visitEachChild(node, visitAst, context); + const newStatements: Statement[] = hideStatements(hiddenNode.statements, nameGenerator, ohHiddenApiInfo, context); + if (newStatements === undefined) { + return hiddenNode; + } + + return factory.createBlock(newStatements, true); + } + + return visitEachChild(node, visitAst, context); + } + } + } + + function hideStatements(statements: NodeArray, nameGenerator: INameGenerator, ohHiddenApiInfo: OhHiddenApiInfo, + context: TransformationContext): Statement[] { + let newStatements: Statement[] = [...statements]; + const apiHiddenMap: Map = new Map(); + + for (let i = 0; i < statements.length; i++) { + // 1. hide api import + for (const module of ohHiddenApiInfo.moduleNames) { + const ohPackType: OhPackType = findOhImportStatement(statements[i], module); + if (ohPackType === OhPackType.NONE) { + continue; + } + + const moduleStr: string = ohPackType === OhPackType.JS_BUNDLE ? module : module.substring('@ohos.'.length); + const hiddenFuncName: string = nameGenerator.getName(); + const hiddenStatement: Statement = createHiddenStatement(hiddenFuncName, moduleStr); + + newStatements[i] = hideOhStr(statements[i], hiddenFuncName, moduleStr, context); + newStatements.push(hiddenStatement); + break; + } + + // 2. hide api + newStatements[i] = hideOhApi(newStatements[i], ohHiddenApiInfo.apis, nameGenerator, context, apiHiddenMap); + } + + for (const key of apiHiddenMap.keys()) { + newStatements.push(createHiddenStatement(apiHiddenMap.get(key), key)); + } + + return newStatements; + } + + function hideOhStr(node: Statement, hiddenFuncName: string, hiddenStr: string, context: TransformationContext): Statement { + let visit = (node: Node): Node => { + if (isStringLiteral(node) && node.text === hiddenStr) { + return factory.createCallExpression(factory.createIdentifier(hiddenFuncName), undefined, []); + } + + return visitEachChild(node, visit, context); + }; + + return visit(node) as Statement; + } + + function hideOhApi(node: Statement, apiNames: Set, nameGenerator: INameGenerator, context: TransformationContext, apiHiddenMap): Statement { + let visit = (node: Node): Node => { + if (isBlock(node)) { + return node; + } + + if (isPropertyAccessExpression(node)) { + if (!apiNames.has(node.name.text)) { + return node; + } + + const hiddenFuncName: string = apiHiddenMap.has(node.name.text) ? + apiHiddenMap.get(node.name.text) : nameGenerator.getName(); + if (!apiHiddenMap.has(node.name.text)) { + apiHiddenMap.set(node.name.text, hiddenFuncName); + } + + const hiddenCall: CallExpression = factory.createCallExpression( + factory.createIdentifier(hiddenFuncName), + undefined, + [] + ); + return factory.createElementAccessExpression(node.expression, hiddenCall); + } + + if (isElementAccessExpression(node)) { + if (!isStringLiteral(node.argumentExpression)) { + return node; + } + + if (!apiNames.has(node.argumentExpression.text)) { + return node; + } + + const hiddenFuncName: string = apiHiddenMap.has(node.argumentExpression.text) ? + apiHiddenMap.get(node.argumentExpression.text) : nameGenerator.getName(); + if (!apiHiddenMap.has(node.argumentExpression.text)) { + apiHiddenMap.set(node.argumentExpression.text, hiddenFuncName); + } + + const hiddenCall: CallExpression = factory.createCallExpression( + factory.createIdentifier(hiddenFuncName), + undefined, + []); + return factory.createElementAccessExpression(node.expression, hiddenCall); + } + + return visitEachChild(node, visit, context); + }; + + return visit(node) as Statement; + } + + /** + * process api list to get module and api function + * @param apiList + * @private + */ + function processOhApi(apiList: string[]): OhHiddenApiInfo { + let apiInfo: OhHiddenApiInfo = { + moduleNames: new Set(), + apis: new Set() + }; + + for (const api of apiList) { + // check format + const MIN_OFFSET = 2; + if (!api.startsWith('@ohos') || !api.includes('.') || api.lastIndexOf('.') > api.length - MIN_OFFSET) { + continue; + } + + // extract api + apiInfo.moduleNames.add(api.substring(0, api.lastIndexOf('.'))); + apiInfo.apis.add(api.substring(api.lastIndexOf('.') + 1)); + } + + return apiInfo; + } + + function createHiddenStatement(hiddenFuncName: string, hiddenStr: string): Statement { + return factory.createFunctionDeclaration( + undefined, + undefined, + undefined, + factory.createIdentifier(hiddenFuncName), + undefined, + [], + undefined, + factory.createBlock( + [ + factory.createReturnStatement(factory.createStringLiteral(hiddenStr)) + ], false + ) + ); + } +} + +export = secharmony; diff --git a/arkguard/src/transformers/rename/RenameIdentifierTransformer.ts b/arkguard/src/transformers/rename/RenameIdentifierTransformer.ts new file mode 100644 index 0000000000000000000000000000000000000000..b860fe5e010f0369e6c509ce5457a29bf6c1834d --- /dev/null +++ b/arkguard/src/transformers/rename/RenameIdentifierTransformer.ts @@ -0,0 +1,385 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + factory, + forEachChild, + isBreakOrContinueStatement, + isIdentifier, + isLabeledStatement, + isSourceFile, + setParentRecursive, + visitEachChild, +} from 'typescript'; + +import type { + Identifier, + Node, + SourceFile, + Symbol, + TransformationContext, + Transformer, + TransformerFactory, + TypeChecker +} from 'typescript'; + +import { + createScopeManager, + isClassScope, + isGlobalScope, + isEnumScope, + isInterfaceScope, + isObjectLiteralScope +} from '../../utils/ScopeAnalyzer'; + +import type { + Label, + Scope, + ScopeManager +} from '../../utils/ScopeAnalyzer'; + +import type {INameGenerator, NameGeneratorOptions} from '../../generator/INameGenerator'; +import type {IOptions} from '../../configs/IOptions'; +import type {INameObfuscationOption} from '../../configs/INameObfuscationOption'; +import type {TransformPlugin} from '../TransformPlugin'; +import {getNameGenerator, NameGeneratorType} from '../../generator/NameFactory'; +import {TypeUtils} from '../../utils/TypeUtils'; +import {collectIdentifiers} from '../../utils/TransformUtil'; +import {NodeUtils} from '../../utils/NodeUtils'; + +namespace secharmony { + /** + * Rename Identifiers, including: + * 1. variable name + * 2. function name + * 3. label name + * 4. class name/interface name/ label name + * we need implement some features: + * 1. rename identifiers + * 2. store/restore name to/from nameCache file. + * 3. do scope analysis for identifier obfuscations + * + * @param option + */ + const createRenameIdentifierFactory = function (option: IOptions): TransformerFactory { + const profile: INameObfuscationOption | undefined = option?.mNameObfuscation; + if (!profile || !profile.mEnable) { + return null; + } + + const openTopLevel: boolean = option?.mTopLevel; + return renameIdentifierFactory; + + function renameIdentifierFactory(context: TransformationContext): Transformer { + let reservedNames: string[] = [...(profile?.mReservedNames ?? []), 'this']; + let mangledSymbolNames: Map = new Map(); + let mangledLabelNames: Map = new Map(); + let historyMangledNames: Set = undefined; + if (historyNameCache && historyNameCache.size > 0) { + historyMangledNames = new Set(Array.from(historyNameCache.values())); + } + let options: NameGeneratorOptions = {}; + if (profile.mNameGeneratorType === NameGeneratorType.HEX) { + options.hexWithPrefixSuffix = true; + } + + let generator: INameGenerator = getNameGenerator(profile.mNameGeneratorType, options); + + let checker: TypeChecker = undefined; + let manager: ScopeManager = createScopeManager(); + let shadowIdentifiers: Identifier[] = undefined; + + let identifierIndex: number = 0; + return renameTransformer; + + /** + * Transformer to rename identifiers + * + * @param node ast node of a file. + */ + function renameTransformer(node: Node): Node { + if (!isSourceFile(node)) { + return node; + } + + const shadowSourceAst: SourceFile = TypeUtils.createNewSourceFile(node); + checker = TypeUtils.createChecker(shadowSourceAst); + manager.analyze(shadowSourceAst, checker); + + manager.getReservedNames().forEach((name) => { + reservedNames.push(name); + }); + // collect all identifiers of shadow sourceFile + shadowIdentifiers = collectIdentifiers(shadowSourceAst, context); + + if (nameCache === undefined) { + nameCache = new Map(); + } + + let root: Scope = manager.getRootScope(); + renameInScope(root); + return setParentRecursive(visit(node), true); + } + + /** + * rename symbol table store in scopes... + * + * @param scope scope, such as global, module, function, block + */ + function renameInScope(scope: Scope): void { + // process labels in scope, the label can't rename as the name of top labels. + renameLabelsInScope(scope); + // process symbols in scope, exclude property name. + renameNamesInScope(scope); + + for (const subScope of scope.children) { + renameInScope(subScope); + } + } + + function renameNamesInScope(scope: Scope): void { + if (scope.parent) { + scope.parent.mangledNames.forEach((value) => { + scope.mangledNames.add(value); + }); + + scope.parent.importNames.forEach((value) => { + scope.importNames.add(value); + }); + } + + if (isExcludeScope(scope)) { + return; + } + + scope.defs.forEach((def) => { + if (scope.importNames.has(def.name)) { + scope.defs.delete(def); + } + }); + + generator.reset(); + renames(scope, scope.defs, generator); + } + + function renames(scope: Scope, defs: Set, generator: INameGenerator): void { + const localCache: Map = new Map(); + findNoSymbolIdentifiers(scope); + + defs.forEach((def) => { + const original: string = def.name; + let mangled: string = original; + // No allow to rename reserved names. + if (reservedNames.includes(original) || scope.exportNames.has(def.name) || isSkippedGlobal(openTopLevel, scope)) { + scope.mangledNames.add(mangled); + mangledSymbolNames.set(def, mangled); + return; + } + + if (mangledSymbolNames.has(def)) { + return; + } + + const path: string = scope.loc + '#' + original; + const historyName: string = historyNameCache?.get(path); + const specifyName: string = historyName ? historyName : nameCache.get(path); + if (specifyName) { + mangled = specifyName; + } else { + const sameMangled: string = localCache.get(original); + mangled = sameMangled ? sameMangled : getMangled(scope, generator); + } + + // add new names to name cache + nameCache.set(path, mangled); + scope.mangledNames.add(mangled); + mangledSymbolNames.set(def, mangled); + localCache.set(original, mangled); + }); + } + + function isExcludeScope(scope: Scope): boolean { + if (isClassScope(scope)) { + return true; + } + + if (isInterfaceScope(scope)) { + return true; + } + + if (isEnumScope(scope)) { + return true; + } + + return isObjectLiteralScope(scope); + } + + function getMangled(scope: Scope, localGenerator: INameGenerator): string { + let mangled: string = ''; + do { + mangled = localGenerator.getName()!; + // if it is a globally reserved name, it needs to be regenerated + if (reservedNames.includes(mangled)) { + mangled = ''; + continue; + } + + if (historyMangledNames && historyMangledNames.has(mangled)) { + mangled = ''; + continue; + } + + // the anme has already been generated in the current scope + if (scope.mangledNames.has(mangled)) { + mangled = ''; + } + } while (mangled === ''); + + return mangled; + } + + function renameLabelsInScope(scope: Scope): void { + const labels: Label[] = scope.labels; + if (labels.length > 0) { + let upperMangledLabels = getUpperMangledLabelNames(labels[0]); + for (const label of labels) { + let mangledLabel = getMangledLabel(label, upperMangledLabels); + mangledLabelNames.set(label, mangledLabel); + } + } + } + + function getMangledLabel(label: Label, mangledLabels: string[]): string { + let mangledLabel: string = ''; + do { + mangledLabel = generator.getName(); + if (mangledLabel === label.name) { + mangledLabel = ''; + } + + if (mangledLabels.includes(mangledLabel)) { + mangledLabel = ''; + } + } while (mangledLabel === ''); + + return mangledLabel; + } + + function getUpperMangledLabelNames(label: Label): string[] { + const results: string[] = []; + let parent: Label = label.parent; + while (parent) { + let mangledLabelName: string = mangledLabelNames.get(parent); + if (mangledLabelName) { + results.push(mangledLabelName); + } + parent = parent.parent; + } + + return results; + } + + /** + * visit each node to change identifier name to mangled name + * - calculate shadow name index to find shadow node + * @param node + */ + function visit(node: Node): Node { + if (!isIdentifier(node) || !node.parent) { + return visitEachChild(node, visit, context); + } + + if (isLabeledStatement(node.parent) || isBreakOrContinueStatement(node.parent)) { + identifierIndex += 1; + return updateLabelNode(node); + } + + const shadowNode: Identifier = shadowIdentifiers[identifierIndex]; + identifierIndex += 1; + return updateNameNode(node, shadowNode); + } + + function findNoSymbolIdentifiers(scope: Scope): void { + const noSymbolVisit = (targetNode: Node): void => { + if (!isIdentifier(targetNode)) { + forEachChild(targetNode, noSymbolVisit); + return; + } + + // skip property in property access expression + if (NodeUtils.isPropertyAccessNode(targetNode)) { + return; + } + + const sym: Symbol | undefined = checker.getSymbolAtLocation(targetNode); + if (!sym) { + scope.mangledNames.add((targetNode as Identifier).escapedText.toString()); + } + }; + + noSymbolVisit(scope.block); + } + + function updateNameNode(node: Identifier, shadowNode: Identifier): Node { + // skip property in property access expression + if (NodeUtils.isPropertyAccessNode(node)) { + return node; + } + + const sym: Symbol | undefined = checker.getSymbolAtLocation(shadowNode); + if (!sym || sym.name === 'default') { + return node; + } + + const mangledName: string = mangledSymbolNames.get(sym); + if (!mangledName || mangledName === sym.name) { + return node; + } + + return factory.createIdentifier(mangledName); + } + + function updateLabelNode(node: Identifier): Node { + let label: Label | undefined; + let labelName: string = ''; + + mangledLabelNames.forEach((value, key) => { + if (key.refs.includes(node)) { + label = key; + labelName = value; + } + }); + + return label ? factory.createIdentifier(labelName) : node; + } + } + }; + + function isSkippedGlobal(enableTopLevel: boolean, scope: Scope): boolean { + return !enableTopLevel && isGlobalScope(scope); + } + + const TRANSFORMER_ORDER: number = 9; + export let transformerPlugin: TransformPlugin = { + 'name': 'renameIdentifierPlugin', + 'order': (1 << TRANSFORMER_ORDER), + 'createTransformerFactory': createRenameIdentifierFactory + }; + + export let nameCache: Map = undefined; + export let historyNameCache: Map = undefined; +} + +export = secharmony; diff --git a/arkguard/src/transformers/rename/RenamePropertiesTransformer.ts b/arkguard/src/transformers/rename/RenamePropertiesTransformer.ts new file mode 100644 index 0000000000000000000000000000000000000000..139540432898c04c050f460d509d68c761ab0e05 --- /dev/null +++ b/arkguard/src/transformers/rename/RenamePropertiesTransformer.ts @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + factory, + forEachChild, + isClassDeclaration, + isComputedPropertyName, + isConstructorDeclaration, + isElementAccessExpression, + isEnumMember, + isIdentifier, + isNumericLiteral, + isPrivateIdentifier, + isStringLiteralLike, + isTypeNode, + setParentRecursive, + visitEachChild +} from 'typescript'; + +import type { + ComputedPropertyName, + EnumMember, + Expression, + Identifier, + Node, + TransformationContext, + Transformer, + TransformerFactory +} from 'typescript'; + +import type {IOptions} from '../../configs/IOptions'; +import type {INameObfuscationOption} from '../../configs/INameObfuscationOption'; +import type {INameGenerator, NameGeneratorOptions} from '../../generator/INameGenerator'; +import {getNameGenerator, NameGeneratorType} from '../../generator/NameFactory'; +import type {TransformPlugin} from '../TransformPlugin'; +import {NodeUtils} from '../../utils/NodeUtils'; +import { getClassProperties, isViewPUBasedClass } from '../../utils/OhsUtil'; + +namespace secharmony { + /** + * global mangled properties table used by all files in a project + */ + export let globalMangledTable: Map = undefined; + + // used for property cache + export let historyMangledTable: Map = undefined; + + /** + * Rename Properties Transformer + * + * @param option obfuscation options + */ + const createRenamePropertiesFactory = function (option: IOptions): TransformerFactory { + let profile: INameObfuscationOption | undefined = option?.mNameObfuscation; + + if (!profile || !profile.mEnable || !profile.mRenameProperties) { + return null; + } + + return renamePropertiesFactory; + + function renamePropertiesFactory(context: TransformationContext): Transformer { + let options: NameGeneratorOptions = {}; + if (profile.mNameGeneratorType === NameGeneratorType.HEX) { + options.hexWithPrefixSuffix = true; + } + + let generator: INameGenerator = getNameGenerator(profile.mNameGeneratorType, options); + + let reservedProperties: string[] = profile?.mReservedProperties ?? []; + let reservedNamesInEnum: string[] = []; + + let currentConstructorParams: Set = new Set(); + + return renamePropertiesTransformer; + + function renamePropertiesTransformer(node: Node): Node { + collectReservedNames(node); + if (globalMangledTable === undefined) { + globalMangledTable = new Map(); + } + + let ret: Node = renameProperties(node); + return setParentRecursive(ret, true); + } + + function renameProperties(node: Node): Node { + if (isConstructorDeclaration(node)) { + currentConstructorParams.clear(); + } + + if (NodeUtils.isClassPropertyInConstructorParams(node)) { + currentConstructorParams.add((node as Identifier).escapedText.toString()); + return renameProperty(node, false); + } + + if (NodeUtils.isClassPropertyInConstructorBody(node, currentConstructorParams)) { + if (currentConstructorParams.has((node as Identifier).escapedText.toString())) { + return renameProperty(node, false); + } + } + + if (!NodeUtils.isPropertyNode(node)) { + return visitEachChild(node, renameProperties, context); + } + + if (isElementAccessExpression(node.parent)) { + return renameElementAccessProperty(node); + } + + if (isComputedPropertyName(node)) { + return renameComputedProperty(node); + } + + return renameProperty(node, false); + } + + function renameElementAccessProperty(node: Node): Node { + if (isStringLiteralLike(node)) { + return renameProperty(node, false); + } + return visitEachChild(node, renameProperties, context); + } + + function renameComputedProperty(node: ComputedPropertyName): ComputedPropertyName { + if (isStringLiteralLike(node.expression) || isNumericLiteral(node.expression)) { + let prop: Node = renameProperty(node.expression, true); + if (prop !== node.expression) { + return factory.createComputedPropertyName(prop as Expression); + } + } + + if (isIdentifier(node.expression)) { + return node; + } + + return visitEachChild(node, renameProperties, context); + } + + function renameProperty(node: Node, computeName: boolean): Node { + if (!isStringLiteralLike(node) && !isIdentifier(node) && !isPrivateIdentifier(node) && !isNumericLiteral(node)) { + return visitEachChild(node, renameProperties, context); + } + + let original: string = node.text; + if (reservedProperties.includes(original)) { + return node; + } + + let mangledName: string = getPropertyName(original); + + if (isStringLiteralLike(node)) { + return factory.createStringLiteral(mangledName); + } + + if (isNumericLiteral(node)) { + return computeName ? factory.createStringLiteral(mangledName) : factory.createIdentifier(mangledName); + + } + + if (isIdentifier(node) || isNumericLiteral(node)) { + return factory.createIdentifier(mangledName); + } + + return factory.createPrivateIdentifier('#' + mangledName); + } + + function getPropertyName(original: string): string { + const historyName: string = historyMangledTable?.get(original); + let mangledName: string = historyName ? historyName : globalMangledTable.get(original); + + while (!mangledName) { + mangledName = generator.getName(); + if (mangledName === original) { + mangledName = null; + continue; + } + + if (reservedProperties.includes(mangledName)) { + mangledName = null; + continue; + } + + let reserved: string[] = [...globalMangledTable.values()]; + if (historyMangledTable) { + reserved = [...reserved, ...historyMangledTable.values()]; + } + + if (reserved.includes(mangledName)) { + mangledName = null; + continue; + } + + if (reservedNamesInEnum.includes(mangledName)) { + mangledName = null; + } + } + globalMangledTable.set(original, mangledName); + return mangledName; + } + + // enum syntax has special scenarios + function collectReservedNames(node: Node): void { + if (!isEnumMember(node) && !isClassDeclaration(node)) { + forEachChild(node, collectReservedNames); + } + + // collect viewPU class properties + if (isClassDeclaration(node)) { + if (!isViewPUBasedClass(node)) { + return; + } + const properties = getClassProperties(node); + properties.forEach((property) => { + reservedProperties.push(property); + }); + return; + } + + // collect enum properties + let initial: Expression = (node as EnumMember).initializer; + let visit = function (child: Node): void { + if (!isIdentifier(child)) { + return; + } + + if (NodeUtils.isPropertyNode(child)) { + return; + } + + if (isTypeNode(child)) { + return; + } + reservedNamesInEnum.push(child.text); + }; + + forEachChild(initial, visit); + } + } + }; + + const TRANSFORMER_ORDER: number = 6; + export let transformerPlugin: TransformPlugin = { + 'name': 'renamePropertiesPlugin', + 'order': (1 << TRANSFORMER_ORDER), + 'createTransformerFactory': createRenamePropertiesFactory + }; +} + +export = secharmony; diff --git a/arkguard/src/transformers/rename/ShorthandPropertyTransformer.ts b/arkguard/src/transformers/rename/ShorthandPropertyTransformer.ts new file mode 100644 index 0000000000000000000000000000000000000000..819dd07638d0a9a5c8ab4d01d78add1956adf442 --- /dev/null +++ b/arkguard/src/transformers/rename/ShorthandPropertyTransformer.ts @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + factory, + isBindingElement, + isObjectBindingPattern, + isShorthandPropertyAssignment, + setParentRecursive, + visitEachChild +} from 'typescript'; + +import type { + BindingElement, + Identifier, + Node, + TransformationContext, + Transformer, + TransformerFactory +} from 'typescript'; + +import type {INameObfuscationOption} from '../../configs/INameObfuscationOption'; +import type {TransformPlugin} from '../TransformPlugin'; +import type {IOptions} from '../../configs/IOptions'; +import {NodeUtils} from '../../utils/NodeUtils'; + +namespace secharmony { + const createShorthandPropertyTransformerFactory = function (option: IOptions): TransformerFactory { + let profile: INameObfuscationOption = option.mNameObfuscation; + if (!profile || !profile.mEnable) { + return null; + } + + return shorthandPropertyTransformFactory; + + function shorthandPropertyTransformFactory(context: TransformationContext): Transformer { + return shorthandPropertyTransformer; + + function shorthandPropertyTransformer(node: Node): Node { + return setParentRecursive(transformShortHandProperty(node), true); + } + + function transformShortHandProperty(node: Node): Node { + /** + * 1. let name = 'hello'; let info = {name} + */ + if (isShorthandPropertyAssignment((node))) { + // update parent + return factory.createPropertyAssignment(factory.createIdentifier(node.name.text), node.name); + } + /** + * const { x, y } = { x: 1, y: 2 }; + * const { x: a, y: b} = { x, y } --> const {x: c, y: d} = { x: e, y: f }; + */ + if (isObjectBindingPattern(node) && NodeUtils.isObjectBindingPatternAssignment(node)) { + return node; + } + + /** + * exclude, eg {name, ...rest}= {'name': 'akira', age : 22} + * exclude, eg let [name, age] = ['akira', 22]; + */ + if (isElementsInObjectBindingPattern(node) && !node.propertyName && !node.dotDotDotToken) { + return factory.createBindingElement(node.dotDotDotToken, factory.createIdentifier((node.name as Identifier).text), + node.name, node.initializer); + } + + return visitEachChild(node, transformShortHandProperty, context); + } + + function isElementsInObjectBindingPattern(node: Node): node is BindingElement { + return node.parent && isObjectBindingPattern(node.parent) && isBindingElement(node); + } + } + }; + + const TRANSFORMER_ORDER: number = 0; + export let transformerPlugin: TransformPlugin = { + 'name': 'ShortHandPropertyTransformer', + 'order': (1 << TRANSFORMER_ORDER), + 'createTransformerFactory': createShorthandPropertyTransformerFactory, + }; +} + +export = secharmony; diff --git a/arkguard/src/utils/EncryptedUtils.ts b/arkguard/src/utils/EncryptedUtils.ts new file mode 100644 index 0000000000000000000000000000000000000000..f4e9ab9ee031afb753be92fd2f59b896b59c721d --- /dev/null +++ b/arkguard/src/utils/EncryptedUtils.ts @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {createSourceFile, ScriptTarget} from 'typescript'; +import type {Node, SourceFile, Statement} from 'typescript'; +import {NodeUtils} from './NodeUtils'; + +export abstract class BaseEncryptedHelper { + protected constructor() { + } + + public abstract encode(content: string): string; + + public abstract decode(content: string): string; + + public abstract decodeStruct(names: string[]): Node; +} + +export class Base64Helper extends BaseEncryptedHelper { + public constructor() { + super(); + } + + /** + * @param content + */ + public encode(content: string): string { + try { + return Buffer.from(encodeURIComponent(content), 'utf-8').toString('base64'); + } catch (e) { + return null; + } + } + + /** + * @param content + */ + public decode(content: string): string { + let decodedContent: string = decodeURI(content); + let _keyStr: string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; + let output: string = ''; + let chr1: number; + let chr2: number; + let chr3: number; + let enc1: number; + let enc2: number; + let enc3: number; + let enc4: number; + let i: number = 0; + + decodedContent = decodedContent.replace(/[^A-Za-z0-9\+\/\=]/g, ''); + while (i < decodedContent.length) { + enc1 = _keyStr.indexOf(decodedContent.charAt(i++)); + enc2 = _keyStr.indexOf(decodedContent.charAt(i++)); + enc3 = _keyStr.indexOf(decodedContent.charAt(i++)); + enc4 = _keyStr.indexOf(decodedContent.charAt(i++)); + chr1 = (enc1 << 2) | (enc2 >> 4); + chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); + chr3 = ((enc3 & 3) << 6) | enc4; + output = output + String.fromCharCode(chr1); + if (enc3 !== 64) { + output = output + String.fromCharCode(chr2); + } + + if (enc4 !== 64) { + output = output + String.fromCharCode(chr3); + } + } + + return decodeURIComponent(output); + } + + public decodeStruct(names: string[]): Statement { + let code: string = ` + let ${names[0]} =function (${names[1]}) { + ${names[1]} = decodeURIComponent(${names[1]}); + let ${names[2]} = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',${names[3]} = '',${names[4]} = 0; + + ${names[1]} = ${names[1]}.replace(/[^A-Za-z0-9\\+\\/\\=]/g, ''); + while (${names[4]} < ${names[1]}.length) { + let ${names[5]} = ${names[2]}.indexOf(${names[1]}.charAt(${names[4]}++)); + let ${names[6]} = ${names[2]}.indexOf(${names[1]}.charAt(${names[4]}++)); + let ${names[7]} = ${names[2]}.indexOf(${names[1]}.charAt(${names[4]}++)); + let ${names[8]} = ${names[2]}.indexOf(${names[1]}.charAt(${names[4]}++)); + ${names[3]} += String.fromCharCode((${names[5]} << 2) | (${names[6]} >> 4)); + ${names[3]} += (${names[7]} >> 6 === 1) ? '' : String.fromCharCode(((${names[6]} & 15) << 4) | (${names[7]} >> 2)); + ${names[3]} += (${names[8]} >> 6 === 1) ? '' : String.fromCharCode(((${names[7]} & 3) << 6) | ${names[8]}); + } + return decodeURIComponent(${names[3]}); + } + `; + + let source: SourceFile = createSourceFile('', code, ScriptTarget.ES2015, true); + return NodeUtils.setSynthesis(source.statements[0]); + } +} diff --git a/arkguard/src/utils/FileUtils.ts b/arkguard/src/utils/FileUtils.ts new file mode 100644 index 0000000000000000000000000000000000000000..4f2ff1b1cc3f415b2e47c6f09f32f5503aacc45d --- /dev/null +++ b/arkguard/src/utils/FileUtils.ts @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {existsSync, readFileSync, writeFileSync} from 'fs'; +import {readJsonSync} from 'fs-extra'; + +export class FileUtils { + /** + * Read file and return content + * + * @param filePath file path + */ + public static readFile(filePath: string): string | undefined { + if (!existsSync(filePath)) { + console.error(`File <${this.getFileName(filePath)} is not found.>`); + return undefined; + } + return readFileSync(filePath, 'utf-8'); + } + + /** + * Read file and convert to json object. + * + * @param filePath file path + */ + public static readFileAsJson(filePath: string): any { + if (!existsSync(filePath)) { + console.error(`File <${this.getFileName(filePath)} is not found.>`); + return undefined; + } + + try { + return readJsonSync(filePath); + } catch (e) { + console.error('json file read error: ' + filePath); + return undefined; + } + } + + /** + * Get File Name + * + * @param filePath file path + */ + public static getFileName(filePath: string): string | undefined { + if (!filePath) { + return undefined; + } + + const lastSepIndex: number = filePath.lastIndexOf('/'); + if (lastSepIndex >= 0) { + return filePath.slice(lastSepIndex + 1); + } + + return filePath.slice(filePath.lastIndexOf('\\') + 1); + } + + /** + * Get suffix of a file. + * + * @param filePath file path + */ + public static getFileExtension(filePath: string): string | undefined { + if (!filePath || !filePath.includes('.')) { + return undefined; + } + + // get file name + let fileName: string = this.getFileName(filePath); + if (!fileName.includes('.')) { + return undefined; + } + + return fileName.slice(fileName.lastIndexOf('.') + 1); + } + + public static writeFile(filePath: string, content: string): void { + writeFileSync(filePath, content); + } + + /** + * get prefix of directory + * @param dirPath + */ + public static getPrefix(dirPath: string): string | undefined { + if (!dirPath || (!dirPath.includes('/') && !dirPath.includes('\\'))) { + return undefined; + } + + const sepIndex: number = dirPath.lastIndexOf('/'); + if (sepIndex >= 0) { + return dirPath.slice(0, sepIndex + 1); + } + + return dirPath.slice(0, dirPath.lastIndexOf('\\') + 1); + } + + public static getPathWithoutPrefix(filePath: string, prefix: string): string | undefined { + if (!filePath.startsWith(prefix)) { + return filePath; + } + + return filePath.slice(prefix.length); + } +} diff --git a/arkguard/src/utils/ListUtil.ts b/arkguard/src/utils/ListUtil.ts new file mode 100644 index 0000000000000000000000000000000000000000..f2451b53537ef0f349770fdc7464789919ee54b3 --- /dev/null +++ b/arkguard/src/utils/ListUtil.ts @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as crypto from 'crypto'; + +export class ListUtil { + public static readonly MAX_INIT_LEN: number = 0xFFFF; + + /** + * get a list with element number filled for each element + * @param length: list length you want init. + */ + public static getInitList(length: number): number[] { + if (isNaN(length) || length < 0 || length > this.MAX_INIT_LEN) { + console.error(`array init length is invalid, should in range: [0, ${this.MAX_INIT_LEN}]`); + return []; + } + + return Array(length).fill(null).map((_, h) => h); + } + + /** + * shuffle list + * @param originList: list to be shuffled + */ + public static shuffle(originList: number[]): void { + if (!originList) { + return; + } + + for (let i = originList.length; i > 0; i--) { + let j = crypto.randomInt(originList.length); + [originList[i - 1], originList[j]] = [originList[j], originList[i - 1]]; + } + } + + /** + * merge two list to one list of unique element + * @param listA + * @param listB + * @param listC + */ + public static uniqueMergeList(listA: string[], listB: string[], listC?: string[]): string[] { + const firstList: string[] = listA ? listA : []; + const secondList: string[] = listB ? listB : []; + const thirdList: string[] = listC ? listC : []; + + const tmpList: string[] = thirdList ? [...firstList, ...secondList, ...thirdList] : [...firstList, ...secondList]; + const elementSet: Set = new Set(tmpList); + return Array.from(elementSet); + } +} diff --git a/arkguard/src/utils/NameCacheUtil.ts b/arkguard/src/utils/NameCacheUtil.ts new file mode 100644 index 0000000000000000000000000000000000000000..5bc78fc4d08a4728e38b1dc8f82aea99363ff86c --- /dev/null +++ b/arkguard/src/utils/NameCacheUtil.ts @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {FileUtils} from './FileUtils'; + +export const NAME_CACHE_SUFFIX: string = '.cache.json'; +export const PROPERTY_CACHE_FILE: string = 'property.cache.json'; + +export function writeCache(cache: Map, destFileName: string): void { + // convert map to json string + if (!cache) { + return; + } + const cacheString: string = JSON.stringify(Object.fromEntries(cache)); + FileUtils.writeFile(destFileName, cacheString); +} + +export function readCache(filePath: string): Object | undefined { + // read json string from file + const cacheString: string = FileUtils.readFile(filePath); + if (cacheString === undefined) { + return undefined; + } + + // get map from json string + return JSON.parse(cacheString); +} + +export function getMapFromJson(jsonObj: Object): Map { + if (jsonObj === undefined) { + return new Map(); + } + + return new Map(Object.entries(jsonObj)); +} diff --git a/arkguard/src/utils/NodeUtils.ts b/arkguard/src/utils/NodeUtils.ts new file mode 100644 index 0000000000000000000000000000000000000000..36065d9f9c1577712a98b5a7cf39f983c0f9b2c1 --- /dev/null +++ b/arkguard/src/utils/NodeUtils.ts @@ -0,0 +1,554 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + createPrinter, + EmitHint, + factory, + forEachChild, + isBinaryExpression, + isBindingElement, + isCallExpression, + isComputedPropertyName, + isConstructorDeclaration, + isElementAccessExpression, + isEnumMember, + isExpressionStatement, + isForInStatement, + isForOfStatement, + isForStatement, + isGetAccessor, + isIdentifier, + isMethodDeclaration, + isMethodSignature, + isParameter, + isPropertyAccessExpression, + isPropertyAssignment, + isPropertyDeclaration, + isPropertySignature, isQualifiedName, + isSetAccessor, + isStringLiteral, + isTaggedTemplateExpression, isVariableDeclaration, + isWhileStatement, + NodeFlags, + SyntaxKind +} from 'typescript'; + +import type { + BinaryExpression, + Block, + ElementAccessExpression, + Expression, + Node, + NodeArray, + ObjectBindingPattern, + Printer, + PrinterOptions, + PropertyAccessExpression, + SourceFile, + Statement, + StringLiteralLike, + VariableDeclaration, + VariableStatement +} from 'typescript'; + +import * as crypto from 'crypto'; + +export class NodeUtils { + public static setSynthesis(node: T): T { + visit(node); + return node; + + function visit(node: Node): void { + if (node) { + (node.pos as number) = -1; + (node.end as number) = -1; + forEachChild(node, visit); + } + } + } + + public static isPropertyDeclarationNode(node: Node): boolean { + let parent: Node | undefined = node.parent; + if (!parent) { + return false; + } + + /** eg: { 'name'' : 'akira' }, pass */ + if (isPropertyAssignment(parent)) { + return parent.name === node; + } + + if (isComputedPropertyName(parent) && parent.expression === node) { + return true; + } + + /** object binding pattern */ + if (isBindingElement(parent) && parent.propertyName === node) { + return true; + } + + /** eg: interface/type inf { 'name' : string}, pass */ + if (isPropertySignature(parent) && parent.name === node) { + return true; + } + + /** eg: interface/type T1 { func(arg: string): number;} */ + if (isMethodSignature(parent) && parent.name === node) { + return true; + } + + /** eg: enum { xxx = 1}; */ + if (isEnumMember(parent) && parent.name === node) { + return true; + } + + /** class { private name= 1}; */ + if (isPropertyDeclaration(parent) && parent.name === node) { + return true; + } + + /** class {'getName': function() {}} let _ = { getName() [}} */ + if (isMethodDeclaration(parent) && parent.name === node) { + return true; + } + + if (isSetAccessor(parent) && parent.name === node) { + return true; + } + + const result: boolean = isGetAccessor(parent) && parent.name === node; + return result; + } + + public static isPropertyOrElementAccessNode(node: Node): boolean { + return this.isPropertyAccessNode(node) || this.isElementAccessNode(node) || false; + } + + public static isPropertyAccessNode(node: Node): boolean { + let parent: Node | undefined = node.parent; + if (!parent) { + return false; + } + + /** eg: a.b = 1 */ + if (isPropertyAccessExpression(parent) && parent.name === node) { + return true; + } + const result: boolean = isQualifiedName(parent) && parent.right === node; + return result; + } + + public static isElementAccessNode(node: Node): boolean { + let parent: Node | undefined = node.parent; + if (!parent) { + return false; + } + + /** eg: a['name'] = 1, pass, a[0] ignore */ + const result: boolean = isElementAccessExpression(parent) && parent.argumentExpression === node; + return result; + } + + public static isClassPropertyInConstructorParams(node: Node): boolean { + if (!isIdentifier(node)) { + return false; + } + + if (!node.parent || !isParameter(node.parent)) { + return false; + } + + return !(!node.parent.parent || !isConstructorDeclaration(node.parent.parent)); + } + + public static isClassPropertyInConstructorBody(node: Node, constructorParams: Set): boolean { + if (!isIdentifier(node)) { + return false; + } + + const id: string = node.escapedText.toString(); + let curNode: Node = node.parent; + while (curNode) { + if (isConstructorDeclaration(curNode) && constructorParams.has(id)) { + return true; + } + + curNode = curNode.parent; + } + + return false; + } + + public static isPropertyNode(node: Node): boolean { + if (this.isPropertyOrElementAccessNode(node)) { + return true; + } + + return this.isPropertyDeclarationNode(node); + } + + /** + * let b = { + * 'id' : 'id22' + * } + * let c = ['123'] + * interface tmp1 { + * ['id'] : string; // pass + * // [b.id] : string; // error + * [b['id']]() : string; // error + * }; + * + * enum tmp2{ + * ['id'] = 2, // pass + * [b.id] = 3, // error + * }; + * + * + * let _ = { + * ['id'] : 2, // pass, + * [b.id] : 3, // pass, + * } + * + * interface IPerson { + * 'jfkkf': number, + * ['kkk'] : number + * } + * + * var customer:IPerson = { + * 'jfkkf': 10, + * ['kkk']: 11 + * } + * + * class A { + * + * private ['id'] = 2; // pass + * private [b.id] = 2; // error + * } + * + * class B { + * ['id']() {} + * [c[0]]() { + * } + * } + * + *1. The computable method declaration string of the class can be converted into an array access form; + *2. Computable properties/methods of object literals, which can be converted into array access forms; + *3. Cannot convert to array access form in other forms + * Interface/Type: A computed property name in an interface must refer to an expression whose type is a literal type or a 'unique symbol' type. + * Enum Computed property names are not allowed in enums. + * ClassDefinition A computed property name in a class property declaration must refer to an expression whose type is a literal type or a 'unique symbol' type. + * @param node + */ + public static isExtractableString(node: StringLiteralLike): boolean { + let parent: Node | undefined = node.parent; + if (!parent) { + return false; + } + + if (isTaggedTemplateExpression(parent)) { + return false; + } + + if (!NodeUtils.isPropertyDeclarationNode(node)) { + return true; + } + + // skip for some situations when in property declaration. + /** let _ = { ['name']: 'jack'} => let _ = {[arr[0]]: 'jack'} */ + if (isComputedPropertyName(parent)) { + let grandparent: Node = parent.parent; + const result: boolean = isMethodDeclaration(grandparent) && grandparent.name === parent; + return result; + } + + return false; + } + + public static randomInsertStatements(statements: Statement[], newStatement: Statement): Statement[] { + let index: number = crypto.randomInt(0, statements.length); + const result: Statement[] = [...statements.slice(0, index), newStatement, ...statements.slice(index, statements.length)]; + return result; + } + + /** + * create array init statement, e.g.: + * const arr = [1,2,3,4]; + * only support string and numeric array + */ + public static createArrayInit(isConst: boolean, varName: string, valueType: SyntaxKind, initArray: string[]): VariableStatement { + let idArr: Expression[] = []; + for (const value of initArray) { + if (valueType === SyntaxKind.StringLiteral) { + idArr.push(factory.createStringLiteral(value)); + } + + if (valueType === SyntaxKind.NumericLiteral) { + idArr.push(factory.createNumericLiteral(value)); + } + } + + const declaration: VariableDeclaration = factory.createVariableDeclaration( + factory.createIdentifier(varName), + undefined, + undefined, + factory.createArrayLiteralExpression(idArr, false) + ); + + return factory.createVariableStatement( + undefined, + factory.createVariableDeclarationList([declaration], NodeFlags.Const) + ); + } + + /** + * create numeric variable declaration with random value + * const varName = Math.floor(Math.random() * (max - min) + min); + * @return integer random value in range [min, max] + */ + public static createNumericWithRandom(varName: string, min: number, max: number): VariableStatement { + let innerBinary: BinaryExpression = factory.createBinaryExpression( + factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier('Math'), + factory.createIdentifier('random') + ), + undefined, + [] + ), + SyntaxKind.AsteriskToken, + factory.createNumericLiteral(max - min) + ); + + if (min !== 0) { + innerBinary = factory.createBinaryExpression( + innerBinary, + SyntaxKind.PlusToken, + factory.createNumericLiteral(min) + ); + } + + const declaration: VariableDeclaration = factory.createVariableDeclaration( + factory.createIdentifier(varName), + undefined, + undefined, + factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier('Math'), + factory.createIdentifier('floor') + ), + undefined, + [ + innerBinary + ] + ) + ); + + return factory.createVariableStatement( + null, + factory.createVariableDeclarationList([declaration], NodeFlags.Const) + ); + } + + /** + * create variable lower expression: (x | 0) + * @private + */ + public static createLowerExpression(expression: Expression): Expression { + return factory.createParenthesizedExpression( + factory.createBinaryExpression( + {...expression}, + SyntaxKind.BarToken, + factory.createNumericLiteral('0') + ) + ); + } + + /** + * create trunc expression: Math.trunc(x) + */ + public static createTruncExpression(expression: Expression): Expression { + return factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier('Math'), + factory.createIdentifier('trunc') + ), + undefined, + [ + {...expression} + ] + ); + } + + /** + * change property access expression to element access expression + * example: + * console.log() -> console['log']() + */ + public static changePropertyAccessToElementAccess(expression: PropertyAccessExpression): ElementAccessExpression { + return factory.createElementAccessExpression( + {...expression.expression}, + factory.createStringLiteral(expression.name.escapedText.toString()) + ); + } + + public static isMostInnerBinary(node: Node): boolean { + let flag: boolean = true; + forEachChild(node, (child) => { + if (!flag) { + return; + } + + if (this.hasBinary(child)) { + flag = false; + return; + } + }); + + return flag; + } + + private static hasBinary(node: Node): boolean { + let flag: boolean = false; + let visit = (inputNode): void => { + if (flag) { + return; + } + + if (isBinaryExpression(inputNode)) { + flag = true; + return; + } + + forEachChild(inputNode, visit); + }; + + visit(node); + return flag; + } + + public static isMostInnerCallExpression(node: Node): boolean { + let flag: boolean = true; + forEachChild(node, (child) => { + if (!flag) { + return; + } + + if (this.hasCallExpression(child)) { + flag = false; + return; + } + }); + + return flag; + } + + private static hasCallExpression(node: Node): boolean { + let flag: boolean = false; + let visit = (inputNode): void => { + if (flag) { + return; + } + + if (isCallExpression(inputNode)) { + flag = true; + return; + } + + forEachChild(inputNode, visit); + }; + + visit(node); + return flag; + } + + public static isContainNarrowNames(node: Node, narrowNames: string[]): boolean { + let flag: boolean = false; + forEachChild(node, (child) => { + if (flag) { + return; + } + + if (this.hasNarrowNames(child, narrowNames)) { + flag = true; + return; + } + }); + + return flag; + } + + private static hasNarrowNames(node: Node, narrowNames: string[]): boolean { + let flag: boolean = false; + let visit = (inputNode: Node): void => { + if (flag) { + return; + } + + if (isIdentifier(inputNode) && + narrowNames.includes(inputNode.text)) { + flag = true; + return; + } + + if (isStringLiteral(inputNode) && + narrowNames.includes(inputNode.text)) { + flag = true; + return; + } + + forEachChild(inputNode, visit); + }; + + visit(node); + return flag; + } + + public static isContainForbidStringStatement(node: Block): boolean { + let result: boolean = false; + let statements: NodeArray = node.statements; + + statements?.forEach((st: Statement) => { + if (isExpressionStatement(st) && isStringLiteral(st.expression)) { + result = true; + } + }); + + return result; + } + + public static printNode(node: Node, sourceFile: SourceFile): string { + const printOptions: PrinterOptions = {}; + const printer: Printer = createPrinter(printOptions); + + return printer.printNode(EmitHint.Unspecified, node, sourceFile); + } + + public static isLoopStatement(node: Node): boolean { + return isForStatement(node) || + isForInStatement(node) || + isForOfStatement(node) || + isWhileStatement(node); + } + + public static isObjectBindingPatternAssignment(node: ObjectBindingPattern): boolean { + if (!node || !node.parent || !isVariableDeclaration(node.parent)) { + return false; + } + + const initializer: Expression = node.parent.initializer; + return initializer && isCallExpression(initializer); + } +} diff --git a/arkguard/src/utils/OhsUtil.ts b/arkguard/src/utils/OhsUtil.ts new file mode 100644 index 0000000000000000000000000000000000000000..5ae093fd5cd2386ecc77dbea22312fbd9e304cac --- /dev/null +++ b/arkguard/src/utils/OhsUtil.ts @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + isBinaryExpression, + isCallExpression, + isClassDeclaration, + isIdentifier, + isPropertyAccessExpression, + isStringLiteral, + isVariableStatement, + SyntaxKind +} from 'typescript'; + +import type { + ClassDeclaration, + Expression, + HeritageClause, + Identifier, + NodeArray, + Statement +} from 'typescript'; + +import {OhPackType} from './TransformUtil'; + +/** + * find openHarmony module import statement + * example: + * jsbundle - var _ohos = _interopRequireDefault(requireModule('@ohos.hilog')); + * esmodule - var hilog = globalThis.requireNapi('hilog') || ... + * + * @param node + * @param moduleName full name of imported module, must check format before called, example: + * - '@ohos.hilog' + * - '@ohos.application.Ability' + */ +export function findOhImportStatement(node: Statement, moduleName: string): OhPackType { + if (!isVariableStatement(node) || node.declarationList.declarations.length !== 1) { + return OhPackType.NONE; + } + + const initializer: Expression = node.declarationList.declarations[0].initializer; + if (initializer === undefined) { + return OhPackType.NONE; + } + + /** esmodule */ + if (isBinaryExpression(initializer)) { + if (initializer.operatorToken.kind !== SyntaxKind.BarBarToken) { + return OhPackType.NONE; + } + + if (!isCallExpression(initializer.left)) { + return OhPackType.NONE; + } + + if (!isPropertyAccessExpression(initializer.left.expression)) { + return OhPackType.NONE; + } + + if (!isIdentifier(initializer.left.expression.expression) || + initializer.left.expression.expression.text !== 'globalThis') { + return OhPackType.NONE; + } + + if (!isIdentifier(initializer.left.expression.name) || + initializer.left.expression.name.text !== 'requireNapi') { + return OhPackType.NONE; + } + + if (initializer.left.arguments.length !== 1) { + return OhPackType.NONE; + } + + const arg: Expression = initializer.left.arguments[0]; + if (isStringLiteral(arg) && arg.text === moduleName.substring('@ohos.'.length)) { + return OhPackType.ES_MODULE; + } + } + + /** jsbundle */ + if (isCallExpression(initializer)) { + if (initializer.arguments.length !== 1) { + return OhPackType.NONE; + } + + if (!isIdentifier(initializer.expression) || + initializer.expression.text !== '_interopRequireDefault') { + return OhPackType.NONE; + } + + const arg: Expression = initializer.arguments[0]; + if (!isCallExpression(arg)) { + return OhPackType.NONE; + } + + if (!isIdentifier(arg.expression) || arg.expression.text !== 'requireModule') { + return OhPackType.NONE; + } + + const innerArg: Expression = arg.arguments[0]; + if (!isStringLiteral(innerArg) || innerArg.text !== moduleName) { + return OhPackType.NONE; + } + + return OhPackType.JS_BUNDLE; + } + + return OhPackType.NONE; +} + + +function containViewPU(heritageClauses: NodeArray): boolean { + if (!heritageClauses) { + return false; + } + let hasViewPU: boolean = false; + heritageClauses.forEach( + (heritageClause) => { + if (!heritageClause || !heritageClause.types) { + return; + } + const types = heritageClause.types; + types.forEach((typeExpression) => { + if (!typeExpression || !typeExpression.expression) { + return; + } + const expression = typeExpression.expression; + if (isIdentifier(expression) && expression.text === 'ViewPU') { + hasViewPU = true; + } + }); + }); + return hasViewPU; +} + +/** + * used to ignore user defined ui component class name + * @param nameNode + */ +export function isViewPUBasedClassName(nameNode: Identifier): boolean { + if (!nameNode || !nameNode.parent) { + return false; + } + if (!isClassDeclaration(nameNode.parent)) { + return false; + } + const heritageClause = nameNode.parent.heritageClauses; + return containViewPU(heritageClause); +} + +/** + * used to ignore user defined ui component class property name + * @param nameNode + */ +export function isViewPUBasedClass(classNode: ClassDeclaration): boolean { + if (!classNode) { + return false; + } + if (!isClassDeclaration(classNode)) { + return false; + } + const heritageClause = classNode.heritageClauses; + return containViewPU(heritageClause); +} + +export function getClassProperties(classNode: ClassDeclaration): Set { + const properties: Set = new Set(); + if (!classNode || !classNode.members) { + return properties; + } + + classNode.members.forEach((member) => { + if (!member || !member.name) { + return; + } + + if (isIdentifier(member.name)) { + properties.add(member.name.text); + } + + if (isStringLiteral(member.name)) { + properties.add(member.name.text); + } + //other kind ignore + }); + return properties; +} \ No newline at end of file diff --git a/arkguard/src/utils/ScopeAnalyzer.ts b/arkguard/src/utils/ScopeAnalyzer.ts new file mode 100644 index 0000000000000000000000000000000000000000..51ae011a0a8f9810524f915a888bbe7858a1e3be --- /dev/null +++ b/arkguard/src/utils/ScopeAnalyzer.ts @@ -0,0 +1,881 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + forEachChild, + isClassDeclaration, + isConstructorDeclaration, + isFunctionDeclaration, + isFunctionLike, + isIdentifier, + isMethodDeclaration, + SyntaxKind +} from 'typescript'; + +import type { + BreakOrContinueStatement, + CaseBlock, + CatchClause, + ClassDeclaration, + ClassElement, + ClassExpression, + EnumDeclaration, + ExportSpecifier, + ForInOrOfStatement, + ForStatement, + FunctionLikeDeclaration, + Identifier, + ImportSpecifier, + InterfaceDeclaration, + LabeledStatement, + ModuleDeclaration, + Node, + ObjectBindingPattern, + ObjectLiteralExpression, + SourceFile, + Symbol, + SymbolTable, + TypeAliasDeclaration, + TypeChecker, + TypeElement +} from 'typescript'; + +import {NodeUtils} from './NodeUtils'; +import {isViewPUBasedClass} from './OhsUtil'; + +/** + * kind of a scope + */ +namespace secharmony { + type ForLikeStatement = ForStatement | ForInOrOfStatement; + type ClassLikeDeclaration = ClassDeclaration | ClassExpression; + + /** + * type of scope + */ + export enum ScopeKind { + GLOBAL, + MODULE, + FUNCTION, + CLASS, + FOR, + SWITCH, + BLOCK, + INTERFACE, + CATCH, + ENUM, + OBJECT_LITERAL + } + + export function isGlobalScope(scope: Scope): boolean { + return scope.kind === ScopeKind.GLOBAL; + } + + export function isFunctionScope(scope: Scope): boolean { + return scope.kind === ScopeKind.FUNCTION; + } + + export function isClassScope(scope: Scope): boolean { + return scope.kind === ScopeKind.CLASS; + } + + export function isInterfaceScope(scope: Scope): boolean { + return scope.kind === ScopeKind.INTERFACE; + } + + export function isEnumScope(scope: Scope): boolean { + return scope.kind === ScopeKind.ENUM; + } + + export function isObjectLiteralScope(scope: Scope): boolean { + return scope.kind === ScopeKind.OBJECT_LITERAL; + } + + /** + * Structure of a scope + */ + export interface Scope { + /** + * name of a scope + */ + name: string; + + /** + * kind of current scope + */ + kind: ScopeKind; + + /** + * node of current scope in ast + */ + block: Node; + + /** + * parent scope of current scope + */ + parent: Scope | undefined; + + /** + * sub scopes of current scope, + */ + children: Scope[]; + + /** + * symbols define in current scope + */ + defs: Set; + + /** + * labels in current scope + */ + labels: Label[]; + + /** + * location path description of current scope, + */ + loc: string; + + importNames?: Set; + + exportNames?: Set; + + mangledNames?: Set; + + /** + * add a sub scope to current scope + * + * @param child + */ + addChild(child: Scope): void; + + /** + * add definition symbol into current scope + * + * @param def definition symbol + */ + addDefinition(def: Symbol): void; + + /** + * add label to current scope + * + * @param label label statement + */ + addLabel(label: Label): void; + + /** + * get symbol location + * + * @param sym symbol + */ + getSymbolLocation(sym: Symbol): string; + + /** + * get label location + * + * @param label + */ + getLabelLocation(label: Label): string; + } + + export function createScope(name: string, node: Node, type: ScopeKind, lexicalScope: boolean = false, upper ?: Scope): Scope { + // scope name + let scopeName: string = name; + // kind of a scope, such as global ,function like, block .. + let kind: ScopeKind = type; + // node of a current scope in ast. + let block: Node = node; + // parent scope of current scope + let parent: Scope | undefined = upper; + // sub scopes of current scope + let children: Scope[] = []; + + // symbols define in current scope + let defs: Set = new Set(); + + // labels in current scope + let labels: Label[] = []; + + let importNames: Set = new Set(); + + let exportNames: Set = new Set(); + + let mangledNames: Set = new Set(); + + // location path + let loc: string = parent?.loc ? parent.loc + '#' + scopeName : scopeName; + + // current scope + let current: Scope = { + 'name': scopeName, + 'kind': kind, + 'block': block, + 'parent': parent, + 'children': children, + 'defs': defs, + 'labels': labels, + 'loc': loc, + 'importNames': importNames, + 'exportNames': exportNames, + 'mangledNames': mangledNames, + addChild, + addDefinition, + addLabel, + getSymbolLocation, + getLabelLocation, + }; + + current.parent?.addChild(current); + return current; + + function addChild(child: Scope): void { + current.children.push(child); + } + + function addDefinition(def: Symbol): void { + current.defs.add(def); + } + + function addLabel(label: Label): void { + current.labels.push(label); + } + + function getSymbolLocation(sym: Symbol): string { + if (!defs.has(sym)) { + return ''; + } + + return current.loc ? sym.name : current.loc + '#' + sym.name; + } + + function getLabelLocation(label: Label): string { + if (!current.labels.includes(label)) { + return ''; + } + + let index: number = current.labels.findIndex((lb: Label) => { + return lb === label; + }); + + return current.loc ? label.name : current.loc + '#' + index + label.name; + } + } + + export interface Label { + name: string; + locInfo: string; + refs: Identifier[]; + parent: Label | undefined; + children: Label[]; + scope: Scope; + } + + export function createLabel(node: LabeledStatement, scope: Scope, parent?: Label | undefined): Label { + let labelName: string = '$' + scope.labels.length + '_' + node.label.text; + let label: Label = { + 'name': node.label.text, + 'locInfo': labelName, + 'refs': [node.label], + 'parent': parent, + 'children': [], + 'scope': scope, + }; + + scope.labels.push(label); + parent?.children.push(label); + + return label; + } + + export interface ScopeManager { + + /** + * get reserved names like ViewPU component class name + */ + getReservedNames(): Set + /** + * do scope analysis + * + * @param ast ast tree of a source file + * @param checker + */ + analyze(ast: SourceFile, checker: TypeChecker): void; + + /** + * get root scope of a file + */ + getRootScope(): Scope; + + /** + * find block Scope of a node + * @param node + */ + getScopeOfNode(node: Node): Scope | undefined; + } + + export function createScopeManager(): ScopeManager { + let reservedNames: Set = new Set(); + let root: Scope; + let current: Scope; + let scopes: Scope[] = []; + + let checker: TypeChecker = null; + let upperLabel: Label | undefined = undefined; + + return { + getReservedNames, + analyze, + getRootScope, + getScopeOfNode, + }; + + function analyze(ast: SourceFile, typeChecker: TypeChecker): void { + checker = typeChecker; + analyzeScope(ast); + } + + function getReservedNames(): Set { + return reservedNames; + } + + function getRootScope(): Scope { + return root; + } + + function addSymbolInScope(node: Node): void { + let defSymbols: SymbolTable = node?.locals; + if (!defSymbols) { + return; + } + + defSymbols.forEach((def: Symbol) => { + // with export identification, special handling. + if (def.exportSymbol) { + current.exportNames.add(def.name); + } + + current.addDefinition(def); + }); + } + + /** + * analyze chain of scopes + * + * @param node + */ + function analyzeScope(node: Node): void { + switch (node.kind) { + // global + case SyntaxKind.SourceFile: + analyzeSourceFile(node as SourceFile); + break; + + // namespace or module + case SyntaxKind.ModuleDeclaration: + analyzeModule(node as ModuleDeclaration); + break; + + // function like + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.Constructor: + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + analyzeFunctionLike(node as FunctionLikeDeclaration); + break; + + // class like + case SyntaxKind.ClassExpression: + case SyntaxKind.ClassDeclaration: + analyzeClassLike(node as ClassLikeDeclaration); + break; + + // for like + case SyntaxKind.ForStatement: + case SyntaxKind.ForInStatement: + case SyntaxKind.ForOfStatement: + analyzeForLike(node as ForLikeStatement); + break; + case SyntaxKind.CaseBlock: + // caseBlock property in switch statement + analyzeSwitch(node as CaseBlock); + break; + case SyntaxKind.Block: + // while, do ...while, block, if/else.. + analyzeBlock(node); + break; + + case SyntaxKind.InterfaceDeclaration: + analyzeInterface(node as InterfaceDeclaration); + break; + + case SyntaxKind.EnumDeclaration: + analyzeEnum(node as EnumDeclaration); + break; + + case SyntaxKind.Identifier: + analyzeSymbol(node as Identifier); + break; + + case SyntaxKind.TypeAliasDeclaration: + analyzeTypeAliasDeclaration(node as TypeAliasDeclaration); + break; + + case SyntaxKind.LabeledStatement: + analyzeLabel(node as LabeledStatement); + break; + + case SyntaxKind.BreakStatement: + case SyntaxKind.ContinueStatement: + analyzeBreakOrContinue(node as BreakOrContinueStatement); + break; + case SyntaxKind.ImportSpecifier: + analyzeImportNames(node as ImportSpecifier); + break; + + case SyntaxKind.ObjectBindingPattern: + analyzeObjectBindingPatternRequire(node as ObjectBindingPattern); + break; + + case SyntaxKind.ObjectLiteralExpression: + analyzeObjectLiteralExpression(node as ObjectLiteralExpression); + break; + + case SyntaxKind.ExportSpecifier: + analyzeExportNames(node as ExportSpecifier); + break; + + case SyntaxKind.CatchClause: + analyzeCatchClause(node as CatchClause); + break; + default: + forEachChild(node, analyzeScope); + break; + } + } + + function analyzeImportNames(node: ImportSpecifier): void { + try { + if (node.propertyName) { + current.importNames.add(node.propertyName.text); + } else { + current.importNames.add(node.name.text); + } + + forEachChild(node, analyzeScope); + } catch (e) { + console.error(e); + } + } + + function analyzeObjectBindingPatternRequire(node: ObjectBindingPattern): void { + if (!NodeUtils.isObjectBindingPatternAssignment(node)) { + forEachChild(node, analyzeScope); + return; + } + + if (!node.elements) { + return; + } + + node.elements.forEach((bindingElement) => { + if (!bindingElement) { + return; + } + + if (!bindingElement.name || !isIdentifier(bindingElement.name)) { + return; + } + + if (bindingElement.propertyName) { + return; + } + + current.importNames.add(bindingElement.name.text); + }); + } + + function analyzeObjectLiteralExpression(node: ObjectLiteralExpression): void { + let scopeName: string = '$' + current.children.length; + current = createScope(scopeName, node, ScopeKind.OBJECT_LITERAL, false, current); + scopes.push(current); + + addSymbolInScope(node); + forEachChild(node, analyzeScope); + current = current.parent || current; + } + + function analyzeExportNames(node: ExportSpecifier): void { + // get export names. + current.exportNames.add(node.name.text); + forEachChild(node, analyzeScope); + } + + function analyzeBreakOrContinue(node: BreakOrContinueStatement): void { + let labelName: string = node?.label?.text ?? ''; + let label: Label = findTargetLabel(labelName); + if (!label) { + return; + } + + if (node.label) { + label?.refs.push(node.label); + } + + forEachChild(node, analyzeScope); + } + + function findTargetLabel(labelName: string): Label | null { + if (!labelName) { + return null; + } + + let label: Label | undefined = upperLabel; + // avoid loop + while (label && label?.name !== labelName) { + label = label?.parent; + } + + return label; + } + + function analyzeSourceFile(node: SourceFile): void { + let scopeName: string = ''; + root = createScope(scopeName, node, ScopeKind.GLOBAL, true); + current = root; + scopes.push(current); + // locals of a node(scope) is symbol that defines in current scope(node). + addSymbolInScope(node); + forEachChild(node, analyzeScope); + current = current.parent || current; + extractImportExports(); + } + + function analyzeCatchClause(node: CatchClause): void { + let scopeName: string = '$' + current.children.length; + current = createScope(scopeName, node, ScopeKind.CATCH, false, current); + scopes.push(current); + // add in catch declaration. + addSymbolInScope(node); + if (node.block) { + // add in block declaration. + addSymbolInScope(node.block); + } + + forEachChild(node.block, analyzeScope); + current = current.parent || current; + } + + function extractImportExports(): void { + for (const def of current.defs) { + if (def.exportSymbol) { + if (!current.exportNames.has(def.name)) { + current.exportNames.add(def.name); + } + const name: string = def.exportSymbol.name; + if (!current.exportNames.has(name)) { + current.exportNames.add(name); + } + } + } + } + + function analyzeTypeAliasDeclaration(node: TypeAliasDeclaration): void { + let scopeName: string = node.name.text ?? '$' + current.children.length; + current = createScope(scopeName, node, ScopeKind.INTERFACE, true, current); + scopes.push(current); + addSymbolInScope(node); + forEachChild(node, analyzeScope); + current = current.parent || current; + } + + /** + * namespace ns { + * ... + * } + * @param node + */ + function analyzeModule(node: ModuleDeclaration): void { + /** + * if it is an anonymous scope, generate the scope name with a number, + * which is based on the order of its child scopes in the upper scope + */ + let scopeName: string = node.name.text ?? '$' + current.children.length; + current = createScope(scopeName, node, ScopeKind.MODULE, true, current); + scopes.push(current); + addSymbolInScope(node); + forEachChild(node, analyzeScope); + current = current.parent || current; + } + + /** + * exclude constructor's parameter witch should be treated as property, example: + * constructor(public name){}, name should be treated as property + * @param node + */ + function excludeConstructorParameter(node: Node): void { + if (!isConstructorDeclaration(node)) { + return; + } + + const visitParam = (param: Node): void => { + if (isIdentifier(param)) { + current.defs.forEach((def) => { + if (def.name === param.text) { + current.defs.delete(def); + current.mangledNames.add(def.name); + } + }); + } + + forEachChild(param, visitParam); + }; + + node.parameters.forEach((param) => { + visitParam(param); + }); + } + + /** + * function func(param1...) { + * ... + * } + * @param node + */ + function analyzeFunctionLike(node: FunctionLikeDeclaration): void { + let scopeName: string = (node?.name as Identifier)?.text ?? '$' + current.children.length; + let loc: string = current?.loc ? current.loc + '#' + scopeName : scopeName; + let overloading: boolean = false; + for (const sub of current.children) { + if (sub.loc === loc) { + overloading = true; + current = sub; + break; + } + } + + if (!overloading) { + current = createScope(scopeName, node, ScopeKind.FUNCTION, true, current); + scopes.push(current); + } + + addSymbolInScope(node); + if (node.symbol && current.parent && !current.parent.defs.has(node.symbol)) { + current.parent.defs.add(node.symbol); + } + + if (isFunctionDeclaration(node) || isMethodDeclaration(node)) { + // function declaration requires skipping function names + node.forEachChild((sub: Node) => { + if (isIdentifier(sub)) { + return; + } + + analyzeScope(sub); + }); + } else { + forEachChild(node, analyzeScope); + } + + excludeConstructorParameter(node); + current = current.parent || current; + } + + function analyzeSwitch(node: CaseBlock): void { + let scopeName: string = '$' + current.children.length; + current = createScope(scopeName, node, ScopeKind.SWITCH, false, current); + scopes.push(current); + addSymbolInScope(node); + forEachChild(node, analyzeScope); + current = current.parent || current; + } + + /** + * ES6+ class like scope, The members of a class aren't not allow to rename in rename identifiers transformer, but + * rename in rename properties transformer. + * + * @param node + */ + function analyzeClassLike(node: ClassLikeDeclaration): void { + if (isClassDeclaration(node) && isViewPUBasedClass(node)) { + reservedNames.add(node.name.text); + } + + try { + let scopeName: string = node?.name?.text ?? '$' + current.children.length; + current = createScope(scopeName, node, ScopeKind.CLASS, true, current); + scopes.push(current); + addSymbolInScope(node); + // Class members are seen as attribute names, and the reference of external symbols can be renamed as the same + node.members?.forEach((elm: ClassElement) => { + if (elm?.symbol) { + current.addDefinition(elm.symbol); + } + }); + + node.members?.forEach((sub: Node) => { + analyzeScope(sub); + }); + } catch (e) { + console.error(e); + } + + current = current.parent || current; + } + + function analyzeForLike(node: ForLikeStatement): void { + let scopeName: string = '$' + current.children.length; + current = createScope(scopeName, node, ScopeKind.FOR, false, current); + scopes.push(current); + addSymbolInScope(node); + forEachChild(node, analyzeScope); + current = current.parent || current; + } + + function analyzeBlock(node: Node): void { + // when block is body of a function + if (isFunctionScope(current) && isFunctionLike(node.parent)) { + // skip direct block scope in function scope + forEachChild(node, analyzeScope); + return; + } + + let scopeName: string = '$' + current.children.length; + current = createScope(scopeName, node, ScopeKind.BLOCK, false, current); + scopes.push(current); + addSymbolInScope(node); + forEachChild(node, analyzeScope); + current = current.parent || current; + } + + function analyzeInterface(node: InterfaceDeclaration): void { + let scopeName: string = node.name.text; + current = createScope(scopeName, node, ScopeKind.INTERFACE, true, current); + scopes.push(current); + try { + addSymbolInScope(node); + } catch (e) { + console.error(''); + } + + node.members?.forEach((elm: TypeElement) => { + if (elm?.symbol) { + current.addDefinition(elm.symbol); + } + }); + + forEachChild(node, analyzeScope); + current = current.parent || current; + } + + function analyzeEnum(node: EnumDeclaration): void { + let scopeName: string = node.name.text; + current = createScope(scopeName, node, ScopeKind.ENUM, true, current); + scopes.push(current); + for (const member of node.members) { + if (member.symbol) { + current.addDefinition(member.symbol); + } + } + + for (const subNode of node.members) { + forEachChild(subNode, analyzeScope); + } + + current = current.parent || current; + } + + function analyzeSymbol(node: Identifier): void { + // ignore all identifiers that treat as property in property declaration + if (NodeUtils.isPropertyDeclarationNode(node)) { + return; + } + + // ignore all identifiers that treat as property in property access + if (NodeUtils.isPropertyAccessNode(node)) { + return; + } + + let symbol: Symbol = null; + + try { + symbol = checker.getSymbolAtLocation(node); + } catch (e) { + console.error(e); + return; + } + + if (!symbol) { + return; + } + + // add def symbol that don't found in current defs. + addSymbolIntoDefsIfNeeded(node, symbol, current.defs); + } + + function addSymbolIntoDefsIfNeeded(node: Identifier, symbol: Symbol, currentDefs: Set): boolean { + // process a new def not in currentDefs + let isSameName: boolean = false; + for (const def of currentDefs) { + if (def.name === node.text) { + isSameName = true; + break; + } + } + + if (isSameName) { + // exclude the possibility of external symbols, as those with duplicate names have been added to currentDefs (this avoids the possibility of omissions) + if (!currentDefs.has(symbol)) { + currentDefs.add(symbol); + } + + if (symbol.exportSymbol && !currentDefs.has(symbol.exportSymbol)) { + currentDefs.add(symbol); + } + } + + return isSameName; + } + + function analyzeLabel(node: LabeledStatement): void { + // labels within the same scope are allowed to be duplicated, so label names need to have numbering information to distinguish them + upperLabel = upperLabel ? createLabel(node, current, upperLabel) : createLabel(node, current); + forEachChild(node, analyzeScope); + upperLabel = upperLabel?.parent; + } + + function getScopeOfNode(node: Node): Scope | undefined { + if (!isIdentifier(node)) { + return undefined; + } + + let sym: Symbol = checker.getSymbolAtLocation(node); + if (!sym) { + return undefined; + } + + for (const scope of scopes) { + if (scope?.defs.has(sym)) { + return scope; + } + } + + return undefined; + } + } +} + +export = secharmony; diff --git a/arkguard/src/utils/SourceMapUtil.ts b/arkguard/src/utils/SourceMapUtil.ts new file mode 100644 index 0000000000000000000000000000000000000000..d709e0681c07e83b34cab548f80332d5a9ef3b10 --- /dev/null +++ b/arkguard/src/utils/SourceMapUtil.ts @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + createCompilerHost, + createSourceMapGenerator, +} from 'typescript'; + +import type { + CompilerHost, + CompilerOptions, + EmitHost, + SourceMapGenerator, + SourceMapGeneratorOptions, +} from 'typescript'; + +/** + * create sourcemap generator use api of typescript + * @param sourceFile: file path of source code + */ +export function getSourceMapGenerator(sourceFile: string): SourceMapGenerator { + if (!sourceFile) { + return undefined; + } + + let compilerOptions: CompilerOptions = {}; + let compilerHost: CompilerHost = createCompilerHost(compilerOptions); + + function getCanonicalFileName(fileName: string): string { + return compilerHost.getCanonicalFileName(fileName); + } + + const currentDirectory: string = compilerHost.getCurrentDirectory(); + + let host: EmitHost = { + getSourceFileFromReference: undefined, + redirectTargetsMap: undefined, + fileExists(path: string): boolean { + return false; + }, + isEmitBlocked(emitFileName: string): boolean { + return false; + }, + useCaseSensitiveFileNames(): boolean { + return false; + }, + getPrependNodes: undefined, + getCanonicalFileName: getCanonicalFileName, + getCommonSourceDirectory: undefined, + getCompilerOptions: undefined, + getCurrentDirectory: () => currentDirectory, + getNewLine: undefined, + getSourceFile: undefined, + getSourceFileByPath: undefined, + getSourceFiles: undefined, + getLibFileFromReference: undefined, + isSourceFileFromExternalLibrary: undefined, + getResolvedProjectReferenceToRedirect: undefined, + getProjectReferenceRedirect: undefined, + isSourceOfProjectReferenceRedirect: undefined, + writeFile: undefined + }; + + const generatorOptions: SourceMapGeneratorOptions = {extendedDiagnostics: false}; + return createSourceMapGenerator(host, sourceFile, currentDirectory, currentDirectory, generatorOptions); +} diff --git a/arkguard/src/utils/TransformUtil.ts b/arkguard/src/utils/TransformUtil.ts new file mode 100644 index 0000000000000000000000000000000000000000..9b888880e67aec4a86fbf9c09aa199531b687635 --- /dev/null +++ b/arkguard/src/utils/TransformUtil.ts @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + forEachChild, + getLeadingCommentRangesOfNode, + isCallExpression, + isExpressionStatement, + isIdentifier, + SyntaxKind, + visitEachChild +} from 'typescript'; + +import type { + CommentRange, + Expression, + Identifier, + Node, + SourceFile, + Statement, + TransformationContext +} from 'typescript'; +/** + * collect exist identifier names in current source file + * @param sourceFile + */ +export function collectExistNames(sourceFile: SourceFile): Set { + const identifiers: Set = new Set(); + + let visit = (node: Node): void => { + if (isIdentifier(node)) { + identifiers.add(node.text); + } + + forEachChild(node, visit); + }; + + forEachChild(sourceFile, visit); + return identifiers; +} + +/** + * collect exist identifiers in current source file + * @param sourceFile + * @param context + */ +export function collectIdentifiers(sourceFile: SourceFile, context: TransformationContext): Identifier[] { + const identifiers: Identifier[] = []; + + let visit = (node: Node): Node => { + if (!isIdentifier(node) || !node.parent) { + return visitEachChild(node, visit, context); + } + + identifiers.push(node); + return node; + }; + + visit(sourceFile); + return identifiers; +} + +/** + * is current node contain ignore obfuscation comment + * comment: // @skipObfuscate + */ +export function isObfsIgnoreNode(node: Node, sourceFile: SourceFile): boolean { + const ranges: CommentRange[] = getLeadingCommentRangesOfNode(node, sourceFile); + if (!ranges) { + return false; + } + + const ignoreComment: string = '//@skipObfuscate'; + for (const range of ranges) { + const comment: string = sourceFile.text.slice(range.pos, range.end).replace(' ', '').replace('\t', ''); + if (comment === ignoreComment) { + return true; + } + } + + return false; +} + +export enum OhPackType { + NONE, + JS_BUNDLE, + ES_MODULE +} + + + +export function isCommentedNode(node: Node, sourceFile: SourceFile): boolean { + const ranges: CommentRange[] = getLeadingCommentRangesOfNode(node, sourceFile); + return ranges !== undefined; +} + +export function isSuperCallStatement(node: Node): boolean { + return isExpressionStatement(node) && + isCallExpression(node.expression) && + node.expression.expression.kind === SyntaxKind.SuperKeyword; +} diff --git a/arkguard/src/utils/TypeUtils.ts b/arkguard/src/utils/TypeUtils.ts new file mode 100644 index 0000000000000000000000000000000000000000..8262a2f6198cf4dec0a38a07d5146be05c0cd938 --- /dev/null +++ b/arkguard/src/utils/TypeUtils.ts @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + createCompilerHost, + createPrinter, + createProgram, + createSourceFile, + ScriptTarget, +} from 'typescript'; + +import type { + CompilerHost, + CompilerOptions, + Printer, + Program, + SourceFile, + TypeChecker, +} from 'typescript'; +import path from 'path'; + +export class TypeUtils { + /** + * performing symbol analysis on the original abstract syntax tree can cause sourcemap errors + * @param oldAst + * + */ + public static createNewSourceFile(oldAst: SourceFile): SourceFile { + let printer: Printer = createPrinter(); + let content: string = printer.printFile(oldAst); + const fileSuffix: string = '.ts'; + const { dir, name } = path.parse(oldAst.fileName); + const targetName: string = path.join(dir, name) + '__tmp' + fileSuffix; + return createSourceFile(targetName, content, ScriptTarget.ES2015, true); + } + + public static createChecker(ast: SourceFile): TypeChecker { + const host: CompilerHost = createCompilerHost({}); + + const customHost: CompilerHost = { + getSourceFile(name, languageVersion): SourceFile | undefined { + if (name === ast.fileName) { + return ast; + } else { + return host.getSourceFile(name, languageVersion); + } + }, + // optional + getDefaultLibLocation: () => '', + getDefaultLibFileName: () => '', + writeFile: (filename, data) => { + }, + getCurrentDirectory: () => '', + useCaseSensitiveFileNames: host.useCaseSensitiveFileNames, + getCanonicalFileName: host.getCanonicalFileName, + getNewLine: host.getNewLine, + fileExists: () => true, + readFile: (name): string => { + return name === ast.fileName ? ast.text : host.readFile(name); + }, + // must, read program.ts => createCompilerHost + directoryExists: undefined, + getEnvironmentVariable: undefined, + getDirectories: undefined, + }; + + let option: CompilerOptions = {}; + if (ast.fileName.endsWith('.js')) { + option.allowJs = true; + } + + let program: Program = createProgram([ast.fileName], option, customHost); + return program.getTypeChecker(); + } +} diff --git a/arkguard/test/grammar/advanced_type/discriminated_unions.ts b/arkguard/test/grammar/advanced_type/discriminated_unions.ts new file mode 100644 index 0000000000000000000000000000000000000000..d420320da72ac1e3760aeb3cd740b4bb4ee9b423 --- /dev/null +++ b/arkguard/test/grammar/advanced_type/discriminated_unions.ts @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +interface Square { + kind: 'square'; + size: number; +} + +interface Rectangle { + kind: 'rectangle'; + width: number; + height: number; +} + +interface Circle { + kind: 'circle'; + radius: number; +} + +type Shape = Square | Rectangle | Circle; + +function area(s: Shape): number { + let result: number; + switch (s.kind) { + case 'square': + result = s.size * s.size; + break; + case 'rectangle': + result = s.height * s.width; + break; + case 'circle': + result = Math.PI * s.radius * s.radius; + break; + } + return result; +} + +let a = {kind: 'square', size: 3}; + +const targetArea: number = 9; +assert(area(a) === targetArea, 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/advanced_type/intersection_types.ts b/arkguard/test/grammar/advanced_type/intersection_types.ts new file mode 100644 index 0000000000000000000000000000000000000000..182de6165ace90143339ba74036556a7589ed347 --- /dev/null +++ b/arkguard/test/grammar/advanced_type/intersection_types.ts @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +function extend(first: T, second: U): T & U { + let result = {}; + for (let id in first) { + (result)[id] = (first)[id]; + } + for (let id in second) { + if (!result.hasOwnProperty(id)) { + (result)[id] = (second)[id]; + } + } + return result; +} + +class Person { + constructor(public name: string) { + } +} + +interface Loggable { + log(): void; +} + +class ConsoleLogger implements Loggable { + log(): void { + console.log('Jim'); + } +} + +const jim = extend(new Person('Jim'), new ConsoleLogger()); +const n = jim.name; + +assert(n === 'Jim', 'success'); diff --git a/arkguard/test/grammar/advanced_type/predefined_types.ts b/arkguard/test/grammar/advanced_type/predefined_types.ts new file mode 100644 index 0000000000000000000000000000000000000000..22d55829e5b3fcf1eebc0e353a4738e0211096de --- /dev/null +++ b/arkguard/test/grammar/advanced_type/predefined_types.ts @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +type T00 = Exclude<'a' | 'b' | 'c' | 'd', 'a' | 'c' | 'f'>; // 'b' | 'd' +type T01 = Extract<'a' | 'b' | 'c' | 'd', 'a' | 'c' | 'f'>; // 'a' | 'c' + +type T02 = Exclude void), Function>; // string | number +type T03 = Extract void), Function>; // () => void + +type T04 = NonNullable; // string | number +type T05 = NonNullable<(() => string) | string[] | null | undefined>; // (() => string) | string[] + +function f1(s: string): any { + return {a: 1, b: s}; +} + +class C { + x = 0; + y = 0; +} + +type T10 = ReturnType<() => string>; // string +type T11 = ReturnType<(s: string) => void>; // void +type T12 = ReturnType<(() => T)>; // {} +type T13 = ReturnType<(() => T)>; // number[] +type T14 = ReturnType; // { a: number, b: string } +type T15 = ReturnType; // any +type T16 = ReturnType; // any + +type T20 = InstanceType; // C +type T21 = InstanceType; // any +type T22 = InstanceType; // any \ No newline at end of file diff --git a/arkguard/test/grammar/advanced_type/union_types.ts b/arkguard/test/grammar/advanced_type/union_types.ts new file mode 100644 index 0000000000000000000000000000000000000000..f1925495ad531d36bc701d2f1a47591070bdaa63 --- /dev/null +++ b/arkguard/test/grammar/advanced_type/union_types.ts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +function padLeft(value: string, padding: string | number): boolean { + return true; +} + +assert(padLeft('Hello World', 2), 'success'); diff --git a/arkguard/test/grammar/array_validation/array_at.ts b/arkguard/test/grammar/array_validation/array_at.ts new file mode 100644 index 0000000000000000000000000000000000000000..6a3f9ebd4981a32013585cea1a4e37154f60e5db --- /dev/null +++ b/arkguard/test/grammar/array_validation/array_at.ts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +var arr = [0, 1, 2, 3, 4, 5]; +console.log(arr[-1]) +assert(arr[5] === 5, 'success'); + +assert(arr[4] === 4, 'success'); diff --git a/arkguard/test/grammar/array_validation/array_copywithin.ts b/arkguard/test/grammar/array_validation/array_copywithin.ts new file mode 100644 index 0000000000000000000000000000000000000000..55cb0cc2373196d013d1a23d113bb6b7be268afc --- /dev/null +++ b/arkguard/test/grammar/array_validation/array_copywithin.ts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +const arr = [0, 1, 2, 3, 4, 5]; + +arr.copyWithin(2, 3); + +assert(arr[2] === 3, 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/array_validation/array_entries.ts b/arkguard/test/grammar/array_validation/array_entries.ts new file mode 100644 index 0000000000000000000000000000000000000000..c047f4915d49828fb1161371478af5dbddd37c56 --- /dev/null +++ b/arkguard/test/grammar/array_validation/array_entries.ts @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +var arr: number[] = [0, 1, 2, 3, 4, 5]; + +arr.entries(); + +const targetIndex: number = 2; +assert(arr[targetIndex] === targetIndex, 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/array_validation/array_every.ts b/arkguard/test/grammar/array_validation/array_every.ts new file mode 100644 index 0000000000000000000000000000000000000000..eedd3b66e487f0e1e3ddf76c8e1274dc873e7087 --- /dev/null +++ b/arkguard/test/grammar/array_validation/array_every.ts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let arr = [1, 2, 3, 4, 5]; + +let arr1 = arr.every( + function (value) { + return value > 0; + } +) + +assert(arr1 === true, 'success'); diff --git a/arkguard/test/grammar/array_validation/array_expanding.ts b/arkguard/test/grammar/array_validation/array_expanding.ts new file mode 100644 index 0000000000000000000000000000000000000000..23cba4ac2c662452b3c8f80d186039f043542300 --- /dev/null +++ b/arkguard/test/grammar/array_validation/array_expanding.ts @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +var arr1 = [1, 2, 3]; +var arr2 = [4, 5, 6]; +var arr3 = [...arr1, ...arr2] + +assert(arr3[3] === 4, 'success'); + +var arr4 = [...arr3]; +assert(arr3[4] === arr4[4], 'success'); diff --git a/arkguard/test/grammar/array_validation/array_fill.ts b/arkguard/test/grammar/array_validation/array_fill.ts new file mode 100644 index 0000000000000000000000000000000000000000..f0ad9aa8f393ce7ce9efa68418c00ac15af3c66b --- /dev/null +++ b/arkguard/test/grammar/array_validation/array_fill.ts @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +var arr = [0, 1, 2, 3, 4, 5]; + +arr.fill(3, 1, 5); + +assert(arr[1] === 3, 'success'); + +assert(arr[2] === 3, 'success'); + +assert(arr[3] === 3, 'success'); + +assert(arr[4] === 3, 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/array_validation/array_flat.ts b/arkguard/test/grammar/array_validation/array_flat.ts new file mode 100644 index 0000000000000000000000000000000000000000..9dbab617168604c62d038a58003150956b993019 --- /dev/null +++ b/arkguard/test/grammar/array_validation/array_flat.ts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let arr = [0, 1, 2, 3, 4, 5, [6, 7, 8]]; + +let arr2 = arr.flat(1); + +assert(arr2[6] === 6, 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/array_validation/array_forEach.ts b/arkguard/test/grammar/array_validation/array_forEach.ts new file mode 100644 index 0000000000000000000000000000000000000000..08cdb87543ead42077a3877ddb928a4cd1778f4c --- /dev/null +++ b/arkguard/test/grammar/array_validation/array_forEach.ts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let arr = [0, 1, 2, 3, 4, 5]; + +arr.forEach(function (value, index) { + assert(value === index, 'success'); +}); diff --git a/arkguard/test/grammar/array_validation/array_includes.ts b/arkguard/test/grammar/array_validation/array_includes.ts new file mode 100644 index 0000000000000000000000000000000000000000..bb610ccf27419550691b5907c1ff05214a86efa9 --- /dev/null +++ b/arkguard/test/grammar/array_validation/array_includes.ts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let arr = [0, 1, 2, 3, 4, 5]; + +let flag = arr.includes(1); + +assert(flag, 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/array_validation/array_index.ts b/arkguard/test/grammar/array_validation/array_index.ts new file mode 100644 index 0000000000000000000000000000000000000000..e555a7036344e34c9f6c30c564517c50770d0043 --- /dev/null +++ b/arkguard/test/grammar/array_validation/array_index.ts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let arr = [0, 1, 2, 3, 4, 5]; + +arr.forEach((value, index) => { + assert(arr.indexOf(value) === index, 'success'); +}); diff --git a/arkguard/test/grammar/array_validation/array_is.ts b/arkguard/test/grammar/array_validation/array_is.ts new file mode 100644 index 0000000000000000000000000000000000000000..f20321a7508a40a939a68f6badd42504679f4186 --- /dev/null +++ b/arkguard/test/grammar/array_validation/array_is.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let arr = [1, 2, 3, 4, 5]; + +assert(Array.isArray(arr) === true, 'success'); diff --git a/arkguard/test/grammar/array_validation/array_join.ts b/arkguard/test/grammar/array_validation/array_join.ts new file mode 100644 index 0000000000000000000000000000000000000000..411359c545d35e75e1caa9d9995e9b66a70022e7 --- /dev/null +++ b/arkguard/test/grammar/array_validation/array_join.ts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let arr = [0, 1, 2, 3, 4, 5]; + +let str = arr.join(''); + +assert(str === '012345', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/array_validation/array_keys.ts b/arkguard/test/grammar/array_validation/array_keys.ts new file mode 100644 index 0000000000000000000000000000000000000000..a079b41e5b8d60f20077583f1e0187349220ddca --- /dev/null +++ b/arkguard/test/grammar/array_validation/array_keys.ts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let arr = [0, 1, 2, 3, 4, 5]; + +let key = arr.keys(); + +assert(key.next().value === 0, 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/array_validation/array_lastindex.ts b/arkguard/test/grammar/array_validation/array_lastindex.ts new file mode 100644 index 0000000000000000000000000000000000000000..0f0132ff4055c56c6e3201ba46339f5a2b8f5d35 --- /dev/null +++ b/arkguard/test/grammar/array_validation/array_lastindex.ts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let arr = [1, 2, 3, 4, 5]; + +arr.forEach((value, index) => { + assert(arr.indexOf(value) === index, 'success'); +}); diff --git a/arkguard/test/grammar/array_validation/array_length.ts b/arkguard/test/grammar/array_validation/array_length.ts new file mode 100644 index 0000000000000000000000000000000000000000..15bf16407327d74ecead55e73404e6109dae0882 --- /dev/null +++ b/arkguard/test/grammar/array_validation/array_length.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let arr = [0, 1, 2, 3, 4, 5]; + +assert(arr.length === 6, 'success'); diff --git a/arkguard/test/grammar/array_validation/array_map.ts b/arkguard/test/grammar/array_validation/array_map.ts new file mode 100644 index 0000000000000000000000000000000000000000..abdb4e04656f49d1f72d44ec0ee0f089d201912d --- /dev/null +++ b/arkguard/test/grammar/array_validation/array_map.ts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let arr = [1, 2, 3, 4, 5]; + +let arr1 = arr.map(function (value) { + return value * 2 + 1; +}); + +arr.forEach((value, index) => { + assert(value * 2 + 1 === arr1[index], 'success'); +}); diff --git a/arkguard/test/grammar/array_validation/array_pop.ts b/arkguard/test/grammar/array_validation/array_pop.ts new file mode 100644 index 0000000000000000000000000000000000000000..056c5a8ef8d2a0edb91568ec39ace1177e54b765 --- /dev/null +++ b/arkguard/test/grammar/array_validation/array_pop.ts @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let arr = [0, 1, 2, 3, 4, 5]; + +let key = arr.pop(); + +assert(key === 5, 'success'); + +assert(arr[arr.length-1] === 4, 'success'); diff --git a/arkguard/test/grammar/array_validation/array_push.ts b/arkguard/test/grammar/array_validation/array_push.ts new file mode 100644 index 0000000000000000000000000000000000000000..2e37ca1a29b6a1f28f7905fc5d4169f36f7f00dd --- /dev/null +++ b/arkguard/test/grammar/array_validation/array_push.ts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let arr = [0, 1, 2, 3, 4, 5]; + +arr.push(6); + +assert(arr[arr.length-1] === 6, 'success'); diff --git a/arkguard/test/grammar/array_validation/array_reduce.ts b/arkguard/test/grammar/array_validation/array_reduce.ts new file mode 100644 index 0000000000000000000000000000000000000000..1ff4bce6b2a42263c27e8b4c616f6b5df9dc1475 --- /dev/null +++ b/arkguard/test/grammar/array_validation/array_reduce.ts @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let arr = [1, 2, 3, 4, 5]; + +let result = arr.reduce(function (last, now) { + return last + now; +}); + +assert(result === 15, 'success'); diff --git a/arkguard/test/grammar/array_validation/array_reverse.ts b/arkguard/test/grammar/array_validation/array_reverse.ts new file mode 100644 index 0000000000000000000000000000000000000000..5f01a6a275d812763a133966ff12a2b972accdc9 --- /dev/null +++ b/arkguard/test/grammar/array_validation/array_reverse.ts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let arr = [0, 1, 2, 3, 4, 5]; + +arr.reverse(); + +assert(arr[0] === 5, 'success'); diff --git a/arkguard/test/grammar/array_validation/array_shift.ts b/arkguard/test/grammar/array_validation/array_shift.ts new file mode 100644 index 0000000000000000000000000000000000000000..c086843cb6eda1bd8b3e4391f1561c75d3382f4b --- /dev/null +++ b/arkguard/test/grammar/array_validation/array_shift.ts @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let arr = [0, 1, 2, 3, 4, 5]; + +let key = arr.shift(); + +assert(key === 0, 'success'); + +assert(arr[0] === 1, 'success'); diff --git a/arkguard/test/grammar/array_validation/array_slice.ts b/arkguard/test/grammar/array_validation/array_slice.ts new file mode 100644 index 0000000000000000000000000000000000000000..1dac135f9e67ad086da2dfb38febda14fdf36b3d --- /dev/null +++ b/arkguard/test/grammar/array_validation/array_slice.ts @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let arr = [0, 1, 2, 3, 4, 5]; + +let arr2 = arr.slice(1, 3); + +assert(arr[0] === 0, 'success'); + +assert(arr2[0] === 1, 'success'); diff --git a/arkguard/test/grammar/array_validation/array_some.ts b/arkguard/test/grammar/array_validation/array_some.ts new file mode 100644 index 0000000000000000000000000000000000000000..80eeac5346b5478fefc117c1cf6976fb8481b45c --- /dev/null +++ b/arkguard/test/grammar/array_validation/array_some.ts @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let arr = [1, 2, 3, 4, 5]; + +let arr1 = arr.some(function (value) { + return value > 4; +}); + +assert(arr1 === true, 'success'); diff --git a/arkguard/test/grammar/array_validation/array_sort.ts b/arkguard/test/grammar/array_validation/array_sort.ts new file mode 100644 index 0000000000000000000000000000000000000000..dc468c990dc188e16221ee402fb9a20e8b87dad9 --- /dev/null +++ b/arkguard/test/grammar/array_validation/array_sort.ts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let arr = [0, 4, 5, 1, 2, 3]; + +arr.sort(); + +assert(arr[2] === 2, 'success'); diff --git a/arkguard/test/grammar/array_validation/array_toLocaleString.ts b/arkguard/test/grammar/array_validation/array_toLocaleString.ts new file mode 100644 index 0000000000000000000000000000000000000000..c57a9cecdd36e689dc362ecf0281cfda2453690f --- /dev/null +++ b/arkguard/test/grammar/array_validation/array_toLocaleString.ts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let arr = [0, 1, 2, 3, 4, 5]; + +let str = arr.toLocaleString(); + +assert(str === '0,1,2,3,4,5', 'success'); diff --git a/arkguard/test/grammar/array_validation/array_toString.ts b/arkguard/test/grammar/array_validation/array_toString.ts new file mode 100644 index 0000000000000000000000000000000000000000..ceb4cb72818bdd122582f29435c1dceee0c99f2f --- /dev/null +++ b/arkguard/test/grammar/array_validation/array_toString.ts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let arr = [0, 1, 2, 3, 4, 5]; + +let str = arr.toString(); + +assert(str === '0,1,2,3,4,5', 'success'); diff --git a/arkguard/test/grammar/array_validation/array_unshift.ts b/arkguard/test/grammar/array_validation/array_unshift.ts new file mode 100644 index 0000000000000000000000000000000000000000..1ea0a00d78dadf418a6b31473342d410a26f9d12 --- /dev/null +++ b/arkguard/test/grammar/array_validation/array_unshift.ts @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let arr = [0, 1, 2, 3, 4, 5]; + +let length = arr.unshift(3, 2, 1); + +assert(length === 9, 'success'); + +assert(arr[0] === 3, 'success'); diff --git a/arkguard/test/grammar/array_validation/array_values.ts b/arkguard/test/grammar/array_validation/array_values.ts new file mode 100644 index 0000000000000000000000000000000000000000..2e20c1dfcc4791c6913c2a93e48fcab5b0d703d2 --- /dev/null +++ b/arkguard/test/grammar/array_validation/array_values.ts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let arr = [0, 1, 2, 3, 4, 5]; + +let value = arr.values(); + +assert(value.next().value === 0, 'success'); diff --git a/arkguard/test/grammar/array_validation/readonly_array.ts b/arkguard/test/grammar/array_validation/readonly_array.ts new file mode 100644 index 0000000000000000000000000000000000000000..ba837cc6bc5a214d885c268f73dde877a3730716 --- /dev/null +++ b/arkguard/test/grammar/array_validation/readonly_array.ts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import assert = require('assert'); + +let arr: ReadonlyArray = [1, 2, 3, 4, 5]; + +assert(arr[4] === 5, 'success'); + +let arr1 = arr as number[]; + +arr1[0] = 0; + +assert(arr1[0] === 0, 'success'); + diff --git a/arkguard/test/grammar/circulations/for_in.ts b/arkguard/test/grammar/circulations/for_in.ts new file mode 100644 index 0000000000000000000000000000000000000000..76066622d06de8fa0facfcba7079efe8905b48cf --- /dev/null +++ b/arkguard/test/grammar/circulations/for_in.ts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let arr = [0, 1, 2, 3, 4, 5]; + +for (let a in arr) { + assert(a === arr[a].toString(), 'success'); +} diff --git a/arkguard/test/grammar/circulations/for_of.ts b/arkguard/test/grammar/circulations/for_of.ts new file mode 100644 index 0000000000000000000000000000000000000000..518e6d741d4367263873a21c022883db298127a1 --- /dev/null +++ b/arkguard/test/grammar/circulations/for_of.ts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let arr = [0, 1, 2, 3, 4, 5]; + +for (let a of arr) { + assert(a === arr[a], 'success'); +} diff --git a/arkguard/test/grammar/class_validation/class_abstract.ts b/arkguard/test/grammar/class_validation/class_abstract.ts new file mode 100644 index 0000000000000000000000000000000000000000..ed91e9058de843ff8b4d03841dd55fa19bb396d2 --- /dev/null +++ b/arkguard/test/grammar/class_validation/class_abstract.ts @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +abstract class Department { + + constructor(public name: string) { + } + + printName(): string { + return this.name; + } + + abstract getMeeting(): string; +} + +class AccountingDepartment extends Department { + + constructor() { + super('Accounting and Auditing'); + } + + getMeeting(): string { + return 'We meet as 10am!'; + } + + generateReports(): void { + console.log('Generating accounting reports...'); + } +} + +let department: Department; +department = new AccountingDepartment(); + +assert(department.printName() === 'Accounting and Auditing', 'success'); +assert(department.getMeeting() === 'We meet as 10am!', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/class_validation/class_accessor.ts b/arkguard/test/grammar/class_validation/class_accessor.ts new file mode 100644 index 0000000000000000000000000000000000000000..7f91a1291bad3886e35a87015bd6078152f077ff --- /dev/null +++ b/arkguard/test/grammar/class_validation/class_accessor.ts @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +class Employee { + private _fullName: string; + + get fullName(): string { + return this._fullName; + } + + set fullName(newName: string) { + this._fullName = newName; + } +} + +let employee = new Employee(); +employee.fullName = 'Bob Smith'; +assert(employee.fullName === 'Bob Smith', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/class_validation/class_compatible.ts b/arkguard/test/grammar/class_validation/class_compatible.ts new file mode 100644 index 0000000000000000000000000000000000000000..261f65ec7db401eb9aeac136a4a91032e33e100a --- /dev/null +++ b/arkguard/test/grammar/class_validation/class_compatible.ts @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +class Animal { + private name: string; + + constructor(theName: string) { + this.name = theName; + } +} + +class Rhino extends Animal { + constructor() { + super('Rhino'); + } +} + +let animal = new Animal('Rhino'); + +let rhino = new Rhino(); + +animal = rhino; + +assert(animal === rhino, 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/class_validation/class_declare.ts b/arkguard/test/grammar/class_validation/class_declare.ts new file mode 100644 index 0000000000000000000000000000000000000000..b7a19fc2f219f08f75d6745cccc4d9d3cf1821fb --- /dev/null +++ b/arkguard/test/grammar/class_validation/class_declare.ts @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +class Greeter { + greeting: string; + + constructor(message: string) { + this.greeting = message; + } + + greet(): string { + return 'Hello, ' + this.greeting; + } +} + +let greeter = new Greeter('world'); + +assert(greeter.greet() === 'Hello, world', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/class_validation/class_inherit.ts b/arkguard/test/grammar/class_validation/class_inherit.ts new file mode 100644 index 0000000000000000000000000000000000000000..239d96c706d939fa31e51017b0db1eda19e4fe9e --- /dev/null +++ b/arkguard/test/grammar/class_validation/class_inherit.ts @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +class Animal { + name: string; + + constructor(theName: string) { + this.name = theName; + } + + move(distanceInMeters: number = 0, mode: string): string { + return `${this.name} ${mode} ${distanceInMeters}m.`; + } +} + +class Dog extends Animal { + constructor(name: string) { + super(name); + } + + move(distanceInMeters = 5, mode: string): string { + console.log('Slithering...'); + return super.move(distanceInMeters, mode); + } + + bark(): string { + return 'Woof! Woof!'; + } +} + +const dog = new Dog('dog'); + +assert(dog.bark() === 'Woof! Woof!', 'success'); + +assert(dog.move(10, 'run') === 'dog run 10m.', 'success'); diff --git a/arkguard/test/grammar/class_validation/class_interface.ts b/arkguard/test/grammar/class_validation/class_interface.ts new file mode 100644 index 0000000000000000000000000000000000000000..fb695c6d42d72107f7c3963058a9221ab78e5ba4 --- /dev/null +++ b/arkguard/test/grammar/class_validation/class_interface.ts @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +class Point { + x: number; + y: number; + + +} + +interface Point3d extends Point { + z: number; +} + +let point3d: Point3d = {x: 1, y: 2, z: 3}; + +assert(point3d.x === 1, 'success'); +assert(point3d.y === 2, 'success'); +assert(point3d.z === 3, 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/class_validation/class_protected.ts b/arkguard/test/grammar/class_validation/class_protected.ts new file mode 100644 index 0000000000000000000000000000000000000000..4cfcec79e6eeb66e749c902c192a0a29f50c45db --- /dev/null +++ b/arkguard/test/grammar/class_validation/class_protected.ts @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +class Person { + protected name: string; + + protected constructor(theName: string) { + this.name = theName; + } +} + +class Employee extends Person { + private department: string; + + constructor(name: string, department: string) { + super(name); + this.department = department; + } + + public getElevatorPitch(): string { + return `Hello, my name is ${this.name} and I work in ${this.department}.`; + } +} + +let howard = new Employee('Howard', 'Sales'); + +assert(howard.getElevatorPitch() === 'Hello, my name is Howard and I work in Sales.', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/class_validation/class_public.ts b/arkguard/test/grammar/class_validation/class_public.ts new file mode 100644 index 0000000000000000000000000000000000000000..d8ee281f7095a079b1213172e1c2754de52096cf --- /dev/null +++ b/arkguard/test/grammar/class_validation/class_public.ts @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +class Animal { + public name: string; + + public constructor(theName: string) { + this.name = theName; + } + + public move(distanceInMeters: number): string { + return `${this.name} moved ${distanceInMeters}m.`; + } +} + +const dog = new Animal('dog'); + +assert(dog.move(10) === 'dog moved 10m.', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/class_validation/class_readonly.ts b/arkguard/test/grammar/class_validation/class_readonly.ts new file mode 100644 index 0000000000000000000000000000000000000000..02efee38ce94d22491fe7c315119f8ede531c402 --- /dev/null +++ b/arkguard/test/grammar/class_validation/class_readonly.ts @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +class Octopus { + readonly name: string; + + constructor(theName: string) { + this.name = theName; + } +} + +let this_man = new Octopus('Tom'); + +assert(this_man.name === 'Tom', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/class_validation/class_static.ts b/arkguard/test/grammar/class_validation/class_static.ts new file mode 100644 index 0000000000000000000000000000000000000000..5050ab4834a9d8b933895e33b0043da903f9b31a --- /dev/null +++ b/arkguard/test/grammar/class_validation/class_static.ts @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +class Grid { + static origin = {x: 3, y: 4}; + + calculateDistanceFromOrigin(point: { x: number; y: number; }): number { + let xDist = (point.x - Grid.origin.x); + let yDist = (point.y - Grid.origin.y); + return (xDist * xDist + yDist * yDist) / this.scale; + } + + constructor(public scale: number) { + } +} + +const grid1 = new Grid(1.0); // 1x scale +const grid2 = new Grid(5.0); // 5x scale + +assert(grid1.calculateDistanceFromOrigin({x: 10, y: 10}) === 85, 'success'); +assert(grid2.calculateDistanceFromOrigin({x: 10, y: 10}) === 17, 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/control_statement/condition_type.ts b/arkguard/test/grammar/control_statement/condition_type.ts new file mode 100644 index 0000000000000000000000000000000000000000..4ec448e7660a92043f27948d3babb51d6d68c471 --- /dev/null +++ b/arkguard/test/grammar/control_statement/condition_type.ts @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let a = 3; + +let b = 6; + +let c = a * 2 === b ? a : b; + +assert(c === a, 'success'); diff --git a/arkguard/test/grammar/control_statement/if_validation.ts b/arkguard/test/grammar/control_statement/if_validation.ts new file mode 100644 index 0000000000000000000000000000000000000000..0a93924c1aef49d9f816240c0a2cf8490a6507cb --- /dev/null +++ b/arkguard/test/grammar/control_statement/if_validation.ts @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let a = 3; + +let b = 6; + +let c; + +if (a * 2 === b) { + c = a + b; +} else { + c = b - a; +} + +assert(c === 9, 'success'); diff --git a/arkguard/test/grammar/data_type/json_validation.ts b/arkguard/test/grammar/data_type/json_validation.ts new file mode 100644 index 0000000000000000000000000000000000000000..3a5def80dc4363b579edfa6ff528513c69c644e6 --- /dev/null +++ b/arkguard/test/grammar/data_type/json_validation.ts @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let json_str = '[{"name":"小勇","age":18},{"name":"小刚","age":23},{"name":"大勇","age":25},{"name":"小花","age":13},{"name":"小黑","age":34},{"name":"小白","age":26}]'; + +let json_obj = JSON.parse(json_str); + +let json_str2 = JSON.stringify(json_obj); + +assert(json_str === json_str2, 'success'); diff --git a/arkguard/test/grammar/data_type/number_validation.ts b/arkguard/test/grammar/data_type/number_validation.ts new file mode 100644 index 0000000000000000000000000000000000000000..72c68fce30d2159f109d2556891b782b78a2e082 --- /dev/null +++ b/arkguard/test/grammar/data_type/number_validation.ts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let a: number = 123; +let b: number = 123; + +assert(a === b, 'success'); diff --git a/arkguard/test/grammar/data_type/type_conversion.ts b/arkguard/test/grammar/data_type/type_conversion.ts new file mode 100644 index 0000000000000000000000000000000000000000..fec24e9cc45ab0476412f5b06f8c9054839589bf --- /dev/null +++ b/arkguard/test/grammar/data_type/type_conversion.ts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +const num1 = '1234'; +const num2 = Number(num1); + +assert(num2 === 1234, 'success'); diff --git a/arkguard/test/grammar/data_type/type_exclude.ts b/arkguard/test/grammar/data_type/type_exclude.ts new file mode 100644 index 0000000000000000000000000000000000000000..9b06cef7566c4c69e1a1f934c65c1ce2e287a09f --- /dev/null +++ b/arkguard/test/grammar/data_type/type_exclude.ts @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +type Exclude = T extends U ? never : T; +// Equivalent to: type A = 'a' +type A = Exclude<'x' | 'a', 'x' | 'y' | 'z'> + +let a:A = 'a'; + +assert(a === 'a', 'success'); diff --git a/arkguard/test/grammar/data_type/type_omit.ts b/arkguard/test/grammar/data_type/type_omit.ts new file mode 100644 index 0000000000000000000000000000000000000000..ba707610b72fa9af51d8e64b44fda456aa95afdf --- /dev/null +++ b/arkguard/test/grammar/data_type/type_omit.ts @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +type Omit = Pick>; + +interface User { + id: number; + age: number; + name: string; +} + +// Equivalent to: type PickUser = { age: number; name: string; } +type OmitUser = Omit; + +const omit_user: OmitUser = {age: 18, name: 'xiaoming'}; + +assert(omit_user.age === 18, 'success'); + +assert(omit_user.name === 'xiaoming', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/data_type/type_pick.ts b/arkguard/test/grammar/data_type/type_pick.ts new file mode 100644 index 0000000000000000000000000000000000000000..89eb6f2000ce6dfc878b2731ddd663baa9840bce --- /dev/null +++ b/arkguard/test/grammar/data_type/type_pick.ts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +interface Shape { + color: string; +} + +type Shap = Pick + +let shap: Shap = {color: 'red'}; + +assert('color' in shap, 'success'); diff --git a/arkguard/test/grammar/date_validation/date_tojson.ts b/arkguard/test/grammar/date_validation/date_tojson.ts new file mode 100644 index 0000000000000000000000000000000000000000..f2bcd596a64ca3f1b81b44701bc2c4063776d8ec --- /dev/null +++ b/arkguard/test/grammar/date_validation/date_tojson.ts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let date = new Date(); + +const dateJson = date.toJSON(); + +const dateStr = date.toISOString(); + +assert(dateJson, 'success'); + +assert(dateStr, 'success'); diff --git a/arkguard/test/grammar/function_usage/function_usages.ts b/arkguard/test/grammar/function_usage/function_usages.ts new file mode 100644 index 0000000000000000000000000000000000000000..7d4aea53e200869f5ca18a35a5f3174e1ffa7b7b --- /dev/null +++ b/arkguard/test/grammar/function_usage/function_usages.ts @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let fun1 = (a, b): number => { + return a + b; +}; + +assert(fun1(1, 2) === 3, 'success'); + +let fun2 = a => a * a; + +assert(fun2(2) === 4, 'success'); + +function fun3(a, b, c = 3) { + return a + b + c; +} + +assert(fun3(1, 2) === 6, 'success'); + +function fun4(a, b, ...args) { + let res = a + b; + args.forEach(function (value, index) { + res += value; + }); + + return res; +} + +assert(fun4(1, 2, 3, 4, 5) === 15, 'success'); diff --git a/arkguard/test/grammar/function_usage/symbol_definition.ts b/arkguard/test/grammar/function_usage/symbol_definition.ts new file mode 100644 index 0000000000000000000000000000000000000000..0af173c4e4e8a94d91e8d8646f24103da039ac11 --- /dev/null +++ b/arkguard/test/grammar/function_usage/symbol_definition.ts @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let sym1 = Symbol('symbol1'); + +let sym2 = Symbol('symbol1'); + +assert(sym1 !== sym2, 'success'); + +let sym3 = Symbol.for('symbol2'); + +let sym4 = Symbol.for('symbol2'); + +assert(sym3 === sym4, 'success'); diff --git a/arkguard/test/grammar/function_validation/anonymous_function.ts b/arkguard/test/grammar/function_validation/anonymous_function.ts new file mode 100644 index 0000000000000000000000000000000000000000..f6fd83197d69380f2a82f729fe925fccd37d2e3d --- /dev/null +++ b/arkguard/test/grammar/function_validation/anonymous_function.ts @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +function add(x, y): any { + return x + y; +} + +assert(add(2, 3) === 5, 'success'); + +let myAdd = function (x, y): any { + return x + y; +}; + +assert(myAdd(3, 4) === 7, 'success'); diff --git a/arkguard/test/grammar/function_validation/function_default_parameter.ts b/arkguard/test/grammar/function_validation/function_default_parameter.ts new file mode 100644 index 0000000000000000000000000000000000000000..e3fa7e2a5fc1b5aaa336536300629a780da92f8e --- /dev/null +++ b/arkguard/test/grammar/function_validation/function_default_parameter.ts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +function buildName(firstName: string, lastName = "Smith") { + return firstName + " " + lastName; +} + +assert(buildName('Bob') === 'Bob Smith', 'success'); + +assert(buildName('Bob', undefined) === 'Bob Smith', 'success'); + +assert(buildName('Bob', "Adams") === 'Bob Adams', 'success'); diff --git a/arkguard/test/grammar/function_validation/function_optional_parameter.ts b/arkguard/test/grammar/function_validation/function_optional_parameter.ts new file mode 100644 index 0000000000000000000000000000000000000000..b968fda45826bfccf074b6e11383c9bc1d3fa2f5 --- /dev/null +++ b/arkguard/test/grammar/function_validation/function_optional_parameter.ts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +function buildName(firstName: string, lastName?: string) { + if (lastName) + return firstName + ' ' + lastName; + else + return firstName; +} + +assert(buildName('Bob') === 'Bob', 'success'); + +assert(buildName('Bob', 'Adams') === 'Bob Adams', 'success'); diff --git a/arkguard/test/grammar/function_validation/function_outer_variable.ts b/arkguard/test/grammar/function_validation/function_outer_variable.ts new file mode 100644 index 0000000000000000000000000000000000000000..21b0f0cdf3e287023ea66009de951bcbf2a9785b --- /dev/null +++ b/arkguard/test/grammar/function_validation/function_outer_variable.ts @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let z = 100; + +function addToZ(x, y) { + return x + y + z; +} + +assert(addToZ(100, 200) === 400, 'success'); diff --git a/arkguard/test/grammar/function_validation/function_overload.ts b/arkguard/test/grammar/function_validation/function_overload.ts new file mode 100644 index 0000000000000000000000000000000000000000..5bf3102e007c33db3bb1301d90f88304b99965c1 --- /dev/null +++ b/arkguard/test/grammar/function_validation/function_overload.ts @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let suits = ['hearts', 'spades', 'clubs', 'diamonds']; + +function pickCard(x: { suit: string; card: number; }[]): number; +function pickCard(x: number): { suit: string; card: number; }; +function pickCard(x): any { + if (typeof x === 'object') { + return Math.floor(0.5 * x.length); + } + // Otherwise just let them pick the card + else if (typeof x === 'number') { + let pickedSuit = Math.floor(x / 13); + return {suit: suits[pickedSuit], card: x % 13}; + } +} + +let myDeck = [{suit: 'diamonds', card: 2}, {suit: 'spades', card: 10}, {suit: 'hearts', card: 4}]; +let pickedCard1 = myDeck[pickCard(myDeck)]; + +assert(pickedCard1.card === 10, 'success'); +assert(pickedCard1.suit === 'spades', 'success'); + +let pickedCard2 = pickCard(15); + + +assert(pickedCard2.card === 2, 'success'); +assert(pickedCard2.suit === 'spades', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/function_validation/function_remaining_parameter.ts b/arkguard/test/grammar/function_validation/function_remaining_parameter.ts new file mode 100644 index 0000000000000000000000000000000000000000..09047561e0dc77084a3bb38125fada2db3b932a1 --- /dev/null +++ b/arkguard/test/grammar/function_validation/function_remaining_parameter.ts @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +function buildName(firstName: string, ...restOfName: string[]) { + return firstName + ' ' + restOfName.join(' '); +} + +let employeeName = buildName('Joseph', 'Samuel', 'Lucas', 'MacKinzie'); + +assert(employeeName === 'Joseph Samuel Lucas MacKinzie', 'success'); + +let buildNameFun: (fname: string, ...rest: string[]) => string = buildName; + +assert(buildNameFun('Joseph', 'Samuel', 'Lucas') === 'Joseph Samuel Lucas', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/function_validation/function_this.ts b/arkguard/test/grammar/function_validation/function_this.ts new file mode 100644 index 0000000000000000000000000000000000000000..f8906cd8a86b4452f46570e9ef2cbd7607baacba --- /dev/null +++ b/arkguard/test/grammar/function_validation/function_this.ts @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let deck = { + suits: ["hearts", "spades", "clubs", "diamonds"], + createCardPicker: function () { + return () => { + let pickedCard = 42; + let pickedSuit = pickedCard / 14; + + return {suit: this.suits[pickedSuit], card: pickedCard / 14}; + } + } +} + +let cardPicker = deck.createCardPicker(); +let pickedCard = cardPicker(); + +assert(pickedCard.card === 3, 'success'); + +assert(pickedCard.suit === 'diamonds', 'success'); diff --git a/arkguard/test/grammar/function_validation/function_types.ts b/arkguard/test/grammar/function_validation/function_types.ts new file mode 100644 index 0000000000000000000000000000000000000000..7679340bf97c035c6fd683f62fe322e1f23a61f1 --- /dev/null +++ b/arkguard/test/grammar/function_validation/function_types.ts @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +function add(x: number, y: number): number { + return x + y; +} + +assert(add(2, 3) === 5, 'success'); + +let theAdd = function (x: number, y: number): number { + return x + y; +}; + +assert(theAdd(2, 3) === 5, 'success'); + +let myAdd: (x: number, y: number) => number = + function (x: number, y: number): number { + return x + y; + }; + +assert(myAdd(2, 3) === 5, 'success'); diff --git a/arkguard/test/grammar/generics_validation/generics_interface.ts b/arkguard/test/grammar/generics_validation/generics_interface.ts new file mode 100644 index 0000000000000000000000000000000000000000..6976df86acda1caaf8f039f068e008aa9a10ee42 --- /dev/null +++ b/arkguard/test/grammar/generics_validation/generics_interface.ts @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + + +interface GenericIdentityFn { + (arg: T): T; +} + +function identity(arg: T): T { + return arg; +} + +let myIdentity: GenericIdentityFn = identity; + +assert(myIdentity(789) === 789, 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/generics_validation/generics_lenth.ts b/arkguard/test/grammar/generics_validation/generics_lenth.ts new file mode 100644 index 0000000000000000000000000000000000000000..716995e66950a58e59d65a04e25b2926086ae84d --- /dev/null +++ b/arkguard/test/grammar/generics_validation/generics_lenth.ts @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let nums = [0, 1, 2, 3, 4, 5]; + +function loggingIdentity1(arg: T[]): T[] { + return arg; +} + +assert(loggingIdentity1(nums).length === 6, 'success'); + +assert(loggingIdentity1(nums).indexOf(1) === 1, 'success'); + +function loggingIdentity2(arg: Array): Array { + console.log(arg.length); // Array has a .length, so no more error + return arg; +} + +assert(loggingIdentity2(nums).length === 6, 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/generics_validation/generics_types.ts b/arkguard/test/grammar/generics_validation/generics_types.ts new file mode 100644 index 0000000000000000000000000000000000000000..28ddce728036f5713f75ced57ec4b524ed96b32b --- /dev/null +++ b/arkguard/test/grammar/generics_validation/generics_types.ts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +function identity(arg: T): T { + return arg; +} + +let myIdentity: (arg: U) => U = identity; + +assert(myIdentity(3) === 3, 'success'); + +assert(myIdentity('huawei') === 'huawei', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/interface_validation/interface_class_method.ts b/arkguard/test/grammar/interface_validation/interface_class_method.ts new file mode 100644 index 0000000000000000000000000000000000000000..f9bea5f4f47237c416fce7cf45a0f63ec8774c0a --- /dev/null +++ b/arkguard/test/grammar/interface_validation/interface_class_method.ts @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +interface ClockInterface { + currentTime: Date; + + setTime(d: Date); +} + +class Clock implements ClockInterface { + currentTime: Date; + + setTime(d: Date) { + this.currentTime = d; + } + + constructor(h: number, m: number) { + } +} + +let nowClock = new Clock(3, 20); + +let now = Date.prototype; + +nowClock.setTime(now); + +assert(nowClock.currentTime === now, 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/interface_validation/interface_in.ts b/arkguard/test/grammar/interface_validation/interface_in.ts new file mode 100644 index 0000000000000000000000000000000000000000..f8906cd8a86b4452f46570e9ef2cbd7607baacba --- /dev/null +++ b/arkguard/test/grammar/interface_validation/interface_in.ts @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let deck = { + suits: ["hearts", "spades", "clubs", "diamonds"], + createCardPicker: function () { + return () => { + let pickedCard = 42; + let pickedSuit = pickedCard / 14; + + return {suit: this.suits[pickedSuit], card: pickedCard / 14}; + } + } +} + +let cardPicker = deck.createCardPicker(); +let pickedCard = cardPicker(); + +assert(pickedCard.card === 3, 'success'); + +assert(pickedCard.suit === 'diamonds', 'success'); diff --git a/arkguard/test/grammar/interface_validation/interface_index_signature.ts b/arkguard/test/grammar/interface_validation/interface_index_signature.ts new file mode 100644 index 0000000000000000000000000000000000000000..ca4ce4316ee449509aaa39d1e085120cab071a53 --- /dev/null +++ b/arkguard/test/grammar/interface_validation/interface_index_signature.ts @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +interface SquareConfig { + color?: string; + width?: number; + + [propName: string]: any; +} + +function createSquare(config: SquareConfig): { color: string; area: number } { + let newSquare = {color: 'white', area: 100}; + if (config.colr) { + newSquare.color = config.colr; + } + if (config.width) { + newSquare.area = config.width * config.width; + } + return newSquare; +} + +let mySquare = createSquare({colr: 'red', width: 100}); + +assert(mySquare.color === 'red', 'success'); +assert(mySquare.area === 10000, 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/interface_validation/interface_inherit.ts b/arkguard/test/grammar/interface_validation/interface_inherit.ts new file mode 100644 index 0000000000000000000000000000000000000000..082af939838ce16f92efa674d3bd7fa39f7e4d99 --- /dev/null +++ b/arkguard/test/grammar/interface_validation/interface_inherit.ts @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +interface Shape { + color: string; +} + +let shape = {}; +shape.color = 'blue'; + +assert('color' in shape, 'success'); diff --git a/arkguard/test/grammar/interface_validation/interface_inherit_class.ts b/arkguard/test/grammar/interface_validation/interface_inherit_class.ts new file mode 100644 index 0000000000000000000000000000000000000000..0e041ba897d1277e41531723546a357afcc044b2 --- /dev/null +++ b/arkguard/test/grammar/interface_validation/interface_inherit_class.ts @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +class Control { + private state: any; +} + +interface SelectableControl extends Control { + select(s: string): string; +} + +class Button extends Control implements SelectableControl { + select(s: string): string { + return s; + } +} + +let one_button = new Button(); +assert(one_button.select('two') === 'two', 'success'); diff --git a/arkguard/test/grammar/interface_validation/interface_keyof.ts b/arkguard/test/grammar/interface_validation/interface_keyof.ts new file mode 100644 index 0000000000000000000000000000000000000000..f57b2b8d4415634d4aee52f4e08e80e4cb686cfd --- /dev/null +++ b/arkguard/test/grammar/interface_validation/interface_keyof.ts @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +interface Box { + height: number; + width: number; +} + +interface Box { + scale: number; +} + +type BoxKeys = keyof Box; + +interface Box2 { + key:BoxKeys; +} + +let box:Box2 = {key:'height'}; + +assert(box.key === 'height', 'success'); diff --git a/arkguard/test/grammar/interface_validation/interface_merge.ts b/arkguard/test/grammar/interface_validation/interface_merge.ts new file mode 100644 index 0000000000000000000000000000000000000000..d3f1a0997eeb9158ca6e568f287c0804517e658f --- /dev/null +++ b/arkguard/test/grammar/interface_validation/interface_merge.ts @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +interface Box { + height: number; + width: number; +} + +interface Box { + scale: number; +} + +let box: Box = {height: 5, width: 6, scale: 10}; + +assert(box.height === 5, 'success'); + +assert(box.width === 6, 'success'); + +assert(box.scale === 10, 'success'); diff --git a/arkguard/test/grammar/interface_validation/interface_mix_type.ts b/arkguard/test/grammar/interface_validation/interface_mix_type.ts new file mode 100644 index 0000000000000000000000000000000000000000..bca5fb734479ec68fc0447da22b22dd9cf652272 --- /dev/null +++ b/arkguard/test/grammar/interface_validation/interface_mix_type.ts @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); +import {start} from "repl"; + +interface Counter { + (start: number): string; + + interval: number; + + reset(): void; +} + +function getCounter(): Counter { + const counter = function (start: number) { }; + counter.interval = 10; + counter.reset = function ():void { + counter.interval = 30 + }; + return counter; +} + +let c = getCounter(); +c(10); +c.reset(); + +assert(c.interval === 30, 'success') \ No newline at end of file diff --git a/arkguard/test/grammar/interface_validation/interface_optional_attributes.ts b/arkguard/test/grammar/interface_validation/interface_optional_attributes.ts new file mode 100644 index 0000000000000000000000000000000000000000..731e5796b0748f0a98326cb3e0a821523a226a12 --- /dev/null +++ b/arkguard/test/grammar/interface_validation/interface_optional_attributes.ts @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +interface SquareConfig { + color?: string; + width?: number; +} + +function createSquare(config: SquareConfig): { color: string; area: number } { + let newSquare = {color: 'white', area: 100}; + if (config.color) { + newSquare.color = config.color; + } + if (config.width) { + newSquare.area = config.width * config.width; + } + return newSquare; +} + +let mySquare = createSquare({color: 'black'}); + +assert(createSquare({color: 'black'}).color === 'black', 'success'); + +assert(createSquare({color: 'black'}).area === 100, 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/interface_validation/interface_property.ts b/arkguard/test/grammar/interface_validation/interface_property.ts new file mode 100644 index 0000000000000000000000000000000000000000..46c79caa04e3d73289521e63e9fca559e20a9777 --- /dev/null +++ b/arkguard/test/grammar/interface_validation/interface_property.ts @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +function printLabel(labelledObj: { label: string }) { + return labelledObj.label; +} + +let myObj = {size: 10, label: 'Size 10 Object'}; + +assert(printLabel(myObj) === 'Size 10 Object', 'success'); + +interface LabelledValue { + label: string; +} + +function getLabel(labelledObj: LabelledValue) { + return labelledObj.label; +} + +let myObj1 = {size: 10, label: 'Size 10 Object'}; + +assert(getLabel(myObj1) === 'Size 10 Object', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/interface_validation/interface_readonly_attributes.ts b/arkguard/test/grammar/interface_validation/interface_readonly_attributes.ts new file mode 100644 index 0000000000000000000000000000000000000000..96c270758f4465ce1d0b99b275c8ea901340bff1 --- /dev/null +++ b/arkguard/test/grammar/interface_validation/interface_readonly_attributes.ts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +interface Square { + readonly color: string; + readonly width: number; +} + +let mySquare: Square = {color: 'black', width: 50}; + +assert(mySquare.color === 'black', 'success'); +assert(mySquare.width === 50, 'success'); diff --git a/arkguard/test/grammar/module_validation/default_export.ts b/arkguard/test/grammar/module_validation/default_export.ts new file mode 100644 index 0000000000000000000000000000000000000000..60ef080ebbed301ad48384d62c91dd69b3bb72f8 --- /dev/null +++ b/arkguard/test/grammar/module_validation/default_export.ts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let s:String = 'huawei'; + +export default s; + diff --git a/arkguard/test/grammar/module_validation/default_export_test.ts b/arkguard/test/grammar/module_validation/default_export_test.ts new file mode 100644 index 0000000000000000000000000000000000000000..6cdf76a1f66650f35e39b19b3f305b81923ccc72 --- /dev/null +++ b/arkguard/test/grammar/module_validation/default_export_test.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +import s from './default_export'; + +assert(s === 'huawei', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/module_validation/export_validation_test.ts b/arkguard/test/grammar/module_validation/export_validation_test.ts new file mode 100644 index 0000000000000000000000000000000000000000..1d7b38d9db896de9712b160ea96b32971453a8b1 --- /dev/null +++ b/arkguard/test/grammar/module_validation/export_validation_test.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +export interface StringValidator { + isAcceptable(s: string): boolean; +} \ No newline at end of file diff --git a/arkguard/test/grammar/module_validation/import_tests.ts b/arkguard/test/grammar/module_validation/import_tests.ts new file mode 100644 index 0000000000000000000000000000000000000000..ddffec4c423c69183ab62cda0458e5e8486d2fb7 --- /dev/null +++ b/arkguard/test/grammar/module_validation/import_tests.ts @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +import {StringValidator} from "./export_validation_test"; + +export const numberRegexp = /^[0-9]+$/; + +export class ZipCodeValidator implements StringValidator { + isAcceptable(s: string) { + return s.length === 5 && numberRegexp.test(s); + } +} + +let str = new ZipCodeValidator(); + +assert(str.isAcceptable('12345'), 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/module_validation/name_space.ts b/arkguard/test/grammar/module_validation/name_space.ts new file mode 100644 index 0000000000000000000000000000000000000000..bc9379802add64166105995aa8e122fb2f3cb846 --- /dev/null +++ b/arkguard/test/grammar/module_validation/name_space.ts @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +interface StringValidator { + isAcceptable(s: string): boolean; +} + +let lettersRegexp = /^[A-Za-z]+$/; +let numberRegexp = /^[0-9]+$/; + +class LettersOnlyValidator implements StringValidator { + isAcceptable(s: string) { + return lettersRegexp.test(s); + } +} + +class ZipCodeValidator implements StringValidator { + isAcceptable(s: string) { + return s.length === 5 && numberRegexp.test(s); + } +} + +// Some samples to try +let strings = ["Hello", "98052", "101"]; + +// Validators to use +let validators: { [s: string]: StringValidator; } = {}; +validators["ZIP code"] = new ZipCodeValidator(); +validators["Letters only"] = new LettersOnlyValidator(); + + +assert(validators["Letters only"].isAcceptable(strings[0]), 'success'); +assert(validators["ZIP code"].isAcceptable(strings[1]), 'success'); diff --git a/arkguard/test/grammar/module_validation/namespace_extend_enum.ts b/arkguard/test/grammar/module_validation/namespace_extend_enum.ts new file mode 100644 index 0000000000000000000000000000000000000000..18f1b54cadec5118472a86f385d03def74f8cc0e --- /dev/null +++ b/arkguard/test/grammar/module_validation/namespace_extend_enum.ts @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +enum Color { + RED = 1, + GREEN = 2, + BLUE = 4 +} + +namespace Color { + export function mixColor(colorName: string): any { + if (colorName === "yellow") { + return Color.RED + Color.GREEN; + } else if (colorName === "white") { + return Color.RED + Color.GREEN + Color.BLUE; + } else if (colorName === "magenta") { + return Color.RED + Color.BLUE; + } else if (colorName === "cyan") { + return Color.GREEN + Color.BLUE; + } + } +} + +assert(Color.mixColor('yellow') === 3, 'success'); + +assert(Color.mixColor('white') === 7, 'success'); + +assert(Color.mixColor('magenta') === 5, 'success'); + +assert(Color.mixColor('cyan') === 6, 'success'); diff --git a/arkguard/test/grammar/module_validation/namespace_merge.ts b/arkguard/test/grammar/module_validation/namespace_merge.ts new file mode 100644 index 0000000000000000000000000000000000000000..f6ef2d29f7871519fcad69605ecd0cd369f49a28 --- /dev/null +++ b/arkguard/test/grammar/module_validation/namespace_merge.ts @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +namespace Animals { + export class Zebra { + } +} + +namespace Animals { + export interface Legged { + numberOfLegs: number; + } + + export class Dog { + } +} + +import Zebra = Animals.Zebra; + +import Dog = Animals.Dog; + +assert(Zebra, 'success'); + +assert(Dog, 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/number_validation/number_toExponential.ts b/arkguard/test/grammar/number_validation/number_toExponential.ts new file mode 100644 index 0000000000000000000000000000000000000000..1ae1f13956ff101d9589436641cc778fa6c4973d --- /dev/null +++ b/arkguard/test/grammar/number_validation/number_toExponential.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let binaryLiteral: number = 0b1010; + +assert(binaryLiteral.toExponential() === '1e+1', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/number_validation/number_toFixed.ts b/arkguard/test/grammar/number_validation/number_toFixed.ts new file mode 100644 index 0000000000000000000000000000000000000000..d6b8b34002aeef8f67ab92982c61bc5c6594b1be --- /dev/null +++ b/arkguard/test/grammar/number_validation/number_toFixed.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let binaryLiteral: number = 0b1010; + +assert(binaryLiteral.toFixed() === '10', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/number_validation/number_toLocaleString.ts b/arkguard/test/grammar/number_validation/number_toLocaleString.ts new file mode 100644 index 0000000000000000000000000000000000000000..be22545ad55af0aba5906c6f2c75293c7b2df70d --- /dev/null +++ b/arkguard/test/grammar/number_validation/number_toLocaleString.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let binaryLiteral: number = 0b1010; + +assert(binaryLiteral.toLocaleString() === '10', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/number_validation/number_toPrecision.ts b/arkguard/test/grammar/number_validation/number_toPrecision.ts new file mode 100644 index 0000000000000000000000000000000000000000..eb90cdc765afe766c4b51dfce961007b5b5bfcb6 --- /dev/null +++ b/arkguard/test/grammar/number_validation/number_toPrecision.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let binaryLiteral: number = 0b1010; + +assert(binaryLiteral.toPrecision() === '10', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/number_validation/number_toString.ts b/arkguard/test/grammar/number_validation/number_toString.ts new file mode 100644 index 0000000000000000000000000000000000000000..1cc520a061d0e872246a67b6172d4f366f7d1d70 --- /dev/null +++ b/arkguard/test/grammar/number_validation/number_toString.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let binaryLiteral: number = 0b1010; + +assert(binaryLiteral.toString() === '10', 'success'); diff --git a/arkguard/test/grammar/number_validation/number_valueOf.ts b/arkguard/test/grammar/number_validation/number_valueOf.ts new file mode 100644 index 0000000000000000000000000000000000000000..0044b6fd46eb4eaae9d8a9755ddf796c11e12046 --- /dev/null +++ b/arkguard/test/grammar/number_validation/number_valueOf.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let binaryLiteral: number = 0b1010; + +assert(binaryLiteral.valueOf() === 10, 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/string_validation/italics.ts b/arkguard/test/grammar/string_validation/italics.ts new file mode 100644 index 0000000000000000000000000000000000000000..73f19e9d66324aae971fb9680f947404a1fb9c96 --- /dev/null +++ b/arkguard/test/grammar/string_validation/italics.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = 'abc'; + +assert(str.italics() === 'abc', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/string_validation/str_link.ts b/arkguard/test/grammar/string_validation/str_link.ts new file mode 100644 index 0000000000000000000000000000000000000000..ad0466c3751155d4971e8fbe468dbfd545a1a1d5 --- /dev/null +++ b/arkguard/test/grammar/string_validation/str_link.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = 'abc'; + +assert(str.link('huawei.com') === 'abc', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/string_validation/str_toLocaleLowerCase.ts b/arkguard/test/grammar/string_validation/str_toLocaleLowerCase.ts new file mode 100644 index 0000000000000000000000000000000000000000..79921f1ee83ddcf52df76baeb7f5d21b810aa6eb --- /dev/null +++ b/arkguard/test/grammar/string_validation/str_toLocaleLowerCase.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = 'ABCDEFG'; + +assert(str.toLocaleLowerCase() === 'abcdefg', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/string_validation/string_anchor.ts b/arkguard/test/grammar/string_validation/string_anchor.ts new file mode 100644 index 0000000000000000000000000000000000000000..460aa47978d64feb752fc9a2332a2ca7500fc55a --- /dev/null +++ b/arkguard/test/grammar/string_validation/string_anchor.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = 'abcbcbc'; + +assert(str.anchor('d') === 'abcbcbc', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/string_validation/string_at.ts b/arkguard/test/grammar/string_validation/string_at.ts new file mode 100644 index 0000000000000000000000000000000000000000..6753c19a07602e8867cd806d7dddcde945178066 --- /dev/null +++ b/arkguard/test/grammar/string_validation/string_at.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = 'abcde'; + +assert(str[2] === 'c', 'success'); diff --git a/arkguard/test/grammar/string_validation/string_big.ts b/arkguard/test/grammar/string_validation/string_big.ts new file mode 100644 index 0000000000000000000000000000000000000000..444d09c22760e0145ef8dad51ef6bacd497e8c20 --- /dev/null +++ b/arkguard/test/grammar/string_validation/string_big.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = 'abc'; + +assert(str.big() === 'abc', 'success'); diff --git a/arkguard/test/grammar/string_validation/string_blink.ts b/arkguard/test/grammar/string_validation/string_blink.ts new file mode 100644 index 0000000000000000000000000000000000000000..d2ec994da8b2d1d2b8e629afcf861253aa8b1a21 --- /dev/null +++ b/arkguard/test/grammar/string_validation/string_blink.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = 'abcbcbc'; + +assert(str.blink() === 'abcbcbc', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/string_validation/string_bold.ts b/arkguard/test/grammar/string_validation/string_bold.ts new file mode 100644 index 0000000000000000000000000000000000000000..fc4f08abf6a818cea287bc865ef48ab23650731b --- /dev/null +++ b/arkguard/test/grammar/string_validation/string_bold.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = 'abcbcbc'; + +assert(str.bold() === 'abcbcbc', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/string_validation/string_charAt.ts b/arkguard/test/grammar/string_validation/string_charAt.ts new file mode 100644 index 0000000000000000000000000000000000000000..26a9d98380cc8be80f4a4e8a68d594daabccd276 --- /dev/null +++ b/arkguard/test/grammar/string_validation/string_charAt.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = 'abcbcbc'; + +assert(str.charAt(3) === 'b', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/string_validation/string_charCodeAt.ts b/arkguard/test/grammar/string_validation/string_charCodeAt.ts new file mode 100644 index 0000000000000000000000000000000000000000..8f0e168195df98668af5b4ea6703c11ffe93d045 --- /dev/null +++ b/arkguard/test/grammar/string_validation/string_charCodeAt.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = 'abcbcbc'; + +assert(str.charCodeAt(0) === 97, 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/string_validation/string_codePointAt.ts b/arkguard/test/grammar/string_validation/string_codePointAt.ts new file mode 100644 index 0000000000000000000000000000000000000000..93a0da1b35fac468a15231cf7670b380764c82cc --- /dev/null +++ b/arkguard/test/grammar/string_validation/string_codePointAt.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = 'abcbcbc'; + +assert(str.codePointAt(1) === 98, 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/string_validation/string_concat.ts b/arkguard/test/grammar/string_validation/string_concat.ts new file mode 100644 index 0000000000000000000000000000000000000000..fd2c614dae6c66925759a6450e070da0f3bbdbb0 --- /dev/null +++ b/arkguard/test/grammar/string_validation/string_concat.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = 'abc'; + +assert(str.concat('def') === 'abcdef', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/string_validation/string_endsWith.ts b/arkguard/test/grammar/string_validation/string_endsWith.ts new file mode 100644 index 0000000000000000000000000000000000000000..7928753573fe591dd42b0030b49ad18fe0989a5a --- /dev/null +++ b/arkguard/test/grammar/string_validation/string_endsWith.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = 'abc'; + +assert(str.endsWith('c'), 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/string_validation/string_fixed.ts b/arkguard/test/grammar/string_validation/string_fixed.ts new file mode 100644 index 0000000000000000000000000000000000000000..2f11ea36bd218338774f0276c1c934e2b858101e --- /dev/null +++ b/arkguard/test/grammar/string_validation/string_fixed.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = 'abc'; + +assert(str.fixed() === 'abc', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/string_validation/string_fontcolor.ts b/arkguard/test/grammar/string_validation/string_fontcolor.ts new file mode 100644 index 0000000000000000000000000000000000000000..b3cfa51c394e4aac23dfb11480747fb5e6623e65 --- /dev/null +++ b/arkguard/test/grammar/string_validation/string_fontcolor.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = 'abc'; + +assert(str.fontcolor('red') === 'abc', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/string_validation/string_includes.ts b/arkguard/test/grammar/string_validation/string_includes.ts new file mode 100644 index 0000000000000000000000000000000000000000..9e84acc86c21fb07ed17b91b24fbf45b1c6dd950 --- /dev/null +++ b/arkguard/test/grammar/string_validation/string_includes.ts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = 'abc,aaa,bbb,abcde'; + +assert(str.includes('abc') === true, 'success'); + diff --git a/arkguard/test/grammar/string_validation/string_index.ts b/arkguard/test/grammar/string_validation/string_index.ts new file mode 100644 index 0000000000000000000000000000000000000000..63f609c0d1669d6a70903bbbecd6cccb36896e23 --- /dev/null +++ b/arkguard/test/grammar/string_validation/string_index.ts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = 'abcdefgbacde'; + +assert(str.indexOf('a') === 0, 'success'); + +assert(str.lastIndexOf('b') === 7, 'success'); + +assert(str.indexOf('a', 3) === 8, 'success'); + +assert(str.lastIndexOf('a', 8) === 8, 'success'); diff --git a/arkguard/test/grammar/string_validation/string_indexOf.ts b/arkguard/test/grammar/string_validation/string_indexOf.ts new file mode 100644 index 0000000000000000000000000000000000000000..86804ef4fc0af585019897da3f3ed98ac76132ad --- /dev/null +++ b/arkguard/test/grammar/string_validation/string_indexOf.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = 'abcbcbc'; + +assert(str.indexOf('b') === 1, 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/string_validation/string_lastIndexOf.ts b/arkguard/test/grammar/string_validation/string_lastIndexOf.ts new file mode 100644 index 0000000000000000000000000000000000000000..f563f2bbdc543d4dec5af65061741e89e79fd1cc --- /dev/null +++ b/arkguard/test/grammar/string_validation/string_lastIndexOf.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = 'abcbcbc'; + +assert(str.lastIndexOf('b') === 5, 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/string_validation/string_length.ts b/arkguard/test/grammar/string_validation/string_length.ts new file mode 100644 index 0000000000000000000000000000000000000000..7ae027bfd150b66fcb81ff7389efef6f09327070 --- /dev/null +++ b/arkguard/test/grammar/string_validation/string_length.ts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = 'abc'; + +assert(str.length === 3, 'success'); + diff --git a/arkguard/test/grammar/string_validation/string_padEnd.ts b/arkguard/test/grammar/string_validation/string_padEnd.ts new file mode 100644 index 0000000000000000000000000000000000000000..5922a34865bf828bb6b126f524163f5befd005f3 --- /dev/null +++ b/arkguard/test/grammar/string_validation/string_padEnd.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = 'abc'; + +assert(str.padEnd(8, 'de') === 'abcdeded', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/string_validation/string_padStart.ts b/arkguard/test/grammar/string_validation/string_padStart.ts new file mode 100644 index 0000000000000000000000000000000000000000..119585f88f7d1fabef99b5d8187f6722cacbc135 --- /dev/null +++ b/arkguard/test/grammar/string_validation/string_padStart.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = 'abc'; + +assert(str.padStart(8, 'de') === 'dededabc', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/string_validation/string_repeat.ts b/arkguard/test/grammar/string_validation/string_repeat.ts new file mode 100644 index 0000000000000000000000000000000000000000..60474e564b315df6fe4f8de9706c14b142f4769b --- /dev/null +++ b/arkguard/test/grammar/string_validation/string_repeat.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = 'abc'; + +assert(str.repeat(3) === 'abcabcabc', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/string_validation/string_slice.ts b/arkguard/test/grammar/string_validation/string_slice.ts new file mode 100644 index 0000000000000000000000000000000000000000..d625413c23a3cdc324e30e35150650e0c19ef415 --- /dev/null +++ b/arkguard/test/grammar/string_validation/string_slice.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = 'abcdefg'; + +assert(str.slice(1, 4) === 'bcd', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/string_validation/string_small.ts b/arkguard/test/grammar/string_validation/string_small.ts new file mode 100644 index 0000000000000000000000000000000000000000..fe6c5951b4b80895a8e39b72b77580aa5d33fa43 --- /dev/null +++ b/arkguard/test/grammar/string_validation/string_small.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = 'abc'; + +assert(str.small() === 'abc', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/string_validation/string_startsWith.ts b/arkguard/test/grammar/string_validation/string_startsWith.ts new file mode 100644 index 0000000000000000000000000000000000000000..8d8098400393f3d12f69f1a529927bea3edf9972 --- /dev/null +++ b/arkguard/test/grammar/string_validation/string_startsWith.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = 'abcdefg'; + +assert(str.startsWith('a'), 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/string_validation/string_strike.ts b/arkguard/test/grammar/string_validation/string_strike.ts new file mode 100644 index 0000000000000000000000000000000000000000..2402ac468b4f5e489eae43e2a19c465deedc701c --- /dev/null +++ b/arkguard/test/grammar/string_validation/string_strike.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = 'abcdefg'; + +assert(str.strike() === 'abcdefg', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/string_validation/string_sub.ts b/arkguard/test/grammar/string_validation/string_sub.ts new file mode 100644 index 0000000000000000000000000000000000000000..9dcf0ce51e6f8f81e8427ba7fdf3eae474fbeaef --- /dev/null +++ b/arkguard/test/grammar/string_validation/string_sub.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = 'abc'; + +assert(str.sub() === 'abc', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/string_validation/string_substr.ts b/arkguard/test/grammar/string_validation/string_substr.ts new file mode 100644 index 0000000000000000000000000000000000000000..e421e24c5a83d310f491b29e98e2f0dc1871a0fa --- /dev/null +++ b/arkguard/test/grammar/string_validation/string_substr.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = 'abcdefg'; + +assert(str.substr(1, 4) === 'bcde', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/string_validation/string_substring.ts b/arkguard/test/grammar/string_validation/string_substring.ts new file mode 100644 index 0000000000000000000000000000000000000000..9785bd1a2c13249dfb0b35af20b074a0113c1257 --- /dev/null +++ b/arkguard/test/grammar/string_validation/string_substring.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = 'abcdefg'; + +assert(str.substring(1, 4) === 'bcd', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/string_validation/string_sup.ts b/arkguard/test/grammar/string_validation/string_sup.ts new file mode 100644 index 0000000000000000000000000000000000000000..6e029d54c833a757bea5a42808d26f8d6868952f --- /dev/null +++ b/arkguard/test/grammar/string_validation/string_sup.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = 'abcdefg'; + +assert(str.sup() === 'abcdefg', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/string_validation/string_toLocaleUpperCase.ts b/arkguard/test/grammar/string_validation/string_toLocaleUpperCase.ts new file mode 100644 index 0000000000000000000000000000000000000000..cd535e410912678109c8ed40747a38293b4dcee7 --- /dev/null +++ b/arkguard/test/grammar/string_validation/string_toLocaleUpperCase.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = 'abcdefg'; + +assert(str.toLocaleUpperCase() === 'ABCDEFG', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/string_validation/string_toLowerCase.ts b/arkguard/test/grammar/string_validation/string_toLowerCase.ts new file mode 100644 index 0000000000000000000000000000000000000000..12b82e33f6c639b33990b167b19fef17d4a88dc8 --- /dev/null +++ b/arkguard/test/grammar/string_validation/string_toLowerCase.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = 'ABCDEFG'; + +assert(str.toLowerCase() === 'abcdefg', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/string_validation/string_toString.ts b/arkguard/test/grammar/string_validation/string_toString.ts new file mode 100644 index 0000000000000000000000000000000000000000..ed684d97fdbab07f45927db0affea18d69cd97a7 --- /dev/null +++ b/arkguard/test/grammar/string_validation/string_toString.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = 'abc'; + +assert(str.toString() === 'abc', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/string_validation/string_toUpperCase.ts b/arkguard/test/grammar/string_validation/string_toUpperCase.ts new file mode 100644 index 0000000000000000000000000000000000000000..f9b58a8216d15a84a73935a25d3110656ef45332 --- /dev/null +++ b/arkguard/test/grammar/string_validation/string_toUpperCase.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = 'abcdefg'; + +assert(str.toUpperCase() === 'ABCDEFG', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/string_validation/string_trim.ts b/arkguard/test/grammar/string_validation/string_trim.ts new file mode 100644 index 0000000000000000000000000000000000000000..f47acec47015999ba355d5de3184e5bc20aa2053 --- /dev/null +++ b/arkguard/test/grammar/string_validation/string_trim.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = ' abc '; + +assert(str.trim() === 'abc', 'success'); diff --git a/arkguard/test/grammar/string_validation/string_trimEnd.ts b/arkguard/test/grammar/string_validation/string_trimEnd.ts new file mode 100644 index 0000000000000000000000000000000000000000..322560b34c1efe1a178dee84126566bc7490ce37 --- /dev/null +++ b/arkguard/test/grammar/string_validation/string_trimEnd.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = 'abcdefg '; + +assert(str.trimEnd() === 'abcdefg', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/string_validation/string_trimLeft.ts b/arkguard/test/grammar/string_validation/string_trimLeft.ts new file mode 100644 index 0000000000000000000000000000000000000000..1c74bd9c19ed6fc2d023a6c549780d4de4ab9548 --- /dev/null +++ b/arkguard/test/grammar/string_validation/string_trimLeft.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = ' abcdefg'; + +assert(str.trimLeft() === 'abcdefg', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/string_validation/string_trimRight.ts b/arkguard/test/grammar/string_validation/string_trimRight.ts new file mode 100644 index 0000000000000000000000000000000000000000..7f11181a6c4c163fc7c493653916c16147dfb5bd --- /dev/null +++ b/arkguard/test/grammar/string_validation/string_trimRight.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = 'abcdefg '; + +assert(str.trimRight() === 'abcdefg', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/string_validation/string_trimStart.ts b/arkguard/test/grammar/string_validation/string_trimStart.ts new file mode 100644 index 0000000000000000000000000000000000000000..b5a6e1a9dec2adb202b33269d1d3c9c83a6fd5fc --- /dev/null +++ b/arkguard/test/grammar/string_validation/string_trimStart.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = ' abcdefg'; + +assert(str.trimStart() === 'abcdefg', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/string_validation/string_valueOf.ts b/arkguard/test/grammar/string_validation/string_valueOf.ts new file mode 100644 index 0000000000000000000000000000000000000000..66e62a69f06724e6e32a88ba36c6417abd6df460 --- /dev/null +++ b/arkguard/test/grammar/string_validation/string_valueOf.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str = '234'; + +assert(str.valueOf() === '234', 'success'); \ No newline at end of file diff --git a/arkguard/test/grammar/types_definition/any_define.ts b/arkguard/test/grammar/types_definition/any_define.ts new file mode 100644 index 0000000000000000000000000000000000000000..c764c81c1d8a89129b512c128d917a708ec852a6 --- /dev/null +++ b/arkguard/test/grammar/types_definition/any_define.ts @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let num: any = 3; + +assert(num === 3, 'success'); + +let str: any = 'a'; + +assert(str === 'a', 'success'); + +let boo: any = true; + +assert(boo === true, 'success'); diff --git a/arkguard/test/grammar/types_definition/array_define.ts b/arkguard/test/grammar/types_definition/array_define.ts new file mode 100644 index 0000000000000000000000000000000000000000..c673234eddea5d2ffaa896bec5d7bbfb59980c9f --- /dev/null +++ b/arkguard/test/grammar/types_definition/array_define.ts @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let nums: number[] = [1, 2, 3, 4, 5]; + +nums.forEach(function (value, index) { + assert(value === nums[index], 'success'); +}); + +let strs: string[] = ['a', 'b', 'c', 'd']; + +assert(strs[0] === 'a', 'success'); + +let list: any[] = [0, 'a', true, 3]; + +assert(list[1] === 'a', 'success'); diff --git a/arkguard/test/grammar/types_definition/boolean_define.ts b/arkguard/test/grammar/types_definition/boolean_define.ts new file mode 100644 index 0000000000000000000000000000000000000000..630ca5d6f3a5ae2c708e434668047c399fc3b4f0 --- /dev/null +++ b/arkguard/test/grammar/types_definition/boolean_define.ts @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let true_flag = true; + +assert(true_flag === true, 'success'); + +let false_flag = false; + +assert(false_flag === false, 'success'); diff --git a/arkguard/test/grammar/types_definition/enum_define.ts b/arkguard/test/grammar/types_definition/enum_define.ts new file mode 100644 index 0000000000000000000000000000000000000000..1f9a06b4fea2564ff754e5805c6269186cdf6ea9 --- /dev/null +++ b/arkguard/test/grammar/types_definition/enum_define.ts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +enum Color {red = 0, green = 1, bule = 2} + +let r = Color.red; + +assert(r === 0, 'success'); + +let g = Color.green; + +assert(Color[g] === 'green', 'success'); diff --git a/arkguard/test/grammar/types_definition/none_define.ts b/arkguard/test/grammar/types_definition/none_define.ts new file mode 100644 index 0000000000000000000000000000000000000000..fa6e2122bcee37d6c0ead4950f95fd2acbe5073f --- /dev/null +++ b/arkguard/test/grammar/types_definition/none_define.ts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let u: undefined = undefined; + +assert(!u, 'success'); + +let n: null = null; + +assert(!n, 'success'); + + + diff --git a/arkguard/test/grammar/types_definition/number_types.ts b/arkguard/test/grammar/types_definition/number_types.ts new file mode 100644 index 0000000000000000000000000000000000000000..0f2d200dc742aa13b2c870f3591a166840ae506c --- /dev/null +++ b/arkguard/test/grammar/types_definition/number_types.ts @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let decLiteral: number = 6; + +let hexLiteral: number = 0xf00d; + +let binaryLiteral: number = 0b1010; + +let octalLiteral: number = 0o744; + +assert(decLiteral === 6, 'success'); + +assert(hexLiteral === 0xf00d, 'success'); + +assert(binaryLiteral === 0b1010, 'success'); + +assert(octalLiteral === 0o744, 'success'); diff --git a/arkguard/test/grammar/types_definition/string_define.ts b/arkguard/test/grammar/types_definition/string_define.ts new file mode 100644 index 0000000000000000000000000000000000000000..84c1f44d09cef9152f002f6262d609436b8b6a9b --- /dev/null +++ b/arkguard/test/grammar/types_definition/string_define.ts @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str1 = 'abc'; + +assert(str1 === 'abc', 'success'); + + +let str2 = 'def'; + +assert(str2 === 'def', 'success'); + +let str3 = `aa${str1}bb${str2}cc\${}`; + +assert(str3 === 'aaabcbbdefcc${}', 'success'); diff --git a/arkguard/test/grammar/types_definition/tuple_define.ts b/arkguard/test/grammar/types_definition/tuple_define.ts new file mode 100644 index 0000000000000000000000000000000000000000..a0010ace5a0aa951b179dc2d9ec36d5911fadad7 --- /dev/null +++ b/arkguard/test/grammar/types_definition/tuple_define.ts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let x: [string, number, boolean]; + +x = ['helloWorld', 1, true]; + +assert(x[0] === 'helloWorld', 'success'); diff --git a/arkguard/test/grammar/variable_declaration/const_declaration.ts b/arkguard/test/grammar/variable_declaration/const_declaration.ts new file mode 100644 index 0000000000000000000000000000000000000000..33898a7fd40ac1543b5ccf39f1a9ec87832b9d8f --- /dev/null +++ b/arkguard/test/grammar/variable_declaration/const_declaration.ts @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +const NAME: string = 'SanYe'; + +assert(NAME === 'SanYe', 'success'); + +const F4: String[] = ['Jay', 'JJ', 'Gang', 'Bai']; + +const [JAY, JJ, GANG, BAI] = F4; + +assert(JJ === 'JJ', 'success'); + +const CHUAN = { + name: 'zhou', + age: 30, + song: function (): string { + return 'I can sing qinghua' + } +}; + +let {name, age, song} = CHUAN; + +assert(age === 30, 'success'); diff --git a/arkguard/test/grammar/variable_declaration/let_declaration.ts b/arkguard/test/grammar/variable_declaration/let_declaration.ts new file mode 100644 index 0000000000000000000000000000000000000000..a991fd48e1e3c5787acb5d668a28b5989074a4b3 --- /dev/null +++ b/arkguard/test/grammar/variable_declaration/let_declaration.ts @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let language: string = 'Chinese'; + +{ + let language: string = 'English'; + assert(language === 'English', 'success'); +} + +assert(language === 'Chinese', 'success'); diff --git a/arkguard/test/grammar/variable_declaration/string_declaration.ts b/arkguard/test/grammar/variable_declaration/string_declaration.ts new file mode 100644 index 0000000000000000000000000000000000000000..e16e77145340ff227ab1a7bfd20e47574702aa9b --- /dev/null +++ b/arkguard/test/grammar/variable_declaration/string_declaration.ts @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let str1 = 'abc'; + +assert(str1 === 'abc', 'success'); + +let str2 = 'def'; + +assert(str2 === 'def', 'success'); + +let str3 = `aa${str1} +bb${str2}cc\${}`; + +assert(str3 === 'aaabc\nbbdefcc${}', 'success'); diff --git a/arkguard/test/grammar/variable_declaration/type_inference.ts b/arkguard/test/grammar/variable_declaration/type_inference.ts new file mode 100644 index 0000000000000000000000000000000000000000..c026f108e942f8ac2c0c111f31db1275c4f8502c --- /dev/null +++ b/arkguard/test/grammar/variable_declaration/type_inference.ts @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert = require('assert'); + +let arr = [0, 1, null, '1'] + +assert(arr instanceof Array, 'success'); + +let num: any = 333; + +assert(typeof num === 'number', 'success'); + +let str: any = '[0, 1, null]'; + +assert(typeof str === 'string', 'success'); + +class Animal { + move(distanceInMeters: number = 0): void { + console.log(`Animal moved ${distanceInMeters}m.`); + } +} + +let ani = new Animal(); + +assert(ani instanceof Animal, 'success'); + diff --git a/arkguard/test/ut/NameGenerator.spec.ts b/arkguard/test/ut/NameGenerator.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..4c091fc884483a92856d94fb899443865d2798aa --- /dev/null +++ b/arkguard/test/ut/NameGenerator.spec.ts @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {describe, it} from 'mocha'; +import {assert} from 'chai'; +import {getNameGenerator, NameGeneratorType} from '../../src/generator/NameFactory'; +import {NameGeneratorOptions} from '../../src/generator/INameGenerator'; + +const orderedName = [ + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', + 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', + 'u', 'v', 'w', 'x', 'y', 'z', 'a1', 'b1', 'c1', 'd1', + 'e1', 'f1', 'g1', 'h1', 'i1', 'j1', 'k1', 'l1', 'm1', 'n1', + 'o1', 'p1', 'q1', 'r1', 's1', 't1', 'u1', 'v1', 'w1', 'x1', + 'y1', 'z1', 'a2', 'b2', 'c2', 'd2', 'e2', 'f2', 'g2', 'h2', + 'i2', 'j2', 'k2', 'l2', 'm2', 'n2', 'o2', 'p2', 'q2', 'r2', + 's2', 't2', 'u2', 'v2', 'w2', 'x2', 'y2', 'z2', 'a3', 'b3', + 'c3', 'd3', 'e3', 'f3', 'g3', 'h3', 'i3', 'j3', 'k3', 'l3', + 'm3', 'n3', 'o3', 'p3', 'q3', 'r3', 's3', 't3', 'u3', 'v3', + 'w3', 'x3', 'y3', 'z3' +]; + +describe("test for name generator", function () { + describe('ordered name generator test', function () { + it('ordered name generator check', function () { + const orderedGenerator = getNameGenerator(NameGeneratorType.ORDERED); + + for (let i = 0; i < 104; i++) { + assert.strictEqual(orderedGenerator.getName(), orderedName[i]); + } + }); + }); + + describe('disordered name generator test', function () { + const disorderGenerator = getNameGenerator(NameGeneratorType.DISORDERED); + let arr = [] + for (let i = 0; i < 104; i++) { + arr.push(disorderGenerator.getName()); + } + + it('disordered name generator check value', function () { + for (let i = 1; i < 5; i++) { + const targetName = orderedName.slice(26 * (i - 1), 26 * i); + const sliceArr = arr.slice(26 * (i - 1), 26 * i); + sliceArr.sort(); + sliceArr.forEach(((value, index) => { + assert.strictEqual(value, targetName[index]); + })); + } + }); + + it('disordered name generator check order', function () { + let count = 0; + + for (let i = 2; i < 26; i++) { + const downConsecutive = (arr[i - 2].charCodeAt(0) - arr[i - 1].charCodeAt(0) === 1) && + (arr[i - 1].charCodeAt(0) - arr[i].charCodeAt(0) === 1); + if (downConsecutive) { + count++; + } + + const upConsecutive = (arr[i].charCodeAt(0) - arr[i - 1].charCodeAt(0) === 1) && + (arr[i - 1].charCodeAt(0) - arr[i - 2].charCodeAt(0) === 1); + if (upConsecutive) { + count = count + 1; + } + } + + assert.isNotTrue(count > 5); + }); + }); + + describe('underline name generator test', function () { + it('underline name generator no option check value', function () { + const underlineGenerator = getNameGenerator(NameGeneratorType.UNDERLINE); + for (let i = 0; i < 128; i++) { + assert.strictEqual(underlineGenerator.getName(), '_'.repeat(i + 1)); + } + + assert.isNull(underlineGenerator.getName()); + }); + + it('underline name generator with option check value', function () { + const options: NameGeneratorOptions = { + underlineMaxLength: 120 + }; + + const underlineGenerator = getNameGenerator(NameGeneratorType.UNDERLINE, options); + for (let i = 0; i < options.underlineMaxLength; i++) { + assert.strictEqual(underlineGenerator.getName(), '_'.repeat(i + 1)); + } + + assert.isNull(underlineGenerator.getName()); + }); + }); + + describe('hex name generator test', function () { + it('hex name generator no option check length', function () { + const hexGenerator = getNameGenerator(NameGeneratorType.HEX); + for (let i = 0; i < 128; i++) { + assert.strictEqual(hexGenerator.getName().length, 8); + } + }); + + it('hex name generator no option check value', function () { + const hexGenerator = getNameGenerator(NameGeneratorType.HEX); + for (let i = 0; i < 128; i++) { + const hexName = hexGenerator.getName(); + + assert.isFalse(hexName.startsWith('_0x')); + assert.isFalse(hexName.endsWith('_')); + + for (let j = 0; j < 8; j++) { + const isHex = (hexName[j] >= '0' && hexName[j] <= '9') || (hexName[j] >= 'a' && hexName[j] <= 'f'); + assert.isTrue(isHex); + } + } + }); + + it('hex name generator with option check length', function () { + const options = { + hexLength: 10 + }; + + const hexGenerator = getNameGenerator(NameGeneratorType.HEX, options); + for (let i = 0; i < 128; i++) { + assert.strictEqual(hexGenerator.getName().length, 20); + } + }); + + it('hex name generator with option check value', function () { + const options = { + hexLength: 10 + }; + + const hexGenerator = getNameGenerator(NameGeneratorType.HEX, options); + for (let i = 0; i < 128; i++) { + const hexName = hexGenerator.getName(); + + assert.isFalse(hexName.startsWith('_0x')); + assert.isFalse(hexName.endsWith('_')); + + for (let j = 0; j < 20; j++) { + const isHex = (hexName[j] >= '0' && hexName[j] <= '9') || (hexName[j] >= 'a' && hexName[j] <= 'f'); + assert.isTrue(isHex); + } + } + }); + }); + + describe('dictionary name generator test', function () { + const noOptionTarget = [ + 'hello', 'Hello', 'hEllo', 'HEllo', 'heLlo', + 'HeLlo', 'hELlo', 'HELlo', 'helLo', 'HelLo', + 'hElLo', 'HElLo', 'heLLo', 'HeLLo', 'hELLo', + 'HELLo', 'hellO', 'HellO', 'hEllO', 'HEllO', + 'heLlO', 'HeLlO', 'hELlO', 'HELlO', 'helLO', + 'HelLO', 'hElLO', 'HElLO', 'heLLO', 'HeLLO', + 'hELLO', 'HELLO', 'world', 'World', 'wOrld', + 'WOrld', 'woRld', 'WoRld', 'wORld', 'WORld', + 'worLd', 'WorLd', 'wOrLd', 'WOrLd', 'woRLd', + 'WoRLd', 'wORLd', 'WORLd', 'worlD', 'WorlD', + 'wOrlD', 'WOrlD', 'woRlD', 'WoRlD', 'wORlD', + 'WORlD', 'worLD', 'WorLD', 'wOrLD', 'WOrLD', + 'woRLD', 'WoRLD', 'wORLD', 'WORLD', 'dictionary', + 'Dictionary', 'dIctionary', 'DIctionary', 'diCtionary', 'DiCtionary', + 'dICtionary', 'DICtionary', 'dicTionary', 'DicTionary', 'dIcTionary', + 'DIcTionary', 'diCTionary', 'DiCTionary', 'dICTionary', 'DICTionary', + 'dictIonary', 'DictIonary', 'dIctIonary', 'DIctIonary', 'diCtIonary', + 'DiCtIonary', 'dICtIonary', 'DICtIonary', 'dicTIonary', 'DicTIonary', + 'dIcTIonary', 'DIcTIonary', 'diCTIonary', 'DiCTIonary', 'dICTIonary', + 'DICTIonary', 'dictiOnary', 'DictiOnary', 'dIctiOnary', 'DIctiOnary' + ]; + + const optionTarget = [ + 'tom', 'Tom', 'tOm', 'TOm', 'toM', 'ToM', 'tOM', 'TOM', 'jerry', 'Jerry', + 'jErry', 'JErry', 'jeRry', 'JeRry', 'jERry', 'JERry', 'jerRy', 'JerRy', + 'jErRy', 'JErRy', 'jeRRy', 'JeRRy', 'jERRy', 'JERRy', 'jerrY', 'JerrY', + 'jErrY', 'JErrY', 'jeRrY', 'JeRrY', 'jERrY', 'JERrY', 'jerRY', 'JerRY', + 'jErRY', 'JErRY', 'jeRRY', 'JeRRY', 'jERRY', 'JERRY', 'hellokitty', 'Hellokitty', + 'hEllokitty', 'HEllokitty', 'heLlokitty', 'HeLlokitty', 'hELlokitty', 'HELlokitty', + 'helLokitty', 'HelLokitty', 'hElLokitty', 'HElLokitty', 'heLLokitty', 'HeLLokitty', + 'hELLokitty', 'HELLokitty', 'hellOkitty', 'HellOkitty', 'hEllOkitty', 'HEllOkitty', + 'heLlOkitty', 'HeLlOkitty', 'hELlOkitty', 'HELlOkitty', 'helLOkitty', 'HelLOkitty', + 'hElLOkitty', 'HElLOkitty', 'heLLOkitty', 'HeLLOkitty', 'hELLOkitty', 'HELLOkitty', + 'helloKitty', 'HelloKitty', 'hElloKitty', 'HElloKitty', 'heLloKitty', 'HeLloKitty', + 'hELloKitty', 'HELloKitty', 'helLoKitty', 'HelLoKitty', 'hElLoKitty', 'HElLoKitty', + 'heLLoKitty', 'HeLLoKitty', 'hELLoKitty', 'HELLoKitty', 'hellOKitty', 'HellOKitty', + 'hEllOKitty', 'HEllOKitty', 'heLlOKitty', 'HeLlOKitty', 'hELlOKitty', 'HELlOKitty', + 'helLOKitty', 'HelLOKitty', 'hElLOKitty', 'HElLOKitty']; + + it('dictionary name generator no option check value', function () { + const dictGenerator = getNameGenerator(NameGeneratorType.DICTIONARY); + let arr = []; + for (let i = 0; i < 100; i++) { + const nameGet = dictGenerator.getName(); + assert.isNotNull(nameGet); + arr.push(nameGet); + } + + arr.forEach(((value, index) => { + assert.strictEqual(value, noOptionTarget[index]); + })); + }); + + it('dictionary name generator with option check value', function () { + const options = { + dictionaryList: ['tom', 'jerry', 'helloKitty', 'jojo', 'betty'] + }; + + const dictGenerator = getNameGenerator(NameGeneratorType.DICTIONARY, options); + let arr = []; + for (let i = 0; i < 100; i++) { + const nameGet = dictGenerator.getName(); + assert.isNotNull(nameGet); + arr.push(nameGet); + } + + arr.forEach(((value, index) => { + assert.strictEqual(value, optionTarget[index]); + })); + }); + }); + + describe('reserved name generator test', function () { + const targetNames = [ + 'ιet', 'lèt', 'ιèt', 'rèturn', 'retυrn', 'rètυrn', 'returη', 'rèturη', + 'retυrη', 'rètυrη', 'þreak', 'brèak', 'þrèak', 'breαk', 'þreαk', 'brèαk', + 'þrèαk', 'breaκ', 'þreaκ', 'brèaκ', 'þrèaκ', 'breακ', 'þreακ', 'brèακ', + 'þrèακ', 'çontinue', 'cοntinue', 'çοntinue', 'coηtinue', 'çoηtinue', + 'cοηtinue', 'çοηtinue', 'contìnue', 'çontìnue', 'cοntìnue', 'çοntìnue', + 'coηtìnue', 'çoηtìnue', 'cοηtìnue', 'çοηtìnue', 'contiηue', 'çontiηue', + 'cοntiηue', 'çοntiηue', 'coηtiηue', 'çoηtiηue', 'cοηtiηue', 'çοηtiηue', + 'contìηue', 'çontìηue', 'cοntìηue', 'çοntìηue', 'coηtìηue', 'çoηtìηue', + 'cοηtìηue', 'çοηtìηue', 'continυe', 'çontinυe', 'cοntinυe', 'çοntinυe', + 'coηtinυe', 'çoηtinυe', 'cοηtinυe', 'çοηtinυe', 'contìnυe', 'çontìnυe', + 'cοntìnυe', 'çοntìnυe', 'coηtìnυe', 'çoηtìnυe', 'cοηtìnυe', 'çοηtìnυe', + 'contiηυe', 'çontiηυe', 'cοntiηυe', 'çοntiηυe', 'coηtiηυe', 'çoηtiηυe', + 'cοηtiηυe', 'çοηtiηυe', 'contìηυe', 'çontìηυe', 'cοntìηυe', 'çοntìηυe', + 'coηtìηυe', 'çoηtìηυe', 'cοηtìηυe', 'çοηtìηυe', 'continuè', 'çontinuè', + 'cοntinuè', 'çοntinuè', 'coηtinuè', 'çoηtinuè', 'cοηtinuè', 'çοηtinuè', + 'contìnuè', 'çontìnuè', 'cοntìnuè', 'çοntìnuè' + ]; + + it('reserved name generator check value', function () { + + const reservedGenerator = getNameGenerator(NameGeneratorType.RESERVED_NAME); + let arr = []; + for (let i = 0; i < 100; i++) { + const nameGet = reservedGenerator.getName(); + assert.isNotNull(nameGet); + arr.push(nameGet); + } + + arr.forEach(((value, index) => { + assert.strictEqual(value, targetNames[index]); + })); + }); + }); +}); diff --git a/arkguard/test/ut/bogus/OpaquePredicate.spec.ts b/arkguard/test/ut/bogus/OpaquePredicate.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..038ec77007564d668a34dc3bcee410626f196dd3 --- /dev/null +++ b/arkguard/test/ut/bogus/OpaquePredicate.spec.ts @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {describe, it} from 'mocha'; +import {assert} from 'chai'; + +describe('opaque predicate test', function () { + const maxValueFirst = 125; + it('test y < 10 || x * (x + 1) % 2 == 0;', function () { + for (let i = 0; i <= maxValueFirst; i++) { + for (let j = 0; j <= maxValueFirst; j++) { + assert.isTrue(j < 10 || i * (i + 1) % 2 === 0); + } + } + }); + + it('test 7* x* x − y* y != 1 || y < n;', function () { + for (let i = 0; i <= maxValueFirst; i++) { + for (let j = 0; j <= maxValueFirst; j++) { + assert.isTrue(7 * i * i - j * j !== 1); + } + } + }); + + const maxValueSecond = 10000; + it('test (4*x*x + 4) mod 19 != 0;', function () { + for (let i = 0; i <= maxValueSecond; i++) { + assert.isTrue((4 * i * i + 4) % 19 !== 0); + } + }); + + it('test (x*x + x +7) % 81 != 0;', function () { + for (let i = 0; i <= maxValueSecond; i++) { + assert.isTrue((i * i + i + 7) % 81 !== 0); + } + }); + + it('test (x*x*x - x) % 3 == 0;', function () { + for (let i = 0; i <= maxValueSecond; i++) { + assert.isTrue((i * i * i - i) % 3 === 0); + } + }); +}); diff --git a/arkguard/test/ut/utils/FileUtils.spec.ts b/arkguard/test/ut/utils/FileUtils.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..c6bb3ac9e1394e9cfa3bcc8035289d5c71f0f8b7 --- /dev/null +++ b/arkguard/test/ut/utils/FileUtils.spec.ts @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {describe, it} from 'mocha'; +import {FileUtils} from '../../../src/utils/FileUtils'; +import {assert} from 'chai'; + +describe('Tester Cases for .', function () { + /** test for readFile */ + it('Tester: case for FileUtils#readFile', function () { + let path = '/user/local/tester'; + assert.strictEqual(FileUtils.readFile(path), undefined); + }); + + it('Tester: case for FileUtils#readFile', function () { + let path = 'test/ut/utils/demo.txt'; + assert.strictEqual(FileUtils.readFile(path), 'hello world!'); + }); + + /** test for readFileAsJson */ + it('Tester: case for FileUtils#readFileAsJson', function () { + let path = 'test/ut/utils/demo.json'; + let obj = FileUtils.readFileAsJson(path); + assert.strictEqual(obj?.mCompact, true); + }); + + it('Tester: case for FileUtils#readFileAsJson', function () { + let path = 'test/utils/demo_not_found.json'; + let obj = FileUtils.readFileAsJson(path); + assert.strictEqual(obj, undefined); + }); + + it('Tester: case for FileUtils#readFileAsJson', function () { + let path = 'test/utils/error_json.txt'; + let obj = FileUtils.readFileAsJson(path); + assert.strictEqual(obj, undefined); + }); + + /** test for getFileName */ + it('Tester: case for FileUtils#getFileName', function () { + let path = null; + assert.strictEqual(FileUtils.getFileName(path), undefined); + + path = undefined; + assert.strictEqual(FileUtils.getFileName(path), undefined); + }); + + it('Tester: case for FileUtils#getFileName', function () { + let path = 'resources/configs/user_profile.json'; + assert.strictEqual(FileUtils.getFileName(path), 'user_profile.json'); + }); + + it('Tester: case for FileUtils#getFileName', function () { + let path = 'D:\\HuaweiApp\\ohsdk\\ets\\3.2.7.5\\user_profile.json'; + assert.strictEqual(FileUtils.getFileName(path), 'user_profile.json'); + }); + + it('Tester: case for FileUtils#getFileName', function () { + let path = 'user_profile.json'; + assert.strictEqual(FileUtils.getFileName(path), 'user_profile.json'); + }); + + /** test for getFileExtension */ + it('Tester: case for FileUtils#getFileExtension', function () { + let path = null; + assert.strictEqual(FileUtils.getFileExtension(path), undefined); + + path = undefined; + assert.strictEqual(FileUtils.getFileExtension(path), undefined); + }); + + it('Tester: case for FileUtils#getFileExtension', function () { + let path = 'resources/configs/user_profile'; + assert.strictEqual(FileUtils.getFileExtension(path), undefined); + }); + + it('Tester: case for FileUtils#getFileExtension', function () { + let path = 'resources/configs.dir/user_profile.conf'; + assert.strictEqual(FileUtils.getFileExtension(path), 'conf'); + }); + + it('Tester: case for FileUtils#getFileExtension', function () { + let path = 'resources/configs/user_profile.json'; + assert.strictEqual(FileUtils.getFileExtension(path), 'json'); + }); + + it('Tester: case for FileUtils#getFileExtension', function () { + let path = 'resources/configs/user_profile.'; + assert.strictEqual(FileUtils.getFileExtension(path), ''); + }); + + /** test for writeFile */ + it('Tester: case for FileUtils#writeFile', function () { + let path = 'test/ut/utils/write_demo.txt'; + let content = 'hello'; + FileUtils.writeFile(path, content); + + const fileContent = FileUtils.readFile(path); + assert.strictEqual(fileContent, content); + }); + + /** test for getPrefix */ + it('Tester: case for FileUtils#getPrefix', function () { + let path = 'test/utils/write_demo.txt'; + let prefix = 'test/utils/'; + + assert.strictEqual(FileUtils.getPrefix(path), prefix); + }); + + it('Tester: case for FileUtils#getPrefix', function () { + let path = 'D:\\HuaweiApp\\ohsdk\\ets\\3.2.7.5\\us'; + let prefix = 'D:\\HuaweiApp\\ohsdk\\ets\\3.2.7.5\\'; + + assert.strictEqual(FileUtils.getPrefix(path), prefix); + }); + + it('Tester: case for FileUtils#getPrefix', function () { + let path = 'D:'; + let prefix = undefined; + + assert.strictEqual(FileUtils.getPrefix(path), prefix); + }); + + /** test for getPathWithoutPrefix */ + it('Tester: case for FileUtils#getPathWithoutPrefix', function () { + let path = 'D:'; + let prefix = 'D:\\HuaweiApp'; + + assert.strictEqual(FileUtils.getPathWithoutPrefix(path, prefix), path); + }); + + it('Tester: case for FileUtils#getPathWithoutPrefix', function () { + let path = 'D:\\HuaweiApp\\ohsdk\\ets\\3.2.7.5'; + let prefix = 'D:\\HuaweiApp'; + + assert.strictEqual(FileUtils.getPathWithoutPrefix(path, prefix), '\\ohsdk\\ets\\3.2.7.5'); + }); + + it('Tester: case for FileUtils#getPathWithoutPrefix', function () { + let path = 'D:\\HuaweiApp\\ohsdk\\ets\\3.2.7.5'; + let prefix = 'D:\\HuaweiApp\\ohsdk\\ets\\3.2.7.5'; + + assert.strictEqual(FileUtils.getPathWithoutPrefix(path, prefix), ''); + }); +}); diff --git a/arkguard/test/ut/utils/ListUtil.spec.ts b/arkguard/test/ut/utils/ListUtil.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..f4c023f1f4dccce8b9efb7d117156381bff6ec6e --- /dev/null +++ b/arkguard/test/ut/utils/ListUtil.spec.ts @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {ListUtil} from '../../../src/utils/ListUtil'; +import {describe, it} from 'mocha'; +import {assert} from 'chai'; + +describe('unit test for ListUtil.ts', function () { + describe('get init list test', function () { + it('check init list input value bad', function () { + let arr = ListUtil.getInitList(-1); + assert.isTrue(arr.length === 0); + }); + + it('check init list input value zero', function () { + let arr = ListUtil.getInitList(0); + assert.isTrue(arr.length === 0); + }); + + it('check init list input value NaN', function () { + let arr = ListUtil.getInitList(NaN); + assert.isTrue(arr.length === 0); + }); + + it('check init list input value MAX_INIT_LEN', function () { + let arr = ListUtil.getInitList(ListUtil.MAX_INIT_LEN); + assert.isTrue(arr.length === ListUtil.MAX_INIT_LEN); + }); + + it('check init list input value bigger than MAX_INIT_LEN', function () { + let arr = ListUtil.getInitList(ListUtil.MAX_INIT_LEN + 1); + assert.isTrue(arr.length === 0); + }); + + it('check init list input normal value', function () { + let arr = ListUtil.getInitList(26); + + arr.forEach(((value, index) => { + assert.strictEqual(value, index); + })); + }); + }); + + describe('list shuffle test', function () { + it('check shuffle invalid list', function () { + let arr = undefined; + ListUtil.shuffle(arr); + + assert.isTrue(true); + }); + + it('check shuffle list', function () { + let arr = ListUtil.getInitList(26); + ListUtil.shuffle(arr); + + for (let i = 1; i < arr.length; i++) { + const isShuffled = arr[i] !== i || Math.abs(arr[i - 1] - arr[i]) > 1; + assert.isTrue(isShuffled); + } + }); + }); + + describe('list unique merge test', function () { + it('check unique merge two undefined list', function () { + let arr1 = undefined; + let arr2 = undefined; + + const arrUnique = ListUtil.uniqueMergeList(arr1, arr2); + assert.isTrue(arrUnique.length === 0); + }); + + it('check unique merge two unique list', function () { + let arr1 = ['1', '2', '3']; + let arr2 = ['4', '5', '6']; + + const expectedArr = ['1', '2', '3', '4', '5', '6']; + + const arrUnique = ListUtil.uniqueMergeList(arr1, arr2); + assert.isTrue(arrUnique.length === expectedArr.length); + arrUnique.forEach((value, index) => { + assert.strictEqual(value, expectedArr[index]); + }); + }); + + it('check unique merge two not unique list', function () { + let arr1 = ['1', '2', '3', '4']; + let arr2 = ['4', '5', '4', '6']; + + const expectedArr = ['1', '2', '3', '4', '5', '6']; + + const arrUnique = ListUtil.uniqueMergeList(arr1, arr2); + assert.isTrue(arrUnique.length === expectedArr.length); + arrUnique.forEach((value, index) => { + assert.strictEqual(value, expectedArr[index]); + }); + }); + + it('check unique merge three undefined list', function () { + let arr1 = undefined; + let arr2 = undefined; + let arr3 = undefined; + + const arrUnique = ListUtil.uniqueMergeList(arr1, arr2, arr3); + assert.isTrue(arrUnique.length === 0); + }); + + it('check unique merge three unique list', function () { + let arr1 = ['1', '2', '3']; + let arr2 = ['4', '5', '6']; + let arr3 = ['7', '8', '9']; + + const expectedArr = ['1', '2', '3', '4', '5', '6', '7', '8', '9']; + + const arrUnique = ListUtil.uniqueMergeList(arr1, arr2, arr3); + assert.isTrue(arrUnique.length === expectedArr.length); + arrUnique.forEach((value, index) => { + assert.strictEqual(value, expectedArr[index]); + }); + }); + + it('check unique merge three not unique list', function () { + let arr1 = ['1', '2', '3', '4']; + let arr2 = ['4', '5', '4', '6']; + let arr3 = ['6', '7', '8', '8']; + + const expectedArr = ['1', '2', '3', '4', '5', '6', '7', '8']; + + const arrUnique = ListUtil.uniqueMergeList(arr1, arr2, arr3); + assert.isTrue(arrUnique.length === expectedArr.length); + arrUnique.forEach((value, index) => { + assert.strictEqual(value, expectedArr[index]); + }); + }); + }); +}); diff --git a/arkguard/test/ut/utils/NodeUtils.spec.ts b/arkguard/test/ut/utils/NodeUtils.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..6806a7fe78902ee9d9a2220c235341c3814e192c --- /dev/null +++ b/arkguard/test/ut/utils/NodeUtils.spec.ts @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {before, describe} from 'mocha'; +import {assert} from 'chai'; +import {createSourceFile, ScriptTarget, SourceFile} from 'typescript'; +import {NodeUtils} from '../../../src/utils/NodeUtils'; + +describe('test for NodeUtils', function () { + let fileContent; + let sourceFile: SourceFile; + + before('init ast for source file', function () { + fileContent = ` + function sayHello2() { + let student = 'Dudu'; + var _c111 = '3|1|2|4|0'.split('|'), _ddd = [3,1,2,0,4], _0x67e02af2_ = 0; + for (;;) { + switch (_c111[_ddd[_0x67e02af2_++]]) { + case '0': + console.log('when ' + student); + continue; + case '1': + console.log('where ' + student); + continue; + case '2': + console.log('how ' + student); + continue; + case '3': + console.log('what ' + student); + continue; + case '4': + console.log('hello ' + student); + continue; + } + break; + } + } + + for (;;) {} + sayHello2(); + `; + + sourceFile = createSourceFile('demo.js', fileContent, ScriptTarget.ES2015, true); + }); + + describe('test for printNode', function () { + it('functional test', function () { + const printedContent = NodeUtils.printNode(sourceFile, sourceFile); + + const originRemoved = fileContent.replace(/\n/g, '').replace(/\r/g, '').replace(/ /g, ''); + const printedRemoved = printedContent.replace(/\n/g, '').replace(/\r/g, '').replace(/ /g, ''); + + assert.equal(originRemoved, printedRemoved); + }); + }); + + describe('test for method isLoopStatement', function () { + it('functional test', function () { + assert.isTrue(NodeUtils.isLoopStatement(sourceFile.statements[1])); + }); + }); +}); \ No newline at end of file diff --git a/arkguard/test/ut/utils/SourceMapUtil.spec.ts b/arkguard/test/ut/utils/SourceMapUtil.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..fa661ec0b17609cd31c7ccead56a9c2f8aa381ac --- /dev/null +++ b/arkguard/test/ut/utils/SourceMapUtil.spec.ts @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {assert} from 'chai'; +import {getSourceMapGenerator} from '../../../src/utils/SourceMapUtil'; + +describe('test for SourceMapUtil', function () { + it('should return undefined when path is invalid', function () { + const filePath = undefined; + + const generator = getSourceMapGenerator(filePath); + assert.strictEqual(generator, undefined); + }); + + it('should return an object if path valid', function () { + const filePath = 'demo.js'; + const generator = getSourceMapGenerator(filePath); + assert.isTrue(generator !== undefined); + }); +}); \ No newline at end of file diff --git a/arkguard/test/ut/utils/TransformUtil.spec.ts b/arkguard/test/ut/utils/TransformUtil.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..b6894521aee35df5234ac1b5fff703eca8907605 --- /dev/null +++ b/arkguard/test/ut/utils/TransformUtil.spec.ts @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {before} from 'mocha'; +import {assert} from 'chai'; +import {createSourceFile, ScriptTarget, SourceFile} from 'typescript'; + +import {collectExistNames, OhPackType} from '../../../src/utils/TransformUtil'; +import {findOhImportStatement} from '../../../src/utils/OhsUtil'; + +describe('test for TransformUtil', function () { + let sourceFile: SourceFile; + + before('init ast for source file', function () { + const fileContent = ` + class Demo{ + constructor(public title: string, public content: string, public mark: number) { + this.title = title + this.content = content + this.mark = mark + } + } + `; + + sourceFile = createSourceFile('demo.js', fileContent, ScriptTarget.ES2015, true); + }); + + describe('test for function collectExistNames', function () { + it('test collectExistNames', function () { + const nameSets = collectExistNames(sourceFile); + const targetNames = ['Demo', 'title', 'content', 'mark']; + + assert.strictEqual(nameSets.size, targetNames.length); + targetNames.forEach((value) => { + assert.isTrue(nameSets.has(value)); + }); + }); + }); + + describe('test for function findOhImportStatement', function () { + it('find oh import in esmodule', function () { + const fileContent = `var hilog = globalThis.requireNapi('hilog') || + (isSystemplugin('hilog', 'ohos') ? + globalThis.ohosplugin.hilog : isSystemplugin('hilog', 'system') ? + globalThis.systemplugin.hilog : undefined); + `; + + const source = createSourceFile('demo2.js', fileContent, ScriptTarget.ES2015, true); + const statement = source.statements[0]; + const ohPackType = findOhImportStatement(statement, '@ohos.hilog'); + + assert.strictEqual(ohPackType, OhPackType.ES_MODULE); + }); + + it('find oh import in jsbundle', function () { + const fileContent = `var _ohos = _interopRequireDefault(requireModule('@ohos.hilog'))`; + const source = createSourceFile('demo2.js', fileContent, ScriptTarget.ES2015, true); + const statement = source.statements[0]; + const ohPackType = findOhImportStatement(statement, '@ohos.hilog'); + + assert.strictEqual(ohPackType, OhPackType.JS_BUNDLE); + }); + }); +}); \ No newline at end of file diff --git a/arkguard/test/ut/utils/TypeUtils.spec.ts b/arkguard/test/ut/utils/TypeUtils.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..aabf679eb54eda4b4fc61c159d06f4383ad641f3 --- /dev/null +++ b/arkguard/test/ut/utils/TypeUtils.spec.ts @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {assert} from 'chai'; +import {before, describe} from 'mocha'; +import {createSourceFile, ScriptTarget, SourceFile} from 'typescript'; + +import {TypeUtils} from '../../../src/utils/TypeUtils'; + +describe('test for TypeUtils', function () { + let sourceFile: SourceFile; + + before('init sourceFile', function () { + const fileContent = ` + class Demo{ + constructor(public title: string, public content: string, public mark: number) { + this.title = title + this.content = content + this.mark = mark + } + } + `; + + sourceFile = createSourceFile('demo.ts', fileContent, ScriptTarget.ES2015, true); + }); + + describe('test for method createNewSourceFile', function () { + it('functional test', function () { + const newSource = TypeUtils.createNewSourceFile(sourceFile); + + assert.strictEqual(sourceFile.statements.length, newSource.statements.length); + assert.notStrictEqual(sourceFile.fileName, newSource.fileName); + assert.isTrue(newSource.fileName.endsWith('.ts')); + }); + }); + + describe('test for function createChecker', function () { + it('functional test', function () { + const checker = TypeUtils.createChecker(sourceFile); + assert.notEqual(checker, undefined); + }); + }); +}); \ No newline at end of file diff --git a/arkguard/test/ut/utils/demo.json b/arkguard/test/ut/utils/demo.json new file mode 100644 index 0000000000000000000000000000000000000000..934a8f246ae8d5af2033a16b98d26941fe0aca0c --- /dev/null +++ b/arkguard/test/ut/utils/demo.json @@ -0,0 +1,3 @@ +{ + "mCompact": true +} \ No newline at end of file diff --git a/arkguard/test/ut/utils/demo.txt b/arkguard/test/ut/utils/demo.txt new file mode 100644 index 0000000000000000000000000000000000000000..bc7774a7b18deb1d7bd0212d34246a9b1260ae17 --- /dev/null +++ b/arkguard/test/ut/utils/demo.txt @@ -0,0 +1 @@ +hello world! \ No newline at end of file diff --git a/arkguard/test/ut/utils/error_json.txt b/arkguard/test/ut/utils/error_json.txt new file mode 100644 index 0000000000000000000000000000000000000000..83a5977b2b6c374f5b7ac0b6190109c66d96b6a1 --- /dev/null +++ b/arkguard/test/ut/utils/error_json.txt @@ -0,0 +1,4 @@ +{ + "mCompact": true +} +1233 \ No newline at end of file diff --git a/arkguard/tsconfig.base.json b/arkguard/tsconfig.base.json new file mode 100644 index 0000000000000000000000000000000000000000..3139bf4dbcc5f0f1b9fabb7554666923e376e274 --- /dev/null +++ b/arkguard/tsconfig.base.json @@ -0,0 +1,26 @@ +{ + /* Visit https://aka.ms/tsconfig.json to read more about this file */ + "compilerOptions": { + /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "target": "ES2015", + /* Specify what module code is generated. */ + "module": "commonjs", + /* use strict mode to upscale security */ + "alwaysStrict": false, + /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + "declaration": false, + /* Create source map files for emitted JavaScript files. */ + "sourceMap": true, + // remove comments + "removeComments": false, + /* Set the newline character for emitting files. */ + "newLine": "crlf", + // 编译后的js代码遵循何种规范 + "moduleResolution": "node", + "esModuleInterop": true, + // 用于debug调试 + "typeRoots": [ + "./node_modules/@types" + ] + } +} diff --git a/arkguard/tsconfig.json b/arkguard/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..23f32ca5c72d39d2dae7ffc7533cbdd1fa0f060a --- /dev/null +++ b/arkguard/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "./tsconfig.base.json", + "semicolon": [true, "always", "ignore-interfaces"], + "compilerOptions": { + "outDir": "./lib", + "resolveJsonModule": true, + "declaration": true, + "allowJs": true, + "checkJs": true + }, + "include": [ + "src/**/*" + ], + "exclude": [ + "node_modules" + ] +}