distinctiomagnam
Version:
JavaScript Obfuscation Tool.
125 lines (107 loc) • 3.25 kB
text/typescript
import { ok } from "assert";
import { reservedIdentifiers } from "../../constants";
import { walk } from "../../traverse";
import { isValidIdentifier } from "../../util/compare";
import { Node } from "../../util/gen";
import { getIdentifierInfo } from "../../util/identifiers";
import {
getDefiningContext,
getVarContext,
getLexContext,
isContext,
getReferencingContexts,
} from "../../util/insert";
import Transform from "../transform";
/**
* Keeps track of what identifiers are defined and referenced in each context.
*/
export default class VariableAnalysis extends Transform {
/**
* Node being the context.
*/
defined: Map<Node, Set<string>>;
/**
* Context->Nodes referenced (does not include nested)
*/
references: Map<Node, Set<string>>;
/**
* Set of global identifiers to never be redefined
*/
globals: Set<string>;
/**
* Set of identifers that are defined within the program
*/
notGlobals: Set<string>;
constructor(o) {
super(o);
this.defined = new Map();
this.references = new Map();
this.globals = new Set();
this.notGlobals = new Set();
}
match(object, parents) {
return isContext(object);
}
transform(object, parents) {
walk(object, parents, (o, p) => {
if (o.type == "Identifier") {
var name = o.name;
ok(typeof name === "string");
if (!isValidIdentifier(name)) {
return;
}
if (reservedIdentifiers.has(name)) {
return;
}
if (this.options.globalVariables.has(name)) {
return;
}
var info = getIdentifierInfo(o, p);
if (!info.spec.isReferenced) {
return;
}
if (info.spec.isExported) {
return;
}
var isDefined = info.spec.isDefined;
// Keep track of defined names within the program
if (isDefined) {
this.notGlobals.add(o.name);
this.globals.delete(o.name);
} else if (!this.notGlobals.has(o.name)) {
this.globals.add(o.name);
}
var definingContexts = info.spec.isDefined
? [getDefiningContext(o, p)]
: getReferencingContexts(o, p, info);
ok(definingContexts.length);
definingContexts.forEach((definingContext) => {
ok(
isContext(definingContext),
`${definingContext.type} is not a context`
);
if (isDefined) {
// Add to defined Map
if (!this.defined.has(definingContext)) {
this.defined.set(definingContext, new Set());
}
this.defined.get(definingContext).add(name);
this.references.has(definingContext) &&
this.references.get(definingContext).delete(name);
} else {
// Add to references Map
if (
!this.defined.has(definingContext) ||
!this.defined.get(definingContext).has(name)
) {
if (!this.references.has(definingContext)) {
this.references.set(definingContext, new Set());
}
this.references.get(definingContext).add(name);
}
}
});
}
});
}
}