mirror of
https://github.com/javascript-obfuscator/javascript-obfuscator
synced 2026-08-09 12:42:29 +00:00
Fixed reservedNames not preserving class method and property names when stringArray or deadCodeInjection is enabled (#1389)
This commit is contained in:
@@ -3,6 +3,7 @@ Change Log
|
||||
v5.4.0
|
||||
---
|
||||
* Add support for `import attributes`. Fixes https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1256
|
||||
* Fixed `reservedNames` not preserving class method and property names when `stringArray` or `deadCodeInjection` is enabled. Fixes https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1279
|
||||
* Replaced `mkdirp` dependency with native `fs.mkdirSync({ recursive: true })`. Fixes https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1275. Thank you https://github.com/roli-lpci!
|
||||
|
||||
v5.3.1
|
||||
|
||||
@@ -12,6 +12,7 @@ import { NodeTransformationStage } from '../../enums/node-transformers/NodeTrans
|
||||
import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
|
||||
import { NodeFactory } from '../../node/NodeFactory';
|
||||
import { NodeGuards } from '../../node/NodeGuards';
|
||||
import { IdentifierReplacer } from '../rename-identifiers-transformers/replacer/IdentifierReplacer';
|
||||
|
||||
/**
|
||||
* replaces:
|
||||
@@ -89,6 +90,18 @@ export class ClassFieldTransformer extends AbstractNodeTransformer {
|
||||
return classFieldNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @returns {boolean}
|
||||
*/
|
||||
private isIgnoredName(name: string): boolean {
|
||||
if (name === ClassFieldTransformer.ignoredName) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return IdentifierReplacer.isReservedName(name, this.options.reservedNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {MethodDefinition | PropertyDefinition} classFieldNode
|
||||
* @param {Identifier} keyNode
|
||||
@@ -98,7 +111,7 @@ export class ClassFieldTransformer extends AbstractNodeTransformer {
|
||||
classFieldNode: ESTree.MethodDefinition | ESTree.PropertyDefinition,
|
||||
keyNode: ESTree.Identifier
|
||||
): ESTree.MethodDefinition | ESTree.PropertyDefinition {
|
||||
if (keyNode.name !== ClassFieldTransformer.ignoredName && !classFieldNode.computed) {
|
||||
if (!this.isIgnoredName(keyNode.name) && !classFieldNode.computed) {
|
||||
classFieldNode.computed = true;
|
||||
classFieldNode.key = NodeFactory.literalNode(keyNode.name);
|
||||
}
|
||||
@@ -115,11 +128,7 @@ export class ClassFieldTransformer extends AbstractNodeTransformer {
|
||||
classFieldNode: ESTree.MethodDefinition | ESTree.PropertyDefinition,
|
||||
keyNode: ESTree.Literal
|
||||
): ESTree.MethodDefinition | ESTree.PropertyDefinition {
|
||||
if (
|
||||
typeof keyNode.value === 'string' &&
|
||||
keyNode.value !== ClassFieldTransformer.ignoredName &&
|
||||
!classFieldNode.computed
|
||||
) {
|
||||
if (typeof keyNode.value === 'string' && !this.isIgnoredName(keyNode.value) && !classFieldNode.computed) {
|
||||
classFieldNode.computed = true;
|
||||
}
|
||||
|
||||
|
||||
+17
-16
@@ -52,6 +52,21 @@ export class IdentifierReplacer implements IIdentifierReplacer {
|
||||
this.identifierNamesGenerator = identifierNamesGeneratorFactory(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @param {string} reservedNames
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public static isReservedName(name: string, reservedNames: string[]): boolean {
|
||||
if (!reservedNames.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return reservedNames.some((reservedName: string) => {
|
||||
return new RegExp(reservedName, 'g').exec(name) !== null;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Store identifier node `name` of global identifiers as key in map with random name as value.
|
||||
* Reserved name will be ignored.
|
||||
@@ -62,7 +77,7 @@ export class IdentifierReplacer implements IIdentifierReplacer {
|
||||
public storeGlobalName(identifierNode: ESTree.Identifier, lexicalScopeNode: TNodeWithLexicalScope): void {
|
||||
const identifierName: string = identifierNode.name;
|
||||
|
||||
if (this.isReservedName(identifierName)) {
|
||||
if (IdentifierReplacer.isReservedName(identifierName, this.options.reservedNames)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -89,7 +104,7 @@ export class IdentifierReplacer implements IIdentifierReplacer {
|
||||
public storeLocalName(identifierNode: ESTree.Identifier, lexicalScopeNode: TNodeWithLexicalScope): void {
|
||||
const identifierName: string = identifierNode.name;
|
||||
|
||||
if (this.isReservedName(identifierName)) {
|
||||
if (IdentifierReplacer.isReservedName(identifierName, this.options.reservedNames)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -142,18 +157,4 @@ export class IdentifierReplacer implements IIdentifierReplacer {
|
||||
): void {
|
||||
this.identifierNamesGenerator.preserveNameForLexicalScope(identifierNode.name, lexicalScopeNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @returns {boolean}
|
||||
*/
|
||||
private isReservedName(name: string): boolean {
|
||||
if (!this.options.reservedNames.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.options.reservedNames.some((reservedName: string) => {
|
||||
return new RegExp(reservedName, 'g').exec(name) !== null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+27
@@ -273,4 +273,31 @@ describe('ClassFieldTransformer', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #3: class method not obfuscated if option `reservedNames` is set', () => {
|
||||
const samplesCount: number = 100;
|
||||
|
||||
let obfuscations: string[];
|
||||
|
||||
beforeEach(() => {
|
||||
obfuscations = [];
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/class-with-function.js');
|
||||
|
||||
for (let i = 0; i < samplesCount; i++) {
|
||||
const obfuscatedCode: string = JavaScriptObfuscator.obfuscate(code, {
|
||||
controlFlowFlattening: true,
|
||||
deadCodeInjection: true,
|
||||
reservedNames: ['bar']
|
||||
}).getObfuscatedCode();
|
||||
|
||||
obfuscations.push(obfuscatedCode);
|
||||
}
|
||||
});
|
||||
|
||||
it('class should always have `bar` method not obfuscated', () => {
|
||||
for (const codeAsString of obfuscations) {
|
||||
assert.match(codeAsString, /\bbar\s*\(/);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
class Foo {
|
||||
bar() {
|
||||
console.log(1);
|
||||
baz();
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -25,7 +25,7 @@ describe('IdentifierReplacer', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #1: ignore global reserved names', () => {
|
||||
describe('Variant #2: ignore global reserved names', () => {
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
|
||||
Reference in New Issue
Block a user