Code coverage report for src/node-transformers/node-obfuscators/replacers/StringLiteralReplacer.ts

# All files / src/node-transformers/node-obfuscators/replacers StringLiteralReplacer.ts

100% Statements 38/38
100% Branches 14/14
100% Functions 2/2
100% Lines 37/37

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

    1x

    1x
    1x
    1x

    1x
    1x

    1x

    1x
    50x

    4666x

    75448x

    75448x
    32626x

    42822x

    32626x

    32626x

    1x

    1x

    1x
    1x

    1x

    32626x
    32625x

    32626x
    32626x

    32626x

    32626x
    26643x

    5983x
    5983x

    32626x
    32626x

    32626x
    1x

    32625x

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

    import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
    import { ICustomNodeWithData } from '../../../interfaces/custom-nodes/ICustomNodeWithData';
    import { ICustomNodeWithIdentifier } from '../../../interfaces/custom-nodes/ICustomNodeWithIdentifier';
    import { IOptions } from '../../../interfaces/options/IOptions';
    import { IStorage } from '../../../interfaces/storages/IStorage';

    import { StringArrayEncoding } from '../../../enums/StringArrayEncoding';

    import { AbstractReplacer } from './AbstractReplacer';
    import { NumberLiteralReplacer } from './NumberLiteralReplacer';
    import { Utils } from '../../../Utils';

    @injectable()
    export class StringLiteralReplacer extends AbstractReplacer {
        /**
         * @type {number}
         */
        private static readonly minimumLengthForStringArray: number = 3;

        /**
         * @type {string[]}
         */
        private static readonly rc4Keys: string[] = Utils.getRandomGenerator()
            .n(() => Utils.getRandomGenerator().string({length: 4}), 50);

        /**
         * @param customNodesStorage
         * @param options
         */
        constructor (
            @inject(ServiceIdentifiers['IStorage<ICustomNode>']) customNodesStorage: IStorage<ICustomNode>,
            @inject(ServiceIdentifiers.IOptions) options: IOptions
        ) {
            super(customNodesStorage, options);
        }

        /**
         * @param nodeValue
         * @returns {string}
         */
        public replace (nodeValue: string): string {
            const replaceWithStringArrayFlag: boolean = (
                nodeValue.length >= StringLiteralReplacer.minimumLengthForStringArray
                && Utils.getRandomFloat(0, 1) <= this.options.stringArrayThreshold
            );

            if (this.options.stringArray && replaceWithStringArrayFlag) {
                return this.replaceStringLiteralWithStringArrayCall(nodeValue);
            }

            return `'${Utils.stringToUnicodeEscapeSequence(nodeValue)}'`;
        }

        /**
         * @param value
         * @returns {string}
         */
        private replaceStringLiteralWithStringArrayCall (value: string): string {
            const stringArrayNode: ICustomNodeWithData = <ICustomNodeWithData>this.customNodesStorage.get('stringArrayNode');

            let rc4Key: string = '';

            switch (this.options.stringArrayEncoding) {
                case StringArrayEncoding.base64:
                    value = Utils.btoa(value);

                    break;

                case StringArrayEncoding.rc4:
                    rc4Key = Utils.getRandomGenerator().pickone(StringLiteralReplacer.rc4Keys);
                    value = Utils.btoa(Utils.rc4(value, rc4Key));

                    break;
            }

            if (this.options.unicodeEscapeSequence) {
                value = Utils.stringToUnicodeEscapeSequence(value);
            }

            const stringArray: IStorage <string> = stringArrayNode.getNodeData();
            const indexOfExistingValue: number = <number>stringArray.getKeyOf(value);

            let indexOfValue: number;

            if (indexOfExistingValue >= 0) {
                indexOfValue = indexOfExistingValue;
            } else {
                indexOfValue = stringArray.getLength();
                stringArray.set(null, value);
            }

            const stringArrayCallsWrapper: ICustomNodeWithIdentifier = <ICustomNodeWithIdentifier>this.customNodesStorage.get('stringArrayCallsWrapper');
            const hexadecimalIndex: string = new NumberLiteralReplacer(this.customNodesStorage, this.options).replace(indexOfValue);

            if (this.options.stringArrayEncoding === StringArrayEncoding.rc4) {
                return `${stringArrayCallsWrapper.getNodeIdentifier()}('${hexadecimalIndex}', '${Utils.stringToUnicodeEscapeSequence(rc4Key)}')`;
            }

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