Skip to content

Commit

Permalink
XWIKI-21207: Improve the evaluation of ConfigurableClass
Browse files Browse the repository at this point in the history
* Stop evaluating pretty names (which seems like an old feature no longer used anywhere)
* Introduce ConfigurableObjectEvaluator to safely evaluate heading and linkPrefix properties
  • Loading branch information
pjeanjean authored and tmortagne committed Apr 26, 2024
1 parent 487f6a9 commit 8493435
Show file tree
Hide file tree
Showing 9 changed files with 276 additions and 33 deletions.
1 change: 1 addition & 0 deletions xwiki-platform-core/xwiki-platform-administration/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
<packaging>pom</packaging>
<description>Application for administrating wiki features like users, groups, rights etc.</description>
<modules>
<module>xwiki-platform-administration-api</module>
<module>xwiki-platform-administration-ui</module>
</modules>
<profiles>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.xwiki.platform</groupId>
<artifactId>xwiki-platform-administration</artifactId>
<version>16.4.0-SNAPSHOT</version>
</parent>
<artifactId>xwiki-platform-administration-api</artifactId>
<name>XWiki Platform - Administration - API</name>
<packaging>jar</packaging>
<description>XWiki Platform - Administration - API</description>
<dependencies>
<dependency>
<groupId>org.xwiki.platform</groupId>
<artifactId>xwiki-platform-oldcore</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.xwiki.commons</groupId>
<artifactId>xwiki-commons-component-api</artifactId>
<version>${commons.version}</version>
</dependency>
<dependency>
<groupId>org.xwiki.commons</groupId>
<artifactId>xwiki-commons-tool-test-component</artifactId>
<version>${commons.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.xwiki.administration.api;

import java.util.Map;

import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;

import org.xwiki.component.annotation.Component;
import org.xwiki.evaluation.ObjectEvaluator;
import org.xwiki.evaluation.ObjectEvaluatorException;
import org.xwiki.evaluation.ObjectPropertyEvaluator;

import com.xpn.xwiki.objects.BaseObject;

/**
* Evaluator for objects of class {@code XWiki.ConfigurableClass}.
* Returns a Map storing the evaluated content for "heading" and "linkPrefix" properties.
*
* @version $Id$
* @since 15.10.9
* @since 16.3.0
*/
@Component
@Singleton
@Named(ConfigurableObjectEvaluator.ROLE_HINT)
public class ConfigurableObjectEvaluator implements ObjectEvaluator
{
/**
* The role hint of this component.
*/
public static final String ROLE_HINT = "XWiki.ConfigurableClass";

@Inject
@Named("velocity")
private ObjectPropertyEvaluator velocityPropertyEvaluator;

@Override
public Map<String, String> evaluate(BaseObject object) throws ObjectEvaluatorException
{
return this.velocityPropertyEvaluator.evaluateProperties(object, "heading", "linkPrefix");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
org.xwiki.administration.api.ConfigurableObjectEvaluator
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.xwiki.administration.api;

import java.util.Map;

import javax.inject.Named;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.xwiki.evaluation.ObjectEvaluatorException;
import org.xwiki.evaluation.ObjectPropertyEvaluator;
import org.xwiki.test.junit5.mockito.ComponentTest;
import org.xwiki.test.junit5.mockito.InjectMockComponents;
import org.xwiki.test.junit5.mockito.MockComponent;

import com.xpn.xwiki.objects.BaseObject;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

/**
* Validate {@link ConfigurableObjectEvaluator}.
*
* @version $Id$
*/
@ComponentTest
class ConfigurableObjectEvaluatorTest
{
@InjectMockComponents
private ConfigurableObjectEvaluator configurableObjectEvaluator;

@MockComponent
@Named("velocity")
private ObjectPropertyEvaluator velocityObjectPropertyEvaluator;

@Mock
private BaseObject baseObject;

@BeforeEach
void setUp() throws ObjectEvaluatorException
{
when(this.baseObject.getStringValue("heading")).thenReturn("unevaluated heading");
when(this.baseObject.getStringValue("linkPrefix")).thenReturn("unevaluated linkPrefix");

Map<String, String> evaluatedVelocityProperties =
Map.of("heading", "evaluated heading", "linkPrefix", "evaluated linkPrefix");

when(this.velocityObjectPropertyEvaluator.evaluateProperties(this.baseObject, "heading", "linkPrefix"))
.thenReturn(evaluatedVelocityProperties);
}

@Test
void checkEvaluationThroughPropertyEvaluator() throws ObjectEvaluatorException
{
Map<String, String> evaluationResults = this.configurableObjectEvaluator.evaluate(this.baseObject);
verify(this.velocityObjectPropertyEvaluator).evaluateProperties(this.baseObject, "heading", "linkPrefix");
assertEquals("evaluated heading", evaluationResults.get("heading"));
assertEquals("evaluated linkPrefix", evaluationResults.get("linkPrefix"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,12 @@
<version>${project.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.xwiki.platform</groupId>
<artifactId>xwiki-platform-administration-api</artifactId>
<version>${project.version}</version>
</dependency>

<!-- Test dependencies. -->
<dependency>
<groupId>org.xwiki.platform</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,32 +195,23 @@ $xwiki.jsfx.use('js/xwiki/actionbuttons/actionButtons.js', true)
#set($formId = "${section.toLowerCase()}_${app.getFullName()}")
#set($escapedAppName = $escapetool.xml($app.getFullName()))
#foreach($configurableObj in $configurableObjs)
## Execute the content code if any
## FIXME: we have to do that before the title before of the dropPermissions
#set($codeToExecute = "$!app.getValue('codeToExecute', $configurableObj)")
#if($codeToExecute != '')
#set($codeToExecuteResult = $configurableObj.display('codeToExecute', 'view', false))
#set ($heading = $app.getValue('heading', $configurableObj))
#set ($codeToExecute = "$!app.getValue('codeToExecute', $configurableObj)")
## If linkPrefix is set, then we will make each property label a link which starts with that prefix.
#set ($linkPrefix = "$!app.getValue('linkPrefix', $configurableObj)")
#if (!$app.restricted)
#set ($evaluatedConfigurableObj = $configurableObj.evaluate())
#set ($heading = $evaluatedConfigurableObj.heading)
#set ($linkPrefix = $evaluatedConfigurableObj.linkPrefix)
#end
## Display the header if one exists.
#set($heading = $app.getValue('heading', $configurableObj))
#if($heading &amp;&amp; $heading != '')
## This application should not run with programming rights because it evaluates code which may not be trustworthy.
## Removing the next line will open a security hole.
## Can't use $configurableObj.display('heading', 'view', false) to have proper heading id (because of the html macro)
## FIXME: find a cleaner solution
#set($void = $doc.dropPermissions())
#if ($services.security.authorization.hasAccess("script",
$app.authors.effectiveMetadataAuthor, $app.documentReference) &amp;&amp; !$app.restricted)
#set($evaluatedHeading = "#evaluate($heading)")
#else
#set($evaluatedHeading = $heading)
#end
== $services.rendering.escape($evaluatedHeading, 'xwiki/2.1') ==
== $services.rendering.escape($heading, 'xwiki/2.1') ==
#end
## Display code to execute
#if($codeToExecute != '')
#if ($codeToExecute != '')
(%class="codeToExecute"%)(((##
$codeToExecuteResult
$configurableObj.display('codeToExecute', 'view', false)
)))
#end
##
Expand All @@ -230,9 +221,6 @@ $xwiki.jsfx.use('js/xwiki/actionbuttons/actionButtons.js', true)
#set($propertiesToShow = [])
#end
##
## If linkPrefix is set, then we will make each property label a link which starts with that prefix.
#set($linkPrefix = "$!app.getValue('linkPrefix', $configurableObj)")
##
## If the Configurable object specifies a configuration class, use it,
## otherwise assume custom forms are used instead.
#set($configClassName = "$!app.getValue('configurationClass', $configurableObj)")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -339,8 +339,6 @@
#if($propertiesToShow.size() &gt; 0 &amp;&amp; !$propertiesToShow.contains($propName))
## Silently skip over this property.
#else
#set($prettyName = "#evaluate($app.displayPrettyName($propName, $obj))")
##
#set($hintKey = "${obj.xWikiClass.name}_${propName}.hint")
#set($hint = $services.localization.render($hintKey))
#if($hint == $hintKey)
Expand All @@ -364,11 +362,10 @@
$out ##
#set ($out = '')
#end
$escapetool.xml($prettyName)
$escapetool.xml($app.displayPrettyName($propName, $obj))
&lt;/label&gt;
#if($linkPrefix != '')
#set($linkScript = "$linkPrefix$propName")
&lt;a href="$escapetool.xml("#evaluate($linkScript)")" class="xHelp" title="$services.localization.render('admin.documentation')"&gt;$services.localization.render('admin.documentation')&lt;/a&gt;
&lt;a href="$escapetool.xml($linkPrefix + $propName)" class="xHelp" title="$services.localization.render('admin.documentation')"&gt;$services.localization.render('admin.documentation')&lt;/a&gt;
#end
#if ($hint)
&lt;span class="xHint"&gt;$hint&lt;/span&gt;
Expand Down
Loading

0 comments on commit 8493435

Please sign in to comment.