Code coverage report for src/node-transformers/obfuscating-transformers/FunctionTransformer.ts

# All files / src/node-transformers/obfuscating-transformers FunctionTransformer.ts

100% Statements 36/36
100% Branches 17/17
100% Functions 5/5
100% Lines 33/33

    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
    1271x
    1x

    1x

    1x

    1x
    1x

    1x

    6262x

    6262x

    6262x

    665151x

    27309x

    27309x

    27309x
    27309x

    27309x

    27309x

    25932x
    1x

    25931x

    25933x
    3x

    3x

    25930x
    25929x

    27309x

    1130269x
    352258x

    352258x
    60640x
    60640x

    25932x

    27309x

     import { injectable, inject } from 'inversify';
    import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';

    import * as estraverse from 'estraverse';
    import * as ESTree from 'estree';

    import { TObfuscationReplacerFactory } from '../../types/container/TObfuscationReplacerFactory';

    import { IOptions } from '../../interfaces/options/IOptions';
    import { IObfuscationReplacerWithStorage } from '../../interfaces/node-transformers/IObfuscationReplacerWithStorage';
    import { IVisitor } from '../../interfaces/IVisitor';

    import { ObfuscationReplacers } from '../../enums/container/ObfuscationReplacers';

    import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
    import { Node } from '../../node/Node';

    /**
     * replaces:
     *     function foo (argument1) { return argument1; };
     *
     * on:
     *     function foo (_0x12d45f) { return _0x12d45f; };
     *
     */
    @injectable()
    export class FunctionTransformer extends AbstractNodeTransformer {
        /**
         * @type {IObfuscationReplacerWithStorage}
         */
        private readonly identifierReplacer: IObfuscationReplacerWithStorage;

        /**
         * @param obfuscationReplacerFactory
         * @param options
         */
        constructor (
            @inject(ServiceIdentifiers.Factory__IObfuscationReplacer) obfuscationReplacerFactory: TObfuscationReplacerFactory,
            @inject(ServiceIdentifiers.IOptions) options: IOptions
        ) {
            super(options);

            this.identifierReplacer = <IObfuscationReplacerWithStorage>obfuscationReplacerFactory(ObfuscationReplacers.IdentifierReplacer);
        }

        /**
         * @return {IVisitor}
         */
        public getVisitor (): IVisitor {
            return {
                enter: (node: ESTree.Node, parentNode: ESTree.Node) => {
                    if (
                        Node.isFunctionDeclarationNode(node) ||
                        Node.isFunctionExpressionNode(node) ||
                        Node.isArrowFunctionExpressionNode(node)
                    ) {
                        return this.transformNode(node, parentNode);
                    }
                }
            };
        }

        /**
         * @param functionNode
         * @param parentNode
         * @returns {ESTree.Node}
         */
        public transformNode (functionNode: ESTree.Function, parentNode: ESTree.Node): ESTree.Node {
            const nodeIdentifier: number = this.nodeIdentifier++;

            this.storeFunctionParams(functionNode, nodeIdentifier);
            this.replaceFunctionParams(functionNode, nodeIdentifier);

            return functionNode;
        }

        /**
         * @param functionNode
         * @param nodeIdentifier
         */
        private storeFunctionParams (functionNode: ESTree.Function, nodeIdentifier: number): void {
            functionNode.params
                .forEach((paramsNode: ESTree.Node) => {
                    if (Node.isObjectPatternNode(paramsNode)) {
                        return estraverse.VisitorOption.Skip;
                    }

                    estraverse.traverse(paramsNode, {
                        enter: (node: ESTree.Node): any => {
                            if (Node.isAssignmentPatternNode(node) && Node.isIdentifierNode(node.left)) {
                                this.identifierReplacer.storeNames(node.left.name, nodeIdentifier);

                                return estraverse.VisitorOption.Skip;
                            }

                            if (Node.isIdentifierNode(node)) {
                                this.identifierReplacer.storeNames(node.name, nodeIdentifier);
                            }
                        }
                    });
                });
        }

        /**
         * @param functionNode
         * @param nodeIdentifier
         */
        private replaceFunctionParams (functionNode: ESTree.Function, nodeIdentifier: number): void {
            const traverseVisitor: estraverse.Visitor = {
                enter: (node: ESTree.Node, parentNode: ESTree.Node): any => {
                    if (Node.isReplaceableIdentifierNode(node, parentNode)) {
                        const newNodeName: string = this.identifierReplacer.replace(node.name, nodeIdentifier);

                        if (node.name !== newNodeName) {
                            node.name = newNodeName;
                            node.obfuscatedNode = true;
                        }
                    }
                }
            };

            functionNode.params.forEach((paramsNode: ESTree.Node) => estraverse.replace(paramsNode, traverseVisitor));

            estraverse.replace(functionNode.body, traverseVisitor);
        }
    }