def test_obfuscate_no_global_recursive(self):
        node = es5(
            dedent("""
        (function named(param1, param2) {
          param1 = param1 * param2 - param2;
          param2--;
          if (param2 < 0) {
            return named(param1, param2);
          }
          return param1;
        })();
        """).strip())

        self.assertEqual(
            dedent("""
        (function named(b, a) {
          b = b * a - a;
          a--;
          if (a < 0) {
            return named(b, a);
          }
          return b;
        })();
        """).lstrip(), ''.join(c.text for c in Unparser(rules=(
                default_rules,
                indent(indent_str='  '),
                obfuscate(obfuscate_globals=False),
            ))(node)))
    def test_obfuscate_try_catch_shadowed(self):
        node = es5(
            dedent("""
        var value = 1;
        try {
          console.log(value);
          throw Error("welp");
        }
        catch (value) {
          console.log(value);
        }
        """).strip())

        self.assertEqual(
            dedent("""
        var a = 1;
        try {
            console.log(a);
            throw Error("welp");
        }
        catch (a) {
            console.log(a);
        }
        """).lstrip(), ''.join(c.text for c in Unparser(rules=(
                default_rules,
                indent(indent_str='    '),
                obfuscate(obfuscate_globals=True),
            ))(node)))
    def test_no_resolve(self):
        # a simple test to show that an obfuscator without the initial
        # loading run executed (i.e. the one with the required handlers)
        # with the resolve added to the dispatcher will not crash, but
        # simply not have any effect.

        tree = es5(
            dedent("""
        (function() {
          var foo = 1;
          var bar = 2;
        })(this);
        """).strip())
        unparser = Unparser()
        obfuscator = Obfuscator()
        dispatcher = Dispatcher(
            unparser.definitions, token_handler_str_default, {
                Space: layout_handler_space_minimum,
                RequiredSpace: layout_handler_space_minimum,
                OpenBlock: layout_handler_openbrace,
                CloseBlock: layout_handler_closebrace,
                EndStatement: layout_handler_semicolon,
            }, {
                Resolve: obfuscator.resolve,
            })
        # see that the manually constructed minimum output works.
        self.assertEqual("(function(){var foo=1;var bar=2;})(this);",
                         ''.join(c.text for c in walk(dispatcher, tree)))
    def test_functions_in_lists(self):
        node = es5(
            dedent("""
        (function main(root) {
          root.exports = [
            (function(module, exports) {
              module.exports = {};
            }),
            (function(module, exports) {
              exports.fun = 1;
            }),
          ];
        })(this);
        """).strip())

        self.assertEqual(
            dedent("""
        (function main(a) {
          a.exports = [(function(a, b) {
            a.exports = {};
          }), (function(b, a) {
            a.fun = 1;
          })];
        })(this);
        """).lstrip(), ''.join(c.text for c in Unparser(rules=(
                default_rules,
                indent(indent_str='  '),
                obfuscate(),
            ))(node)))
    def test_obfuscate_try_catch_scope_inside_catch(self):
        node = es5(
            dedent("""
        var value = 100;
        (function() {
          var dummy = 0;
          console.log(value);
          value = 1;
          try {
            console.log(value);
            throw Error("welp");
          }
          catch (exc) {
            var value = 2;
            var welped = value;
            welped = 'welped';
            (function() {
              console.log(exc);
              console.log(value);
              console.log(welped);
            })();
          }
          value = 3;
        })();
        console.log(value);
        """).strip())

        # note that dummy -> c because exc is a local, not counted in
        # the priority at the parent scope.
        self.assertEqual(
            dedent("""
        var value = 100;
        (function() {
          var c = 0;
          console.log(a);
          a = 1;
          try {
            console.log(a);
            throw Error("welp");
          }
          catch (d) {
            var a = 2;
            var b = a;
            b = 'welped';
            (function() {
              console.log(d);
              console.log(a);
              console.log(b);
            })();
          }
          a = 3;
        })();
        console.log(value);
        """).lstrip(), ''.join(c.text for c in Unparser(rules=(
                default_rules,
                indent(indent_str='  '),
                obfuscate(),
            ))(node)))
    def test_obfuscate_globals(self):
        node = es5(
            dedent("""
        var a_global = 1;
        (function(a_param) {
          var a_local = 1;
          a_local = a_param;
          a_local = a_global;
        })();
        """).strip())

        self.assertEqual(
            dedent("""
        var a_global = 1;
        (function(b) {
            var a = 1;
            a = b;
            a = a_global;
        })();
        """).lstrip(), ''.join(c.text for c in Unparser(rules=(
                default_rules,
                indent(indent_str='    '),
                obfuscate(obfuscate_globals=False),
            ))(node)))

        self.assertEqual(
            dedent("""
        var a = 1;
        (function(c) {
            var b = 1;
            b = c;
            b = a;
        })();
        """).lstrip(), ''.join(c.text for c in Unparser(rules=(
                default_rules,
                indent(indent_str='    '),
                obfuscate(obfuscate_globals=True),
            ))(node)))
    def test_obfuscate_no_shadow_funcname_not_mapped(self):
        node = es5(
            dedent("""
        function a(arg) {
        }
        """).strip())

        self.assertEqual(
            dedent("""
        function a(b) {
        }
        """).lstrip(), ''.join(c.text for c in Unparser(rules=(
                default_rules,
                indent(indent_str='  '),
                obfuscate(obfuscate_globals=False, shadow_funcname=False),
            ))(node)))
    def test_multiple_reuse(self):
        tree = es5(
            dedent("""
        (function() {
          var foo = 1;
          var bar = 2;
          bar = 3;
        })(this);
        """).strip())
        obfuscator_unparser = Unparser(rules=(
            minimum_rules,
            obfuscate(),
        ))

        self.assertEqual(
            ''.join(c.text for c in obfuscator_unparser(tree)),
            ''.join(c.text for c in obfuscator_unparser(tree)),
        )
    def test_obfuscate_try_catch_vardeclare_inside_catch(self):
        node = es5(
            dedent("""
        var value = 100;
        (function() {
          console.log(value);
          value = 1;
          try {
            console.log(value);
            throw Error("welp");
          }
          catch (exc) {
            var value = 2;
            console.log(value);
          }
          value = 3;
        })();
        console.log(value);
        """).strip())

        self.assertEqual(
            dedent("""
        var value = 100;
        (function() {
          console.log(a);
          a = 1;
          try {
            console.log(a);
            throw Error("welp");
          }
          catch (b) {
            var a = 2;
            console.log(a);
          }
          a = 3;
        })();
        console.log(value);
        """).lstrip(), ''.join(c.text for c in Unparser(rules=(
                default_rules,
                indent(indent_str='  '),
                obfuscate(),
            ))(node)))
    def test_no_shadow_children(self):
        node = es5(
            dedent("""
        var some_value = 1;
        (function(param) {
          a.is_not_declared_in_this_file(param);
        })();
        """).strip())

        self.assertEqual(
            dedent("""
        var b = 1;
        (function(b) {
            a.is_not_declared_in_this_file(b);
        })();
        """).lstrip(), ''.join(c.text for c in Unparser(rules=(
                default_rules,
                indent(indent_str='    '),
                obfuscate(obfuscate_globals=True),
            ))(node)))
    def test_obfuscate_skip(self):
        node = es5(
            dedent("""
        (function(a_param) {
          var a_local = a_param;
        })();
        """).strip())

        self.assertEqual(
            dedent("""
        (function(c) {
            var d = c;
        })();
        """).lstrip(), ''.join(c.text for c in Unparser(rules=(
                default_rules,
                indent(indent_str='    '),
                obfuscate(reserved_keywords=(
                    'a',
                    'b',
                )),
            ))(node)))
    def test_obfuscate_try_catch_no_declare(self):
        node = es5(
            dedent("""
        var value = 100;
        (function() {
          value = 1;
          try {
            console.log(value);
            throw Error("welp");
          }
          catch (value) {
            value = 0;
            console.log(value);
          }
          console.log(value);
        })();
        console.log(value);
        """).strip())

        self.assertEqual(
            dedent("""
        var value = 100;
        (function() {
          value = 1;
          try {
            console.log(value);
            throw Error("welp");
          }
          catch (a) {
            a = 0;
            console.log(a);
          }
          console.log(value);
        })();
        console.log(value);
        """).lstrip(), ''.join(c.text for c in Unparser(rules=(
                default_rules,
                indent(indent_str='  '),
                obfuscate(),
            ))(node)))
    def test_no_shadow_parent_remapped(self):
        node = es5(
            dedent("""
        var a = c;
        (function(param) {
          b.is_not_declared_in_this_file(a, param);
        })(c);
        """).strip())

        # param can remap to c because the global 'c' not used in that
        # scope.
        self.assertEqual(
            dedent("""
        var a = c;
        (function(c) {
            b.is_not_declared_in_this_file(a, c);
        })(c);
        """).lstrip(), ''.join(c.text for c in Unparser(rules=(
                default_rules,
                indent(indent_str='    '),
                obfuscate(obfuscate_globals=True),
            ))(node)))
    def test_obfuscate_no_global_recursive_redeclared_no_shadow_funcname(self):
        node = es5(
            dedent("""
        (function $() {
          $();
          (function $() {
            var foo = 1;
          })();
        })();
        """).strip())

        self.assertEqual(
            dedent("""
        (function $() {
          a();
          (function a() {
            var b = 1;
          })();
        })();
        """).lstrip(), ''.join(c.text for c in Unparser(rules=(
                default_rules,
                indent(indent_str='  '),
                obfuscate(obfuscate_globals=False, shadow_funcname=False),
            ))(node)))
示例#15
0
config_definitions = dict(**definitions)
config_definitions.update({
    # definition to ensure that array items are serialized one per line
    'Array': (
        Text(value='['),
        Indent,
        Newline,
        ElisionJoinAttr('items', value=(Newline, )),
        Dedent,
        OptionalNewline,
        Text(value=']'),
    ),
})
wpconf_serializer = Unparser(
    definitions=config_definitions,
    rules=(indent(indent_str='    '), ),
)

# produce customized versions of the commented calmjs.parse imports
# from calmjs.parse import asttypes
asttypes = AstTypesFactory(
    lambda ast: ''.join(chunk.text for chunk in wpconf_serializer(ast)),
    ReprWalker(),
)


# from calmjs.parse import es5
def es5(source):
    return Parser(asttypes=asttypes).parse(source)

示例#16
0
def run(inputs, output, mangle, obfuscate, pretty, source_map, indent_width,
        drop_semi, encoding, version):
    """
    Not a general use method, as sys.exit is called.
    """

    def stdin():
        return (
            sys.stdin
            if isinstance(sys.stdin, (StringIO, TextIOWrapper)) else
            codecs.getreader(sys.stdin.encoding or encoding)(sys.stdin)
        )

    def stdout():
        return (
            sys.stdout
            if isinstance(sys.stdout, (StringIO, TextIOWrapper)) else
            codecs.getwriter(sys.stdout.encoding or encoding)(sys.stdout)
        )

    abs_output = abspath(output) if output else output
    abs_source_map = abspath(source_map) if source_map else source_map

    input_streams = (
        [partial(codecs.open, abspath(p), encoding=encoding) for p in inputs]
        if inputs else
        [stdin]
    )
    output_stream = (
        partial(codecs.open, abs_output, 'w', encoding=encoding)
        if abs_output else
        stdout
    )
    # if source_map is flagged (from empty string, in the const), if
    # no further name is supplied, use the output to build the path,
    # if it is also not stdout.
    source_map_path = (
        abs_output + '.map'
        if source_map == '' and output_stream is not stdout else
        abs_source_map
    )

    if source_map and abs_source_map == abs_output:
        # if a source_map was specified and the absolute paths of that
        # and the output is equal, use the output_stream that was
        # already created.
        sourcemap_stream = output_stream
    else:
        # no source map if source_map path is actually None, and only
        # generate a callable if the source_map_path is not an empty
        # string.
        sourcemap_stream = None if source_map_path is None else (
            partial(codecs.open, source_map_path, 'w', encoding=encoding)
            if source_map_path else
            stdout
        )

    enabled_rules = [rules.minify(drop_semi=drop_semi or mangle)]
    if obfuscate or mangle:
        enabled_rules.append(rules.obfuscate(
            reserved_keywords=Lexer.keywords_dict.keys()
        ))

    if pretty:
        enabled_rules.append(rules.indent(indent_str=' ' * indent_width))

    printer = Unparser(rules=enabled_rules)
    try:
        io.write(
            printer, (io.read(parse, f) for f in input_streams),
            output_stream, sourcemap_stream,
        )
    except ECMASyntaxError as e:
        logger.error('%s', e)
        sys.exit(1)
    except (IOError, OSError) as e:
        logger.error('%s', e)
        if e.args and isinstance(e.args[0], int):
            sys.exit(e.args[0])
        sys.exit(5)  # EIO
    except UnicodeDecodeError as e:
        logger.error('read error: %s', e)
        sys.exit(1)
    except UnicodeEncodeError as e:
        logger.error('write error: %s', e)
        sys.exit(1)
    except KeyboardInterrupt:
        sys.exit(130)
    # no need to close any streams as they are callables and that the io
    # read/write functions take care of that.

    sys.exit(0)
    def test_build_substitutions(self):
        tree = es5(
            dedent("""
        (function(root) {
          var foo = 1;
          var bar = 2;
          baz = 3;
          foo = 4;
          window.document.body.focus();
        })(this, factory);
        """).strip())
        unparser = Unparser()
        obfuscator = Obfuscator()
        # a bare dispatcher should work, as it is used for extracting
        # the definitions from.
        sub_dispatcher = Dispatcher(unparser.definitions, rule_handler_noop,
                                    {}, {})
        # only do the intial walk.
        result = obfuscator.walk(sub_dispatcher, tree)
        # should be empty list as the run should produce nothing, due to
        # the null token producer.
        self.assertEqual(result, [])

        # only one scope was defined.
        self.assertEqual(1, len(obfuscator.scopes))
        self.assertEqual(1, len(obfuscator.global_scope.children))

        # do some validation on the scope itself.
        self.assertEqual(set(), obfuscator.global_scope.declared_symbols)
        self.assertEqual({
            'factory': 1,
            'baz': 1,
            'window': 1
        }, obfuscator.global_scope.referenced_symbols)
        scope = obfuscator.global_scope.children[0]

        self.assertEqual({'root', 'foo', 'bar'}, scope.declared_symbols)
        self.assertEqual(
            {
                'root': 1,
                'foo': 2,
                'bar': 1,
                'baz': 1,
                'window': 1,
            }, scope.referenced_symbols)

        # do a trial run to show that the resolution works.
        main_dispatcher = Dispatcher(
            unparser.definitions, token_handler_unobfuscate, {
                Space: layout_handler_space_minimum,
                RequiredSpace: layout_handler_space_minimum,
                OpenBlock: layout_handler_openbrace,
                CloseBlock: layout_handler_closebrace,
                EndStatement: layout_handler_semicolon,
            }, {
                Resolve: obfuscator.resolve,
            })
        # see that the manually constructed minimum output works.
        self.assertEqual(
            "(function(root){var foo=1;var bar=2;baz=3;foo=4;"
            "window.document.body.focus();})(this,factory);",
            ''.join(c.text for c in walk(main_dispatcher, tree)))
        # since nothing was remapped.
        self.assertEqual([], [(c.text, c.name)
                              for c in walk(main_dispatcher, tree) if c.name])

        # now manually give the scope with a set of replacement names
        scope.remapped_symbols.update({
            'root': 'r',
            'foo': 'f',
            'bar': 'b',
            'baz': 'z',
        })
        self.assertEqual(
            "(function(r){var f=1;var b=2;z=3;f=4;"
            "window.document.body.focus();})(this,factory);",
            ''.join(c.text for c in walk(main_dispatcher, tree)))
        # check that the source chunks yielded contain both the original
        # text token and the original row/col location
        self.assertEqual([
            ('r', 1, 11, 'root'),
            ('f', 2, 7, 'foo'),
            ('b', 3, 7, 'bar'),
            ('z', 4, 3, 'baz'),
            ('f', 5, 3, 'foo'),
        ], [c[:4] for c in walk(main_dispatcher, tree) if c.name])
    def test_multi_scope(self):
        node = es5(
            dedent("""
        (function(value) {
          var parent = 1;
          (function(value) {
            var child = 2;
            (function(value) {
              var grandchild = 3;
              (function(value) {
                var greatgrandchild = 4;
                (function(value) {
                  var result = 1;
                  // using greatgrandchild a lot to ensure priority
                  // mucking
                  console.log(parent);
                  console.log(greatgrandchild);
                  console.log(greatgrandchild * value);
                  console.log(greatgrandchild * parent);
                  console.log(greatgrandchild * greatgrandchild);
                })(value);
              })(value);
            })(value);
          })(value);
        })(0);
        """).strip())

        # Note that grandchild and greatgrandchild never had any of
        # their local variables referenced by any of their nested
        # scopes, their values got shadowed in the greatgrandchild scope
        # before both that and parent is used in the innermost scope.
        # Also, note that since greatgrandchild stopped propagating the
        # reference usage upwards, even though it has a lot more usage,
        # it never will claim priority over the parent at the parent
        # scope since parent got mapped to 'a' thus forcing
        # greatgrandchild to map to 'b', the next lowest value symbol.
        self.assertEqual(
            dedent("""
        (function(b) {
          var a = 1;
          (function(b) {
            var c = 2;
            (function(b) {
              var c = 3;
              (function(c) {
                var b = 4;
                (function(c) {
                  var d = 1;
                  console.log(a);
                  console.log(b);
                  console.log(b * c);
                  console.log(b * a);
                  console.log(b * b);
                })(c);
              })(b);
            })(b);
          })(b);
        })(0);
        """).lstrip(), ''.join(c.text for c in Unparser(rules=(
                default_rules,
                indent(indent_str='  '),
                obfuscate(),
            ))(node)))