mirror of
https://github.com/javascript-obfuscator/javascript-obfuscator
synced 2026-08-09 12:42:29 +00:00
Fixed wrong scope of preserved identifiers of shorthand object pattern property
This commit is contained in:
@@ -1,5 +1,9 @@
|
||||
Change Log
|
||||
|
||||
v0.25.1
|
||||
---
|
||||
* Additional fixes of https://github.com/javascript-obfuscator/javascript-obfuscator/issues/550
|
||||
|
||||
v0.25.0
|
||||
---
|
||||
* Improved `mangled` identifier names generator logic
|
||||
|
||||
Vendored
+5
-5
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
@@ -14,6 +14,6 @@ export interface ObfuscatedCode extends IObfuscatedCode {}
|
||||
export function obfuscate (sourceCode: string, inputOptions?: ObfuscatorOptions): ObfuscatedCode;
|
||||
|
||||
/**
|
||||
* @type {string | undefined}
|
||||
* @type {string}
|
||||
*/
|
||||
export const version: string;
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "javascript-obfuscator",
|
||||
"version": "0.25.0",
|
||||
"version": "0.25.1",
|
||||
"description": "JavaScript obfuscator",
|
||||
"keywords": [
|
||||
"obfuscator",
|
||||
|
||||
@@ -4,6 +4,7 @@ import { TNodeWithLexicalScope } from '../../types/node/TNodeWithLexicalScope';
|
||||
|
||||
export interface IScopeIdentifiersTraverserCallbackData {
|
||||
isGlobalDeclaration: boolean;
|
||||
isBubblingDeclaration: boolean;
|
||||
rootScope: eslintScope.Scope;
|
||||
variable: eslintScope.Variable;
|
||||
variableLexicalScopeNode: TNodeWithLexicalScope;
|
||||
|
||||
@@ -7,7 +7,6 @@ import * as ESTree from 'estree';
|
||||
|
||||
import { TNodeTransformerFactory } from '../types/container/node-transformers/TNodeTransformerFactory';
|
||||
import { TNormalizedNodeTransformers } from '../types/node-transformers/TNormalizedNodeTransformers';
|
||||
import { TTransformersRunnerData } from '../types/node-transformers/TTransformersRunnerData';
|
||||
import { TVisitorDirection } from '../types/node-transformers/TVisitorDirection';
|
||||
import { TVisitorFunction } from '../types/node-transformers/TVisitorFunction';
|
||||
import { TVisitorResult } from '../types/node-transformers/TVisitorResult';
|
||||
@@ -26,11 +25,6 @@ import { NodeMetadata } from '../node/NodeMetadata';
|
||||
|
||||
@injectable()
|
||||
export class TransformersRunner implements ITransformersRunner {
|
||||
/**
|
||||
* @type {Map<NodeTransformer[], TTransformersRunnerData>}
|
||||
*/
|
||||
private readonly cachedNodeTransformersData: Map<NodeTransformer[], TTransformersRunnerData> = new Map();
|
||||
|
||||
/**
|
||||
* @type {TNodeTransformerFactory}
|
||||
*/
|
||||
@@ -70,19 +64,10 @@ export class TransformersRunner implements ITransformersRunner {
|
||||
return astTree;
|
||||
}
|
||||
|
||||
let normalizedNodeTransformers: TNormalizedNodeTransformers;
|
||||
let nodeTransformerNamesGroups: NodeTransformer[][];
|
||||
|
||||
if (!this.cachedNodeTransformersData.has(nodeTransformerNames)) {
|
||||
normalizedNodeTransformers = this.buildNormalizedNodeTransformers(nodeTransformerNames);
|
||||
nodeTransformerNamesGroups = this.nodeTransformerNamesGroupsBuilder.build(normalizedNodeTransformers);
|
||||
this.cachedNodeTransformersData.set(nodeTransformerNames, [normalizedNodeTransformers, nodeTransformerNamesGroups]);
|
||||
} else {
|
||||
[
|
||||
normalizedNodeTransformers,
|
||||
nodeTransformerNamesGroups
|
||||
] = <TTransformersRunnerData>this.cachedNodeTransformersData.get(nodeTransformerNames);
|
||||
}
|
||||
const normalizedNodeTransformers: TNormalizedNodeTransformers =
|
||||
this.buildNormalizedNodeTransformers(nodeTransformerNames, transformationStage);
|
||||
const nodeTransformerNamesGroups: NodeTransformer[][] =
|
||||
this.nodeTransformerNamesGroupsBuilder.build(normalizedNodeTransformers);
|
||||
|
||||
for (const nodeTransformerNamesGroup of nodeTransformerNamesGroups) {
|
||||
const enterVisitors: IVisitor[] = [];
|
||||
@@ -120,15 +105,27 @@ export class TransformersRunner implements ITransformersRunner {
|
||||
|
||||
/**
|
||||
* @param {NodeTransformer[]} nodeTransformerNames
|
||||
* @param {TransformationStage} transformationStage
|
||||
* @returns {TNormalizedNodeTransformers}
|
||||
*/
|
||||
private buildNormalizedNodeTransformers (nodeTransformerNames: NodeTransformer[]): TNormalizedNodeTransformers {
|
||||
private buildNormalizedNodeTransformers (
|
||||
nodeTransformerNames: NodeTransformer[],
|
||||
transformationStage: TransformationStage
|
||||
): TNormalizedNodeTransformers {
|
||||
return nodeTransformerNames
|
||||
.reduce<TNormalizedNodeTransformers>(
|
||||
(acc: TNormalizedNodeTransformers, nodeTransformerName: NodeTransformer) => ({
|
||||
...acc,
|
||||
[nodeTransformerName]: this.nodeTransformerFactory(nodeTransformerName)
|
||||
}),
|
||||
(acc: TNormalizedNodeTransformers, nodeTransformerName: NodeTransformer) => {
|
||||
const nodeTransformer: INodeTransformer = this.nodeTransformerFactory(nodeTransformerName);
|
||||
|
||||
if (!nodeTransformer.getVisitor(transformationStage)) {
|
||||
return acc;
|
||||
}
|
||||
|
||||
return {
|
||||
...acc,
|
||||
[nodeTransformerName]: nodeTransformer
|
||||
};
|
||||
},
|
||||
{}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import { IOptions } from '../../interfaces/options/IOptions';
|
||||
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
|
||||
import { IVisitor } from '../../interfaces/node-transformers/IVisitor';
|
||||
|
||||
import { NodeTransformer } from '../../enums/node-transformers/NodeTransformer';
|
||||
import { TransformationStage } from '../../enums/node-transformers/TransformationStage';
|
||||
|
||||
import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
|
||||
@@ -24,6 +25,14 @@ export class CommentsTransformer extends AbstractNodeTransformer {
|
||||
'@preserve'
|
||||
];
|
||||
|
||||
/**
|
||||
* @type {NodeTransformer.ParentificationTransformer[]}
|
||||
*/
|
||||
public readonly runAfter: NodeTransformer[] = [
|
||||
NodeTransformer.ParentificationTransformer,
|
||||
NodeTransformer.VariablePreserveTransformer
|
||||
];
|
||||
|
||||
/**
|
||||
* @param {IRandomGenerator} randomGenerator
|
||||
* @param {IOptions} options
|
||||
|
||||
@@ -14,6 +14,7 @@ import { ICallsGraphData } from '../../interfaces/analyzers/calls-graph-analyzer
|
||||
import { IPrevailingKindOfVariablesAnalyzer } from '../../interfaces/analyzers/calls-graph-analyzer/IPrevailingKindOfVariablesAnalyzer';
|
||||
import { IVisitor } from '../../interfaces/node-transformers/IVisitor';
|
||||
|
||||
import { NodeTransformer } from '../../enums/node-transformers/NodeTransformer';
|
||||
import { ObfuscationEvent } from '../../enums/event-emitters/ObfuscationEvent';
|
||||
import { TransformationStage } from '../../enums/node-transformers/TransformationStage';
|
||||
|
||||
@@ -25,6 +26,14 @@ import { NodeGuards } from '../../node/NodeGuards';
|
||||
*/
|
||||
@injectable()
|
||||
export class CustomCodeHelpersTransformer extends AbstractNodeTransformer {
|
||||
/**
|
||||
* @type {NodeTransformer.ParentificationTransformer[]}
|
||||
*/
|
||||
public readonly runAfter: NodeTransformer[] = [
|
||||
NodeTransformer.ParentificationTransformer,
|
||||
NodeTransformer.VariablePreserveTransformer
|
||||
];
|
||||
|
||||
/**
|
||||
* @type {TCustomCodeHelperGroupStorage}
|
||||
*/
|
||||
|
||||
@@ -8,6 +8,7 @@ import { IOptions } from '../../interfaces/options/IOptions';
|
||||
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
|
||||
import { IVisitor } from '../../interfaces/node-transformers/IVisitor';
|
||||
|
||||
import { NodeTransformer } from '../../enums/node-transformers/NodeTransformer';
|
||||
import { TransformationStage } from '../../enums/node-transformers/TransformationStage';
|
||||
|
||||
import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
|
||||
@@ -17,6 +18,14 @@ import { NodeUtils } from '../../node/NodeUtils';
|
||||
|
||||
@injectable()
|
||||
export class EvalCallExpressionTransformer extends AbstractNodeTransformer {
|
||||
/**
|
||||
* @type {NodeTransformer.ParentificationTransformer[]}
|
||||
*/
|
||||
public readonly runAfter: NodeTransformer[] = [
|
||||
NodeTransformer.ParentificationTransformer,
|
||||
NodeTransformer.VariablePreserveTransformer
|
||||
];
|
||||
|
||||
/**
|
||||
* @type {Set <FunctionExpression>}
|
||||
*/
|
||||
@@ -147,6 +156,9 @@ export class EvalCallExpressionTransformer extends AbstractNodeTransformer {
|
||||
const evalRootAstHostNode: ESTree.FunctionExpression = NodeFactory
|
||||
.functionExpressionNode([], NodeFactory.blockStatementNode(ast));
|
||||
|
||||
NodeUtils.parentizeAst(evalRootAstHostNode);
|
||||
NodeUtils.parentizeNode(evalRootAstHostNode, parentNode);
|
||||
|
||||
/**
|
||||
* we should store that host node and then extract AST-tree on the `finalizing` stage
|
||||
*/
|
||||
|
||||
@@ -7,6 +7,7 @@ import { IOptions } from '../../interfaces/options/IOptions';
|
||||
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
|
||||
import { IVisitor } from '../../interfaces/node-transformers/IVisitor';
|
||||
|
||||
import { NodeTransformer } from '../../enums/node-transformers/NodeTransformer';
|
||||
import { TransformationStage } from '../../enums/node-transformers/TransformationStage';
|
||||
|
||||
import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
|
||||
@@ -18,6 +19,14 @@ import { NodeMetadata } from '../../node/NodeMetadata';
|
||||
*/
|
||||
@injectable()
|
||||
export class MetadataTransformer extends AbstractNodeTransformer {
|
||||
/**
|
||||
* @type {NodeTransformer.ParentificationTransformer[]}
|
||||
*/
|
||||
public readonly runAfter: NodeTransformer[] = [
|
||||
NodeTransformer.ParentificationTransformer,
|
||||
NodeTransformer.VariablePreserveTransformer
|
||||
];
|
||||
|
||||
/**
|
||||
* @param {IRandomGenerator} randomGenerator
|
||||
* @param {IOptions} options
|
||||
|
||||
@@ -10,6 +10,7 @@ import { IOptions } from '../../interfaces/options/IOptions';
|
||||
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
|
||||
import { IVisitor } from '../../interfaces/node-transformers/IVisitor';
|
||||
|
||||
import { NodeTransformer } from '../../enums/node-transformers/NodeTransformer';
|
||||
import { ObfuscatingGuard } from '../../enums/node-transformers/preparing-transformers/obfuscating-guards/ObfuscatingGuard';
|
||||
import { TransformationStage } from '../../enums/node-transformers/TransformationStage';
|
||||
|
||||
@@ -30,6 +31,14 @@ export class ObfuscatingGuardsTransformer extends AbstractNodeTransformer {
|
||||
ObfuscatingGuard.ReservedStringObfuscatingGuard
|
||||
];
|
||||
|
||||
/**
|
||||
* @type {NodeTransformer.ParentificationTransformer[]}
|
||||
*/
|
||||
public readonly runAfter: NodeTransformer[] = [
|
||||
NodeTransformer.ParentificationTransformer,
|
||||
NodeTransformer.VariablePreserveTransformer
|
||||
];
|
||||
|
||||
/**
|
||||
* @type {IObfuscatingGuard[]}
|
||||
*/
|
||||
|
||||
@@ -12,6 +12,7 @@ import { IScopeIdentifiersTraverser } from '../../interfaces/node/IScopeIdentifi
|
||||
import { IScopeIdentifiersTraverserCallbackData } from '../../interfaces/node/IScopeIdentifiersTraverserCallbackData';
|
||||
import { IVisitor } from '../../interfaces/node-transformers/IVisitor';
|
||||
|
||||
import { NodeTransformer } from '../../enums/node-transformers/NodeTransformer';
|
||||
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
|
||||
import { TransformationStage } from '../../enums/node-transformers/TransformationStage';
|
||||
|
||||
@@ -24,6 +25,13 @@ import { NodeGuards } from '../../node/NodeGuards';
|
||||
*/
|
||||
@injectable()
|
||||
export class VariablePreserveTransformer extends AbstractNodeTransformer {
|
||||
/**
|
||||
* @type {NodeTransformer.ParentificationTransformer[]}
|
||||
*/
|
||||
public readonly runAfter: NodeTransformer[] = [
|
||||
NodeTransformer.ParentificationTransformer
|
||||
];
|
||||
|
||||
/**
|
||||
* @type {IIdentifierObfuscatingReplacer}
|
||||
*/
|
||||
@@ -53,6 +61,8 @@ export class VariablePreserveTransformer extends AbstractNodeTransformer {
|
||||
IdentifierObfuscatingReplacer.BaseIdentifierObfuscatingReplacer
|
||||
);
|
||||
this.scopeIdentifiersTraverser = scopeIdentifiersTraverser;
|
||||
|
||||
this.preserveScopeVariableIdentifiers = this.preserveScopeVariableIdentifiers.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -86,36 +96,25 @@ export class VariablePreserveTransformer extends AbstractNodeTransformer {
|
||||
this.scopeIdentifiersTraverser.traverse(
|
||||
programNode,
|
||||
parentNode,
|
||||
(data: IScopeIdentifiersTraverserCallbackData) => {
|
||||
const {
|
||||
isGlobalDeclaration,
|
||||
variable,
|
||||
variableScope
|
||||
} = data;
|
||||
|
||||
this.preserveScopeVariableIdentifiers(
|
||||
variable,
|
||||
variableScope,
|
||||
isGlobalDeclaration
|
||||
);
|
||||
}
|
||||
this.preserveScopeVariableIdentifiers
|
||||
);
|
||||
|
||||
return programNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Variable} variable
|
||||
* @param {Scope} variableScope
|
||||
* @param {boolean} isGlobalDeclaration
|
||||
* @param {IScopeIdentifiersTraverserCallbackData} data
|
||||
*/
|
||||
private preserveScopeVariableIdentifiers (
|
||||
variable: eslintScope.Variable,
|
||||
variableScope: eslintScope.Scope,
|
||||
isGlobalDeclaration: boolean
|
||||
): void {
|
||||
private preserveScopeVariableIdentifiers (data: IScopeIdentifiersTraverserCallbackData): void {
|
||||
const {
|
||||
isGlobalDeclaration,
|
||||
isBubblingDeclaration,
|
||||
variable,
|
||||
variableScope
|
||||
} = data;
|
||||
|
||||
for (const identifier of variable.identifiers) {
|
||||
if (isGlobalDeclaration) {
|
||||
if (isGlobalDeclaration || isBubblingDeclaration) {
|
||||
this.preserveIdentifierNameForRootLexicalScope(identifier);
|
||||
} else {
|
||||
this.preserveIdentifierNameForLexicalScope(identifier, variableScope);
|
||||
|
||||
@@ -86,8 +86,17 @@ export class ScopeIdentifiersTraverser implements IScopeIdentifiersTraverser {
|
||||
continue;
|
||||
}
|
||||
|
||||
const isBubblingDeclaration: boolean = variable
|
||||
.identifiers
|
||||
.some((identifier: ESTree.Node) =>
|
||||
identifier.parentNode
|
||||
&& NodeGuards.isPropertyNode(identifier.parentNode)
|
||||
&& identifier.parentNode.shorthand
|
||||
);
|
||||
|
||||
callback({
|
||||
isGlobalDeclaration,
|
||||
isBubblingDeclaration,
|
||||
rootScope,
|
||||
variable,
|
||||
variableScope,
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
import { TNormalizedNodeTransformers } from './TNormalizedNodeTransformers';
|
||||
|
||||
import { NodeTransformer } from '../../enums/node-transformers/NodeTransformer';
|
||||
|
||||
export type TTransformersRunnerData = [TNormalizedNodeTransformers, NodeTransformer[][]];
|
||||
+96
@@ -156,4 +156,100 @@ describe('VariablePreserveTransformer', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #4: destructed object property identifier name conflict with identifier name', () => {
|
||||
describe('Variant #1: `renameGlobals` option is disabled', () => {
|
||||
const variableDeclarationIdentifierName: RegExp = /var b *= *0x1;/;
|
||||
const destructedObjectPropertyIdentifierName: RegExp = /const { *a *} *= *{ *'a' *: *0x2 *};/;
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/destructed-object-property-identifier-name-1.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
identifierNamesGenerator: 'mangled',
|
||||
renameGlobals: false
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should generate non-preserved name for variable name', () => {
|
||||
assert.match(obfuscatedCode, variableDeclarationIdentifierName);
|
||||
});
|
||||
|
||||
it('should keep the original name for destructed object property identifier', () => {
|
||||
assert.match(obfuscatedCode, destructedObjectPropertyIdentifierName);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #2: `renameGlobals` option is enabled', () => {
|
||||
const variableDeclarationIdentifierName: RegExp = /var b *= *0x1;/;
|
||||
const functionDeclarationIdentifierName: RegExp = /function c *\(\) *{/;
|
||||
const destructedObjectPropertyIdentifierName: RegExp = /const { *a *} *= *{ *'a' *: *0x2 *};/;
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/destructed-object-property-identifier-name-2.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
identifierNamesGenerator: 'mangled',
|
||||
renameGlobals: true
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should generate non-preserved name for variable declaration', () => {
|
||||
assert.match(obfuscatedCode, variableDeclarationIdentifierName);
|
||||
});
|
||||
|
||||
it('should generate non-preserved name for function declaration', () => {
|
||||
assert.match(obfuscatedCode, functionDeclarationIdentifierName);
|
||||
});
|
||||
|
||||
it('should keep the original name for destructed object property identifier', () => {
|
||||
assert.match(obfuscatedCode, destructedObjectPropertyIdentifierName);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #3: function destructed object property', () => {
|
||||
const variableDeclarationIdentifierName: RegExp = /var b *= *0x1;/;
|
||||
const destructedObjectPropertyIdentifierName: RegExp = /return *\({ *a *}\) *=> *{/;
|
||||
const consoleLogIdentifierNames: RegExp = /console\['log']\(b, *a\);/;
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/destructed-object-property-identifier-name-3.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
identifierNamesGenerator: 'mangled',
|
||||
renameGlobals: false
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should generate non-preserved name for variable declaration', () => {
|
||||
assert.match(obfuscatedCode, variableDeclarationIdentifierName);
|
||||
});
|
||||
|
||||
it('should keep the original name for destructed object property identifier', () => {
|
||||
assert.match(obfuscatedCode, destructedObjectPropertyIdentifierName);
|
||||
});
|
||||
|
||||
it('should generate valid identifier names for console.log call', () => {
|
||||
assert.match(obfuscatedCode, consoleLogIdentifierNames);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
function foo() {
|
||||
var bar = 1;
|
||||
|
||||
return () => {
|
||||
const { a } = {a: 2};
|
||||
|
||||
console.log(bar, a);
|
||||
};
|
||||
}
|
||||
foo();
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
var foo = 1;
|
||||
|
||||
function bar() {
|
||||
const { a } = {a: 2};
|
||||
|
||||
console.log(foo, a);
|
||||
}
|
||||
bar();
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
function foo() {
|
||||
var bar = 1;
|
||||
|
||||
return ({a}) => {
|
||||
console.log(bar, a);
|
||||
}
|
||||
}
|
||||
foo();
|
||||
Reference in New Issue
Block a user