| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349 | "use strict";const acorn = require("acorn");const escodegen = require("@javascript-obfuscator/escodegen");const vm = require("vm");const fs = require("fs");const path = require("path");const PDFJS_PREPROCESSOR_NAME = "PDFJSDev";const ROOT_PREFIX = "$ROOT/";const ACORN_ECMA_VERSION = 2022;function isLiteral(obj, value) {  return obj.type === "Literal" && obj.value === value;}function isPDFJSPreprocessor(obj) {  return obj.type === "Identifier" && obj.name === PDFJS_PREPROCESSOR_NAME;}function evalWithDefines(code, defines, loc) {  if (!code || !code.trim()) {    throw new Error("No JavaScript expression given");  }  return vm.runInNewContext(code, defines, { displayErrors: false });}function handlePreprocessorAction(ctx, actionName, args, loc) {  try {    let arg;    switch (actionName) {      case "test":        arg = args[0];        if (!arg || arg.type !== "Literal" || typeof arg.value !== "string") {          throw new Error("No code for testing is given");        }        const isTrue = !!evalWithDefines(arg.value, ctx.defines);        return { type: "Literal", value: isTrue, loc };      case "eval":        arg = args[0];        if (!arg || arg.type !== "Literal" || typeof arg.value !== "string") {          throw new Error("No code for eval is given");        }        const result = evalWithDefines(arg.value, ctx.defines);        if (          typeof result === "boolean" ||          typeof result === "string" ||          typeof result === "number"        ) {          return { type: "Literal", value: result, loc };        }        if (typeof result === "object") {          const parsedObj = acorn.parse("(" + JSON.stringify(result) + ")", {            ecmaVersion: ACORN_ECMA_VERSION,          });          parsedObj.body[0].expression.loc = loc;          return parsedObj.body[0].expression;        }        break;      case "json":        arg = args[0];        if (!arg || arg.type !== "Literal" || typeof arg.value !== "string") {          throw new Error("Path to JSON is not provided");        }        let jsonPath = arg.value;        if (jsonPath.indexOf(ROOT_PREFIX) === 0) {          jsonPath = path.join(            ctx.rootPath,            jsonPath.substring(ROOT_PREFIX.length)          );        }        const jsonContent = fs.readFileSync(jsonPath).toString();        const parsedJSON = acorn.parse("(" + jsonContent + ")", {          ecmaVersion: ACORN_ECMA_VERSION,        });        parsedJSON.body[0].expression.loc = loc;        return parsedJSON.body[0].expression;    }    throw new Error("Unsupported action");  } catch (e) {    throw new Error(      "Could not process " +        PDFJS_PREPROCESSOR_NAME +        "." +        actionName +        " at " +        JSON.stringify(loc) +        "\n" +        e.name +        ": " +        e.message    );  }}function postprocessNode(ctx, node) {  switch (node.type) {    case "ExportNamedDeclaration":    case "ImportDeclaration":      if (        node.source &&        node.source.type === "Literal" &&        ctx.map &&        ctx.map[node.source.value]      ) {        const newValue = ctx.map[node.source.value];        node.source.value = node.source.raw = newValue;      }      break;    case "IfStatement":      if (isLiteral(node.test, true)) {        // if (true) stmt1; => stmt1        return node.consequent;      } else if (isLiteral(node.test, false)) {        // if (false) stmt1; else stmt2; => stmt2        return node.alternate || { type: "EmptyStatement", loc: node.loc };      }      break;    case "ConditionalExpression":      if (isLiteral(node.test, true)) {        // true ? stmt1 : stmt2 => stmt1        return node.consequent;      } else if (isLiteral(node.test, false)) {        // false ? stmt1 : stmt2 => stmt2        return node.alternate;      }      break;    case "UnaryExpression":      if (node.operator === "typeof" && isPDFJSPreprocessor(node.argument)) {        // typeof PDFJSDev => 'object'        return { type: "Literal", value: "object", loc: node.loc };      }      if (        node.operator === "!" &&        node.argument.type === "Literal" &&        typeof node.argument.value === "boolean"      ) {        // !true => false,  !false => true        return { type: "Literal", value: !node.argument.value, loc: node.loc };      }      break;    case "LogicalExpression":      switch (node.operator) {        case "&&":          if (isLiteral(node.left, true)) {            return node.right;          }          if (isLiteral(node.left, false)) {            return node.left;          }          break;        case "||":          if (isLiteral(node.left, true)) {            return node.left;          }          if (isLiteral(node.left, false)) {            return node.right;          }          break;      }      break;    case "BinaryExpression":      switch (node.operator) {        case "==":        case "===":        case "!=":        case "!==":          if (            node.left.type === "Literal" &&            node.right.type === "Literal" &&            typeof node.left.value === typeof node.right.value          ) {            // folding two literals == and != check            switch (typeof node.left.value) {              case "string":              case "boolean":              case "number":                const equal = node.left.value === node.right.value;                return {                  type: "Literal",                  value: (node.operator[0] === "=") === equal,                  loc: node.loc,                };            }          }          break;      }      break;    case "CallExpression":      if (        node.callee.type === "MemberExpression" &&        isPDFJSPreprocessor(node.callee.object) &&        node.callee.property.type === "Identifier"      ) {        // PDFJSDev.xxxx(arg1, arg2, ...) => transform        const action = node.callee.property.name;        return handlePreprocessorAction(ctx, action, node.arguments, node.loc);      }      // require('string')      if (        node.callee.type === "Identifier" &&        node.callee.name === "require" &&        node.arguments.length === 1 &&        node.arguments[0].type === "Literal" &&        ctx.map &&        ctx.map[node.arguments[0].value]      ) {        const requireName = node.arguments[0];        requireName.value = requireName.raw = ctx.map[requireName.value];      }      break;    case "BlockStatement":      let subExpressionIndex = 0;      while (subExpressionIndex < node.body.length) {        switch (node.body[subExpressionIndex].type) {          case "EmptyStatement":            // Removing empty statements from the blocks.            node.body.splice(subExpressionIndex, 1);            continue;          case "BlockStatement":            // Block statements inside a block are moved to the parent one.            const subChildren = node.body[subExpressionIndex].body;            Array.prototype.splice.apply(node.body, [              subExpressionIndex,              1,              ...subChildren,            ]);            subExpressionIndex += Math.max(subChildren.length - 1, 0);            continue;          case "ReturnStatement":          case "ThrowStatement":            // Removing dead code after return or throw.            node.body.splice(              subExpressionIndex + 1,              node.body.length - subExpressionIndex - 1            );            break;        }        subExpressionIndex++;      }      break;    case "FunctionDeclaration":    case "FunctionExpression":      const block = node.body;      if (        block.body.length > 0 &&        block.body[block.body.length - 1].type === "ReturnStatement" &&        !block.body[block.body.length - 1].argument      ) {        // Function body ends with return without arg -- removing it.        block.body.pop();      }      break;  }  return node;}function fixComments(ctx, node) {  if (!ctx.saveComments) {    return;  }  // Fixes double comments in the escodegen output.  delete node.trailingComments;  // Removes ESLint and other service comments.  if (node.leadingComments) {    const CopyrightRegExp = /\bcopyright\b/i;    const BlockCommentRegExp = /^\s*(globals|eslint|falls through)\b/;    const LineCommentRegExp = /^\s*eslint\b/;    let i = 0;    while (i < node.leadingComments.length) {      const type = node.leadingComments[i].type;      const value = node.leadingComments[i].value;      if (ctx.saveComments === "copyright") {        // Remove all comments, except Copyright notices and License headers.        if (!(type === "Block" && CopyrightRegExp.test(value))) {          node.leadingComments.splice(i, 1);          continue;        }      } else if (        (type === "Block" && BlockCommentRegExp.test(value)) ||        (type === "Line" && LineCommentRegExp.test(value))      ) {        node.leadingComments.splice(i, 1);        continue;      }      i++;    }  }}function traverseTree(ctx, node) {  // generic node processing  for (const i in node) {    const child = node[i];    if (typeof child === "object" && child !== null && child.type) {      const result = traverseTree(ctx, child);      if (result !== child) {        node[i] = result;      }    } else if (Array.isArray(child)) {      child.forEach(function (childItem, index) {        if (          typeof childItem === "object" &&          childItem !== null &&          childItem.type        ) {          const result = traverseTree(ctx, childItem);          if (result !== childItem) {            child[index] = result;          }        }      });    }  }  node = postprocessNode(ctx, node) || node;  fixComments(ctx, node);  return node;}function preprocessPDFJSCode(ctx, code) {  const format = ctx.format || {    indent: {      style: " ",    },  };  const parseOptions = {    ecmaVersion: ACORN_ECMA_VERSION,    locations: true,    sourceFile: ctx.sourceFile,    sourceType: "module",  };  const codegenOptions = {    format,    parse(input) {      return acorn.parse(input, { ecmaVersion: ACORN_ECMA_VERSION });    },    sourceMap: ctx.sourceMap,    sourceMapWithCode: ctx.sourceMap,  };  const syntax = acorn.parse(code, parseOptions);  traverseTree(ctx, syntax);  return escodegen.generate(syntax, codegenOptions);}exports.preprocessPDFJSCode = preprocessPDFJSCode;
 |