0

Trying to use a complex decryption logic into own script but code is ES6 which I have no idea about.

    const parseDecsig = data => {
        try {
            if (data.startsWith('var script')) {
                // they inject the script via script tag
                const obj = {}
                const document = { createElement: () => obj, head: { appendChild: () => {} } }
                eval(data)
                data = obj.innerHTML
            }
            const fnnameresult = /yt\.akamaized\.net.*encodeURIComponent\((\w+)/.exec(data)
            const fnname = fnnameresult[1]
            const _argnamefnbodyresult = new RegExp(fnname + '=function\\((.+?)\\){(.+?)}').exec(data)
            const [_, argname, fnbody] = _argnamefnbodyresult
            const helpernameresult = /;(.+?)\..+?\(/.exec(fnbody)
            const helpername = helpernameresult[1]
            const helperresult = new RegExp('var ' + helpername + '={[\\s\\S]+?};').exec(data)
            const helper = helperresult[0]
            logger.log(`parsedecsig result: %s=>{%s\n%s}`, argname, helper, fnbody)
            return new Function([argname], helper + '\n' + fnbody)
        } catch (e) {
            logger.error('parsedecsig error: %o', e)
            logger.info('script content: %s', data)
            logger.info(
                'If you encounter this error, please copy the full "script content" to https://pastebin.com/ for me.'
            )
        }
    }

What would be the Pre ES6 equivalent code of above?

WannabeCoder
  • 57
  • 1
  • 1
  • 12

2 Answers2

3

One option is to use Babel. Plug in your code, and you get:

"use strict";

function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }

function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); }

function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }

function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }

var parseDecsig = function parseDecsig(data) {
  try {
    if (data.startsWith('var script')) {
      // they inject the script via script tag
      var obj = {};
      var document = {
        createElement: function createElement() {
          return obj;
        },
        head: {
          appendChild: function appendChild() {}
        }
      };
      eval(data);
      data = obj.innerHTML;
    }

    var fnnameresult = /yt\.akamaized\.net.*encodeURIComponent\((\w+)/.exec(data);
    var fnname = fnnameresult[1];

    var _argnamefnbodyresult = new RegExp(fnname + '=function\\((.+?)\\){(.+?)}').exec(data);

    var _argnamefnbodyresult2 = _slicedToArray(_argnamefnbodyresult, 3),
        _ = _argnamefnbodyresult2[0],
        argname = _argnamefnbodyresult2[1],
        fnbody = _argnamefnbodyresult2[2];

    var helpernameresult = /;(.+?)\..+?\(/.exec(fnbody);
    var helpername = helpernameresult[1];
    var helperresult = new RegExp('var ' + helpername + '={[\\s\\S]+?};').exec(data);
    var helper = helperresult[0];
    logger.log("parsedecsig result: %s=>{%s\n%s}", argname, helper, fnbody);
    return new Function([argname], helper + '\n' + fnbody);
  } catch (e) {
    logger.error('parsedecsig error: %o', e);
    logger.info('script content: %s', data);
    logger.info('If you encounter this error, please copy the full "script content" to https://pastebin.com/ for me.');
  }
};

Looks ugly, but that shouldn't matter - it'll work, and can be done automatically.

You also have one ES6+ method you're using, String.prototype.startsWith, which isn't syntax, so it doesn't transpile - add a polyfill for it which runs before the other code.

if (!String.prototype.startsWith) {
    Object.defineProperty(String.prototype, 'startsWith', {
        value: function(search, pos) {
            pos = !pos || pos < 0 ? 0 : +pos;
            return this.substring(pos, pos + search.length) === search;
        }
    });
}

Then, the code should be fully ES5 compliant, and should run even on obsolete browsers like IE11.

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • I want to use this in a web-extension userscript, should I just stick this in there? Doe't using `"use strict";` mess up my other code? – WannabeCoder Jun 20 '19 at 04:57
  • If the `use strict` creates problems with other parts of the code (which, if the code is proper, it shouldn't), you can use the function form of it - put the whole transpiled code inside an IIFE, with `use strict` at the top of the IIFE, so that only what is contained in it is executed in strict mode. – CertainPerformance Jun 20 '19 at 04:59
  • Sorry but I have no idea what this means. – WannabeCoder Jun 20 '19 at 05:07
  • See https://stackoverflow.com/questions/8228281/what-is-the-function-construct-in-javascript - wrap the transpiled code in a function which runs immediately – CertainPerformance Jun 20 '19 at 05:08
  • OK, great, how can I call this `parseDecsig` from my existing code (pre ES6) and send back the results? – WannabeCoder Jun 20 '19 at 12:43
2

The new features of ES6 are listed at ECMAScript 6 - ECMAScript 2015 or ECMAScript 2015 support in Mozilla and by removing them, the code will become pre-ES6. For example:

  • change const or let to var
  • change Arrow function to normal function (there is a scope change but in majority of cases that may not cause any issues)
  • change startsWith with indexOf
  • change Destructuring assignment

Here is a QUICK rework of the code to show you the process. I didn't check it thoroughly.

var parseDecsig = funnction(data) {
    try {
        if (data.indexOf('var script') !== -1) {
            // they inject the script via script tag
            var obj = {}
            var document = { createElement: function(){ obj }, head: { appendChild: function(){} } }
            eval(data)
            data = obj.innerHTML
        }
        var fnnameresult = /yt\.akamaized\.net.*encodeURIComponent\((\w+)/.exec(data)
        var fnname = fnnameresult[1]
        var _argnamefnbodyresult = new RegExp(fnname + '=function\\((.+?)\\){(.+?)}').exec(data)
        var _ = _argnamefnbodyresult[0]
        var argname = _argnamefnbodyresult[1]
        var fnbody = _argnamefnbodyresult[2]
        var helpernameresult = /;(.+?)\..+?\(/.exec(fnbody)
        var helpername = helpernameresult[1]
        var helperresult = new RegExp('var ' + helpername + '={[\\s\\S]+?};').exec(data)
        var helper = helperresult[0]
        logger.log(`parsedecsig result: %s=>{%s\n%s}`, argname, helper, fnbody)
        return new Function([argname], helper + '\n' + fnbody)
    } catch (e) {
        logger.error('parsedecsig error: %o', e)
        logger.info('script content: %s', data)
        logger.info(
            'If you encounter this error, please copy the full "script content" to https://pastebin.com/ for me.'
        )
    }
}
erosman
  • 7,094
  • 7
  • 27
  • 46
  • And I can call this function with data variable like this, `parseDecsig (data)` from my userscript right? – WannabeCoder Jun 24 '19 at 09:38
  • @WannabeCoder Nothing has changed about what the code does and it should work as it worked before. It has defined the function `parseDecsig` and you can call it by `parseDecsig(data)`. If I have missed anything and you get errors, let me know and I will recheck the code. – erosman Jun 24 '19 at 14:52
  • @erosman When supplied with same script data this function results in error - `parsedecsig error: TypeError: "fnnameresult is null"` in my script but the original works fine!!! Are we missing something here? – iLearn2016 Jun 28 '19 at 12:58
  • @iLearn2016 That error relates to the RegEx of `data`. You need to check what is passed to `parseDecsig(data)` – erosman Jun 28 '19 at 17:23
  • That worked after a few tweaks, but now stuck at this - https://imgur.com/a/0TfkSlC , the console log shows correct extreaction but the return value says `` at calling function. – iLearn2016 Jun 29 '19 at 14:44
  • @iLearn2016 The return value is a function and can not be logged to console.Anyway, that is not an issue with ES6 to ES5 conversion. – erosman Jun 29 '19 at 15:10
  • @erosman Understood, the ES6 script calls the same result function like this `const decsig = await xf.get(e.data.path).text(parseDecsig)` (using xfetch) when I try this `decsigfn(unsig)` in my script it results in `decsigfn` not defined? What am I missing here? – iLearn2016 Jun 29 '19 at 15:38
  • @iLearn2016 await belongs to ES2017 (ES8) and not supported in ES5 – erosman Jun 29 '19 at 18:56
  • @erosman Then what solution do we have to execute this function and get the results :( – iLearn2016 Jun 30 '19 at 05:06
  • @iLearn2016 That is a different question. You need to open a new topic for it. – erosman Jun 30 '19 at 13:33