All files / src/node-transformers/node-obfuscators MemberExpressionObfuscator.ts

100% Statements 28/28
100% Branches 10/10
100% Functions 2/2
100% Lines 27/27
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 1121x 1x   1x 1x               1x 1x   1x 1x   1x 1x                               2586x   2586x             31646x   31654x 5097x   5097x     26557x 26553x 1573x     24980x 24980x                                     24980x 24980x                   24980x   24980x                         5097x 4077x              
import { injectable, inject } from 'inversify';
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
 
import * as escodegen from 'escodegen';
import * as estraverse from 'estraverse';
import * as ESTree from 'estree';
 
import { ICustomNode } from '../../interfaces/custom-nodes/ICustomNode';
import { IOptions } from '../../interfaces/options/IOptions';
import { IReplacer } from '../../interfaces/node-transformers/IReplacer';
import { IStorage } from '../../interfaces/storages/IStorage';
 
import { NodeObfuscatorsReplacers } from '../../enums/container/NodeObfuscatorsReplacers';
import { NodeType } from '../../enums/NodeType';
 
import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
import { Node } from '../../node/Node';
 
@injectable()
export class MemberExpressionObfuscator extends AbstractNodeTransformer {
    /**
     * @type {IReplacer}
     */
    private readonly stringLiteralReplacer: IReplacer;
 
    /**
     * @param customNodesStorage
     * @param replacersFactory
     * @param options
     */
    constructor(
        @inject(ServiceIdentifiers['IStorage<ICustomNode>']) customNodesStorage: IStorage<ICustomNode>,
        @inject(ServiceIdentifiers['Factory<IReplacer>']) replacersFactory: (replacer: NodeObfuscatorsReplacers) => IReplacer,
        @inject(ServiceIdentifiers.IOptions) options: IOptions
    ) {
        super(customNodesStorage, options);
 
        this.stringLiteralReplacer = replacersFactory(NodeObfuscatorsReplacers.StringLiteralReplacer);
    }
 
    /**
     * @param memberExpressionNode
     */
    public transformNode (memberExpressionNode: ESTree.MemberExpression): void {
        estraverse.traverse(memberExpressionNode.property, {
            enter: (node: ESTree.Node, parentNode: ESTree.Node): any => {
                if (Node.isLiteralNode(node)) {
                    this.obfuscateLiteralProperty(node);
 
                    return;
                }
 
                if (Node.isIdentifierNode(node)) {
                    if (memberExpressionNode.computed) {
                        return;
                    }
 
                    memberExpressionNode.computed = true;
                    this.obfuscateIdentifierProperty(node);
                }
            }
        });
    }
 
    /**
     * replaces:
     *     object.identifier = 1;
     *
     * on:
     *     object[_0x23d45[25]] = 1;
     *
     * and skip:
     *     object[identifier] = 1;
     *
     * @param node
     */
    private obfuscateIdentifierProperty (node: ESTree.Identifier): void {
        const nodeValue: string = node.name;
        const literalNode: ESTree.Literal = {
            raw: `'${nodeValue}'`,
            'x-verbatim-property': {
                content: this.stringLiteralReplacer.replace(nodeValue),
                precedence: escodegen.Precedence.Primary
            },
            type: NodeType.Literal,
            value: nodeValue
        };
 
        delete node.name;
 
        Object.assign(node, literalNode);
    }
 
    /**
     * replaces:
     *     object['literal'] = 1;
     *
     * on:
     *     object[_0x23d45[25]] = 1;
     *
     * @param node
     */
    private obfuscateLiteralProperty (node: ESTree.Literal): void {
        if (typeof node.value === 'string' && !node['x-verbatim-property']) {
            node['x-verbatim-property'] = {
                content : this.stringLiteralReplacer.replace(node.value),
                precedence: escodegen.Precedence.Primary
            };
        }
    }
}