Skip to content

Commit

Permalink
refine api + path check
Browse files Browse the repository at this point in the history
  • Loading branch information
syjer committed Dec 22, 2024
1 parent ade8f07 commit 06c106f
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 20 deletions.
2 changes: 0 additions & 2 deletions src/main/java/ch/digitalfondue/mjml4j/GlobalContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ class GlobalContext {
final String dir;
//
final Mjml4j.IncludeResolver includeResolver;
final String basePath;
final ArrayDeque<String> currentResourcePaths = new ArrayDeque<>();
//

Expand Down Expand Up @@ -48,7 +47,6 @@ class GlobalContext {

//
this.includeResolver = configuration.includeResolver();
this.basePath = configuration.basePath();
//
}

Expand Down
65 changes: 48 additions & 17 deletions src/main/java/ch/digitalfondue/mjml4j/Mjml4j.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,46 @@ public String value() {
}

interface IncludeResolver {
/**
* Read the content of the file (with UTF-8) at a given resolved path.
*
* @param resolvedResourcePath
* @return
* @throws IOException
*/
String resolveAsString(String resolvedResourcePath) throws IOException;

/**
* Read the content of the file (with UTF-8 content) and parse it's content.
*
* @param resolvedResourcePath
* @return
*/
org.w3c.dom.Document resolveAsDocument(String resolvedResourcePath);
String resolvePath(String name, String base, Deque<String> parents);

/**
* Resolve the given path.
*
* @param name
* @param parents
* @return
*/
String resolvePath(String name, Deque<String> parents);
}

/**
* Filesystem based resolver. The content _must_ be within the provided basePath.
*
* The check can be customized, see {@link #checkAccess(Path, Path)}.
*/
public static class FileSystemResolver implements IncludeResolver {

private final Path basePath;

public FileSystemResolver(Path basePath) {
this.basePath = Objects.requireNonNull(basePath).toAbsolutePath();
}

@Override
public String resolveAsString(String resolvedResourcePath) throws IOException {
return Files.readString(Path.of(resolvedResourcePath), StandardCharsets.UTF_8);
Expand All @@ -64,28 +97,26 @@ public org.w3c.dom.Document resolveAsDocument(String resolvedResourcePath) {
throw new IllegalStateException("to implement");
}

@Override
public String resolvePath(String name, String base, Deque<String> parents) {
if (parents.isEmpty()) {
return Path.of(base, name).toAbsolutePath().toString();
} else {
return Path.of(parents.peek(), name).toAbsolutePath().toString();
public void checkAccess(Path basePath, Path resolvedPath) {
if (!resolvedPath.startsWith(basePath)) {
throw new IllegalStateException("Cannot access path outside of basePath");
}
}

@Override
public String resolvePath(String name, Deque<String> parents) {
var resolvedPath = (parents.isEmpty() ? basePath.resolve(name) : Path.of(parents.peek(), name)).toAbsolutePath();
checkAccess(basePath, resolvedPath);
return resolvedPath.toString();
}
}

public record Configuration(
String language, TextDirection dir,
IncludeResolver includeResolver, String basePath
IncludeResolver includeResolver
) {
public Configuration {
if (includeResolver != null && basePath == null) {
throw new IllegalStateException("basepath must be defined if includeResolver is defined");
}
}

public Configuration(String language, TextDirection dir) {
this(language, dir, null, null);
this(language, dir, null);
}

public Configuration(String language) {
Expand Down Expand Up @@ -438,12 +469,12 @@ private static BaseComponent createMjmlComponent(Element element, BaseComponent
private static BaseComponent handleInclude(Element element, BaseComponent parent, GlobalContext context) {

var path = element.getAttribute("path");
if (context.includeResolver == null || path == null) {
if (context.includeResolver == null || path == null || path.isEmpty()) {
return new HtmlComponent.HtmlRawComponent(element, parent, context);
}

var includeResolver = context.includeResolver;
var resolvedPath = includeResolver.resolvePath(path, context.basePath, context.currentResourcePaths);
var resolvedPath = includeResolver.resolvePath(path, context.currentResourcePaths);

var attributeType = element.getAttribute("type");
if ("html".equals(attributeType) || "css".equals(attributeType)) {
Expand Down
3 changes: 2 additions & 1 deletion src/test/java/ch/digitalfondue/mjml4j/Helpers.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.regex.Pattern;
Expand Down Expand Up @@ -70,7 +71,7 @@ static String alignIdFor(String input) {
static void testTemplate(String name) {
try {
var template = Files.readString(new File("data/" + name + ".mjml").toPath(), StandardCharsets.UTF_8);
var conf = new Mjml4j.Configuration("und", Mjml4j.TextDirection.AUTO, new Mjml4j.FileSystemResolver(), "data");
var conf = new Mjml4j.Configuration("und", Mjml4j.TextDirection.AUTO, new Mjml4j.FileSystemResolver(Path.of("data")));
var res = Mjml4j.render(template, conf);
var comparison = Files.readString(new File("data/" + name + ".html").toPath(), StandardCharsets.UTF_8);
Assertions.assertEquals(simplifyBrTags(alignIdFor(beautifyHtml(comparison))), alignIdFor(beautifyHtml(res)));
Expand Down

0 comments on commit 06c106f

Please sign in to comment.