10000 Use of `eslint-scope` data to rename identifiers #2: more refactoring · sec-js/javascript-obfuscator@b89ebcc · GitHub
[go: up one dir, main page]

Skip to content

Commit b89ebcc

Browse files
author
sanex3339
committed
Use of eslint-scope data to rename identifiers #2: more refactoring
1 parent 102b4cd commit b89ebcc

File tree

4 files changed

+99
-89
lines changed

4 files changed

+99
-89
lines changed

dist/index.browser.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/index.cli.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/index.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/node-transformers/obfuscating-transformers/ScopeIdentifiersTransformer.ts

Lines changed: 96 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import * as ESTree from 'estree';
66
import * as estraverse from 'estraverse';
77

88
import { TIdentifierObfuscatingReplacerFactory } from '../../types/container/node-transformers/TIdentifierObfuscatingReplacerFactory';
9+
import { TNodeWithLexicalScope } from '../../types/node/TNodeWithLexicalScope';
910

1011
import { IIdentifierObfuscatingReplacer } from '../../interfaces/node-transformers/obfuscating-transformers/obfuscating-replacers/IIdentifierObfuscatingReplacer';
1112
import { IOptions } from '../../interfaces/options/IOptions';
@@ -44,9 +45,9 @@ export class ScopeIdentifiersTransformer extends AbstractNodeTransformer {
4445
private readonly identifierObfuscatingReplacer: IIdentifierObfuscatingReplacer;
4546

4647
/**
47-
* @type {Map<eslintScope.Scope['block'], boolean>}
48+
* @type {Map<TNodeWithLexicalScope, boolean>}
4849
*/
49-
private readonly lexicalScopesWithObjectPatternWithoutDeclarationMap: Map<eslintScope.Scope['block'], boolean> = new Map();
50+
private readonly lexicalScopesWithObjectPatternWithoutDeclarationMap: Map<TNodeWithLexicalScope, boolean> = new Map();
5051

5152
/**
5253
* @type {IScopeAnalyzer}
@@ -122,12 +123,36 @@ export class ScopeIdentifiersTransformer extends AbstractNodeTransformer {
122123
* @param {Scope} scope
123124
*/
124125
private traverseScopeVariables (scope: eslintScope.Scope): void {
125-
const variableScope: eslintScope.Scope = scope.variableScope;
126-
const isGlobalVariableScope: boolean = ScopeIdentifiersTransformer.globalScopeNames.includes(variableScope.type);
126+
const lexicalScope: eslintScope.Scope = scope.variableScope;
127+
const nodeWithLexicalScope: TNodeWithLexicalScope | null = NodeGuards.isNodeWithBlockLexicalScope(lexicalScope.block)
128+
? lexicalScope.block
129+
: null;
130+
const isGlobalDeclaration: boolean = ScopeIdentifiersTransformer.globalScopeNames.includes(lexicalScope.type);
127131

128-
scope.variables.forEach((variable: eslintScope.Variable) => {
129-
this.processScopeVariableIdentifiers(variable, scope, variableScope, isGlobalVariableScope);
130-
});
132+
if (!nodeWithLexicalScope) {
133+
return;
134+
}
135+
136+
for (const variable of scope.variables) {
137+
if (variable.name === ScopeIdentifiersTransformer.argumentsVariableName) {
138+
continue;
139+
}
140+
141+
if (!this.options.renameGlobals && isGlobalDeclaration) {
142+
const isImportBindingOrCatchClauseIdentifier: boolean = variable.defs
143+
.every((definition: eslintScope.Definition) =>
144+
definition.type === 'ImportBinding'
145+
|| definition.type === 'CatchClause'
146+
);
147+
148+
// skip all global identifiers except import statement and catch clause parameter identifiers
149+
if (!isImportBindingOrCatchClauseIdentifier) {
150+
continue;
151+
}
152+
}
153+
154+
this.transformScopeVariableIdentifiers(variable, nodeWithLexicalScope, isGlobalDeclaration);
155+
}
131156

132157
for (const childScope of scope.childScopes) {
133158
this.traverseScopeVariables(childScope);
@@ -136,117 +161,86 @@ export class ScopeIdentifiersTransformer extends AbstractNodeTransformer {
136161

137162
/**
138163
* @param {Variable} variable
139-
* @param {Scope} scope
140-
* @param {Scope} variableScope
141-
* @param {boolean} isGlobalVariableScope
164+
* @param {TNodeWithLexicalScope} lexicalScopeNode
165+
* @param {boolean} isGlobalDeclaration
142166
*/
143-
private processScopeVariableIdentifiers (
167+
private transformScopeVariableIdentifiers (
144168
variable: eslintScope.Variable,
145-
scope: eslintScope.Scope,
146-
variableScope: eslintScope.Scope,
147-
isGlobalVariableScope: boolean
169+
lexicalScopeNode: TNodeWithLexicalScope,
170+
isGlobalDeclaration: boolean
148171
): void {
149-
if (variable.name === ScopeIdentifiersTransformer.argumentsVariableName) {
150-
return;
151-
}
152-
153-
if (!this.options.renameGlobals && isGlobalVariableScope) {
154-
const isImportBindingOrCatchClauseIdentifier: boolean = variable.defs
155-
.every((definition: eslintScope.Definition) =>
156-
definition.type === 'ImportBinding'
157-
|| definition.type === 'CatchClause'
158-
);
159-
160-
// skip all global identifiers except import statement and catch clause identifiers
161-
if (!isImportBindingOrCatchClauseIdentifier) {
162-
return;
163-
}
164-
}
165-
166172
for (const identifier of variable.identifiers) {
167-
if (!this.isReplaceableIdentifierNode(variable, identifier, variableScope.block)) {
173+
if (!this.isReplaceableIdentifierNode(identifier, lexicalScopeNode, variable)) {
168174
continue;
169175
}
170176

171-
identifier.name = this.getNewIdentifierName(
172-
identifier,
173-
scope,
174-
variableScope,
175-
isGlobalVariableScope
176-
);
177-
178-
// rename of references
179-
variable.references.forEach((reference: eslintScope.Reference) => {
180-
reference.identifier.name = identifier.name;
181-
});
182-
183-
// rename of function default parameter identifiers if exists
184-
(<any>variable.scope.block).defaults?.forEach((node: ESTree.Node) => {
185-
if (NodeGuards.isIdentifierNode(node) && node.name === variable.name) {
186-
node.name = identifier.name;
187-
}
188-
});
177+
this.storeIdentifierName(identifier, lexicalScopeNode, isGlobalDeclaration);
178+
this.replaceIdentifierName(identifier, lexicalScopeNode, variable);
189179
}
190180
}
191181

192182
/**
193183
* @param {Identifier} identifierNode
194-
* @param {Scope} scope
195-
* @param {Scope} variableScope
196-
* @param {boolean} isGlobalVariableScope
197-
* @returns {string}
184+
* @param {TNodeWithLexicalScope} lexicalScopeNode
185+
* @param {boolean} isGlobalDeclaration
198186
*/
199-
private getNewIdentifierName (
187+
private storeIdentifierName (
200188
identifierNode: ESTree.Identifier,
201-
scope: eslintScope.Scope,
202-
variableScope: eslintScope.Scope,
203-
isGlobalVariableScope: boolean
204-
): string {
205-
if (!identifierNode.parentNode || !NodeGuards.isNodeWithBlockLexicalScope(variableScope.block)) {
206-
return identifierNode.name;
207-
}
208-
209-
// prevent class name renaming twice for outer scope and for class scope
210-
if (scope.type === 'class' && this.isClassDeclarationNameIdentifierNode(identifierNode, identifierNode.parentNode)) {
211-
return identifierNode.name;
189+
lexicalScopeNode: TNodeWithLexicalScope,
190+
isGlobalDeclaration: boolean
191+
): void {
192+
if (isGlobalDeclaration) {
193+
this.identifierObfuscatingReplacer.storeGlobalName(identifierNode, lexicalScopeNode);
194+
} else {
195+
this.identifierObfuscatingReplacer.storeLocalName(identifierNode, lexicalScopeNode);
212196
}
213-
214-
isGlobalVariableScope
215-
? this.identifierObfuscatingReplacer.storeGlobalName(identifierNode, variableScope.block)
216-
: this.identifierObfuscatingReplacer.storeLocalName(identifierNode, variableScope.block);
217-
218-
return this.identifierObfuscatingReplacer.replace(identifierNode, variableScope.block).name;
219197
}
220198

221199
/**
222200
* @param {Identifier} identifierNode
223-
* @param {Node} parentNode
224-
* @returns {identifierNode is Identifier}
201+
* @param {TNodeWithLexicalScope} lexicalScopeNode
202+
* @param {Variable} variable
225203
*/
226-
private isClassDeclarationNameIdentifierNode (
204+
private replaceIdentifierName (
227205
identifierNode: ESTree.Identifier,
228-
parentNode: ESTree.Node
229-
): identifierNode is ESTree.Identifier {
230-
return NodeGuards.isClassDeclarationNode(parentNode)
231-
&& parentNode.id === identifierNode;
206+
lexicalScopeNode: TNodeWithLexicalScope,
207+
variable: eslintScope.Variable
208+
): void {
209+
const newIdentifier: ESTree.Identifier = this.identifierObfuscatingReplacer
210+
.replace(identifierNode, lexicalScopeNode);
211+
212+
identifierNode.name = newIdentifier.name;
213+
214+
// rename of references
215+
variable.references.forEach((reference: eslintScope.Reference) => {
216+
reference.identifier.name = identifierNode.name;
217+
});
218+
219+
// rename of function default parameter identifiers if exists
220+
(<any>variable.scope.block).defaults?.forEach((node: ESTree.Node) => {
221+
if (NodeGuards.isIdentifierNode(node) && node.name === variable.name) {
222+
node.name = identifierNode.name;
223+
}
224+
});
232225
}
233226

234227
/**
235-
* @param {Variable} variable
236228
* @param {Identifier} identifierNode
237-
* @param {Scope["block"]} lexicalScopeNode
229+
* @param {TNodeWithLexicalScope} lexicalScopeNode
230+
* @param {Variable} variable
238231
* @returns {boolean}
239232
*/
240233
private isReplaceableIdentifierNode (
241-
variable: eslintScope.Variable,
242234
identifierNode: ESTree.Identifier,
243-
lexicalScopeNode: eslintScope.Scope['block']
244-
): boolean {
235+
lexicalScopeNode: TNodeWithLexicalScope,
236+
variable: eslintScope.Variable
237+
): identifierNode is ESTree.Identifier & { parentNode: ESTree.Node } {
245238
const parentNode: ESTree.Node | undefined = identifierNode.parentNode;
246239

247240
return !!parentNode
248241
&& !NodeMetadata.isIgnoredNode(identifierNode)
249242
&& !this.isProhibitedPropertyNode(identifierNode, parentNode)
243+
&& !this.isProhibitedClassDeclarationNameIdentifierNode(variable, identifierNode, parentNode)
250244
&& !this.isProhibitedExportNamedClassDeclarationIdentifierNode(identifierNode, parentNode)
251245
&& !this.isProhibitedExportNamedFunctionDeclarationIdentifierNode(identifierNode, parentNode)
252246
&& !this.isProhibitedExportNamedVariableDeclarationIdentifierNode(identifierNode, parentNode)
@@ -255,6 +249,22 @@ export class ScopeIdentifiersTransformer extends AbstractNodeTransformer {
255249
&& !NodeGuards.isLabelIdentifierNode(identifierNode, parentNode);
256250
}
257251

252+
/**
253+
* @param {Variable} variable
254+
* @param {Identifier} identifierNode
255+
* @param {Node} parentNode
256+
* @returns {identifierNode is Identifier}
257+
*/
258+
private isProhibitedClassDeclarationNameIdentifierNode (
259+
variable: eslintScope.Variable,
260+
identifierNode: ESTree.Identifier,
261+
parentNode: ESTree.Node
262+
): identifierNode is ESTree.Identifier {
263+
return NodeGuards.isClassDeclarationNode(variable.scope.block)
264+
&& NodeGuards.isClassDeclarationNode(parentNode)
265+
&& parentNode.id === identifierNode;
266+
}
267+
258268
/**
259269
* @param {Identifier} identifierNode
260270
* @param {Node} parentNode
@@ -331,13 +341,13 @@ export class ScopeIdentifiersTransformer extends AbstractNodeTransformer {
331341
*
332342
* @param {Variable} variable
333343
* @param {Identifier} identifierNode
334-
* @param {eslintScope.Scope['block']} lexicalScopeNode
344+
* @param {TNodeWithLexicalScope} lexicalScopeNode
335345
* @returns {boolean}
336346
*/
337347
private isProhibitedVariableNameUsedInObjectPatternNode (
338348
variable: eslintScope.Variable,
339349
identifierNode: ESTree.Identifier,
340-
lexicalScopeNode: eslintScope.Scope['block']
350+
lexicalScopeNode: TNodeWithLexicalScope
341351
): boolean {
342352
let isLexicalScopeHasObjectPatternWithoutDeclaration: boolean | undefined =
343353
this.lexicalScopesWithObjectPatternWithoutDeclarationMap.get(lexicalScopeNode);

0 commit comments

Comments
 (0)
0