Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions src/main/java/com/hubspot/jinjava/JinjavaConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
import com.hubspot.jinjava.el.JinjavaObjectUnwrapper;
import com.hubspot.jinjava.el.JinjavaProcessors;
import com.hubspot.jinjava.el.ObjectUnwrapper;
import com.hubspot.jinjava.el.ext.AllowlistMethodValidator;
import com.hubspot.jinjava.el.ext.AllowlistReturnTypeValidator;
import com.hubspot.jinjava.features.FeatureConfig;
import com.hubspot.jinjava.features.Features;
import com.hubspot.jinjava.interpret.Context.Library;
Expand Down Expand Up @@ -98,8 +100,6 @@ default int getMaxMacroRecursionDepth() {
}

Map<Library, Set<String>> getDisabled();
Set<String> getRestrictedMethods();
Set<String> getRestrictedProperties();

@Value.Default
default boolean isFailOnUnknownTokens() {
Expand Down Expand Up @@ -161,6 +161,16 @@ default TokenScannerSymbols getTokenScannerSymbols() {
return new DefaultTokenScannerSymbols();
}

@Value.Default
default AllowlistMethodValidator getMethodValidator() {
return AllowlistMethodValidator.DEFAULT;
}

@Value.Default
default AllowlistReturnTypeValidator getReturnTypeValidator() {
return AllowlistReturnTypeValidator.DEFAULT;
}

@Value.Default
default ELResolver getElResolver() {
return isDefaultReadOnlyResolver()
Expand Down
17 changes: 15 additions & 2 deletions src/main/java/com/hubspot/jinjava/el/ExpressionResolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@
import com.hubspot.jinjava.interpret.UnknownTokenException;
import com.hubspot.jinjava.interpret.errorcategory.BasicTemplateErrorCategory;
import com.hubspot.jinjava.lib.fn.ELFunctionDefinition;
import com.hubspot.jinjava.objects.serialization.PyishObjectMapper;
import com.hubspot.jinjava.util.WhitespaceUtils;
import de.odysseus.el.tree.TreeBuilderException;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import javax.el.ELException;
import javax.el.ExpressionFactory;
import javax.el.PropertyNotFoundException;
Expand All @@ -39,7 +41,7 @@ public class ExpressionResolver {

private final JinjavaInterpreter interpreter;
private final ExpressionFactory expressionFactory;
private final JinjavaInterpreterResolver resolver;
private final ReturnTypeValidatingJinjavaInterpreterResolver resolver;
private final JinjavaELContext elContext;
private final ObjectUnwrapper objectUnwrapper;

Expand All @@ -53,7 +55,11 @@ public ExpressionResolver(JinjavaInterpreter interpreter, Jinjava jinjava) {
? jinjava.getEagerExpressionFactory()
: jinjava.getExpressionFactory();

this.resolver = new JinjavaInterpreterResolver(interpreter);
this.resolver =
new ReturnTypeValidatingJinjavaInterpreterResolver(
interpreter.getConfig().getReturnTypeValidator(),
new JinjavaInterpreterResolver(interpreter)
);
this.elContext = new JinjavaELContext(interpreter, resolver);
for (ELFunctionDefinition fn : jinjava.getGlobalContext().getAllFunctions()) {
this.elContext.setFunction(fn.getNamespace(), fn.getLocalName(), fn.getMethod());
Expand Down Expand Up @@ -343,4 +349,11 @@ public Object resolveProperty(Object object, List<String> propertyNames) {
public Object wrap(Object object) {
return resolver.wrap(object);
}

public String getAsString(Object object) {
if (interpreter.getConfig().getLegacyOverrides().isUsePyishObjectMapper()) {
return PyishObjectMapper.getAsUnquotedPyishString(object);
}
return Objects.toString(object, "");
}
}
7 changes: 7 additions & 0 deletions src/main/java/com/hubspot/jinjava/el/HasInterpreter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.hubspot.jinjava.el;

import com.hubspot.jinjava.interpret.JinjavaInterpreter;

public interface HasInterpreter {
JinjavaInterpreter interpreter();
}
8 changes: 7 additions & 1 deletion src/main/java/com/hubspot/jinjava/el/JinjavaELContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
import java.lang.reflect.Method;
import javax.el.ELResolver;

public class JinjavaELContext extends SimpleContext {
public class JinjavaELContext extends SimpleContext implements HasInterpreter {

private JinjavaInterpreter interpreter;
private MacroFunctionMapper functionMapper;

@Deprecated
public JinjavaELContext() {
super();
}
Expand All @@ -19,6 +20,11 @@ public JinjavaELContext(JinjavaInterpreter interpreter, ELResolver resolver) {
this.interpreter = interpreter;
}

@Override
public JinjavaInterpreter interpreter() {
return interpreter;
}

@Override
public MacroFunctionMapper getFunctionMapper() {
if (functionMapper == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.hubspot.jinjava.objects.PyWrapper;
import com.hubspot.jinjava.objects.collections.SizeLimitingPyList;
import com.hubspot.jinjava.objects.collections.SizeLimitingPyMap;
import com.hubspot.jinjava.objects.collections.SizeLimitingPySet;
import com.hubspot.jinjava.objects.date.FormattedDate;
import com.hubspot.jinjava.objects.date.InvalidDateFormatException;
import com.hubspot.jinjava.objects.date.PyishDate;
Expand All @@ -39,6 +40,7 @@
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import javax.el.ArrayELResolver;
import javax.el.CompositeELResolver;
import javax.el.ELContext;
Expand Down Expand Up @@ -274,7 +276,7 @@ private Object getValue(
}

context.setPropertyResolved(true);
return wrap(value);
return value;
}

@SuppressWarnings("unchecked")
Expand Down Expand Up @@ -308,6 +310,12 @@ Object wrap(Object value) {
interpreter.getConfig().getMaxListSize()
);
}
if (Set.class.isAssignableFrom(value.getClass())) {
return new SizeLimitingPySet(
(Set<Object>) value,
interpreter.getConfig().getMaxListSize()
);
}
if (Map.class.isAssignableFrom(value.getClass())) {
// FIXME: ensure keys are actually strings, if not, convert them
return new SizeLimitingPyMap(
Expand Down
13 changes: 11 additions & 2 deletions src/main/java/com/hubspot/jinjava/el/NoInvokeELContext.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package com.hubspot.jinjava.el;

import com.hubspot.jinjava.interpret.JinjavaInterpreter;
import javax.el.ELContext;
import javax.el.ELResolver;
import javax.el.FunctionMapper;
import javax.el.VariableMapper;

public class NoInvokeELContext extends ELContext {
public class NoInvokeELContext extends ELContext implements HasInterpreter {

private ELContext delegate;
private final ELContext delegate;
private NoInvokeELResolver elResolver;

public NoInvokeELContext(ELContext delegate) {
Expand All @@ -31,4 +32,12 @@ public FunctionMapper getFunctionMapper() {
public VariableMapper getVariableMapper() {
return delegate.getVariableMapper();
}

@Override
public JinjavaInterpreter interpreter() {
if (delegate instanceof HasInterpreter hasInterpreter) {
return hasInterpreter.interpreter();
}
return JinjavaInterpreter.getCurrent();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package com.hubspot.jinjava.el;

import com.hubspot.jinjava.el.ext.AllowlistReturnTypeValidator;
import java.beans.FeatureDescriptor;
import java.util.Iterator;
import javax.el.ELContext;
import javax.el.ELResolver;

class ReturnTypeValidatingJinjavaInterpreterResolver extends ELResolver {

private final AllowlistReturnTypeValidator returnTypeValidator;
private final JinjavaInterpreterResolver delegate;

ReturnTypeValidatingJinjavaInterpreterResolver(
AllowlistReturnTypeValidator returnTypeValidator,
JinjavaInterpreterResolver delegate
) {
this.returnTypeValidator = returnTypeValidator;
this.delegate = delegate;
}

@Override
public Class<?> getCommonPropertyType(ELContext context, Object base) {
return delegate.getCommonPropertyType(context, base);
}

@Override
public Iterator<FeatureDescriptor> getFeatureDescriptors(
ELContext context,
Object base
) {
return delegate.getFeatureDescriptors(context, base);
}

@Override
public Class<?> getType(ELContext context, Object base, Object property) {
return delegate.getType(context, base, property);
}

@Override
public Object getValue(ELContext context, Object base, Object property) {
return returnTypeValidator.validateReturnType(
wrap(delegate.getValue(context, base, property))
);
}

@Override
public boolean isReadOnly(ELContext context, Object base, Object property) {
return delegate.isReadOnly(context, base, property);
}

@Override
public void setValue(ELContext context, Object base, Object property, Object value) {
delegate.setValue(context, base, property, value);
}

@Override
public Object invoke(
ELContext context,
Object base,
Object method,
Class<?>[] paramTypes,
Object[] params
) {
return returnTypeValidator.validateReturnType(
wrap(delegate.invoke(context, base, method, paramTypes, params))
);
}

Object wrap(Object object) {
return delegate.wrap(object);
}
}
Loading