UNPKG

quamvoluptatem

Version:
254 lines (226 loc) 6.4 kB
import { ok } from "assert"; import { ObfuscateOrder } from "../../order"; import Template from "../../templates/template"; import { isDirective } from "../../util/compare"; import { ArrayExpression, CallExpression, FunctionDeclaration, Identifier, Literal, MemberExpression, Node, ReturnStatement, VariableDeclaration, VariableDeclarator, } from "../../util/gen"; import { append, prepend } from "../../util/insert"; import Transform from "../transform"; /* eslint-disable @typescript-eslint/no-unused-expressions */ function encode_ascii85(a) { var b, c, d, e, f, g, h, i, j, k; // @ts-ignore for ( // @ts-ignore !/[^\x00-\xFF]/.test(a), b = "\x00\x00\x00\x00".slice(a.length % 4 || 4), a += b, c = [], d = 0, e = a.length; e > d; d += 4 ) (f = (a.charCodeAt(d) << 24) + (a.charCodeAt(d + 1) << 16) + (a.charCodeAt(d + 2) << 8) + a.charCodeAt(d + 3)), 0 !== f ? ((k = f % 85), (f = (f - k) / 85), (j = f % 85), (f = (f - j) / 85), (i = f % 85), (f = (f - i) / 85), (h = f % 85), (f = (f - h) / 85), (g = f % 85), c.push(g + 33, h + 33, i + 33, j + 33, k + 33)) : c.push(122); return ( (function (a, b) { for (var c = b; c > 0; c--) a.pop(); })(c, b.length), "<~" + String.fromCharCode.apply(String, c) + "~>" ); } function decode_ascii85(a) { var c, d, e, f, g, h = String, l = "length", w = 255, x = "charCodeAt", y = "slice", z = "replace"; for ( "<~" === a[y](0, 2) && "~>" === a[y](-2), a = a[y](2, -2)[z](/s/g, "")[z]("z", "!!!!!"), c = "uuuuu"[y](a[l] % 5 || 5), a += c, e = [], f = 0, g = a[l]; g > f; f += 5 ) (d = 52200625 * (a[x](f) - 33) + 614125 * (a[x](f + 1) - 33) + 7225 * (a[x](f + 2) - 33) + 85 * (a[x](f + 3) - 33) + (a[x](f + 4) - 33)), e.push(w & (d >> 24), w & (d >> 16), w & (d >> 8), w & d); return ( (function (a, b) { for (var c = b; c > 0; c--) a.pop(); })(e, c[l]), h.fromCharCode.apply(h, e) ); } var Ascii85Template = Template(` function {name}(a) { var c, d, e, f, g, h = String, l = "length", w = 255, x = "charCodeAt", y = "slice", z = "replace"; for ("<~" === a[y](0, 2) && "~>" === a[y](-2), a = a[y](2, -2)[z](/\s/g, "")[z]("z", "!!!!!"), c = "uuuuu"[y](a[l] % 5 || 5), a += c, e = [], f = 0, g = a[l]; g > f; f += 5) d = 52200625 * (a[x](f) - 33) + 614125 * (a[x](f + 1) - 33) + 7225 * (a[x](f + 2) - 33) + 85 * (a[x](f + 3) - 33) + (a[x](f + 4) - 33), e.push(w & d >> 24, w & d >> 16, w & d >> 8, w & d); return function(a, b) { for (var c = b; c > 0; c--) a.pop(); }(e, c[l]), h.fromCharCode.apply(h, e); } `); export function isModuleSource(object: Node, parents: Node[]) { if (!parents[0]) { return false; } if (parents[0].type == "ImportDeclaration" && parents[0].source == object) { return true; } if (parents[0].type == "ImportExpression" && parents[0].source == object) { return true; } if ( parents[1] && parents[1].type == "CallExpression" && parents[1].arguments[0] === object && parents[1].callee.type == "Identifier" ) { if ( parents[1].callee.name == "require" || parents[1].callee.name == "import" ) { return true; } } return false; } export default class StringConcealing extends Transform { arrayExpression: Node; set: Set<string>; index: { [str: string]: number }; getterName = this.getPlaceholder(); arrayName = this.getPlaceholder(); decodeFn = this.getPlaceholder(); decodeNode: Node; constructor(o) { super(o, ObfuscateOrder.StringConcealing); this.set = new Set(); this.index = Object.create(null); } match(object, parents) { return ( object.type == "Program" || (object.type == "Literal" && typeof object.value === "string" && !isModuleSource(object, parents) && !isDirective(object, parents)) //&& /*!parents.find((x) => x.$dispatcherSkip)*/ ); } transform(object, parents) { if (object.type == "Program") { this.arrayExpression = ArrayExpression([]); return () => { var cacheName = this.getPlaceholder(); append( object, Template(` function ${this.getterName}(x){ return ${cacheName}[x] || (${cacheName}[x] = ${this.decodeFn}(${this.arrayName}[x]), ${cacheName}[x]) } `).single() ); prepend( object, VariableDeclaration([ VariableDeclarator(cacheName, ArrayExpression([])), VariableDeclarator(this.arrayName, this.arrayExpression), ]) ); append( object, (this.decodeNode = Ascii85Template.single({ name: this.decodeFn, })) ); }; } return () => { // No string concealing in the decoder function if (parents.find((x) => x == this.decodeNode)) { return; } // Empty strings are discarded if (!object.value) { return; } // The decode function must return correct result if (decode_ascii85(encode_ascii85(object.value)) != object.value) { this.warn(object.value.slice(0, 100)); return; } // Fix 1. weird undefined error if (object.value && object.value.length > 0) { var index = -1; if (!this.set.has(object.value)) { this.arrayExpression.elements.push( Literal(encode_ascii85(object.value)) ); index = this.arrayExpression.elements.length - 1; this.index[object.value] = index; } else { index = this.index[object.value]; ok(index); } ok(index != -1, "index == -1"); this.replace( object, CallExpression(Identifier(this.getterName), [Literal(index)]) ); // Fix 2. Make parent property key computed if ( parents[0] && parents[0].type == "Property" && parents[0].key == object ) { parents[0].computed = true; parents[0].shorthand = false; } } }; } }