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   664830x         27374x                       27374x   27374x 27374x   27374x               27374x   26059x 1x     26058x   26060x 3x   3x     26057x 26056x                       27374x   1131033x 352990x   352990x 60911x 60911x           26059x   27374x      
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);
    }
}