On Mon, Jan 13, 2014 at 6:35 PM, Saar Korren <
slugf...@gmail.com> wrote:
> Taking a slice of code from my own haxe-built JS output:
> var org = {}
> org.slugfiller = {}
> org.slugfiller.aspect = {}
> org.slugfiller.aspect.Advice = function() { }
>
> And this from an auto-build interface.
> This code cannot be obfuscated with traditional obfuscators, because of
> JavaScript's expando features which allow something like this:
> org["slug"+"filler"]
If you avoid reflection, then it's reasonable to assume that Haxe also
does. In that case there is no reason why the generated JS should
contain anything that breaks.
> I agree that this should probably be reduced to "a.a.a.a", or even
> flattening the package structure to make it just "a". But this is not
> something that can be handled at the JS level, which is no longer
> package-aware.
Quite simply, you either want this to work or not. You can just as
well do `Type.resolveClass("
org.sl"+"ug.filler"+".aspect.Advice")`.
I suggest you run your output through closure and report any concrete issues.
> I'm not sure how the SWF source looks like, since it's auto-compiled, but a
> look at the binary with a text editor shows the package and method names are
> all there in plain-text, so I'm guessing it suffers from the same issues as
> JavaScript.
There is no SWF "source" as the generator spits out byte code directly.
As for obfuscation, the same argument applies as above. If you're
building and resolving class names at runtime, any obfuscator will
break. If you don't they will work.
> As for CPP, I've opened my executable in a text editor, and found all the
> class and method names there. This, despite not using anything from the Haxe
> reflection API. I believe the culprit is this:
> void TestMain_obj::__register()
> {
> hx::Static(__mClass) =
> hx::RegisterClass(HX_CSTRING("org.slugfiller.haxetest.TestMain"),
> hx::TCanCast< TestMain_obj> ,sStaticFields,sMemberFields,
> &__CreateEmpty, &__Create,
> &super::__SGetClass(), 0, sMarkStatics, sVisitStatics);
> }
> This method is apparently called from "__boot_all", and ensures
> code-coverage for the class name and all fields and members.
> Again, no remoting or reflection APIs were used.
>
> if at least the CPP target would not generate this information, I would have
> no issues using Emscripten for JavaScript. I would generally prefer to
> target asm.js anyway, for performance reasons.
>
> In PHP, this little line:
> spl_autoload_register('_hx_autoload');
> makes any attempt at obfuscation or code pre-compilation useless.
I agree that it makes it somewhat harder, but not impossible/useless.
For example, if you have a clean build in Haxe, all the files that are
in the output are used. Crawling the directory to generate an
include_all.php to work with is trivial. With `--next -main
MakeIncludeAll --interp` you can add that to your build without any
external tools.
> I've actually spent quite a few pages riffing on Zend's SPL, and frameworks
> that use it. Just like people who use Java are perfectly capable of using
> "import" for every class they use in a file, there's no reason why PHP
> should not use "require_once", perhaps with some healthy helping of
> "dirname(__FILE__)".
It would bloat output or impact on runtime performance.
You can either put the requires at the top, which makes you loose lazy
loading and thus is expensive in uncached php environments (which
unfortunately are still pretty much the default). Or you put them into
the method bodies. Which makes the code rather unreadable.
> Since the package and class names are in the produced filenames themselves,
> which are addressed at run-time, even using code-encryption wouldn't work,
> since the filenames can't be changed without breaking the code that loads
> the classes and imports.
>
> I can see how this direct translation can be useful for debugging. But for
> release builds, packaging everything into one flat file would be better.
Flattening is just as trivial as generating an include_all.
And again, depending on your environment it might not be what you want.
If you have a lousy webspace, where caching is not enabled, then this
will impact execution time. And if the bandwidth is in the same
league, deployment will take significantly longer, since you always
have to upload the whole app instead of the files that were changed.
> I realize output like that is not "for everyone".
That's exactly the point. The output now is for everyone. And if you
have specific needs, then you will have to walk the extra mile to meet
them.
> That's why I've been looking for a compiler flag, both in the compiler documentation, and in the
> "tips and tricks" (Why isn't there a single reference/man page with ALL the
> flags?), but couldn't find anything. What I did find is that there is a
> specific metadata for enabling RTTI ("@:rtti") for a specific class
> (Although I'm not sure what additional RTTI could be added to what is
> already present), but none for disabling all RTTI and reflection for a class
> or interface.
>
> Also, I don't think it has to be fully done at the code generation level.
> Something like converting "my.really.long.package.name.AndClass" to "a1234"
> can be done at the typing level.
To make my above point clear: If - and only if - you write your code
in such a way that you avoid building and resolving names at runtime,
then obfuscation is easily achieved. If not, then it's pretty much
impossible (unless you can add some sufficiently cryptic name
resolution code).
For example you can use Context.onGenerate to add a macro that will
decorate every class with a `@:native("<CrypticName>")` metadata to
replace the name in the output. Similarly, with a build macro you can
take every method and give it some obscure name, and generate an
inline method that will just forward the call. With a few extra tricks
you can even make it work for accessors and fields.
Or use any of the established tools for the platform.
Regards,
Juraj