Code coverage report for src/node-obfuscators/NodeObfuscator.ts

# All files / src/node-obfuscators NodeObfuscator.ts

93.48% Statements 43/46
91.89% Branches 34/37
50% Functions 1/2
93.48% Lines 43/46

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176

    1x

    1x
    1x

    1x

    652x
    652x

    106x

    106x
    106x

    6616x

    304x

    304x

    304x
    3x

    301x

    31x

    150x

    150x
    3x

    147x

    152x

    152x
    1x

    152x

    152x
    41x

    111x

    41x

    41x

    41x
    41x
    41x
    41x

    41x
    20x

    21x
    21x

    41x

    41x
    36x

    36x

    36x

    5x

     import { ICustomNode } from '../interfaces/custom-nodes/ICustomNode';
    import { INodeObfuscator } from '../interfaces/INodeObfuscator';
    import { INode } from "../interfaces/nodes/INode";
    import { IOptions } from "../interfaces/IOptions";

    import { TUnicodeArrayCallsWrapper } from "../types/custom-nodes/TUnicodeArrayCallsWrapper";
    import { TUnicodeArrayNode } from "../types/custom-nodes/TUnicodeArrayNode";

    import { JSFuck } from "../enums/JSFuck";

    import { Nodes } from "../Nodes";
    import { Utils } from '../Utils';

    export abstract class NodeObfuscator implements INodeObfuscator {
        /**
         * @type Map <string, Node>
         */
        protected nodes: Map <string, ICustomNode>;

        /**
         * @type {IOptions}
         */
        protected options: IOptions;

        /**
         * @param nodes
         * @param options
         */
        constructor(nodes: Map <string, ICustomNode>, options: IOptions) {
            this.nodes = nodes;
            this.options = options;
        }

        /**
         * @param node
         * @param parentNode
         */
        public abstract obfuscateNode (node: INode, parentNode?: INode): void;

        /**
         * @param name
         * @returns {boolean}
         */
        protected isReservedName (name: string): boolean {
            return this.options.reservedNames
                .some((reservedName: string) => {
                    return new RegExp(reservedName, 'g').test(name);
                });
        }

        /**
         * Store all identifiers names as keys in given `namesMap` with random names as value.
         * Reserved names will be ignored.
         *
         * @param node
         * @param namesMap
         */
        protected storeIdentifiersNames (
            node: INode,
            namesMap: Map <string, string>
        ): void {
            Eif (Nodes.isIdentifierNode(node) && !this.isReservedName(node.name)) {
                namesMap.set(node.name, Utils.getRandomVariableName());
            }
        }

        /**
         * @param node
         * @param parentNode
         * @param namesMap
         */
        protected replaceIdentifiersWithRandomNames (
            node: INode,
            parentNode: INode,
            namesMap: Map <string, string>
        ): void {
            if (Nodes.isIdentifierNode(node) && namesMap.has(node.name)) {
                const parentNodeIsPropertyNode: boolean = (
                        Nodes.isPropertyNode(parentNode) &&
                        parentNode.key === node
                    ),
                    parentNodeIsMemberExpressionNode: boolean = (
                        Nodes.isMemberExpressionNode(parentNode) &&
                        parentNode.computed === false &&
                        parentNode.property === node
                    );

                if (parentNodeIsPropertyNode || parentNodeIsMemberExpressionNode) {
                    return;
                }

                node.name = <string>namesMap.get(node.name);
            }
        }

        /**
         * @param nodeValue
         * @returns {string}
         */
        protected replaceLiteralBooleanWithJSFuck (nodeValue: boolean): string {
            return nodeValue ? JSFuck.True : JSFuck.False;
        }

        /**
         * @param nodeValue
         * @returns {string}
         */
        protected replaceLiteralNumberWithHexadecimalValue (nodeValue: number): string {
            const prefix: string = '0x';

            if (!Utils.isInteger(nodeValue)) {
                return String(nodeValue);
            }

            return `${prefix}${Utils.decToHex(nodeValue)}`;
        }

        /**
         * @param nodeValue
         * @returns {string}
         */
        protected replaceLiteralValueWithUnicodeValue (nodeValue: string): string {
            let replaceWithUnicodeArrayFlag: boolean = Math.random() <= this.options.unicodeArrayThreshold;

            if (this.options.encodeUnicodeArray && replaceWithUnicodeArrayFlag) {
                nodeValue = Utils.btoa(nodeValue);
            }

            nodeValue = Utils.stringToUnicode(nodeValue);

            if (this.options.unicodeArray && replaceWithUnicodeArrayFlag) {
                return this.replaceLiteralValueWithUnicodeArrayCall(nodeValue);
            }

            return nodeValue;
        }

        /**
         * @param value
         * @returns {string}
         */
        protected replaceLiteralValueWithUnicodeArrayCall (value: string): string {
            let unicodeArrayNode: TUnicodeArrayNode = <TUnicodeArrayNode>this.nodes.get('unicodeArrayNode');

            Iif (!unicodeArrayNode) {
                throw new ReferenceError('`unicodeArrayNode` node is not found in Map with custom nodes.');
            }

            let unicodeArray: string[] = unicodeArrayNode.getNodeData(),
                valueIndex: number = unicodeArray.indexOf(value),
                literalValueCallIndex: number,
                hexadecimalIndex: string;

            if (valueIndex >= 0) {
                literalValueCallIndex = valueIndex;
            } else {
                literalValueCallIndex = unicodeArray.length;
                unicodeArrayNode.updateNodeData(value);
            }

            hexadecimalIndex = this.replaceLiteralNumberWithHexadecimalValue(literalValueCallIndex);

            if (this.options.wrapUnicodeArrayCalls) {
                let unicodeArrayCallsWrapper: TUnicodeArrayCallsWrapper = <TUnicodeArrayCallsWrapper>this.nodes.get('unicodeArrayCallsWrapper');

                Iif (!unicodeArrayCallsWrapper) {
                    throw new ReferenceError('`unicodeArrayCallsWrapper` node is not found in Map with custom nodes.');
                }

                return `${unicodeArrayCallsWrapper.getNodeIdentifier()}('${hexadecimalIndex}')`;
            }

            return `${unicodeArrayNode.getNodeIdentifier()}[${hexadecimalIndex}]`;
        }
    }