I downloaded (https://www.playframework.com/download#starters) a simple example of a Play project called “Play Java Starter Example” (Play 2.6.x Starter Projects) and I would like to obscure it with Proguard6.0.2.
Instead of including the obfuscation as a build part (with sbt-proguard), I opened the zip file generated by activator dist
, obfuscated the jar and returned it back into the lib folder with the same name. Here is how to do it.
Proguard can run on its own. You simply download the tar file from sourceforge and run the jar with a configuration file like:
java -jar /path/to/proguard/lib/proguard.jar @myConfig.pro
Now for the configuration file, You need to specify:
- injar - the jar being obfuscated - After unzipping the zip file created by the dist, cd into the lib file and found the jar names YOUR_PROJECT.VERSION-sans-externalized.jar this is the jar you need to obfuscate.
- outjar - the path for the obfuscated jar (output). At the end of the process just copy this jar back to the lib directory and rename it to the name of the in jar
- Libraries - include all libraries in the lib file except for your own jars.
- keep - any package-name, class, method or field that needs to keep its name. Common things that you should keep in a webapp:
- controller method names.
- any class that is used by play and specified in the application.conf like ErrorHandler, ApplicationLoader
- All router-generated classes
So my configuration file called myConfig.pro, should like something like this:
# specify the input jars, output jars, and library jars. ::::::::::::::::::::::::::::::
-injars /home/koala/Scaricati/play-java-starter-example/target/universal/play-java-starter-example-1.0-SNAPSHOT/lib/play-java-starter-example.play-java-starter-example-1.0-SNAPSHOT-sans-externalized.jar(!META-INF)
-outjars /home/koala/Scaricati/obfuscated.jar
-libraryjars /usr/lib/jvm/java-8-oracle/jre/lib/rt.jar
-libraryjars /home/koala/Scaricati/play-java-starter-example/target/universal/play-java-starter-example-1.0-SNAPSHOT/lib/
#-libraryjars /path/to/lib/library1.jar
#-libraryjars /path/to/lib/library2.jar
# keep ::::::::::::::::::::::::::::::
-keepnames class com.example.ErrorHandler
-keepnames class com.example.ApplicationLoader
-keepnames class controllers.**
-keepclassmembernames class controllers.** {
<methods>;
}
-keeppackagenames controllers.**, router.**, views.**
-keep class router.** {*;}
-keepnames class router.** {*;}
-keepclassmembers class router.** {*;}
-keep class views.** {*;}
-keepnames class views.** {*;}
-keepclassmembers class views.** {*;}
After obfuscation is done and you copied the output jar back to its old dir and name, you can zip back your project and you’ve got an obfuscated play project.
I tried to apply this method using the simple Java starter example downloaded from here:
https://www.playframework.com/download#starters
Everything went well but when I tried to run the obfuscated project in production mode (through the corresponding autogenerated script in the bin folder):
/your-app-dir/target/universal/your-app-1.0-SNAPSHOT/bin/your-app -Dhttp.port = 9000
I got the following error:
[warn] o.h.v.m.ParameterMessageInterpolator - HV000184: ParameterMessageInterpolator has been chosen, EL interpolation will not be supported
Oops, cannot start the server.
Configuration error: Configuration error[Cannot load class filters.ExampleFilter]
at play.api.Configuration$.configError(Configuration.scala:156)
at play.api.Configuration.reportError(Configuration.scala:990)
at play.api.http.EnabledFilters.$anonfun$filters$2(HttpFilters.scala:90)
at scala.collection.TraversableLike.$anonfun$map$1(TraversableLike.scala:234)
at scala.collection.mutable.ResizableArray.foreach(ResizableArray.scala:59)
at scala.collection.mutable.ResizableArray.foreach$(ResizableArray.scala:52)
at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:48)
at scala.collection.TraversableLike.map(TraversableLike.scala:234)
at scala.collection.TraversableLike.map$(TraversableLike.scala:227)
at scala.collection.AbstractTraversable.map(Traversable.scala:104)
at play.api.http.EnabledFilters.liftedTree1$1(HttpFilters.scala:84)
at play.api.http.EnabledFilters.<init>(HttpFilters.scala:80)
at play.api.http.EnabledFilters$$FastClassByGuice$$5bec3932.newInstance(<generated>)
at com.google.inject.internal.DefaultConstructionProxyFactory$FastClassProxy.newInstance(DefaultConstructionProxyFactory.java:89)
at com.google.inject.internal.ConstructorInjector.provision(ConstructorInjector.java:111)
at com.google.inject.internal.ConstructorInjector.construct(ConstructorInjector.java:90)
at com.google.inject.internal.ConstructorBindingImpl$Factory.get(ConstructorBindingImpl.java:268)
at com.google.inject.internal.ProviderToInternalFactoryAdapter$1.call(ProviderToInternalFactoryAdapter.java:46)
at com.google.inject.internal.InjectorImpl.callInContext(InjectorImpl.java:1092)
at com.google.inject.internal.ProviderToInternalFactoryAdapter.get(ProviderToInternalFactoryAdapter.java:40)
at com.google.inject.internal.SingletonScope$1.get(SingletonScope.java:194)
at com.google.inject.internal.InternalFactoryToProviderAdapter.get(InternalFactoryToProviderAdapter.java:41)
at com.google.inject.internal.FactoryProxy.get(FactoryProxy.java:56)
at com.google.inject.internal.SingleParameterInjector.inject(SingleParameterInjector.java:38)
at com.google.inject.internal.SingleParameterInjector.getAll(SingleParameterInjector.java:62)
at com.google.inject.internal.ConstructorInjector.provision(ConstructorInjector.java:110)
at com.google.inject.internal.ConstructorInjector.construct(ConstructorInjector.java:90)
at com.google.inject.internal.ConstructorBindingImpl$Factory.get(ConstructorBindingImpl.java:268)
at com.google.inject.internal.FactoryProxy.get(FactoryProxy.java:56)
at com.google.inject.internal.SingleParameterInjector.inject(SingleParameterInjector.java:38)
at com.google.inject.internal.SingleParameterInjector.getAll(SingleParameterInjector.java:62)
at com.google.inject.internal.ConstructorInjector.provision(ConstructorInjector.java:110)
at com.google.inject.internal.ConstructorInjector.construct(ConstructorInjector.java:90)
at com.google.inject.internal.ConstructorBindingImpl$Factory.get(ConstructorBindingImpl.java:268)
at com.google.inject.internal.ProviderToInternalFactoryAdapter$1.call(ProviderToInternalFactoryAdapter.java:46)
at com.google.inject.internal.InjectorImpl.callInContext(InjectorImpl.java:1092)
at com.google.inject.internal.ProviderToInternalFactoryAdapter.get(ProviderToInternalFactoryAdapter.java:40)
at com.google.inject.internal.SingletonScope$1.get(SingletonScope.java:194)
at com.google.inject.internal.InternalFactoryToProviderAdapter.get(InternalFactoryToProviderAdapter.java:41)
at com.google.inject.internal.FactoryProxy.get(FactoryProxy.java:56)
at com.google.inject.internal.InternalInjectorCreator$1.call(InternalInjectorCreator.java:205)
at com.google.inject.internal.InternalInjectorCreator$1.call(InternalInjectorCreator.java:199)
at com.google.inject.internal.InjectorImpl.callInContext(InjectorImpl.java:1085)
at com.google.inject.internal.InternalInjectorCreator.loadEagerSingletons(InternalInjectorCreator.java:199)
at com.google.inject.internal.InternalInjectorCreator.injectDynamically(InternalInjectorCreator.java:180)
at com.google.inject.internal.InternalInjectorCreator.build(InternalInjectorCreator.java:110)
at com.google.inject.Guice.createInjector(Guice.java:99)
at com.google.inject.Guice.createInjector(Guice.java:84)
at play.api.inject.guice.GuiceBuilder.injector(GuiceInjectorBuilder.scala:185)
at play.api.inject.guice.GuiceApplicationBuilder.build(GuiceApplicationBuilder.scala:137)
at play.api.inject.guice.GuiceApplicationLoader.load(GuiceApplicationLoader.scala:21)
at play.core.server.ProdServerStart$.start(ProdServerStart.scala:51)
at play.core.server.ProdServerStart$.main(ProdServerStart.scala:25)
at play.core.server.ProdServerStart.main(ProdServerStart.scala)
Caused by: java.lang.ClassNotFoundException: filters.ExampleFilter
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at play.api.http.EnabledFilters.$anonfun$filters$2(HttpFilters.scala:86)
... 51 more
I think it is due to an error or omission in the myConfig.pro configuration file.
Can someone help me?
Does anyone know a simpler way to obfuscate a Play project?