Skip to content

Commit

Permalink
Merge pull request #599 from javascript-obfuscator/bigint-support
Browse files Browse the repository at this point in the history
Bigint support
  • Loading branch information
sanex3339 committed Apr 25, 2020
2 parents 3cebb78 + 0a57798 commit 31f3ab9
Show file tree
Hide file tree
Showing 19 changed files with 164 additions and 52 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
@@ -1,7 +1,8 @@
Change Log

v0.27.5
v0.28.0
---
* Added BigInt support. https://github.com/javascript-obfuscator/javascript-obfuscator/issues/588
* Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/554

v0.27.4
Expand Down
8 changes: 4 additions & 4 deletions dist/index.browser.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/index.cli.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/index.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
@@ -1,6 +1,6 @@
{
"name": "javascript-obfuscator",
"version": "0.27.4",
"version": "0.28.0",
"description": "JavaScript obfuscator",
"keywords": [
"obfuscator",
Expand Down
Expand Up @@ -11,6 +11,6 @@ export function StringArrayRotateFunctionTemplate (): string {
};
{code}
})({stringArrayName}, 0x{stringArrayRotationAmount});
})({stringArrayName}, {stringArrayRotationAmount});
`;
}
Expand Up @@ -37,12 +37,11 @@ export class HexadecimalIdentifierNamesGenerator extends AbstractIdentifierNames
const rangeMaxInteger: number = 99_999_999;
const randomInteger: number = this.randomGenerator.getRandomInteger(rangeMinInteger, rangeMaxInteger);
const hexadecimalNumber: string = NumberUtils.toHex(randomInteger);
const prefixLength: number = Utils.hexadecimalPrefix.length + 1;
const baseNameLength: number = nameLength
? nameLength - prefixLength
: HexadecimalIdentifierNamesGenerator.baseIdentifierNameLength;
const prefixLength: number = Utils.hexadecimalPrefix.length;
const baseNameLength: number = (nameLength ?? HexadecimalIdentifierNamesGenerator.baseIdentifierNameLength)
+ prefixLength;
const baseIdentifierName: string = hexadecimalNumber.substr(0, baseNameLength);
const identifierName: string = `_${Utils.hexadecimalPrefix}${baseIdentifierName}`;
const identifierName: string = `_${baseIdentifierName}`;

if (!this.isValidIdentifierName(identifierName)) {
return this.generateNext(nameLength);
Expand Down
Expand Up @@ -118,6 +118,7 @@ export class LiteralTransformer extends AbstractNodeTransformer {
break;

case 'number':
case 'bigint':
newLiteralNode = this.literalObfuscatingReplacerFactory(
LiteralObfuscatingReplacer.NumberLiteralObfuscatingReplacer
).replace(literalNode);
Expand Down
Expand Up @@ -8,7 +8,6 @@ import { IOptions } from '../../../../interfaces/options/IOptions';
import { AbstractObfuscatingReplacer } from '../AbstractObfuscatingReplacer';
import { NodeFactory } from '../../../../node/NodeFactory';
import { NumberUtils } from '../../../../utils/NumberUtils';
import { Utils } from '../../../../utils/Utils';

@injectable()
export class NumberLiteralObfuscatingReplacer extends AbstractObfuscatingReplacer {
Expand All @@ -33,19 +32,19 @@ export class NumberLiteralObfuscatingReplacer extends AbstractObfuscatingReplace
public replace (literalNode: ESTree.SimpleLiteral): ESTree.Node {
const literalValue: ESTree.SimpleLiteral['value'] = literalNode.value;

if (typeof literalValue !== 'number') {
throw new Error('`NumberLiteralObfuscatingReplacer` should accept only literals with `number` value');
if (typeof literalValue !== 'number' && typeof literalValue !== 'bigint') {
throw new Error('`NumberLiteralObfuscatingReplacer` should accept only literals with `number` and `bigint` value');
}

let rawValue: string;

if (this.numberLiteralCache.has(literalValue)) {
rawValue = <string>this.numberLiteralCache.get(literalValue);
} else {
if (!NumberUtils.isCeil(literalValue)) {
rawValue = String(literalValue);
if (NumberUtils.isCeil(literalValue)) {
rawValue = NumberUtils.toHex(literalValue);
} else {
rawValue = `${Utils.hexadecimalPrefix}${NumberUtils.toHex(literalValue)}`;
rawValue = String(literalValue);
}

this.numberLiteralCache.set(literalValue, rawValue);
Expand Down
Expand Up @@ -15,7 +15,6 @@ import { AbstractObfuscatingReplacer } from '../AbstractObfuscatingReplacer';
import { NodeMetadata } from '../../../../node/NodeMetadata';
import { NodeFactory } from '../../../../node/NodeFactory';
import { NumberUtils } from '../../../../utils/NumberUtils';
import { Utils } from '../../../../utils/Utils';

@injectable()
export class StringLiteralObfuscatingReplacer extends AbstractObfuscatingReplacer implements IInitializable {
Expand Down Expand Up @@ -129,7 +128,7 @@ export class StringLiteralObfuscatingReplacer extends AbstractObfuscatingReplace
private replaceWithStringArrayCallNode (stringArrayStorageItemData: IStringArrayStorageItemData): ESTree.Node {
const { index, decodeKey } = stringArrayStorageItemData;

const hexadecimalIndex: string = `${Utils.hexadecimalPrefix}${NumberUtils.toHex(index)}`;
const hexadecimalIndex: string = NumberUtils.toHex(index);
const callExpressionArgs: (ESTree.Expression | ESTree.SpreadElement)[] = [
StringLiteralObfuscatingReplacer.getHexadecimalLiteralNode(hexadecimalIndex)
];
Expand Down
2 changes: 1 addition & 1 deletion src/storages/string-array/StringArrayStorage.ts
Expand Up @@ -42,7 +42,7 @@ export class StringArrayStorage extends MapStorage <string, IStringArrayStorageI
/**
* @type {number}
*/
private static readonly stringArrayNameLength: number = 7;
private static readonly stringArrayNameLength: number = 4;

/**
* @type {IArrayUtils}
Expand Down
18 changes: 13 additions & 5 deletions src/utils/NumberUtils.ts
@@ -1,19 +1,27 @@
import { Utils } from './Utils';

export class NumberUtils {
/**
* @param {number} dec
* @param {number} number
* @returns {string}
*/
public static toHex (dec: number): string {
public static toHex (number: number | bigint): string {
const radix: number = 16;

return dec.toString(radix);
const basePart: string = typeof number === 'number'
? number.toString(radix)
: `${number.toString(radix)}n`;

return `${Utils.hexadecimalPrefix}${basePart}`;
}

/**
* @param {number} number
* @returns {boolean}
*/
public static isCeil (number: number): boolean {
return number % 1 === 0;
public static isCeil (number: number | bigint): boolean {
return typeof number === 'number'
? number % 1 === 0
: true;
}
}
8 changes: 4 additions & 4 deletions test/dev/dev.ts
Expand Up @@ -7,13 +7,13 @@ import { NO_ADDITIONAL_NODES_PRESET } from '../../src/options/presets/NoCustomNo

let obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
`
var a, b;
({a, ...b} = {a: 1, b: 2, c: 3});
var foo = 'abc';
`,
{
...NO_ADDITIONAL_NODES_PRESET,
compact: false,
renameGlobals: true
renameGlobals: true,
stringArray: true,
stringArrayThreshold: 1
}
).getObfuscatedCode();

Expand Down
Expand Up @@ -613,6 +613,27 @@ describe('JavaScriptObfuscator', () => {
});
});

describe('BigInt support', () => {
const regExp: RegExp = /return 0x20000000000001n *\+ *0xan *\+ *0xan;/;

let obfuscatedCode: string;

beforeEach(() => {
const code: string = readFileAsString(__dirname + '/fixtures/bigint-support.js');

obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET
}
).getObfuscatedCode();
});

it('should support BigInt', () => {
assert.match(obfuscatedCode, regExp);
});
});

describe('mangled identifier names generator', () => {
const regExp: RegExp = /var c *= *0x1/;

Expand Down
@@ -0,0 +1,3 @@
function test() {
return 9007199254740993n + 10n + 0xan;
}
Expand Up @@ -624,6 +624,29 @@ describe('LiteralTransformer', () => {
});
});

describe('transformation of literal node with bigint value', () => {
const regExp: RegExp = /^var test *= *0xan;$/;

let obfuscatedCode: string;

before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/bigint-value.js');

obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET,
stringArray: true,
stringArrayThreshold: 1
}
).getObfuscatedCode();
});

it('should transform literal node', () => {
assert.match(obfuscatedCode, regExp);
});
});

describe('RegExp literal', () => {
const regExp: RegExp = /^var regExp *= *\/\(\\d\+\)\/;$/;

Expand Down
@@ -0,0 +1 @@
var test = 10n;
Expand Up @@ -13,26 +13,51 @@ import { InversifyContainerFacade } from '../../../../src/container/InversifyCon

describe('HexadecimalIdentifierNamesGenerator', () => {
describe('generateNext', () => {
let identifierNamesGenerator: IIdentifierNamesGenerator,
hexadecimalIdentifierName: string,
regExp: RegExp;
describe('Base', () => {
let identifierNamesGenerator: IIdentifierNamesGenerator,
hexadecimalIdentifierName: string,
regExp: RegExp;

before(() => {
const inversifyContainerFacade: IInversifyContainerFacade = new InversifyContainerFacade();

inversifyContainerFacade.load('', '', {});
identifierNamesGenerator = inversifyContainerFacade.getNamed<IIdentifierNamesGenerator>(
ServiceIdentifiers.IIdentifierNamesGenerator,
IdentifierNamesGenerator.HexadecimalIdentifierNamesGenerator
);

hexadecimalIdentifierName = identifierNamesGenerator.generateNext();
regExp = /^_0x(\w){4,6}$/;
});

before(() => {
const inversifyContainerFacade: IInversifyContainerFacade = new InversifyContainerFacade();
it('should return hexadecimal name', () => {
assert.match(hexadecimalIdentifierName, regExp);
})
});

inversifyContainerFacade.load('', '', {});
identifierNamesGenerator = inversifyContainerFacade.getNamed<IIdentifierNamesGenerator>(
ServiceIdentifiers.IIdentifierNamesGenerator,
IdentifierNamesGenerator.HexadecimalIdentifierNamesGenerator
);
describe('Custom length', () => {
let identifierNamesGenerator: IIdentifierNamesGenerator,
hexadecimalIdentifierName: string,
regExp: RegExp;

hexadecimalIdentifierName = identifierNamesGenerator.generateNext();
regExp = /^_0x(\w){4,6}$/;
});
before(() => {
const inversifyContainerFacade: IInversifyContainerFacade = new InversifyContainerFacade();

it('should return hexadecimal name', () => {
assert.match(hexadecimalIdentifierName, regExp);
})
inversifyContainerFacade.load('', '', {});
identifierNamesGenerator = inversifyContainerFacade.getNamed<IIdentifierNamesGenerator>(
ServiceIdentifiers.IIdentifierNamesGenerator,
IdentifierNamesGenerator.HexadecimalIdentifierNamesGenerator
);

hexadecimalIdentifierName = identifierNamesGenerator.generateNext(3);
regExp = /^_0x(\w){3}$/;
});

it('should return hexadecimal name', () => {
assert.match(hexadecimalIdentifierName, regExp);
})
});
});

describe('generateForGlobalScope', () => {
Expand Down
40 changes: 36 additions & 4 deletions test/unit-tests/utils/NumberUtils.spec.ts
Expand Up @@ -6,7 +6,7 @@ describe('NumberUtils', () => {
describe('toHex', () => {
describe('Variant #1: number `0`', () => {
const number: number = 0;
const expectedHexString = '0';
const expectedHexString = '0x0';

let hexString: string;

Expand All @@ -21,7 +21,7 @@ describe('NumberUtils', () => {

describe('Variant #2: number `10`', () => {
const number: number = 10;
const expectedHexString = 'a';
const expectedHexString = '0xa';

let hexString: string;

Expand All @@ -36,7 +36,7 @@ describe('NumberUtils', () => {

describe('Variant #3: number `17`', () => {
const number: number = 17;
const expectedHexString = '11';
const expectedHexString = '0x11';

let hexString: string;

Expand All @@ -51,7 +51,7 @@ describe('NumberUtils', () => {

describe('Variant #4: number `536870912`', () => {
const number: number = 536870912;
const expectedHexString = '20000000';
const expectedHexString = '0x20000000';

let hexString: string;

Expand All @@ -63,6 +63,22 @@ describe('NumberUtils', () => {
assert.equal(hexString, expectedHexString);
});
});

describe('Variant #5: bigint number `10n`', () => {
// @ts-ignore
const number: bigint = 10n;
const expectedHexString = '0xan';

let hexString: string;

before(() => {
hexString = NumberUtils.toHex(number);
});

it('should create a string with hexadecimal value from a given bigint number', () => {
assert.equal(hexString, expectedHexString);
});
});
});

describe('isCeil', () => {
Expand Down Expand Up @@ -95,5 +111,21 @@ describe('NumberUtils', () => {
assert.equal(result, expectedResult);
});
});

describe('bigint number', () => {
// @ts-ignore
const number: bigint = 10n;
const expectedResult: boolean = true;

let result: boolean;

before(() => {
result = NumberUtils.isCeil(number);
});

it('should return true', () => {
assert.equal(result, expectedResult);
});
});
});
});

0 comments on commit 31f3ab9

Please sign in to comment.