@dacely/toildefender 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -36,6 +36,21 @@ function veilmark$numericVmPow(a, b) {
36
36
  return Math.pow(a, b);
37
37
  }
38
38
 
39
+ function veilmark$numericVmDigit(program, baseBig, index, powers) {
40
+ if (powers) {
41
+ while (powers.length <= index) {
42
+ powers[powers.length] = powers[powers.length - 1] * baseBig;
43
+ }
44
+ return Number((program / powers[index]) % baseBig);
45
+ }
46
+ var pow = BigInt(1);
47
+ while (index > 0) {
48
+ pow *= baseBig;
49
+ index -= 1;
50
+ }
51
+ return Number((program / pow) % baseBig);
52
+ }
53
+
39
54
  function veilmark$hashMeshMix(current, value) {
40
55
  var h = (current ^ value) >>> 0;
41
56
  h = Math.imul(h ^ (h >>> 16), 2246822507) >>> 0;
@@ -87,34 +102,21 @@ function veilmark$hashMeshStream(key, index, base, salt) {
87
102
  return hash % base;
88
103
  }
89
104
 
90
- function veilmark$hashMeshUnlock(program, base, tokenCount, seed, tag, ops, mesh) {
91
- var key = veilmark$hashMeshKey(mesh, base, tokenCount, seed, tag, ops);
92
- var salt = mesh[5] >>> 0;
93
- var baseBig = BigInt(base);
94
- var out = BigInt(0);
95
- var pow = BigInt(1);
96
- var i = 0;
97
- while (i < tokenCount) {
98
- var cipher = Number(program % baseBig);
99
- program = program / baseBig;
100
- var plain = (cipher - veilmark$hashMeshStream(key, i, base, salt) + base) % base;
101
- out += BigInt(plain) * pow;
102
- pow *= baseBig;
103
- i += 1;
104
- }
105
- return out;
105
+ function veilmark$hashMeshUnlock(program, base, baseBig, index, key, salt, powers) {
106
+ var cipher = veilmark$numericVmDigit(program, baseBig, index, powers);
107
+ return (cipher - veilmark$hashMeshStream(key, index, base, salt) + base) % base;
106
108
  }
107
109
 
108
110
  function veilmark$numericVmRun(program, base, tokenCount, seed, tag, constants, argsLike, self, ops, mesh) {
111
+ var baseBig = BigInt(base);
112
+ var digitPowers = [BigInt(1)];
113
+ var meshKey = 0;
114
+ var meshSalt = 0;
109
115
  if (mesh) {
110
- program = veilmark$hashMeshUnlock(program, base, tokenCount, seed, tag, ops, mesh);
116
+ meshKey = veilmark$hashMeshKey(mesh, base, tokenCount, seed, tag, ops);
117
+ meshSalt = mesh[5] >>> 0;
111
118
  }
112
119
 
113
- var tokens = [];
114
- var state = seed >>> 0;
115
- var seen = seed >>> 0;
116
- var baseBig = BigInt(base);
117
-
118
120
  function inverse(value, modulo) {
119
121
  var t = 0, nt = 1;
120
122
  var r = modulo, nr = value % modulo;
@@ -136,28 +138,95 @@ function veilmark$numericVmRun(program, base, tokenCount, seed, tag, constants,
136
138
  return (mixed ^ (mixed >>> 13)) >>> 0;
137
139
  }
138
140
 
141
+ function encryptedAt(index) {
142
+ if (mesh) return veilmark$hashMeshUnlock(program, base, baseBig, index, meshKey, meshSalt, digitPowers);
143
+ return veilmark$numericVmDigit(program, baseBig, index, digitPowers);
144
+ }
145
+
139
146
  var i = 0;
147
+ var seen = seed >>> 0;
140
148
  while (i < tokenCount) {
141
- var encrypted = Number(program % baseBig);
142
- program = program / baseBig;
143
- var mul = 1 + ((state >>> 5) % (base - 1));
144
- var add = state % base;
145
- var plain = (((encrypted - add + base) % base) * inverse(mul, base)) % base;
146
- tokens.push(plain);
149
+ var encrypted = encryptedAt(i);
147
150
  seen = mix(seen, encrypted, i);
148
- state = mix(state, encrypted, i);
149
151
  i += 1;
150
152
  }
151
153
 
152
154
  if ((seen >>> 0) !== (tag >>> 0)) throw new Error("invalid numeric vm program");
153
155
 
154
- var stack = [];
155
- var locals = [];
156
+ var decodeIndex = 0;
157
+ var decodeState = seed >>> 0;
158
+
159
+ function stateBefore(index) {
160
+ if (index < decodeIndex) {
161
+ decodeIndex = 0;
162
+ decodeState = seed >>> 0;
163
+ }
164
+ while (decodeIndex < index) {
165
+ var skipped = encryptedAt(decodeIndex);
166
+ decodeState = mix(decodeState, skipped, decodeIndex);
167
+ decodeIndex += 1;
168
+ }
169
+ return decodeState;
170
+ }
171
+
172
+ function decodeAt(index) {
173
+ var state = stateBefore(index);
174
+ var encrypted = encryptedAt(index);
175
+ var mul = 1 + ((state >>> 5) % (base - 1));
176
+ var add = state % base;
177
+ var plain = (((encrypted - add + base) % base) * inverse(mul, base)) % base;
178
+ if (index === decodeIndex) {
179
+ decodeState = mix(state, encrypted, index);
180
+ decodeIndex = index + 1;
181
+ }
182
+ return plain;
183
+ }
184
+
185
+ var layout = seed & 1;
186
+ var stack = layout ? null : [];
187
+ var locals = layout ? null : [];
188
+ var cells = layout ? { s: [], l: Object.create(null) } : null;
156
189
  var frameArgs = Array.prototype.slice.call(argsLike);
157
190
  var ip = 0;
158
191
 
192
+ function push(value) {
193
+ if (layout) cells.s[cells.s.length] = value;
194
+ else stack.push(value);
195
+ }
196
+
197
+ function pop() {
198
+ return layout ? cells.s.pop() : stack.pop();
199
+ }
200
+
201
+ function peek() {
202
+ var current = layout ? cells.s : stack;
203
+ return current[current.length - 1];
204
+ }
205
+
206
+ function loadLocal(slot) {
207
+ return layout ? cells.l["$" + slot] : locals[slot];
208
+ }
209
+
210
+ function storeLocal(slot, value) {
211
+ if (layout) cells.l["$" + slot] = value;
212
+ else locals[slot] = value;
213
+ return value;
214
+ }
215
+
216
+ function readConstant(index) {
217
+ var cell = constants[index];
218
+ if (cell && cell[0] === 0 && typeof cell[1] === "function") {
219
+ cell[1] = cell[1]();
220
+ cell[0] = 1;
221
+ }
222
+ return cell && cell[0] === 1 ? cell[1] : cell;
223
+ }
224
+
159
225
  function read() {
160
- return tokens[ip++];
226
+ if (ip < 0 || ip >= tokenCount) throw new Error("invalid virtual opcode");
227
+ var value = decodeAt(ip);
228
+ ip += 1;
229
+ return value;
161
230
  }
162
231
 
163
232
  function readUnsigned() {
@@ -181,7 +250,7 @@ function veilmark$numericVmRun(program, base, tokenCount, seed, tag, constants,
181
250
  var i = count;
182
251
  while (i > 0) {
183
252
  i -= 1;
184
- out[i] = stack.pop();
253
+ out[i] = pop();
185
254
  }
186
255
  return out;
187
256
  }
@@ -189,49 +258,51 @@ function veilmark$numericVmRun(program, base, tokenCount, seed, tag, constants,
189
258
  while (true) {
190
259
  var op = read();
191
260
  if (op === ops[0]) continue;
192
- if (op === ops[1]) { stack.push(undefined); continue; }
193
- if (op === ops[2]) { stack.push(null); continue; }
194
- if (op === ops[3]) { stack.push(true); continue; }
195
- if (op === ops[4]) { stack.push(false); continue; }
196
- if (op === ops[5]) { stack.push(readUnsigned()); continue; }
197
- if (op === ops[6]) { stack.push(constants[readUnsigned()]); continue; }
198
- if (op === ops[7]) { stack.push(frameArgs[readUnsigned()]); continue; }
199
- if (op === ops[8]) { stack.push(locals[readUnsigned()]); continue; }
200
- if (op === ops[9]) { locals[readUnsigned()] = stack.pop(); continue; }
201
- if (op === ops[10]) { stack.push(stack[stack.length - 1]); continue; }
202
- if (op === ops[11]) { stack.pop(); continue; }
203
- if (op === ops[12]) { var addB = stack.pop(); var addA = stack.pop(); stack.push(addA + addB); continue; }
204
- if (op === ops[13]) { var subB = stack.pop(); var subA = stack.pop(); stack.push(subA - subB); continue; }
205
- if (op === ops[14]) { var mulB = stack.pop(); var mulA = stack.pop(); stack.push(mulA * mulB); continue; }
206
- if (op === ops[15]) { var divB = stack.pop(); var divA = stack.pop(); stack.push(divA / divB); continue; }
207
- if (op === ops[16]) { var modB = stack.pop(); var modA = stack.pop(); stack.push(modA % modB); continue; }
208
- if (op === ops[17]) { var powB = stack.pop(); var powA = stack.pop(); stack.push(veilmark$numericVmPow(powA, powB)); continue; }
209
- if (op === ops[18]) { stack.push(-stack.pop()); continue; }
210
- if (op === ops[19]) { stack.push(!stack.pop()); continue; }
211
- if (op === ops[20]) { stack.push(~stack.pop()); continue; }
212
- if (op === ops[21]) { var eqB = stack.pop(); var eqA = stack.pop(); stack.push(eqA == eqB); continue; }
213
- if (op === ops[22]) { var neqB = stack.pop(); var neqA = stack.pop(); stack.push(neqA != neqB); continue; }
214
- if (op === ops[23]) { var seqB = stack.pop(); var seqA = stack.pop(); stack.push(seqA === seqB); continue; }
215
- if (op === ops[24]) { var sneB = stack.pop(); var sneA = stack.pop(); stack.push(sneA !== sneB); continue; }
216
- if (op === ops[25]) { var ltB = stack.pop(); var ltA = stack.pop(); stack.push(ltA < ltB); continue; }
217
- if (op === ops[26]) { var lteB = stack.pop(); var lteA = stack.pop(); stack.push(lteA <= lteB); continue; }
218
- if (op === ops[27]) { var gtB = stack.pop(); var gtA = stack.pop(); stack.push(gtA > gtB); continue; }
219
- if (op === ops[28]) { var gteB = stack.pop(); var gteA = stack.pop(); stack.push(gteA >= gteB); continue; }
261
+ if (op === ops[1]) { push(undefined); continue; }
262
+ if (op === ops[2]) { push(null); continue; }
263
+ if (op === ops[3]) { push(true); continue; }
264
+ if (op === ops[4]) { push(false); continue; }
265
+ if (op === ops[5]) { push(readUnsigned()); continue; }
266
+ if (op === ops[6]) { push(readConstant(readUnsigned())); continue; }
267
+ if (op === ops[7]) { push(frameArgs[readUnsigned()]); continue; }
268
+ if (op === ops[8]) { push(loadLocal(readUnsigned())); continue; }
269
+ if (op === ops[9]) { storeLocal(readUnsigned(), pop()); continue; }
270
+ if (op === ops[10]) { push(peek()); continue; }
271
+ if (op === ops[11]) { pop(); continue; }
272
+ if (op === ops[12]) { var addB = pop(); var addA = pop(); push(addA + addB); continue; }
273
+ if (op === ops[13]) { var subB = pop(); var subA = pop(); push(subA - subB); continue; }
274
+ if (op === ops[14]) { var mulB = pop(); var mulA = pop(); push(mulA * mulB); continue; }
275
+ if (op === ops[15]) { var divB = pop(); var divA = pop(); push(divA / divB); continue; }
276
+ if (op === ops[16]) { var modB = pop(); var modA = pop(); push(modA % modB); continue; }
277
+ if (op === ops[17]) { var powB = pop(); var powA = pop(); push(veilmark$numericVmPow(powA, powB)); continue; }
278
+ if (op === ops[18]) { push(-pop()); continue; }
279
+ if (op === ops[19]) { push(!pop()); continue; }
280
+ if (op === ops[20]) { push(~pop()); continue; }
281
+ if (op === ops[21]) { var eqB = pop(); var eqA = pop(); push(eqA == eqB); continue; }
282
+ if (op === ops[22]) { var neqB = pop(); var neqA = pop(); push(neqA != neqB); continue; }
283
+ if (op === ops[23]) { var seqB = pop(); var seqA = pop(); push(seqA === seqB); continue; }
284
+ if (op === ops[24]) { var sneB = pop(); var sneA = pop(); push(sneA !== sneB); continue; }
285
+ if (op === ops[25]) { var ltB = pop(); var ltA = pop(); push(ltA < ltB); continue; }
286
+ if (op === ops[26]) { var lteB = pop(); var lteA = pop(); push(lteA <= lteB); continue; }
287
+ if (op === ops[27]) { var gtB = pop(); var gtA = pop(); push(gtA > gtB); continue; }
288
+ if (op === ops[28]) { var gteB = pop(); var gteA = pop(); push(gteA >= gteB); continue; }
220
289
  if (op === ops[29]) { var jmp = readSigned(); ip += jmp; continue; }
221
- if (op === ops[30]) { var jf = readSigned(); if (!stack.pop()) ip += jf; continue; }
222
- if (op === ops[31]) { var jt = readSigned(); if (stack.pop()) ip += jt; continue; }
223
- if (op === ops[32]) { readUnsigned(); var argc = readUnsigned(); var ca = popArgs(argc); var fn = stack.pop(); stack.push(fn.apply(undefined, ca)); continue; }
224
- if (op === ops[33]) { readUnsigned(); var largc = readUnsigned(); var la = popArgs(largc); var lfn = constants[readUnsigned()]; stack.push(lfn.apply(undefined, la)); continue; }
225
- if (op === ops[34]) { var gpKey = stack.pop(); var gpObj = stack.pop(); stack.push(gpObj[gpKey]); continue; }
226
- if (op === ops[35]) { var spValue = stack.pop(); var spKey = stack.pop(); var spObj = stack.pop(); spObj[spKey] = spValue; stack.push(spValue); continue; }
227
- if (op === ops[36]) { var ac = readUnsigned(); var arr = new Array(ac); var ai = ac; while (ai > 0) { ai -= 1; arr[ai] = stack.pop(); } stack.push(arr); continue; }
228
- if (op === ops[37]) { var oc = readUnsigned(); var pairs = new Array(oc); var oi = oc; while (oi > 0) { oi -= 1; var ov = stack.pop(); var ok = stack.pop(); pairs[oi] = [ok, ov]; } var obj = {}; var pi = 0; while (pi < oc) { obj[pairs[pi][0]] = pairs[pi][1]; pi += 1; } stack.push(obj); continue; }
229
- if (op === ops[38]) return stack.pop();
230
- if (op === ops[39]) throw stack.pop();
231
- if (op === ops[40]) { stack.push(self); continue; }
232
- if (op === ops[41]) { stack.push(argsLike); continue; }
233
- if (op === ops[42]) { stack.push(typeof stack.pop()); continue; }
234
- if (op === ops[43]) { var mc = readUnsigned(); var ma = popArgs(mc); var mk = stack.pop(); var mo = stack.pop(); stack.push(mo[mk].apply(mo, ma)); continue; }
290
+ if (op === ops[30]) { var jf = readSigned(); if (!pop()) ip += jf; continue; }
291
+ if (op === ops[31]) { var jt = readSigned(); if (pop()) ip += jt; continue; }
292
+ if (op === ops[32]) { readUnsigned(); var argc = readUnsigned(); var ca = popArgs(argc); var fn = pop(); push(fn.apply(undefined, ca)); continue; }
293
+ if (op === ops[33]) { readUnsigned(); var largc = readUnsigned(); var la = popArgs(largc); var lfn = readConstant(readUnsigned()); push(lfn.apply(undefined, la)); continue; }
294
+ if (op === ops[34]) { var gpKey = pop(); var gpObj = pop(); push(gpObj[gpKey]); continue; }
295
+ if (op === ops[35]) { var spValue = pop(); var spKey = pop(); var spObj = pop(); spObj[spKey] = spValue; push(spValue); continue; }
296
+ if (op === ops[36]) { var ac = readUnsigned(); var arr = new Array(ac); var ai = ac; while (ai > 0) { ai -= 1; arr[ai] = pop(); } push(arr); continue; }
297
+ if (op === ops[37]) { var oc = readUnsigned(); var pairs = new Array(oc); var oi = oc; while (oi > 0) { oi -= 1; var ov = pop(); var ok = pop(); pairs[oi] = [ok, ov]; } var obj = {}; var pi = 0; while (pi < oc) { obj[pairs[pi][0]] = pairs[pi][1]; pi += 1; } push(obj); continue; }
298
+ if (op === ops[38]) return pop();
299
+ if (op === ops[39]) throw pop();
300
+ if (op === ops[40]) { push(self); continue; }
301
+ if (op === ops[41]) { push(argsLike); continue; }
302
+ if (op === ops[42]) { push(typeof pop()); continue; }
303
+ if (op === ops[43]) { var mc = readUnsigned(); var ma = popArgs(mc); var mk = pop(); var mo = pop(); push(mo[mk].apply(mo, ma)); continue; }
304
+ if (op === ops[44]) { var cgpKey = readConstant(readUnsigned()); var cgpObj = pop(); push(cgpObj[cgpKey]); continue; }
305
+ if (op === ops[45]) { storeLocal(readUnsigned(), pop()); continue; }
235
306
  throw new Error("invalid virtual opcode");
236
307
  }
237
308
  }
@@ -244,7 +315,7 @@ var OP_NAMES = [
244
315
  "STRICT_EQ", "STRICT_NEQ", "LT", "LTE", "GT", "GTE", "JMP", "JMP_FALSE",
245
316
  "JMP_TRUE", "CALL_EXT", "CALL_LOCAL", "GET_PROP", "SET_PROP", "MAKE_ARRAY",
246
317
  "MAKE_OBJECT", "RETURN", "THROW", "PUSH_THIS", "PUSH_ARGUMENTS", "TYPEOF",
247
- "CALL_METHOD"
318
+ "CALL_METHOD", "GET_CONST_PROP", "STORE_LOCAL_POP"
248
319
  ];
249
320
 
250
321
  var BASES = [257, 263, 269, 521, 1031, 4099, 65537];
@@ -258,6 +329,7 @@ function unary(operator, argument) { return { type: "UnaryExpression", operator:
258
329
  function member(object, property) { return { type: "MemberExpression", object: object, property: property, computed: true }; }
259
330
  function arrayExpression(values) { return { type: "ArrayExpression", elements: values }; }
260
331
  function returnStatement(argument) { return { type: "ReturnStatement", argument: argument }; }
332
+ function functionExpression(body) { return { type: "FunctionExpression", id: null, params: [], body: { type: "BlockStatement", body: body }, generator: false, expression: false, async: false }; }
261
333
  function functionName(node) { return node.id && node.id.name ? node.id.name : ""; }
262
334
 
263
335
  function hashSeed(seed) {
@@ -773,6 +845,29 @@ Compiler.prototype.instructionSize = function (instr, positions) {
773
845
  }
774
846
  return size;
775
847
  };
848
+ Compiler.prototype.isInstruction = function (instr, op) {
849
+ return instr && !instr.label && instr.op === op;
850
+ };
851
+ Compiler.prototype.fuseSuperinstructions = function () {
852
+ var out = [];
853
+ for (var i = 0; i < this.instructions.length; i += 1) {
854
+ var one = this.instructions[i];
855
+ var two = this.instructions[i + 1];
856
+ var three = this.instructions[i + 2];
857
+ if (this.isInstruction(one, "PUSH_CONST") && this.isInstruction(two, "GET_PROP")) {
858
+ out.push({ op: "GET_CONST_PROP", args: [one.args[0]] });
859
+ i += 1;
860
+ continue;
861
+ }
862
+ if (this.isInstruction(one, "DUP") && this.isInstruction(two, "STORE_LOCAL") && this.isInstruction(three, "POP")) {
863
+ out.push({ op: "STORE_LOCAL_POP", args: [two.args[0]] });
864
+ i += 2;
865
+ continue;
866
+ }
867
+ out.push(one);
868
+ }
869
+ this.instructions = out;
870
+ };
776
871
  Compiler.prototype.assemble = function () {
777
872
  var positions = new Map();
778
873
  var stable = false;
@@ -836,14 +931,21 @@ Compiler.prototype.constantExpression = function (constant) {
836
931
  if (constant.kind === "undefined") return { type: "UnaryExpression", operator: "void", prefix: true, argument: literal(0) };
837
932
  throw new Error("unsupported constant " + constant.kind);
838
933
  };
934
+ Compiler.prototype.constantCellExpression = function (constant) {
935
+ return arrayExpression([
936
+ literal(0),
937
+ functionExpression([ returnStatement(this.constantExpression(constant)) ])
938
+ ]);
939
+ };
839
940
  Compiler.prototype.finish = function () {
941
+ this.fuseSuperinstructions();
840
942
  var tokens = this.assemble();
841
943
  var encrypted = encryptedStream(tokens, this.dialect.base, this.dialect.seed);
842
944
  var opValues = OP_NAMES.map(name => this.dialect.opcodes[name]);
843
945
  var record = {
844
946
  base: this.dialect.base,
845
947
  blob: packTokens(encrypted.encrypted, this.dialect.base),
846
- constants: this.constants.map(this.constantExpression.bind(this)),
948
+ constants: this.constants.map(this.constantCellExpression.bind(this)),
847
949
  opValues: opValues.map(literal),
848
950
  seed: this.dialect.seed,
849
951
  tag: encrypted.tag,
@@ -9,6 +9,21 @@ var ESUtils = require("../esutils");
9
9
  var traverser = require("../traverser");
10
10
  var utils = require("../utils");
11
11
 
12
+ function isClassMethodFunction(stack) {
13
+ return stack.some(frame => frame.node.type == "MethodDefinition" || frame.node.type == "ClassBody");
14
+ }
15
+
16
+ function isClassMethodScope(scope) {
17
+ var node = scope && scope.block;
18
+ while (node) {
19
+ if (node.type == "MethodDefinition" || node.type == "ClassBody") {
20
+ return true;
21
+ }
22
+ node = node.veilmark$parent;
23
+ }
24
+ return false;
25
+ }
26
+
12
27
  module.exports = class Scopes {
13
28
 
14
29
  constructor (logger) {
@@ -33,6 +48,9 @@ module.exports = class Scopes {
33
48
  var scopes = scopeManager.acquireAll(ast);
34
49
  var rngAlpha = new utils.UniqueRandomAlpha(3);
35
50
  scopeManager.scopes.forEach(scope => {
51
+ if (!this.esutils.canInsertIntoScope(scope) || isClassMethodScope(scope)) {
52
+ return;
53
+ }
36
54
  var scopeVarName = `$$scope$${rngAlpha.get()}`;
37
55
 
38
56
  var counter = 0;
@@ -132,6 +150,9 @@ module.exports = class Scopes {
132
150
  });
133
151
  });
134
152
  } else if (def.type == "FunctionName") {
153
+ if (def.node.type == "FunctionExpression") {
154
+ return;
155
+ }
135
156
  variable.references.forEach(reference => {
136
157
  this.esutils.replaceNode(scope.block, reference.identifier, {
137
158
  type: "CallExpression",
@@ -150,6 +171,10 @@ module.exports = class Scopes {
150
171
  if (scope.block == node) {
151
172
  return node;
152
173
  }
174
+
175
+ if (isClassMethodFunction(stack)) {
176
+ return node;
177
+ }
153
178
 
154
179
  if (node.type.indexOf("Function") == 0) {
155
180
  node.params.unshift({
@@ -9,6 +9,74 @@ var ESUtils = require("../esutils");
9
9
  var traverser = require("../traverser");
10
10
  var utils = require("../utils");
11
11
 
12
+ function isReferenceIdentifier(node, stack) {
13
+ var parentFrame = stack[1];
14
+ if (!parentFrame) {
15
+ return true;
16
+ }
17
+
18
+ var parent = parentFrame.node;
19
+ var key = parentFrame.key;
20
+
21
+ if ((parent.type == "FunctionDeclaration" || parent.type == "FunctionExpression") && (key == "id" || key == "params")) {
22
+ return false;
23
+ }
24
+ if ((parent.type == "ClassDeclaration" || parent.type == "ClassExpression") && key == "id") {
25
+ return false;
26
+ }
27
+ if (parent.type == "VariableDeclarator" && key == "id") {
28
+ return false;
29
+ }
30
+ if (parent.type == "CatchClause" && key == "param") {
31
+ return false;
32
+ }
33
+ if ((parent.type == "MemberExpression" || parent.type == "Property") && key == "property" && parent.computed === false) {
34
+ return false;
35
+ }
36
+ if (parent.type == "Property" && key == "key" && parent.computed === false) {
37
+ return false;
38
+ }
39
+ if ((parent.type == "MethodDefinition" || parent.type == "PropertyDefinition" || parent.type == "FieldDefinition") && key == "key" && parent.computed === false) {
40
+ return false;
41
+ }
42
+ if ((parent.type == "LabeledStatement" || parent.type == "BreakStatement" || parent.type == "ContinueStatement") && key == "label") {
43
+ return false;
44
+ }
45
+
46
+ return true;
47
+ }
48
+
49
+ function functionExpressionUsesOwnName(node) {
50
+ assert.equal(node.type, "FunctionExpression");
51
+
52
+ if (!node.id) {
53
+ return false;
54
+ }
55
+
56
+ var name = node.id.name;
57
+ var used = false;
58
+
59
+ traverser.traverse(node.body, [], (child, stack) => {
60
+ if (child.type == "Identifier" && child.name == name && isReferenceIdentifier(child, stack)) {
61
+ used = true;
62
+ }
63
+ return child;
64
+ });
65
+
66
+ return used;
67
+ }
68
+
69
+ function isClassMethodScope(scope) {
70
+ var node = scope && scope.block;
71
+ while (node) {
72
+ if (node.type == "MethodDefinition" || node.type == "ClassBody") {
73
+ return true;
74
+ }
75
+ node = node.veilmark$parent;
76
+ }
77
+ return false;
78
+ }
79
+
12
80
  module.exports = class Variables {
13
81
 
14
82
  constructor (logger) {
@@ -25,7 +93,7 @@ module.exports = class Variables {
25
93
  */
26
94
  removeFunctionExpressionIds (ast) {
27
95
  return traverser.traverse(ast, [], (node, stack) => {
28
- if (node.type == "FunctionExpression" && node.id) {
96
+ if (node.type == "FunctionExpression" && node.id && !functionExpressionUsesOwnName(node)) {
29
97
  node.id = null;
30
98
  }
31
99
  return node;
@@ -46,6 +114,9 @@ module.exports = class Variables {
46
114
  this.esutils.setParentsRecursive(ast);
47
115
 
48
116
  scopeManager.scopes.forEach(scope => {
117
+ if (!this.esutils.canInsertIntoScope(scope) || isClassMethodScope(scope)) {
118
+ return;
119
+ }
49
120
  scope.variables.forEach(variable => {
50
121
  variable.defs.forEach(def => {
51
122
  if (def.type == "FunctionName") {
@@ -68,7 +139,10 @@ module.exports = class Variables {
68
139
  init: {
69
140
  type: "FunctionExpression",
70
141
  params: def.node.params,
71
- body: def.node.body
142
+ body: def.node.body,
143
+ generator: def.node.generator === true,
144
+ expression: def.node.expression === true,
145
+ async: def.node.async === true
72
146
  }
73
147
  }
74
148
  ]
@@ -90,6 +164,9 @@ module.exports = class Variables {
90
164
  */
91
165
  obfuscateIdentifiers (ast, scopeManager) {
92
166
  scopeManager.scopes.forEach(scope => {
167
+ if (isClassMethodScope(scope)) {
168
+ return;
169
+ }
93
170
  if (scope.isStatic()) {
94
171
  scope.variables.sort((a, b) => {
95
172
  if (a.tainted) {
@@ -104,6 +181,10 @@ module.exports = class Variables {
104
181
  for (let variable of scope.variables) {
105
182
  var name = "$$var$" + utils.hash(variable) + "$" + variable.name;
106
183
 
184
+ if (variable.defs.some(def => def.type == "ClassName")) {
185
+ continue;
186
+ }
187
+
107
188
  if (variable.tainted) {
108
189
  continue;
109
190
  }
@@ -155,6 +236,9 @@ module.exports = class Variables {
155
236
  var rng = new utils.UniqueRandomAlpha(3);
156
237
 
157
238
  scopeManager.scopes.forEach(scope => {
239
+ if (!this.esutils.canInsertIntoScope(scope) || isClassMethodScope(scope)) {
240
+ return;
241
+ }
158
242
  scope.variables.forEach(variable => {
159
243
  variable.defs.forEach(def => {
160
244
  if (def.type == "Parameter") {
package/traverser.js CHANGED
@@ -7,6 +7,12 @@ var estraverse = require("estraverse");
7
7
  var estest = require("./estest");
8
8
  var utils = require("./utils");
9
9
 
10
+ var VISITOR_KEYS = Object.assign({}, estraverse.VisitorKeys, {
11
+ ChainExpression: [ "expression" ],
12
+ PropertyDefinition: [ "key", "value" ],
13
+ FieldDefinition: [ "key", "value" ]
14
+ });
15
+
10
16
  // Depth-first
11
17
  exports.traverse = function (node, stack, processor) {
12
18
  assert.ok(estest.isNode(node));
@@ -57,7 +63,7 @@ exports.visitChildren = function (node, processor) {
57
63
  assert.ok(estest.isNode(node));
58
64
  assert.equal(typeof processor, "function");
59
65
 
60
- var keys = estraverse.VisitorKeys[node.type] || [];
66
+ var keys = VISITOR_KEYS[node.type] || [];
61
67
  keys.forEach(key => {
62
68
  if (Array.isArray(node[key])) {
63
69
  node[key] = node[key].map(x => {
@@ -80,7 +86,7 @@ exports.visitChildrenEx = function (node, processor) {
80
86
  assert.ok(estest.isNode(node));
81
87
  assert.equal(typeof processor, "function");
82
88
 
83
- var keys = estraverse.VisitorKeys[node.type] || [];
89
+ var keys = VISITOR_KEYS[node.type] || [];
84
90
  keys.forEach(key => {
85
91
  if (Array.isArray(node[key])) {
86
92
  let i = node[key].length;