sbt-proguard with play 2.2.3
Asked Answered
P

2

8

We developed a web application with play 2.2.3 and want to obfuscate it. I am trying to use sbt-proguard plugin. I put the line below to PROJECT_FOLDER/project/plugins.sbt file

addSbtPlugin("com.typesafe.sbt" % "sbt-proguard" % "0.2.2")

and put the lines below to PROJECT_FOLDER/build.sbt file

proguardSettings

ProguardKeys.options in Proguard ++= Seq("-dontnote", "-dontwarn", "-ignorewarnings")

ProguardKeys.options in Proguard += ProguardOptions.keepMain("Application")

inConfig(Proguard)(javaOptions in ProguardKeys.proguard := Seq("-Xmx2g"))

I am not sure proguard is working when I say dist on play console and on the plugin website they say call proguard:proguard. When I write proguard:proguard on play console, Play gives me error shown below

[info] Reading program jar [/Users/kamil/DEVELOPMENT/play-2.2.3/repository/local/net.sf.ehcache/ehcache-core/2.6.6/jars/ehcache-core.jar] (filtered)
[info] Reading program jar [/Users/kamil/DEVELOPMENT/play-2.2.3/repository/cache/org.json/json/jars/json-20140107.jar] (filtered)
[info] Reading library jar [/Library/Java/JavaVirtualMachines/jdk1.7.0_45.jdk/Contents/Home/jre/lib/jce.jar]
[info] Reading library jar [/Library/Java/JavaVirtualMachines/jdk1.7.0_45.jdk/Contents/Home/jre/lib/rt.jar]
[error] Error: The output jar is empty. Did you specify the proper '-keep' options?
[trace] Stack trace suppressed: run last proguard:proguard for the full output.
[error] (proguard:proguard) Proguard failed with exit code [1]
[error] Total time: 35 s, completed 10.Tem.2014 09:45:23

Is there anybody using this plugin with play framework succesfully?

Parthen answered 10/7, 2014 at 7:6 Comment(0)
T
2

After burning a few days on trying to make sbt-proguard configured properly, I gave up, and just used proguard after building the project.

Instead of including the obfuscation as a build part, 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 @CONF_FILE

Now for the configuration file, You need to specify:

  1. 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.
  2. 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.

  3. keep - any package-name, class, method or field that needs to keep its name. Common things that you should keep in a webapp:

    3.1. controller method names.

    3.2. any class that is used by play and specified in the application.conf like ErrorHandler, ApplicationLoader

    3.3. All router-generated classes

  4. Libraries - include all libraries in the lib file except for your own jars.

So your conf.pro file should like something like this:

-injars /path/to/jar/project-version-sans-externalized.jar(!META-INF)
-outjars /path/to/obfuscated/jar.jar


-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.** {*;}
-libraryjars /usr/lib/jvm/latest/jre/lib/rt.jar
-libraryjars /path/to/lib/library1.jar
-libraryjars /path/to/lib/library2.jar

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!

EDIT:

I really recommend looking at the proguard manual. It has many examples for different project setups and frameworks.

Tray answered 25/10, 2016 at 19:4 Comment(3)
ok @Tray but where should I put the conf.pro file? What is Its path?Marta
@Marta it doesn't matterTray
ok. @Tom, check this #50170251Marta
W
1

Tom provided great answer. I may improve it slightly, and make modern for new versions of Play Framework and for Scala 3 (Scala 2 should work to).

  1. You may specify lib directory: -libraryjars target/universal/app-name-0.1.0-SNAPSHOT/lib
  2. You may specify to keep annotations for constructors (or else you probably will have an error):
    -keep @javax.inject.Singleton class * { <init>(...); }
    -keep @javax.inject.Inject class * { <init>(...); }
    
  3. You may do post-processing, like deleting docs and Scala 3 .tasty files:
name=your-app-name
version=0.1.0-SNAPSHOT
rm -rf share # remove docs
rm -rf bin # remove bin. You may run it via java -cp, see below
rm -rf logs # remove old logs
rm -f README.md # remove README
rm -f $name.$name-$version-sans-externalized.jar # remove old jar
zip -dq out.jar **.tasty # remove Scala 3 tasty files
zip -dq out.jar **.js # remove duplicated js files. You have them in assets jar
zip -dq out.jar **.html # remove duplicated html files. You have them in assets jar
java -Dconfig.file=conf/application.conf -Dlogback.configurationFile=conf/logback.xml -cp "conf/*:lib/*:out.jar" play.core.server.ProdServerStart # run

My whole proguard file:

-injars      target/universal/my-app-0.1.0-SNAPSHOT/my-app.my-app-0.1.0-SNAPSHOT-sans-externalized.jar
-outjars     target/universal/my-app-0.1.0-SNAPSHOT/out.jar
-libraryjars <java.home>/jmods/java.base.jmod(!**.jar;!module-info.class)
-libraryjars target/universal/my-app-0.1.0-SNAPSHOT/lib

-keep class !db.**,!log.**,!utils.**,** { *; }
-keep @javax.inject.Singleton class * { <init>(...); }
-keep @javax.inject.Inject class * { <init>(...); }

-dontwarn
-dontobfuscate
-dontoptimize
-dontnote
-ignorewarnings

You may notice -dontobfuscate and -dontoptimize options. You may try to avoid them, but it's hard to do due to Play Framework magic.

Note: out.jar name in proguard file should be the same as in java cp flag.

UPDATE: Actually, I found a way to obfuscate Scala Play framework code. You need to specify injars, outjars as I did it in the snippet above, and replace the other part on

-dontnote
-dontwarn
#-dontoptimize
-optimizations code/allocation/variable,code/removal/simple,code/removal/advanced,code/simplification/math,code/simplification/string,code/simplification/object,code/simplification/arithmetic,class/marking/final,method/inlining/tailrecursion

# Keep all annotations, including constructor annotations
-keepattributes *Annotation*,EnclosingMethod,InnerClasses,Signature

# Keep all constructors for all classes
-keepclassmembers class * {
    public <init>(...);
}

# Allow obfuscation for specific package/classes
-keep class router.** { *; }
Woolworth answered 1/5 at 18:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.