Skip to content

Commit 3a24a12

Browse files
committed
redirect file ctor
1 parent 0aaec99 commit 3a24a12

File tree

3 files changed

+85
-14
lines changed

3 files changed

+85
-14
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package com.cleanroommc.groovyscript.helper;
2+
3+
import com.cleanroommc.groovyscript.GroovyScript;
4+
import com.cleanroommc.groovyscript.api.GroovyLog;
5+
import com.cleanroommc.groovyscript.sandbox.FileUtil;
6+
7+
import java.io.File;
8+
import java.net.URI;
9+
10+
public class Wrapper {
11+
12+
public static void validatePath(String path) {
13+
if (!path.startsWith(GroovyScript.getMinecraftHome().getPath())) {
14+
throw new SecurityException("Only files in minecraft home and sub directories can be accessed from scripts! Tried to access " + path);
15+
}
16+
}
17+
18+
public static void logFileCtorWarning() {
19+
GroovyLog.get().warn("Tried to use `new File(...)` constructor. Use `file(...)` instead!");
20+
}
21+
22+
public static File wrappedFileCtor(String path) {
23+
logFileCtorWarning();
24+
return GroovyHelper.file(path);
25+
}
26+
27+
public static File wrappedFileCtor(String parent, String child) {
28+
logFileCtorWarning();
29+
return GroovyHelper.file(parent, child);
30+
}
31+
32+
public static File wrappedFileCtor(File parent, String child) {
33+
logFileCtorWarning();
34+
File file = new File(parent, FileUtil.sanitizePath(child));
35+
validatePath(file.getPath());
36+
return file;
37+
}
38+
39+
public static File wrappedFileCtor(URI uri) {
40+
File file = new File(uri);
41+
validatePath(file.getPath());
42+
return file;
43+
}
44+
}

src/main/java/com/cleanroommc/groovyscript/sandbox/FileUtil.java

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.cleanroommc.groovyscript.sandbox;
22

3-
import com.google.common.base.Joiner;
43
import net.minecraftforge.fml.common.Loader;
54
import org.apache.commons.lang3.StringUtils;
65

@@ -10,8 +9,6 @@
109

1110
public class FileUtil {
1211

13-
private static final Joiner fileJoiner = Joiner.on(File.separator);
14-
1512
public static String relativize(String rootPath, String longerThanRootPath) {
1613
if (File.separatorChar != '/') {
1714
longerThanRootPath = longerThanRootPath.replace('/', File.separatorChar);
@@ -30,7 +27,26 @@ public static String getParent(String path) {
3027
}
3128

3229
public static String makePath(String... pieces) {
33-
return fileJoiner.join(pieces);
30+
if (pieces == null || pieces.length == 0) return StringUtils.EMPTY;
31+
if (pieces.length == 1) return sanitizePath(pieces[0]);
32+
StringBuilder builder = new StringBuilder();
33+
for (String piece : pieces) {
34+
if (piece != null && !piece.isEmpty()) {
35+
builder.append(sanitizePath(piece)).append(File.separatorChar);
36+
}
37+
}
38+
if (builder.length() > 0) {
39+
builder.deleteCharAt(builder.length() - 1);
40+
}
41+
return builder.toString();
42+
}
43+
44+
public static String sanitizePath(String path) {
45+
return path.replace(getOtherSeparatorChar(), File.separatorChar);
46+
}
47+
48+
public static char getOtherSeparatorChar() {
49+
return File.separatorChar == '/' ? '\\' : '/';
3450
}
3551

3652
public static File makeFile(String... pieces) {

src/main/java/com/cleanroommc/groovyscript/sandbox/transformer/GroovyScriptTransformer.java

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package com.cleanroommc.groovyscript.sandbox.transformer;
22

3-
import com.cleanroommc.groovyscript.api.GroovyLog;
43
import com.cleanroommc.groovyscript.gameobjects.GameObjectHandlerManager;
4+
import com.cleanroommc.groovyscript.helper.Wrapper;
55
import org.codehaus.groovy.ast.ClassCodeExpressionTransformer;
66
import org.codehaus.groovy.ast.ClassHelper;
77
import org.codehaus.groovy.ast.ClassNode;
@@ -16,6 +16,7 @@
1616
public class GroovyScriptTransformer extends ClassCodeExpressionTransformer {
1717

1818
private static final ClassNode bracketHandlerClass = ClassHelper.makeCached(GameObjectHandlerManager.class);
19+
private static final ClassNode wrapper = ClassHelper.makeCached(Wrapper.class);
1920
private final SourceUnit source;
2021
private final ClassNode classNode;
2122

@@ -29,10 +30,25 @@ protected SourceUnit getSourceUnit() {
2930
return source;
3031
}
3132

32-
private static Expression makeCheckedCall(ClassNode classNode, String name, Expression... arguments) {
33+
private static Expression makeCheckedCall(ClassNode classNode, String name, List<Expression> arguments) {
3334
return new StaticMethodCallExpression(classNode, name, new ArgumentListExpression(arguments));
3435
}
3536

37+
private static Expression makeCheckedCall(ClassNode classNode, String name, Expression arguments) {
38+
return makeCheckedCall(classNode, name, getArguments(arguments));
39+
}
40+
41+
private static List<Expression> getArguments(Expression expr) {
42+
List<Expression> args;
43+
if (expr instanceof TupleExpression te) {
44+
args = new ArrayList<>(te.getExpressions());
45+
} else {
46+
args = new ArrayList<>();
47+
args.add(expr);
48+
}
49+
return args;
50+
}
51+
3652
@Override
3753
public Expression transform(Expression expr) {
3854
if (expr == null) return null;
@@ -52,7 +68,7 @@ private Expression transformInternal(Expression expr) {
5268
return checkValid((MethodCallExpression) expr);
5369
}
5470
if (expr instanceof ConstructorCallExpression cce && cce.getType().getName().equals(File.class.getName())) {
55-
GroovyLog.get().warn("Detected `new File(...)` usage. Use `file(...)` instead!");
71+
return makeCheckedCall(wrapper, "wrappedFileCtor", cce.getArguments());
5672
}
5773
return expr;
5874
}
@@ -81,14 +97,9 @@ private Expression checkValid(MethodCallExpression expression) {
8197
if (expression.isImplicitThis() && argCount > 0) {
8298
String name = expression.getMethodAsString();
8399
if (GameObjectHandlerManager.hasGameObjectHandler(name)) {
84-
List<Expression> args;
85-
if (expression.getArguments() instanceof TupleExpression) {
86-
args = ((TupleExpression) expression.getArguments()).getExpressions();
87-
} else {
88-
args = new ArrayList<>();
89-
}
100+
List<Expression> args = getArguments(expression.getArguments());
90101
args.add(0, new ConstantExpression(name));
91-
return makeCheckedCall(bracketHandlerClass, "getGameObject", args.toArray(new Expression[0]));
102+
return makeCheckedCall(bracketHandlerClass, "getGameObject", args);
92103
}
93104
}
94105
return expression;

0 commit comments

Comments
 (0)