From 91846ec74afaeb1c4e2962742a6af517d835a750 Mon Sep 17 00:00:00 2001 From: sanex3339 Date: Sun, 22 Mar 2026 12:23:44 +0700 Subject: [PATCH] Fixed `reservedNames` not preserving class method and property names when `stringArray` or `deadCodeInjection` is enabled --- CHANGELOG.md | 1 + .../ClassFieldTransformer.ts | 21 ++++++++---- .../replacer/IdentifierReplacer.ts | 33 ++++++++++--------- .../ClassFieldTransformer.spec.ts | 27 +++++++++++++++ .../fixtures/class-with-function.js | 6 ++++ .../IdentifierReplacer.spec.ts | 2 +- 6 files changed, 67 insertions(+), 23 deletions(-) create mode 100644 test/functional-tests/node-transformers/converting-transformers/class-field-transformer/fixtures/class-with-function.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 60ea00dd1..d626ae830 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/src/node-transformers/converting-transformers/ClassFieldTransformer.ts b/src/node-transformers/converting-transformers/ClassFieldTransformer.ts index f19ca4e96..6ed14af3c 100644 --- a/src/node-transformers/converting-transformers/ClassFieldTransformer.ts +++ b/src/node-transformers/converting-transformers/ClassFieldTransformer.ts @@ -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; } diff --git a/src/node-transformers/rename-identifiers-transformers/replacer/IdentifierReplacer.ts b/src/node-transformers/rename-identifiers-transformers/replacer/IdentifierReplacer.ts index 8a7d70846..7c2847fa0 100644 --- a/src/node-transformers/rename-identifiers-transformers/replacer/IdentifierReplacer.ts +++ b/src/node-transformers/rename-identifiers-transformers/replacer/IdentifierReplacer.ts @@ -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; - }); - } } diff --git a/test/functional-tests/node-transformers/converting-transformers/class-field-transformer/ClassFieldTransformer.spec.ts b/test/functional-tests/node-transformers/converting-transformers/class-field-transformer/ClassFieldTransformer.spec.ts index 7dae5624e..ecc0fc387 100644 --- a/test/functional-tests/node-transformers/converting-transformers/class-field-transformer/ClassFieldTransformer.spec.ts +++ b/test/functional-tests/node-transformers/converting-transformers/class-field-transformer/ClassFieldTransformer.spec.ts @@ -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*\(/); + } + }); + }); }); diff --git a/test/functional-tests/node-transformers/converting-transformers/class-field-transformer/fixtures/class-with-function.js b/test/functional-tests/node-transformers/converting-transformers/class-field-transformer/fixtures/class-with-function.js new file mode 100644 index 000000000..42686f069 --- /dev/null +++ b/test/functional-tests/node-transformers/converting-transformers/class-field-transformer/fixtures/class-with-function.js @@ -0,0 +1,6 @@ +class Foo { + bar() { + console.log(1); + baz(); + } +} diff --git a/test/functional-tests/node-transformers/rename-identifiers-transformers/identifier-replacer/IdentifierReplacer.spec.ts b/test/functional-tests/node-transformers/rename-identifiers-transformers/identifier-replacer/IdentifierReplacer.spec.ts index 26da60efd..80b4308dc 100644 --- a/test/functional-tests/node-transformers/rename-identifiers-transformers/identifier-replacer/IdentifierReplacer.spec.ts +++ b/test/functional-tests/node-transformers/rename-identifiers-transformers/identifier-replacer/IdentifierReplacer.spec.ts @@ -25,7 +25,7 @@ describe('IdentifierReplacer', () => { }); }); - describe('Variant #1: ignore global reserved names', () => { + describe('Variant #2: ignore global reserved names', () => { let obfuscatedCode: string; before(() => {